Changeset 44 for trunk/src/game/GameEvent.cpp
- Timestamp:
- 11/19/08 13:27:40 (17 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/game/GameEvent.cpp
r39 r44 1 1 /* 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/> 3 5 * 4 6 * This program is free software; you can redistribute it and/or modify … … 9 11 * This program is distributed in the hope that it will be useful, 10 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 14 * GNU General Public License for more details. 13 15 * 14 16 * You should have received a copy of the GNU General Public License 15 17 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307USA18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 19 */ 18 20 … … 25 27 #include "MapManager.h" 26 28 #include "Policies/SingletonImp.h" 27 #include "IRCClient.h" 29 #include "GossipDef.h" 30 #include "Player.h" 28 31 29 32 INSTANTIATE_SINGLETON_1(GameEvent); … … 31 34 bool GameEvent::CheckOneGameEvent(uint16 entry) const 32 35 { 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 } 33 56 // Get the event information 34 time_t currenttime = time(NULL);35 57 if( mGameEvent[entry].start < currenttime && currenttime < mGameEvent[entry].end && 36 58 ((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * MINUTE)) < (mGameEvent[entry].length * MINUTE) ) … … 43 65 { 44 66 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; 45 75 46 76 // outdated event: we return max … … 66 96 } 67 97 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; 98 bool 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; 77 134 } 78 135 } … … 80 137 void GameEvent::StopEvent( uint16 event_id, bool overwrite ) 81 138 { 139 bool serverwide_evt = mGameEvent[event_id].state != GAMEEVENT_NORMAL; 140 82 141 RemoveActiveEvent(event_id); 83 142 UnApplyEvent(event_id); 84 if(overwrite) 143 144 if(overwrite && !serverwide_evt) 85 145 { 86 146 mGameEvent[event_id].start = time(NULL) - mGameEvent[event_id].length * MINUTE; … … 88 148 mGameEvent[event_id].end = mGameEvent[event_id].start+mGameEvent[event_id].length; 89 149 } 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 } 90 167 } 91 168 … … 109 186 } 110 187 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"); 112 189 if( !result ) 113 190 { … … 142 219 pGameEvent.occurence = fields[3].GetUInt32(); 143 220 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); 148 228 continue; 149 229 } 150 151 pGameEvent.description = fields[5].GetCppString();152 230 153 231 } while( result->NextRow() ); … … 156 234 sLog.outString( ">> Loaded %u game events", count ); 157 235 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 } 158 339 159 340 mGameEventCreatureGuids.resize(mGameEvent.size()*2-1); … … 308 489 } 309 490 310 mGameEvent Quests.resize(mGameEvent.size());491 mGameEventCreatureQuests.resize(mGameEvent.size()); 311 492 // 0 1 2 312 493 result = WorldDatabase.Query("SELECT id, quest, event FROM game_event_creature_quest"); … … 334 515 uint16 event_id = fields[2].GetUInt16(); 335 516 336 if(event_id >= mGameEvent Quests.size())517 if(event_id >= mGameEventCreatureQuests.size()) 337 518 { 338 519 sLog.outErrorDb("`game_event_creature_quest` game event id (%u) is out of range compared to max event id in `game_event`",event_id); … … 341 522 342 523 ++count; 343 QuestRelList& questlist = mGameEvent Quests[event_id];524 QuestRelList& questlist = mGameEventCreatureQuests[event_id]; 344 525 questlist.push_back(QuestRelation(id, quest)); 345 526 … … 350 531 delete result; 351 532 } 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 873 uint32 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 890 uint32 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; 352 897 } 353 898 … … 363 908 uint32 GameEvent::Update() // return the next event delay in ms 364 909 { 910 time_t currenttime = time(NULL); 365 911 uint32 nextEventDelay = max_ge_check_delay; // 1 day 366 912 uint32 calcDelay; 913 std::set<uint16> activate, deactivate; 367 914 for (uint16 itr = 1; itr < mGameEvent.size(); itr++) 368 915 { 916 // must do the activating first, and after that the deactivating 917 // so first queue it 369 918 //sLog.outErrorDb("Checking event %u",itr); 370 919 if (CheckOneGameEvent(itr)) 371 920 { 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 372 939 //sLog.outDebug("GameEvent %u is active",itr->first); 940 // queue for activation 373 941 if (!IsActiveEvent(itr)) 374 StartEvent(itr);942 activate.insert(itr); 375 943 } 376 944 else … … 378 946 //sLog.outDebug("GameEvent %u is not active",itr->first); 379 947 if (IsActiveEvent(itr)) 380 StopEvent(itr);948 deactivate.insert(itr); 381 949 else 382 950 { … … 393 961 nextEventDelay = calcDelay; 394 962 } 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); 395 974 sLog.outBasic("Next game event check in %u seconds.", nextEventDelay + 1); 396 975 return (nextEventDelay + 1) * 1000; // Add 1 second to be sure event has started/stopped at next call … … 409 988 // Remove quests that are events only to non event npc 410 989 UpdateEventQuests(event_id, false); 990 // update npcflags in this event 991 UpdateEventNPCFlags(event_id); 992 // remove vendor items 993 UpdateEventNPCVendor(event_id, false); 411 994 } 412 995 … … 423 1006 424 1007 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 }432 1008 433 1009 // spawn positive event tagget objects … … 440 1016 // Add quests that are events only to non event npc 441 1017 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 1024 void 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 1050 void 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 } 442 1059 } 443 1060 … … 526 1143 for (GuidList::iterator itr = mGameEventCreatureGuids[internal_event_id].begin();itr != mGameEventCreatureGuids[internal_event_id].end();++itr) 527 1144 { 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; 528 1148 // Remove the creature from grid 529 1149 if( CreatureData const* data = objmgr.GetCreatureData(*itr) ) … … 547 1167 for (GuidList::iterator itr = mGameEventGameobjectGuids[internal_event_id].begin();itr != mGameEventGameobjectGuids[internal_event_id].end();++itr) 548 1168 { 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; 549 1172 // Remove the gameobject from grid 550 1173 if(GameObjectData const* data = objmgr.GetGOData(*itr)) … … 637 1260 } 638 1261 1262 bool 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 1276 bool 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 } 1289 bool 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 } 1305 bool 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 639 1322 void GameEvent::UpdateEventQuests(uint16 event_id, bool Activate) 640 1323 { 641 1324 QuestRelList::iterator itr; 642 for (itr = mGameEvent Quests[event_id].begin();itr != mGameEventQuests[event_id].end();++itr)1325 for (itr = mGameEventCreatureQuests[event_id].begin();itr != mGameEventCreatureQuests[event_id].end();++itr) 643 1326 { 644 1327 QuestRelations &CreatureQuestMap = objmgr.mCreatureQuestRelations; … … 646 1329 CreatureQuestMap.insert(QuestRelations::value_type(itr->first, itr->second)); 647 1330 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) 656 1340 { 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 } 659 1346 } 660 1347 } 661 1348 } 662 1349 } 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 }} 664 1375 665 1376 GameEvent::GameEvent() … … 667 1378 isSystemInit = false; 668 1379 } 1380 1381 void 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 1427 bool 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 1444 void 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 1455 void 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 1467 void 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 }