Show
Ignore:
Timestamp:
11/19/08 13:27:40 (17 years ago)
Author:
yumileroy
Message:

[svn] * Merge Temp dev SVN with Assembla.
* Changes include:

  • Implementation of w12x's Outdoor PvP and Game Event Systems.
  • Temporary removal of IRC Chat Bot (until infinite loop when disabled is fixed).
  • All mangos -> trinity (to convert your mangos_string table, please run mangos_string_to_trinity_string.sql).
  • Improved Config cleanup.
  • And many more changes.

Original author: Seline
Date: 2008-10-14 11:57:03-05:00

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/src/game/GameEvent.cpp

    r39 r44  
    11/* 
    2  * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> 
     2 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> 
     3 * 
     4 * Thanks to the original authors: MaNGOS <http://www.mangosproject.org/> 
    35 * 
    46 * This program is free software; you can redistribute it and/or modify 
     
    911 * This program is distributed in the hope that it will be useful, 
    1012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
    1214 * GNU General Public License for more details. 
    1315 * 
    1416 * You should have received a copy of the GNU General Public License 
    1517 * along with this program; if not, write to the Free Software 
    16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
     18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
    1719 */ 
    1820 
     
    2527#include "MapManager.h" 
    2628#include "Policies/SingletonImp.h" 
    27 #include "IRCClient.h" 
     29#include "GossipDef.h" 
     30#include "Player.h" 
    2831 
    2932INSTANTIATE_SINGLETON_1(GameEvent); 
     
    3134bool GameEvent::CheckOneGameEvent(uint16 entry) const 
    3235{ 
     36    time_t currenttime = time(NULL); 
     37    // if the state is conditions or nextphase, then the event should be active 
     38    if (mGameEvent[entry].state == GAMEEVENT_WORLD_CONDITIONS || mGameEvent[entry].state == GAMEEVENT_WORLD_NEXTPHASE) 
     39        return true; 
     40    // finished world events are inactive 
     41    else if (mGameEvent[entry].state == GAMEEVENT_WORLD_FINISHED) 
     42        return false; 
     43    // if inactive world event, check the prerequisite events 
     44    else if (mGameEvent[entry].state == GAMEEVENT_WORLD_INACTIVE) 
     45    { 
     46        for(std::set<uint16>::const_iterator itr = mGameEvent[entry].prerequisite_events.begin(); itr != mGameEvent[entry].prerequisite_events.end(); ++itr) 
     47        { 
     48            if( (mGameEvent[*itr].state != GAMEEVENT_WORLD_NEXTPHASE && mGameEvent[*itr].state != GAMEEVENT_WORLD_FINISHED) ||   // if prereq not in nextphase or finished state, then can't start this one 
     49                mGameEvent[*itr].nextstart > currenttime)               // if not in nextphase state for long enough, can't start this one 
     50                return false; 
     51        } 
     52        // all prerequisite events are met 
     53        // but if there are no prerequisites, this can be only activated through gm command 
     54        return !(mGameEvent[entry].prerequisite_events.empty()); 
     55    } 
    3356    // Get the event information 
    34     time_t currenttime = time(NULL); 
    3557    if( mGameEvent[entry].start < currenttime && currenttime < mGameEvent[entry].end && 
    3658        ((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * MINUTE)) < (mGameEvent[entry].length * MINUTE) ) 
     
    4365{ 
    4466    time_t currenttime = time(NULL); 
     67 
     68    // for NEXTPHASE state world events, return the delay to start the next event, so the followup event will be checked correctly 
     69    if ((mGameEvent[entry].state == GAMEEVENT_WORLD_NEXTPHASE || mGameEvent[entry].state == GAMEEVENT_WORLD_FINISHED) && mGameEvent[entry].nextstart >= currenttime) 
     70        return (mGameEvent[entry].nextstart - currenttime); 
     71 
     72    // for CONDITIONS state world events, return the length of the wait period, so if the conditions are met, this check will be called again to set the timer as NEXTPHASE event 
     73    if (mGameEvent[entry].state == GAMEEVENT_WORLD_CONDITIONS) 
     74        return mGameEvent[entry].length ? mGameEvent[entry].length * 60 : max_ge_check_delay; 
    4575 
    4676    // outdated event: we return max 
     
    6696} 
    6797 
    68 void GameEvent::StartEvent( uint16 event_id, bool overwrite ) 
    69 { 
    70     AddActiveEvent(event_id); 
    71     ApplyNewEvent(event_id); 
    72     if(overwrite) 
    73     { 
    74         mGameEvent[event_id].start = time(NULL); 
    75         if(mGameEvent[event_id].end <= mGameEvent[event_id].start) 
    76             mGameEvent[event_id].end = mGameEvent[event_id].start+mGameEvent[event_id].length; 
     98bool GameEvent::StartEvent( uint16 event_id, bool overwrite ) 
     99{ 
     100    if(mGameEvent[event_id].state == GAMEEVENT_NORMAL) 
     101    { 
     102        AddActiveEvent(event_id); 
     103        ApplyNewEvent(event_id); 
     104        if(overwrite) 
     105        { 
     106            mGameEvent[event_id].start = time(NULL); 
     107            if(mGameEvent[event_id].end <= mGameEvent[event_id].start) 
     108                mGameEvent[event_id].end = mGameEvent[event_id].start+mGameEvent[event_id].length; 
     109        } 
     110        return false; 
     111    } 
     112    else 
     113    { 
     114        if( mGameEvent[event_id].state == GAMEEVENT_WORLD_INACTIVE ) 
     115            // set to conditions phase 
     116            mGameEvent[event_id].state = GAMEEVENT_WORLD_CONDITIONS; 
     117 
     118        // add to active events 
     119        AddActiveEvent(event_id); 
     120        // add spawns 
     121        ApplyNewEvent(event_id); 
     122 
     123        // check if can go to next state 
     124        bool conditions_met = CheckOneGameEventConditions(event_id); 
     125        // save to db 
     126        SaveWorldEventStateToDB(event_id); 
     127        // force game event update to set the update timer if conditions were met from a command 
     128        // this update is needed to possibly start events dependent on the started one 
     129        // or to scedule another update where the next event will be started 
     130        if(overwrite && conditions_met) 
     131            sWorld.ForceGameEventUpdate(); 
     132 
     133        return conditions_met; 
    77134    } 
    78135} 
     
    80137void GameEvent::StopEvent( uint16 event_id, bool overwrite ) 
    81138{ 
     139    bool serverwide_evt = mGameEvent[event_id].state != GAMEEVENT_NORMAL; 
     140 
    82141    RemoveActiveEvent(event_id); 
    83142    UnApplyEvent(event_id); 
    84     if(overwrite) 
     143 
     144    if(overwrite && !serverwide_evt) 
    85145    { 
    86146        mGameEvent[event_id].start = time(NULL) - mGameEvent[event_id].length * MINUTE; 
     
    88148            mGameEvent[event_id].end = mGameEvent[event_id].start+mGameEvent[event_id].length; 
    89149    } 
     150    else if(serverwide_evt) 
     151    { 
     152        // if finished world event, then only gm command can stop it 
     153        if(overwrite || mGameEvent[event_id].state != GAMEEVENT_WORLD_FINISHED) 
     154        { 
     155            // reset conditions 
     156            mGameEvent[event_id].nextstart = 0; 
     157            mGameEvent[event_id].state = GAMEEVENT_WORLD_INACTIVE; 
     158            std::map<uint32 /*condition id*/, GameEventFinishCondition>::iterator itr; 
     159            for(itr = mGameEvent[event_id].conditions.begin(); itr != mGameEvent[event_id].conditions.end(); ++itr) 
     160                itr->second.done = 0; 
     161            CharacterDatabase.BeginTransaction(); 
     162            CharacterDatabase.PExecute("DELETE FROM game_event_save WHERE event_id = '%u'",event_id); 
     163            CharacterDatabase.PExecute("DELETE FROM game_event_condition_save WHERE event_id = '%u'",event_id); 
     164            CharacterDatabase.CommitTransaction(); 
     165        } 
     166    } 
    90167} 
    91168 
     
    109186    } 
    110187 
    111     QueryResult *result = WorldDatabase.Query("SELECT entry,UNIX_TIMESTAMP(start_time),UNIX_TIMESTAMP(end_time),occurence,length,description FROM game_event"); 
     188    QueryResult *result = WorldDatabase.Query("SELECT entry,UNIX_TIMESTAMP(start_time),UNIX_TIMESTAMP(end_time),occurence,length,description,world_event FROM game_event"); 
    112189    if( !result ) 
    113190    { 
     
    142219        pGameEvent.occurence    = fields[3].GetUInt32(); 
    143220        pGameEvent.length       = fields[4].GetUInt32(); 
    144  
    145         if(pGameEvent.length==0)                            // length>0 is validity check 
    146         { 
    147             sLog.outErrorDb("`game_event` game event id (%i) have length 0 and can't be used.",event_id); 
     221        pGameEvent.description  = fields[5].GetCppString(); 
     222        pGameEvent.state        = (GameEventState)(fields[6].GetUInt8()); 
     223        pGameEvent.nextstart    = 0; 
     224 
     225        if(pGameEvent.length==0 && pGameEvent.state == GAMEEVENT_NORMAL)                            // length>0 is validity check 
     226        { 
     227            sLog.outErrorDb("`game_event` game event id (%i) isn't a world event and has length = 0, thus it can't be used.",event_id); 
    148228            continue; 
    149229        } 
    150  
    151         pGameEvent.description  = fields[5].GetCppString(); 
    152230 
    153231    } while( result->NextRow() ); 
     
    156234    sLog.outString( ">> Loaded %u game events", count ); 
    157235    delete result; 
     236 
     237    // load game event saves 
     238    //                                       0         1      2  
     239    result = CharacterDatabase.Query("SELECT event_id, state, UNIX_TIMESTAMP(next_start) FROM game_event_save"); 
     240 
     241    count = 0; 
     242    if( !result ) 
     243    { 
     244        barGoLink bar2(1); 
     245        bar2.step(); 
     246 
     247        sLog.outString(); 
     248        sLog.outString(">> Loaded %u game event saves in game events", count ); 
     249    } 
     250    else 
     251    { 
     252 
     253        barGoLink bar2( result->GetRowCount() ); 
     254        do 
     255        { 
     256            Field *fields = result->Fetch(); 
     257 
     258            bar2.step(); 
     259 
     260            uint16 event_id = fields[0].GetUInt16(); 
     261 
     262            if(event_id >= mGameEvent.size()) 
     263            { 
     264                sLog.outErrorDb("`game_event_save` game event id (%i) is out of range compared to max event id in `game_event`",event_id); 
     265                continue; 
     266            } 
     267 
     268            if(mGameEvent[event_id].state != GAMEEVENT_NORMAL) 
     269            { 
     270                mGameEvent[event_id].state = (GameEventState)(fields[1].GetUInt8()); 
     271                mGameEvent[event_id].nextstart    = time_t(fields[2].GetUInt64()); 
     272            } 
     273            else 
     274            { 
     275                sLog.outErrorDb("game_event_save includes event save for non-worldevent id %u",event_id); 
     276                continue; 
     277            } 
     278 
     279            ++count; 
     280 
     281        } while( result->NextRow() ); 
     282        sLog.outString(); 
     283        sLog.outString( ">> Loaded %u game event saves in game events", count ); 
     284        delete result; 
     285    } 
     286 
     287    // load game event links (prerequisites) 
     288    result = WorldDatabase.Query("SELECT event_id, prerequisite_event FROM game_event_prerequisite"); 
     289    if( !result ) 
     290    { 
     291        barGoLink bar2(1); 
     292        bar2.step(); 
     293 
     294        sLog.outString(); 
     295        sLog.outString(">> Loaded %u game event prerequisites in game events", count ); 
     296    } 
     297    else 
     298    { 
     299 
     300        barGoLink bar2( result->GetRowCount() ); 
     301        do 
     302        { 
     303            Field *fields = result->Fetch(); 
     304 
     305            bar2.step(); 
     306 
     307            uint16 event_id = fields[0].GetUInt16(); 
     308 
     309            if(event_id >= mGameEvent.size()) 
     310            { 
     311                sLog.outErrorDb("`game_event_prerequisite` game event id (%i) is out of range compared to max event id in `game_event`",event_id); 
     312                continue; 
     313            } 
     314 
     315 
     316            if(mGameEvent[event_id].state != GAMEEVENT_NORMAL) 
     317            { 
     318                uint16 prerequisite_event = fields[1].GetUInt16(); 
     319                if(prerequisite_event >= mGameEvent.size()) 
     320                { 
     321                    sLog.outErrorDb("`game_event_prerequisite` game event prerequisite id (%i) is out of range compared to max event id in `game_event`",prerequisite_event); 
     322                    continue; 
     323                } 
     324                mGameEvent[event_id].prerequisite_events.insert(prerequisite_event); 
     325            } 
     326            else 
     327            { 
     328                sLog.outErrorDb("game_event_prerequisiste includes event entry for non-worldevent id %u",event_id); 
     329                continue; 
     330            } 
     331 
     332            ++count; 
     333 
     334        } while( result->NextRow() ); 
     335        sLog.outString(); 
     336        sLog.outString( ">> Loaded %u game event prerequisites in game events", count ); 
     337        delete result; 
     338    } 
    158339 
    159340    mGameEventCreatureGuids.resize(mGameEvent.size()*2-1); 
     
    308489    } 
    309490 
    310     mGameEventQuests.resize(mGameEvent.size()); 
     491    mGameEventCreatureQuests.resize(mGameEvent.size()); 
    311492    //                                   0   1      2 
    312493    result = WorldDatabase.Query("SELECT id, quest, event FROM game_event_creature_quest"); 
     
    334515            uint16 event_id = fields[2].GetUInt16(); 
    335516 
    336             if(event_id >= mGameEventQuests.size()) 
     517            if(event_id >= mGameEventCreatureQuests.size()) 
    337518            { 
    338519                sLog.outErrorDb("`game_event_creature_quest` game event id (%u) is out of range compared to max event id in `game_event`",event_id); 
     
    341522 
    342523            ++count; 
    343             QuestRelList& questlist = mGameEventQuests[event_id]; 
     524            QuestRelList& questlist = mGameEventCreatureQuests[event_id]; 
    344525            questlist.push_back(QuestRelation(id, quest)); 
    345526 
     
    350531        delete result; 
    351532    } 
     533 
     534    mGameEventGameObjectQuests.resize(mGameEvent.size()); 
     535    //                                   0   1      2 
     536    result = WorldDatabase.Query("SELECT id, quest, event FROM game_event_gameobject_quest"); 
     537 
     538    count = 0; 
     539    if( !result ) 
     540    { 
     541        barGoLink bar3(1); 
     542        bar3.step(); 
     543 
     544        sLog.outString(); 
     545        sLog.outString(">> Loaded %u go quests additions in game events", count ); 
     546    } 
     547    else 
     548    { 
     549 
     550        barGoLink bar3( result->GetRowCount() ); 
     551        do 
     552        { 
     553            Field *fields = result->Fetch(); 
     554 
     555            bar3.step(); 
     556            uint32 id       = fields[0].GetUInt32(); 
     557            uint32 quest    = fields[1].GetUInt32(); 
     558            uint16 event_id = fields[2].GetUInt16(); 
     559 
     560            if(event_id >= mGameEventGameObjectQuests.size()) 
     561            { 
     562                sLog.outErrorDb("`game_event_gameobject_quest` game event id (%u) is out of range compared to max event id in `game_event`",event_id); 
     563                continue; 
     564            } 
     565 
     566            ++count; 
     567            QuestRelList& questlist = mGameEventGameObjectQuests[event_id]; 
     568            questlist.push_back(QuestRelation(id, quest)); 
     569 
     570        } while( result->NextRow() ); 
     571        sLog.outString(); 
     572        sLog.outString( ">> Loaded %u quests additions in game events", count ); 
     573 
     574        delete result; 
     575    } 
     576 
     577    // Load quest to (event,condition) mapping 
     578    //                                   0      1         2             3 
     579    result = WorldDatabase.Query("SELECT quest, event_id, condition_id, num FROM game_event_quest_condition"); 
     580 
     581    count = 0; 
     582    if( !result ) 
     583    { 
     584        barGoLink bar3(1); 
     585        bar3.step(); 
     586 
     587        sLog.outString(); 
     588        sLog.outString(">> Loaded %u quest event conditions in game events", count ); 
     589    } 
     590    else 
     591    { 
     592 
     593        barGoLink bar3( result->GetRowCount() ); 
     594        do 
     595        { 
     596            Field *fields = result->Fetch(); 
     597 
     598            bar3.step(); 
     599            uint32 quest     = fields[0].GetUInt32(); 
     600            uint16 event_id  = fields[1].GetUInt16(); 
     601            uint32 condition = fields[2].GetUInt32(); 
     602            float num       = fields[3].GetFloat(); 
     603 
     604            if(event_id >= mGameEvent.size()) 
     605            { 
     606                sLog.outErrorDb("`game_event_quest_condition` game event id (%u) is out of range compared to max event id in `game_event`",event_id); 
     607                continue; 
     608            } 
     609 
     610            ++count; 
     611            mQuestToEventConditions[quest].event_id = event_id; 
     612            mQuestToEventConditions[quest].condition = condition; 
     613            mQuestToEventConditions[quest].num = num; 
     614 
     615        } while( result->NextRow() ); 
     616        sLog.outString(); 
     617        sLog.outString( ">> Loaded %u quest event conditions in game events", count ); 
     618 
     619        delete result; 
     620    } 
     621 
     622    // load conditions of the events 
     623    //                                   0         1             2        3                      4          
     624    result = WorldDatabase.Query("SELECT event_id, condition_id, req_num, max_world_state_field, done_world_state_field FROM game_event_condition"); 
     625 
     626    count = 0; 
     627    if( !result ) 
     628    { 
     629        barGoLink bar3(1); 
     630        bar3.step(); 
     631 
     632        sLog.outString(); 
     633        sLog.outString(">> Loaded %u conditions in game events", count ); 
     634    } 
     635    else 
     636    { 
     637 
     638        barGoLink bar3( result->GetRowCount() ); 
     639        do 
     640        { 
     641            Field *fields = result->Fetch(); 
     642 
     643            bar3.step(); 
     644            uint16 event_id  = fields[0].GetUInt16(); 
     645            uint32 condition = fields[1].GetUInt32(); 
     646 
     647            if(event_id >= mGameEvent.size()) 
     648            { 
     649                sLog.outErrorDb("`game_event_condition` game event id (%u) is out of range compared to max event id in `game_event`",event_id); 
     650                continue; 
     651            } 
     652 
     653            mGameEvent[event_id].conditions[condition].reqNum = fields[2].GetFloat(); 
     654            mGameEvent[event_id].conditions[condition].done = 0; 
     655            mGameEvent[event_id].conditions[condition].max_world_state = fields[3].GetUInt32(); 
     656            mGameEvent[event_id].conditions[condition].done_world_state = fields[4].GetUInt32(); 
     657 
     658            ++count; 
     659 
     660        } while( result->NextRow() ); 
     661        sLog.outString(); 
     662        sLog.outString( ">> Loaded %u conditions in game events", count ); 
     663 
     664        delete result; 
     665    } 
     666 
     667    // load condition saves 
     668    //                                       0         1             2          
     669    result = CharacterDatabase.Query("SELECT event_id, condition_id, done FROM game_event_condition_save"); 
     670 
     671    count = 0; 
     672    if( !result ) 
     673    { 
     674        barGoLink bar3(1); 
     675        bar3.step(); 
     676 
     677        sLog.outString(); 
     678        sLog.outString(">> Loaded %u condition saves in game events", count ); 
     679    } 
     680    else 
     681    { 
     682 
     683        barGoLink bar3( result->GetRowCount() ); 
     684        do 
     685        { 
     686            Field *fields = result->Fetch(); 
     687 
     688            bar3.step(); 
     689            uint16 event_id  = fields[0].GetUInt16(); 
     690            uint32 condition = fields[1].GetUInt32(); 
     691 
     692            if(event_id >= mGameEvent.size()) 
     693            { 
     694                sLog.outErrorDb("`game_event_condition_save` game event id (%u) is out of range compared to max event id in `game_event`",event_id); 
     695                continue; 
     696            } 
     697 
     698            std::map<uint32, GameEventFinishCondition>::iterator itr = mGameEvent[event_id].conditions.find(condition); 
     699            if(itr != mGameEvent[event_id].conditions.end()) 
     700            { 
     701                itr->second.done = fields[2].GetFloat(); 
     702            } 
     703            else 
     704            { 
     705                sLog.outErrorDb("game_event_condition_save contains not present condition evt id %u cond id %u",event_id, condition); 
     706                continue; 
     707            } 
     708 
     709            ++count; 
     710 
     711        } while( result->NextRow() ); 
     712        sLog.outString(); 
     713        sLog.outString( ">> Loaded %u condition saves in game events", count ); 
     714 
     715        delete result; 
     716    } 
     717 
     718    mGameEventNPCFlags.resize(mGameEvent.size()); 
     719    // load game event npcflag 
     720    //                                   0         1        2 
     721    result = WorldDatabase.Query("SELECT guid, event_id, npcflag FROM game_event_npcflag"); 
     722 
     723    count = 0; 
     724    if( !result ) 
     725    { 
     726        barGoLink bar3(1); 
     727        bar3.step(); 
     728 
     729        sLog.outString(); 
     730        sLog.outString(">> Loaded %u npcflags in game events", count ); 
     731    } 
     732    else 
     733    { 
     734 
     735        barGoLink bar3( result->GetRowCount() ); 
     736        do 
     737        { 
     738            Field *fields = result->Fetch(); 
     739 
     740            bar3.step(); 
     741            uint32 guid     = fields[0].GetUInt32(); 
     742            uint16 event_id = fields[1].GetUInt16(); 
     743            uint32 npcflag  = fields[2].GetUInt32(); 
     744 
     745            if(event_id >= mGameEvent.size()) 
     746            { 
     747                sLog.outErrorDb("`game_event_npcflag` game event id (%u) is out of range compared to max event id in `game_event`",event_id); 
     748                continue; 
     749            } 
     750 
     751            mGameEventNPCFlags[event_id].push_back(GuidNPCFlagPair(guid,npcflag)); 
     752 
     753            ++count; 
     754 
     755        } while( result->NextRow() ); 
     756        sLog.outString(); 
     757        sLog.outString( ">> Loaded %u npcflags in game events", count ); 
     758 
     759        delete result; 
     760    } 
     761 
     762    mGameEventVendors.resize(mGameEvent.size()); 
     763    //                                   0      1      2     3         4         5 
     764    result = WorldDatabase.Query("SELECT event, guid, item, maxcount, incrtime, ExtendedCost FROM game_event_npc_vendor"); 
     765 
     766    count = 0; 
     767    if( !result ) 
     768    { 
     769        barGoLink bar3(1); 
     770        bar3.step(); 
     771 
     772        sLog.outString(); 
     773        sLog.outString(">> Loaded %u vendor additions in game events", count ); 
     774    } 
     775    else 
     776    { 
     777 
     778        barGoLink bar3( result->GetRowCount() ); 
     779        do 
     780        { 
     781            Field *fields = result->Fetch(); 
     782 
     783            bar3.step(); 
     784            uint16 event_id  = fields[0].GetUInt16(); 
     785 
     786            if(event_id >= mGameEventVendors.size()) 
     787            { 
     788                sLog.outErrorDb("`game_event_npc_vendor` game event id (%u) is out of range compared to max event id in `game_event`",event_id); 
     789                continue; 
     790            } 
     791 
     792            NPCVendorList& vendors = mGameEventVendors[event_id]; 
     793            NPCVendorEntry newEntry; 
     794            uint32 guid = fields[1].GetUInt32(); 
     795            newEntry.item = fields[2].GetUInt32(); 
     796            newEntry.maxcount = fields[3].GetUInt32(); 
     797            newEntry.incrtime = fields[4].GetUInt32(); 
     798            newEntry.ExtendedCost = fields[5].GetUInt32(); 
     799            // get the event npc flag for checking if the npc will be vendor during the event or not 
     800            uint32 event_npc_flag = 0; 
     801            NPCFlagList& flist = mGameEventNPCFlags[event_id]; 
     802            for(NPCFlagList::const_iterator itr = flist.begin(); itr != flist.end(); ++itr) 
     803            { 
     804                if(itr->first == guid) 
     805                { 
     806                    event_npc_flag = itr->second; 
     807                    break; 
     808                } 
     809            } 
     810            // get creature entry 
     811            newEntry.entry = 0; 
     812 
     813            if( CreatureData const* data = objmgr.GetCreatureData(guid) ) 
     814                newEntry.entry = data->id; 
     815 
     816            // check validity with event's npcflag 
     817            if(!objmgr.IsVendorItemValid(newEntry.entry, newEntry.item, newEntry.maxcount, newEntry.incrtime, newEntry.ExtendedCost, NULL, NULL, event_npc_flag)) 
     818                continue; 
     819            ++count; 
     820            vendors.push_back(newEntry); 
     821 
     822        } while( result->NextRow() ); 
     823        sLog.outString(); 
     824        sLog.outString( ">> Loaded %u vendor additions in game events", count ); 
     825 
     826        delete result; 
     827    } 
     828 
     829    // load game event npc gossip ids 
     830    //                                   0         1        2 
     831    result = WorldDatabase.Query("SELECT guid, event_id, textid FROM game_event_npc_gossip"); 
     832 
     833    count = 0; 
     834    if( !result ) 
     835    { 
     836        barGoLink bar3(1); 
     837        bar3.step(); 
     838 
     839        sLog.outString(); 
     840        sLog.outString(">> Loaded %u npc gossip textids in game events", count ); 
     841    } 
     842    else 
     843    { 
     844 
     845        barGoLink bar3( result->GetRowCount() ); 
     846        do 
     847        { 
     848            Field *fields = result->Fetch(); 
     849 
     850            bar3.step(); 
     851            uint32 guid     = fields[0].GetUInt32(); 
     852            uint16 event_id = fields[1].GetUInt16(); 
     853            uint32 textid  = fields[2].GetUInt32(); 
     854 
     855            if(event_id >= mGameEvent.size()) 
     856            { 
     857                sLog.outErrorDb("`game_event_npc_gossip` game event id (%u) is out of range compared to max event id in `game_event`",event_id); 
     858                continue; 
     859            } 
     860 
     861            mNPCGossipIds[guid]=EventNPCGossipIdPair(event_id, textid); 
     862 
     863            ++count; 
     864 
     865        } while( result->NextRow() ); 
     866        sLog.outString(); 
     867        sLog.outString( ">> Loaded %u npc gossip textids in game events", count ); 
     868 
     869        delete result; 
     870    } 
     871} 
     872 
     873uint32 GameEvent::GetNPCFlag(Creature * cr) 
     874{ 
     875    uint32 mask = 0; 
     876    uint32 guid = cr->GetDBTableGUIDLow(); 
     877 
     878    for(ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr) 
     879    { 
     880        for(NPCFlagList::iterator itr = mGameEventNPCFlags[*e_itr].begin(); 
     881            itr != mGameEventNPCFlags[*e_itr].end(); 
     882            ++ itr) 
     883            if(itr->first == guid) 
     884                mask |= itr->second; 
     885    } 
     886 
     887    return mask; 
     888} 
     889 
     890uint32 GameEvent::GetNpcTextId(uint32 guid) 
     891{ 
     892    GuidEventNpcGossipIdMap::iterator itr = mNPCGossipIds.find(guid); 
     893    if(itr != mNPCGossipIds.end()) 
     894        if(IsActiveEvent(itr->second.first)) 
     895            return itr->second.second; 
     896    return 0; 
    352897} 
    353898 
     
    363908uint32 GameEvent::Update()                                  // return the next event delay in ms 
    364909{ 
     910    time_t currenttime = time(NULL); 
    365911    uint32 nextEventDelay = max_ge_check_delay;             // 1 day 
    366912    uint32 calcDelay; 
     913    std::set<uint16> activate, deactivate; 
    367914    for (uint16 itr = 1; itr < mGameEvent.size(); itr++) 
    368915    { 
     916        // must do the activating first, and after that the deactivating 
     917        // so first queue it 
    369918        //sLog.outErrorDb("Checking event %u",itr); 
    370919        if (CheckOneGameEvent(itr)) 
    371920        { 
     921            // if the world event is in NEXTPHASE state, and the time has passed to finish this event, then do so 
     922            if (mGameEvent[itr].state == GAMEEVENT_WORLD_NEXTPHASE && mGameEvent[itr].nextstart <= currenttime) 
     923            { 
     924                // set this event to finished, null the nextstart time 
     925                mGameEvent[itr].state = GAMEEVENT_WORLD_FINISHED; 
     926                mGameEvent[itr].nextstart = 0; 
     927                // save the state of this gameevent 
     928                SaveWorldEventStateToDB(itr); 
     929                // queue for deactivation 
     930                if(IsActiveEvent(itr)) 
     931                    deactivate.insert(itr); 
     932                // go to next event, this no longer needs an event update timer 
     933                continue; 
     934            } 
     935            else if (mGameEvent[itr].state == GAMEEVENT_WORLD_CONDITIONS && CheckOneGameEventConditions(itr)) 
     936                // changed, save to DB the gameevent state, will be updated in next update cycle 
     937                SaveWorldEventStateToDB(itr); 
     938 
    372939            //sLog.outDebug("GameEvent %u is active",itr->first); 
     940            // queue for activation 
    373941            if (!IsActiveEvent(itr)) 
    374                 StartEvent(itr); 
     942                activate.insert(itr); 
    375943        } 
    376944        else 
     
    378946            //sLog.outDebug("GameEvent %u is not active",itr->first); 
    379947            if (IsActiveEvent(itr)) 
    380                 StopEvent(itr); 
     948                deactivate.insert(itr); 
    381949            else 
    382950            { 
     
    393961            nextEventDelay = calcDelay; 
    394962    } 
     963    // now activate the queue 
     964    // a now activated event can contain a spawn of a to-be-deactivated one 
     965    // following the activate - deactivate order, deactivating the first event later will leave the spawn in (wont disappear then reappear clientside) 
     966    for(std::set<uint16>::iterator itr = activate.begin(); itr != activate.end(); ++itr) 
     967        // start the event 
     968        // returns true the started event completed 
     969        // in that case, initiate next update in 1 second 
     970        if(StartEvent(*itr)) 
     971            nextEventDelay = 0; 
     972    for(std::set<uint16>::iterator itr = deactivate.begin(); itr != deactivate.end(); ++itr) 
     973        StopEvent(*itr); 
    395974    sLog.outBasic("Next game event check in %u seconds.", nextEventDelay + 1); 
    396975    return (nextEventDelay + 1) * 1000;                     // Add 1 second to be sure event has started/stopped at next call 
     
    409988    // Remove quests that are events only to non event npc 
    410989    UpdateEventQuests(event_id, false); 
     990    // update npcflags in this event 
     991    UpdateEventNPCFlags(event_id); 
     992    // remove vendor items 
     993    UpdateEventNPCVendor(event_id, false); 
    411994} 
    412995 
     
    4231006 
    4241007    sLog.outString("GameEvent %u \"%s\" started.", event_id, mGameEvent[event_id].description.c_str()); 
    425  
    426     if((sIRC.BOTMASK & 256) != 0) 
    427     { 
    428         std::string ircchan = "#"; 
    429         ircchan += sIRC._irc_chan[sIRC.anchn].c_str(); 
    430         sIRC.Send_IRC_Channel(ircchan, sIRC.MakeMsg("\00304,08\037/!\\\037\017\00304 Game Event \00304,08\037/!\\\037\017 %s", "%s", mGameEvent[event_id].description.c_str()), true); 
    431     } 
    4321008 
    4331009    // spawn positive event tagget objects 
     
    4401016    // Add quests that are events only to non event npc 
    4411017    UpdateEventQuests(event_id, true); 
     1018    // update npcflags in this event 
     1019    UpdateEventNPCFlags(event_id); 
     1020    // add vendor items 
     1021    UpdateEventNPCVendor(event_id, true); 
     1022} 
     1023 
     1024void GameEvent::UpdateEventNPCFlags(uint16 event_id) 
     1025{ 
     1026    // go through the creatures whose npcflags are changed in the event 
     1027    for(NPCFlagList::iterator itr = mGameEventNPCFlags[event_id].begin(); itr != mGameEventNPCFlags[event_id].end(); ++itr) 
     1028    { 
     1029        // get the creature data from the low guid to get the entry, to be able to find out the whole guid 
     1030        if( CreatureData const* data = objmgr.GetCreatureData(itr->first) ) 
     1031        { 
     1032            Creature * cr = HashMapHolder<Creature>::Find(MAKE_NEW_GUID(itr->first,data->id,HIGHGUID_UNIT)); 
     1033            // if we found the creature, modify its npcflag 
     1034            if(cr) 
     1035            { 
     1036                uint32 npcflag = GetNPCFlag(cr); 
     1037                if(const CreatureInfo * ci = cr->GetCreatureInfo()) 
     1038                    npcflag |= ci->npcflag; 
     1039                cr->SetUInt32Value(UNIT_NPC_FLAGS,npcflag); 
     1040                // reset gossip options, since the flag change might have added / removed some 
     1041                cr->ResetGossipOptions(); 
     1042                // update to world 
     1043                cr->SendUpdateObjectToAllExcept(NULL); 
     1044            } 
     1045            // if we didn't find it, then the npcflag will be updated when the creature is loaded 
     1046        } 
     1047    } 
     1048} 
     1049 
     1050void GameEvent::UpdateEventNPCVendor(uint16 event_id, bool activate) 
     1051{ 
     1052    for(NPCVendorList::iterator itr = mGameEventVendors[event_id].begin(); itr != mGameEventVendors[event_id].end(); ++itr) 
     1053    { 
     1054        if(activate) 
     1055            objmgr.AddVendorItem(itr->entry, itr->item, itr->maxcount, itr->incrtime, itr->ExtendedCost, false); 
     1056        else 
     1057            objmgr.RemoveVendorItem(itr->entry, itr->item, false); 
     1058    } 
    4421059} 
    4431060 
     
    5261143    for (GuidList::iterator itr = mGameEventCreatureGuids[internal_event_id].begin();itr != mGameEventCreatureGuids[internal_event_id].end();++itr) 
    5271144    { 
     1145        // check if it's needed by another event, if so, don't remove 
     1146        if( event_id > 0 && hasCreatureActiveEventExcept(*itr,event_id) ) 
     1147            continue; 
    5281148        // Remove the creature from grid 
    5291149        if( CreatureData const* data = objmgr.GetCreatureData(*itr) ) 
     
    5471167    for (GuidList::iterator itr = mGameEventGameobjectGuids[internal_event_id].begin();itr != mGameEventGameobjectGuids[internal_event_id].end();++itr) 
    5481168    { 
     1169        // check if it's needed by another event, if so, don't remove 
     1170        if( event_id >0 && hasGameObjectActiveEventExcept(*itr,event_id) ) 
     1171            continue; 
    5491172        // Remove the gameobject from grid 
    5501173        if(GameObjectData const* data = objmgr.GetGOData(*itr)) 
     
    6371260} 
    6381261 
     1262bool GameEvent::hasCreatureQuestActiveEventExcept(uint32 quest_id, uint16 event_id) 
     1263{ 
     1264    for(ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr) 
     1265    { 
     1266        if((*e_itr) != event_id) 
     1267            for(QuestRelList::iterator itr = mGameEventCreatureQuests[*e_itr].begin(); 
     1268                itr != mGameEventCreatureQuests[*e_itr].end(); 
     1269                ++ itr) 
     1270                if(itr->second == quest_id) 
     1271                    return true; 
     1272    } 
     1273    return false; 
     1274} 
     1275 
     1276bool GameEvent::hasGameObjectQuestActiveEventExcept(uint32 quest_id, uint16 event_id) 
     1277{ 
     1278    for(ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr) 
     1279    { 
     1280        if((*e_itr) != event_id) 
     1281            for(QuestRelList::iterator itr = mGameEventGameObjectQuests[*e_itr].begin(); 
     1282                itr != mGameEventGameObjectQuests[*e_itr].end(); 
     1283                ++ itr) 
     1284                if(itr->second == quest_id) 
     1285                    return true; 
     1286    } 
     1287    return false; 
     1288} 
     1289bool GameEvent::hasCreatureActiveEventExcept(uint32 creature_id, uint16 event_id) 
     1290{ 
     1291    for(ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr) 
     1292    { 
     1293        if((*e_itr) != event_id) 
     1294        { 
     1295            int32 internal_event_id = mGameEvent.size() + (*e_itr) - 1; 
     1296            for(GuidList::iterator itr = mGameEventCreatureGuids[internal_event_id].begin(); 
     1297                itr != mGameEventCreatureGuids[internal_event_id].end(); 
     1298                ++ itr) 
     1299                if(*itr == creature_id) 
     1300                    return true; 
     1301        } 
     1302    } 
     1303    return false; 
     1304} 
     1305bool GameEvent::hasGameObjectActiveEventExcept(uint32 go_id, uint16 event_id) 
     1306{ 
     1307    for(ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr) 
     1308    { 
     1309        if((*e_itr) != event_id) 
     1310        { 
     1311            int32 internal_event_id = mGameEvent.size() + (*e_itr) - 1; 
     1312            for(GuidList::iterator itr = mGameEventGameobjectGuids[internal_event_id].begin(); 
     1313                itr != mGameEventGameobjectGuids[internal_event_id].end(); 
     1314                ++ itr) 
     1315                if(*itr == go_id) 
     1316                    return true; 
     1317        } 
     1318    } 
     1319    return false; 
     1320} 
     1321 
    6391322void GameEvent::UpdateEventQuests(uint16 event_id, bool Activate) 
    6401323{ 
    6411324    QuestRelList::iterator itr; 
    642     for (itr = mGameEventQuests[event_id].begin();itr != mGameEventQuests[event_id].end();++itr) 
     1325    for (itr = mGameEventCreatureQuests[event_id].begin();itr != mGameEventCreatureQuests[event_id].end();++itr) 
    6431326    { 
    6441327        QuestRelations &CreatureQuestMap = objmgr.mCreatureQuestRelations; 
     
    6461329            CreatureQuestMap.insert(QuestRelations::value_type(itr->first, itr->second)); 
    6471330        else 
    648         {                                                   // Remove the pair(id,quest) from the multimap 
    649             QuestRelations::iterator qitr = CreatureQuestMap.find(itr->first); 
    650             if (qitr == CreatureQuestMap.end()) 
    651                 continue; 
    652             QuestRelations::iterator lastElement = CreatureQuestMap.upper_bound(itr->first); 
    653             for ( ;qitr != lastElement;++qitr) 
    654             { 
    655                 if (qitr->second == itr->second) 
     1331        {    
     1332            if(!hasCreatureQuestActiveEventExcept(itr->second,event_id)) 
     1333            { 
     1334                // Remove the pair(id,quest) from the multimap 
     1335                QuestRelations::iterator qitr = CreatureQuestMap.find(itr->first); 
     1336                if (qitr == CreatureQuestMap.end()) 
     1337                    continue; 
     1338                QuestRelations::iterator lastElement = CreatureQuestMap.upper_bound(itr->first); 
     1339                for ( ;qitr != lastElement;++qitr) 
    6561340                { 
    657                     CreatureQuestMap.erase(qitr);           // iterator is now no more valid 
    658                     break;                                  // but we can exit loop since the element is found 
     1341                    if (qitr->second == itr->second) 
     1342                    { 
     1343                        CreatureQuestMap.erase(qitr);           // iterator is now no more valid 
     1344                        break;                                  // but we can exit loop since the element is found 
     1345                    } 
    6591346                } 
    6601347            } 
    6611348        } 
    6621349    } 
    663 } 
     1350    for (itr = mGameEventGameObjectQuests[event_id].begin();itr != mGameEventGameObjectQuests[event_id].end();++itr) 
     1351    { 
     1352        QuestRelations &GameObjectQuestMap = objmgr.mGOQuestRelations; 
     1353        if (Activate)                                       // Add the pair(id,quest) to the multimap 
     1354            GameObjectQuestMap.insert(QuestRelations::value_type(itr->first, itr->second)); 
     1355        else 
     1356        {    
     1357            if(!hasGameObjectQuestActiveEventExcept(itr->second,event_id)) 
     1358            { 
     1359                // Remove the pair(id,quest) from the multimap 
     1360                QuestRelations::iterator qitr = GameObjectQuestMap.find(itr->first); 
     1361                if (qitr == GameObjectQuestMap.end()) 
     1362                    continue; 
     1363                QuestRelations::iterator lastElement = GameObjectQuestMap.upper_bound(itr->first); 
     1364                for ( ;qitr != lastElement;++qitr) 
     1365                { 
     1366                    if (qitr->second == itr->second) 
     1367                    { 
     1368                        GameObjectQuestMap.erase(qitr);           // iterator is now no more valid 
     1369                        break;                                  // but we can exit loop since the element is found 
     1370                    } 
     1371                } 
     1372            } 
     1373        } 
     1374    }} 
    6641375 
    6651376GameEvent::GameEvent() 
     
    6671378    isSystemInit = false; 
    6681379} 
     1380 
     1381void GameEvent::HandleQuestComplete(uint32 quest_id) 
     1382{ 
     1383    // translate the quest to event and condition 
     1384    QuestIdToEventConditionMap::iterator itr = mQuestToEventConditions.find(quest_id); 
     1385    // quest is registered 
     1386    if(itr != mQuestToEventConditions.end()) 
     1387    { 
     1388        uint16 event_id = itr->second.event_id; 
     1389        uint32 condition = itr->second.condition; 
     1390        float num = itr->second.num; 
     1391 
     1392        // the event is not active, so return, don't increase condition finishes 
     1393        if(!IsActiveEvent(event_id)) 
     1394            return; 
     1395        // not in correct phase, return 
     1396        if(mGameEvent[event_id].state != GAMEEVENT_WORLD_CONDITIONS) 
     1397            return; 
     1398        std::map<uint32,GameEventFinishCondition>::iterator citr = mGameEvent[event_id].conditions.find(condition); 
     1399        // condition is registered 
     1400        if(citr != mGameEvent[event_id].conditions.end()) 
     1401        { 
     1402            // increase the done count, only if less then the req 
     1403            if(citr->second.done < citr->second.reqNum) 
     1404            { 
     1405                citr->second.done += num; 
     1406                // check max limit 
     1407                if(citr->second.done > citr->second.reqNum) 
     1408                    citr->second.done = citr->second.reqNum; 
     1409                // save the change to db 
     1410                CharacterDatabase.BeginTransaction(); 
     1411                CharacterDatabase.PExecute("DELETE FROM game_event_condition_save WHERE event_id = '%u' AND condition_id = '%u'",event_id,condition); 
     1412                CharacterDatabase.PExecute("INSERT INTO game_event_condition_save (event_id, condition_id, done) VALUES (%u,%u,%f)",event_id,condition,citr->second.done); 
     1413                CharacterDatabase.CommitTransaction(); 
     1414                // check if all conditions are met, if so, update the event state 
     1415                if(CheckOneGameEventConditions(event_id)) 
     1416                { 
     1417                    // changed, save to DB the gameevent state 
     1418                    SaveWorldEventStateToDB(event_id); 
     1419                    // force update events to set timer 
     1420                    sWorld.ForceGameEventUpdate(); 
     1421                } 
     1422            } 
     1423        } 
     1424    } 
     1425} 
     1426 
     1427bool GameEvent::CheckOneGameEventConditions(uint16 event_id) 
     1428{ 
     1429    for(std::map<uint32,GameEventFinishCondition>::iterator itr = mGameEvent[event_id].conditions.begin(); itr != mGameEvent[event_id].conditions.end(); ++itr) 
     1430        if(itr->second.done < itr->second.reqNum) 
     1431            // return false if a condition doesn't match 
     1432            return false; 
     1433    // set the phase 
     1434    mGameEvent[event_id].state = GAMEEVENT_WORLD_NEXTPHASE; 
     1435    // set the followup events' start time 
     1436    if(!mGameEvent[event_id].nextstart) 
     1437    { 
     1438        time_t currenttime = time(NULL); 
     1439        mGameEvent[event_id].nextstart = currenttime + mGameEvent[event_id].length * 60; 
     1440    } 
     1441    return true; 
     1442} 
     1443 
     1444void GameEvent::SaveWorldEventStateToDB(uint16 event_id) 
     1445{ 
     1446    CharacterDatabase.BeginTransaction(); 
     1447    CharacterDatabase.PExecute("DELETE FROM game_event_save WHERE event_id = '%u'",event_id); 
     1448    if(mGameEvent[event_id].nextstart) 
     1449        CharacterDatabase.PExecute("INSERT INTO game_event_save (event_id, state, next_start) VALUES ('%u','%u',FROM_UNIXTIME('"I64FMTD"'))",event_id,mGameEvent[event_id].state,mGameEvent[event_id].nextstart); 
     1450    else 
     1451        CharacterDatabase.PExecute("INSERT INTO game_event_save (event_id, state, next_start) VALUES ('%u','%u','0000-00-00 00:00:00')",event_id,mGameEvent[event_id].state); 
     1452    CharacterDatabase.CommitTransaction(); 
     1453} 
     1454 
     1455void GameEvent::HandleWorldEventGossip(Player *plr, Creature *c) 
     1456{ 
     1457    // this function is used to send world state update before sending gossip menu 
     1458    // find the npc's gossip id (if set) in an active game event 
     1459    // if present, send the event's world states 
     1460    GuidEventNpcGossipIdMap::iterator itr = mNPCGossipIds.find(c->GetDBTableGUIDLow()); 
     1461    if(itr != mNPCGossipIds.end()) 
     1462        if(IsActiveEvent(itr->second.first)) 
     1463            // send world state updates to the player about the progress 
     1464            SendWorldStateUpdate(plr, itr->second.first); 
     1465} 
     1466 
     1467void GameEvent::SendWorldStateUpdate(Player * plr, uint16 event_id) 
     1468{ 
     1469    std::map<uint32,GameEventFinishCondition>::iterator itr; 
     1470    for(itr = mGameEvent[event_id].conditions.begin(); itr !=mGameEvent[event_id].conditions.end(); ++itr) 
     1471    { 
     1472        if(itr->second.done_world_state) 
     1473            plr->SendUpdateWorldState(itr->second.done_world_state, itr->second.done); 
     1474        if(itr->second.max_world_state) 
     1475            plr->SendUpdateWorldState(itr->second.max_world_state, itr->second.reqNum); 
     1476    } 
     1477}