2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
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
21 #include "WorldPacket.h"
22 #include "WorldSession.h"
25 #include "ObjectMgr.h"
27 #include "GossipDef.h"
29 #include "ObjectAccessor.h"
30 #include "ScriptCalls.h"
33 void WorldSession::HandleQuestgiverStatusQueryOpcode( WorldPacket
& recv_data
)
37 uint8 questStatus
= DIALOG_STATUS_NONE
;
38 uint8 defstatus
= DIALOG_STATUS_NONE
;
40 Object
* questgiver
= ObjectAccessor::GetObjectByTypeMask(*_player
, guid
,TYPEMASK_UNIT
|TYPEMASK_GAMEOBJECT
);
43 sLog
.outDetail("Error in CMSG_QUESTGIVER_STATUS_QUERY, called for not found questgiver (Typeid: %u GUID: %u)",GuidHigh2TypeId(GUID_HIPART(guid
)),GUID_LOPART(guid
));
47 switch(questgiver
->GetTypeId())
51 sLog
.outDebug( "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for npc, guid = %u",uint32(GUID_LOPART(guid
)) );
52 Creature
* cr_questgiver
=(Creature
*)questgiver
;
53 if( !cr_questgiver
->IsHostileTo(_player
)) // not show quest status to enemies
55 questStatus
= Script
->NPCDialogStatus(_player
, cr_questgiver
);
57 questStatus
= getDialogStatus(_player
, cr_questgiver
, defstatus
);
61 case TYPEID_GAMEOBJECT
:
63 sLog
.outDebug( "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for GameObject guid = %u",uint32(GUID_LOPART(guid
)) );
64 GameObject
* go_questgiver
=(GameObject
*)questgiver
;
65 questStatus
= Script
->GODialogStatus(_player
, go_questgiver
);
67 questStatus
= getDialogStatus(_player
, go_questgiver
, defstatus
);
71 sLog
.outError("QuestGiver called for unexpected type %u", questgiver
->GetTypeId());
75 //inform client about status of quest
76 _player
->PlayerTalkClass
->SendQuestGiverStatus(questStatus
, guid
);
79 void WorldSession::HandleQuestgiverHelloOpcode(WorldPacket
& recv_data
)
84 sLog
.outDebug ("WORLD: Received CMSG_QUESTGIVER_HELLO npc = %u", GUID_LOPART(guid
));
86 Creature
*pCreature
= GetPlayer()->GetNPCIfCanInteractWith(guid
, UNIT_NPC_FLAG_NONE
);
90 sLog
.outDebug ("WORLD: HandleQuestgiverHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(guid
));
95 if (GetPlayer()->hasUnitState(UNIT_STAT_DIED
))
96 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH
);
98 // Stop the npc if moving
99 if (!pCreature
->IsStopped())
100 pCreature
->StopMoving();
102 if (Script
->GossipHello(_player
, pCreature
))
105 _player
->PrepareGossipMenu(pCreature
, pCreature
->GetCreatureInfo()->GossipMenuId
);
106 _player
->SendPreparedGossip(pCreature
);
109 void WorldSession::HandleQuestgiverAcceptQuestOpcode( WorldPacket
& recv_data
)
114 recv_data
>> guid
>> quest
>> unk1
;
116 if(!GetPlayer()->isAlive())
119 sLog
.outDebug( "WORLD: Received CMSG_QUESTGIVER_ACCEPT_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid
)), quest
, unk1
);
121 Object
* pObject
= ObjectAccessor::GetObjectByTypeMask(*_player
, guid
,TYPEMASK_UNIT
|TYPEMASK_GAMEOBJECT
|TYPEMASK_ITEM
|TYPEMASK_PLAYER
);
123 // no or incorrect quest giver
125 || (pObject
->GetTypeId()!=TYPEID_PLAYER
&& !pObject
->hasQuest(quest
))
126 || (pObject
->GetTypeId()==TYPEID_PLAYER
&& !((Player
*)pObject
)->CanShareQuest(quest
))
129 _player
->PlayerTalkClass
->CloseGossip();
130 _player
->SetDivider( 0 );
134 Quest
const* qInfo
= sObjectMgr
.GetQuestTemplate(quest
);
138 if(!GetPlayer()->CanTakeQuest(qInfo
,true) )
140 _player
->PlayerTalkClass
->CloseGossip();
141 _player
->SetDivider( 0 );
145 if( _player
->GetDivider() != 0 )
147 Player
*pPlayer
= ObjectAccessor::FindPlayer( _player
->GetDivider() );
150 pPlayer
->SendPushToPartyResponse( _player
, QUEST_PARTY_MSG_ACCEPT_QUEST
);
151 _player
->SetDivider( 0 );
155 if( _player
->CanAddQuest( qInfo
, true ) )
157 _player
->AddQuest( qInfo
, pObject
);
159 if (qInfo
->HasFlag(QUEST_FLAGS_PARTY_ACCEPT
))
161 if (Group
* pGroup
= _player
->GetGroup())
163 for(GroupReference
*itr
= pGroup
->GetFirstMember(); itr
!= NULL
; itr
= itr
->next())
165 Player
* pPlayer
= itr
->getSource();
167 if (!pPlayer
|| pPlayer
== _player
) // not self
170 if (pPlayer
->CanTakeQuest(qInfo
, true))
172 pPlayer
->SetDivider(_player
->GetGUID());
174 //need confirmation that any gossip window will close
175 pPlayer
->PlayerTalkClass
->CloseGossip();
177 _player
->SendQuestConfirmAccept(qInfo
, pPlayer
);
183 if ( _player
->CanCompleteQuest( quest
) )
184 _player
->CompleteQuest( quest
);
186 switch(pObject
->GetTypeId())
189 Script
->QuestAccept(_player
, ((Creature
*)pObject
), qInfo
);
192 case TYPEID_CONTAINER
:
194 Script
->ItemQuestAccept(_player
, ((Item
*)pObject
), qInfo
);
196 // destroy not required for quest finish quest starting item
197 bool destroyItem
= true;
198 for(int i
= 0; i
< QUEST_ITEM_OBJECTIVES_COUNT
; ++i
)
200 if ((qInfo
->ReqItemId
[i
] == ((Item
*)pObject
)->GetEntry()) && (((Item
*)pObject
)->GetProto()->MaxCount
> 0))
208 _player
->DestroyItem(((Item
*)pObject
)->GetBagSlot(), ((Item
*)pObject
)->GetSlot(), true);
212 case TYPEID_GAMEOBJECT
:
213 Script
->GOQuestAccept(_player
, ((GameObject
*)pObject
), qInfo
);
216 _player
->PlayerTalkClass
->CloseGossip();
218 if( qInfo
->GetSrcSpell() > 0 )
219 _player
->CastSpell( _player
, qInfo
->GetSrcSpell(), true);
225 _player
->PlayerTalkClass
->CloseGossip();
228 void WorldSession::HandleQuestgiverQueryQuestOpcode( WorldPacket
& recv_data
)
233 recv_data
>> guid
>> quest
>> unk1
;
234 sLog
.outDebug( "WORLD: Received CMSG_QUESTGIVER_QUERY_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid
)), quest
, unk1
);
236 // Verify that the guid is valid and is a questgiver or involved in the requested quest
237 Object
* pObject
= ObjectAccessor::GetObjectByTypeMask(*_player
, guid
,TYPEMASK_UNIT
|TYPEMASK_GAMEOBJECT
|TYPEMASK_ITEM
);
238 if(!pObject
||!pObject
->hasQuest(quest
) && !pObject
->hasInvolvedQuest(quest
))
240 _player
->PlayerTalkClass
->CloseGossip();
244 Quest
const* pQuest
= sObjectMgr
.GetQuestTemplate(quest
);
247 _player
->PlayerTalkClass
->SendQuestGiverQuestDetails(pQuest
, pObject
->GetGUID(), true);
251 void WorldSession::HandleQuestQueryOpcode( WorldPacket
& recv_data
)
255 sLog
.outDebug( "WORLD: Received CMSG_QUEST_QUERY quest = %u",quest
);
257 Quest
const *pQuest
= sObjectMgr
.GetQuestTemplate(quest
);
260 _player
->PlayerTalkClass
->SendQuestQueryResponse( pQuest
);
264 void WorldSession::HandleQuestgiverChooseRewardOpcode( WorldPacket
& recv_data
)
266 uint32 quest
, reward
;
268 recv_data
>> guid
>> quest
>> reward
;
270 if(reward
>= QUEST_REWARD_CHOICES_COUNT
)
272 sLog
.outError("Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player %s (guid %d) tried to get invalid reward (%u) (probably packet hacking)", _player
->GetName(), _player
->GetGUIDLow(), reward
);
276 if(!GetPlayer()->isAlive())
279 sLog
.outDebug( "WORLD: Received CMSG_QUESTGIVER_CHOOSE_REWARD npc = %u, quest = %u, reward = %u",uint32(GUID_LOPART(guid
)),quest
,reward
);
281 Object
* pObject
= ObjectAccessor::GetObjectByTypeMask(*_player
, guid
,TYPEMASK_UNIT
|TYPEMASK_GAMEOBJECT
);
285 if(!pObject
->hasInvolvedQuest(quest
))
288 Quest
const *pQuest
= sObjectMgr
.GetQuestTemplate(quest
);
291 if( _player
->CanRewardQuest( pQuest
, reward
, true ) )
293 _player
->RewardQuest( pQuest
, reward
, pObject
);
295 switch(pObject
->GetTypeId())
298 if( !(Script
->ChooseReward( _player
, ((Creature
*)pObject
), pQuest
, reward
)) )
301 if(Quest
const* nextquest
= _player
->GetNextQuest( guid
,pQuest
) )
302 _player
->PlayerTalkClass
->SendQuestGiverQuestDetails(nextquest
,guid
,true);
305 case TYPEID_GAMEOBJECT
:
306 if( !Script
->GOChooseReward( _player
, ((GameObject
*)pObject
), pQuest
, reward
) )
309 if(Quest
const* nextquest
= _player
->GetNextQuest( guid
,pQuest
) )
310 _player
->PlayerTalkClass
->SendQuestGiverQuestDetails(nextquest
,guid
,true);
316 _player
->PlayerTalkClass
->SendQuestGiverOfferReward( pQuest
, guid
, true );
320 void WorldSession::HandleQuestgiverRequestRewardOpcode( WorldPacket
& recv_data
)
324 recv_data
>> guid
>> quest
;
326 if(!GetPlayer()->isAlive())
329 sLog
.outDebug( "WORLD: Received CMSG_QUESTGIVER_REQUEST_REWARD npc = %u, quest = %u",uint32(GUID_LOPART(guid
)),quest
);
331 Object
* pObject
= ObjectAccessor::GetObjectByTypeMask(*_player
, guid
,TYPEMASK_UNIT
|TYPEMASK_GAMEOBJECT
);
332 if(!pObject
||!pObject
->hasInvolvedQuest(quest
))
335 if ( _player
->CanCompleteQuest( quest
) )
336 _player
->CompleteQuest( quest
);
338 if( _player
->GetQuestStatus( quest
) != QUEST_STATUS_COMPLETE
)
341 if(Quest
const *pQuest
= sObjectMgr
.GetQuestTemplate(quest
))
342 _player
->PlayerTalkClass
->SendQuestGiverOfferReward( pQuest
, guid
, true );
345 void WorldSession::HandleQuestgiverCancel(WorldPacket
& /*recv_data*/ )
347 sLog
.outDebug( "WORLD: Received CMSG_QUESTGIVER_CANCEL" );
349 _player
->PlayerTalkClass
->CloseGossip();
352 void WorldSession::HandleQuestLogSwapQuest(WorldPacket
& recv_data
)
355 recv_data
>> slot1
>> slot2
;
357 if(slot1
== slot2
|| slot1
>= MAX_QUEST_LOG_SIZE
|| slot2
>= MAX_QUEST_LOG_SIZE
)
360 sLog
.outDebug( "WORLD: Received CMSG_QUESTLOG_SWAP_QUEST slot 1 = %u, slot 2 = %u", slot1
, slot2
);
362 GetPlayer()->SwapQuestSlot(slot1
,slot2
);
365 void WorldSession::HandleQuestLogRemoveQuest(WorldPacket
& recv_data
)
370 sLog
.outDebug( "WORLD: Received CMSG_QUESTLOG_REMOVE_QUEST slot = %u",slot
);
372 if( slot
< MAX_QUEST_LOG_SIZE
)
374 if(uint32 quest
= _player
->GetQuestSlotQuestId(slot
))
376 if(!_player
->TakeQuestSourceItem( quest
, true ))
377 return; // can't un-equip some items, reject quest cancel
379 if (const Quest
*pQuest
= sObjectMgr
.GetQuestTemplate(quest
))
381 if (pQuest
->HasFlag(QUEST_MANGOS_FLAGS_TIMED
))
382 _player
->RemoveTimedQuest(quest
);
385 _player
->SetQuestStatus( quest
, QUEST_STATUS_NONE
);
388 _player
->SetQuestSlot(slot
, 0);
390 _player
->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED
, 1);
394 void WorldSession::HandleQuestConfirmAccept(WorldPacket
& recv_data
)
399 sLog
.outDebug("WORLD: Received CMSG_QUEST_CONFIRM_ACCEPT quest = %u", quest
);
401 if (const Quest
* pQuest
= sObjectMgr
.GetQuestTemplate(quest
))
403 if (!pQuest
->HasFlag(QUEST_FLAGS_PARTY_ACCEPT
))
406 Player
* pOriginalPlayer
= ObjectAccessor::FindPlayer(_player
->GetDivider());
408 if (!pOriginalPlayer
)
411 if (pQuest
->GetType() == QUEST_TYPE_RAID
)
413 if (!_player
->IsInSameRaidWith(pOriginalPlayer
))
418 if (!_player
->IsInSameGroupWith(pOriginalPlayer
))
422 if (_player
->CanAddQuest(pQuest
, true))
423 _player
->AddQuest(pQuest
, NULL
); // NULL, this prevent DB script from duplicate running
425 _player
->SetDivider(0);
429 void WorldSession::HandleQuestgiverCompleteQuest(WorldPacket
& recv_data
)
433 recv_data
>> guid
>> quest
;
435 if(!GetPlayer()->isAlive())
438 sLog
.outDebug( "WORLD: Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %u, quest = %u",uint32(GUID_LOPART(guid
)),quest
);
440 Quest
const *pQuest
= sObjectMgr
.GetQuestTemplate(quest
);
443 if( _player
->GetQuestStatus( quest
) != QUEST_STATUS_COMPLETE
)
445 if( pQuest
->IsRepeatable() )
446 _player
->PlayerTalkClass
->SendQuestGiverRequestItems(pQuest
, guid
, _player
->CanCompleteRepeatableQuest(pQuest
), false);
448 _player
->PlayerTalkClass
->SendQuestGiverRequestItems(pQuest
, guid
, _player
->CanRewardQuest(pQuest
,false), false);
452 if(pQuest
->GetReqItemsCount()) // some items required
453 _player
->PlayerTalkClass
->SendQuestGiverRequestItems(pQuest
, guid
, _player
->CanRewardQuest(pQuest
,false), false);
454 else // no items required
455 _player
->PlayerTalkClass
->SendQuestGiverOfferReward(pQuest
, guid
, true);
460 void WorldSession::HandleQuestgiverQuestAutoLaunch(WorldPacket
& /*recvPacket*/)
462 sLog
.outDebug( "WORLD: Received CMSG_QUESTGIVER_QUEST_AUTOLAUNCH" );
465 void WorldSession::HandlePushQuestToParty(WorldPacket
& recvPacket
)
468 recvPacket
>> questId
;
470 sLog
.outDebug("WORLD: Received CMSG_PUSHQUESTTOPARTY quest = %u", questId
);
472 if (Quest
const *pQuest
= sObjectMgr
.GetQuestTemplate(questId
))
474 if (Group
* pGroup
= _player
->GetGroup())
476 for(GroupReference
*itr
= pGroup
->GetFirstMember(); itr
!= NULL
; itr
= itr
->next())
478 Player
*pPlayer
= itr
->getSource();
480 if (!pPlayer
|| pPlayer
== _player
) // skip self
483 _player
->SendPushToPartyResponse(pPlayer
, QUEST_PARTY_MSG_SHARING_QUEST
);
485 if (!pPlayer
->SatisfyQuestStatus(pQuest
, false))
487 _player
->SendPushToPartyResponse(pPlayer
, QUEST_PARTY_MSG_HAVE_QUEST
);
491 if (pPlayer
->GetQuestStatus(questId
) == QUEST_STATUS_COMPLETE
)
493 _player
->SendPushToPartyResponse(pPlayer
, QUEST_PARTY_MSG_FINISH_QUEST
);
497 if (!pPlayer
->CanTakeQuest(pQuest
, false))
499 _player
->SendPushToPartyResponse(pPlayer
, QUEST_PARTY_MSG_CANT_TAKE_QUEST
);
503 if (!pPlayer
->SatisfyQuestLog(false))
505 _player
->SendPushToPartyResponse(pPlayer
, QUEST_PARTY_MSG_LOG_FULL
);
509 if (pPlayer
->GetDivider() != 0)
511 _player
->SendPushToPartyResponse(pPlayer
, QUEST_PARTY_MSG_BUSY
);
515 pPlayer
->PlayerTalkClass
->SendQuestGiverQuestDetails(pQuest
, _player
->GetGUID(), true);
516 pPlayer
->SetDivider(_player
->GetGUID());
522 void WorldSession::HandleQuestPushResult(WorldPacket
& recvPacket
)
526 recvPacket
>> guid
>> msg
;
528 sLog
.outDebug( "WORLD: Received MSG_QUEST_PUSH_RESULT" );
530 if( _player
->GetDivider() != 0 )
532 Player
*pPlayer
= ObjectAccessor::FindPlayer( _player
->GetDivider() );
535 WorldPacket
data( MSG_QUEST_PUSH_RESULT
, (8+1) );
536 data
<< uint64(guid
);
537 data
<< uint8(msg
); // valid values: 0-8
538 pPlayer
->GetSession()->SendPacket(&data
);
539 _player
->SetDivider( 0 );
544 uint32
WorldSession::getDialogStatus(Player
*pPlayer
, Object
* questgiver
, uint32 defstatus
)
546 uint32 result
= defstatus
;
548 QuestRelations
const* qir
;
549 QuestRelations
const* qr
;
551 switch(questgiver
->GetTypeId())
553 case TYPEID_GAMEOBJECT
:
555 qir
= &sObjectMgr
.mGOQuestInvolvedRelations
;
556 qr
= &sObjectMgr
.mGOQuestRelations
;
561 qir
= &sObjectMgr
.mCreatureQuestInvolvedRelations
;
562 qr
= &sObjectMgr
.mCreatureQuestRelations
;
566 //its imposible, but check ^)
567 sLog
.outError("Warning: GetDialogStatus called for unexpected type %u", questgiver
->GetTypeId());
568 return DIALOG_STATUS_NONE
;
571 for(QuestRelations::const_iterator i
= qir
->lower_bound(questgiver
->GetEntry()); i
!= qir
->upper_bound(questgiver
->GetEntry()); ++i
)
574 uint32 quest_id
= i
->second
;
575 Quest
const *pQuest
= sObjectMgr
.GetQuestTemplate(quest_id
);
576 if ( !pQuest
) continue;
578 QuestStatus status
= pPlayer
->GetQuestStatus( quest_id
);
579 if( (status
== QUEST_STATUS_COMPLETE
&& !pPlayer
->GetQuestRewardStatus(quest_id
)) ||
580 (pQuest
->IsAutoComplete() && pPlayer
->CanTakeQuest(pQuest
, false)) )
582 if ( pQuest
->IsAutoComplete() && pQuest
->IsRepeatable() )
583 result2
= DIALOG_STATUS_REWARD_REP
;
585 result2
= DIALOG_STATUS_REWARD
;
587 else if ( status
== QUEST_STATUS_INCOMPLETE
)
588 result2
= DIALOG_STATUS_INCOMPLETE
;
590 if (result2
> result
)
594 for(QuestRelations::const_iterator i
= qr
->lower_bound(questgiver
->GetEntry()); i
!= qr
->upper_bound(questgiver
->GetEntry()); ++i
)
597 uint32 quest_id
= i
->second
;
598 Quest
const *pQuest
= sObjectMgr
.GetQuestTemplate(quest_id
);
602 QuestStatus status
= pPlayer
->GetQuestStatus( quest_id
);
603 if ( status
== QUEST_STATUS_NONE
)
605 if ( pPlayer
->CanSeeStartQuest( pQuest
) )
607 if ( pPlayer
->SatisfyQuestLevel(pQuest
, false) )
609 if ( pQuest
->IsAutoComplete() || (pQuest
->IsRepeatable() && pPlayer
->getQuestStatusMap()[quest_id
].m_rewarded
))
610 result2
= DIALOG_STATUS_REWARD_REP
;
611 else if (pPlayer
->getLevel() <= pPlayer
->GetQuestLevelForPlayer(pQuest
) + sWorld
.getConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF
) )
613 if (pQuest
->HasFlag(QUEST_FLAGS_DAILY
))
614 result2
= DIALOG_STATUS_AVAILABLE_REP
;
616 result2
= DIALOG_STATUS_AVAILABLE
;
619 result2
= DIALOG_STATUS_CHAT
;
622 result2
= DIALOG_STATUS_UNAVAILABLE
;
626 if (result2
> result
)
633 void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket
& /*recvPacket*/)
635 sLog
.outDebug("WORLD: Received CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY");
639 WorldPacket
data(SMSG_QUESTGIVER_STATUS_MULTIPLE
, 4);
640 data
<< uint32(count
); // placeholder
642 for(Player::ClientGUIDs::const_iterator itr
= _player
->m_clientGUIDs
.begin(); itr
!= _player
->m_clientGUIDs
.end(); ++itr
)
644 uint8 questStatus
= DIALOG_STATUS_NONE
;
645 uint8 defstatus
= DIALOG_STATUS_NONE
;
647 if (IS_CREATURE_OR_PET_GUID(*itr
))
649 // need also pet quests case support
650 Creature
*questgiver
= GetPlayer()->GetMap()->GetCreatureOrPetOrVehicle(*itr
);
651 if(!questgiver
|| questgiver
->IsHostileTo(_player
))
653 if(!questgiver
->HasFlag(UNIT_NPC_FLAGS
, UNIT_NPC_FLAG_QUESTGIVER
))
655 questStatus
= Script
->NPCDialogStatus(_player
, questgiver
);
656 if( questStatus
> 6 )
657 questStatus
= getDialogStatus(_player
, questgiver
, defstatus
);
659 data
<< uint64(questgiver
->GetGUID());
660 data
<< uint8(questStatus
);
663 else if(IS_GAMEOBJECT_GUID(*itr
))
665 GameObject
*questgiver
= GetPlayer()->GetMap()->GetGameObject(*itr
);
668 if(questgiver
->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER
)
670 questStatus
= Script
->GODialogStatus(_player
, questgiver
);
671 if( questStatus
> 6 )
672 questStatus
= getDialogStatus(_player
, questgiver
, defstatus
);
674 data
<< uint64(questgiver
->GetGUID());
675 data
<< uint8(questStatus
);
680 data
.put
<uint32
>(0, count
); // write real count