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

Revision 3152, 12.4 kB (checked in by AlexisB, 7 months ago)

ADDED: Some more quest stuff from Mangos. Quests should no longer crash the client!

  • 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( 0 );
39
40        if(qst->quest_sort > 0)
41                *data << int32(-(int32)qst->quest_sort);          // Negative if pointing to a sort.
42        else
43                *data << uint32(qst->zone_id);                    // Positive if pointing to a zone.
44
45        *data << uint32(qst->type);                                      // Info ID / Type
46        *data << qst->suggestedplayers;                                                         // suggested players
47        *data << uint32(qst->required_rep_faction);      // Faction ID
48        *data << uint32(qst->required_rep_value);          // Faction Amount
49        *data << uint32(0);                                                      // Unknown (always 0)
50        *data << uint32(0);                                                      // Unknown (always 0)
51        *data << uint32(qst->next_quest_id);                    // Next Quest ID
52    *data << uint32( 0 );
53        *data << uint32( sQuestMgr.GenerateRewardMoney( _player, qst ) );                        // Copper reward
54        *data << uint32(qst->reward_money<0 ? -qst->reward_money : 0);             // Required Money
55        *data << uint32(qst->effect_on_player);          // Spell casted on player upon completion
56        *data << uint32(qst->reward_spell);                      // Spell added to spellbook upon completion
57    *data << float( 0 );
58        *data << qst->bonushonor;                                                               // 2.3.0 - bonus honor
59        *data << uint32(qst->srcitem);                            // Item given at the start of a quest (srcitem)
60        *data << uint32(qst->quest_flags);                        // Quest Flags
61        *data << qst->rewardtitleid;                                                            // 2.4.0 unk
62        *data << uint32( 0 );                                                           // playerkillcount
63        *data << qst->rewardtalents;
64    *data << uint32( 0 );
65    *data << uint32( 0 );
66
67    for( i = 0; i < 5; ++i )
68        *data << uint32( 0 );
69
70    for( i = 0; i < 5; ++i )
71        *data << uint32( 0 );
72
73    for( i = 0; i < 5; ++i )
74        *data << uint32( 0 );
75
76        // (loop 4 times)
77        for(i = 0; i < 4; ++i)
78        {
79                *data << qst->reward_item[i];                      // Forced Reward Item [i]
80                *data << qst->reward_itemcount[i];                // Forced Reward Item Count [i]
81        }
82
83        // (loop 6 times)
84        for(i = 0; i < 6; ++i)
85        {
86                *data << qst->reward_choiceitem[i];              // Choice Reward Item [i]
87                *data << qst->reward_choiceitemcount[i];        // Choice Reward Item Count [i]
88        }
89
90        *data << qst->point_mapid;                                        // Unknown
91        *data << qst->point_x;                                            // Unknown
92        *data << qst->point_y;                                            // Unknown
93        *data << qst->point_opt;                                                // Unknown
94       
95        if(lci)
96        {
97                *data << lci->Title;
98                *data << lci->Objectives;
99                *data << lci->Details;
100                *data << lci->EndText;
101        }
102        else
103        {
104                *data << qst->title;                                                    // Title / name of quest
105                *data << qst->objectives;                                          // Objectives / description
106                *data << qst->details;                                            // Details
107                *data << qst->endtext;                                            // Subdescription
108        }
109
110    *data << uint8( 0 );
111
112        for(i = 0; i < 4; ++i)
113        {
114                *data << qst->required_mob[i];                    // Kill mob entry ID [i]
115                *data << qst->required_mobcount[i];              // Kill mob count [i]
116                *data << uint32( 0 ); // Unknown
117        }
118
119        for(i = 0; i < 6; ++i)
120        {
121                *data << qst->required_item[i];                  // Collect item [i]
122                *data << qst->required_itemcount[i];            // Collect item count [i]
123        }
124
125        if(lci)
126        {
127                *data << lci->ObjectiveText[0];
128                *data << lci->ObjectiveText[1];
129                *data << lci->ObjectiveText[2];
130                *data << lci->ObjectiveText[3];
131        }
132        else
133        {
134                *data << qst->objectivetexts[0];                                // Objective 1 - Used as text if mob not set
135                *data << qst->objectivetexts[1];                                // Objective 2 - Used as text if mob not set
136                *data << qst->objectivetexts[2];                                // Objective 3 - Used as text if mob not set
137                *data << qst->objectivetexts[3];                                // Objective 4 - Used as text if mob not set
138        }
139
140        return data;
141}
142
143
144/*****************
145* QuestLogEntry *
146*****************/
147QuestLogEntry::QuestLogEntry()
148{
149        mInitialized = false;
150        m_quest = NULL;
151        mDirty = false;
152        m_slot = -1;
153        completed= 0;
154}
155
156QuestLogEntry::~QuestLogEntry()
157{
158
159}
160
161void QuestLogEntry::Init(Quest* quest, Player* plr, uint32 slot)
162{
163        Arcemu::Util::ARCEMU_ASSERT(   quest != NULL );
164        Arcemu::Util::ARCEMU_ASSERT(   plr != NULL );
165
166        m_quest = quest;
167        m_plr = plr;
168        m_slot = slot;
169
170        iscastquest = false;
171        isemotequest = false;
172        for(uint32 i = 0; i < 4; ++i)
173        {
174                if( quest->required_spell[i] != 0 )
175                {
176                        iscastquest = true;
177                        if( !plr->HasQuestSpell(quest->required_spell[i]) )
178                                plr->quest_spells.insert(quest->required_spell[i]);
179                }
180                else if( quest->required_emote[i] != 0 )
181                {
182                        isemotequest = true;
183                }
184                if( quest->required_mob[i] != 0 )
185                {
186                        if( !plr->HasQuestMob(quest->required_mob[i]) )
187                                plr->quest_mobs.insert(quest->required_mob[i]);
188                }
189        }
190
191
192        // update slot
193        plr->SetQuestLogSlot(this, slot);
194       
195        mDirty = true;
196
197        memset(m_mobcount, 0, 4*4);
198        memset(m_explored_areas, 0, 4*4);
199
200        if(m_quest->time)
201                m_time_left = m_quest->time;
202        else
203                m_time_left = 0;
204
205        CALL_QUESTSCRIPT_EVENT(this, OnQuestStart)(plr, this);
206}
207
208void QuestLogEntry::ClearAffectedUnits()
209{
210        if (m_affected_units.size()>0)
211                m_affected_units.clear();
212}
213void QuestLogEntry::AddAffectedUnit(Unit* target)
214{
215        if (!target)
216                return;
217        if (!IsUnitAffected(target))
218                m_affected_units.insert(target->GetGUID());
219}
220bool QuestLogEntry::IsUnitAffected(Unit* target)
221{
222        if (!target)
223                return true;
224        if (m_affected_units.find(target->GetGUID()) != m_affected_units.end())
225                return true;
226        return false;
227}
228
229void QuestLogEntry::SaveToDB(QueryBuffer * buf)
230{
231        Arcemu::Util::ARCEMU_ASSERT(   m_slot != -1);
232        if(!mDirty)
233                return;
234
235        std::stringstream ss;
236
237    ss << "DELETE FROM questlog WHERE player_guid = ";
238    ss << m_plr->GetLowGUID();
239    ss << " AND quest_id = ";
240    ss << m_quest->id;
241    ss << ";";
242
243    if( buf == NULL )
244                CharacterDatabase.Execute( ss.str().c_str() );
245        else
246                buf->AddQueryStr(ss.str());
247
248    ss.rdbuf()->str("");
249
250        ss << "INSERT INTO questlog VALUES(";
251        ss << m_plr->GetLowGUID() << "," << m_quest->id << "," << m_slot << "," << m_time_left;
252        for(int i = 0; i < 4; ++i)
253                ss << "," << m_explored_areas[i];
254       
255        for(int i = 0; i < 4; ++i)
256                ss << "," << m_mobcount[i];
257
258    ss << "," << uint32( completed );
259
260        ss << ")";
261       
262        if( buf == NULL )
263                CharacterDatabase.Execute( ss.str().c_str() );
264        else
265                buf->AddQueryStr(ss.str());
266}
267
268bool QuestLogEntry::LoadFromDB(Field *fields)
269{
270        // playerguid,questid,timeleft,area0,area1,area2,area3,kill0,kill1,kill2,kill3
271        int f = 3;
272        Arcemu::Util::ARCEMU_ASSERT(   m_plr && m_quest);
273        m_time_left = fields[f].GetUInt32();    f++;
274        for(int i = 0; i < 4; ++i)
275        {
276                m_explored_areas[i] = fields[f].GetUInt32();    f++;
277                CALL_QUESTSCRIPT_EVENT(this, OnExploreArea)(m_explored_areas[i], m_plr, this);
278        }
279
280        for(int i = 0; i < 4; ++i)
281        {
282                m_mobcount[i] = fields[f].GetUInt32();  f++;
283                if(GetQuest()->required_mobtype[i] == QUEST_MOB_TYPE_CREATURE)
284                {
285                        CALL_QUESTSCRIPT_EVENT(this, OnCreatureKill)(GetQuest()->required_mob[i], m_plr, this);
286                }
287                else
288                {
289                        CALL_QUESTSCRIPT_EVENT(this, OnGameObjectActivate)(GetQuest()->required_mob[i], m_plr, this);
290                }
291        }
292
293    completed = fields[f].GetUInt32();
294
295        mDirty = false;
296        return true;
297}
298
299bool QuestLogEntry::CanBeFinished()
300{
301        uint32 i;
302
303    if( m_quest->iscompletedbyspelleffect && !completed )
304        return false;
305
306    if( completed )
307        return true;
308
309        for(i = 0; i < 4; ++i)
310        {
311                if(m_quest->required_mob[i])
312                {
313                        if(m_mobcount[i] < m_quest->required_mobcount[i])
314                        {
315                                return false;
316                        }
317                }
318                if( m_quest->required_spell[i] ) // requires spell cast, with no required target
319                {
320                        if( m_mobcount[i] == 0 || m_mobcount[i] < m_quest->required_mobcount[i] )
321                        {
322                                return false;
323                        }
324                }
325                if( m_quest->required_emote[i] ) // requires emote, with no required target
326                {
327                        if( m_mobcount[i] == 0 || m_mobcount[i] < m_quest->required_mobcount[i] )
328                        {
329                                return false;
330                        }
331                }
332        }
333
334        for(i = 0; i < 4; ++i)
335        {
336                if(m_quest->required_item[i])
337                {
338                        if(m_plr->GetItemInterface()->GetItemCount(m_quest->required_item[i]) < m_quest->required_itemcount[i])
339                        {
340                                return false;
341                        }
342                }
343        }
344
345        //Check for Gold & AreaTrigger Requirements
346        if ( m_quest->reward_money < 0 && m_plr->GetGold() < uint32(-m_quest->reward_money) )
347                return false;
348
349        for(i = 0; i < 4; ++i)
350        {
351                if(m_quest->required_triggers[i])
352                {
353                        if(m_explored_areas[i] == 0)
354                                return false;
355                }
356        }
357
358        return true;
359}
360
361void QuestLogEntry::SubtractTime(uint32 value)
362{
363        if(this->m_time_left  <=value)
364                m_time_left = 0;
365        else
366                m_time_left-=value;
367}
368
369void QuestLogEntry::SetMobCount(uint32 i, uint32 count)
370{
371        Arcemu::Util::ARCEMU_ASSERT(   i<4);
372        m_mobcount[i] = count;
373        mDirty = true;
374}
375
376void QuestLogEntry::IncrementMobCount(uint32 i)
377{
378        Arcemu::Util::ARCEMU_ASSERT(   i<4);
379        ++m_mobcount[i];
380        mDirty = true;
381}
382
383void QuestLogEntry::SetTrigger(uint32 i)
384{
385        Arcemu::Util::ARCEMU_ASSERT(   i<4);
386        m_explored_areas[i] = 1;
387        mDirty = true;
388}
389
390void QuestLogEntry::SetSlot(int32 i)
391{
392        Arcemu::Util::ARCEMU_ASSERT(   i!=-1);
393        m_slot = i;
394}
395
396void QuestLogEntry::Finish()
397{
398        uint32 base = GetBaseField(m_slot);
399        m_plr->SetUInt32Value(base + 0, 0);
400        m_plr->SetUInt32Value(base + 1, 0);
401        m_plr->SetUInt32Value(base + 2, 0);
402
403        // clear from player log
404        m_plr->SetQuestLogSlot(NULL, m_slot);
405        m_plr->PushToRemovedQuests(m_quest->id);
406        m_plr->UpdateNearbyGameObjects();
407        // delete ourselves
408
409        delete this;
410}
411
412void QuestLogEntry::UpdatePlayerFields()
413{
414        if(!m_plr)
415                return;
416
417        uint32 base = GetBaseField(m_slot);
418        m_plr->SetUInt32Value(base + 0, m_quest->id);
419        uint32 field0 = 0; // 0x01000000 = "Objective Complete" - 0x02 = Quest Failed - 0x04 = Quest Accepted
420
421        // next field is count (kills, etc)
422        uint32 field1 = 0;
423
424        // explored areas
425        if(m_quest->count_requiredtriggers)
426        {
427                uint32 count = 0;
428                for(int i = 0; i < 4; ++i)
429                {
430                        if(m_quest->required_triggers[i])
431                        {
432                                if(m_explored_areas[i] == 1)
433                                {
434                                        count++;
435                                }
436                        }
437                }
438
439                if(count == m_quest->count_requiredtriggers)
440                {
441                        field1 |= 0x01000000;
442                }
443        }
444
445        // spell casts / emotes
446        if( iscastquest )
447        {
448                bool cast_complete = true;
449                for(int i = 0; i < 4; ++i)
450                {
451                        if( m_quest->required_spell[i] && m_quest->required_mobcount[i] > m_mobcount[i] )
452                        {
453                                cast_complete = false;
454                                break;
455                        }
456                }
457                if( cast_complete )
458                {
459                        field0 |= 0x01000000; // "Objective Complete"
460                }
461        }
462        else if( isemotequest )
463        {
464                bool emote_complete = true;
465                for( int i = 0; i < 4; ++i )
466                {
467                        if( m_quest->required_emote[i] && m_quest->required_mobcount[i] > m_mobcount[i] )
468                        {
469                                emote_complete = false;
470                                break;
471                        }
472                }
473                if( emote_complete )
474                {
475                        field0 |= 0x01000000; // "Objective Complete"
476                }
477        }
478
479        // mob hunting / counter
480        if(m_quest->count_required_mob)
481        {
482                /*uint8 cnt;
483                for(int i = 0; i < 4; ++i)
484                {
485                        if(m_quest->required_mob[i] && m_mobcount[i] > 0)
486                        {
487                                // 1 << (offset * 6)
488                                cnt = m_mobcount[i];
489                                field1 |= (cnt << (i*8));
490                        }
491                }*/
492
493                // optimized this - burlex
494                uint8* p = (uint8*)&field1;
495                for(int i = 0; i < 4; ++i)
496                {
497                        if( m_quest->required_mob[i] && m_mobcount[i] > 0 )
498                                p[i] |= (uint8)m_mobcount[i];
499                }
500        }
501
502        m_plr->SetUInt32Value(base + 1, field0);
503        m_plr->SetUInt32Value(base + 2, field1);
504        m_plr->SetUInt32Value(base + 3, ( m_time_left ? (uint32)(UNIXTIME+m_time_left/1000) : 0 ) );
505}
506
507void QuestLogEntry::SendQuestComplete()
508{
509        WorldPacket data(4);
510        data.SetOpcode(SMSG_QUESTUPDATE_COMPLETE);
511        data << m_quest->id;
512        m_plr->GetSession()->SendPacket(&data);
513        m_plr->UpdateNearbyGameObjects();
514        CALL_QUESTSCRIPT_EVENT(this, OnQuestComplete)(m_plr, this);
515}
516
517void QuestLogEntry::SendUpdateAddKill(uint32 i)
518{
519        sQuestMgr.SendQuestUpdateAddKill(m_plr, m_quest->id, m_quest->required_mob[i], m_mobcount[i], m_quest->required_mobcount[i], 0);
520}
521
522void QuestLogEntry::Complete(){
523    completed = 1;
524}
Note: See TracBrowser for help on using the browser.