2 * Copyright (C) 2005,2006 MaNGOS <http://www.mangosproject.org/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "WorldPacket.h"
20 #include "WorldSession.h"
24 #include "ObjectMgr.h"
26 #include "UpdateMask.h"
27 #include "AuctionHouseObject.h"
29 //pls DO NOT use iterator++, because it is slowlier than ++iterator!!!
30 //post-incrementation is always slowlier than pre-incrementation !
32 void WorldSession::HandleAuctionHelloOpcode( WorldPacket
& recv_data
)
34 uint64 guid
; //NPC guid
37 Creature
*unit
= ObjectAccessor::Instance().GetCreature(*_player
, guid
);
40 sLog
.outDebug( "WORLD: HandleAuctionHelloOpcode - NO SUCH UNIT! (GUID: %u)", uint32(GUID_LOPART(guid
)) );
43 if( unit
->IsHostileTo(_player
)) // do not talk with enemies
45 if( !unit
->isAuctioner()) // it's not auctioner
48 SendAuctionHello(guid
, unit
);
51 static uint8
AuctioneerFactionToLocation(uint32 faction
)
53 if(sWorld
.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION
))
68 default: /* 85 and so on ... neutral*/
73 void WorldSession::SendAuctionHello( uint64 guid
, Creature
* unit
)
76 data
.Initialize( MSG_AUCTION_HELLO
);
77 data
<< (uint64
) guid
;
78 data
<< (uint32
) AuctioneerFactionToLocation(unit
->getFaction());
82 //this function inserts to WorldPacket auction's data
83 bool WorldSession::SendAuctionInfo(WorldPacket
& data
, AuctionEntry
* auction
)
85 Item
*pItem
= objmgr
.GetAItem(auction
->item_guid
);
88 sLog
.outError("auction to item, that doesn't exist !!!!");
92 data
<< pItem
->GetUInt32Value(OBJECT_FIELD_ENTRY
);
93 data
<< (uint32
) 0; //0 - HighBidder, 1 - outbid, BID TYPE - not sure
94 data
<< (uint32
) 0; //unknown constant 0 ?
95 data
<< (uint32
) 0; //not pItem->GetCreator();// 4a d0 64 02, 0, unknown
96 data
<< (uint32
) pItem
->GetCount(); //item->count
97 //item->charge FFFFFFF
98 data
<< (uint32
) pItem
->GetUInt32Value(ITEM_FIELD_SPELL_CHARGES
);
99 data
<< (uint32
) auction
->owner
; //Auction->owner
100 data
<< (uint32
) 0; //player_high_guid
101 data
<< (uint32
) auction
->startbid
; //Auction->startbid
102 data
<< (uint32
) auction
->outBid
; //minimal outbid...
103 data
<< (uint32
) auction
->buyout
; //auction->buyout
104 data
<< (uint32
) (auction
->time
- time(NULL
)) * 1000; //time
105 data
<< (uint32
) auction
->bidder
; //auction->bidder current
106 data
<< (uint32
) 0; //0 ? .. player highguid
107 data
<< (uint32
) auction
->bid
; //current bid
111 //call this method when player bids, creates, or deletes auction
112 void WorldSession::SendAuctionCommandResult(uint32 auctionId
, uint32 Action
, uint32 ErrorCode
, uint32 bidError
)
115 data
.Initialize( SMSG_AUCTION_COMMAND_RESULT
);
119 if ( !ErrorCode
&& Action
)
120 data
<< bidError
; //when bid, then send 0, once...
124 //this function sends notification, if bidder is online
125 void WorldSession::SendAuctionBidderNotification( uint32 location
, uint32 auctionId
, uint64 bidder
, uint32 bidSum
, uint32 diff
, uint32 item_template
)
128 data
.Initialize(SMSG_AUCTION_BIDDER_NOTIFICATION
);
131 data
<< (uint64
) bidder
;
133 data
<< (uint32
) diff
;
134 data
<< item_template
;
139 void WorldSession::SendAuctionOwnerNotification( AuctionEntry
* auction
)
142 data
.Initialize(SMSG_AUCTION_OWNER_NOTIFICATION
);
144 data
<< auction
->bid
;
145 data
<< (uint32
) 0; //unk
146 data
<< (uint32
) 0; //unk
147 data
<< (uint32
) 0; //unk
148 data
<< auction
->item_template
;
149 data
<< (uint32
) 0; //unk
153 //this function sends mail to old bidder
154 void WorldSession::SendAuctionOutbiddedMail(AuctionEntry
*auction
, uint32 newPrice
)
156 uint32 mailId
= objmgr
.GenerateMailID();
157 time_t etime
= time(NULL
) + (30 * DAY
);
159 std::ostringstream msgAuctionOutbiddedSubject
;
160 msgAuctionOutbiddedSubject
<< auction
->item_template
<< ":0:" << AUCTION_OUTBIDDED
;
162 Player
*oldBidder
= objmgr
.GetPlayer((uint64
) auction
->bidder
);
165 oldBidder
->GetSession()->SendAuctionBidderNotification( auction
->location
, auction
->Id
, _player
->GetGUID(), newPrice
, auction
->outBid
, auction
->item_template
);
166 oldBidder
->CreateMail(mailId
, AUCTIONHOUSE_MAIL
, auction
->location
, msgAuctionOutbiddedSubject
.str(), 0, 0, 0, etime
, auction
->bid
, 0, NOT_READ
, NULL
);
169 sDatabase
.PExecute("INSERT INTO `mail` (`id`,`messageType`,`sender`,`receiver`,`subject`,`itemPageId`,`item_guid`,`item_template`,`time`,`money`,`cod`,`checked`) "
170 "VALUES ('%u', '%d', '%u', '%u', '%s', '0', '0', '0', '" I64FMTD
"', '%u', '0', '%d')",
171 mailId
, AUCTIONHOUSE_MAIL
, auction
->location
, auction
->bidder
, msgAuctionOutbiddedSubject
.str().c_str(), (uint64
)etime
, auction
->bid
, NOT_READ
);
174 //this function sends mail, when auction is cancelled to old bidder
175 void WorldSession::SendAuctionCancelledToBidderMail( AuctionEntry
* auction
)
177 uint32 mailId
= objmgr
.GenerateMailID();
178 time_t etime
= time(NULL
) + (30 * DAY
);
180 std::ostringstream msgAuctionCancelledSubject
;
181 msgAuctionCancelledSubject
<< auction
->item_template
<< ":0:" << AUCTION_CANCELLED_TO_BIDDER
;
183 Player
*bidder
= objmgr
.GetPlayer((uint64
) auction
->bidder
);
186 // unknown : bidder->GetSession()->SendAuctionBidderNotification( auction->location, auction->Id, _player->GetGUID(), newPrice, newPrice - auction->bid, auction->item_template);
187 bidder
->CreateMail(mailId
, AUCTIONHOUSE_MAIL
, auction
->location
, msgAuctionCancelledSubject
.str(), 0, 0, 0, etime
, auction
->bid
, 0, NOT_READ
, NULL
);
190 sDatabase
.PExecute("INSERT INTO `mail` (`id`,`messageType`,`sender`,`receiver`,`subject`,`itemPageId`,`item_guid`,`item_template`,`time`,`money`,`cod`,`checked`) "
191 "VALUES ('%u', '%d', '%u', '%u', '%s', '0', '0', '0', '" I64FMTD
"', '%u', '0', '%d')",
192 mailId
, AUCTIONHOUSE_MAIL
, auction
->location
, auction
->bidder
, msgAuctionCancelledSubject
.str().c_str(), (uint64
)etime
, auction
->bid
, NOT_READ
);
195 void WorldSession::HandleAuctionSellItem( WorldPacket
& recv_data
)
197 uint64 auctioneer
, item
;
198 uint32 etime
, bid
, buyout
;
199 recv_data
>> auctioneer
>> item
;
200 recv_data
>> bid
>> buyout
>> etime
;
201 Player
*pl
= GetPlayer();
203 Creature
*pCreature
= ObjectAccessor::Instance().GetCreature(*_player
, auctioneer
);
204 if(!pCreature
||!pCreature
->isAuctioner())
209 uint16 pos
= pl
->GetPosByGuid(item
);
210 Item
*it
= pl
->GetItemByPos( pos
);
212 // prevent sending bag with items (cheat: can be placed in bag after adding equiped empty bag to auction)
213 if(!it
|| !it
->CanBeTraded())
215 //5b 02 00 00 00 00 00 00 00 00 02 00 00 00 -- -- : [.............
217 SendAuctionCommandResult(0, AUCTION_SELL_ITEM
, AUCTION_INTERNAL_ERROR
);
221 uint32 location
= AuctioneerFactionToLocation(pCreature
->getFaction());
222 AuctionHouseObject
* mAuctions
;
223 mAuctions
= objmgr
.GetAuctionsMap( location
);
225 //we have to take deposit :
226 uint32 deposit
= objmgr
.GetAuctionDeposit( location
, etime
, it
);
227 if ( pl
->GetMoney() < deposit
)
229 SendAuctionCommandResult(0, AUCTION_SELL_ITEM
, AUCTION_NOT_ENOUGHT_MONEY
);
232 pl
->ModifyMoney( ((int32
) deposit
) * -1 );
234 AuctionEntry
*AH
= new AuctionEntry
;
235 AH
->Id
= objmgr
.GenerateAuctionID();
236 AH
->auctioneer
= GUID_LOPART(auctioneer
);
237 AH
->item_guid
= GUID_LOPART(item
);
238 AH
->item_template
= it
->GetEntry();
239 AH
->owner
= pl
->GetGUIDLow();
245 time_t base
= time(NULL
);
246 AH
->time
= ((time_t)(etime
* 60)) + base
;
247 AH
->deposit
= deposit
;
248 AH
->location
= location
;
250 sLog
.outDetail("selling item %u to auctioneer %u with inital bid %u with buyout %u and with time %u (in minutes) in location: %u", GUID_LOPART(item
), GUID_LOPART(auctioneer
), bid
, buyout
, GUID_LOPART(time
), location
);
251 mAuctions
->AddAuction(AH
);
253 // DB can have outdate auction item with same guid
254 objmgr
.RemoveAItem(GUID_LOPART(item
));
257 pl
->RemoveItem( (pos
>> 8),(pos
& 255), true);
258 it
->RemoveFromUpdateQueueOf(pl
);
259 it
->DeleteFromInventoryDB();
261 sDatabase
.PExecute("INSERT INTO `auctionhouse` (`id`,`auctioneerguid`,`itemguid`,`item_template`,`itemowner`,`buyoutprice`,`time`,`buyguid`,`lastbid`,`startbid`,`deposit`,`location`) "
262 "VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '" I64FMTD
"', '%u', '%u', '%u', '%u', '%u')",
263 AH
->Id
, AH
->auctioneer
, AH
->item_guid
, AH
->item_template
, AH
->owner
, AH
->buyout
, (uint64
)AH
->time
, AH
->bidder
, AH
->bid
, AH
->startbid
, AH
->deposit
, AH
->location
);
265 SendAuctionCommandResult(AH
->Id
, AUCTION_SELL_ITEM
, AUCTION_OK
);
266 //pl->SaveToDB() - isn't needed, because item will be removed from inventory now, only money are problem
269 void WorldSession::HandleAuctionPlaceBid( WorldPacket
& recv_data
)
275 recv_data
>> auctioneer
;
276 recv_data
>> auctionId
>> price
;
278 Creature
*pCreature
= ObjectAccessor::Instance().GetCreature(*_player
, auctioneer
);
279 if(!pCreature
||!pCreature
->isAuctioner())
281 uint32 location
= AuctioneerFactionToLocation(pCreature
->getFaction());
283 AuctionHouseObject
* mAuctions
;
284 mAuctions
= objmgr
.GetAuctionsMap( location
);
286 AuctionEntry
*auction
= mAuctions
->GetAuction(auctionId
);
287 Player
*pl
= GetPlayer();
288 if ((auction
) && (auction
->owner
!= pl
->GetGUIDLow()))
290 if (price
< (auction
->bid
+ auction
->outBid
))
292 //auction has already higher bid, client tests it!
293 //SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???);
296 if (price
> pl
->GetMoney())
298 //you don't have enought money!, client tests!
299 //SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???);
302 if ((price
< auction
->buyout
) || (auction
->buyout
== 0))
304 auction
->outBid
+= 5; //this line must be here
306 if (auction
->bidder
> 0)
308 if ( auction
->bidder
== pl
->GetGUIDLow() )
310 pl
->ModifyMoney(((uint32
)(price
- auction
->bid
)) * -1);
314 // mail to last bidder if there's one... + return money
315 SendAuctionOutbiddedMail( auction
, price
);
316 pl
->ModifyMoney(((int32
) price
) * -1);
321 pl
->ModifyMoney(((int32
) price
) * -1);
323 auction
->bidder
= pl
->GetGUIDLow();
324 auction
->bid
= price
;
325 if ( auction
->outBid
> 10000 ) //one gold
328 // after this update we should save player's money ...
329 sDatabase
.PExecute("UPDATE `auctionhouse` SET `buyguid` = '%u',`lastbid` = '%u' WHERE `id` = '%u';", auction
->bidder
, auction
->bid
, auction
->Id
);
331 SendAuctionCommandResult(auction
->Id
, AUCTION_PLACE_BID
, AUCTION_OK
, 0 );
336 if (pl
->GetGUIDLow() == auction
->bidder
)
338 pl
->ModifyMoney(-int32(auction
->buyout
- auction
->bid
));
342 pl
->ModifyMoney(-int32(auction
->buyout
));
343 if ( auction
->bidder
) //buyout for bidded auction ..
345 SendAuctionOutbiddedMail( auction
, auction
->buyout
);
348 auction
->bidder
= pl
->GetGUIDLow();
349 auction
->bid
= auction
->buyout
;
351 objmgr
.SendAuctionSuccessfulMail( auction
);
352 objmgr
.SendAuctionWonMail( auction
);
354 SendAuctionCommandResult(auction
->Id
, AUCTION_PLACE_BID
, AUCTION_OK
);
359 //you cannot bid your own auction:
360 SendAuctionCommandResult( 0, AUCTION_PLACE_BID
, CANNOT_BID_YOUR_AUCTION_ERROR
);
364 //will be fixed soon , but now it's not used....
365 void WorldSession::HandleAuctionRemoveItem( WorldPacket
& recv_data
)
369 recv_data
>> auctioneer
;
370 recv_data
>> auctionId
;
371 sLog
.outDebug( "Cancel AUCTION AuctionID: %u", auctionId
);
373 Creature
*pCreature
= ObjectAccessor::Instance().GetCreature(*_player
, auctioneer
);
374 if(!pCreature
||!pCreature
->isAuctioner())
376 uint32 location
= AuctioneerFactionToLocation(pCreature
->getFaction());
378 AuctionHouseObject
* mAuctions
;
379 mAuctions
= objmgr
.GetAuctionsMap( location
);
381 AuctionEntry
*auction
= mAuctions
->GetAuction(auctionId
);
382 Player
*pl
= GetPlayer();
384 if (auction
&& auction
->owner
== pl
->GetGUIDLow())
386 Item
*pItem
= objmgr
.GetAItem(auction
->item_guid
);
389 if (auction
->bidder
> 0) // If we have a bidder, we have to send him the money he paid
391 uint32 auctionCut
= objmgr
.GetAuctionCut( auction
->location
, auction
->bid
);
392 if ( pl
->GetMoney() < auctionCut
) //player doesn't have enought money, maybe message needed
394 //some auctionBidderNotification would be needed, but don't know that parts..
395 SendAuctionCancelledToBidderMail( auction
);
396 pl
->ModifyMoney( ((int32
) auctionCut
) * -1 );
399 std::ostringstream msgAuctionCanceledOwner
;
400 msgAuctionCanceledOwner
<< auction
->item_template
<< ":0:" << AUCTION_CANCELED
;
402 uint32 messageID
= objmgr
.GenerateMailID();
403 time_t etime
= time(NULL
) + (30 * DAY
);
405 pl
->CreateMail( messageID
, AUCTIONHOUSE_MAIL
, auction
->location
, msgAuctionCanceledOwner
.str(), 0, auction
->item_guid
, auction
->item_template
, etime
, 0, 0, 0, pItem
);
406 sDatabase
.PExecute("INSERT INTO `mail` (`id`,`messageType`,`sender`,`receiver`,`subject`,`itemPageId`,`item_guid`,`item_template`,`time`,`money`,`cod`,`checked`) "
407 "VALUES ('%u', '%d', '%u', '%u', '%s', '0', '%u', '%u', '" I64FMTD
"', '0', '0', '0')",
408 messageID
, AUCTIONHOUSE_MAIL
, auction
->location
, pl
->GetGUIDLow() , msgAuctionCanceledOwner
.str().c_str(), auction
->item_guid
, auction
->item_template
, (uint64
)etime
);
412 sLog
.outError("Auction id: %u has non-existed item (item guid : %u)!!!", auction
->Id
, auction
->item_guid
);
413 SendAuctionCommandResult( 0, AUCTION_CANCEL
, AUCTION_INTERNAL_ERROR
);
419 SendAuctionCommandResult( 0, AUCTION_CANCEL
, AUCTION_INTERNAL_ERROR
);
420 //this code isn't possible ... maybe there should be assert
421 sLog
.outError("CHEATER : %u, he tried to cancel auction (id: %u) of another player, or auction is NULL", pl
->GetGUIDLow(), auctionId
);
425 //inform player, that auction is removed
426 SendAuctionCommandResult( auction
->Id
, AUCTION_CANCEL
, AUCTION_OK
);
427 // Now remove the auction
428 sDatabase
.PExecute("DELETE FROM `auctionhouse` WHERE `id` = '%u'",auction
->Id
);
429 objmgr
.RemoveAItem( auction
->item_guid
);
430 mAuctions
->RemoveAuction( auction
->Id
);
434 void WorldSession::HandleAuctionListBidderItems( WorldPacket
& recv_data
)
436 uint64 guid
; //NPC guid
437 uint32 listfrom
; //page of auctions
438 uint32 outbiddedCount
; //count of outbidded auctions
441 recv_data
>> listfrom
;
442 recv_data
>> outbiddedCount
;
443 if (recv_data
.size() != (16 + outbiddedCount
* 4 ))
445 sLog
.outError("Client sent bad opcode!!! with count: %u and size : %d", outbiddedCount
, recv_data
.size());
449 Creature
*pCreature
= ObjectAccessor::Instance().GetCreature(*_player
, guid
);
450 if(!pCreature
||!pCreature
->isAuctioner())
452 uint32 location
= AuctioneerFactionToLocation(pCreature
->getFaction());
454 AuctionHouseObject
* mAuctions
;
455 mAuctions
= objmgr
.GetAuctionsMap( location
);
458 data
.Initialize( SMSG_AUCTION_BIDDER_LIST_RESULT
);
459 Player
*pl
= GetPlayer();
460 data
<< (uint32
) 0; //add 0 as count
462 uint32 totalcount
= 0;
463 while ( outbiddedCount
> 0) //add all data, which client requires
466 uint32 outbiddedAuctionId
;
467 recv_data
>> outbiddedAuctionId
;
468 AuctionEntry
* auction
= mAuctions
->GetAuction( outbiddedAuctionId
);
469 if ( auction
&& SendAuctionInfo(data
, auction
))
475 for (AuctionHouseObject::AuctionEntryMap::iterator itr
= mAuctions
->GetAuctionsBegin();itr
!= mAuctions
->GetAuctionsEnd();++itr
)
477 AuctionEntry
*Aentry
= itr
->second
;
478 if( Aentry
&& Aentry
->bidder
== pl
->GetGUIDLow() )
480 if ((count
< 50) && (totalcount
>= listfrom
) && SendAuctionInfo(data
, itr
->second
))
485 data
.put( 0, count
); // add count to placeholder
490 void WorldSession::HandleAuctionListOwnerItems( WorldPacket
& recv_data
)
496 recv_data
>> listfrom
; // page of auctions
498 Creature
*pCreature
= ObjectAccessor::Instance().GetCreature(*_player
, guid
);
499 if(!pCreature
||!pCreature
->isAuctioner())
501 uint32 location
= AuctioneerFactionToLocation(pCreature
->getFaction());
503 AuctionHouseObject
* mAuctions
;
504 mAuctions
= objmgr
.GetAuctionsMap( location
);
507 data
.Initialize( SMSG_AUCTION_OWNER_LIST_RESULT
);
510 uint32 totalcount
= 0;
511 for (AuctionHouseObject::AuctionEntryMap::iterator itr
= mAuctions
->GetAuctionsBegin();itr
!= mAuctions
->GetAuctionsEnd();++itr
)
513 AuctionEntry
*Aentry
= itr
->second
;
514 if( Aentry
&& Aentry
->owner
== _player
->GetGUIDLow() )
516 if ((count
< 50) && (totalcount
>= listfrom
) && SendAuctionInfo(data
, itr
->second
))
521 data
.put
<uint32
>(0, count
);
522 data
<< (uint32
) totalcount
;
526 void WorldSession::HandleAuctionListItems( WorldPacket
& recv_data
)
528 std::string searchedname
, name
;
529 uint8 levelmin
, levelmax
, usable
, location
;
530 uint32 count
, totalcount
, listfrom
, auctionSlotID
, auctionMainCategory
, auctionSubCategory
, quality
;
534 recv_data
>> listfrom
;
535 recv_data
>> searchedname
;
536 recv_data
>> levelmin
>> levelmax
;
537 recv_data
>> auctionSlotID
>> auctionMainCategory
>> auctionSubCategory
;
538 recv_data
>> quality
>> usable
;
540 Creature
*pCreature
= ObjectAccessor::Instance().GetCreature(*_player
, guid
);
541 if(!pCreature
||!pCreature
->isAuctioner())
544 location
= AuctioneerFactionToLocation(pCreature
->getFaction());
545 AuctionHouseObject
* mAuctions
;
546 mAuctions
= objmgr
.GetAuctionsMap( location
);
548 sLog
.outDebug("Auctionhouse search guid: " I64FMTD
", list from: %u, searchedname: %s, levelmin: %u, levelmax: %u, auctionSlotID: %u, auctionMainCategory: %u, auctionSubCategory: %u, quality: %u, usable: %u", guid
, listfrom
, searchedname
.c_str(), levelmin
, levelmax
, auctionSlotID
, auctionMainCategory
, auctionSubCategory
, quality
, usable
);
551 data
.Initialize( SMSG_AUCTION_LIST_RESULT
);
555 for (AuctionHouseObject::AuctionEntryMap::iterator itr
= mAuctions
->GetAuctionsBegin();itr
!= mAuctions
->GetAuctionsEnd();++itr
)
557 AuctionEntry
*Aentry
= itr
->second
;
558 Item
*item
= objmgr
.GetAItem(Aentry
->item_guid
);
561 ItemPrototype
const *proto
= item
->GetProto();
564 if( auctionMainCategory
== (0xffffffff) || proto
->Class
== auctionMainCategory
)
566 if( auctionSubCategory
== (0xffffffff) || proto
->SubClass
== auctionSubCategory
)
568 if( auctionSlotID
== (0xffffffff) || proto
->InventoryType
== auctionSlotID
)
570 if( quality
== (0xffffffff) || proto
->Quality
== quality
)
572 if( usable
== (0x00) || _player
->CanUseItem( item
) == EQUIP_ERR_OK
)
574 if( ( levelmin
== (0x00) || proto
->RequiredLevel
>= levelmin
) && ( levelmax
== (0x00) || proto
->RequiredLevel
<= levelmax
) )
577 std::transform( name
.begin(), name
.end(), name
.begin(), ::tolower
);
578 std::transform( searchedname
.begin(), searchedname
.end(), searchedname
.begin(), ::tolower
);
579 if( searchedname
.empty() || name
.find( searchedname
) != std::string::npos
)
581 if ((count
< 50) && (totalcount
>= listfrom
))
584 SendAuctionInfo( data
, Aentry
);
597 data
.put
<uint32
>(0, count
);
598 data
<< (uint32
) totalcount
;