diff --git a/sql/310/1_mangos_item_template.sql b/sql/310/1_mangos_item_template.sql index ea3994516..04cbb180c 100644 --- a/sql/310/1_mangos_item_template.sql +++ b/sql/310/1_mangos_item_template.sql @@ -2,9 +2,9 @@ alter table `item_template` drop column `dmg_type3`, drop column `dmg_max3`, drop column `dmg_min3`, - drop column `dmg_type5`, - drop column `dmg_max5`, - drop column `dmg_min5`, drop column `dmg_type4`, drop column `dmg_max4`, - drop column `dmg_min4`; + drop column `dmg_min4`, + drop column `dmg_type5`, + drop column `dmg_max5`, + drop column `dmg_min5`; diff --git a/sql/mangos.sql b/sql/mangos.sql index 7302faea9..829a7586d 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -22,7 +22,7 @@ DROP TABLE IF EXISTS `db_version`; CREATE TABLE `db_version` ( `version` varchar(120) default NULL, - `required_7331_01_mangos_command` bit(1) default NULL + `required_7349_01_mangos_spell_area` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -275,7 +275,7 @@ INSERT INTO `command` VALUES ('demorph',2,'Syntax: .demorph\r\n\r\nDemorph the selected player.'), ('die',3,'Syntax: .die\r\n\r\nKill the selected player. If no player is selected, it will kill you.'), ('dismount',0,'Syntax: .dismount\r\n\r\nDismount you, if you are mounted.'), -('distance',3,'Syntax: .distance\r\n\r\nDisplay the distance from your character to the selected creature.'), +('distance',3,'Syntax: .distance [$name/$link]\r\n\r\nDisplay the distance from your character to the selected creature/player, or player with name $name, or player/creature/gameobject pointed to shift-link with guid.'), ('event',2,'Syntax: .event #event_id\r\nShow details about event with #event_id.'), ('event activelist',2,'Syntax: .event activelist\r\nShow list of currently active events.'), ('event start',2,'Syntax: .event start #event_id\r\nStart event #event_id. Set start time for event to current moment (change not saved in DB).'), @@ -13288,6 +13288,33 @@ LOCK TABLES `spell_affect` WRITE; /*!40000 ALTER TABLE `spell_affect` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Table structure for table `spell_area` +-- + +DROP TABLE IF EXISTS `spell_area`; +CREATE TABLE `spell_area` ( + `spell` mediumint(8) unsigned NOT NULL default '0', + `area` mediumint(8) unsigned NOT NULL default '0', + `quest_start` mediumint(8) unsigned NOT NULL default '0', + `quest_start_active` tinyint(1) unsigned NOT NULL default '0', + `quest_end` mediumint(8) unsigned NOT NULL default '0', + `aura_spell` mediumint(8) unsigned NOT NULL default '0', + `racemask` mediumint(8) unsigned NOT NULL default '0', + `gender` tinyint(1) unsigned NOT NULL default '2', + `autocast` tinyint(1) unsigned NOT NULL default '0', + PRIMARY KEY (`spell`,`area`,`quest_start`,`quest_start_active`,`aura_spell`,`racemask`,`gender`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `spell_area` +-- + +LOCK TABLES `spell_area` WRITE; +/*!40000 ALTER TABLE `spell_area` DISABLE KEYS */; +/*!40000 ALTER TABLE `spell_area` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `spell_chain` -- diff --git a/sql/updates/7332_01_mangos_command.sql b/sql/updates/7332_01_mangos_command.sql new file mode 100644 index 000000000..65248d19c --- /dev/null +++ b/sql/updates/7332_01_mangos_command.sql @@ -0,0 +1,6 @@ +ALTER TABLE db_version CHANGE COLUMN required_7331_01_mangos_command required_7332_01_mangos_command bit; + +DELETE FROM `command` WHERE `name` = 'distance'; + +INSERT INTO `command` VALUES +('distance',3,'Syntax: .distance [$name/$link]\r\n\r\nDisplay the distance from your character to the selected creature/player, or player with name $name, or player/creature/gameobject pointed to shift-link with guid.'); diff --git a/sql/updates/7349_01_mangos_spell_area.sql b/sql/updates/7349_01_mangos_spell_area.sql new file mode 100644 index 000000000..969fff950 --- /dev/null +++ b/sql/updates/7349_01_mangos_spell_area.sql @@ -0,0 +1,15 @@ +ALTER TABLE db_version CHANGE COLUMN required_7332_01_mangos_command required_7349_01_mangos_spell_area bit; + +DROP TABLE IF EXISTS `spell_area`; +CREATE TABLE `spell_area` ( + `spell` mediumint(8) unsigned NOT NULL default '0', + `area` mediumint(8) unsigned NOT NULL default '0', + `quest_start` mediumint(8) unsigned NOT NULL default '0', + `quest_start_active` tinyint(1) unsigned NOT NULL default '0', + `quest_end` mediumint(8) unsigned NOT NULL default '0', + `aura_spell` mediumint(8) unsigned NOT NULL default '0', + `racemask` mediumint(8) unsigned NOT NULL default '0', + `gender` tinyint(1) unsigned NOT NULL default '2', + `autocast` tinyint(1) unsigned NOT NULL default '0', + PRIMARY KEY (`spell`,`area`,`quest_start`,`quest_start_active`,`aura_spell`,`racemask`,`gender`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index edaf35255..6f9ec4dd4 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -186,6 +186,8 @@ pkgdata_DATA = \ 7324_01_characters_character_spell.sql \ 7324_02_characters_character_aura.sql \ 7331_01_mangos_command.sql \ + 7332_01_mangos_command.sql \ + 7349_01_mangos_spell_area.sql \ README ## Additional files to include when running 'make dist' @@ -352,4 +354,6 @@ EXTRA_DIST = \ 7324_01_characters_character_spell.sql \ 7324_02_characters_character_aura.sql \ 7331_01_mangos_command.sql \ + 7332_01_mangos_command.sql \ + 7349_01_mangos_spell_area.sql \ README diff --git a/src/bindings/universal/Makefile.am b/src/bindings/universal/Makefile.am index 9c605004c..2655e3aa0 100644 --- a/src/bindings/universal/Makefile.am +++ b/src/bindings/universal/Makefile.am @@ -25,13 +25,13 @@ AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(srcdir) -I$(srcdir)/../../../dep/include -I # libmangosscript shared library will later be reused by world server daemon. lib_LTLIBRARIES = libmangosscript.la libmangosscript_la_SOURCES = \ - ScriptMgr.cpp \ - ScriptMgr.h \ - config.h \ - system.cpp \ - Scripts/sc_default.cpp \ - Scripts/sc_defines.cpp \ - Scripts/sc_defines.h + ScriptMgr.cpp \ + ScriptMgr.h \ + config.h \ + system.cpp \ + Scripts/sc_default.cpp \ + Scripts/sc_defines.cpp \ + Scripts/sc_defines.h ## libtool settings # API versioning @@ -51,6 +51,6 @@ libmangosscript_la_LIBFLAGS = -version-info $(LTMANGOS_CURRENT):$(LTMANGOS_REVIS ## Additional files to include when running 'make dist' # Scripts defaults. EXTRA_DIST = \ - Scripts/sc_default.cpp \ - Scripts/sc_defines.cpp \ - Scripts/sc_defines.h + Scripts/sc_default.cpp \ + Scripts/sc_defines.cpp \ + Scripts/sc_defines.h diff --git a/src/framework/GameSystem/Grid.h b/src/framework/GameSystem/Grid.h index f1c826da0..ce1d5463e 100644 --- a/src/framework/GameSystem/Grid.h +++ b/src/framework/GameSystem/Grid.h @@ -103,7 +103,7 @@ class MANGOS_DLL_DECL Grid /** Returns the number of object within the grid. */ - unsigned int ActiveObjectsInGrid(void) const { return i_objects.template Count(); } + unsigned int ActiveObjectsInGrid(void) const { return m_activeGridObjects.size()+i_objects.template Count(); } /** Accessors: Returns a specific type of object in the GRID_OBJECT_TYPES */ @@ -112,11 +112,21 @@ class MANGOS_DLL_DECL Grid /** Inserts a container type object into the grid. */ - template bool AddGridObject(SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl) { return i_container.template insert(hdl, obj); } + template bool AddGridObject(SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl) + { + if(obj->isActiveObject()) + m_activeGridObjects.insert(obj); + return i_container.template insert(hdl, obj); + } /** Removes a containter type object from the grid */ - template bool RemoveGridObject(SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl) { return i_container.template remove(obj, hdl); } + template bool RemoveGridObject(SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl) + { + if(obj->isActiveObject()) + m_activeGridObjects.erase(obj); + return i_container.template remove(obj, hdl); + } private: @@ -125,5 +135,7 @@ class MANGOS_DLL_DECL Grid TypeMapContainer i_container; TypeMapContainer i_objects; + typedef std::set ActiveGridObjects; + ActiveGridObjects m_activeGridObjects; }; #endif diff --git a/src/framework/GameSystem/NGrid.h b/src/framework/GameSystem/NGrid.h index 663cf2059..469e47fb0 100644 --- a/src/framework/GameSystem/NGrid.h +++ b/src/framework/GameSystem/NGrid.h @@ -29,18 +29,26 @@ class GridInfo { public: - GridInfo() : i_timer(0) {} - GridInfo(time_t expiry, bool unload = true ) : i_timer(expiry), i_unloadflag(unload) {} + GridInfo() + : i_timer(0), i_unloadActiveLockCount(0), i_unloadExplicitLock(false), i_unloadReferenceLock(false) {} + GridInfo(time_t expiry, bool unload = true ) + : i_timer(expiry), i_unloadActiveLockCount(0), i_unloadExplicitLock(!unload), i_unloadReferenceLock(false) {} const TimeTracker& getTimeTracker() const { return i_timer; } - bool getUnloadFlag() const { return i_unloadflag; } - void setUnloadFlag( bool pFlag) { i_unloadflag = pFlag; } + bool getUnloadLock() const { return i_unloadActiveLockCount || i_unloadExplicitLock || i_unloadReferenceLock; } + void setUnloadExplicitLock( bool on ) { i_unloadExplicitLock = on; } + void setUnloadReferenceLock( bool on ) { i_unloadReferenceLock = on; } + void incUnloadActiveLock() { ++i_unloadActiveLockCount; } + void decUnloadActiveLock() { if(i_unloadActiveLockCount) --i_unloadActiveLockCount; } + void setTimer(const TimeTracker& pTimer) { i_timer = pTimer; } void ResetTimeTracker(time_t interval) { i_timer.Reset(interval); } void UpdateTimeTracker(time_t diff) { i_timer.Update(diff); } private: TimeTracker i_timer; - bool i_unloadflag; + uint16 i_unloadActiveLockCount : 16; // lock from active object spawn points (prevent clone loading) + bool i_unloadExplicitLock : 1; // explicit manual lock or config setting + bool i_unloadReferenceLock : 1; // lock from instance map copy }; typedef enum @@ -90,8 +98,11 @@ class MANGOS_DLL_DECL NGrid GridInfo* getGridInfoRef() { return &i_GridInfo; } const TimeTracker& getTimeTracker() const { return i_GridInfo.getTimeTracker(); } - bool getUnloadFlag() const { return i_GridInfo.getUnloadFlag(); } - void setUnloadFlag( bool pFlag) { i_GridInfo.setUnloadFlag(pFlag); } + bool getUnloadLock() const { return i_GridInfo.getUnloadLock(); } + void setUnloadExplicitLock( bool on ) { i_GridInfo.setUnloadExplicitLock(on); } + void setUnloadReferenceLock( bool on ) { i_GridInfo.setUnloadReferenceLock(on); } + void incUnloadActiveLock() { i_GridInfo.incUnloadActiveLock(); } + void decUnloadActiveLock() { i_GridInfo.decUnloadActiveLock(); } void ResetTimeTracker(time_t interval) { i_GridInfo.ResetTimeTracker(interval); } void UpdateTimeTracker(time_t diff) { i_GridInfo.UpdateTimeTracker(diff); } diff --git a/src/framework/Makefile.am b/src/framework/Makefile.am index a519dad42..748d5325e 100644 --- a/src/framework/Makefile.am +++ b/src/framework/Makefile.am @@ -25,39 +25,39 @@ AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(srcdir) # libMaNGOSScript shared library will later be reused by world server daemon. noinst_LIBRARIES = libmangosframework.a libmangosframework_a_SOURCES = \ - Policies/ObjectLifeTime.cpp \ - Utilities/EventProcessor.cpp + Policies/ObjectLifeTime.cpp \ + Utilities/EventProcessor.cpp ## Additional files to include when running 'make dist' # Source and header files for the Framework. EXTRA_DIST = \ - Dynamic/FactoryHolder.h \ - Dynamic/ObjectRegistry.h \ - GameSystem/Grid.h \ - GameSystem/GridLoader.h \ - GameSystem/GridRefManager.h \ - GameSystem/GridReference.h \ - GameSystem/NGrid.h \ - GameSystem/TypeContainer.h \ - GameSystem/TypeContainerFunctions.h \ - GameSystem/TypeContainerFunctionsPtr.h \ - GameSystem/TypeContainerVisitor.h \ - Network/SocketDefines.h \ - Platform/CompilerDefs.h \ - Platform/Define.h \ - Policies/CreationPolicy.h \ - Policies/ObjectLifeTime.h \ - Policies/Singleton.h \ - Policies/SingletonImp.h \ - Policies/ThreadingModel.h \ - Utilities/CountedReference/Reference.h \ - Utilities/CountedReference/ReferenceHolder.h \ - Utilities/CountedReference/ReferenceImpl.h \ - Utilities/LinkedReference/RefManager.h \ - Utilities/LinkedReference/Reference.h \ - Utilities/ByteConverter.h \ - Utilities/Callback.h \ - Utilities/EventProcessor.h \ - Utilities/UnorderedMap.h \ - Utilities/LinkedList.h \ - Utilities/TypeList.h + Dynamic/FactoryHolder.h \ + Dynamic/ObjectRegistry.h \ + GameSystem/Grid.h \ + GameSystem/GridLoader.h \ + GameSystem/GridRefManager.h \ + GameSystem/GridReference.h \ + GameSystem/NGrid.h \ + GameSystem/TypeContainer.h \ + GameSystem/TypeContainerFunctions.h \ + GameSystem/TypeContainerFunctionsPtr.h \ + GameSystem/TypeContainerVisitor.h \ + Network/SocketDefines.h \ + Platform/CompilerDefs.h \ + Platform/Define.h \ + Policies/CreationPolicy.h \ + Policies/ObjectLifeTime.h \ + Policies/Singleton.h \ + Policies/SingletonImp.h \ + Policies/ThreadingModel.h \ + Utilities/CountedReference/Reference.h \ + Utilities/CountedReference/ReferenceHolder.h \ + Utilities/CountedReference/ReferenceImpl.h \ + Utilities/LinkedReference/RefManager.h \ + Utilities/LinkedReference/Reference.h \ + Utilities/ByteConverter.h \ + Utilities/Callback.h \ + Utilities/EventProcessor.h \ + Utilities/UnorderedMap.h \ + Utilities/LinkedList.h \ + Utilities/TypeList.h diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index 989c1be35..52adc738a 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -86,7 +86,6 @@ const CriteriaCastSpellRequirement AchievementGlobalMgr::m_criteriaCastSpellRequ {6662, 31261, 0, 0} }; - namespace MaNGOS { class AchievementChatBuilder @@ -573,11 +572,11 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui uint32 spellCount = 0; for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin(); spellIter != GetPlayer()->GetSpellMap().end(); - spellIter++) + ++spellIter) { for(SkillLineAbilityMap::const_iterator skillIter = spellmgr.GetBeginSkillLineAbilityMap(spellIter->first); skillIter != spellmgr.GetEndSkillLineAbilityMap(spellIter->first); - skillIter++) + ++skillIter) { if(skillIter->second->skillId == achievementCriteria->learn_skilline_spell.skillLine) spellCount++; @@ -605,7 +604,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui { uint32 counter = 0; const FactionStateList factionStateList = GetPlayer()->GetFactionStateList(); - for (FactionStateList::const_iterator iter = factionStateList.begin(); iter!= factionStateList.end(); iter++) + for (FactionStateList::const_iterator iter = factionStateList.begin(); iter!= factionStateList.end(); ++iter) { if(GetPlayer()->ReputationToRank(iter->second.Standing) >= REP_EXALTED) ++counter; @@ -727,6 +726,9 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui } } +static const uint32 achievIdByClass[MAX_CLASSES] = { 0, 459, 465 , 462, 458, 464, 461, 467, 460, 463, 0, 466 }; +static const uint32 achievIdByRace[MAX_RACES] = { 0, 1408, 1410, 1407, 1409, 1413, 1411, 1404, 1412, 0, 1405, 1406 }; + bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria) { AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementCriteria->referredAchievement); @@ -753,29 +755,12 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve switch(achievementCriteria->requiredType) { case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: - if ((achievement->ID == 467 && GetPlayer()->getClass() != CLASS_SHAMAN ) || - (achievement->ID == 466 && GetPlayer()->getClass() != CLASS_DRUID ) || - (achievement->ID == 465 && GetPlayer()->getClass() != CLASS_PALADIN ) || - (achievement->ID == 464 && GetPlayer()->getClass() != CLASS_PRIEST ) || - (achievement->ID == 463 && GetPlayer()->getClass() != CLASS_WARLOCK ) || - (achievement->ID == 462 && GetPlayer()->getClass() != CLASS_HUNTER ) || - (achievement->ID == 461 && GetPlayer()->getClass() != CLASS_DEATH_KNIGHT)|| - (achievement->ID == 460 && GetPlayer()->getClass() != CLASS_MAGE ) || - (achievement->ID == 459 && GetPlayer()->getClass() != CLASS_WARRIOR ) || - (achievement->ID == 458 && GetPlayer()->getClass() != CLASS_ROGUE ) || - - (achievement->ID == 1404 && GetPlayer()->getRace() != RACE_GNOME ) || - (achievement->ID == 1405 && GetPlayer()->getRace() != RACE_BLOODELF ) || - (achievement->ID == 1406 && GetPlayer()->getRace() != RACE_DRAENEI ) || - (achievement->ID == 1407 && GetPlayer()->getRace() != RACE_DWARF ) || - (achievement->ID == 1408 && GetPlayer()->getRace() != RACE_HUMAN ) || - (achievement->ID == 1409 && GetPlayer()->getRace() != RACE_NIGHTELF ) || - (achievement->ID == 1410 && GetPlayer()->getRace() != RACE_ORC ) || - (achievement->ID == 1411 && GetPlayer()->getRace() != RACE_TAUREN ) || - (achievement->ID == 1412 && GetPlayer()->getRace() != RACE_TROLL ) || - (achievement->ID == 1413 && GetPlayer()->getRace() != RACE_UNDEAD_PLAYER) ) - return false; - return progress->counter >= achievementCriteria->reach_level.level; + { + if (achievIdByClass[GetPlayer()->getClass()] == achievement->ID || + achievIdByRace[GetPlayer()->getRace()] == achievement->ID) + return progress->counter >= achievementCriteria->reach_level.level; + return false; + } case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT: return progress->counter >= achievementCriteria->buy_bank_slot.numberOfSlots; case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: diff --git a/src/game/AuctionHouseMgr.cpp b/src/game/AuctionHouseMgr.cpp index 7db668ab0..b5370c19b 100644 --- a/src/game/AuctionHouseMgr.cpp +++ b/src/game/AuctionHouseMgr.cpp @@ -49,6 +49,9 @@ AuctionHouseMgr::~AuctionHouseMgr() AuctionHouseObject * AuctionHouseMgr::GetAuctionsMap( uint32 factionTemplateId ) { + if(sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) + return &mNeutralAuctions; + // team have linked auction houses FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(factionTemplateId); if(!u_entry) @@ -456,7 +459,7 @@ void AuctionHouseMgr::Update() AuctionHouseEntry const* AuctionHouseMgr::GetAuctionHouseEntry(uint32 factionTemplateId) { - uint32 houseid = 1; // human auction house + uint32 houseid = 1; // dwarf auction house (used for normal cut/etc percents) if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) { diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index 1790df0e5..530ec6b3e 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -39,7 +39,7 @@ BattleGround::BattleGround() m_Status = 0; m_EndTime = 0; m_LastResurrectTime = 0; - m_QueueId = MAX_BATTLEGROUND_QUEUES; + m_QueueId = QUEUE_ID_MAX_LEVEL_19; m_InvitedAlliance = 0; m_InvitedHorde = 0; m_ArenaType = 0; @@ -115,7 +115,7 @@ BattleGround::~BattleGround() // remove from battlegrounds } - sBattleGroundMgr.RemoveBattleGround(GetInstanceID()); + sBattleGroundMgr.RemoveBattleGround(GetInstanceID(), GetTypeID()); // unload map if(Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID())) if(map->IsBattleGroundOrArena()) @@ -130,8 +130,6 @@ void BattleGround::Update(uint32 diff) //BG is empty return; - WorldPacket data; - if(GetRemovedPlayersSize()) { for(std::map::iterator itr = m_RemovedPlayers.begin(); itr != m_RemovedPlayers.end(); ++itr) @@ -139,16 +137,6 @@ void BattleGround::Update(uint32 diff) Player *plr = objmgr.GetPlayer(itr->first); switch(itr->second) { - //following code is handled by event: - /*case 0: - sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].RemovePlayer(itr->first); - //RemovePlayerFromQueue(itr->first); - if(plr) - { - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0); - plr->GetSession()->SendPacket(&data); - } - break;*/ case 1: // currently in bg and was removed from bg if(plr) RemovePlayerAtLeave(itr->first, true, true); @@ -827,7 +815,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac DecreaseInvitedCount(team); //we should update battleground queue, but only if bg isn't ending - if (GetQueueId() < MAX_BATTLEGROUND_QUEUES) + if (GetStatus() < STATUS_WAIT_LEAVE) sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueId()); Group * group = plr->GetGroup(); @@ -847,7 +835,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac } // Do next only if found in battleground - plr->SetBattleGroundId(0); // We're not in BG. + plr->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG. // reset destination bg team plr->SetBGTeam(0); @@ -874,7 +862,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac // this method is called when no players remains in battleground void BattleGround::Reset() { - SetQueueId(MAX_BATTLEGROUND_QUEUES); + SetQueueId(QUEUE_ID_MAX_LEVEL_19); SetWinner(WINNER_NONE); SetStatus(STATUS_WAIT_QUEUE); SetStartTime(0); @@ -1009,7 +997,7 @@ void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid, void BattleGround::AddToBGFreeSlotQueue() { // make sure to add only once - if(!m_InBGFreeSlotQueue) + if(!m_InBGFreeSlotQueue && isBattleGround()) { sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this); m_InBGFreeSlotQueue = true; @@ -1022,7 +1010,7 @@ void BattleGround::RemoveFromBGFreeSlotQueue() // set to be able to re-add if needed m_InBGFreeSlotQueue = false; // uncomment this code when battlegrounds will work like instances - for (std::deque::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr) + for (BGFreeSlotQueueType::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr) { if ((*itr)->GetInstanceID() == m_InstanceID) { @@ -1033,61 +1021,12 @@ void BattleGround::RemoveFromBGFreeSlotQueue() } // get the number of free slots for team -// works in similar way that HasFreeSlotsForTeam did, but this is needed for join as group +// returns the number how many players can join battleground to MaxPlayersPerTeam uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const { //if BG is starting ... invite anyone - if (GetStatus() == STATUS_WAIT_JOIN) + if (GetStatus() == STATUS_WAIT_JOIN || GetStatus() == STATUS_IN_PROGRESS) return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0; - //if BG is already started .. do not allow to join too much players of one faction - uint32 otherTeam; - uint32 otherIn; - if (Team == ALLIANCE) - { - otherTeam = GetInvitedCount(HORDE); - otherIn = GetPlayersCountByTeam(HORDE); - } - else - { - otherTeam = GetInvitedCount(ALLIANCE); - otherIn = GetPlayersCountByTeam(ALLIANCE); - } - if (GetStatus() == STATUS_IN_PROGRESS) - { - // difference based on ppl invited (not necessarily entered battle) - // default: allow 0 - uint32 diff = 0; - // allow join one person if the sides are equal (to fill up bg to minplayersperteam) - if (otherTeam == GetInvitedCount(Team)) - diff = 1; - // allow join more ppl if the other side has more players - else if(otherTeam > GetInvitedCount(Team)) - diff = otherTeam - GetInvitedCount(Team); - - // difference based on max players per team (don't allow inviting more) - uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0; - - // difference based on players who already entered - // default: allow 0 - uint32 diff3 = 0; - // allow join one person if the sides are equal (to fill up bg minplayersperteam) - if (otherIn == GetPlayersCountByTeam(Team)) - diff3 = 1; - // allow join more ppl if the other side has more players - else if (otherIn > GetPlayersCountByTeam(Team)) - diff3 = otherIn - GetPlayersCountByTeam(Team); - // or other side has less than minPlayersPerTeam - else if (GetInvitedCount(Team) <= GetMinPlayersPerTeam()) - diff3 = GetMinPlayersPerTeam() - GetInvitedCount(Team) + 1; - - // return the minimum of the 3 differences - - // min of diff and diff 2 - diff = diff < diff2 ? diff : diff2; - - // min of diff, diff2 and diff3 - return diff < diff3 ? diff : diff3 ; - } return 0; } diff --git a/src/game/BattleGround.h b/src/game/BattleGround.h index 4590ed839..696ef84b5 100644 --- a/src/game/BattleGround.h +++ b/src/game/BattleGround.h @@ -86,6 +86,7 @@ enum BattleGroundTimeIntervals { RESURRECTION_INTERVAL = 30000, // ms REMIND_INTERVAL = 30000, // ms + INVITATION_REMIND_TIME = 60000, // ms INVITE_ACCEPT_WAIT_TIME = 80000, // ms TIME_TO_AUTOREMOVE = 120000, // ms MAX_OFFLINE_TIME = 300000, // ms @@ -135,16 +136,30 @@ struct BattleGroundObjectInfo // handle the queue types and bg types separately to enable joining queue for different sized arenas at the same time enum BattleGroundQueueTypeId { - BATTLEGROUND_QUEUE_NONE = 0, - BATTLEGROUND_QUEUE_AV = 1, - BATTLEGROUND_QUEUE_WS = 2, - BATTLEGROUND_QUEUE_AB = 3, - BATTLEGROUND_QUEUE_EY = 4, - BATTLEGROUND_QUEUE_SA = 5, - BATTLEGROUND_QUEUE_2v2 = 6, - BATTLEGROUND_QUEUE_3v3 = 7, - BATTLEGROUND_QUEUE_5v5 = 8, + BATTLEGROUND_QUEUE_NONE = 0, + BATTLEGROUND_QUEUE_AV = 1, + BATTLEGROUND_QUEUE_WS = 2, + BATTLEGROUND_QUEUE_AB = 3, + BATTLEGROUND_QUEUE_EY = 4, + BATTLEGROUND_QUEUE_SA = 5, + BATTLEGROUND_QUEUE_2v2 = 6, + BATTLEGROUND_QUEUE_3v3 = 7, + BATTLEGROUND_QUEUE_5v5 = 8 }; +#define MAX_BATTLEGROUND_QUEUE_TYPES 9 + +enum BGQueueIdBasedOnLevel // queue_id for level ranges +{ + QUEUE_ID_MAX_LEVEL_19 = 0, + QUEUE_ID_MAX_LEVEL_29 = 1, + QUEUE_ID_MAX_LEVEL_39 = 2, + QUEUE_ID_MAX_LEVEL_49 = 3, + QUEUE_ID_MAX_LEVEL_59 = 4, + QUEUE_ID_MAX_LEVEL_69 = 5, + QUEUE_ID_MAX_LEVEL_79 = 6, + QUEUE_ID_MAX_LEVEL_80 = 7 +}; +#define MAX_BATTLEGROUND_QUEUES 8 enum ScoreType { @@ -197,6 +212,7 @@ enum BattleGroundTeamId BG_TEAM_ALLIANCE = 0, BG_TEAM_HORDE = 1 }; +#define BG_TEAMS_COUNT 2 enum BattleGroundJoinError { @@ -255,7 +271,7 @@ class BattleGround // Get methods: char const* GetName() const { return m_Name; } BattleGroundTypeId GetTypeID() const { return m_TypeID; } - uint32 GetQueueId() const { return m_QueueId; } + BGQueueIdBasedOnLevel GetQueueId() const { return m_QueueId; } uint32 GetInstanceID() const { return m_InstanceID; } uint32 GetStatus() const { return m_Status; } uint32 GetStartTime() const { return m_StartTime; } @@ -278,7 +294,13 @@ class BattleGround // Set methods: void SetName(char const* Name) { m_Name = Name; } void SetTypeID(BattleGroundTypeId TypeID) { m_TypeID = TypeID; } - void SetQueueId(uint32 ID) { m_QueueId = ID; } + //here we can count minlevel and maxlevel for players + void SetQueueId(BGQueueIdBasedOnLevel ID) + { + m_QueueId = ID; + uint8 diff = (m_TypeID == BATTLEGROUND_AV) ? 1 : 0; + this->SetLevelRange((ID + 1) * 10 + diff, (ID + 2) * 10 - ((diff + 1) % 2)); + } void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; } void SetStatus(uint32 Status) { m_Status = Status; } void SetStartTime(uint32 Time) { m_StartTime = Time; } @@ -310,7 +332,6 @@ class BattleGround else return m_InvitedHorde; } - bool HasFreeSlotsForTeam(uint32 Team) const; bool HasFreeSlots() const; uint32 GetFreeSlotsForTeam(uint32 Team) const; @@ -472,7 +493,7 @@ class BattleGround uint32 m_StartTime; uint32 m_EndTime; uint32 m_LastResurrectTime; - uint32 m_QueueId; + BGQueueIdBasedOnLevel m_QueueId; uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5 bool m_InBGFreeSlotQueue; // used to make sure that BG is only once inserted into the BattleGroundMgr.BGFreeSlotQueue[bgTypeId] deque bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave @@ -498,15 +519,15 @@ class BattleGround uint32 m_InvitedHorde; /* Raid Group */ - Group *m_BgRaids[2]; // 0 - alliance, 1 - horde + Group *m_BgRaids[BG_TEAMS_COUNT]; // 0 - alliance, 1 - horde /* Players count by team */ - uint32 m_PlayersCount[2]; + uint32 m_PlayersCount[BG_TEAMS_COUNT]; /* Arena team ids by team */ - uint32 m_ArenaTeamIds[2]; + uint32 m_ArenaTeamIds[BG_TEAMS_COUNT]; - int32 m_ArenaTeamRatingChanges[2]; + int32 m_ArenaTeamRatingChanges[BG_TEAMS_COUNT]; /* Limits */ uint32 m_LevelMin; @@ -518,9 +539,9 @@ class BattleGround /* Location */ uint32 m_MapId; - float m_TeamStartLocX[2]; - float m_TeamStartLocY[2]; - float m_TeamStartLocZ[2]; - float m_TeamStartLocO[2]; + float m_TeamStartLocX[BG_TEAMS_COUNT]; + float m_TeamStartLocY[BG_TEAMS_COUNT]; + float m_TeamStartLocZ[BG_TEAMS_COUNT]; + float m_TeamStartLocO[BG_TEAMS_COUNT]; }; #endif diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp index dca996662..0098490e1 100644 --- a/src/game/BattleGroundHandler.cpp +++ b/src/game/BattleGroundHandler.cpp @@ -78,6 +78,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) uint32 bgTypeId_; uint32 instanceId; uint8 joinAsGroup; + bool isPremade = false; Group * grp; recv_data >> guid; // battlemaster guid @@ -112,7 +113,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) // get bg instance or bg template if instance not found BattleGround * bg = 0; if(instanceId) - BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId); + BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId, bgTypeId); if(!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId))) { @@ -146,6 +147,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) if(!grp) return; uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0); + isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam()); if (err != BG_JOIN_ERR_OK) { SendBattleGroundOrArenaJoinError(err); @@ -158,7 +160,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) if(joinAsGroup /* && _player->GetGroup()*/) { sLog.outDebug("Battleground: the following players are joining as group:"); - GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0); + GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, isPremade, 0); for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { Player *member = itr->getSource(); @@ -195,7 +197,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0); SendPacket(&data); - GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0); + GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, false, 0); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); if(!ginfo->IsInvitedToBGInstanceGUID) @@ -316,8 +318,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) if(!bgQueueTypeId) continue; BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); - uint32 queue_id = _player->GetBattleGroundQueueIdFromLevel(bgTypeId); - BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[queue_id]; + BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); // if the player is not in queue, continue if(itrPlayerStatus == qpMap.end()) @@ -344,7 +345,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) else { // get the bg we're invited to - BattleGround * bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID); + BattleGround * bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID, bgTypeId); status = STATUS_WAIT_JOIN; } @@ -370,7 +371,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) BattleGroundQueueTypeId bgQueueTypeId = BATTLEGROUND_QUEUE_NONE; // get the bg what we were invited to bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId,type); - BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel(bgTypeId)]; + BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); if(itrPlayerStatus == qpMap.end()) { @@ -386,7 +387,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) return; } - BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId); + BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId, bgTypeId); // bg template might and must be used in case of leaving queue, when instance is not created yet if(!bg && action == 0) @@ -410,7 +411,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) uint32 opponentsRating = 0; // get the team info from the queue - BattleGroundQueue::QueuedPlayersMap& qpMap2 = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel(bgTypeId)]; + BattleGroundQueue::QueuedPlayersMap& qpMap2 = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::iterator pitr = qpMap2.find(_player->GetGUID()); if (pitr !=qpMap2.end() && pitr->second.GroupInfo) { @@ -455,11 +456,11 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); // set the destination instance id - _player->SetBattleGroundId(bg->GetInstanceID()); + _player->SetBattleGroundId(bg->GetInstanceID(), bgTypeId); // set the destination team _player->SetBGTeam(team); // bg->HandleBeforeTeleportToBattleGround(_player); - sBattleGroundMgr.SendToBattleGround(_player, instanceId); + sBattleGroundMgr.SendToBattleGround(_player, instanceId, bgTypeId); // add only in HandleMoveWorldPortAck() // bg->AddPlayer(_player,team); sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetInstanceID(),bg->GetTypeID(),bgQueueTypeId); @@ -546,8 +547,7 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ ) BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); uint8 arenatype = BattleGroundMgr::BGArenaType(bgQueueTypeId); uint8 isRated = 0; - uint32 queue_id = _player->GetBattleGroundQueueIdFromLevel(bgTypeId); - BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[queue_id]; + BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); if(itrPlayerStatus == qpMap.end()) continue; @@ -578,9 +578,8 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ ) BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); uint8 arenatype = BattleGroundMgr::BGArenaType(bgQueueTypeId); uint8 isRated = 0; - uint32 queue_id = _player->GetBattleGroundQueueIdFromLevel(bgTypeId); BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[queue_id]; + BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); if(itrPlayerStatus == qpMap.end()) continue; @@ -768,7 +767,7 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data ) if(asGroup) { - GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating, ateamId); + GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating, ateamId); sLog.outDebug("Battleground: arena join as group start"); if(isRated) sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype); @@ -807,7 +806,7 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data ) // send status packet (in queue) sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated); SendPacket(&data); - GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating); + GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenatype, isRated, arenaRating); sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp index 73345aafb..457b36c70 100644 --- a/src/game/BattleGroundMgr.cpp +++ b/src/game/BattleGroundMgr.cpp @@ -52,159 +52,90 @@ INSTANTIATE_SINGLETON_1( BattleGroundMgr ); BattleGroundQueue::BattleGroundQueue() { - //queues are empty, we don't have to call clear() } BattleGroundQueue::~BattleGroundQueue() { + m_QueuedPlayers.clear(); for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++) { - m_QueuedPlayers[i].clear(); - for(QueuedGroupsList::iterator itr = m_QueuedGroups[i].begin(); itr!= m_QueuedGroups[i].end(); ++itr) + for(uint32 j = 0; j < BG_QUEUE_GROUP_TYPES_COUNT; j++) { - delete (*itr); - } - m_QueuedGroups[i].clear(); - } -} - -// initialize eligible groups from the given source matching the given specifications -void BattleGroundQueue::EligibleGroups::Init(BattleGroundQueue::QueuedGroupsList *source, BattleGroundTypeId BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType, bool IsRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime, uint32 excludeTeam) -{ - // clear from prev initialization - clear(); - BattleGroundQueue::QueuedGroupsList::iterator itr, next; - // iterate through the source - for(itr = source->begin(); itr!= source->end(); itr = next) - { - next = itr; - ++next; - if( (*itr)->BgTypeId == BgTypeId && // bg type must match - (*itr)->ArenaType == ArenaType && // arena type must match - (*itr)->IsRated == IsRated && // israted must match - (*itr)->IsInvitedToBGInstanceGUID == 0 && // leave out already invited groups - (*itr)->Team == side && // match side - (*itr)->Players.size() <= MaxPlayers && // the group must fit in the bg - ( !excludeTeam || (*itr)->ArenaTeamId != excludeTeam ) && // if excludeTeam is specified, leave out those arena team ids - ( !IsRated || (*itr)->Players.size() == MaxPlayers ) && // if rated, then pass only if the player count is exact NEEDS TESTING! (but now this should never happen) - ( (*itr)->JoinTime <= DisregardTime // pass if disregard time is greater than join time - || (*itr)->ArenaTeamRating == 0 // pass if no rating info - || ( (*itr)->ArenaTeamRating >= MinRating // pass if matches the rating range - && (*itr)->ArenaTeamRating <= MaxRating ) ) ) - { - // the group matches the conditions - // insert it in order of groupsize, and join time - uint32 size = (*itr)->Players.size(); - uint32 jointime = (*itr)->JoinTime; - bool inserted = false; - - for(std::list::iterator elig_itr = begin(); elig_itr != end(); ++elig_itr) - { - // if the next one's size is smaller, then insert - // also insert if the next one's size is equal, but it joined the queue later - if( ((*elig_itr)->Players.size()Players.size() == size && (*elig_itr)->JoinTime > jointime) ) - { - insert(elig_itr,(*itr)); - inserted = true; - break; - } - } - // if not inserted -> this is the smallest group -> push_back - if(!inserted) - { - push_back((*itr)); - } + for(GroupsQueueType::iterator itr = m_QueuedGroups[i][j].begin(); itr!= m_QueuedGroups[i][j].end(); ++itr) + delete (*itr); + m_QueuedGroups[i][j].clear(); } } } -// remove group from eligible groups -// used when building selection pools -void BattleGroundQueue::EligibleGroups::RemoveGroup(GroupQueueInfo * ginfo) -{ - for(std::list::iterator itr = begin(); itr != end(); ++itr) - { - if((*itr)==ginfo) - { - erase(itr); - return; - } - } -} +/*********************************************************/ +/*** BATTLEGROUND QUEUE SELECTION POOLS ***/ +/*********************************************************/ // selection pool initialization, used to clean up from prev selection void BattleGroundQueue::SelectionPool::Init() { SelectedGroups.clear(); - MaxGroup = 0; PlayerCount = 0; } -// get the maximal group from the selection pool -// used when building the pool, and have to remove the largest -GroupQueueInfo * BattleGroundQueue::SelectionPool::GetMaximalGroup() -{ - if(SelectedGroups.empty()) - { - sLog.outError("Getting max group when selection pool is empty, this should never happen."); - MaxGroup = NULL; - return 0; - } - // actually select the max group if it's not set - if(MaxGroup==0 && !SelectedGroups.empty()) - { - uint32 max_size = 0; - for(std::list::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr) - { - if(max_size<(*itr)->Players.size()) - { - MaxGroup =(*itr); - max_size = MaxGroup->Players.size(); - } - } - } - return MaxGroup; -} - // remove group info from selection pool -// used when building selection pools and have to remove maximal group -void BattleGroundQueue::SelectionPool::RemoveGroup(GroupQueueInfo *ginfo) +// returns true when we need to try to add new group to selection pool +// or false when pool is ok +// sometimes it can be called on empty selection pool +bool BattleGroundQueue::SelectionPool::KickGroup(uint32 size) { - // uninitiate max group info if needed - if(MaxGroup == ginfo) - MaxGroup = 0; - // find what to remove - for(std::list::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr) + //find maxgroup or LAST group with size == size and kick it + bool found = false; + GroupsQueueType::iterator groupToKick = SelectedGroups.begin(); + for (GroupsQueueType::iterator itr = groupToKick; itr != SelectedGroups.end(); ++itr) { - if((*itr)==ginfo) + if( abs((int32)((*itr)->Players.size() - size)) <= 1 ) { - SelectedGroups.erase(itr); - // decrease selected players count - PlayerCount -= ginfo->Players.size(); - return; + groupToKick = itr; + found = true; } + else if (!found && (*itr)->Players.size() >= (*groupToKick)->Players.size()) + groupToKick = itr; } + //if pool is empty, do nothing + if( GetPlayerCount() ) + { + //update player count + GroupQueueInfo* ginfo = (*groupToKick); + SelectedGroups.erase(groupToKick); + PlayerCount -= ginfo->Players.size(); + if (abs((int32)(ginfo->Players.size() - size)) <= 1) + return false; + } + return true; } -// add group to selection +// add group to selection pool // used when building selection pools -void BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo * ginfo) +// returns true if we can invite more players, otherwise return false - (selection pool is set that time) +bool BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo *ginfo, uint32 desiredCount) { - SelectedGroups.push_back(ginfo); - // increase selected players count - PlayerCount+=ginfo->Players.size(); - if(!MaxGroup || ginfo->Players.size() > MaxGroup->Players.size()) + //if group is larger than desired count - don't allow to add it to pool + if (!ginfo->IsInvitedToBGInstanceGUID && desiredCount >= PlayerCount + ginfo->Players.size()) { - // update max group info if needed - MaxGroup = ginfo; + SelectedGroups.push_back(ginfo); + // increase selected players count + PlayerCount += ginfo->Players.size(); } + if (PlayerCount == desiredCount) + return true; + return false; } +/*********************************************************/ +/*** BATTLEGROUND QUEUES ***/ +/*********************************************************/ + // add group to bg queue with the given leader and bg specifications -GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId BgTypeId, uint8 ArenaType, bool isRated, uint32 arenaRating, uint32 arenateamid) +GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId BgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 arenaRating, uint32 arenateamid) { - uint32 queue_id = leader->GetBattleGroundQueueIdFromLevel(BgTypeId); + BGQueueIdBasedOnLevel queue_id = leader->GetBattleGroundQueueIdFromLevel(BgTypeId); // create new ginfo // cannot use the method like in addplayer, because that could modify an in-queue group's stats @@ -214,26 +145,33 @@ GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId ginfo->ArenaType = ArenaType; ginfo->ArenaTeamId = arenateamid; ginfo->IsRated = isRated; - ginfo->IsInvitedToBGInstanceGUID = 0; // maybe this should be modifiable by function arguments to enable selection of running instances? + ginfo->IsInvitedToBGInstanceGUID = 0; ginfo->JoinTime = getMSTime(); ginfo->Team = leader->GetTeam(); ginfo->ArenaTeamRating = arenaRating; - ginfo->OpponentsTeamRating = 0; //initialize it to 0 + ginfo->OpponentsTeamRating = 0; ginfo->Players.clear(); - m_QueuedGroups[queue_id].push_back(ginfo); + //compute index (if group is premade or joined a rated match) to queues + uint32 index = 0; + if(!isRated && !isPremade) + index += BG_TEAMS_COUNT; + if(ginfo->Team == HORDE) + index++; + sLog.outDebug("Adding Group to BattleGroundQueue bgTypeId : %u, queue_id : %u, index : %u", BgTypeId, queue_id, index); + + m_QueuedGroups[queue_id][index].push_back(ginfo); // return ginfo, because it is needed to add players to this group info return ginfo; } +//add player to playermap void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo) { - uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel(ginfo->BgTypeId); - //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak - PlayerQueueInfo& info = m_QueuedPlayers[queue_id][plr->GetGUID()]; + PlayerQueueInfo& info = m_QueuedPlayers[plr->GetGUID()]; info.InviteTime = 0; info.LastInviteTime = 0; info.LastOnlineTime = getMSTime(); @@ -243,112 +181,116 @@ void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo) ginfo->Players[plr->GetGUID()] = &info; } +//remove player from queue and from group info, if group info is empty then remove it too void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount) { - Player *plr = objmgr.GetPlayer(guid); + //Player *plr = objmgr.GetPlayer(guid); - int32 queue_id = 0; // signed for proper for-loop finish + int32 queue_id = -1; // signed for proper for-loop finish QueuedPlayersMap::iterator itr; - // mostly people with the highest levels are in battlegrounds, thats why - // we count from MAX_BATTLEGROUND_QUEUES to 0 - for (queue_id = MAX_BATTLEGROUND_QUEUES-1; queue_id >= 0; queue_id--) + //remove player from map, if he's there + itr = m_QueuedPlayers.find(guid); + if( itr == m_QueuedPlayers.end() ) { - itr = m_QueuedPlayers[queue_id].find(guid); - if(itr != m_QueuedPlayers[queue_id].end()) - break; - } - - // couldn't find the player in bg queue, return - if(queue_id == -1) - { - sLog.outError("Battleground: couldn't find player to remove."); + sLog.outError("BattleGroundQueue: couldn't find player to remove GUID: %u", GUID_LOPART(guid)); return; } GroupQueueInfo* group = itr->second.GroupInfo; + GroupsQueueType::iterator group_itr, group_itr_tmp; + // mostly people with the highest levels are in battlegrounds, thats why + // we count from MAX_BATTLEGROUND_QUEUES - 1 to 0 + // variable index removes useless searching in other team's queue + uint32 index = (group->Team == HORDE) ? BG_TEAM_HORDE : BG_TEAM_ALLIANCE; - QueuedGroupsList::iterator group_itr = m_QueuedGroups[queue_id].begin(); - for(; group_itr != m_QueuedGroups[queue_id].end(); ++group_itr) + for (int32 queue_id_tmp = MAX_BATTLEGROUND_QUEUES - 1; queue_id_tmp >= 0 && queue_id == -1; --queue_id_tmp) { - if(group == *group_itr) - break; + //we must check premade and normal team's queue - because when players from premade are joining bg, + //they leave groupinfo so we can't use its players size to find out index + for (uint32 j = index; j < BG_QUEUE_GROUP_TYPES_COUNT; j += BG_QUEUE_NORMAL_ALLIANCE) + { + for(group_itr_tmp = m_QueuedGroups[queue_id_tmp][j].begin(); group_itr_tmp != m_QueuedGroups[queue_id_tmp][j].end(); ++group_itr_tmp) + { + if( (*group_itr_tmp) == group ) + { + queue_id = queue_id_tmp; + group_itr = group_itr_tmp; + //we must store index to be able to erase iterator + index = j; + break; + } + } + } } + //player can't be in queue without group, but just in case + if( queue_id == -1 ) + { + sLog.outError("BattleGroundQueue: ERROR Cannot find groupinfo for player GUID: %u", GUID_LOPART(guid)); + return; + } + sLog.outDebug("BattleGroundQueue: Removing player GUID %u, from queue_id %u", GUID_LOPART(guid), (uint32)queue_id); - // variables are set (what about leveling up when in queue???? - // iterate through all queue_ids this isn't bad for us) + // ALL variables are corrcetly set + // We can ignore leveling up in queue - it should not cause crash // remove player from group - // if only player there, remove group + // if only one player there, remove group // remove player queue info from group queue info std::map::iterator pitr = group->Players.find(guid); - - if(pitr != group->Players.end()) + if( pitr != group->Players.end() ) group->Players.erase(pitr); - // check for iterator correctness - if (group_itr != m_QueuedGroups[queue_id].end() && itr != m_QueuedPlayers[queue_id].end()) + // if invited to bg, and should decrease invited count, then do it + if( decreaseInvitedCount && group->IsInvitedToBGInstanceGUID ) { - // used when player left the queue, NOT used when porting to bg - if (decreaseInvitedCount) - { - // if invited to bg, and should decrease invited count, then do it - if(group->IsInvitedToBGInstanceGUID) - { - BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID); - if (bg) - bg->DecreaseInvitedCount(group->Team); - if (bg && !bg->GetPlayersSize() && !bg->GetInvitedCount(ALLIANCE) && !bg->GetInvitedCount(HORDE)) - { - // no more players on battleground, set delete it - bg->SetDeleteThis(); - } - } - // update the join queue, maybe now the player's group fits in a queue! - // not yet implemented (should store bgTypeId in group queue info?) - } - // remove player queue info - m_QueuedPlayers[queue_id].erase(itr); - // remove group queue info if needed + BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID, group->BgTypeId); + if( bg ) + bg->DecreaseInvitedCount(group->Team); + } - //if we left BG queue(not porting) OR if arena team left queue for rated match - if((decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty())) - AnnounceWorld(group, guid, false); + // remove player queue info + m_QueuedPlayers.erase(itr); - if(group->Players.empty()) + //if we left BG queue(not porting) OR if arena team left queue for rated match + if( (decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty()) ) + AnnounceWorld(group, guid, false); + + // remove group queue info if needed + if( group->Players.empty() ) + { + m_QueuedGroups[queue_id][index].erase(group_itr); + delete group; + } + // if group wasn't empty, so it wasn't deleted, and player have left a rated + // queue -> everyone from the group should leave too + // don't remove recursively if already invited to bg! + else if( !group->IsInvitedToBGInstanceGUID && group->IsRated ) + { + // remove next player, this is recursive + // first send removal information + if(Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first)) { - m_QueuedGroups[queue_id].erase(group_itr); - delete group; - } - // NEEDS TESTING! - // group wasn't empty, so it wasn't deleted, and player have left a rated queue -> everyone from the group should leave too - // don't remove recursively if already invited to bg! - else if(!group->IsInvitedToBGInstanceGUID && decreaseInvitedCount && group->IsRated) - { - // remove next player, this is recursive - // first send removal information - if(Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first)) - { - BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId); - BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(group->BgTypeId,group->ArenaType); - uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId); - plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs - WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr2->GetTeam(), queueSlot, STATUS_NONE, 0, 0); - plr2->GetSession()->SendPacket(&data); - } - // then actually delete, this may delete the group as well! - RemovePlayer(group->Players.begin()->first,decreaseInvitedCount); + BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId); + BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(group->BgTypeId, group->ArenaType); + uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId); + plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to + // queue->removeplayer, it causes bugs + WorldPacket data; + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr2->GetTeam(), queueSlot, STATUS_NONE, 0, 0); + plr2->GetSession()->SendPacket(&data); } + // then actually delete, this may delete the group as well! + RemovePlayer(group->Players.begin()->first, decreaseInvitedCount); } } +//Announce world message void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue) { - if(ginfo->ArenaType) //if Arena { - if( sWorld.getConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE) && ginfo->IsRated) + if( sWorld.getConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE) && ginfo->IsRated ) { BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId); if(!bg) @@ -366,57 +308,35 @@ void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playe if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) ) { Player *plr = objmgr.GetPlayer(playerGUID); - if(!plr) - return; - BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId); - if(!bg) + if(!bg || !plr) return; - uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel(bg->GetTypeID()); + BGQueueIdBasedOnLevel queue_id = plr->GetBattleGroundQueueIdFromLevel(bg->GetTypeID()); char const* bgName = bg->GetName(); - - uint32 q_min_level = Player::GetMinLevelForBattleGroundQueueId(queue_id, ginfo->BgTypeId); - uint32 q_max_level = Player::GetMaxLevelForBattleGroundQueueId(queue_id, ginfo->BgTypeId); - - // replace hardcoded max level by player max level for nice output - if(q_max_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - q_max_level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); - - int8 MinPlayers = bg->GetMinPlayersPerTeam(); - - uint8 qHorde = 0; - uint8 qAlliance = 0; - - BattleGroundTypeId bgTypeId = ginfo->BgTypeId; - QueuedPlayersMap::iterator itr; - for(itr = m_QueuedPlayers[queue_id].begin(); itr!= m_QueuedPlayers[queue_id].end(); ++itr) - { - if(itr->second.GroupInfo->BgTypeId == bgTypeId) - { - switch(itr->second.GroupInfo->Team) - { - case HORDE: - qHorde++; break; - case ALLIANCE: - qAlliance++; break; - default: - break; - } - } - } + uint32 MinPlayers = bg->GetMinPlayersPerTeam(); + uint32 qHorde = 0; + uint32 qAlliance = 0; + uint32 q_min_level = (queue_id + 1) * 10; + GroupsQueueType::const_iterator itr; + for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr) + if( !(*itr)->IsInvitedToBGInstanceGUID ) + qAlliance += (*itr)->Players.size(); + for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].end(); ++itr) + if( !(*itr)->IsInvitedToBGInstanceGUID ) + qHorde += (*itr)->Players.size(); // Show queue status to player only (when joining queue) - if(sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY)) + if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY) ) { ChatHandler(plr).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF, - bgName, q_min_level, q_max_level, qAlliance, MinPlayers, qHorde, MinPlayers); + bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers); } // System message else { sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD, - bgName, q_min_level, q_max_level, qAlliance, MinPlayers, qHorde, MinPlayers); + bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers); } } } @@ -425,10 +345,10 @@ void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playe bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side) { // set side if needed - if(side) + if( side ) ginfo->Team = side; - if(!ginfo->IsInvitedToBGInstanceGUID) + if( !ginfo->IsInvitedToBGInstanceGUID ) { // not yet invited // set invitation @@ -443,12 +363,12 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b // get the player Player* plr = objmgr.GetPlayer(itr->first); - // if offline, skip him - if(!plr) + // if offline, skip him, this should not happen - player is removed from queue when he logs out + if( !plr ) continue; // invite the player - sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(),ginfo->Team); + sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(), bg->GetTypeID(), ginfo->Team); WorldPacket data; @@ -466,169 +386,295 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b return false; } -// this function is responsible for the selection of queued groups when trying to create new battlegrounds -bool BattleGroundQueue::BuildSelectionPool(BattleGroundTypeId bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType, bool isRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime, uint32 excludeTeam) -{ - uint32 side; - switch(mode) - { - case NORMAL_ALLIANCE: - case ONESIDE_ALLIANCE_TEAM1: - case ONESIDE_ALLIANCE_TEAM2: - side = ALLIANCE; - break; - case NORMAL_HORDE: - case ONESIDE_HORDE_TEAM1: - case ONESIDE_HORDE_TEAM2: - side = HORDE; - break; - default: - //unknown mode, return false - sLog.outDebug("Battleground: unknown selection pool build mode, returning..."); - return false; - } - - // inititate the groups eligible to create the bg - m_EligibleGroups.Init(&(m_QueuedGroups[queue_id]), bgTypeId, side, MaxPlayers, ArenaType, isRated, MinRating, MaxRating, DisregardTime, excludeTeam); - // init the selected groups (clear) - m_SelectionPools[mode].Init(); - while(!(m_EligibleGroups.empty())) - { - sLog.outDebug("m_EligibleGroups is not empty, continue building selection pool"); - // in decreasing group size, add groups to join if they fit in the MaxPlayersPerTeam players - for(EligibleGroups::iterator itr= m_EligibleGroups.begin(); itr!=m_EligibleGroups.end(); ++itr) - { - // get the maximal not yet checked group - GroupQueueInfo * MaxGroup = (*itr); - // if it fits in the maxplayer size, add it - if( (m_SelectionPools[mode].GetPlayerCount() + MaxGroup->Players.size()) <= MaxPlayers ) - { - m_SelectionPools[mode].AddGroup(MaxGroup); - } - } - if(m_SelectionPools[mode].GetPlayerCount()>=MinPlayers) - { - // the selection pool is set, return - sLog.outDebug("pool build succeeded, return true"); - return true; - } - // if the selection pool's not set, then remove the group with the highest player count, and try again with the rest. - GroupQueueInfo * MaxGroup = m_SelectionPools[mode].GetMaximalGroup(); - m_EligibleGroups.RemoveGroup(MaxGroup); - m_SelectionPools[mode].RemoveGroup(MaxGroup); - } - // failed to build a selection pool matching the given values - return false; -} - -// used to remove the Enter Battle window if the battle has already, but someone still has it +// used to remove the Enter Battle window if the battle has already ended, but someone still has it // (this can happen in arenas mainly, since the preparation is shorter than the timer for the bgqueueremove event void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg) { - uint32 queue_id = bg->GetQueueId(); + BGQueueIdBasedOnLevel queue_id = bg->GetQueueId(); uint32 bgInstanceId = bg->GetInstanceID(); BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType()); - QueuedGroupsList::iterator itr, next; - for(itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); itr = next) + GroupsQueueType::iterator itr, next; + for(uint32 i = 0; i < BG_QUEUE_GROUP_TYPES_COUNT; i++) { - // must do this way, because the groupinfo will be deleted when all playerinfos are removed - GroupQueueInfo * ginfo = (*itr); + itr = m_QueuedGroups[queue_id][i].begin(); next = itr; - ++next; - // if group was invited to this bg instance, then remove all references - if(ginfo->IsInvitedToBGInstanceGUID == bgInstanceId) + while (next != m_QueuedGroups[queue_id][i].end()) { - // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop - uint32 to_remove = ginfo->Players.size(); - uint32 team = ginfo->Team; - for(int i = 0; i < to_remove; ++i) + // must do this way, because the groupinfo will be deleted when all playerinfos are removed + itr = next; + ++next; + GroupQueueInfo * ginfo = (*itr); + // if group was invited to this bg instance, then remove all references + if( ginfo->IsInvitedToBGInstanceGUID == bgInstanceId ) { - // always remove the first one in the group - std::map::iterator itr2 = ginfo->Players.begin(); - if(itr2 == ginfo->Players.end()) + // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop + uint32 to_remove = ginfo->Players.size(); + uint32 team = ginfo->Team; + for(uint32 j = 0; j < to_remove; j++) { - sLog.outError("Empty Players in ginfo, this should never happen!"); - return; - } + // always remove the first one in the group + std::map::iterator itr2 = ginfo->Players.begin(); + if( itr2 == ginfo->Players.end() ) + { + sLog.outError("Empty Players in ginfo, this should never happen!"); + return; + } + // get the player + Player * plr = objmgr.GetPlayer(itr2->first); + if( !plr ) + { + sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen."); + continue; + } - // get the player - Player * plr = objmgr.GetPlayer(itr2->first); - if(!plr) - { - sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen."); - continue; - } - - // get the queueslot - uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId); - if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue - { - plr->RemoveBattleGroundQueueId(bgQueueTypeId); - // remove player from queue, this might delete the ginfo as well! don't use that pointer after this! - RemovePlayer(itr2->first, true); - // this is probably unneeded, since this player was already invited -> does not fit when initing eligible groups - // but updateing the queue can't hurt - Update(bg->GetTypeID(), bg->GetQueueId()); - // send info to client - WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, team, queueSlot, STATUS_NONE, 0, 0); - plr->GetSession()->SendPacket(&data); + // get the queueslot + uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId); + if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue + { + plr->RemoveBattleGroundQueueId(bgQueueTypeId); + // remove player from queue, this might delete the ginfo as well! don't use that pointer after this! + RemovePlayer(itr2->first, true); + WorldPacket data; + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, team, queueSlot, STATUS_NONE, 0, 0); + plr->GetSession()->SendPacket(&data); + } } } } } } +/* +This function is inviting players to already running battlegrounds +Invitation type is based on config file +large groups are disadvantageous, because they will be kicked first if invitation type = 1 +*/ +void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel queue_id) +{ + uint32 hordeFree = bg->GetFreeSlotsForTeam(HORDE); + uint32 aliFree = bg->GetFreeSlotsForTeam(ALLIANCE); + + //iterator for iterating through bg queue + GroupsQueueType::const_iterator Ali_itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin(); + //count of groups in queue - used to stop cycles + uint32 aliCount = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].size(); + //index to queue which group is current + uint32 aliIndex = 0; + for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), aliFree); aliIndex++) + ++Ali_itr; + //the same thing for horde + GroupsQueueType::const_iterator Horde_itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin(); + uint32 hordeCount = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].size(); + uint32 hordeIndex = 0; + for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), hordeFree); hordeIndex++) + ++Horde_itr; + + //if ofc like BG queue invitation is set in config, then we are happy + if (sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) == 0) + return; + + /* + if we reached this code, then we have to solve NP - complete problem called Subset sum problem + So one solution is to check all possible invitation subgroups, or we can use these conditions: + 1. Last time when BattleGroundQueue::Update was executed we invited all possible players - so there is only small possibility + that we will invite now whole queue, because only 1 change has been made to queues from the last BattleGroundQueue::Update call + 2. Other thing we should consider is group order in queue + */ + + // At first we need to compare free space in bg and our selection pool + int32 diffAli = aliFree - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount(); + int32 diffHorde = hordeFree - m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount(); + while( abs(diffAli - diffHorde) > 1 && (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() > 0 || m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() > 0) ) + { + //each cycle execution we need to kick at least 1 group + if( diffAli < diffHorde ) + { + //kick alliance group, add to pool new group if needed + if( m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffHorde - diffAli) ) + { + for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), (aliFree >= diffHorde) ? aliFree - diffHorde : 0); aliIndex++) + ++Ali_itr; + } + //if ali selection is already empty, then kick horde group, but if there are less horde than ali in bg - break; + if( !m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() ) + { + if( aliFree <= diffHorde - 1 ) + break; + m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffHorde - diffAli); + } + } + else + { + //kick horde group, add to pool new group if needed + if( m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffAli - diffHorde) ) + { + for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), (hordeFree >= diffAli) ? hordeFree - diffAli : 0); hordeIndex++) + ++Horde_itr; + } + if( !m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() ) + { + if( hordeFree <= diffAli - 1 ) + break; + m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffAli - diffHorde); + } + } + //count diffs after small update + diffAli = aliFree - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount(); + diffHorde = hordeFree - m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount(); + } +} + +// this method checks if premade versus premade battleground is possible +// then after 30 mins (default) in queue it moves premade group to normal queue +// it tries to invite as much players as it can - to MaxPlayersPerTeam, because premade groups have more than MinPlayersPerTeam players +bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam) +{ + //check match + if(!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty()) + { + //start premade match + //if groups aren't invited + GroupsQueueType::const_iterator ali_group, horde_group; + for( ali_group = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin(); ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++ali_group) + if( !(*ali_group)->IsInvitedToBGInstanceGUID ) + break; + for( horde_group = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].begin(); horde_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end(); ++horde_group) + if( !(*horde_group)->IsInvitedToBGInstanceGUID ) + break; + + if( ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end()) + { + m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam); + m_SelectionPools[BG_TEAM_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam); + //add groups/players from normal queue to size of bigger group + uint32 maxPlayers = std::max(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount(), m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()); + GroupsQueueType::const_iterator itr; + for(uint32 i = 0; i < BG_TEAMS_COUNT; i++) + { + for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr) + { + if( !(*itr)->IsInvitedToBGInstanceGUID && m_SelectionPools[i].AddGroup((*itr), maxPlayers) ) + break; + } + } + //premade selection pools are set + return true; + } + } + // now check if we can move group from Premade queue to normal queue (timer has expired) or group size lowered!! + // this could be 2 cycles but i'm checking only first team in queue - it can cause problem - + // if first is invited to BG and seconds timer expired, but we can ignore it, because players have only 80 seconds to click to enter bg + // and when they click or after 80 seconds the queue info is removed from queue + uint32 time_before = getMSTime() - sWorld.getConfig(CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH); + for(uint32 i = 0; i < BG_TEAMS_COUNT; i++) + { + if(!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty()) + { + GroupsQueueType::iterator itr = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].begin(); + if(!(*itr)->IsInvitedToBGInstanceGUID && ((*itr)->JoinTime < time_before || (*itr)->Players.size() < MinPlayersPerTeam)) + { + //we must insert group to normal queue and erase pointer from premade queue + m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].push_front((*itr)); + m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].erase(itr); //pop_front(); + } + } + } + //selection pools are not set + return false; +} + +//this function tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam +bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id, uint32 minPlayers, uint32 maxPlayers) +{ + GroupsQueueType::const_iterator itr_team[BG_TEAMS_COUNT]; + for(uint32 i = 0; i < BG_TEAMS_COUNT; i++) + { + itr_team[i] = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); + for(; itr_team[i] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++(itr_team[i])) + { + if( !(*(itr_team[i]))->IsInvitedToBGInstanceGUID ) + { + m_SelectionPools[i].AddGroup(*(itr_team[i]), maxPlayers); + if( m_SelectionPools[i].GetPlayerCount() >= minPlayers ) + break; + } + } + } + //try to invite same number of players - this cycle may cause longer wait time even if there are enough players in queue, but we want ballanced bg + uint32 j = BG_TEAM_ALLIANCE; + if( m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() ) + j = BG_TEAM_HORDE; + if( sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) != 0 + && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers ) + { + //we will try to invite more groups to team with less players indexed by j + ++(itr_team[j]); //this will not cause a crash, because for cycle above reached break; + for(; itr_team[j] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + j].end(); ++(itr_team[j])) + { + if( !(*(itr_team[j]))->IsInvitedToBGInstanceGUID ) + if( m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % BG_TEAMS_COUNT].GetPlayerCount()) ) + break; + } + // do not allow to start bg with more than 2 players more on 1 faction + if( abs((int32)(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())) > 2 ) + return false; + } + //allow 1v0 if debug bg + if( sBattleGroundMgr.isTesting() && (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()) ) + return true; + //return true if there are enough players in selection pools - enable to work .debug bg command correctly + return m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers; +} + /* this method is called when group is inserted, or player / group is removed from BG Queue - there is only one player's status changed, so we don't use while(true) cycles to invite whole queue it must be called after fully adding the members of a group to ensure group joining -should be called after removeplayer functions in some cases +should be called from BattleGround::RemovePlayer function in some cases */ -void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, uint32 queue_id, uint8 arenatype, bool isRated, uint32 arenaRating) +void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated, uint32 arenaRating) { - if (queue_id >= MAX_BATTLEGROUND_QUEUES) - { - //this is error, that caused crashes (not in , but now it shouldn't) - sLog.outError("BattleGroundQueue::Update() called for non existing queue type - this can cause crash, pls report problem, if this is the last line of error log before crash"); - return; - } - - //if no players in queue ... do nothing - if (m_QueuedGroups[queue_id].empty()) + //if no players in queue - do nothing + if( m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && + m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() && + m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].empty() && + m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].empty() ) return; - BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype); + BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenaType); - //battleground with free slot for player should be always the last in this queue + //battleground with free slot for player should be always in the beggining of the queue + // maybe it would be better to create bgfreeslotqueue for each queue_id_based_on_level + bool continueAdding = true; BGFreeSlotQueueType::iterator itr, next; - for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next) + for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); continueAdding && itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next) { next = itr; ++next; - // battleground is running, so if: - // DO NOT allow queue manager to invite new player to running arena - if ((*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueId() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE) + // DO NOT allow queue manager to invite new player to arena + if( (*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueId() == queue_id && + (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE ) { - //we must check both teams BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!) // and iterator is invalid - for(QueuedGroupsList::iterator itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); ++itr) - { - // did the group join for this bg type? - if((*itr)->BgTypeId != bgTypeId) - continue; - // if so, check if fits in - if(bg->GetFreeSlotsForTeam((*itr)->Team) >= (*itr)->Players.size()) - { - // if group fits in, invite it - InviteGroupToBG((*itr),bg,(*itr)->Team); - } - } + // clear selection pools + m_SelectionPools[BG_TEAM_ALLIANCE].Init(); + m_SelectionPools[BG_TEAM_HORDE].Init(); - if (!bg->HasFreeSlots()) + // call a function that does the job for us + FillPlayersToBG(bg, queue_id); + + // now everything is set, invite players + for(GroupsQueueType::const_iterator itr = m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.end(); ++itr) + InviteGroupToBG((*itr), bg, (*itr)->Team); + for(GroupsQueueType::const_iterator itr = m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.end(); ++itr) + InviteGroupToBG((*itr), bg, (*itr)->Team); + + if( !bg->HasFreeSlots() ) { - //remove BG from BGFreeSlotQueue + if( next == sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end() ) + continueAdding = false; + // remove BG from BGFreeSlotQueue bg->RemoveFromBGFreeSlotQueue(); } } @@ -637,25 +683,29 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, uint32 queue_id, uin // finished iterating through the bgs with free slots, maybe we need to create a new bg BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - if(!bg_template) + if( !bg_template ) { sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId); return; } - // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!) uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam(); uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam(); - if(bg_template->isArena()) + if( sBattleGroundMgr.isTesting() ) + MinPlayersPerTeam = 1; + if( bg_template->isArena() ) { - if(sBattleGroundMgr.isArenaTesting()) + if( sBattleGroundMgr.isArenaTesting() ) { MaxPlayersPerTeam = 1; MinPlayersPerTeam = 1; } else { - switch(arenatype) + //this switch can be much shorter + MaxPlayersPerTeam = arenaType; + MinPlayersPerTeam = arenaType; + /*switch(arenaType) { case ARENA_TYPE_2v2: MaxPlayersPerTeam = 2; @@ -669,292 +719,191 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, uint32 queue_id, uin MaxPlayersPerTeam = 5; MinPlayersPerTeam = 5; break; - } - } - } - // BG case - else - { - if(sBattleGroundMgr.isTesting()) - { - MinPlayersPerTeam = 1; + }*/ } } - // found out the minimum and maximum ratings the newly added team should battle against - // arenaRating is the rating of the latest joined team - uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference(); - // if no rating is specified, set maxrating to 0 - uint32 arenaMaxRating = (arenaRating == 0)? 0 : arenaRating + sBattleGroundMgr.GetMaxRatingDifference(); - uint32 discardTime = 0; - // if max rating difference is set and the time past since server startup is greater than the rating discard time - // (after what time the ratings aren't taken into account when making teams) then - // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account - // else leave the discard time on 0, this way all ratings will be discarded - if(sBattleGroundMgr.GetMaxRatingDifference() && getMSTime() >= sBattleGroundMgr.GetRatingDiscardTimer()) - discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer(); + m_SelectionPools[BG_TEAM_ALLIANCE].Init(); + m_SelectionPools[BG_TEAM_HORDE].Init(); - // try to build the selection pools - bool bAllyOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_ALLIANCE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime); - if(bAllyOK) - sLog.outDebug("Battleground: ally pool succesfully build"); - else - sLog.outDebug("Battleground: ally pool wasn't created"); - bool bHordeOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_HORDE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime); - if(bHordeOK) - sLog.outDebug("Battleground: horde pool succesfully built"); - else - sLog.outDebug("Battleground: horde pool wasn't created"); - - // if selection pools are ready, create the new bg - if ((bAllyOK && bHordeOK) || ( sBattleGroundMgr.isTesting() && (bAllyOK || bHordeOK))) + if( bg_template->isBattleGround() ) { - BattleGround * bg2 = 0; - // special handling for arenas - if(bg_template->isArena()) + //check if there is premade against premade match + if( CheckPremadeMatch(queue_id, MinPlayersPerTeam, MaxPlayersPerTeam) ) { - // Find a random arena, that can be created - BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL}; - uint32 arena_num = urand(0,2); - if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) && - !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) && - !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) ) + //create new battleground + BattleGround * bg2 = NULL; + if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, 0, false)) ) { - sLog.outError("Battleground: couldn't create any arena instance!"); + sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId); return; } - - // set the MaxPlayersPerTeam values based on arenatype - // setting the min player values isn't needed, since we won't be using that value later on. - if(sBattleGroundMgr.isArenaTesting()) - { - bg2->SetMaxPlayersPerTeam(1); - bg2->SetMaxPlayers(2); - } - else - { - switch(arenatype) - { - case ARENA_TYPE_2v2: - bg2->SetMaxPlayersPerTeam(2); - bg2->SetMaxPlayers(4); - break; - case ARENA_TYPE_3v3: - bg2->SetMaxPlayersPerTeam(3); - bg2->SetMaxPlayers(6); - break; - case ARENA_TYPE_5v5: - bg2->SetMaxPlayersPerTeam(5); - bg2->SetMaxPlayers(10); - break; - default: - break; - } - } - } - else - { - // create new battleground - bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId); - if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) ) - { - char const* bgName = bg2->GetName(); - uint32 q_min_level = Player::GetMinLevelForBattleGroundQueueId(queue_id, bgTypeId); - uint32 q_max_level = Player::GetMaxLevelForBattleGroundQueueId(queue_id, bgTypeId); - if(q_max_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - q_max_level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); - sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level); - } - } - - if(!bg2) - { - sLog.outError("Battleground: couldn't create bg %u",bgTypeId); - return; - } - - // start the joining of the bg - bg2->SetStatus(STATUS_WAIT_JOIN); - bg2->SetQueueId(queue_id); - // initialize arena / rating info - bg2->SetArenaType(arenatype); - // set rating - bg2->SetRated(isRated); - - std::list::iterator itr; - - // invite groups from horde selection pool - for(itr = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_HORDE].SelectedGroups.end(); ++itr) - { - InviteGroupToBG((*itr),bg2,HORDE); - } - - // invite groups from ally selection pools - for(itr = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.end(); ++itr) - { - InviteGroupToBG((*itr),bg2,ALLIANCE); - } - - if (isRated) - { - std::list::iterator itr_alliance = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin(); - std::list::iterator itr_horde = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin(); - (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating; - sLog.outDebug("setting oposite teamrating for team %u to %u", (*itr_alliance)->ArenaTeamId, (*itr_alliance)->OpponentsTeamRating); - (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating; - sLog.outDebug("setting oposite teamrating for team %u to %u", (*itr_horde)->ArenaTeamId, (*itr_horde)->OpponentsTeamRating); - } - - // start the battleground - bg2->StartBattleGround(); - } - - // there weren't enough players for a "normal" match - // if arena, enable horde versus horde or alliance versus alliance teams here - - else if(bg_template->isArena()) - { - bool bOneSideHordeTeam1 = false, bOneSideHordeTeam2 = false; - bool bOneSideAllyTeam1 = false, bOneSideAllyTeam2 = false; - bOneSideHordeTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime); - if(bOneSideHordeTeam1) - { - // one team has been selected, find out if other can be selected too - std::list::iterator itr; - // temporarily change the team side to enable building the next pool excluding the already selected groups - for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr) - (*itr)->Team=ALLIANCE; - - bOneSideHordeTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime, (*(m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin()))->ArenaTeamId); - - // change back the team to horde - for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr) - (*itr)->Team=HORDE; - - if(!bOneSideHordeTeam2) - bOneSideHordeTeam1 = false; - } - if(!bOneSideHordeTeam1) - { - // check for one sided ally - bOneSideAllyTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime); - if(bOneSideAllyTeam1) - { - // one team has been selected, find out if other can be selected too - std::list::iterator itr; - // temporarily change the team side to enable building the next pool excluding the already selected groups - for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr) - (*itr)->Team=HORDE; - - bOneSideAllyTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime,(*(m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin()))->ArenaTeamId); - - // change back the team to ally - for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr) - (*itr)->Team=ALLIANCE; - } - - if(!bOneSideAllyTeam2) - bOneSideAllyTeam1 = false; - } - // 1-sided BuildSelectionPool() will work, because the MinPlayersPerTeam == MaxPlayersPerTeam in every arena!!!! - if( (bOneSideHordeTeam1 && bOneSideHordeTeam2) || - (bOneSideAllyTeam1 && bOneSideAllyTeam2) ) - { - // which side has enough players? - uint32 side = 0; - SelectionPoolBuildMode mode1, mode2; - // find out what pools are we using - if(bOneSideAllyTeam1 && bOneSideAllyTeam2) - { - side = ALLIANCE; - mode1 = ONESIDE_ALLIANCE_TEAM1; - mode2 = ONESIDE_ALLIANCE_TEAM2; - } - else - { - side = HORDE; - mode1 = ONESIDE_HORDE_TEAM1; - mode2 = ONESIDE_HORDE_TEAM2; - } - - // create random arena - BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL}; - uint32 arena_num = urand(0,2); - BattleGround* bg2 = NULL; - if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) && - !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) && - !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) ) - { - sLog.outError("Could not create arena."); - return; - } - - sLog.outDebug("Battleground: One-faction arena created."); - // init stats - if(sBattleGroundMgr.isArenaTesting()) - { - bg2->SetMaxPlayersPerTeam(1); - bg2->SetMaxPlayers(2); - } - else - { - switch(arenatype) - { - case ARENA_TYPE_2v2: - bg2->SetMaxPlayersPerTeam(2); - bg2->SetMaxPlayers(4); - break; - case ARENA_TYPE_3v3: - bg2->SetMaxPlayersPerTeam(3); - bg2->SetMaxPlayers(6); - break; - case ARENA_TYPE_5v5: - bg2->SetMaxPlayersPerTeam(5); - bg2->SetMaxPlayers(10); - break; - default: - break; - } - } - - bg2->SetRated(isRated); - - // assigned team of the other group - uint32 other_side; - if(side == ALLIANCE) - other_side = HORDE; - else - other_side = ALLIANCE; - - // start the joining of the bg - bg2->SetStatus(STATUS_WAIT_JOIN); - bg2->SetQueueId(queue_id); - // initialize arena / rating info - bg2->SetArenaType(arenatype); - - std::list::iterator itr; - - // invite players from the first group as horde players (actually green team) - for(itr = m_SelectionPools[mode1].SelectedGroups.begin(); itr != m_SelectionPools[mode1].SelectedGroups.end(); ++itr) - { - InviteGroupToBG((*itr),bg2,HORDE); - } - - // invite players from the second group as ally players (actually gold team) - for(itr = m_SelectionPools[mode2].SelectedGroups.begin(); itr != m_SelectionPools[mode2].SelectedGroups.end(); ++itr) - { - InviteGroupToBG((*itr),bg2,ALLIANCE); - } - - if (isRated) - { - std::list::iterator itr_alliance = m_SelectionPools[mode1].SelectedGroups.begin(); - std::list::iterator itr_horde = m_SelectionPools[mode2].SelectedGroups.begin(); - (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating; - (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating; - } - + //invite those selection pools + for(uint32 i = 0; i < BG_TEAMS_COUNT; i++) + for(GroupsQueueType::const_iterator itr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); itr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++itr) + InviteGroupToBG((*itr), bg2, (*itr)->Team); + //start bg bg2->StartBattleGround(); + //clear structures + m_SelectionPools[BG_TEAM_ALLIANCE].Init(); + m_SelectionPools[BG_TEAM_HORDE].Init(); + } + } + + // now check if there are in queues enough players to start new game of (normal battleground, or non-rated arena) + if( !isRated ) + { + // if there are enough players in pools, start new battleground or non rated arena + if( CheckNormalMatch(bg_template, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam) ) + { + // we successfully created a pool + BattleGround * bg2 = NULL; + if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, false)) ) + { + sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId); + return; + } + + // invite those selection pools + for(uint32 i = 0; i < BG_TEAMS_COUNT; i++) + for(GroupsQueueType::const_iterator itr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); itr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++itr) + InviteGroupToBG((*itr), bg2, (*itr)->Team); + // start bg + bg2->StartBattleGround(); + } + } + else if( bg_template->isArena() ) + { + // found out the minimum and maximum ratings the newly added team should battle against + // arenaRating is the rating of the latest joined team, or 0 + // 0 is on (automatic update call) and we must set it to team's with longest wait time + if ( !arenaRating ) + { + GroupQueueInfo* front1 = NULL; + GroupQueueInfo* front2 = NULL; + if( !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() ) + { + front1 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].front(); + arenaRating = front1->ArenaTeamRating; + } + if( !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() ) + { + front2 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].front(); + arenaRating = front2->ArenaTeamRating; + } + if( front1 && front2 ) + { + if( front1->JoinTime < front2->JoinTime ) + arenaRating = front1->ArenaTeamRating; + } + else if( !front1 && !front2 ) + return; //queues are empty + } + + //set rating range + uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference(); + uint32 arenaMaxRating = arenaRating + sBattleGroundMgr.GetMaxRatingDifference(); + // if max rating difference is set and the time past since server startup is greater than the rating discard time + // (after what time the ratings aren't taken into account when making teams) then + // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account + // else leave the discard time on 0, this way all ratings will be discarded + uint32 discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer(); + + // we need to find 2 teams which will play next game + + GroupsQueueType::iterator itr_team[BG_TEAMS_COUNT]; + + //optimalization : --- we dont need to use selection_pools - each update we select max 2 groups + + for(uint32 i = BG_QUEUE_PREMADE_ALLIANCE; i < BG_QUEUE_NORMAL_ALLIANCE; i++) + { + // take the group that joined first + itr_team[i] = m_QueuedGroups[queue_id][i].begin(); + for(; itr_team[i] != m_QueuedGroups[queue_id][i].end(); ++(itr_team[i])) + { + // if group match conditions, then add it to pool + if( !(*itr_team[i])->IsInvitedToBGInstanceGUID + && (((*itr_team[i])->ArenaTeamRating >= arenaMinRating && (*itr_team[i])->ArenaTeamRating <= arenaMaxRating) + || (*itr_team[i])->JoinTime < discardTime) ) + { + m_SelectionPools[i].AddGroup((*itr_team[i]), MaxPlayersPerTeam); + // break for cycle to be able to start selecting another group from same faction queue + break; + } + } + } + // now we are done if we have 2 groups - ali vs horde! + // if we don't have, we must try to continue search in same queue + // tmp variables are correctly set + // this code isn't much userfriendly - but it is supposed to continue search for mathing group in HORDE queue + if( m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() ) + { + itr_team[BG_TEAM_ALLIANCE] = itr_team[BG_TEAM_HORDE]; + ++itr_team[BG_TEAM_ALLIANCE]; + for(; itr_team[BG_TEAM_ALLIANCE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end(); ++(itr_team[BG_TEAM_ALLIANCE])) + { + if( !(*itr_team[BG_TEAM_ALLIANCE])->IsInvitedToBGInstanceGUID + && (((*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating <= arenaMaxRating) + || (*itr_team[BG_TEAM_ALLIANCE])->JoinTime < discardTime) ) + { + m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*itr_team[BG_TEAM_ALLIANCE]), MaxPlayersPerTeam); + break; + } + } + } + // this code isn't much userfriendly - but it is supposed to continue search for mathing group in ALLIANCE queue + if( m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() ) + { + itr_team[BG_TEAM_HORDE] = itr_team[BG_TEAM_ALLIANCE]; + ++itr_team[BG_TEAM_HORDE]; + for(; itr_team[BG_TEAM_HORDE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++(itr_team[BG_TEAM_HORDE])) + { + if( !(*itr_team[BG_TEAM_HORDE])->IsInvitedToBGInstanceGUID + && (((*itr_team[BG_TEAM_HORDE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_HORDE])->ArenaTeamRating <= arenaMaxRating) + || (*itr_team[BG_TEAM_HORDE])->JoinTime < discardTime) ) + { + m_SelectionPools[BG_TEAM_HORDE].AddGroup((*itr_team[BG_TEAM_HORDE]), MaxPlayersPerTeam); + break; + } + } + } + + //if we have 2 teams, then start new arena and invite players! + if( m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() ) + { + BattleGround* arena = NULL; + if( !(arena = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, true)) ) + { + sLog.outError("BattlegroundQueue::Update couldn't create arena instance for rated arena match!"); + return; + } + + (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamRating; + sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamId, (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating); + (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamRating; + sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamId, (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating); + // now we must move team if we changed its faction to another faction queue, because then we will spam log by errors in Queue::RemovePlayer + if( (*(itr_team[BG_TEAM_ALLIANCE]))->Team != ALLIANCE ) + { + // add to alliance queue + m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].push_front(*(itr_team[BG_TEAM_ALLIANCE])); + // erase from horde queue + m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[BG_TEAM_ALLIANCE]); + itr_team[BG_TEAM_ALLIANCE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin(); + } + if( (*(itr_team[BG_TEAM_HORDE]))->Team != HORDE ) + { + m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].push_front(*(itr_team[BG_TEAM_HORDE])); + m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].erase(itr_team[BG_TEAM_HORDE]); + itr_team[BG_TEAM_HORDE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].begin(); + } + + InviteGroupToBG(*(itr_team[BG_TEAM_ALLIANCE]), arena, ALLIANCE); + InviteGroupToBG(*(itr_team[BG_TEAM_HORDE]), arena, HORDE); + + sLog.outDebug("Starting rated arena match!"); + + arena->StartBattleGround(); } } } @@ -972,26 +921,22 @@ bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) return true; // Player can be in another BG queue and must be removed in normal way in any case - // // player is already in battleground ... do nothing (battleground queue status is deleted when player is teleported to BG) - // if (plr->GetBattleGroundId() > 0) - // return true; - BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID); + BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId); if (!bg) return true; BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType()); - BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId); if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue { // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems - BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel(bgTypeId)]; + BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid); if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID) { WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, qItr->second.GroupInfo->Team, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME/2, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, qItr->second.GroupInfo->Team, queueSlot, STATUS_WAIT_JOIN, INVITATION_REMIND_TIME, 0); plr->GetSession()->SendPacket(&data); } } @@ -1011,7 +956,7 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) // player logged off (we should do nothing, he is correctly removed from queue in another procedure) return true; - BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID); + BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId); if (!bg) return true; @@ -1022,8 +967,7 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue { // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems - uint32 queue_id=plr->GetBattleGroundQueueIdFromLevel(bg->GetTypeID()); - BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[queue_id]; + BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = qpMap.find(m_PlayerGuid); if (qMapItr != qpMap.end() && qMapItr->second.GroupInfo && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID) { @@ -1039,7 +983,7 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) } plr->RemoveBattleGroundQueueId(bgQueueTypeId); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true); - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bg->GetTypeID(),bg->GetQueueId()); + sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bg->GetTypeID(), bg->GetQueueId()); WorldPacket data; sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, m_PlayersTeam, queueSlot, STATUS_NONE, 0, 0); plr->GetSession()->SendPacket(&data); @@ -1064,7 +1008,8 @@ void BGQueueRemoveEvent::Abort(uint64 /*e_time*/) BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTesting(false) { - m_BattleGrounds.clear(); + for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++) + m_BattleGrounds[i].clear(); m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER); m_Testing=false; } @@ -1076,11 +1021,14 @@ BattleGroundMgr::~BattleGroundMgr() void BattleGroundMgr::DeleteAlllBattleGrounds() { - for(BattleGroundSet::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end();) + for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++) { - BattleGround * bg = itr->second; - m_BattleGrounds.erase(itr++); - delete bg; + for(BattleGroundSet::iterator itr = m_BattleGrounds[i].begin(); itr != m_BattleGrounds[i].end();) + { + BattleGround * bg = itr->second; + m_BattleGrounds[i].erase(itr++); + delete bg; + } } // destroy template battlegrounds that listed only in queues (other already terminated) @@ -1096,30 +1044,41 @@ void BattleGroundMgr::DeleteAlllBattleGrounds() void BattleGroundMgr::Update(uint32 diff) { BattleGroundSet::iterator itr, next; - for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next) + for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++) { - next = itr; - ++next; - itr->second->Update(diff); - // use the SetDeleteThis variable - // direct deletion caused crashes - if(itr->second->m_SetDeleteThis) + itr = m_BattleGrounds[i].begin(); + // skip updating battleground template + if( itr != m_BattleGrounds[i].end() ) + ++itr; + for(itr = m_BattleGrounds[i].begin(); itr != m_BattleGrounds[i].end(); itr = next) { - BattleGround * bg = itr->second; - m_BattleGrounds.erase(itr); - delete bg; + next = itr; + ++next; + itr->second->Update(diff); + // use the SetDeleteThis variable + // direct deletion caused crashes + if(itr->second->m_SetDeleteThis) + { + BattleGround * bg = itr->second; + m_BattleGrounds[i].erase(itr); + delete bg; + } } } // if rating difference counts, maybe force-update queues - if(sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE)) + if(sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE) && sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER)) { // it's time to force update if(m_NextRatingDiscardUpdate < diff) { // forced update for level 70 rated arenas - m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA,6,ARENA_TYPE_2v2,true,0); - m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA,6,ARENA_TYPE_3v3,true,0); - m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA,6,ARENA_TYPE_5v5,true,0); + sLog.outDebug("BattleGroundMgr: UPDATING ARENA QUEUES"); + m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_2v2, true, 0); + m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_2v2, true, 0); + m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_3v3, true, 0); + m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_3v3, true, 0); + m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_5v5, true, 0); + m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_5v5, true, 0); m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER); } else @@ -1380,10 +1339,10 @@ void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Pla *data << uint64(plr->GetGUID()); } -void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team) +void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, BattleGroundTypeId bgTypeId, uint32 team) { // set invited player counters: - BattleGround* bg = GetBattleGround(bgInstanceGUID); + BattleGround* bg = GetBattleGround(bgInstanceGUID, bgTypeId); if(!bg) return; bg->IncreaseInvitedCount(team); @@ -1411,19 +1370,38 @@ void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 te // create invite events: //add events to player's counters ---- this is not good way - there should be something like global event processor, where we should add those events - BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID); - plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME/2)); - BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, team); + BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID, bgTypeId); + plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITATION_REMIND_TIME)); + BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, bgTypeId, team); plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME)); } +BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId) +{ + //search if needed + BattleGroundSet::iterator itr; + if( bgTypeId == BATTLEGROUND_TYPE_NONE) + { + for(uint32 i = BATTLEGROUND_AV; i < MAX_BATTLEGROUND_TYPE_ID; i++) + { + itr = m_BattleGrounds[i].find(InstanceID); + if( itr != m_BattleGrounds[i].end() ) + return itr->second; + } + return NULL; + } + itr = m_BattleGrounds[bgTypeId].find(InstanceID); + return ( (itr != m_BattleGrounds[bgTypeId].end()) ? itr->second : NULL ); +} + BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId) { - return BGFreeSlotQueue[bgTypeId].empty() ? NULL : BGFreeSlotQueue[bgTypeId].back(); + //map is sorted and we can be sure that lowest instance id has only BG template + return m_BattleGrounds[bgTypeId].empty() ? NULL : m_BattleGrounds[bgTypeId].begin()->second; } // create a new battleground that will really be used to play -BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId) +BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated) { // get the template BG BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId); @@ -1433,8 +1411,21 @@ BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeI return NULL; } - BattleGround *bg = NULL; + //for arenas there is random map used + if(bg_template->isArena()) + { + BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL}; + uint32 arena_num = urand(0,2); + bgTypeId = arenas[arena_num]; + bg_template = GetBattleGroundTemplate(bgTypeId); + if(!bg_template) + { + sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId); + return NULL; + } + } + BattleGround *bg = NULL; // create a copy of the BG template switch(bgTypeId) { @@ -1482,20 +1473,22 @@ BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeI // reset the new bg (set status to status_wait_queue from status_none) bg->Reset(); - /* will be setup in BG::Update() when the first player is ported in - if(!(bg->SetupBattleGround())) + if( bg->isBattleGround() && sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) ) { - sLog.outError("BattleGround: CreateNewBattleGround: SetupBattleGround failed for bg %u", bgTypeId); - delete bg; - return 0; + sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, bg->GetName(), bg->GetMinLevel(), bg->GetMaxLevel()); } - */ + + // start the joining of the bg + bg->SetStatus(STATUS_WAIT_JOIN); + bg->SetQueueId(queue_id); + bg->SetArenaType(arenaType); + bg->SetRated(isRated); // add BG to free slot queue bg->AddToBGFreeSlotQueue(); // add bg to update list - AddBattleGround(bg->GetInstanceID(), bg); + AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg); return bg; } @@ -1522,9 +1515,6 @@ uint32 BattleGroundMgr::CreateBattleGround(BattleGroundTypeId bgTypeId, bool IsA } bg->SetMapId(MapID); - - bg->Reset(); - bg->SetTypeID(bgTypeId); bg->SetInstanceID(0); bg->SetArenaorBGType(IsArena); @@ -1537,10 +1527,8 @@ uint32 BattleGroundMgr::CreateBattleGround(BattleGroundTypeId bgTypeId, bool IsA bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO); bg->SetLevelRange(LevelMin, LevelMax); - //add BattleGround instance to FreeSlotQueue (.back() will return the template!) - bg->AddToBGFreeSlotQueue(); - - // do NOT add to update list, since this is a template battleground! + // add bg to update list + AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg); // return some not-null value, bgTypeId is good enough for me return bgTypeId; @@ -1760,9 +1748,12 @@ void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint6 uint32 count = 0; *data << uint32(0x00); // number of bg instances - for(std::map::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr) + for(BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr) { - if(itr->second->GetTypeID() == bgTypeId && (PlayerLevel >= itr->second->GetMinLevel()) && (PlayerLevel <= itr->second->GetMaxLevel())) + // skip sending battleground template + if( itr == m_BattleGrounds[bgTypeId].begin() ) + continue; + if( PlayerLevel >= itr->second->GetMinLevel() && PlayerLevel <= itr->second->GetMaxLevel() ) { *data << uint32(itr->second->GetInstanceID()); ++count; @@ -1772,9 +1763,9 @@ void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint6 } } -void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId) +void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, BattleGroundTypeId bgTypeId) { - BattleGround *bg = GetBattleGround(instanceId); + BattleGround *bg = GetBattleGround(instanceId, bgTypeId); if(bg) { uint32 mapid = bg->GetMapId(); @@ -1905,7 +1896,11 @@ void BattleGroundMgr::ToggleArenaTesting() uint32 BattleGroundMgr::GetMaxRatingDifference() const { - return sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE); + // this is for stupid people who can't use brain and set max rating difference to 0 + uint32 diff = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE); + if (diff == 0) + diff = 5000; + return diff; } uint32 BattleGroundMgr::GetRatingDiscardTimer() const diff --git a/src/game/BattleGroundMgr.h b/src/game/BattleGroundMgr.h index df5e9668c..cf500629d 100644 --- a/src/game/BattleGroundMgr.h +++ b/src/game/BattleGroundMgr.h @@ -22,18 +22,12 @@ #include "Common.h" #include "BattleGround.h" -//TODO it is not possible to have this structure, because we should have BattlegroundSet for each queue -//so i propose to change this type to array 1..MAX_BATTLEGROUND_TYPES of sets or maps.. typedef std::map BattleGroundSet; -//typedef std::map BattleGroundQueueSet; + typedef std::deque BGFreeSlotQueueType; typedef UNORDERED_MAP BattleMastersMap; -#define MAX_BATTLEGROUND_QUEUES 8 // for level ranges 10-19, 20-29, 30-39, 40-49, 50-59, 60-69, 70-79, 80+ - -#define MAX_BATTLEGROUND_QUEUE_TYPES 9 - #define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY 86400 // seconds in a day struct GroupQueueInfo; // type predefinition @@ -59,6 +53,15 @@ struct GroupQueueInfo // stores informatio uint32 OpponentsTeamRating; // for rated arena matches }; +enum BattleGroundQueueGroupTypes +{ + BG_QUEUE_PREMADE_ALLIANCE = 0, + BG_QUEUE_PREMADE_HORDE = 1, + BG_QUEUE_NORMAL_ALLIANCE = 2, + BG_QUEUE_NORMAL_HORDE = 3 +}; +#define BG_QUEUE_GROUP_TYPES_COUNT 4 + class BattleGround; class BattleGroundQueue { @@ -66,9 +69,12 @@ class BattleGroundQueue BattleGroundQueue(); ~BattleGroundQueue(); - void Update(BattleGroundTypeId bgTypeId, uint32 queue_id, uint8 arenatype = 0, bool isRated = false, uint32 minRating = 0); + void Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType = 0, bool isRated = false, uint32 minRating = 0); - GroupQueueInfo * AddGroup(Player * leader, BattleGroundTypeId bgTypeId, uint8 ArenaType, bool isRated, uint32 ArenaRating, uint32 ArenaTeamId = 0); + void FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel queue_id); + bool CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam); + bool CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id, uint32 minPlayers, uint32 maxPlayers); + GroupQueueInfo * AddGroup(Player * leader, BattleGroundTypeId bgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 ArenaRating, uint32 ArenaTeamId = 0); void AddPlayer(Player *plr, GroupQueueInfo *ginfo); void RemovePlayer(const uint64& guid, bool decreaseInvitedCount); void DecreaseGroupLength(uint32 queueId, uint32 AsGroup); @@ -76,52 +82,38 @@ class BattleGroundQueue void AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue); typedef std::map QueuedPlayersMap; - QueuedPlayersMap m_QueuedPlayers[MAX_BATTLEGROUND_QUEUES]; + QueuedPlayersMap m_QueuedPlayers; - typedef std::list QueuedGroupsList; - QueuedGroupsList m_QueuedGroups[MAX_BATTLEGROUND_QUEUES]; + //we need constant add to begin and constant remove / add from the end, therefore deque suits our problem well + typedef std::list GroupsQueueType; - // class to hold pointers to the groups eligible for a specific selection pool building mode - class EligibleGroups : public std::list - { - public: - void Init(QueuedGroupsList * source, BattleGroundTypeId BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType = 0, bool IsRated = false, uint32 MinRating = 0, uint32 MaxRating = 0, uint32 DisregardTime = 0, uint32 excludeTeam = 0); - void RemoveGroup(GroupQueueInfo * ginfo); - }; - - EligibleGroups m_EligibleGroups; + /* + This two dimensional array is used to store All queued groups + First dimension specifies the bgTypeId + Second dimension specifies the player's group types - + BG_QUEUE_PREMADE_ALLIANCE is used for premade alliance groups and alliance rated arena teams + BG_QUEUE_PREMADE_HORDE is used for premade horde groups and horde rated arena teams + BG_QUEUE_NORMAL_ALLIANCE is used for normal (or small) alliance groups or non-rated arena matches + BG_QUEUE_NORMAL_HORDE is used for normal (or small) horde groups or non-rated arena matches + */ + GroupsQueueType m_QueuedGroups[MAX_BATTLEGROUND_QUEUES][BG_QUEUE_GROUP_TYPES_COUNT]; // class to select and invite groups to bg class SelectionPool { public: void Init(); - void AddGroup(GroupQueueInfo * group); - GroupQueueInfo * GetMaximalGroup(); - void RemoveGroup(GroupQueueInfo * group); + bool AddGroup(GroupQueueInfo *ginfo, uint32 desiredCount); + bool KickGroup(uint32 size); uint32 GetPlayerCount() const {return PlayerCount;} public: - std::list SelectedGroups; + GroupsQueueType SelectedGroups; private: uint32 PlayerCount; - GroupQueueInfo * MaxGroup; }; - enum SelectionPoolBuildMode - { - NORMAL_ALLIANCE, - NORMAL_HORDE, - ONESIDE_ALLIANCE_TEAM1, - ONESIDE_ALLIANCE_TEAM2, - ONESIDE_HORDE_TEAM1, - ONESIDE_HORDE_TEAM2, - - NUM_SELECTION_POOL_TYPES - }; - - SelectionPool m_SelectionPools[NUM_SELECTION_POOL_TYPES]; - - bool BuildSelectionPool(BattleGroundTypeId bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType = 0, bool isRated = false, uint32 MinRating = 0, uint32 MaxRating = 0, uint32 DisregardTime = 0, uint32 excludeTeam = 0); + //one selection pool for horde, other one for alliance + SelectionPool m_SelectionPools[BG_TEAMS_COUNT]; private: @@ -135,7 +127,10 @@ class BattleGroundQueue class BGQueueInviteEvent : public BasicEvent { public: - BGQueueInviteEvent(const uint64& pl_guid, uint32 BgInstanceGUID) : m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID) {}; + BGQueueInviteEvent(const uint64& pl_guid, uint32 BgInstanceGUID, BattleGroundTypeId BgTypeId) : + m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID), m_BgTypeId(BgTypeId) + { + }; virtual ~BGQueueInviteEvent() {}; virtual bool Execute(uint64 e_time, uint32 p_time); @@ -143,6 +138,7 @@ class BGQueueInviteEvent : public BasicEvent private: uint64 m_PlayerGuid; uint32 m_BgInstanceGUID; + BattleGroundTypeId m_BgTypeId; }; /* @@ -151,8 +147,8 @@ class BGQueueInviteEvent : public BasicEvent class BGQueueRemoveEvent : public BasicEvent { public: - BGQueueRemoveEvent(const uint64& pl_guid, uint32 bgInstanceGUID, uint32 playersTeam) : - m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_PlayersTeam(playersTeam) + BGQueueRemoveEvent(const uint64& pl_guid, uint32 bgInstanceGUID, BattleGroundTypeId BgTypeId, uint32 playersTeam) : + m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_BgTypeId(BgTypeId), m_PlayersTeam(playersTeam) { }; virtual ~BGQueueRemoveEvent() {}; @@ -163,6 +159,7 @@ class BGQueueRemoveEvent : public BasicEvent uint64 m_PlayerGuid; uint32 m_BgInstanceGUID; uint32 m_PlayersTeam; + BattleGroundTypeId m_BgTypeId; }; class BattleGroundMgr @@ -182,34 +179,27 @@ class BattleGroundMgr void BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg); void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype = 0, uint8 israted = 0); void BuildPlaySoundPacket(WorldPacket *data, uint32 soundid); - void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid); + /* Player invitation */ // called from Queue update, or from Addplayer to queue - void InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team); + void InvitePlayer(Player* plr, uint32 bgInstanceGUID, BattleGroundTypeId bgTypeId, uint32 team); /* Battlegrounds */ - BattleGroundSet::iterator GetBattleGroundsBegin() { return m_BattleGrounds.begin(); }; - BattleGroundSet::iterator GetBattleGroundsEnd() { return m_BattleGrounds.end(); }; - - BattleGround* GetBattleGround(uint32 InstanceID) - { - BattleGroundSet::iterator i = m_BattleGrounds.find(InstanceID); - return ( (i != m_BattleGrounds.end()) ? i->second : NULL ); - }; + BattleGround* GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId); //there must be uint32 because MAX_BATTLEGROUND_TYPE_ID means unknown BattleGround * GetBattleGroundTemplate(BattleGroundTypeId bgTypeId); - BattleGround * CreateNewBattleGround(BattleGroundTypeId bgTypeId); + BattleGround * CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated); uint32 CreateBattleGround(BattleGroundTypeId bgTypeId, bool IsArena, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO); - void AddBattleGround(uint32 InstanceID, BattleGround* BG) { m_BattleGrounds[InstanceID] = BG; }; - void RemoveBattleGround(uint32 instanceID) { m_BattleGrounds.erase(instanceID); } + void AddBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId, BattleGround* BG) { m_BattleGrounds[bgTypeId][InstanceID] = BG; }; + void RemoveBattleGround(uint32 instanceID, BattleGroundTypeId bgTypeId) { m_BattleGrounds[bgTypeId].erase(instanceID); } void CreateInitialBattleGrounds(); void DeleteAlllBattleGrounds(); - void SendToBattleGround(Player *pl, uint32 InstanceID); + void SendToBattleGround(Player *pl, uint32 InstanceID, BattleGroundTypeId bgTypeId); /* Battleground queues */ //these queues are instantiated when creating BattlegroundMrg @@ -247,7 +237,7 @@ class BattleGroundMgr BattleMastersMap mBattleMastersMap; /* Battlegrounds */ - BattleGroundSet m_BattleGrounds; + BattleGroundSet m_BattleGrounds[MAX_BATTLEGROUND_TYPE_ID]; uint32 m_NextRatingDiscardUpdate; uint64 m_NextAutoDistributionTime; uint32 m_AutoDistributionTimeChecker; diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 917234e62..dac790ca4 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -309,6 +309,7 @@ ChatCommand * ChatHandler::getCommandTable() { "skill_fishing_base_level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillFishingBaseLevelCommand, "", NULL }, { "skinning_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSkinningCommand, "", NULL }, { "spell_affect", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAffectCommand, "", NULL }, + { "spell_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAreaCommand, "", NULL }, { "spell_chain", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellChainCommand, "", NULL }, { "spell_elixir", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellElixirCommand, "", NULL }, { "spell_learn_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLearnSpellCommand, "", NULL }, diff --git a/src/game/Chat.h b/src/game/Chat.h index 87dd31610..0ab3bd902 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -259,6 +259,7 @@ class ChatHandler bool HandleReloadSkillExtraItemTemplateCommand(const char* args); bool HandleReloadSkillFishingBaseLevelCommand(const char* args); bool HandleReloadSpellAffectCommand(const char* args); + bool HandleReloadSpellAreaCommand(const char* args); bool HandleReloadSpellChainCommand(const char* args); bool HandleReloadSpellElixirCommand(const char* args); bool HandleReloadSpellLearnSpellCommand(const char* args); diff --git a/src/game/Corpse.cpp b/src/game/Corpse.cpp index 8dcac70f4..780eb8c96 100644 --- a/src/game/Corpse.cpp +++ b/src/game/Corpse.cpp @@ -100,12 +100,21 @@ void Corpse::SaveToDB() std::ostringstream ss; ss << "INSERT INTO corpse (guid,player,position_x,position_y,position_z,orientation,zone,map,data,time,corpse_type,instance,phaseMask) VALUES (" - << GetGUIDLow() << ", " << GUID_LOPART(GetOwnerGUID()) << ", " << GetPositionX() << ", " << GetPositionY() << ", " << GetPositionZ() << ", " - << GetOrientation() << ", " << GetZoneId() << ", " << GetMapId() << ", '"; + << GetGUIDLow() << ", " + << GUID_LOPART(GetOwnerGUID()) << ", " + << GetPositionX() << ", " + << GetPositionY() << ", " + << GetPositionZ() << ", " + << GetOrientation() << ", " + << GetZoneId() << ", " + << GetMapId() << ", '"; for(uint16 i = 0; i < m_valuesCount; i++ ) ss << GetUInt32Value(i) << " "; - ss << "'," << uint64(m_time) <<", " << uint32(GetType()) - << ", " << int(GetInstanceId()) << ", " << int(GetPhaseMask()) << ")"; + ss << "'," + << uint64(m_time) <<", " + << uint32(GetType()) << ", " + << int(GetInstanceId()) << ", " + << uint16(GetPhaseMask()) << ")"; // prevent out of range error CharacterDatabase.Execute( ss.str().c_str() ); CharacterDatabase.CommitTransaction(); } diff --git a/src/game/Corpse.h b/src/game/Corpse.h index a072402e5..819382847 100644 --- a/src/game/Corpse.h +++ b/src/game/Corpse.h @@ -86,6 +86,8 @@ class Corpse : public WorldObject void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); } GridReference &GetGridRef() { return m_gridRef; } + + bool isActiveObject() const { return false; } private: GridReference m_gridRef; diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index df96a2b88..32ab79c6a 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -114,7 +114,7 @@ m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_resp m_gossipOptionLoaded(false), m_emoteState(0), m_isPet(false), m_isVehicle(false), m_isTotem(false), m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_AlreadyCallAssistance(false), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), -m_creatureInfo(NULL) +m_creatureInfo(NULL), m_isActiveObject(false) { m_regenTimer = 200; m_valuesCount = UNIT_END; @@ -1124,8 +1124,8 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) << m_DBTableGuid << "," << GetEntry() << "," << mapid <<"," - << (uint32)spawnMask << "," - << (uint32)GetPhaseMask() << "," + << uint32(spawnMask) << "," // cast to prevent save as symbol + << uint16(GetPhaseMask()) << "," // prevent out of range error << displayId <<"," << GetEquipmentId() <<"," << GetPositionX() << "," @@ -2098,3 +2098,23 @@ const char* Creature::GetNameForLocaleIdx(int32 loc_idx) const return GetName(); } + +void Creature::SetActiveObjectState( bool on ) +{ + if(m_isActiveObject==on) + return; + + bool world = IsInWorld(); + + Map* map; + if(world) + { + map = GetMap(); + map->Remove(this,false); + } + + m_isActiveObject = on; + + if(world) + map->Add(this); +} \ No newline at end of file diff --git a/src/game/Creature.h b/src/game/Creature.h index e6076dbbb..59c655477 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -609,7 +609,10 @@ class MANGOS_DLL_SPEC Creature : public Unit uint32 GetGlobalCooldown() const { return m_GlobalCooldown; } - void SetDeadByDefault (bool death_state) {m_isDeadByDefault = death_state;} + void SetDeadByDefault (bool death_state) { m_isDeadByDefault = death_state; } + + bool isActiveObject() const { return m_isActiveObject; } + void SetActiveObjectState(bool on); protected: bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL); @@ -661,6 +664,7 @@ class MANGOS_DLL_SPEC Creature : public Unit private: GridReference m_gridRef; CreatureInfo const* m_creatureInfo; // in heroic mode can different from ObjMgr::GetCreatureTemplate(GetEntry()) + bool m_isActiveObject; }; class AssistDelayEvent : public BasicEvent diff --git a/src/game/DestinationHolderImp.h b/src/game/DestinationHolderImp.h index 911f9d2be..d91eb8bcd 100644 --- a/src/game/DestinationHolderImp.h +++ b/src/game/DestinationHolderImp.h @@ -83,20 +83,7 @@ DestinationHolder::StartTravel(TRAVELLER &traveller, bool sendMove) i_fromY = traveller.GetPositionY(); i_fromZ = traveller.GetPositionZ(); - float dx = i_destX - i_fromX; - float dy = i_destY - i_fromY; - float dz = i_destZ - i_fromZ; - - float dist; - //Should be for Creature Flying and Swimming. - if(traveller.GetTraveller().hasUnitState(UNIT_STAT_IN_FLIGHT)) - dist = sqrt((dx*dx) + (dy*dy) + (dz*dz)); - else //Walking on the ground - dist = sqrt((dx*dx) + (dy*dy)); - float speed = traveller.Speed(); - - speed *= 0.001f; // speed is in seconds so convert from second to millisecond - i_totalTravelTime = static_cast(dist/speed); + i_totalTravelTime = traveller.GetTotalTrevelTimeTo(i_destX,i_destY,i_destZ); i_timeElapsed = 0; if(sendMove) traveller.MoveTo(i_destX, i_destY, i_destZ, i_totalTravelTime); diff --git a/src/game/DynamicObject.h b/src/game/DynamicObject.h index 7c1d821e1..830662f0c 100644 --- a/src/game/DynamicObject.h +++ b/src/game/DynamicObject.h @@ -54,6 +54,8 @@ class DynamicObject : public WorldObject void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); } GridReference &GetGridRef() { return m_gridRef; } + + bool isActiveObject() const { return false; } protected: uint64 m_casterGuid; uint32 m_spellId; diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index 39fa01203..939da111b 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -531,8 +531,8 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) << m_DBTableGuid << ", " << GetEntry() << ", " << mapid << ", " - << (uint32)spawnMask << ", " - << (uint32)GetPhaseMask() << "," + << uint32(spawnMask) << "," // cast to prevent save as symbol + << uint16(GetPhaseMask()) << "," // prevent out of range error << GetPositionX() << ", " << GetPositionY() << ", " << GetPositionZ() << ", " diff --git a/src/game/GameObject.h b/src/game/GameObject.h index 404d20fac..f34364bc5 100644 --- a/src/game/GameObject.h +++ b/src/game/GameObject.h @@ -575,6 +575,8 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject GameObject* LookupFishingHoleAround(float range); GridReference &GetGridRef() { return m_gridRef; } + + bool isActiveObject() const { return false; } protected: uint32 m_charges; // Spell charges for GAMEOBJECT_TYPE_SPELLCASTER (22) uint32 m_spellId; diff --git a/src/game/GossipDef.cpp b/src/game/GossipDef.cpp index b1c642276..c86e235bb 100644 --- a/src/game/GossipDef.cpp +++ b/src/game/GossipDef.cpp @@ -151,7 +151,7 @@ void PlayerMenu::SendGossipMenu( uint32 TitleTextId, uint64 npcGUID ) data << uint32(questID); data << uint32( qItem.m_qIcon ); - data << uint32(pQuest && pQuest->GetQuestLevel() ? pQuest->GetQuestLevel() : pSession->GetPlayer()->getLevel()); + data << uint32(pSession->GetPlayer()->GetQuestLevel(pQuest)); std::string Title = pQuest->GetTitle(); int loc_idx = pSession->GetSessionDbLocaleIndex(); @@ -400,7 +400,7 @@ void PlayerMenu::SendQuestGiverQuestList( QEmote eEmote, const std::string& Titl data << uint32(questID); data << uint32(qmi.m_qIcon); - data << uint32(pQuest && pQuest->GetQuestLevel() ? pQuest->GetQuestLevel() : pSession->GetPlayer()->getLevel()); + data << uint32(pSession->GetPlayer()->GetQuestLevel(pQuest)); data << title; } pSession->SendPacket( &data ); @@ -547,7 +547,7 @@ void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest ) data << uint32(pQuest->GetQuestId()); data << uint32(pQuest->GetQuestMethod()); // Accepted values: 0, 1 or 2. 0==IsAutoComplete() (skip objectives/details) - data << uint32(pQuest->GetQuestLevel()); // may be 0 + data << uint32(pQuest->GetQuestLevel()); // may be 0, static data, in other cases must be used dynamic level: Player::GetQuestLevel data << uint32(pQuest->GetZoneOrSort()); // zone or sort to display in quest log data << uint32(pQuest->GetType()); diff --git a/src/game/GridNotifiers.cpp b/src/game/GridNotifiers.cpp index 56de6adaa..8f49150d3 100644 --- a/src/game/GridNotifiers.cpp +++ b/src/game/GridNotifiers.cpp @@ -130,11 +130,17 @@ VisibleNotifier::Notify() // Now do operations that required done at object visibility change to visible - // target aura duration for caster show only if target exist at caster client // send data at target visibility change (adding to client) for(std::set::const_iterator vItr = i_visibleNow.begin(); vItr != i_visibleNow.end(); ++vItr) + { + // target aura duration for caster show only if target exist at caster client if((*vItr)!=&i_player && (*vItr)->isType(TYPEMASK_UNIT)) i_player.SendAurasForTarget((Unit*)(*vItr)); + + // non finished movements show to player + if((*vItr)->GetTypeId()==TYPEID_UNIT && ((Creature*)(*vItr))->isAlive()) + ((Creature*)(*vItr))->SendMonsterMoveWithSpeedToCurrentDestination(&i_player); + } } void diff --git a/src/game/GridStates.cpp b/src/game/GridStates.cpp index 1bace7c27..4743860f5 100644 --- a/src/game/GridStates.cpp +++ b/src/game/GridStates.cpp @@ -34,7 +34,7 @@ ActiveState::Update(Map &m, NGridType &grid, GridInfo & info, const uint32 &x, c info.UpdateTimeTracker(t_diff); if( info.getTimeTracker().Passed() ) { - if( grid.ActiveObjectsInGrid() == 0 && !m.PlayersNearGrid(x, y) ) + if( grid.ActiveObjectsInGrid() == 0 && !m.ActiveObjectsNearGrid(x, y) ) { ObjectGridStoper stoper(grid); stoper.StopN(); @@ -58,14 +58,14 @@ IdleState::Update(Map &m, NGridType &grid, GridInfo &, const uint32 &x, const ui void RemovalState::Update(Map &m, NGridType &grid, GridInfo &info, const uint32 &x, const uint32 &y, const uint32 &t_diff) const { - if(info.getUnloadFlag()) + if(!info.getUnloadLock()) { info.UpdateTimeTracker(t_diff); if( info.getTimeTracker().Passed() ) { if( !m.UnloadGrid(x, y, false) ) { - sLog.outDebug("Grid[%u,%u] for map %u differed unloading due to players nearby", x, y, m.GetId()); + sLog.outDebug("Grid[%u,%u] for map %u differed unloading due to players or active objects nearby", x, y, m.GetId()); m.ResetGridExpiry(grid); } } diff --git a/src/game/Group.cpp b/src/game/Group.cpp index d2fabecea..21695b754 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -1344,7 +1344,7 @@ uint32 Group::CanJoinBattleGroundQueue(BattleGroundTypeId bgTypeId, BattleGround if(!reference) return BG_JOIN_ERR_OFFLINE_MEMBER; - uint32 queue_id = reference->GetBattleGroundQueueIdFromLevel(bgTypeId); + BGQueueIdBasedOnLevel queue_id = reference->GetBattleGroundQueueIdFromLevel(bgTypeId); uint32 arenaTeamId = reference->GetArenaTeamId(arenaSlot); uint32 team = reference->GetTeam(); diff --git a/src/game/Item.cpp b/src/game/Item.cpp index b2934fc48..486781b66 100644 --- a/src/game/Item.cpp +++ b/src/game/Item.cpp @@ -263,7 +263,7 @@ bool Item::Create( uint32 guidlow, uint32 itemid, Player const* owner) SetUInt32Value(ITEM_FIELD_MAXDURABILITY, itemProto->MaxDurability); SetUInt32Value(ITEM_FIELD_DURABILITY, itemProto->MaxDurability); - for(int i = 0; i < 5; ++i) + for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) SetSpellCharges(i,itemProto->Spells[i].SpellCharges); SetUInt32Value(ITEM_FIELD_FLAGS, itemProto->Flags); diff --git a/src/game/Item.h b/src/game/Item.h index 4dfea4b90..b3afa1124 100644 --- a/src/game/Item.h +++ b/src/game/Item.h @@ -165,7 +165,7 @@ enum EnchantmentSlot #define MAX_VISIBLE_ITEM_OFFSET 18 // 18 fields per visible item (creator(2) + enchantments(13) + properties(1) + seed(1) + pad(1)) -#define MAX_GEM_SOCKETS 3 // (BONUS_ENCHANTMENT_SLOT-SOCK_ENCHANTMENT_SLOT) +#define MAX_GEM_SOCKETS MAX_ITEM_PROTO_SOCKETS// (BONUS_ENCHANTMENT_SLOT-SOCK_ENCHANTMENT_SLOT) and item proto size, equal value expected enum EnchantmentOffset { diff --git a/src/game/ItemHandler.cpp b/src/game/ItemHandler.cpp index f5937dd60..33b94943c 100644 --- a/src/game/ItemHandler.cpp +++ b/src/game/ItemHandler.cpp @@ -355,7 +355,7 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data ) } data << pProto->ScalingStatDistribution; // scaling stats distribution data << pProto->ScalingStatValue; // some kind of flags used to determine stat values column - for(int i = 0; i < 2; ++i) + for(int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) { data << pProto->Damage[i].DamageMin; data << pProto->Damage[i].DamageMax; @@ -375,7 +375,7 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data ) data << pProto->AmmoType; data << pProto->RangedModRange; - for(int s = 0; s < 5; s++) + for(int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s) { // send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown // use `item_template` or if not set then only use spell cooldowns @@ -429,7 +429,7 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data ) data << pProto->Map; // Added in 1.12.x & 2.0.1 client branch data << pProto->BagFamily; data << pProto->TotemCategory; - for(int s = 0; s < 3; s++) + for(int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s) { data << pProto->Socket[s].Color; data << pProto->Socket[s].Content; diff --git a/src/game/ItemPrototype.h b/src/game/ItemPrototype.h index f30ed2bfb..cb512ae8d 100644 --- a/src/game/ItemPrototype.h +++ b/src/game/ItemPrototype.h @@ -491,6 +491,11 @@ struct _Socket uint32 Content; }; +#define MAX_ITEM_PROTO_DAMAGES 2 // changed in 3.1.0 +#define MAX_ITEM_PROTO_SOCKETS 3 +#define MAX_ITEM_PROTO_SPELLS 5 +#define MAX_ITEM_PROTO_STATS 10 + struct ItemPrototype { uint32 ItemId; @@ -520,10 +525,10 @@ struct ItemPrototype int32 Stackable; // 0: not allowed, -1: put in player coin info tab and don't limit stacking (so 1 slot) uint32 ContainerSlots; uint32 StatsCount; - _ItemStat ItemStat[10]; + _ItemStat ItemStat[MAX_ITEM_PROTO_STATS]; uint32 ScalingStatDistribution; // id from ScalingStatDistribution.dbc uint32 ScalingStatValue; // mask for selecting column in ScalingStatValues.dbc - _Damage Damage[2]; + _Damage Damage[MAX_ITEM_PROTO_DAMAGES]; uint32 Armor; uint32 HolyRes; uint32 FireRes; @@ -534,7 +539,7 @@ struct ItemPrototype uint32 Delay; uint32 AmmoType; float RangedModRange; - _Spell Spells[5]; + _Spell Spells[MAX_ITEM_PROTO_SPELLS]; uint32 Bonding; char* Description; uint32 PageText; @@ -553,7 +558,7 @@ struct ItemPrototype uint32 Map; // id from Map.dbc uint32 BagFamily; // id from ItemBagFamily.dbc uint32 TotemCategory; // id from TotemCategory.dbc - _Socket Socket[3]; + _Socket Socket[MAX_ITEM_PROTO_SOCKETS]; uint32 socketBonus; // id from SpellItemEnchantment.dbc uint32 GemProperties; // id from GemProperties.dbc uint32 RequiredDisenchantSkill; @@ -634,8 +639,8 @@ struct ItemPrototype if (Delay == 0) return 0; float temp = 0; - for (int i = 0; i < 2; ++i) - temp += Damage[i].DamageMin + Damage[i].DamageMax; + for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) + temp+=Damage[i].DamageMin + Damage[i].DamageMax; return temp*500/Delay; } diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index 60781c47d..4fd4e4a86 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -381,7 +381,7 @@ bool ChatHandler::HandleNamegoCommand(const char* args) } // all's well, set bg id // when porting out from the bg, it will be reset to 0 - chr->SetBattleGroundId(m_session->GetPlayer()->GetBattleGroundId()); + chr->SetBattleGroundId(m_session->GetPlayer()->GetBattleGroundId(), m_session->GetPlayer()->GetBattleGroundTypeId()); // remember current position as entry point for return at bg end teleportation chr->SetBattleGroundEntryPoint(chr->GetMapId(),chr->GetPositionX(),chr->GetPositionY(),chr->GetPositionZ(),chr->GetOrientation()); } @@ -499,7 +499,7 @@ bool ChatHandler::HandleGonameCommand(const char* args) } // all's well, set bg id // when porting out from the bg, it will be reset to 0 - _player->SetBattleGroundId(chr->GetBattleGroundId()); + _player->SetBattleGroundId(chr->GetBattleGroundId(), chr->GetBattleGroundTypeId()); // remember current position as entry point for return at bg end teleportation _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation()); } diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index c993949d1..ec2bd95d5 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -134,6 +134,7 @@ bool ChatHandler::HandleReloadAllSpellCommand(const char*) HandleReloadSkillDiscoveryTemplateCommand("a"); HandleReloadSkillExtraItemTemplateCommand("a"); HandleReloadSpellAffectCommand("a"); + HandleReloadSpellAreaCommand("a"); HandleReloadSpellChainCommand("a"); HandleReloadSpellElixirCommand("a"); HandleReloadSpellLearnSpellCommand("a"); @@ -444,6 +445,14 @@ bool ChatHandler::HandleReloadSpellAffectCommand(const char*) return true; } +bool ChatHandler::HandleReloadSpellAreaCommand(const char*) +{ + sLog.outString( "Re-Loading SpellArea Data..." ); + spellmgr.LoadSpellAreas(); + SendGlobalSysMessage("DB table `spell_area` (spell dependences from area/quest/auras state) reloaded."); + return true; +} + bool ChatHandler::HandleReloadSpellChainCommand(const char*) { sLog.outString( "Re-Loading Spell Chain Data... " ); @@ -3218,18 +3227,36 @@ bool ChatHandler::HandleGuildDeleteCommand(const char* args) return true; } -bool ChatHandler::HandleGetDistanceCommand(const char* /*args*/) +bool ChatHandler::HandleGetDistanceCommand(const char* args) { - Unit* pUnit = getSelectedUnit(); + WorldObject* obj; - if(!pUnit) + if (*args) { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; + uint64 guid = extractGuidFromLink((char*)args); + if(guid) + obj = (WorldObject*)ObjectAccessor::GetObjectByTypeMask(*m_session->GetPlayer(),guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); + + if(!obj) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + } + else + { + obj = getSelectedUnit(); + + if(!obj) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } } - PSendSysMessage(LANG_DISTANCE, m_session->GetPlayer()->GetDistance(pUnit),m_session->GetPlayer()->GetDistance2d(pUnit)); + PSendSysMessage(LANG_DISTANCE, m_session->GetPlayer()->GetDistance(obj),m_session->GetPlayer()->GetDistance2d(obj)); return true; } @@ -3825,7 +3852,7 @@ bool ChatHandler::HandleLevelUpCommand(const char* args) return false; } - name = GetNameLink(chr); + name = chr->GetName(); } assert(chr || chr_guid); diff --git a/src/game/LootMgr.cpp b/src/game/LootMgr.cpp index 05b08eb8a..591a123f8 100644 --- a/src/game/LootMgr.cpp +++ b/src/game/LootMgr.cpp @@ -55,7 +55,7 @@ class LootTemplate::LootGroup // A set of loot def bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry bool HasQuestDropForPlayer(Player const * player) const; // The same for active quests of the player - void Process(Loot& loot, bool rate) const; // Rolls an item from the group (if any) and adds the item to the loot + void Process(Loot& loot) const; // Rolls an item from the group (if any) and adds the item to the loot float RawTotalChance() const; // Overall chance for the group (without equal chanced items) float TotalChance() const; // Overall chance for the group @@ -66,7 +66,7 @@ class LootTemplate::LootGroup // A set of loot def LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance - LootStoreItem const * Roll(bool rate) const; // Rolls an item from the group, returns NULL if all miss their chances + LootStoreItem const * Roll() const; // Rolls an item from the group, returns NULL if all miss their chances }; //Remove all data and free all memory @@ -789,7 +789,7 @@ void LootTemplate::LootGroup::AddEntry(LootStoreItem& item) } // Rolls an item from the group, returns NULL if all miss their chances -LootStoreItem const * LootTemplate::LootGroup::Roll(bool rate) const +LootStoreItem const * LootTemplate::LootGroup::Roll() const { if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked { @@ -800,9 +800,7 @@ LootStoreItem const * LootTemplate::LootGroup::Roll(bool rate) const if(ExplicitlyChanced[i].chance>=100.f) return &ExplicitlyChanced[i]; - ItemPrototype const *pProto = objmgr.GetItemPrototype(ExplicitlyChanced[i].itemid); - float qualityMultiplier = pProto && rate ? sWorld.getRate(qualityToRate[pProto->Quality]) : 1.0f; - Roll -= ExplicitlyChanced[i].chance * qualityMultiplier; + Roll -= ExplicitlyChanced[i].chance; if (Roll < 0) return &ExplicitlyChanced[i]; } @@ -838,9 +836,9 @@ bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const * player) const } // Rolls an item from the group (if any takes its chance) and adds the item to the loot -void LootTemplate::LootGroup::Process(Loot& loot, bool rate) const +void LootTemplate::LootGroup::Process(Loot& loot) const { - LootStoreItem const * item = Roll(rate); + LootStoreItem const * item = Roll(); if (item != NULL) loot.AddItem(*item); } @@ -932,7 +930,7 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint8 if (groupId > Groups.size()) return; // Error message already printed at loading stage - Groups[groupId-1].Process(loot,rate); + Groups[groupId-1].Process(loot); return; } @@ -958,7 +956,7 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint8 // Now processing groups for (LootGroups::const_iterator i = Groups.begin( ) ; i != Groups.end( ) ; ++i ) - i->Process(loot,rate); + i->Process(loot); } // True if template includes at least 1 quest drop entry diff --git a/src/game/Makefile.am b/src/game/Makefile.am index a162214ca..2b10e7b6e 100644 --- a/src/game/Makefile.am +++ b/src/game/Makefile.am @@ -28,261 +28,261 @@ noinst_LIBRARIES = libmangosgame.a # libmangossgame library will later be reused by ... libmangosgame_a_SOURCES = \ - AccountMgr.cpp \ - AccountMgr.h \ - AchievementMgr.h \ - AchievementMgr.cpp \ - AddonHandler.cpp \ - AddonHandler.h \ - AggressorAI.cpp \ - AggressorAI.h \ - AnimalRandomMovementGenerator.h \ - ArenaTeam.cpp \ - ArenaTeam.h \ - ArenaTeamHandler.cpp \ - AuctionHouseHandler.cpp \ - AuctionHouseMgr.cpp \ - AuctionHouseMgr.h \ - Bag.cpp \ - Bag.h \ - BattleGround.cpp \ - BattleGroundAA.cpp \ - BattleGroundAB.cpp \ - BattleGroundAV.cpp \ - BattleGroundBE.cpp \ - BattleGroundDS.cpp \ - BattleGroundEY.cpp \ - BattleGroundNA.cpp \ - BattleGroundRL.cpp \ - BattleGroundRV.cpp \ - BattleGroundSA.cpp \ - BattleGroundWS.cpp \ - BattleGround.h \ - BattleGroundAA.h \ - BattleGroundAB.h \ - BattleGroundAV.h \ - BattleGroundBE.h \ - BattleGroundDS.h \ - BattleGroundEY.h \ - BattleGroundNA.h \ - BattleGroundRL.h \ - BattleGroundRV.h \ - BattleGroundSA.h \ - BattleGroundWS.h \ - BattleGroundHandler.cpp \ - BattleGroundMgr.cpp \ - BattleGroundMgr.h \ - Calendar.cpp \ - Calendar.h \ - CalendarHandler.cpp \ - Cell.h \ - CellImpl.h \ - Channel.cpp \ - Channel.h \ - ChannelHandler.cpp \ - ChannelMgr.h \ - CharacterHandler.cpp \ - Chat.cpp \ - Chat.h \ - ChatHandler.cpp \ - CombatHandler.cpp \ - ConfusedMovementGenerator.cpp \ - ConfusedMovementGenerator.h \ - Corpse.cpp \ - Corpse.h \ - CreatureAI.cpp \ - CreatureAI.h \ - CreatureAIImpl.h \ - CreatureAIRegistry.cpp \ - CreatureAIRegistry.h \ - CreatureAISelector.cpp \ - CreatureAISelector.h \ - Creature.cpp \ - Creature.h \ - debugcmds.cpp \ - DestinationHolder.cpp \ - DestinationHolder.h \ - DestinationHolderImp.h \ - DuelHandler.cpp \ - DynamicObject.cpp \ - DynamicObject.h \ - FleeingMovementGenerator.cpp \ - FleeingMovementGenerator.h \ - Formulas.h \ - GameEvent.cpp \ - GameEvent.h \ - GameObject.cpp \ - GameObject.h \ - GlobalEvents.cpp \ - GlobalEvents.h \ - GMTicketHandler.cpp \ - GMTicketMgr.cpp \ - GMTicketMgr.h \ - GossipDef.cpp \ - GossipDef.h \ - GridDefines.h \ - GridNotifiers.cpp \ - GridNotifiers.h \ - GridNotifiersImpl.h \ - GridStates.cpp \ - GridStates.h \ - Group.cpp \ - Group.h \ - GroupHandler.cpp \ - GuardAI.cpp \ - GuardAI.h \ - Guild.cpp \ - Guild.h \ - GuildHandler.cpp \ - HomeMovementGenerator.cpp \ - HomeMovementGenerator.h \ - HostilRefManager.cpp \ - HostilRefManager.h \ - IdleMovementGenerator.cpp \ - IdleMovementGenerator.h \ - InstanceData.cpp \ - InstanceData.h \ - InstanceSaveMgr.cpp \ - InstanceSaveMgr.h \ - Item.cpp \ - Item.h \ - ItemEnchantmentMgr.cpp \ - ItemEnchantmentMgr.h \ - ItemHandler.cpp \ - ItemPrototype.h \ - Language.h \ - Level0.cpp \ - Level1.cpp \ - Level2.cpp \ - Level3.cpp \ - LFGHandler.cpp \ - LootHandler.cpp \ - LootMgr.cpp \ - LootMgr.h \ - Mail.cpp \ - Mail.h \ - Map.cpp \ - Map.h \ - MapInstanced.cpp \ - MapInstanced.h \ - MapManager.cpp \ - MapManager.h \ - MapReference.h \ - MapRefManager.h \ - MiscHandler.cpp \ - MotionMaster.cpp \ - MotionMaster.h \ - MovementGenerator.cpp \ - MovementGenerator.h \ - MovementGeneratorImpl.h \ - MovementHandler.cpp \ - NPCHandler.cpp \ - NPCHandler.h \ - NullCreatureAI.cpp \ - NullCreatureAI.h \ - ObjectAccessor.cpp \ - ObjectAccessor.h \ - Object.cpp \ - ObjectDefines.h \ - ObjectGridLoader.cpp \ - ObjectGridLoader.h \ - Object.h \ - ObjectMgr.cpp \ - ObjectMgr.h \ - ObjectPosSelector.cpp \ - ObjectPosSelector.h \ - Opcodes.cpp \ - Opcodes.h \ - Path.h \ - PetAI.cpp \ - PetAI.h \ - Pet.cpp \ - Pet.h \ - PetHandler.cpp \ - PetitionsHandler.cpp \ - Player.cpp \ - Player.h \ - PlayerDump.cpp \ - PlayerDump.h \ - PointMovementGenerator.cpp \ - PointMovementGenerator.h \ - PoolHandler.cpp \ - PoolHandler.h \ - QueryHandler.cpp \ - QuestDef.cpp \ - QuestDef.h \ - QuestHandler.cpp \ - RandomMovementGenerator.cpp \ - RandomMovementGenerator.h \ - ReactorAI.cpp \ - ReactorAI.h \ - ScriptCalls.cpp \ - ScriptCalls.h \ - SharedDefines.h \ - SkillHandler.cpp \ - SpellAuraDefines.h \ - SpellAuras.cpp \ - SpellAuras.h \ - Spell.cpp \ - SpellEffects.cpp \ - Spell.h \ - SkillDiscovery.cpp \ - SkillDiscovery.h \ - SkillExtraItems.cpp \ - SkillExtraItems.h \ - SpellHandler.cpp \ - SocialMgr.cpp \ - SocialMgr.h \ - SpellMgr.cpp \ - SpellMgr.h \ - StatSystem.cpp \ - TargetedMovementGenerator.cpp \ - TargetedMovementGenerator.h \ - TaxiHandler.cpp \ - TemporarySummon.cpp \ - TemporarySummon.h \ - TotemAI.cpp \ - TotemAI.h \ - Totem.cpp \ - Totem.h \ - TradeHandler.cpp \ - Transports.cpp \ - Transports.h \ - ThreatManager.cpp \ - ThreatManager.h \ - Traveller.h \ - Unit.cpp \ - Unit.h \ - UnitEvents.h \ - UpdateData.cpp \ - UpdateData.h \ - UpdateFields.h \ - UpdateMask.h \ - Vehicle.cpp \ - Vehicle.h \ - VoiceChatHandler.cpp \ - WaypointManager.cpp \ - WaypointManager.h \ - WaypointMovementGenerator.cpp \ - WaypointMovementGenerator.h \ - Weather.cpp \ - Weather.h \ - World.cpp \ - World.h \ - WorldLog.cpp \ - WorldLog.h \ - WorldSession.cpp \ - WorldSession.h \ - WorldSocket.cpp \ - WorldSocket.h \ - WorldSocketMgr.cpp \ - WorldSocketMgr.h \ - FollowerReference.cpp \ - FollowerReference.h \ - FollowerRefManager.h \ - GroupReference.cpp \ - GroupReference.h \ - GroupRefManager.h + AccountMgr.cpp \ + AccountMgr.h \ + AchievementMgr.h \ + AchievementMgr.cpp \ + AddonHandler.cpp \ + AddonHandler.h \ + AggressorAI.cpp \ + AggressorAI.h \ + AnimalRandomMovementGenerator.h \ + ArenaTeam.cpp \ + ArenaTeam.h \ + ArenaTeamHandler.cpp \ + AuctionHouseHandler.cpp \ + AuctionHouseMgr.cpp \ + AuctionHouseMgr.h \ + Bag.cpp \ + Bag.h \ + BattleGround.cpp \ + BattleGroundAA.cpp \ + BattleGroundAB.cpp \ + BattleGroundAV.cpp \ + BattleGroundBE.cpp \ + BattleGroundDS.cpp \ + BattleGroundEY.cpp \ + BattleGroundNA.cpp \ + BattleGroundRL.cpp \ + BattleGroundRV.cpp \ + BattleGroundSA.cpp \ + BattleGroundWS.cpp \ + BattleGround.h \ + BattleGroundAA.h \ + BattleGroundAB.h \ + BattleGroundAV.h \ + BattleGroundBE.h \ + BattleGroundDS.h \ + BattleGroundEY.h \ + BattleGroundNA.h \ + BattleGroundRL.h \ + BattleGroundRV.h \ + BattleGroundSA.h \ + BattleGroundWS.h \ + BattleGroundHandler.cpp \ + BattleGroundMgr.cpp \ + BattleGroundMgr.h \ + Calendar.cpp \ + Calendar.h \ + CalendarHandler.cpp \ + Cell.h \ + CellImpl.h \ + Channel.cpp \ + Channel.h \ + ChannelHandler.cpp \ + ChannelMgr.h \ + CharacterHandler.cpp \ + Chat.cpp \ + Chat.h \ + ChatHandler.cpp \ + CombatHandler.cpp \ + ConfusedMovementGenerator.cpp \ + ConfusedMovementGenerator.h \ + Corpse.cpp \ + Corpse.h \ + CreatureAI.cpp \ + CreatureAI.h \ + CreatureAIImpl.h \ + CreatureAIRegistry.cpp \ + CreatureAIRegistry.h \ + CreatureAISelector.cpp \ + CreatureAISelector.h \ + Creature.cpp \ + Creature.h \ + debugcmds.cpp \ + DestinationHolder.cpp \ + DestinationHolder.h \ + DestinationHolderImp.h \ + DuelHandler.cpp \ + DynamicObject.cpp \ + DynamicObject.h \ + FleeingMovementGenerator.cpp \ + FleeingMovementGenerator.h \ + Formulas.h \ + GameEvent.cpp \ + GameEvent.h \ + GameObject.cpp \ + GameObject.h \ + GlobalEvents.cpp \ + GlobalEvents.h \ + GMTicketHandler.cpp \ + GMTicketMgr.cpp \ + GMTicketMgr.h \ + GossipDef.cpp \ + GossipDef.h \ + GridDefines.h \ + GridNotifiers.cpp \ + GridNotifiers.h \ + GridNotifiersImpl.h \ + GridStates.cpp \ + GridStates.h \ + Group.cpp \ + Group.h \ + GroupHandler.cpp \ + GuardAI.cpp \ + GuardAI.h \ + Guild.cpp \ + Guild.h \ + GuildHandler.cpp \ + HomeMovementGenerator.cpp \ + HomeMovementGenerator.h \ + HostilRefManager.cpp \ + HostilRefManager.h \ + IdleMovementGenerator.cpp \ + IdleMovementGenerator.h \ + InstanceData.cpp \ + InstanceData.h \ + InstanceSaveMgr.cpp \ + InstanceSaveMgr.h \ + Item.cpp \ + Item.h \ + ItemEnchantmentMgr.cpp \ + ItemEnchantmentMgr.h \ + ItemHandler.cpp \ + ItemPrototype.h \ + Language.h \ + Level0.cpp \ + Level1.cpp \ + Level2.cpp \ + Level3.cpp \ + LFGHandler.cpp \ + LootHandler.cpp \ + LootMgr.cpp \ + LootMgr.h \ + Mail.cpp \ + Mail.h \ + Map.cpp \ + Map.h \ + MapInstanced.cpp \ + MapInstanced.h \ + MapManager.cpp \ + MapManager.h \ + MapReference.h \ + MapRefManager.h \ + MiscHandler.cpp \ + MotionMaster.cpp \ + MotionMaster.h \ + MovementGenerator.cpp \ + MovementGenerator.h \ + MovementGeneratorImpl.h \ + MovementHandler.cpp \ + NPCHandler.cpp \ + NPCHandler.h \ + NullCreatureAI.cpp \ + NullCreatureAI.h \ + ObjectAccessor.cpp \ + ObjectAccessor.h \ + Object.cpp \ + ObjectDefines.h \ + ObjectGridLoader.cpp \ + ObjectGridLoader.h \ + Object.h \ + ObjectMgr.cpp \ + ObjectMgr.h \ + ObjectPosSelector.cpp \ + ObjectPosSelector.h \ + Opcodes.cpp \ + Opcodes.h \ + Path.h \ + PetAI.cpp \ + PetAI.h \ + Pet.cpp \ + Pet.h \ + PetHandler.cpp \ + PetitionsHandler.cpp \ + Player.cpp \ + Player.h \ + PlayerDump.cpp \ + PlayerDump.h \ + PointMovementGenerator.cpp \ + PointMovementGenerator.h \ + PoolHandler.cpp \ + PoolHandler.h \ + QueryHandler.cpp \ + QuestDef.cpp \ + QuestDef.h \ + QuestHandler.cpp \ + RandomMovementGenerator.cpp \ + RandomMovementGenerator.h \ + ReactorAI.cpp \ + ReactorAI.h \ + ScriptCalls.cpp \ + ScriptCalls.h \ + SharedDefines.h \ + SkillHandler.cpp \ + SpellAuraDefines.h \ + SpellAuras.cpp \ + SpellAuras.h \ + Spell.cpp \ + SpellEffects.cpp \ + Spell.h \ + SkillDiscovery.cpp \ + SkillDiscovery.h \ + SkillExtraItems.cpp \ + SkillExtraItems.h \ + SpellHandler.cpp \ + SocialMgr.cpp \ + SocialMgr.h \ + SpellMgr.cpp \ + SpellMgr.h \ + StatSystem.cpp \ + TargetedMovementGenerator.cpp \ + TargetedMovementGenerator.h \ + TaxiHandler.cpp \ + TemporarySummon.cpp \ + TemporarySummon.h \ + TotemAI.cpp \ + TotemAI.h \ + Totem.cpp \ + Totem.h \ + TradeHandler.cpp \ + Transports.cpp \ + Transports.h \ + ThreatManager.cpp \ + ThreatManager.h \ + Traveller.h \ + Unit.cpp \ + Unit.h \ + UnitEvents.h \ + UpdateData.cpp \ + UpdateData.h \ + UpdateFields.h \ + UpdateMask.h \ + Vehicle.cpp \ + Vehicle.h \ + VoiceChatHandler.cpp \ + WaypointManager.cpp \ + WaypointManager.h \ + WaypointMovementGenerator.cpp \ + WaypointMovementGenerator.h \ + Weather.cpp \ + Weather.h \ + World.cpp \ + World.h \ + WorldLog.cpp \ + WorldLog.h \ + WorldSession.cpp \ + WorldSession.h \ + WorldSocket.cpp \ + WorldSocket.h \ + WorldSocketMgr.cpp \ + WorldSocketMgr.h \ + FollowerReference.cpp \ + FollowerReference.h \ + FollowerRefManager.h \ + GroupReference.cpp \ + GroupReference.h \ + GroupRefManager.h ## Link against shared library libmangosgame_a_LIBADD = ../shared/libmangosshared.a ../shared/Auth/libmangosauth.a ../shared/Config/libmangosconfig.a ../shared/Database/libmangosdatabase.a ../shared/vmap/libmangosvmaps.a diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 47df9ebc9..cafb3464c 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -138,7 +138,6 @@ void Map::LoadMap(uint32 mapid, uint32 instanceid, int x,int y) // return; ((MapInstanced*)(baseMap))->AddGridMapReference(GridPair(x,y)); - baseMap->SetUnloadFlag(GridPair(63-x,63-y), false); GridMaps[x][y] = baseMap->GridMaps[x][y]; return; } @@ -209,7 +208,8 @@ void Map::DeleteStateMachine() Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode) : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), - i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0), i_gridExpiry(expiry) + i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0), i_gridExpiry(expiry), + m_activeNonPlayersIter(m_activeNonPlayers.end()) { for(unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx) { @@ -360,22 +360,22 @@ Map::EnsureGridCreated(const GridPair &p) } void -Map::EnsureGridLoadedForPlayer(const Cell &cell, Player *player, bool add_player) +Map::EnsureGridLoaded(const Cell &cell, Player *player) { EnsureGridCreated(GridPair(cell.GridX(), cell.GridY())); NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); assert(grid != NULL); - if( !isGridObjectDataLoaded(cell.GridX(), cell.GridY()) ) + if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY())) { - if( player != NULL ) + if (player) { player->SendDelayResponse(MAX_GRID_LOAD_TIME); DEBUG_LOG("Player %s enter cell[%u,%u] triggers of loading grid[%u,%u] on map %u", player->GetName(), cell.CellX(), cell.CellY(), cell.GridX(), cell.GridY(), i_id); } else { - DEBUG_LOG("Player nearby triggers of loading grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), i_id); + DEBUG_LOG("Active object nearby triggers of loading grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), i_id); } ObjectGridLoader loader(*grid, this, cell); @@ -387,11 +387,9 @@ Map::EnsureGridLoadedForPlayer(const Cell &cell, Player *player, bool add_player ResetGridExpiry(*getNGrid(cell.GridX(), cell.GridY()), 0.1f); grid->SetGridState(GRID_STATE_ACTIVE); - - if( add_player && player != NULL ) - (*grid)(cell.CellX(), cell.CellY()).AddWorldObject(player, player->GetGUID()); } - else if( player && add_player ) + + if (player) AddToGrid(player,grid,cell); } @@ -412,7 +410,7 @@ Map::LoadGrid(const Cell& cell, bool no_unload) setGridObjectDataLoaded(true,cell.GridX(), cell.GridY()); if(no_unload) - getNGrid(cell.GridX(), cell.GridY())->setUnloadFlag(false); + getNGrid(cell.GridX(), cell.GridY())->setUnloadExplicitLock(true); } LoadVMap(63-cell.GridX(),63-cell.GridY()); } @@ -426,7 +424,7 @@ bool Map::Add(Player *player) // update player state for other player and visa-versa CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); Cell cell(p); - EnsureGridLoadedForPlayer(cell, player, true); + EnsureGridLoaded(cell, player); player->AddToWorld(); SendInitSelf(player); @@ -454,13 +452,20 @@ Map::Add(T *obj) } Cell cell(p); - EnsureGridCreated(GridPair(cell.GridX(), cell.GridY())); + if(obj->isActiveObject()) + EnsureGridLoaded(cell); + else + EnsureGridCreated(GridPair(cell.GridX(), cell.GridY())); + NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); assert( grid != NULL ); AddToGrid(obj,grid,cell); obj->AddToWorld(); + if(obj->isActiveObject()) + AddToActive(obj); + DEBUG_LOG("Object %u enters grid[%u,%u]", GUID_LOPART(obj->GetGUID()), cell.GridX(), cell.GridY()); UpdateObjectVisibility(obj,cell,p); @@ -616,6 +621,56 @@ void Map::Update(const uint32 &t_diff) } } + // non-player active objects + if(!m_activeNonPlayers.empty()) + { + for(m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end(); ) + { + // skip not in world + WorldObject* obj = *m_activeNonPlayersIter; + + // step before processing, in this case if Map::Remove remove next object we correctly + // step to next-next, and if we step to end() then newly added objects can wait next update. + ++m_activeNonPlayersIter; + + if(!obj->IsInWorld()) + continue; + + CellPair standing_cell(MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY())); + + // Check for correctness of standing_cell, it also avoids problems with update_cell + if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + continue; + + // the overloaded operators handle range checking + // so ther's no need for range checking inside the loop + CellPair begin_cell(standing_cell), end_cell(standing_cell); + begin_cell << 1; begin_cell -= 1; // upper left + end_cell >> 1; end_cell += 1; // lower right + + for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x) + { + for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y) + { + // marked cells are those that have been visited + // don't visit the same cell twice + uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; + if(!isCellMarked(cell_id)) + { + markCell(cell_id); + CellPair pair(x,y); + Cell cell(pair); + cell.data.Part.reserved = CENTER_DISTRICT; + cell.SetNoCreate(); + CellLock cell_lock(cell, pair); + cell_lock->Visit(cell_lock, grid_object_update, *this); + cell_lock->Visit(cell_lock, world_object_update, *this); + } + } + } + } + } + // Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load ! // This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended if (IsBattleGroundOrArena()) @@ -708,6 +763,9 @@ Map::Remove(T *obj, bool remove) NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); assert( grid != NULL ); + if(obj->isActiveObject()) + RemoveFromActive(obj); + obj->RemoveFromWorld(); RemoveFromGrid(obj,grid,cell); @@ -749,9 +807,8 @@ Map::PlayerRelocation(Player *player, float x, float y, float z, float orientati RemoveFromGrid(player, oldGrid,old_cell); if( !old_cell.DiffGrid(new_cell) ) AddToGrid(player, oldGrid,new_cell); - - if( old_cell.DiffGrid(new_cell) ) - EnsureGridLoadedForPlayer(new_cell, player, true); + else + EnsureGridLoaded(new_cell, player); } // if move then update what player see and who seen @@ -868,8 +925,27 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell) sLog.outDebug("Creature (GUID: %u Entry: %u) move in same grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY()); #endif } + + return true; } - else // in diff. grids + + // in diff. grids but active creature + if(c->isActiveObject()) + { + EnsureGridLoaded(new_cell); + + #ifdef MANGOS_DEBUG + if((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES)==0) + sLog.outDebug("Active creature (GUID: %u Entry: %u) moved from grid[%u,%u]cell[%u,%u] to grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); + #endif + + RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); + AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); + + return true; + } + + // in diff. loaded grid normal creature if(loaded(GridPair(new_cell.GridX(), new_cell.GridY()))) { #ifdef MANGOS_DEBUG @@ -882,17 +958,16 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell) EnsureGridCreated(GridPair(new_cell.GridX(), new_cell.GridY())); AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); } - } - else - { - #ifdef MANGOS_DEBUG - if((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES)==0) - sLog.outDebug("Creature (GUID: %u Entry: %u) attempt move from grid[%u,%u]cell[%u,%u] to unloaded grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); - #endif - return false; + + return true; } - return true; + // fail to move: normal creature attempt move to unloaded grid + #ifdef MANGOS_DEBUG + if((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES)==0) + sLog.outDebug("Creature (GUID: %u Entry: %u) attempt move from grid[%u,%u]cell[%u,%u] to unloaded grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); + #endif + return false; } bool Map::CreatureRespawnRelocation(Creature *c) @@ -929,7 +1004,7 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool pForce) assert( grid != NULL); { - if(!pForce && PlayersNearGrid(x, y) ) + if(!pForce && ActiveObjectsNearGrid(x, y) ) return false; DEBUG_LOG("Unloading grid[%u,%u] for map %u", x,y, i_id); @@ -1513,7 +1588,7 @@ void Map::SendToPlayers(WorldPacket const* data) const itr->getSource()->GetSession()->SendPacket(data); } -bool Map::PlayersNearGrid(uint32 x, uint32 y) const +bool Map::ActiveObjectsNearGrid(uint32 x, uint32 y) const { CellPair cell_min(x*MAX_NUMBER_OF_CELLS, y*MAX_NUMBER_OF_CELLS); CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS); @@ -1532,9 +1607,61 @@ bool Map::PlayersNearGrid(uint32 x, uint32 y) const return true; } + for(ActiveNonPlayers::const_iterator iter = m_activeNonPlayers.begin(); iter != m_activeNonPlayers.end(); ++iter) + { + WorldObject* obj = *iter; + + CellPair p = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); + if( (cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) && + (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord) ) + return true; + } + return false; } +void Map::AddToActive( Creature* c ) +{ + AddToActiveHelper(c); + + // also not allow unloading spawn grid to prevent creating creature clone at load + if(!c->isPet() && c->GetDBTableGUIDLow()) + { + float x,y,z; + c->GetRespawnCoord(x,y,z); + GridPair p = MaNGOS::ComputeGridPair(x, y); + if(getNGrid(p.x_coord, p.y_coord)) + getNGrid(p.x_coord, p.y_coord)->incUnloadActiveLock(); + else + { + GridPair p2 = MaNGOS::ComputeGridPair(c->GetPositionX(), c->GetPositionY()); + sLog.outError("Active creature (GUID: %u Entry: %u) added to grid[%u,%u] but spawn grid[%u,%u] not loaded.", + c->GetGUIDLow(), c->GetEntry(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord); + } + } +} + +void Map::RemoveFromActive( Creature* c ) +{ + RemoveFromActiveHelper(c); + + // also allow unloading spawn grid + if(!c->isPet() && c->GetDBTableGUIDLow()) + { + float x,y,z; + c->GetRespawnCoord(x,y,z); + GridPair p = MaNGOS::ComputeGridPair(x, y); + if(getNGrid(p.x_coord, p.y_coord)) + getNGrid(p.x_coord, p.y_coord)->decUnloadActiveLock(); + else + { + GridPair p2 = MaNGOS::ComputeGridPair(c->GetPositionX(), c->GetPositionY()); + sLog.outError("Active creature (GUID: %u Entry: %u) removed from grid[%u,%u] but spawn grid[%u,%u] not loaded.", + c->GetGUIDLow(), c->GetEntry(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord); + } + } +} + template void Map::Add(Corpse *); template void Map::Add(Creature *); template void Map::Add(GameObject *); diff --git a/src/game/Map.h b/src/game/Map.h index 65baba71d..80f042674 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -164,8 +164,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj return( !getNGrid(p.x_coord, p.y_coord) || getNGrid(p.x_coord, p.y_coord)->GetGridState() == GRID_STATE_REMOVAL ); } - bool GetUnloadFlag(const GridPair &p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadFlag(); } - void SetUnloadFlag(const GridPair &p, bool unload) { getNGrid(p.x_coord, p.y_coord)->setUnloadFlag(unload); } + bool GetUnloadLock(const GridPair &p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); } + void SetUnloadLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); } void LoadGrid(const Cell& cell, bool no_unload = false); bool UnloadGrid(const uint32 &x, const uint32 &y, bool pForce); virtual void UnloadAll(bool pForce); @@ -216,8 +216,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj // assert print helper bool CheckGridIntegrity(Creature* c, bool moved) const; - uint32 GetInstanceId() { return i_InstanceId; } - uint8 GetSpawnMode() { return (i_spawnMode); } + uint32 GetInstanceId() const { return i_InstanceId; } + uint8 GetSpawnMode() const { return (i_spawnMode); } virtual bool CanEnter(Player* /*player*/) { return true; } const char* GetMapName() const; @@ -256,12 +256,24 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj bool HavePlayers() const { return !m_mapRefManager.isEmpty(); } uint32 GetPlayersCountExceptGMs() const; - bool PlayersNearGrid(uint32 x,uint32 y) const; + bool ActiveObjectsNearGrid(uint32 x,uint32 y) const; void SendToPlayers(WorldPacket const* data) const; typedef MapRefManager PlayerList; PlayerList const& GetPlayers() const { return m_mapRefManager; } + + // must called with AddToWorld + template + void AddToActive(T* obj) { AddToActiveHelper(obj); } + + void AddToActive(Creature* obj); + + // must called with RemoveFromWorld + template + void RemoveFromActive(T* obj) { RemoveFromActiveHelper(obj); } + + void RemoveFromActive(Creature* obj); private: void LoadVMap(int pX, int pY); void LoadMap(uint32 mapid, uint32 instanceid, int x,int y); @@ -283,7 +295,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj CreatureMoveList i_creaturesToMove; bool loaded(const GridPair &) const; - void EnsureGridLoadedForPlayer(const Cell&, Player*, bool add_player); + void EnsureGridLoaded(const Cell&, Player* player = NULL); void EnsureGridCreated(const GridPair &); void buildNGridLinkage(NGridType* pNGridType) { pNGridType->link(this); } @@ -302,6 +314,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj void setNGrid(NGridType* grid, uint32 x, uint32 y); protected: + void SetUnloadReferenceLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); } + typedef MaNGOS::ObjectLevelLockable::Lock Guard; MapEntry const* i_mapEntry; @@ -312,6 +326,10 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj MapRefManager m_mapRefManager; MapRefManager::iterator m_mapRefIter; + + typedef std::set ActiveNonPlayers; + ActiveNonPlayers m_activeNonPlayers; + ActiveNonPlayers::iterator m_activeNonPlayersIter; private: typedef GridReadGuard ReadGuard; typedef GridWriteGuard WriteGuard; @@ -336,6 +354,27 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj template void DeleteFromWorld(T*); + + template + void AddToActiveHelper(T* obj) + { + m_activeNonPlayers.insert(obj); + } + + template + void RemoveFromActiveHelper(T* obj) + { + // Map::Update for active object in proccess + if(m_activeNonPlayersIter != m_activeNonPlayers.end()) + { + ActiveNonPlayers::iterator itr = m_activeNonPlayers.find(obj); + if(itr==m_activeNonPlayersIter) + ++m_activeNonPlayersIter; + m_activeNonPlayers.erase(itr); + } + else + m_activeNonPlayers.erase(obj); + } }; enum InstanceResetMethod @@ -408,7 +447,7 @@ Map::Visit(const CellLock &cell, TypeContainerVisitor & if( !cell->NoCreate() || loaded(GridPair(x,y)) ) { - EnsureGridLoadedForPlayer(cell, NULL, false); + EnsureGridLoaded(cell); //LOCK_TYPE guard(i_info[x][y]->i_lock); getNGrid(x, y)->Visit(cell_x, cell_y, visitor); } diff --git a/src/game/MapInstanced.h b/src/game/MapInstanced.h index 0a998e50d..e195cdcb7 100644 --- a/src/game/MapInstanced.h +++ b/src/game/MapInstanced.h @@ -42,11 +42,18 @@ class MANGOS_DLL_DECL MapInstanced : public Map Map* FindMap(uint32 InstanceId) { return _FindMap(InstanceId); } void DestroyInstance(uint32 InstanceId); void DestroyInstance(InstancedMaps::iterator &itr); - void AddGridMapReference(const GridPair &p) { ++GridMapReference[p.x_coord][p.y_coord]; } + + void AddGridMapReference(const GridPair &p) + { + ++GridMapReference[p.x_coord][p.y_coord]; + SetUnloadReferenceLock(GridPair(63-p.x_coord, 63-p.y_coord), true); + } + void RemoveGridMapReference(const GridPair &p) { --GridMapReference[p.x_coord][p.y_coord]; - if (!GridMapReference[p.x_coord][p.y_coord]) { SetUnloadFlag(GridPair(63-p.x_coord,63-p.y_coord), true); } + if (!GridMapReference[p.x_coord][p.y_coord]) + SetUnloadReferenceLock(GridPair(63-p.x_coord, 63-p.y_coord), false); } InstancedMaps &GetInstancedMaps() { return m_InstancedMaps; } diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp index 9dc84d62f..84a28e463 100644 --- a/src/game/MovementHandler.cpp +++ b/src/game/MovementHandler.cpp @@ -87,7 +87,6 @@ void WorldSession::HandleMoveWorldportAckOpcode() return; } - //this will set player's team ... so IT MUST BE CALLED BEFORE SendInitialPacketsAfterAddToMap() // battleground state prepare (in case join to BG), at relogin/tele player not invited // only add to bg group and object, if the player was invited (else he entered through command) if(_player->InBattleGround()) @@ -95,7 +94,7 @@ void WorldSession::HandleMoveWorldportAckOpcode() // cleanup seting if outdated if(!mEntry->IsBattleGroundOrArena()) { - _player->SetBattleGroundId(0); // We're not in BG. + _player->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG. // reset destination bg team _player->SetBGTeam(0); } diff --git a/src/game/ObjectGridLoader.cpp b/src/game/ObjectGridLoader.cpp index b2735df3b..04a343d36 100644 --- a/src/game/ObjectGridLoader.cpp +++ b/src/game/ObjectGridLoader.cpp @@ -125,6 +125,9 @@ void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager & addUnitState(obj,cell); obj->AddToWorld(); + if(obj->isActiveObject()) + map->AddToActive(obj); + ++count; } @@ -150,6 +153,9 @@ void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType addUnitState(obj,cell); obj->AddToWorld(); + if(obj->isActiveObject()) + map->AddToActive(obj); + ++count; } } diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 9b739c72c..36c209a00 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -932,6 +932,13 @@ void ObjectMgr::LoadCreatures() data.curhealth = cInfo->minhealth; } + if(cInfo->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND) + { + MapEntry const* map = sMapStore.LookupEntry(data.mapid); + if(!map || !map->IsDungeon()) + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`flags_extra` including CREATURE_FLAG_EXTRA_INSTANCE_BIND but creature are not in instance.",guid,data.id); + } + if(data.curmana < cInfo->minmana) { sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`minmana`=%u.",guid,data.id,data.curmana, cInfo->minmana ); @@ -1470,7 +1477,7 @@ void ObjectMgr::LoadItemPrototypes() bool req = proto->InventoryType!=INVTYPE_NON_EQUIP || proto->PageText; if(!req) { - for (int j = 0; j < 5; ++j) + for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j) { if(proto->Spells[j].SpellId) { @@ -1535,7 +1542,13 @@ void ObjectMgr::LoadItemPrototypes() const_cast(proto)->Stackable = 255; } - for (int j = 0; j < 10; j++) + if(proto->StatsCount > MAX_ITEM_PROTO_STATS) + { + sLog.outErrorDb("Item (Entry: %u) has too large value in statscount (%u), replace by hardcoded limit (%u).",i,proto->StatsCount,MAX_ITEM_PROTO_STATS); + const_cast(proto)->StatsCount = MAX_ITEM_PROTO_STATS; + } + + for (int j = 0; j < MAX_ITEM_PROTO_STATS; ++j) { // for ItemStatValue != 0 if(proto->ItemStat[j].ItemStatValue && proto->ItemStat[j].ItemStatType >= MAX_ITEM_MOD) @@ -1545,7 +1558,7 @@ void ObjectMgr::LoadItemPrototypes() } } - for (int j = 0; j < 2; j++) + for (int j = 0; j < MAX_ITEM_PROTO_DAMAGES; ++j) { if(proto->Damage[j].DamageType >= MAX_SPELL_SCHOOL) { @@ -1602,7 +1615,7 @@ void ObjectMgr::LoadItemPrototypes() } // spell_3*,spell_4*,spell_5* is empty - for (int j = 2; j < 5; j++) + for (int j = 2; j < MAX_ITEM_PROTO_SPELLS; ++j) { if(proto->Spells[j].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE) { @@ -1620,7 +1633,7 @@ void ObjectMgr::LoadItemPrototypes() // normal spell list else { - for (int j = 0; j < 5; j++) + for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j) { if(proto->Spells[j].SpellTrigger >= MAX_ITEM_SPELLTRIGGER || proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID) { @@ -1689,7 +1702,7 @@ void ObjectMgr::LoadItemPrototypes() if(proto->TotemCategory && !sTotemCategoryStore.LookupEntry(proto->TotemCategory)) sLog.outErrorDb("Item (Entry: %u) has wrong TotemCategory (%u)",i,proto->TotemCategory); - for (int j = 0; j < 3; j++) + for (int j = 0; j < MAX_ITEM_PROTO_SOCKETS; j++) { if(proto->Socket[j].Color && (proto->Socket[j].Color & SOCKET_COLOR_ALL) != proto->Socket[j].Color) { diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 6a7d0d811..befd71495 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -366,6 +366,7 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this) m_DetectInvTimer = 1000; m_bgBattleGroundID = 0; + m_bgTypeID = BATTLEGROUND_TYPE_NONE; for (int j=0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; j++) { m_bgBattleGroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE; @@ -3857,12 +3858,12 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) SetPower(POWER_ENERGY, uint32(GetMaxPower(POWER_ENERGY)*restore_percent)); } + // trigger update zone for alive state zone updates + UpdateZone(GetZoneId()); + // update visibility ObjectAccessor::UpdateVisibilityForPlayer(this); - // some items limited to specific map - DestroyZoneLimitedItem( true, GetZoneId()); - if(!applySickness) return; @@ -4231,7 +4232,7 @@ void Player::RepopAtGraveyard() WorldSafeLocsEntry const *ClosestGrave = NULL; // Special handle for battleground maps - BattleGround *bg = sBattleGroundMgr.GetBattleGround(GetBattleGroundId()); + BattleGround *bg = sBattleGroundMgr.GetBattleGround(GetBattleGroundId(), m_bgTypeID); if(bg && (bg->GetTypeID() == BATTLEGROUND_AB || bg->GetTypeID() == BATTLEGROUND_EY)) ClosestGrave = bg->GetClosestGraveYard(GetPositionX(), GetPositionY(), GetPositionZ(), GetTeam()); @@ -6004,7 +6005,7 @@ void Player::RewardReputation(Quest const *pQuest) { if(pQuest->RewRepFaction[i] && pQuest->RewRepValue[i] ) { - int32 rep = CalculateReputationGain(pQuest->GetQuestLevel(),pQuest->RewRepValue[i],true); + int32 rep = CalculateReputationGain(GetQuestLevel(pQuest),pQuest->RewRepValue[i],true); FactionEntry const* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i]); if(factionEntry) ModifyFactionReputation(factionEntry, rep); @@ -6566,7 +6567,7 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl if(slot >= INVENTORY_SLOT_BAG_END || !proto) return; - for (int i = 0; i < 10; i++) + for (int i = 0; i < MAX_ITEM_PROTO_STATS; ++i) { uint32 statType = 0; int32 val = 0; @@ -6899,7 +6900,7 @@ void Player::ApplyItemEquipSpell(Item *item, bool apply, bool form_change) if(!proto) return; - for (int i = 0; i < 5; i++) + for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { _Spell const& spellData = proto->Spells[i]; @@ -7012,7 +7013,7 @@ void Player::CastItemCombatSpell(Item *item,Unit* Target, WeaponAttackType attTy if (!Target || Target == this ) return; - for (int i = 0; i < 5; i++) + for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { _Spell const& spellData = proto->Spells[i]; @@ -7110,7 +7111,7 @@ void Player::CastItemUseSpell(Item *item,SpellCastTargets const& targets,uint8 c int count = 0; // item spells casted at use - for(int i = 0; i < 5; ++i) + for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { _Spell const& spellData = proto->Spells[i]; @@ -12621,6 +12622,19 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver ) if(questGiver && pQuest->GetQuestStartScript()!=0) sWorld.ScriptsStart(sQuestStartScripts, pQuest->GetQuestStartScript(), questGiver, this); + // Some spells applied at quest activation + SpellAreaForQuestMapBounds saBounds = spellmgr.GetSpellAreaForQuestMapBounds(quest_id,true); + if(saBounds.first != saBounds.second) + { + uint32 zone = GetZoneId(); + uint32 area = GetAreaId(); + + for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) + if(itr->second->autocast && itr->second->IsFitToRequirements(this,zone,area)) + if( !HasAura(itr->second->spellId,0) ) + CastSpell(this,itr->second->spellId,true); + } + UpdateForQuestsGO(); } @@ -12811,6 +12825,34 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST); + + uint32 zone = 0; + uint32 area = 0; + + // remove auras from spells with quest reward state limitations + SpellAreaForQuestMapBounds saEndBounds = spellmgr.GetSpellAreaForQuestEndMapBounds(quest_id); + if(saEndBounds.first != saEndBounds.second) + { + uint32 zone = GetZoneId(); + uint32 area = GetAreaId(); + + for(SpellAreaForAreaMap::const_iterator itr = saEndBounds.first; itr != saEndBounds.second; ++itr) + if(!itr->second->IsFitToRequirements(this,zone,area)) + RemoveAurasDueToSpell(itr->second->spellId); + } + + // Some spells applied at quest reward + SpellAreaForQuestMapBounds saBounds = spellmgr.GetSpellAreaForQuestMapBounds(quest_id,false); + if(saBounds.first != saBounds.second) + { + if(!zone) zone = GetZoneId(); + if(!area) area = GetAreaId(); + + for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) + if(itr->second->autocast && itr->second->IsFitToRequirements(this,zone,area)) + if( !HasAura(itr->second->spellId,0) ) + CastSpell(this,itr->second->spellId,true); + } } void Player::FailQuest( uint32 quest_id ) @@ -14179,14 +14221,14 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) if(!mapEntry || mapEntry->Instanceable() || !MapManager::IsValidMapCoord(m_bgEntryPoint)) SetBattleGroundEntryPoint(m_homebindMapId,m_homebindX,m_homebindY,m_homebindZ,0.0f); - BattleGround *currentBg = sBattleGroundMgr.GetBattleGround(bgid); + BattleGround *currentBg = sBattleGroundMgr.GetBattleGround(bgid, BATTLEGROUND_TYPE_NONE); if(currentBg && currentBg->IsPlayerInBattleGround(GetGUID())) { BattleGroundQueueTypeId bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(currentBg->GetTypeID(), currentBg->GetArenaType()); uint32 queueSlot = AddBattleGroundQueueId(bgQueueTypeId); - SetBattleGroundId(currentBg->GetInstanceID()); + SetBattleGroundId(currentBg->GetInstanceID(), currentBg->GetTypeID()); SetBGTeam(bgteam); //join player to battleground group @@ -15560,8 +15602,7 @@ void Player::SaveToDB() uint32 tmp_displayid = GetDisplayId(); // Set player sit state to standing on save, also stealth and shifted form - SetStandState(UNIT_STAND_STATE_STAND); // stand state - RemoveStandFlags(UNIT_STAND_FLAGS_ALL); // stand flags? + SetByteValue(UNIT_FIELD_BYTES_1, 0, UNIT_STAND_STATE_STAND); SetByteValue(UNIT_FIELD_BYTES_2, 3, 0); // shapeshift RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); SetDisplayId(GetNativeDisplayId()); @@ -18169,7 +18210,7 @@ void Player::SendInstanceResetWarning(uint32 mapid, uint32 time) void Player::ApplyEquipCooldown( Item * pItem ) { - for(int i = 0; i <5; ++i) + for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { _Spell const& spellData = pItem->GetProto()->Spells[i]; @@ -18419,7 +18460,7 @@ BattleGround* Player::GetBattleGround() const if(GetBattleGroundId()==0) return NULL; - return sBattleGroundMgr.GetBattleGround(GetBattleGroundId()); + return sBattleGroundMgr.GetBattleGround(GetBattleGroundId(), m_bgTypeID); } bool Player::InArena() const @@ -18444,34 +18485,20 @@ bool Player::GetBGAccessByLevel(BattleGroundTypeId bgTypeId) const return true; } -uint32 Player::GetMinLevelForBattleGroundQueueId(uint32 queue_id, BattleGroundTypeId bgTypeId) +BGQueueIdBasedOnLevel Player::GetBattleGroundQueueIdFromLevel(BattleGroundTypeId bgTypeId) const { - BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - assert(bg); - return (queue_id*10)+bg->GetMinLevel(); -} + //returned to hardcoded version of this function, because there is no way to code it dynamic + uint32 level = getLevel(); + if( bgTypeId == BATTLEGROUND_AV ) + level--; -uint32 Player::GetMaxLevelForBattleGroundQueueId(uint32 queue_id, BattleGroundTypeId bgTypeId) -{ - return GetMinLevelForBattleGroundQueueId(queue_id, bgTypeId)+10; -} - -uint32 Player::GetBattleGroundQueueIdFromLevel(BattleGroundTypeId bgTypeId) const -{ - BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - assert(bg); - if(getLevel()GetMinLevel()) + uint32 queue_id = (level / 10) - 1; // for ranges 0 - 19, 20 - 29, 30 - 39, 40 - 49, 50 - 59, 60 - 69, 70 -79, 80 + if( queue_id >= MAX_BATTLEGROUND_QUEUES ) { - sLog.outError("getting queue_id for player who doesn't meet the requirements - this shouldn't happen"); - return 0; + sLog.outError("BattleGround: too high queue_id %u this shouldn't happen", queue_id); + return QUEUE_ID_MAX_LEVEL_80; } - uint32 queue_id = (getLevel() - bg->GetMinLevel()) / 10; - if(queue_id>MAX_BATTLEGROUND_QUEUES) - { - sLog.outError("to high queue_id %u this shouldn't happen",queue_id); - return 0; - } - return queue_id; + return BGQueueIdBasedOnLevel(queue_id); } float Player::GetReputationPriceDiscount( Creature const* pCreature ) const @@ -18966,26 +18993,12 @@ void Player::UpdateZoneDependentAuras( uint32 newZone ) RemoveSpellsCausingAura(SPELL_AURA_FLY); } - // Some spells applied at enter into zone (with subzones) - switch(newZone) - { - case 2367: // Old Hillsbrad Foothills - { - // Human Illusion - // NOTE: these are removed by RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP); - uint32 spellid = 0; - // all horde races - if( GetTeam() == HORDE ) - spellid = getGender() == GENDER_FEMALE ? 35481 : 35480; - // and some alliance races - else if( getRace() == RACE_NIGHTELF || getRace() == RACE_DRAENEI ) - spellid = getGender() == GENDER_FEMALE ? 35483 : 35482; - - if(spellid && !HasAura(spellid,0) ) - CastSpell(this,spellid,true); - break; - } - } + // Some spells applied at enter into zone (with subzones), aura removed in UpdateAreaDependentAuras that called always at zone->area update + SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAreaMapBounds(newZone); + for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) + if(itr->second->autocast && itr->second->IsFitToRequirements(this,newZone,0)) + if( !HasAura(itr->second->spellId,0) ) + CastSpell(this,itr->second->spellId,true); } void Player::UpdateAreaDependentAuras( uint32 newArea ) @@ -18994,42 +19007,18 @@ void Player::UpdateAreaDependentAuras( uint32 newArea ) for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();) { // use m_zoneUpdateId for speed: UpdateArea called from UpdateZone or instead UpdateZone in both cases m_zoneUpdateId up-to-date - if(GetSpellAllowedInLocationError(iter->second->GetSpellProto(),GetMapId(),m_zoneUpdateId,newArea,GetBattleGroundId())!=0) + if(spellmgr.GetSpellAllowedInLocationError(iter->second->GetSpellProto(),GetMapId(),m_zoneUpdateId,newArea,this)!=0) RemoveAura(iter); else ++iter; } // some auras applied at subzone enter - switch(newArea) - { - // Dragonmaw Illusion - case 3759: // Netherwing Ledge - case 3939: // Dragonmaw Fortress - case 3966: // Dragonmaw Base Camp - if( GetDummyAura(40214) ) - { - if( !HasAura(40216,0) ) - CastSpell(this,40216,true); - if( !HasAura(42016,0) ) - CastSpell(this,42016,true); - } - break; - // Dominion Over Acherus - case 4281: // Acherus: The Ebon Hold - case 4342: // Acherus: The Ebon Hold - if( HasSpell(51721) ) - if( !HasAura(51721,0) ) - CastSpell(this,51721,true); - break; - // Mist of the Kvaldir - case 4028: //Riplash Strand - case 4029: //Riplash Ruins - case 4106: //Garrosh's Landing - case 4031: //Pal'ea - CastSpell(this,54119,true); - break; - } + SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAreaMapBounds(newArea); + for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) + if(itr->second->autocast && itr->second->IsFitToRequirements(this,m_zoneUpdateId,newArea)) + if( !HasAura(itr->second->spellId,0) ) + CastSpell(this,itr->second->spellId,true); } uint32 Player::GetCorpseReclaimDelay(bool pvp) const diff --git a/src/game/Player.h b/src/game/Player.h index 9e102436a..2176150f6 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1199,6 +1199,8 @@ class MANGOS_DLL_SPEC Player : public Unit /*** QUEST SYSTEM ***/ /*********************************************************/ + uint32 GetQuestLevel( Quest const* pQuest ) const { return pQuest && pQuest->GetQuestLevel() ? pQuest->GetQuestLevel() : getLevel(); } + void PrepareQuestMenu( uint64 guid ); void SendPreparedQuest( uint64 guid ); bool IsActiveQuest( uint32 quest_id ) const; @@ -1865,14 +1867,14 @@ class MANGOS_DLL_SPEC Player : public Unit /*** BATTLEGROUND SYSTEM ***/ /*********************************************************/ - bool InBattleGround() const { return m_bgBattleGroundID != 0; } - uint32 GetBattleGroundId() const { return m_bgBattleGroundID; } + bool InBattleGround() const { return m_bgBattleGroundID != 0; } + bool InArena() const; + uint32 GetBattleGroundId() const { return m_bgBattleGroundID; } + BattleGroundTypeId GetBattleGroundTypeId() const { return m_bgTypeID; } BattleGround* GetBattleGround() const; - bool InArena() const; - static uint32 GetMinLevelForBattleGroundQueueId(uint32 queue_id, BattleGroundTypeId bgTypeId); - static uint32 GetMaxLevelForBattleGroundQueueId(uint32 queue_id, BattleGroundTypeId bgTypeId); - uint32 GetBattleGroundQueueIdFromLevel(BattleGroundTypeId bgTypeId) const; + + BGQueueIdBasedOnLevel GetBattleGroundQueueIdFromLevel(BattleGroundTypeId bgTypeId) const; bool InBattleGroundQueue() const { @@ -1902,7 +1904,11 @@ class MANGOS_DLL_SPEC Player : public Unit return GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES; } - void SetBattleGroundId(uint32 val) { m_bgBattleGroundID = val; } + void SetBattleGroundId(uint32 val, BattleGroundTypeId bgTypeId) + { + m_bgBattleGroundID = val; + m_bgTypeID = bgTypeId; + } uint32 AddBattleGroundQueueId(BattleGroundQueueTypeId val) { for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) @@ -2142,6 +2148,7 @@ class MANGOS_DLL_SPEC Player : public Unit bool HasTitle(CharTitlesEntry const* title) { return HasTitle(title->bit_index); } void SetTitle(CharTitlesEntry const* title); + bool isActiveObject() const { return true; } protected: /*********************************************************/ @@ -2150,6 +2157,7 @@ class MANGOS_DLL_SPEC Player : public Unit /* this variable is set to bg->m_InstanceID, when player is teleported to BG - (it is battleground's GUID)*/ uint32 m_bgBattleGroundID; + BattleGroundTypeId m_bgTypeID; /* this is an array of BG queues (BgTypeIDs) in which is player */ diff --git a/src/game/QuestHandler.cpp b/src/game/QuestHandler.cpp index 72b966e6b..28787184a 100644 --- a/src/game/QuestHandler.cpp +++ b/src/game/QuestHandler.cpp @@ -570,7 +570,7 @@ uint32 WorldSession::getDialogStatus(Player *pPlayer, Object* questgiver, uint32 { if ( pQuest->IsAutoComplete() || (pQuest->IsRepeatable() && pPlayer->getQuestStatusMap()[quest_id].m_rewarded)) result2 = DIALOG_STATUS_REWARD_REP; - else if (pPlayer->getLevel() <= pQuest->GetQuestLevel() + sWorld.getConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF) ) + else if (pPlayer->getLevel() <= pPlayer->GetQuestLevel(pQuest) + sWorld.getConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF) ) { if (pQuest->HasFlag(QUEST_FLAGS_DAILY)) result2 = DIALOG_STATUS_AVAILABLE_REP; diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 5c4d2dd7e..b0d6d9844 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -2218,6 +2218,7 @@ enum BanReturn // indexes of BattlemasterList.dbc enum BattleGroundTypeId { + BATTLEGROUND_TYPE_NONE = 0, BATTLEGROUND_AV = 1, BATTLEGROUND_WS = 2, BATTLEGROUND_AB = 3, diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index f40001b54..60036ab61 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -321,7 +321,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi if((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0 && m_caster->GetTypeId()==TYPEID_PLAYER) { if(Item* pItem = ((Player*)m_caster)->GetWeaponForAttack(RANGED_ATTACK)) - m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage->DamageType); + m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage[0].DamageType); } } // Set health leech amount to zero @@ -2542,7 +2542,7 @@ void Spell::SendSpellCooldown() ItemPrototype const* proto = m_CastItem->GetProto(); if(proto) { - for(int idx = 0; idx < 5; ++idx) + for(int idx = 0; idx < MAX_ITEM_PROTO_SPELLS; ++idx) { if(proto->Spells[idx].SpellId == m_spellInfo->Id) { @@ -3324,7 +3324,7 @@ void Spell::TakeCastItem() bool expendable = false; bool withoutCharges = false; - for (int i = 0; i<5; i++) + for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { if (proto->Spells[i].SpellId) { @@ -3824,8 +3824,8 @@ uint8 Spell::CanCast(bool strict) return SPELL_FAILED_NOT_IN_ARENA; // zone check - if (uint8 res= GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),m_caster->GetZoneId(),m_caster->GetAreaId(), - m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster)->GetBattleGroundId() : 0)) + if (uint8 res= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),m_caster->GetZoneId(),m_caster->GetAreaId(), + m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster) : NULL)) return res; // not let players cast spells at mount (and let do it to creatures) @@ -4998,7 +4998,7 @@ uint8 Spell::CheckItems() ItemPrototype const *proto = m_CastItem->GetProto(); if(!proto) return SPELL_FAILED_ITEM_NOT_READY; - for(int s=0;s<5;s++) + for(int s=0; s < MAX_ITEM_PROTO_SPELLS; ++s) { // CastItem will be used up and does not count as reagent int32 charges = m_CastItem->GetSpellCharges(s); diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 40c3ddd46..fcd96ac5c 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -2067,6 +2067,22 @@ void Aura::HandleAuraDummy(bool apply, bool Real) m_modifier.m_amount = caster->SpellHealingBonus(m_target, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE); return; } + + // some auras applied at aura apply + if(GetEffIndex()==0 && m_target->GetTypeId()==TYPEID_PLAYER) + { + SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId()); + if(saBounds.first != saBounds.second) + { + uint32 zone = m_target->GetZoneId(); + uint32 area = m_target->GetAreaId(); + + for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) + if(itr->second->autocast && itr->second->IsFitToRequirements((Player*)m_target,zone,area)) + if( !m_target->HasAura(itr->second->spellId,0) ) + m_target->CastSpell(m_target,itr->second->spellId,true); + } + } } // AT REMOVE else @@ -2156,6 +2172,21 @@ void Aura::HandleAuraDummy(bool apply, bool Real) } } + + // some auras remove at aura remove + if(GetEffIndex()==0 && m_target->GetTypeId()==TYPEID_PLAYER) + { + SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId()); + if(saBounds.first != saBounds.second) + { + uint32 zone = m_target->GetZoneId(); + uint32 area = m_target->GetAreaId(); + + for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) + if(!itr->second->IsFitToRequirements((Player*)m_target,zone,area)) + m_target->RemoveAurasDueToSpell(itr->second->spellId); + } + } } // AT APPLY & REMOVE diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp index 70227980e..986c39908 100644 --- a/src/game/SpellHandler.cpp +++ b/src/game/SpellHandler.cpp @@ -94,7 +94,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) if (pUser->isInCombat()) { - for(int i = 0; i < 5; ++i) + for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId)) { diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index fcaf501fa..89e88600e 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -2348,7 +2348,193 @@ bool SpellMgr::IsSpellValid(SpellEntry const* spellInfo, Player* pl, bool msg) return true; } -uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,uint32 zone_id,uint32 area_id, uint32 bgInstanceId) +void SpellMgr::LoadSpellAreas() +{ + mSpellAreaMap.clear(); // need for reload case + mSpellAreaForQuestMap.clear(); + mSpellAreaForActiveQuestMap.clear(); + mSpellAreaForQuestEndMap.clear(); + mSpellAreaForAuraMap.clear(); + + uint32 count = 0; + + // 0 1 2 3 4 5 6 7 8 + QueryResult *result = WorldDatabase.Query("SELECT spell, area, quest_start, quest_start_active, quest_end, aura_spell, racemask, gender, autocast FROM spell_area"); + + if( !result ) + { + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u spell area requirements", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + Field *fields = result->Fetch(); + + bar.step(); + + uint32 spell = fields[0].GetUInt32(); + SpellArea spellArea; + spellArea.spellId = spell; + spellArea.areaId = fields[1].GetUInt32(); + spellArea.questStart = fields[2].GetUInt32(); + spellArea.questStartCanActive = fields[3].GetBool(); + spellArea.questEnd = fields[4].GetUInt32(); + spellArea.auraSpell = fields[5].GetUInt32(); + spellArea.raceMask = fields[6].GetUInt32(); + spellArea.gender = Gender(fields[7].GetUInt8()); + spellArea.autocast = fields[8].GetBool(); + + if(!sSpellStore.LookupEntry(spell)) + { + sLog.outErrorDb("Spell %u listed in `spell_area` does not exist", spell); + continue; + } + + if(mSpellAreaForAuraMap.find(spellArea.spellId)!=mSpellAreaForAuraMap.end()) + { + sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that already listed in table itself", spell,spellArea.auraSpell); + continue; + } + + if(spellArea.areaId && !GetAreaEntryByAreaID(spellArea.areaId)) + { + sLog.outErrorDb("Spell %u listed in `spell_area` have wrong area (%u) requirement", spell,spellArea.areaId); + continue; + } + + if(spellArea.questStart && !objmgr.GetQuestTemplate(spellArea.questStart)) + { + sLog.outErrorDb("Spell %u listed in `spell_area` have wrong start quest (%u) requirement", spell,spellArea.questStart); + continue; + } + + if(spellArea.questEnd) + { + if(!objmgr.GetQuestTemplate(spellArea.questEnd)) + { + sLog.outErrorDb("Spell %u listed in `spell_area` have wrong end quest (%u) requirement", spell,spellArea.questEnd); + continue; + } + + if(spellArea.questEnd==spellArea.questStart && !spellArea.questStartCanActive) + { + sLog.outErrorDb("Spell %u listed in `spell_area` have quest (%u) requirement for start and end in same time", spell,spellArea.questEnd); + continue; + } + } + + if(spellArea.auraSpell) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellArea.auraSpell); + if(!spellInfo) + { + sLog.outErrorDb("Spell %u listed in `spell_area` have wrong aura spell (%u) requirement", spell,spellArea.auraSpell); + continue; + } + + if(spellInfo->EffectApplyAuraName[0]!=SPELL_AURA_DUMMY) + { + sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell requirement (%u) without dummy aura in effect 0", spell,spellArea.auraSpell); + continue; + } + + if(spellArea.auraSpell==spellArea.spellId) + { + sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement for itself", spell,spellArea.auraSpell); + continue; + } + + // not allow autocast chains by auraSpell field + if(spellArea.autocast) + { + bool chain = false; + SpellAreaForAuraMapBounds saBound = GetSpellAreaForAuraMapBounds(spellArea.spellId); + for(SpellAreaForAuraMap::const_iterator itr = saBound.first; itr != saBound.second; ++itr) + { + if(itr->second->autocast) + { + chain = true; + break; + } + } + + if(chain) + { + sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell,spellArea.auraSpell); + continue; + } + + SpellAreaMapBounds saBound2 = GetSpellAreaMapBounds(spellArea.auraSpell); + for(SpellAreaMap::const_iterator itr2 = saBound2.first; itr2 != saBound2.second; ++itr2) + { + if(itr2->second.autocast && itr2->second.auraSpell) + { + chain = true; + break; + } + } + + if(chain) + { + sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell,spellArea.auraSpell); + continue; + } + } + } + + if(spellArea.raceMask && (spellArea.raceMask & RACEMASK_ALL_PLAYABLE)==0) + { + sLog.outErrorDb("Spell %u listed in `spell_area` have wrong race mask (%u) requirement", spell,spellArea.raceMask); + continue; + } + + if(spellArea.gender!=GENDER_NONE && spellArea.gender!=GENDER_FEMALE && spellArea.gender!=GENDER_MALE) + { + sLog.outErrorDb("Spell %u listed in `spell_area` have wrong gender (%u) requirement", spell,spellArea.gender); + continue; + } + + SpellArea const* sa = &mSpellAreaMap.insert(SpellAreaMap::value_type(spell,spellArea))->second; + + // for search by current zone/subzone at zone/subzone change + if(spellArea.areaId) + mSpellAreaForAreaMap.insert(SpellAreaForAreaMap::value_type(spellArea.areaId,sa)); + + // for search at quest start/reward + if(spellArea.questStart) + { + if(spellArea.questStartCanActive) + mSpellAreaForActiveQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart,sa)); + else + mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart,sa)); + } + + // for search at quest start/reward + if(spellArea.questEnd) + mSpellAreaForQuestEndMap.insert(SpellAreaForQuestMap::value_type(spellArea.questEnd,sa)); + + // for search at aura apply + if(spellArea.auraSpell) + mSpellAreaForAuraMap.insert(SpellAreaForAuraMap::value_type(spellArea.auraSpell,sa)); + + ++count; + } while( result->NextRow() ); + + delete result; + + sLog.outString(); + sLog.outString( ">> Loaded %u spell area requirements", count ); +} + +uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player) { // normal case if( spellInfo->AreaGroupId > 0) @@ -2367,75 +2553,26 @@ uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,u return SPELL_FAILED_INCORRECT_AREA; } - // elixirs (all area dependent elixirs have family SPELLFAMILY_POTION, use this for speedup) - if(spellInfo->SpellFamilyName==SPELLFAMILY_POTION) + // DB base check (if non empty then must fit at least single for allow) + SpellAreaMapBounds saBounds = spellmgr.GetSpellAreaMapBounds(spellInfo->Id); + if(saBounds.first != saBounds.second) { - if(uint32 mask = spellmgr.GetSpellElixirMask(spellInfo->Id)) + for(SpellAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) { - if(mask & ELIXIR_BATTLE_MASK) - { - if(spellInfo->Id==45373) // Bloodberry Elixir - return zone_id==4075 ? 0 : SPELL_FAILED_REQUIRES_AREA; - } - if(mask & ELIXIR_UNSTABLE_MASK) - { - // in the Blade's Edge Mountains Plateaus and Gruul's Lair. - return zone_id ==3522 || map_id==565 ? 0 : SPELL_FAILED_INCORRECT_AREA; - } - if(mask & ELIXIR_SHATTRATH_MASK) - { - // in Tempest Keep, Serpentshrine Cavern, Caverns of Time: Mount Hyjal, Black Temple, Sunwell Plateau - if(zone_id ==3607 || map_id==534 || map_id==564 || zone_id==4075) - return 0; - - MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); - if(!mapEntry) - return SPELL_FAILED_INCORRECT_AREA; - - return mapEntry->multimap_id==206 ? 0 : SPELL_FAILED_INCORRECT_AREA; - } - - // elixirs not have another limitations - return 0; + if(itr->second.IsFitToRequirements(player,zone_id,area_id)) + return 0; } + return SPELL_FAILED_INCORRECT_AREA; } - // special cases zone check (maps checked by multimap common id) + // bg spell checks switch(spellInfo->Id) { - case 41618: // Bottled Nethergon Energy - case 41620: // Bottled Nethergon Vapor - { - MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); - if(!mapEntry) - return SPELL_FAILED_INCORRECT_AREA; - - return mapEntry->multimap_id==206 ? 0 : SPELL_FAILED_REQUIRES_AREA; - } - case 41617: // Cenarion Mana Salve - case 41619: // Cenarion Healing Salve - { - MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); - if(!mapEntry) - return SPELL_FAILED_INCORRECT_AREA; - - return mapEntry->multimap_id==207 ? 0 : SPELL_FAILED_REQUIRES_AREA; - } - case 40216: // Dragonmaw Illusion - case 42016: // Dragonmaw Illusion - return area_id == 3759 || area_id == 3966 || area_id == 3939 ? 0 : SPELL_FAILED_INCORRECT_AREA; - case 51721: // Dominion Over Acherus - case 54055: // Dominion Over Acherus - return area_id == 4281 || area_id == 4342 ? 0 : SPELL_FAILED_INCORRECT_AREA; - case 51852: // The Eye of Acherus - return map_id == 609 ? 0 : SPELL_FAILED_REQUIRES_AREA; - case 54119: // Mist of the Kvaldir - return area_id == 4028 || area_id == 4029 || area_id == 4106 || area_id == 4031 ? 0 : SPELL_FAILED_INCORRECT_AREA; case 23333: // Warsong Flag case 23335: // Silverwing Flag - return map_id == 489 && bgInstanceId ? 0 : SPELL_FAILED_REQUIRES_AREA; + return map_id == 489 && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA; case 34976: // Netherstorm Flag - return map_id == 566 && bgInstanceId ? 0 : SPELL_FAILED_REQUIRES_AREA; + return map_id == 566 && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA; case 2584: // Waiting to Resurrect case 22011: // Spirit Heal Channel case 22012: // Spirit Heal @@ -2448,11 +2585,11 @@ uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,u if(!mapEntry) return SPELL_FAILED_INCORRECT_AREA; - return mapEntry->IsBattleGround() && bgInstanceId ? 0 : SPELL_FAILED_REQUIRES_AREA; + return mapEntry->IsBattleGround() && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA; } case 44521: // Preparation { - if(!bgInstanceId) + if(!player) return SPELL_FAILED_REQUIRES_AREA; MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); @@ -2462,7 +2599,7 @@ uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,u if(!mapEntry->IsBattleGround()) return SPELL_FAILED_REQUIRES_AREA; - BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgInstanceId); + BattleGround* bg = player->GetBattleGround(); return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? 0 : SPELL_FAILED_REQUIRES_AREA; } case 32724: // Gold Team (Alliance) @@ -2474,11 +2611,11 @@ uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,u if(!mapEntry) return SPELL_FAILED_INCORRECT_AREA; - return mapEntry->IsBattleArena() && bgInstanceId ? 0 : SPELL_FAILED_REQUIRES_AREA; + return mapEntry->IsBattleArena() && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA; } case 32727: // Arena Preparation { - if(!bgInstanceId) + if(!player) return SPELL_FAILED_REQUIRES_AREA; MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); @@ -2488,7 +2625,7 @@ uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,u if(!mapEntry->IsBattleArena()) return SPELL_FAILED_REQUIRES_AREA; - BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgInstanceId); + BattleGround* bg = player->GetBattleGround(); return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? 0 : SPELL_FAILED_REQUIRES_AREA; } } @@ -2632,3 +2769,50 @@ DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group) return DRTYPE_NONE; } + +bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 newArea) const +{ + if(gender!=GENDER_NONE) + { + // not in expected gender + if(!player || gender != player->getGender()) + return false; + } + + if(raceMask) + { + // not in expected race + if(!player || !(raceMask & player->getRaceMask())) + return false; + } + + if(areaId) + { + // not in expected zone + if(newZone!=areaId && newArea!=areaId) + return false; + } + + if(questStart) + { + // not in expected required quest state + if(!player || (!questStartCanActive || !player->IsActiveQuest(questStart)) && !player->GetQuestRewardStatus(questStart)) + return false; + } + + if(questEnd) + { + // not in expected forbidden quest state + if(!player || player->GetQuestRewardStatus(questEnd)) + return false; + } + + if(auraSpell) + { + // not have expected aura + if(!player || !player->HasAura(auraSpell,0)) + return false; + } + + return true; +} diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h index 9b318e954..157981d5c 100644 --- a/src/game/SpellMgr.h +++ b/src/game/SpellMgr.h @@ -338,14 +338,6 @@ inline bool IsPassiveSpellStackableWithRanks(SpellEntry const* spellProto) inline bool IsDeathPersistentSpell(SpellEntry const *spellInfo) { - switch(spellInfo->Id) - { - case 40214: // Dragonmaw Illusion - case 35480: case 35481: case 35482: // Human Illusion - case 35483: case 39824: // Human Illusion - return true; - } - return spellInfo->AttributesEx3 & SPELL_ATTR_EX3_DEATH_PERSISTENT; } @@ -363,8 +355,6 @@ bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellI bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId); -uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo,uint32 map_id,uint32 zone_id,uint32 area_id,uint32 bgInstanceId); - inline bool IsAreaEffectTarget( Targets target ) { switch (target ) @@ -687,6 +677,32 @@ class PetAura }; typedef std::map SpellPetAuraMap; +struct SpellArea +{ + uint32 spellId; + uint32 areaId; // zone/subzone/or 0 is not limited to zone + uint32 questStart; // quest start (quest must be active or rewarded for spell apply) + uint32 questEnd; // quest end (quest don't must be rewarded for spell apply) + uint32 auraSpell; // spell aura must be applied for spell apply + uint32 raceMask; // can be applied only to races + Gender gender; // can be applied only to gender + bool questStartCanActive; // if true then quest start can be active (not only rewarded) + bool autocast; // if true then auto applied at area enter, in other case just allowed to cast + + // helpers + bool IsFitToRequirements(Player const* player, uint32 newZone, uint32 newArea) const; +}; + +typedef std::multimap SpellAreaMap; +typedef std::multimap SpellAreaForQuestMap; +typedef std::multimap SpellAreaForAuraMap; +typedef std::multimap SpellAreaForAreaMap; +typedef std::pair SpellAreaMapBounds; +typedef std::pair SpellAreaForQuestMapBounds; +typedef std::pair SpellAreaForAuraMapBounds; +typedef std::pair SpellAreaForAreaMapBounds; + + // Spell rank chain (accessed using SpellMgr functions) struct SpellChainNode { @@ -973,6 +989,36 @@ class SpellMgr return NULL; } + uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL); + + SpellAreaMapBounds GetSpellAreaMapBounds(uint32 spell_id) const + { + return SpellAreaMapBounds(mSpellAreaMap.lower_bound(spell_id),mSpellAreaMap.upper_bound(spell_id)); + } + + SpellAreaForQuestMapBounds GetSpellAreaForQuestMapBounds(uint32 quest_id, bool active) const + { + if(active) + return SpellAreaForQuestMapBounds(mSpellAreaForActiveQuestMap.lower_bound(quest_id),mSpellAreaForActiveQuestMap.upper_bound(quest_id)); + else + return SpellAreaForQuestMapBounds(mSpellAreaForQuestMap.lower_bound(quest_id),mSpellAreaForQuestMap.upper_bound(quest_id)); + } + + SpellAreaForQuestMapBounds GetSpellAreaForQuestEndMapBounds(uint32 quest_id) const + { + return SpellAreaForQuestMapBounds(mSpellAreaForQuestEndMap.lower_bound(quest_id),mSpellAreaForQuestEndMap.upper_bound(quest_id)); + } + + SpellAreaForAuraMapBounds GetSpellAreaForAuraMapBounds(uint32 spell_id) const + { + return SpellAreaForAuraMapBounds(mSpellAreaForAuraMap.lower_bound(spell_id),mSpellAreaForAuraMap.upper_bound(spell_id)); + } + + SpellAreaForAreaMapBounds GetSpellAreaForAreaMapBounds(uint32 area_id) const + { + return SpellAreaForAreaMapBounds(mSpellAreaForAreaMap.lower_bound(area_id),mSpellAreaForAreaMap.upper_bound(area_id)); + } + // Modifiers public: static SpellMgr& Instance(); @@ -991,6 +1037,7 @@ class SpellMgr void LoadSkillLineAbilityMap(); void LoadSpellPetAuras(); void LoadPetLevelupSpellMap(); + void LoadSpellAreas(); private: SpellScriptTarget mSpellScriptTarget; @@ -1005,7 +1052,13 @@ class SpellMgr SpellBonusMap mSpellBonusMap; SkillLineAbilityMap mSkillLineAbilityMap; SpellPetAuraMap mSpellPetAuraMap; - PetLevelupSpellMap mPetLevelupSpellMap; + PetLevelupSpellMap mPetLevelupSpellMap; + SpellAreaMap mSpellAreaMap; + SpellAreaForQuestMap mSpellAreaForQuestMap; + SpellAreaForQuestMap mSpellAreaForActiveQuestMap; + SpellAreaForQuestMap mSpellAreaForQuestEndMap; + SpellAreaForAuraMap mSpellAreaForAuraMap; + SpellAreaForAreaMap mSpellAreaForAreaMap; }; #define spellmgr SpellMgr::Instance() diff --git a/src/game/Traveller.h b/src/game/Traveller.h index 3daa558da..6aa55eb14 100644 --- a/src/game/Traveller.h +++ b/src/game/Traveller.h @@ -50,11 +50,24 @@ struct MANGOS_DLL_DECL Traveller T& GetTraveller(void) { return i_traveller; } float Speed(void) { assert(false); return 0.0f; } + float GetMoveDestinationTo(float x, float y, float z); + uint32 GetTotalTrevelTimeTo(float x, float y, float z); + void Relocation(float x, float y, float z, float orientation) {} void Relocation(float x, float y, float z) { Relocation(x, y, z, i_traveller.GetOrientation()); } void MoveTo(float x, float y, float z, uint32 t) {} }; +template +inline uint32 Traveller::GetTotalTrevelTimeTo(float x, float y, float z) +{ + float dist = GetMoveDestinationTo(x,y,z); + double speed = Speed(); + + speed *= 0.001f; // speed is in seconds so convert from second to millisecond + return static_cast(dist/speed); +} + // specialization for creatures template<> inline float Traveller::Speed() @@ -73,6 +86,20 @@ inline void Traveller::Relocation(float x, float y, float z, float ori i_traveller.GetMap()->CreatureRelocation(&i_traveller, x, y, z, orientation); } +template<> +inline float Traveller::GetMoveDestinationTo(float x, float y, float z) +{ + float dx = x - GetPositionX(); + float dy = y - GetPositionY(); + float dz = z - GetPositionZ(); + + if(i_traveller.hasUnitState(UNIT_STAT_IN_FLIGHT)) + return sqrt((dx*dx) + (dy*dy) + (dz*dz)); + else //Walking on the ground + return sqrt((dx*dx) + (dy*dy)); +} + + template<> inline void Traveller::MoveTo(float x, float y, float z, uint32 t) { @@ -89,6 +116,19 @@ inline float Traveller::Speed() return i_traveller.GetSpeed(i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_WALK_MODE) ? MOVE_WALK : MOVE_RUN); } +template<> +inline float Traveller::GetMoveDestinationTo(float x, float y, float z) +{ + float dx = x - GetPositionX(); + float dy = y - GetPositionY(); + float dz = z - GetPositionZ(); + + if (i_traveller.isInFlight()) + return sqrt((dx*dx) + (dy*dy) + (dz*dz)); + else //Walking on the ground + return sqrt((dx*dx) + (dy*dy)); +} + template<> inline void Traveller::Relocation(float x, float y, float z, float orientation) { diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index aca4960ba..de2e3335e 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -43,6 +43,7 @@ #include "GridNotifiersImpl.h" #include "CellImpl.h" #include "Path.h" +#include "Traveller.h" #include @@ -232,31 +233,26 @@ void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player* player) { float x, y, z; if(GetMotionMaster()->GetDestination(x, y, z)) - SendMonsterMoveWithSpeed(x, y, z, GetUnitMovementFlags(), 0, player); + SendMonsterMoveWithSpeed(x, y, z, 0, player); } -void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 MovementFlags, uint32 transitTime, Player* player) +void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime, Player* player) { if (!transitTime) { - float dx = x - GetPositionX(); - float dy = y - GetPositionY(); - float dz = z - GetPositionZ(); - - float dist = ((dx*dx) + (dy*dy) + (dz*dz)); - if(dist<0) - dist = 0; + if(GetTypeId()==TYPEID_PLAYER) + { + Traveller traveller(*(Player*)this); + transitTime = traveller.GetTotalTrevelTimeTo(x,y,z); + } else - dist = sqrt(dist); - - double speed = GetSpeed((MovementFlags & MOVEMENTFLAG_WALK_MODE) ? MOVE_WALK : MOVE_RUN); - if(speed<=0) - speed = 2.5f; - speed *= 0.001f; - transitTime = static_cast(dist / speed + 0.5); + { + Traveller traveller(*(Creature*)this); + transitTime = traveller.GetTotalTrevelTimeTo(x,y,z); + } } //float orientation = (float)atan2((double)dy, (double)dx); - SendMonsterMove(x, y, z, 0, MovementFlags, transitTime, player); + SendMonsterMove(x, y, z, 0, GetUnitMovementFlags(), transitTime, player); } void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player) @@ -1722,7 +1718,6 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe Unit* caster = (*i)->GetCaster(); if (!caster) break; - int32 reflectDamage = 0; AuraList const& vOverRideCS = caster->GetAurasByType(SPELL_AURA_DUMMY); for(AuraList::const_iterator k = vOverRideCS.begin(); k != vOverRideCS.end(); ++k) { diff --git a/src/game/Unit.h b/src/game/Unit.h index 7ad9da6b6..362ead84b 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1068,7 +1068,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL); void SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end, uint32 MovementFlags); - void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 MovementFlags, uint32 transitTime = 0, Player* player = NULL); + void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0, Player* player = NULL); void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL); virtual void MoveOutOfRange(Player &) { }; diff --git a/src/game/WaypointMovementGenerator.h b/src/game/WaypointMovementGenerator.h index cc552d974..2ee893fb4 100644 --- a/src/game/WaypointMovementGenerator.h +++ b/src/game/WaypointMovementGenerator.h @@ -105,6 +105,10 @@ public PathMovementBase // statics static void Initialize(void); + + // allow use for overwrite empty implementation + bool GetDestination(float& x, float& y, float& z) const { return PathMovementBase::GetDestination(x,y,z); } + private: void ClearWaypoints(); @@ -138,5 +142,8 @@ public PathMovementBase bool HasArrived() const { return (i_currentNode >= i_path.Size()); } void SetCurrentNodeAfterTeleport(); void SkipCurrentNode() { ++i_currentNode; } + + // allow use for overwrite empty implementation + bool GetDestination(float& x, float& y, float& z) const { return PathMovementBase::GetDestination(x,y,z); } }; #endif diff --git a/src/game/World.cpp b/src/game/World.cpp index 3576a60a8..8b04917a7 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -615,20 +615,20 @@ void World::LoadConfigSettings(bool reload) else m_configs[CONFIG_REALM_ZONE] = sConfig.GetIntDefault("RealmZone", REALM_ZONE_DEVELOPMENT); - m_configs[CONFIG_ALLOW_TWO_SIDE_ACCOUNTS] = sConfig.GetBoolDefault("AllowTwoSide.Accounts", false); + m_configs[CONFIG_ALLOW_TWO_SIDE_ACCOUNTS] = sConfig.GetBoolDefault("AllowTwoSide.Accounts", false); m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Chat",false); m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Channel",false); m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Group",false); m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Guild",false); m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Auction",false); m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Mail",false); - m_configs[CONFIG_ALLOW_TWO_SIDE_WHO_LIST] = sConfig.GetBoolDefault("AllowTwoSide.WhoList", false); - m_configs[CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND] = sConfig.GetBoolDefault("AllowTwoSide.AddFriend", false); - m_configs[CONFIG_STRICT_PLAYER_NAMES] = sConfig.GetIntDefault("StrictPlayerNames", 0); - m_configs[CONFIG_STRICT_CHARTER_NAMES] = sConfig.GetIntDefault("StrictCharterNames", 0); - m_configs[CONFIG_STRICT_PET_NAMES] = sConfig.GetIntDefault("StrictPetNames", 0); + m_configs[CONFIG_ALLOW_TWO_SIDE_WHO_LIST] = sConfig.GetBoolDefault("AllowTwoSide.WhoList", false); + m_configs[CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND] = sConfig.GetBoolDefault("AllowTwoSide.AddFriend", false); + m_configs[CONFIG_STRICT_PLAYER_NAMES] = sConfig.GetIntDefault ("StrictPlayerNames", 0); + m_configs[CONFIG_STRICT_CHARTER_NAMES] = sConfig.GetIntDefault ("StrictCharterNames", 0); + m_configs[CONFIG_STRICT_PET_NAMES] = sConfig.GetIntDefault ("StrictPetNames", 0); - m_configs[CONFIG_CHARACTERS_CREATING_DISABLED] = sConfig.GetIntDefault("CharactersCreatingDisabled", 0); + m_configs[CONFIG_CHARACTERS_CREATING_DISABLED] = sConfig.GetIntDefault ("CharactersCreatingDisabled", 0); m_configs[CONFIG_CHARACTERS_PER_REALM] = sConfig.GetIntDefault("CharactersPerRealm", 10); if(m_configs[CONFIG_CHARACTERS_PER_REALM] < 1 || m_configs[CONFIG_CHARACTERS_PER_REALM] > 10) @@ -762,13 +762,6 @@ void World::LoadConfigSettings(bool reload) m_configs[CONFIG_INSTANCE_IGNORE_LEVEL] = sConfig.GetBoolDefault("Instance.IgnoreLevel", false); m_configs[CONFIG_INSTANCE_IGNORE_RAID] = sConfig.GetBoolDefault("Instance.IgnoreRaid", false); - m_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfig.GetBoolDefault("Battleground.CastDeserter", true); - m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.Enable", false); - m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.PlayerOnly", false); - m_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE] = sConfig.GetBoolDefault("Arena.QueueAnnouncer.Enable", false); - m_configs[CONFIG_ARENA_SEASON_ID] = sConfig.GetIntDefault ("Arena.ArenaSeason.ID", 1); - m_configs[CONFIG_ARENA_SEASON_IN_PROGRESS] = sConfig.GetBoolDefault("Arena.ArenaSeason.InProgress", true); - m_configs[CONFIG_CAST_UNSTUCK] = sConfig.GetBoolDefault("CastUnstuck", true); m_configs[CONFIG_INSTANCE_RESET_TIME_HOUR] = sConfig.GetIntDefault("Instance.ResetTimeHour", 4); m_configs[CONFIG_INSTANCE_UNLOAD_DELAY] = sConfig.GetIntDefault("Instance.UnloadDelay", 1800000); @@ -905,23 +898,23 @@ void World::LoadConfigSettings(bool reload) m_configs[CONFIG_DETECT_POS_COLLISION] = sConfig.GetBoolDefault("DetectPosCollision", true); - m_configs[CONFIG_RESTRICTED_LFG_CHANNEL] = sConfig.GetBoolDefault("Channel.RestrictedLfg", true); + m_configs[CONFIG_RESTRICTED_LFG_CHANNEL] = sConfig.GetBoolDefault("Channel.RestrictedLfg", true); m_configs[CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL] = sConfig.GetBoolDefault("Channel.SilentlyGMJoin", false); - m_configs[CONFIG_TALENTS_INSPECTING] = sConfig.GetBoolDefault("TalentsInspecting", true); + m_configs[CONFIG_TALENTS_INSPECTING] = sConfig.GetBoolDefault("TalentsInspecting", true); m_configs[CONFIG_CHAT_FAKE_MESSAGE_PREVENTING] = sConfig.GetBoolDefault("ChatFakeMessagePreventing", false); - m_configs[CONFIG_CORPSE_DECAY_NORMAL] = sConfig.GetIntDefault("Corpse.Decay.NORMAL", 60); - m_configs[CONFIG_CORPSE_DECAY_RARE] = sConfig.GetIntDefault("Corpse.Decay.RARE", 300); - m_configs[CONFIG_CORPSE_DECAY_ELITE] = sConfig.GetIntDefault("Corpse.Decay.ELITE", 300); + m_configs[CONFIG_CORPSE_DECAY_NORMAL] = sConfig.GetIntDefault("Corpse.Decay.NORMAL", 60); + m_configs[CONFIG_CORPSE_DECAY_RARE] = sConfig.GetIntDefault("Corpse.Decay.RARE", 300); + m_configs[CONFIG_CORPSE_DECAY_ELITE] = sConfig.GetIntDefault("Corpse.Decay.ELITE", 300); m_configs[CONFIG_CORPSE_DECAY_RAREELITE] = sConfig.GetIntDefault("Corpse.Decay.RAREELITE", 300); m_configs[CONFIG_CORPSE_DECAY_WORLDBOSS] = sConfig.GetIntDefault("Corpse.Decay.WORLDBOSS", 3600); - m_configs[CONFIG_DEATH_SICKNESS_LEVEL] = sConfig.GetIntDefault("Death.SicknessLevel", 11); + m_configs[CONFIG_DEATH_SICKNESS_LEVEL] = sConfig.GetIntDefault ("Death.SicknessLevel", 11); m_configs[CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP] = sConfig.GetBoolDefault("Death.CorpseReclaimDelay.PvP", true); m_configs[CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE] = sConfig.GetBoolDefault("Death.CorpseReclaimDelay.PvE", true); - m_configs[CONFIG_DEATH_BONES_WORLD] = sConfig.GetBoolDefault("Death.Bones.World", true); - m_configs[CONFIG_DEATH_BONES_BG_OR_ARENA] = sConfig.GetBoolDefault("Death.Bones.BattlegroundOrArena", true); + m_configs[CONFIG_DEATH_BONES_WORLD] = sConfig.GetBoolDefault("Death.Bones.World", true); + m_configs[CONFIG_DEATH_BONES_BG_OR_ARENA] = sConfig.GetBoolDefault("Death.Bones.BattlegroundOrArena", true); m_configs[CONFIG_THREAT_RADIUS] = sConfig.GetIntDefault("ThreatRadius", 100); @@ -933,12 +926,20 @@ void World::LoadConfigSettings(bool reload) m_configs[CONFIG_LISTEN_RANGE_TEXTEMOTE] = sConfig.GetIntDefault("ListenRange.TextEmote", 25); m_configs[CONFIG_LISTEN_RANGE_YELL] = sConfig.GetIntDefault("ListenRange.Yell", 300); - m_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfig.GetIntDefault("Arena.MaxRatingDifference", 0); - m_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfig.GetIntDefault("Arena.RatingDiscardTimer",300000); - m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfig.GetBoolDefault("Arena.AutoDistributePoints", false); - m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfig.GetIntDefault("Arena.AutoDistributeInterval", 7); + m_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfig.GetBoolDefault("Battleground.CastDeserter", true); + m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.Enable", false); + m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.PlayerOnly", false); + m_configs[CONFIG_BATTLEGROUND_INVITATION_TYPE] = sConfig.GetIntDefault ("Battleground.InvitationType", 0); + m_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfig.GetIntDefault ("BattleGround.PrematureFinishTimer", 5 * MINUTE * IN_MILISECONDS); + m_configs[CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH] = sConfig.GetIntDefault ("BattleGround.PremadeGroupWaitForMatch", 30 * MINUTE * IN_MILISECONDS); + m_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfig.GetIntDefault ("Arena.MaxRatingDifference", 100); + m_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfig.GetIntDefault ("Arena.RatingDiscardTimer", 10 * MINUTE * IN_MILISECONDS); + m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfig.GetBoolDefault("Arena.AutoDistributePoints", false); + m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfig.GetIntDefault ("Arena.AutoDistributeInterval", 7); + m_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE] = sConfig.GetBoolDefault("Arena.QueueAnnouncer.Enable", false); + m_configs[CONFIG_ARENA_SEASON_ID] = sConfig.GetIntDefault ("Arena.ArenaSeason.ID", 1); + m_configs[CONFIG_ARENA_SEASON_IN_PROGRESS] = sConfig.GetBoolDefault("Arena.ArenaSeason.InProgress", true); - m_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfig.GetIntDefault("BattleGround.PrematureFinishTimer", 0); m_configs[CONFIG_INSTANT_LOGOUT] = sConfig.GetIntDefault("InstantLogout", SEC_MODERATOR); m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1); @@ -1201,6 +1202,9 @@ void World::SetInitialWorldSettings() sLog.outString( ">>> Quests Relations loaded" ); sLog.outString(); + sLog.outString( "Loading SpellArea Data..." ); // must be after quest load + spellmgr.LoadSpellAreas(); + sLog.outString( "Loading AreaTrigger definitions..." ); objmgr.LoadAreaTriggerTeleports(); // must be after item template load @@ -1799,7 +1803,7 @@ void World::ScriptsProcess() sLog.outError("SCRIPT_COMMAND_MOVE_TO call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); break; } - ((Unit *)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, ((Unit *)source)->GetUnitMovementFlags(), step.script->datalong2 ); + ((Unit *)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, step.script->datalong2 ); ((Unit *)source)->GetMap()->CreatureRelocation(((Creature *)source), step.script->x, step.script->y, step.script->z, 0); break; case SCRIPT_COMMAND_FLAG_SET: diff --git a/src/game/World.h b/src/game/World.h index 4bbf4ebf1..9c908c127 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -113,9 +113,6 @@ enum WorldConfigs CONFIG_START_ARENA_POINTS, CONFIG_INSTANCE_IGNORE_LEVEL, CONFIG_INSTANCE_IGNORE_RAID, - CONFIG_BATTLEGROUND_CAST_DESERTER, - CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE, - CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY, CONFIG_INSTANCE_RESET_TIME_HOUR, CONFIG_INSTANCE_UNLOAD_DELAY, CONFIG_CAST_UNSTUCK, @@ -184,6 +181,13 @@ enum WorldConfigs CONFIG_LISTEN_RANGE_SAY, CONFIG_LISTEN_RANGE_TEXTEMOTE, CONFIG_LISTEN_RANGE_YELL, + CONFIG_SKILL_MILLING, + CONFIG_BATTLEGROUND_CAST_DESERTER, + CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE, + CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY, + CONFIG_BATTLEGROUND_INVITATION_TYPE, + CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER, + CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH, CONFIG_ARENA_MAX_RATING_DIFFERENCE, CONFIG_ARENA_RATING_DISCARD_TIMER, CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS, @@ -191,8 +195,6 @@ enum WorldConfigs CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE, CONFIG_ARENA_SEASON_ID, CONFIG_ARENA_SEASON_IN_PROGRESS, - CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER, - CONFIG_SKILL_MILLING, CONFIG_VALUE_COUNT }; diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index 9101711a9..73f622d6d 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -302,6 +302,9 @@ void WorldSession::LogoutPlayer(bool Save) _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } + //drop a flag if player is carrying it + if(BattleGround *bg = _player->GetBattleGround()) + bg->EventPlayerDroppedFlag(_player); ///- Teleport to home if the player is in an invalid instance if(!_player->m_InstanceValid && !_player->isGameMaster()) diff --git a/src/mangosd/Makefile.am b/src/mangosd/Makefile.am index 73a385d4e..b7106cc4f 100644 --- a/src/mangosd/Makefile.am +++ b/src/mangosd/Makefile.am @@ -22,15 +22,15 @@ AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir)/../../ ## Build world list daemon as standalone program bin_PROGRAMS = mangos-worldd mangos_worldd_SOURCES = \ - CliRunnable.cpp \ - CliRunnable.h \ - Main.cpp \ - Master.cpp \ - Master.h \ - RASocket.cpp \ - RASocket.h \ - WorldRunnable.cpp \ - WorldRunnable.h + CliRunnable.cpp \ + CliRunnable.h \ + Main.cpp \ + Master.cpp \ + Master.h \ + RASocket.cpp \ + RASocket.h \ + WorldRunnable.cpp \ + WorldRunnable.h ## Link world daemon against the shared library mangos_worldd_LDADD = ../bindings/universal/libmangosscript.la ../game/libmangosgame.a ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../shared/vmap/libmangosvmaps.a ../framework/libmangosframework.a ../../dep/src/sockets/libmangossockets.a ../../dep/src/zthread/libZThread.la ../../dep/src/g3dlite/libg3dlite.a @@ -39,22 +39,23 @@ mangos_worldd_LDFLAGS = -L../../dep/src/sockets -L../../dep/src/zthread -L../../ ## Additional files to include when running 'make dist' # Include world daemon configuration EXTRA_DIST = \ - mangosd.conf.dist + mangosd.conf.dist ## Additional files to install sysconf_DATA = \ - mangosd.conf.dist + mangosd.conf.dist install-data-hook: - @list='$(sysconf_DATA)'; for p in $$list; do \ - dest=`echo $$p | sed -e s/.dist//`; \ - if test -f $(DESTDIR)$(sysconfdir)/$$dest; then \ - echo "$@ will not overwrite existing $(DESTDIR)$(sysconfdir)/$$dest"; \ - else \ - echo " $(INSTALL_DATA) $$p $(DESTDIR)$(sysconfdir)/$$dest"; \ - $(INSTALL_DATA) $$p $(DESTDIR)$(sysconfdir)/$$dest; \ - fi; \ - done + @list='$(sysconf_DATA)' + for p in $$list; do \ + dest=`echo $$p | sed -e s/.dist//`; \ + if test -f $(DESTDIR)$(sysconfdir)/$$dest; then \ + echo "$@ will not overwrite existing $(DESTDIR)$(sysconfdir)/$$dest"; \ + else \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(sysconfdir)/$$dest"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(sysconfdir)/$$dest; \ + fi; \ + done clean-local: rm -f $(sysconf_DATA) diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.in index e8b916ce8..8a333823f 100644 --- a/src/mangosd/mangosd.conf.dist.in +++ b/src/mangosd/mangosd.conf.dist.in @@ -483,25 +483,6 @@ LogColors = "" # Default: 1 (true) # 0 (false) # -# Battleground.CastDeserter -# Cast or not Deserter spell at player who leave battleground in progress -# Default: 1 (true) -# 0 (false) -# -# Battleground.QueueAnnouncer.Enable -# Enable queue announcer posting to chat -# Default: 0 (false) -# 1 (true) -# -# Battleground.QueueAnnouncer.PlayerOnly -# Enable queue announcer posting to chat -# Default: 0 (false) -# 1 (true) -# -# Arena.QueueAnnouncer.Enable: Enable queue announcer posting to chat -# Default: 0 (false) -# 1 (true) -# # CastUnstuck # Allow cast or not Unstuck spell at .start or client Help option use # Default: 1 (true) @@ -606,10 +587,6 @@ DisableWaterBreath = 4 AllFlightPaths = 0 AlwaysMaxSkillForLevel = 0 ActivateWeather = 1 -Battleground.CastDeserter = 1 -Battleground.QueueAnnouncer.Enable = 0 -Battleground.QueueAnnouncer.PlayerOnly = 0 -Arena.QueueAnnouncer.Enable = 0 CastUnstuck = 1 Instance.IgnoreLevel = 0 Instance.IgnoreRaid = 0 @@ -1128,59 +1105,101 @@ Death.CorpseReclaimDelay.PvE = 1 Death.Bones.World = 1 Death.Bones.BattlegroundOrArena = 1 + ################################################################################################################### +# BATTLEGROUND CONFIG # -# Rated arena matches config +# Battleground.CastDeserter +# Cast or not Deserter spell at player who leave battleground in progress +# Default: 1 (true) +# 0 (false) # -# MaxRatingDifference: the maximum rating difference between two groups in rated matches -# Default: 0 (disable, rating difference is discarded) +# Battleground.QueueAnnouncer.Enable +# Enable queue announcer posting to chat +# Default: 0 (false) +# 1 (true) # -# RatingDiscardTimer: after the specified milliseconds has passed, -# rating information will be discarded when selecting teams for matches -# also initiates an update by this timer -# Default: 60000 +# Battleground.QueueAnnouncer.PlayerOnly +# Enable queue announcer posting to chat +# Default: 0 (false) +# 1 (true) # -# AutoDistributePoints: set if arena points should be distributed automatically, or by GM command -# Default: 0 (disable) (recommended): use gm command or sql query to distribute the points -# 1 (enable): arena points are distributed automatically +# Battleground.InvitationType +# Set Battleground invitation type +# Default: 0 (normal - invite as much players to bg as possible, don't bother with ballance) +# 1 (Experimental - don't allow to invite much more players of one faction) # -# AutoDistributeInterval: how often should the distribution take place -# if automatic distribution is enabled -# in days -# Default: 7 (weekly) +# Battleground.PrematureFinishTimer +# The time to end the bg if there are less than MinPlayersPerTeam on one side in milliseconds +# Default: 300000 (5 minutes) +# 0 - disable (not recommended) # -# ArenaSeason.ID: current area season id show in client -# Default: 1 -# -# ArenaSeason.InProgress: current area season state -# Default: 1 (active) -# 0 (finished) +# BattleGround.PremadeGroupWaitForMatch +# The time in which premade group of 1 faction waits in BG Queue for premade group of other faction +# Default: 1800000 (30 minutes) +# 0 - disable (not recommended) # ################################################################################################################### -Arena.MaxRatingDifference = 0 -Arena.RatingDiscardTimer = 60000 +Battleground.CastDeserter = 1 +Battleground.QueueAnnouncer.Enable = 0 +Battleground.QueueAnnouncer.PlayerOnly = 0 +Battleground.InvitationType = 0 +BattleGround.PrematureFinishTimer = 300000 +BattleGround.PremadeGroupWaitForMatch = 1800000 + + +################################################################################################################### +# ARENA CONFIG +# +# Arena.MaxRatingDifference +# The maximum rating difference between two groups in rated matches +# Default: 100 (enable, recommended) +# 0 (disable, rating difference is discarded) +# +# Arena.RatingDiscardTimer +# After the specified milliseconds has passed, +# rating information will be discarded when selecting teams for matches +# also initiates an update by this timer +# Default: 600000 (10 minutes, recommended) +# 0 (disable, DO NOT USE - it will cause lags) +# +# Arena.AutoDistributePoints +# Set if arena points should be distributed automatically, or by GM command +# Default: 0 (disable) (recommended): use gm command or sql query to distribute the points +# 1 (enable) arena points are distributed automatically +# +# Arena.AutoDistributeInterval +# How often should the distribution take place +# If automatic distribution is enabled in days +# Default: 7 (weekly) +# +# Arena.QueueAnnouncer.Enable +# Enable bg queue announcer posting to chat +# Default: 0 (false) +# 1 (true) +# +# Arena.ArenaSeason.ID +# Current area season id show in client +# Default: 1 +# +# Arena.ArenaSeason.InProgress +# Current area season state +# Default: 1 (active) +# 0 (finished) +# +################################################################################################################### + +Arena.MaxRatingDifference = 100 +Arena.RatingDiscardTimer = 600000 Arena.AutoDistributePoints = 0 Arena.AutoDistributeInterval = 7 +Arena.QueueAnnouncer.Enable = 0 Arena.ArenaSeason.ID = 1 Arena.ArenaSeason.InProgress = 1 -################################################################################################################### -# -# Battleground config -# -# PrematureFinishTimer: the time to end the bg if there are less than minplayersperteam on one side -# in milliseconds -# Default: 300000 -# 0 - disable -# -################################################################################################################### - -BattleGround.PrematureFinishTimer = 300000 - ################################################################################################################### -# # NETWORK CONFIG # # Network.Threads diff --git a/src/realmd/Makefile.am b/src/realmd/Makefile.am index 6de5189c3..38e1bdd61 100644 --- a/src/realmd/Makefile.am +++ b/src/realmd/Makefile.am @@ -22,12 +22,12 @@ AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir)/../../ ## Build realm list daemon as standalone program bin_PROGRAMS = mangos-realmd mangos_realmd_SOURCES = \ - AuthCodes.h \ - AuthSocket.cpp \ - AuthSocket.h \ - Main.cpp \ - RealmList.cpp \ - RealmList.h + AuthCodes.h \ + AuthSocket.cpp \ + AuthSocket.h \ + Main.cpp \ + RealmList.cpp \ + RealmList.h ## Link realm list daemon against the shared library mangos_realmd_LDADD = ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../framework/libmangosframework.a ../../dep/src/sockets/libmangossockets.a ../../dep/src/zthread/libZThread.la @@ -36,22 +36,23 @@ mangos_realmd_LDFLAGS = -L../../dep/src/sockets -L../../dep/src/zthread -L$(libd ## Additional files to include when running 'make dist' # Include realm list daemon configuration EXTRA_DIST = \ - realmd.conf.dist + realmd.conf.dist ## Additional files to install sysconf_DATA = \ - realmd.conf.dist + realmd.conf.dist install-data-hook: - @list='$(sysconf_DATA)'; for p in $$list; do \ - dest=`echo $$p | sed -e s/.dist//`; \ - if test -f $(DESTDIR)$(sysconfdir)/$$dest; then \ - echo "$@ will not overwrite existing $(DESTDIR)$(sysconfdir)/$$dest"; \ - else \ - echo " $(INSTALL_DATA) $$p $(DESTDIR)$(sysconfdir)/$$dest"; \ - $(INSTALL_DATA) $$p $(DESTDIR)$(sysconfdir)/$$dest; \ - fi; \ - done + @list='$(sysconf_DATA)' + for p in $$list; do \ + dest=`echo $$p | sed -e s/.dist//`; \ + if test -f $(DESTDIR)$(sysconfdir)/$$dest; then \ + echo "$@ will not overwrite existing $(DESTDIR)$(sysconfdir)/$$dest"; \ + else \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(sysconfdir)/$$dest"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(sysconfdir)/$$dest; \ + fi; \ + done clean-local: rm -f $(sysconf_DATA) diff --git a/src/shared/Auth/Makefile.am b/src/shared/Auth/Makefile.am index b7a2de5fc..9e4956711 100644 --- a/src/shared/Auth/Makefile.am +++ b/src/shared/Auth/Makefile.am @@ -27,13 +27,13 @@ AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(sr noinst_LIBRARIES = libmangosauth.a libmangosauth_a_SOURCES = \ - AuthCrypt.cpp \ - AuthCrypt.h \ - BigNumber.cpp \ - BigNumber.h \ - Hmac.cpp \ - Hmac.h \ - Sha1.cpp \ - Sha1.h \ - md5.c \ - md5.h + AuthCrypt.cpp \ + AuthCrypt.h \ + BigNumber.cpp \ + BigNumber.h \ + Hmac.cpp \ + Hmac.h \ + Sha1.cpp \ + Sha1.h \ + md5.c \ + md5.h diff --git a/src/shared/Common.h b/src/shared/Common.h index ab65d0743..2dce4ac37 100644 --- a/src/shared/Common.h +++ b/src/shared/Common.h @@ -157,7 +157,8 @@ enum TimeConstants MINUTE = 60, HOUR = MINUTE*60, DAY = HOUR*24, - MONTH = DAY*30 + MONTH = DAY*30, + IN_MILISECONDS = 1000 }; enum AccountTypes diff --git a/src/shared/Database/Makefile.am b/src/shared/Database/Makefile.am index 31c24917b..f9de9576f 100644 --- a/src/shared/Database/Makefile.am +++ b/src/shared/Database/Makefile.am @@ -27,38 +27,38 @@ AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(sr noinst_LIBRARIES = libmangosdatabase.a libmangosdatabase_a_SOURCES = \ - DBCStores.cpp \ - DBCStores.h \ - DBCStructure.h \ - DBCfmt.cpp \ - Database.cpp \ - Database.h \ - DatabaseEnv.h \ - DatabaseImpl.h \ - DatabaseMysql.cpp \ - DatabasePostgre.cpp \ - DatabaseMysql.h \ - DatabasePostgre.h \ - DatabaseSqlite.cpp \ - DatabaseSqlite.h \ - DBCEnums.h \ - Field.cpp \ - Field.h \ - MySQLDelayThread.h \ - PGSQLDelayThread.h \ - QueryResult.h \ - QueryResultMysql.cpp \ - QueryResultMysql.h \ - QueryResultPostgre.cpp \ - QueryResultPostgre.h \ - QueryResultSqlite.cpp \ - QueryResultSqlite.h \ - SQLStorage.cpp \ - SQLStorage.h \ - SQLStorageImpl.h \ - SqlDelayThread.cpp \ - SqlDelayThread.h \ - SqlOperations.cpp \ - SqlOperations.h \ - dbcfile.cpp \ - dbcfile.h + DBCStores.cpp \ + DBCStores.h \ + DBCStructure.h \ + DBCfmt.cpp \ + Database.cpp \ + Database.h \ + DatabaseEnv.h \ + DatabaseImpl.h \ + DatabaseMysql.cpp \ + DatabasePostgre.cpp \ + DatabaseMysql.h \ + DatabasePostgre.h \ + DatabaseSqlite.cpp \ + DatabaseSqlite.h \ + DBCEnums.h \ + Field.cpp \ + Field.h \ + MySQLDelayThread.h \ + PGSQLDelayThread.h \ + QueryResult.h \ + QueryResultMysql.cpp \ + QueryResultMysql.h \ + QueryResultPostgre.cpp \ + QueryResultPostgre.h \ + QueryResultSqlite.cpp \ + QueryResultSqlite.h \ + SQLStorage.cpp \ + SQLStorage.h \ + SQLStorageImpl.h \ + SqlDelayThread.cpp \ + SqlDelayThread.h \ + SqlOperations.cpp \ + SqlOperations.h \ + dbcfile.cpp \ + dbcfile.h diff --git a/src/shared/Makefile.am b/src/shared/Makefile.am index 087f0ec20..f4533e4c2 100644 --- a/src/shared/Makefile.am +++ b/src/shared/Makefile.am @@ -30,24 +30,24 @@ noinst_LIBRARIES = libmangosshared.a # libmangosshared library will later be reused by ... libmangosshared_a_SOURCES = \ - Base.cpp \ - Base.h \ - ByteBuffer.h \ - Common.cpp \ - Common.h \ - Errors.h \ - Log.cpp \ - Log.h \ - MemoryLeaks.cpp \ - MemoryLeaks.h \ - ProgressBar.cpp \ - ProgressBar.h \ - Timer.h \ - Util.cpp \ - Util.h \ - WorldPacket.h \ - revision_nr.h \ - revision.h + Base.cpp \ + Base.h \ + ByteBuffer.h \ + Common.cpp \ + Common.h \ + Errors.h \ + Log.cpp \ + Log.h \ + MemoryLeaks.cpp \ + MemoryLeaks.h \ + ProgressBar.cpp \ + ProgressBar.h \ + Timer.h \ + Util.cpp \ + Util.h \ + WorldPacket.h \ + revision_nr.h \ + revision.h # Get revision (git or svn) REVISION_FILE = revision.h @@ -63,16 +63,16 @@ $(REVISION_FILE) : $(top_builddir)/src/tools/genrevision/genrevision FORCE ## Additional files to include when running 'make dist' # Disabled packet logger EXTRA_DIST = \ - PacketLog.cpp \ - PacketLog.h + PacketLog.cpp \ + PacketLog.h # System configuration EXTRA_DIST += \ - SystemConfig.h + SystemConfig.h # System Win32 files EXTRA_DIST += \ - ServiceWin32.cpp \ - ServiceWin32.h \ - WheatyExceptionReport.cpp \ - WheatyExceptionReport.h + ServiceWin32.cpp \ + ServiceWin32.h \ + WheatyExceptionReport.cpp \ + WheatyExceptionReport.h diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 019806b23..057f92297 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7331" + #define REVISION_NR "7360" #endif // __REVISION_NR_H__ diff --git a/src/shared/vmap/Makefile.am b/src/shared/vmap/Makefile.am index 14ace12f0..8ebbb1e04 100644 --- a/src/shared/vmap/Makefile.am +++ b/src/shared/vmap/Makefile.am @@ -27,30 +27,30 @@ AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(sr noinst_LIBRARIES = libmangosvmaps.a libmangosvmaps_a_SOURCES = \ - AABSPTree.h \ - BaseModel.cpp \ - BaseModel.h \ - CoordModelMapping.cpp \ - CoordModelMapping.h \ - DebugCmdLogger.cpp \ - DebugCmdLogger.h \ - IVMapManager.h \ - ManagedModelContainer.cpp \ - ManagedModelContainer.h \ - ModelContainer.cpp \ - ModelContainer.h \ - NodeValueAccess.h \ - ShortBox.h \ - ShortVector.h \ - SubModel.cpp \ - SubModel.h \ - TileAssembler.cpp \ - TileAssembler.h \ - TreeNode.cpp \ - TreeNode.h \ - VMapDefinitions.h \ - VMapFactory.cpp \ - VMapFactory.h \ - VMapManager.cpp \ - VMapManager.h \ - VMapTools.h + AABSPTree.h \ + BaseModel.cpp \ + BaseModel.h \ + CoordModelMapping.cpp \ + CoordModelMapping.h \ + DebugCmdLogger.cpp \ + DebugCmdLogger.h \ + IVMapManager.h \ + ManagedModelContainer.cpp \ + ManagedModelContainer.h \ + ModelContainer.cpp \ + ModelContainer.h \ + NodeValueAccess.h \ + ShortBox.h \ + ShortVector.h \ + SubModel.cpp \ + SubModel.h \ + TileAssembler.cpp \ + TileAssembler.h \ + TreeNode.cpp \ + TreeNode.h \ + VMapDefinitions.h \ + VMapFactory.cpp \ + VMapFactory.h \ + VMapManager.cpp \ + VMapManager.h \ + VMapTools.h