root/trunk/src/arcemu-world/Quest.cpp @ 3153

Revision 3153, 13.1 kB (checked in by Hoffa, 7 months ago)

Applied 3.3.2 misc fixes by Terrorblade -> http://arcemu.org/forums/index.php?showtopic=20707

  • Property svn:eol-style set to native
  • Property ff set to
    *.cpp = svn:eol-style=native
    Makefile = svn:eol-style=native
    README = svn:eol-style=native
    CHANGELOG = svn:eol-style=native
    LICENSE = svn:eol-style=native
  • Property svn:keywords set to Date Author Rev
Line 
1/*
2 * ArcEmu MMORPG Server
3 * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
4 * Copyright (C) 2008-2010 <http://www.ArcEmu.org/>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "StdAfx.h"
22
23//Pakcet Building
24/////////////////
25
26WorldPacket* WorldSession::BuildQuestQueryResponse(Quest *qst)
27{
28        // 2048 bytes should be more than enough. The fields cost ~200 bytes.
29        // better to allocate more at startup than have to realloc the buffer later on.
30
31        WorldPacket *data = new WorldPacket(SMSG_QUEST_QUERY_RESPONSE, 2048);
32        LocalizedQuest * lci = (language>0) ? sLocalizationMgr.GetLocalizedQuest(qst->id, language) : NULL;
33        uint32 i;
34   
35        *data << uint32(qst->id);                                               // Quest ID
36        *data << uint32(2);                                                             // Unknown, always seems to be 2
37        *data << uint32(qst->max_level);                                // Quest level
38        *data << uint32(qst->min_level);                                // Quest required level
39        if(qst->quest_sort > 0)
40                *data << int32(-(int32)qst->quest_sort);        // Negative if pointing to a sort.
41        else
42                *data << uint32(qst->zone_id);                          // Positive if pointing to a zone.
43
44        *data << uint32(qst->type);                                             // Info ID / Type
45        *data << qst->suggestedplayers;                                 // suggested players
46        *data << uint32(qst->required_rep_faction);             // Faction ID
47        *data << uint32(qst->required_rep_value);               // Faction Amount
48        *data << uint32(0);                                                             // Unknown (always 0)
49        *data << uint32(0);                                                             // Unknown (always 0)
50        *data << uint32(qst->next_quest_id);                    // Next Quest ID
51        *data << uint32(0);                                                             // Column id +1 from QuestXp.dbc, entry is quest level
52        *data << uint32( sQuestMgr.GenerateRewardMoney( _player, qst ) );       // Copper reward
53        *data << uint32(qst->reward_money<0 ? -qst->reward_money : 0);          // Required Money
54        *data << uint32(qst->effect_on_player);                 // Spell casted on player upon completion
55        *data << uint32(qst->reward_spell);                             // Spell added to spellbook upon completion
56        *data << uint32(qst->bonushonor);                               // 2.3.0 - bonus honor
57        *data << float(0);                                                              // 3.3.0 - some multiplier for honor
58        *data << uint32(qst->srcitem);                                  // Item given at the start of a quest (srcitem)
59        *data << uint32(qst->quest_flags);                              // Quest Flags
60        *data << qst->rewardtitleid;                                    // 2.4.0 unk
61        *data << uint32( 0 );                                                           // playerkillcount
62        *data << qst->rewardtalents;
63        *data << uint32(0);                                                             // 3.3.0 Unknown
64        *data << uint32(0);                                                             // 3.3.0 Unknown
65    for( i = 0; i < 5; ++i )
66        *data << uint32( 0 );
67
68    for( i = 0; i < 5; ++i )
69        *data << uint32( 0 );
70
71    for( i = 0; i < 5; ++i )
72        *data << uint32( 0 );
73
74        // (loop 4 times)
75        for(i = 0; i < 4; ++i)
76        {
77                *data << qst->reward_item[i];                           // Forced Reward Item [i]
78                *data << qst->reward_itemcount[i];                      // Forced Reward Item Count [i]
79        }
80
81        // (loop 6 times)
82        for(i = 0; i < 6; ++i)
83        {
84                *data << qst->reward_choiceitem[i];                     // Choice Reward Item [i]
85                *data << qst->reward_choiceitemcount[i];        // Choice Reward Item Count [i]
86        }
87
88        // (loop 5 times) - these 3 loops are here to allow displaying rep rewards in client (not handled in core yet)
89        for(uint32 i = 0; i < 5; ++i)
90        {
91                *data << uint32(qst->reward_repfaction[i]);     // reward factions ids
92        }
93
94        for(uint32 i = 0; i < 5; ++i)
95        {
96                *data << uint32(0);                                                     // column index in QuestFactionReward.dbc but use unknown
97        }
98
99        for(uint32 i = 0; i < 5; ++i)                                   // Unknown
100        {
101                *data << uint32(0);
102        }
103
104        *data << qst->point_mapid;                                              // Unknown
105        *data << qst->point_x;                                                  // Unknown
106        *data << qst->point_y;                                                  // Unknown
107        *data << qst->point_opt;                                                // Unknown
108       
109        if(lci)
110        {
111                *data << lci->Title;
112                *data << lci->Objectives;
113                *data << lci->Details;
114                *data << lci->EndText;
115                *data << uint8(0);
116        }
117        else
118        {
119                *data << qst->title;                                            // Title / name of quest
120                *data << qst->objectives;                                       // Objectives / description
121                *data << qst->details;                                          // Details
122                *data << qst->endtext;                                          // Subdescription
123                *data << uint8(0);                                                      // most 3.3.0 quests i seen have something like "Return to NPCNAME"
124        }
125
126    *data << uint8( 0 );
127
128        for(i = 0; i < 4; ++i)
129        {
130                *data << qst->required_mob[i];                          // Kill mob entry ID [i]
131                *data << qst->required_mobcount[i];                     // Kill mob count [i]
132                *data << uint32(0);                                                     // Unknown
133                *data << uint32(0);                                                     // 3.3.0 Unknown
134        }
135
136        for(i = 0; i < 6; ++i)
137        {
138                *data << qst->required_item[i];                         // Collect item [i]
139                *data << qst->required_itemcount[i];            // Collect item count [i]
140        }
141
142        if(lci)
143        {
144                *data << lci->ObjectiveText[0];
145                *data << lci->ObjectiveText[1];
146                *data << lci->ObjectiveText[2];
147                *data << lci->ObjectiveText[3];
148        }
149        else
150        {
151                *data << qst->objectivetexts[0];                                // Objective 1 - Used as text if mob not set
152                *data << qst->objectivetexts[1];                                // Objective 2 - Used as text if mob not set
153                *data << qst->objectivetexts[2];                                // Objective 3 - Used as text if mob not set
154                *data << qst->objectivetexts[3];                                // Objective 4 - Used as text if mob not set
155        }
156
157        return data;
158}
159
160
161/*****************
162* QuestLogEntry *
163*****************/
164QuestLogEntry::QuestLogEntry()
165{
166        mInitialized = false;
167        m_quest = NULL;
168        mDirty = false;
169        m_slot = -1;
170        completed= 0;
171}
172
173QuestLogEntry::~QuestLogEntry()
174{
175
176}
177
178void QuestLogEntry::Init(Quest* quest, Player* plr, uint32 slot)
179{
180        Arcemu::Util::ARCEMU_ASSERT(   quest != NULL );
181        Arcemu::Util::ARCEMU_ASSERT(   plr != NULL );
182
183        m_quest = quest;
184        m_plr = plr;
185        m_slot = slot;
186
187        iscastquest = false;
188        isemotequest = false;
189        for(uint32 i = 0; i < 4; ++i)
190        {
191                if( quest->required_spell[i] != 0 )
192                {
193                        iscastquest = true;
194                        if( !plr->HasQuestSpell(quest->required_spell[i]) )
195                                plr->quest_spells.insert(quest->required_spell[i]);
196                }
197                else if( quest->required_emote[i] != 0 )
198                {
199                        isemotequest = true;
200                }
201                if( quest->required_mob[i] != 0 )
202                {
203                        if( !plr->HasQuestMob(quest->required_mob[i]) )
204                                plr->quest_mobs.insert(quest->required_mob[i]);
205                }
206        }
207
208
209        // update slot
210        plr->SetQuestLogSlot(this, slot);
211       
212        mDirty = true;
213
214        memset(m_mobcount, 0, 4*4);
215        memset(m_explored_areas, 0, 4*4);
216
217        if(m_quest->time)
218                m_time_left = m_quest->time;
219        else
220                m_time_left = 0;
221
222        CALL_QUESTSCRIPT_EVENT(this, OnQuestStart)(plr, this);
223}
224
225void QuestLogEntry::ClearAffectedUnits()
226{
227        if (m_affected_units.size()>0)
228                m_affected_units.clear();
229}
230void QuestLogEntry::AddAffectedUnit(Unit* target)
231{
232        if (!target)
233                return;
234        if (!IsUnitAffected(target))
235                m_affected_units.insert(target->GetGUID());
236}
237bool QuestLogEntry::IsUnitAffected(Unit* target)
238{
239        if (!target)
240                return true;
241        if (m_affected_units.find(target->GetGUID()) != m_affected_units.end())
242                return true;
243        return false;
244}
245
246void QuestLogEntry::SaveToDB(QueryBuffer * buf)
247{
248        Arcemu::Util::ARCEMU_ASSERT(   m_slot != -1);
249        if(!mDirty)
250                return;
251
252        std::stringstream ss;
253
254    ss << "DELETE FROM questlog WHERE player_guid = ";
255    ss << m_plr->GetLowGUID();
256    ss << " AND quest_id = ";
257    ss << m_quest->id;
258    ss << ";";
259
260    if( buf == NULL )
261                CharacterDatabase.Execute( ss.str().c_str() );
262        else
263                buf->AddQueryStr(ss.str());
264
265    ss.rdbuf()->str("");
266
267        ss << "INSERT INTO questlog VALUES(";
268        ss << m_plr->GetLowGUID() << "," << m_quest->id << "," << m_slot << "," << m_time_left;
269        for(int i = 0; i < 4; ++i)
270                ss << "," << m_explored_areas[i];
271       
272        for(int i = 0; i < 4; ++i)
273                ss << "," << m_mobcount[i];
274
275    ss << "," << uint32( completed );
276
277        ss << ")";
278       
279        if( buf == NULL )
280                CharacterDatabase.Execute( ss.str().c_str() );
281        else
282                buf->AddQueryStr(ss.str());
283}
284
285bool QuestLogEntry::LoadFromDB(Field *fields)
286{
287        // playerguid,questid,timeleft,area0,area1,area2,area3,kill0,kill1,kill2,kill3
288        int f = 3;
289        Arcemu::Util::ARCEMU_ASSERT(   m_plr && m_quest);
290        m_time_left = fields[f].GetUInt32();    f++;
291        for(int i = 0; i < 4; ++i)
292        {
293                m_explored_areas[i] = fields[f].GetUInt32();    f++;
294                CALL_QUESTSCRIPT_EVENT(this, OnExploreArea)(m_explored_areas[i], m_plr, this);
295        }
296
297        for(int i = 0; i < 4; ++i)
298        {
299                m_mobcount[i] = fields[f].GetUInt32();  f++;
300                if(GetQuest()->required_mobtype[i] == QUEST_MOB_TYPE_CREATURE)
301                {
302                        CALL_QUESTSCRIPT_EVENT(this, OnCreatureKill)(GetQuest()->required_mob[i], m_plr, this);
303                }
304                else
305                {
306                        CALL_QUESTSCRIPT_EVENT(this, OnGameObjectActivate)(GetQuest()->required_mob[i], m_plr, this);
307                }
308        }
309
310    completed = fields[f].GetUInt32();
311
312        mDirty = false;
313        return true;
314}
315
316bool QuestLogEntry::CanBeFinished()
317{
318        uint32 i;
319
320    if( m_quest->iscompletedbyspelleffect && !completed )
321        return false;
322
323    if( completed )
324        return true;
325
326        for(i = 0; i < 4; ++i)
327        {
328                if(m_quest->required_mob[i])
329                {
330                        if(m_mobcount[i] < m_quest->required_mobcount[i])
331                        {
332                                return false;
333                        }
334                }
335                if( m_quest->required_spell[i] ) // requires spell cast, with no required target
336                {
337                        if( m_mobcount[i] == 0 || m_mobcount[i] < m_quest->required_mobcount[i] )
338                        {
339                                return false;
340                        }
341                }
342                if( m_quest->required_emote[i] ) // requires emote, with no required target
343                {
344                        if( m_mobcount[i] == 0 || m_mobcount[i] < m_quest->required_mobcount[i] )
345                        {
346                                return false;
347                        }
348                }
349        }
350
351        for(i = 0; i < 4; ++i)
352        {
353                if(m_quest->required_item[i])
354                {
355                        if(m_plr->GetItemInterface()->GetItemCount(m_quest->required_item[i]) < m_quest->required_itemcount[i])
356                        {
357                                return false;
358                        }
359                }
360        }
361
362        //Check for Gold & AreaTrigger Requirements
363        if ( m_quest->reward_money < 0 && m_plr->GetGold() < uint32(-m_quest->reward_money) )
364                return false;
365
366        for(i = 0; i < 4; ++i)
367        {
368                if(m_quest->required_triggers[i])
369                {
370                        if(m_explored_areas[i] == 0)
371                                return false;
372                }
373        }
374
375        return true;
376}
377
378void QuestLogEntry::SubtractTime(uint32 value)
379{
380        if(this->m_time_left  <=value)
381                m_time_left = 0;
382        else
383                m_time_left-=value;
384}
385
386void QuestLogEntry::SetMobCount(uint32 i, uint32 count)
387{
388        Arcemu::Util::ARCEMU_ASSERT(   i<4);
389        m_mobcount[i] = count;
390        mDirty = true;
391}
392
393void QuestLogEntry::IncrementMobCount(uint32 i)
394{
395        Arcemu::Util::ARCEMU_ASSERT(   i<4);
396        ++m_mobcount[i];
397        mDirty = true;
398}
399
400void QuestLogEntry::SetTrigger(uint32 i)
401{
402        Arcemu::Util::ARCEMU_ASSERT(   i<4);
403        m_explored_areas[i] = 1;
404        mDirty = true;
405}
406
407void QuestLogEntry::SetSlot(int32 i)
408{
409        Arcemu::Util::ARCEMU_ASSERT(   i!=-1);
410        m_slot = i;
411}
412
413void QuestLogEntry::Finish()
414{
415        uint32 base = GetBaseField(m_slot);
416        m_plr->SetUInt32Value(base + 0, 0);
417        m_plr->SetUInt32Value(base + 1, 0);
418        m_plr->SetUInt32Value(base + 2, 0);
419
420        // clear from player log
421        m_plr->SetQuestLogSlot(NULL, m_slot);
422        m_plr->PushToRemovedQuests(m_quest->id);
423        m_plr->UpdateNearbyGameObjects();
424        // delete ourselves
425
426        delete this;
427}
428
429void QuestLogEntry::UpdatePlayerFields()
430{
431        if(!m_plr)
432                return;
433
434        uint32 base = GetBaseField(m_slot);
435        m_plr->SetUInt32Value(base + 0, m_quest->id);
436        uint32 field0 = 0; // 0x01000000 = "Objective Complete" - 0x02 = Quest Failed - 0x04 = Quest Accepted
437
438        // next field is count (kills, etc)
439        uint64 field1 = 0;
440
441        // explored areas
442        if(m_quest->count_requiredtriggers)
443        {
444                uint32 count = 0;
445                for(int i = 0; i < 4; ++i)
446                {
447                        if(m_quest->required_triggers[i])
448                        {
449                                if(m_explored_areas[i] == 1)
450                                {
451                                        count++;
452                                }
453                        }
454                }
455
456                if(count == m_quest->count_requiredtriggers)
457                {
458                        field1 |= 0x01000000;
459                }
460        }
461
462        // spell casts / emotes
463        if( iscastquest )
464        {
465                bool cast_complete = true;
466                for(int i = 0; i < 4; ++i)
467                {
468                        if( m_quest->required_spell[i] && m_quest->required_mobcount[i] > m_mobcount[i] )
469                        {
470                                cast_complete = false;
471                                break;
472                        }
473                }
474                if( cast_complete )
475                {
476                        field0 |= 0x01000000; // "Objective Complete"
477                }
478        }
479        else if( isemotequest )
480        {
481                bool emote_complete = true;
482                for( int i = 0; i < 4; ++i )
483                {
484                        if( m_quest->required_emote[i] && m_quest->required_mobcount[i] > m_mobcount[i] )
485                        {
486                                emote_complete = false;
487                                break;
488                        }
489                }
490                if( emote_complete )
491                {
492                        field0 |= 0x01000000; // "Objective Complete"
493                }
494        }
495
496        // mob hunting / counter
497        if(m_quest->count_required_mob)
498        {
499                /*uint8 cnt;
500                for(int i = 0; i < 4; ++i)
501                {
502                        if(m_quest->required_mob[i] && m_mobcount[i] > 0)
503                        {
504                                // 1 << (offset * 6)
505                                cnt = m_mobcount[i];
506                                field1 |= (cnt << (i*8));
507                        }
508                }*/
509
510                // optimized this - burlex
511                uint8* p = (uint8*)&field1;
512                for(int i = 0; i < 4; ++i)
513                {
514                        if( m_quest->required_mob[i] && m_mobcount[i] > 0 )
515                                p[2*i] |= (uint8)m_mobcount[i];
516                }
517        }
518
519        m_plr->SetUInt32Value(base + 1, field0);
520        m_plr->SetUInt64Value(base + 2, field1);
521        m_plr->SetUInt32Value(base + 3, ( m_time_left ? (uint32)(UNIXTIME+m_time_left/1000) : 0 ) );
522}
523
524void QuestLogEntry::SendQuestComplete()
525{
526        WorldPacket data(4);
527        data.SetOpcode(SMSG_QUESTUPDATE_COMPLETE);
528        data << m_quest->id;
529        m_plr->GetSession()->SendPacket(&data);
530        m_plr->UpdateNearbyGameObjects();
531        CALL_QUESTSCRIPT_EVENT(this, OnQuestComplete)(m_plr, this);
532}
533
534void QuestLogEntry::SendUpdateAddKill(uint32 i)
535{
536        sQuestMgr.SendQuestUpdateAddKill(m_plr, m_quest->id, m_quest->required_mob[i], m_mobcount[i], m_quest->required_mobcount[i], 0);
537}
538
539void QuestLogEntry::Complete(){
540    completed = 1;
541}
Note: See TracBrowser for help on using the browser.