aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/genrev/CMakeLists.txt4
-rw-r--r--src/server/authserver/CMakeLists.txt2
-rw-r--r--src/server/collision/CMakeLists.txt1
-rw-r--r--src/server/collision/Management/MMapManager.cpp14
-rw-r--r--src/server/collision/Maps/MapTree.cpp5
-rw-r--r--src/server/collision/Maps/TileAssembler.cpp12
-rw-r--r--src/server/collision/Models/GameObjectModel.cpp6
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.cpp6
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.cpp5
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.h1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp4
-rw-r--r--src/server/game/Achievements/AchievementMgr.cpp1281
-rw-r--r--src/server/game/Achievements/AchievementMgr.h8
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp4
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBot.cpp20
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBot.h24
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp569
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h31
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp4
-rw-r--r--src/server/game/Battlegrounds/ArenaTeam.cpp2
-rw-r--r--src/server/game/Battlegrounds/Battleground.cpp2
-rw-r--r--src/server/game/CMakeLists.txt1
-rw-r--r--src/server/game/Chat/Chat.cpp32
-rw-r--r--src/server/game/Chat/Chat.h22
-rw-r--r--src/server/game/Chat/ChatLink.cpp2
-rw-r--r--src/server/game/Combat/ThreatManager.cpp2
-rw-r--r--src/server/game/Conditions/ConditionMgr.cpp23
-rw-r--r--src/server/game/Conditions/ConditionMgr.h3
-rw-r--r--src/server/game/DungeonFinding/LFG.cpp3
-rw-r--r--src/server/game/DungeonFinding/LFG.h4
-rw-r--r--src/server/game/DungeonFinding/LFGGroupData.cpp12
-rw-r--r--src/server/game/DungeonFinding/LFGGroupData.h4
-rw-r--r--src/server/game/DungeonFinding/LFGMgr.cpp43
-rw-r--r--src/server/game/DungeonFinding/LFGMgr.h3
-rw-r--r--src/server/game/DungeonFinding/LFGQueue.cpp2
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp4
-rw-r--r--src/server/game/Entities/Object/Object.cpp39
-rw-r--r--src/server/game/Entities/Object/Object.h1
-rw-r--r--src/server/game/Entities/Object/ObjectGuid.h2
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp2
-rw-r--r--src/server/game/Entities/Player/Player.cpp135
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp120
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp69
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.cpp2
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.h2
-rw-r--r--src/server/game/Groups/Group.cpp2
-rw-r--r--src/server/game/Handlers/PetHandler.cpp22
-rw-r--r--src/server/game/Handlers/QuestHandler.cpp8
-rw-r--r--src/server/game/Handlers/SpellHandler.cpp2
-rw-r--r--src/server/game/Loot/LootMgr.cpp2
-rw-r--r--src/server/game/Maps/Map.cpp32
-rw-r--r--src/server/game/Miscellaneous/Language.h3
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h2
-rw-r--r--src/server/game/Movement/MotionMaster.cpp39
-rw-r--r--src/server/game/Movement/MotionMaster.h1
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp4
-rw-r--r--src/server/game/Movement/Spline/MoveSpline.cpp2
-rw-r--r--src/server/game/Reputation/ReputationMgr.cpp2
-rw-r--r--src/server/game/Scripting/ScriptLoader.cpp8
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp3
-rw-r--r--src/server/game/Scripting/ScriptMgr.h2
-rw-r--r--src/server/game/Server/WorldSession.cpp18
-rw-r--r--src/server/game/Server/WorldSocket.cpp10
-rw-r--r--src/server/game/Server/WorldSocketMgr.cpp2
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp54
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp13
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h4
-rw-r--r--src/server/game/Spells/Spell.cpp154
-rw-r--r--src/server/game/Spells/SpellEffects.cpp18
-rw-r--r--src/server/game/Spells/SpellInfo.cpp96
-rw-r--r--src/server/game/Spells/SpellInfo.h10
-rw-r--r--src/server/game/Spells/SpellMgr.cpp8
-rw-r--r--src/server/game/World/World.cpp10
-rw-r--r--src/server/scripts/CMakeLists.txt1
-rw-r--r--src/server/scripts/Commands/cs_debug.cpp2
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp3
-rw-r--r--src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp6
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/SunkenTemple/sunken_temple.cpp26
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp81
-rw-r--r--src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/zone_undercity.cpp242
-rw-r--r--src/server/scripts/Kalimdor/CMakeLists.txt1
-rw-r--r--src/server/scripts/Kalimdor/RazorfenKraul/razorfen_kraul.cpp124
-rw-r--r--src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp9
-rw-r--r--src/server/scripts/Kalimdor/zone_felwood.cpp37
-rw-r--r--src/server/scripts/Kalimdor/zone_mulgore.cpp306
-rw-r--r--src/server/scripts/Kalimdor/zone_the_barrens.cpp1
-rw-r--r--src/server/scripts/Northrend/CMakeLists.txt3
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp8
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp18
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp190
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp22
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.h54
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp15
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp393
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h23
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp52
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp51
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp1
-rw-r--r--src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp43
-rw-r--r--src/server/scripts/Northrend/Nexus/Nexus/boss_commander_kolurg.cpp80
-rw-r--r--src/server/scripts/Northrend/Nexus/Nexus/boss_commander_stoutbeard.cpp72
-rw-r--r--src/server/scripts/Northrend/Nexus/Nexus/boss_nexus_commanders.cpp110
-rw-r--r--src/server/scripts/Northrend/Nexus/Nexus/nexus.h23
-rw-r--r--src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp243
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp21
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp9
-rw-r--r--src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp1
-rw-r--r--src/server/scripts/Northrend/zone_borean_tundra.cpp49
-rw-r--r--src/server/scripts/Northrend/zone_storm_peaks.cpp92
-rw-r--r--src/server/scripts/Northrend/zone_zuldrak.cpp2
-rw-r--r--src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp146
-rw-r--r--src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp7
-rw-r--r--src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp5
-rw-r--r--src/server/shared/CMakeLists.txt2
-rw-r--r--src/server/shared/Cryptography/BigNumber.cpp7
-rw-r--r--src/server/shared/DataStores/DBCStore.h7
-rw-r--r--src/server/shared/Database/DatabaseWorkerPool.h9
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp4
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.h2
-rw-r--r--src/server/shared/Database/MySQLConnection.cpp12
-rw-r--r--src/server/shared/Database/MySQLConnection.h2
-rw-r--r--src/server/shared/Database/Transaction.cpp12
-rw-r--r--src/server/shared/Database/Transaction.h1
-rw-r--r--src/server/shared/Debugging/Errors.h6
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.cpp14
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.h2
-rw-r--r--src/server/shared/Logging/Appender.cpp34
-rw-r--r--src/server/shared/Logging/Appender.h15
-rw-r--r--src/server/shared/Logging/AppenderConsole.cpp10
-rw-r--r--src/server/shared/Logging/AppenderConsole.h2
-rw-r--r--src/server/shared/Logging/AppenderDB.cpp12
-rw-r--r--src/server/shared/Logging/AppenderDB.h2
-rw-r--r--src/server/shared/Logging/AppenderFile.cpp14
-rw-r--r--src/server/shared/Logging/AppenderFile.h2
-rw-r--r--src/server/shared/Logging/Log.cpp51
-rw-r--r--src/server/shared/Logging/Log.h69
-rw-r--r--src/server/shared/Logging/LogOperation.cpp8
-rw-r--r--src/server/shared/Logging/LogOperation.h10
-rw-r--r--src/server/shared/Logging/Logger.cpp4
-rw-r--r--src/server/shared/Logging/Logger.h2
-rw-r--r--src/server/shared/Networking/Socket.h4
-rw-r--r--src/server/shared/Networking/SocketMgr.h2
-rw-r--r--src/server/shared/Utilities/StringFormat.h34
-rw-r--r--src/server/worldserver/CMakeLists.txt2
-rw-r--r--src/server/worldserver/RemoteAccess/RASession.h2
-rw-r--r--src/server/worldserver/worldserver.conf.dist60
151 files changed, 3118 insertions, 2951 deletions
diff --git a/src/genrev/CMakeLists.txt b/src/genrev/CMakeLists.txt
index 8ab3494cd70..e72643c6a6b 100644
--- a/src/genrev/CMakeLists.txt
+++ b/src/genrev/CMakeLists.txt
@@ -10,6 +10,6 @@
# Need to pass old ${CMAKE_BINARY_DIR} as param because its different at build stage
add_custom_target(revision.h ALL
- COMMAND ${CMAKE_COMMAND} -DNO_GIT=${WITHOUT_GIT} -DGIT_EXEC=${GIT_EXECUTABLE} -DBUILDDIR=${CMAKE_BINARY_DIR} -P ${CMAKE_SOURCE_DIR}/cmake/genrev.cmake
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ COMMAND "${CMAKE_COMMAND}" -DBUILDDIR="${CMAKE_BINARY_DIR}" -P "${CMAKE_SOURCE_DIR}/cmake/genrev.cmake" "${CMAKE_BINARY_DIR}"
+ WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt
index edd87a5c347..077cd15404b 100644
--- a/src/server/authserver/CMakeLists.txt
+++ b/src/server/authserver/CMakeLists.txt
@@ -43,6 +43,7 @@ endif()
include_directories(
${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
${CMAKE_SOURCE_DIR}/src/server/shared/Database
@@ -78,6 +79,7 @@ endif()
target_link_libraries(authserver
shared
+ format
${MYSQL_LIBRARY}
${OPENSSL_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
diff --git a/src/server/collision/CMakeLists.txt b/src/server/collision/CMakeLists.txt
index e3c77736d5e..150c32a15a3 100644
--- a/src/server/collision/CMakeLists.txt
+++ b/src/server/collision/CMakeLists.txt
@@ -35,6 +35,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include
+ ${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
diff --git a/src/server/collision/Management/MMapManager.cpp b/src/server/collision/Management/MMapManager.cpp
index 170350d4de4..847b7bbd001 100644
--- a/src/server/collision/Management/MMapManager.cpp
+++ b/src/server/collision/Management/MMapManager.cpp
@@ -73,7 +73,7 @@ namespace MMAP
delete [] fileName;
- TC_LOG_INFO("maps", "MMAP:loadMapData: Loaded %03i.mmap", mapId);
+ TC_LOG_DEBUG("maps", "MMAP:loadMapData: Loaded %03i.mmap", mapId);
// store inside our map list
MMapData* mmap_data = new MMapData(mesh);
@@ -156,7 +156,7 @@ namespace MMAP
{
mmap->mmapLoadedTiles.insert(std::pair<uint32, dtTileRef>(packedGridPos, tileRef));
++loadedTiles;
- TC_LOG_INFO("maps", "MMAP:loadMap: Loaded mmtile %03i[%02i, %02i] into %03i[%02i, %02i]", mapId, x, y, mapId, header->x, header->y);
+ TC_LOG_DEBUG("maps", "MMAP:loadMap: Loaded mmtile %03i[%02i, %02i] into %03i[%02i, %02i]", mapId, x, y, mapId, header->x, header->y);
return true;
}
else
@@ -205,7 +205,7 @@ namespace MMAP
{
mmap->mmapLoadedTiles.erase(packedGridPos);
--loadedTiles;
- TC_LOG_INFO("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId);
+ TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId);
return true;
}
@@ -232,13 +232,13 @@ namespace MMAP
else
{
--loadedTiles;
- TC_LOG_INFO("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId);
+ TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId);
}
}
delete mmap;
loadedMMaps.erase(mapId);
- TC_LOG_INFO("maps", "MMAP:unloadMap: Unloaded %03i.mmap", mapId);
+ TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded %03i.mmap", mapId);
return true;
}
@@ -264,7 +264,7 @@ namespace MMAP
dtFreeNavMeshQuery(query);
mmap->navMeshQueries.erase(instanceId);
- TC_LOG_INFO("maps", "MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId);
+ TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId);
return true;
}
@@ -295,7 +295,7 @@ namespace MMAP
return NULL;
}
- TC_LOG_INFO("maps", "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
+ TC_LOG_DEBUG("maps", "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
mmap->navMeshQueries.insert(std::pair<uint32, dtNavMeshQuery*>(instanceId, query));
}
diff --git a/src/server/collision/Maps/MapTree.cpp b/src/server/collision/Maps/MapTree.cpp
index 72435594ad0..b493ec18f5f 100644
--- a/src/server/collision/Maps/MapTree.cpp
+++ b/src/server/collision/Maps/MapTree.cpp
@@ -386,13 +386,12 @@ namespace VMAP
{
if (!iLoadedSpawns.count(referencedVal))
{
-#ifdef VMAP_DEBUG
if (referencedVal > iNTreeValues)
{
- TC_LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : invalid tree element (%u/%u)", referencedVal, iNTreeValues);
+ VMAP_ERROR_LOG("maps", "StaticMapTree::LoadMapTile() : invalid tree element (%u/%u) referenced in tile %s", referencedVal, iNTreeValues, tilefile.c_str());
continue;
}
-#endif
+
iTreeValues[referencedVal] = ModelInstance(spawn, model);
iLoadedSpawns[referencedVal] = 1;
}
diff --git a/src/server/collision/Maps/TileAssembler.cpp b/src/server/collision/Maps/TileAssembler.cpp
index 06540ecdc61..ee978211577 100644
--- a/src/server/collision/Maps/TileAssembler.cpp
+++ b/src/server/collision/Maps/TileAssembler.cpp
@@ -391,6 +391,18 @@ namespace VMAP
}
}
+ if (bounds.isEmpty())
+ {
+ std::cout << "\nModel " << std::string(buff, name_length) << " has empty bounding box" << std::endl;
+ continue;
+ }
+
+ if (!bounds.isFinite())
+ {
+ std::cout << "\nModel " << std::string(buff, name_length) << " has invalid bounding box" << std::endl;
+ continue;
+ }
+
fwrite(&displayId, sizeof(uint32), 1, model_list_copy);
fwrite(&name_length, sizeof(uint32), 1, model_list_copy);
fwrite(&buff, sizeof(char), name_length, model_list_copy);
diff --git a/src/server/collision/Models/GameObjectModel.cpp b/src/server/collision/Models/GameObjectModel.cpp
index 993c298941c..05bd5d360c6 100644
--- a/src/server/collision/Models/GameObjectModel.cpp
+++ b/src/server/collision/Models/GameObjectModel.cpp
@@ -78,6 +78,12 @@ void LoadGameObjectModelList()
break;
}
+ if (v1.isNaN() || v2.isNaN())
+ {
+ VMAP_ERROR_LOG("misc", "File '%s' Model '%s' has invalid v1%s v2%s values!", VMAP::GAMEOBJECT_MODELS, std::string(buff, name_length).c_str(), v1.toString().c_str(), v2.toString().c_str());
+ continue;
+ }
+
model_list.insert
(
ModelList::value_type( displayId, GameobjectModelData(std::string(buff, name_length), AABox(v1, v2)) )
diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp
index e7d39d715eb..5aa6ea8ea7a 100644
--- a/src/server/game/AI/CoreAI/UnitAI.cpp
+++ b/src/server/game/AI/CoreAI/UnitAI.cpp
@@ -141,7 +141,7 @@ void UnitAI::DoCast(uint32 spellId)
{
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId))
{
- bool playerOnly = (spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS) != 0;
+ bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS);
target = SelectTarget(SELECT_TARGET_RANDOM, 0, spellInfo->GetMaxRange(false), playerOnly);
}
break;
@@ -156,7 +156,7 @@ void UnitAI::DoCast(uint32 spellId)
{
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId))
{
- bool playerOnly = (spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS) != 0;
+ bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS);
float range = spellInfo->GetMaxRange(false);
DefaultTargetSelector targetSelector(me, range, playerOnly, -(int32)spellId);
@@ -213,7 +213,7 @@ void UnitAI::FillAISpellInfo()
if (!spellInfo)
continue;
- if (spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD))
AIInfo->condition = AICOND_DIE;
else if (spellInfo->IsPassive() || spellInfo->GetDuration() == -1)
AIInfo->condition = AICOND_AGGRO;
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
index b00a24129c3..135a0fcee93 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
@@ -663,3 +663,8 @@ void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& list, WorldObject*
{
source->GetGameObjectListWithEntryInGrid(list, entry, maxSearchRange);
}
+
+void GetPlayerListInGrid(std::list<Player*>& list, WorldObject* source, float maxSearchRange)
+{
+ source->GetPlayerListInGrid(list, maxSearchRange);
+}
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
index cff628a847e..1a4c3064a59 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
@@ -425,5 +425,6 @@ Creature* GetClosestCreatureWithEntry(WorldObject* source, uint32 entry, float m
GameObject* GetClosestGameObjectWithEntry(WorldObject* source, uint32 entry, float maxSearchRange);
void GetCreatureListWithEntryInGrid(std::list<Creature*>& list, WorldObject* source, uint32 entry, float maxSearchRange);
void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& list, WorldObject* source, uint32 entry, float maxSearchRange);
+void GetPlayerListInGrid(std::list<Player*>& list, WorldObject* source, float maxSearchRange);
#endif // SCRIPTEDCREATURE_H_
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index e7e5f53f7a2..58b25781035 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -3167,7 +3167,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
std::list<Creature*> list;
me->GetCreatureListWithEntryInGrid(list, e.event.distance.entry, (float)e.event.distance.dist);
- if (list.size() > 0)
+ if (!list.empty())
creature = list.front();
}
@@ -3198,7 +3198,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
std::list<GameObject*> list;
me->GetGameObjectListWithEntryInGrid(list, e.event.distance.entry, (float)e.event.distance.dist);
- if (list.size() > 0)
+ if (!list.empty())
gameobject = list.front();
}
diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp
index c1fde9f53d3..51106d7cfe1 100644
--- a/src/server/game/Achievements/AchievementMgr.cpp
+++ b/src/server/game/Achievements/AchievementMgr.cpp
@@ -55,6 +55,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE:
case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING:
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: // only hardcoded list
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
@@ -700,58 +701,100 @@ void AchievementMgr::CheckAllAchievementCriteria()
}
static const uint32 achievIdByArenaSlot[MAX_ARENA_SLOT] = { 1057, 1107, 1108 };
-static const uint32 achievIdForDungeon[][4] =
-{
- // ach_cr_id, is_dungeon, is_raid, is_heroic_dungeon
- { 321, true, true, true },
- { 916, false, true, false },
- { 917, false, true, false },
- { 918, true, false, false },
- { 2219, false, false, true },
- { 0, false, false, false }
-};
/**
* this function will be called whenever the user might have done a criteria relevant action
*/
void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /*= 0*/, Unit* unit /*= NULL*/)
{
- TC_LOG_DEBUG("achievement", "AchievementMgr::UpdateAchievementCriteria(%u, %u, %u)", type, miscValue1, miscValue2);
+ if (type >= ACHIEVEMENT_CRITERIA_TYPE_TOTAL)
+ {
+ TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: Wrong criteria type %u", type);
+ return;
+ }
// disable for gamemasters with GM-mode enabled
if (m_player->IsGameMaster())
+ {
+ TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: [Player %s GM mode on] %s, %s (%u), %u, %u"
+ , m_player->GetName().c_str(), m_player->GetGUID().ToString().c_str(), AchievementGlobalMgr::GetCriteriaTypeString(type), type, miscValue1, miscValue2);
return;
+ }
+
+ TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: %s, %s (%u), %u, %u"
+ , m_player->GetGUID().ToString().c_str(), AchievementGlobalMgr::GetCriteriaTypeString(type), type, miscValue1, miscValue2);
AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type);
- for (AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i != achievementCriteriaList.end(); ++i)
+ for (AchievementCriteriaEntry const* achievementCriteria : achievementCriteriaList)
{
- AchievementCriteriaEntry const* achievementCriteria = (*i);
AchievementEntry const* achievement = sAchievementMgr->GetAchievement(achievementCriteria->referredAchievement);
if (!achievement)
continue;
- if (!CanUpdateCriteria(achievementCriteria, achievement))
+ if (!CanUpdateCriteria(achievementCriteria, achievement, miscValue1, miscValue2, unit))
continue;
switch (type)
{
+ // special cases, db data is checked later
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA:
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT:
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT:
+ break;
+ default:
+ if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria))
+ if (!data->Meets(GetPlayer(), unit, miscValue1))
+ continue;
+ break;
+ }
+
+ switch (type)
+ {
// std. case: increment at 1
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST:
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
+ case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
+ case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
+ case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET:
+ case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
+ case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE:
+ case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA:
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: // This also behaves like ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA
+ case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL:
+ case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM:
+ case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS:
+ case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE:
+ case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
+ case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS:
case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS:
+ case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
+ case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2:
+ case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL:
+ case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT:
+ case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN:
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL:
case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL:
case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION:
- case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS: /* FIXME: for online player only currently */
+ case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS: /* FIXME: for online player only currently */
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM:
+ case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED:
case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED:
case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN:
+ case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS:
case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS:
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
// std case: increment at miscvalue1
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
+ case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE:
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
+ case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE:
case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS:
case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD:
@@ -759,14 +802,19 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL:
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY:
- case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS:/* FIXME: for online player only currently */
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS: /* FIXME: for online player only currently */
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED:
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED:
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_ACCUMULATE);
break;
+ // std case: increment at miscvalue2
+ case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
+ case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
+ case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE:
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE:
+ SetCriteriaProgress(achievementCriteria, miscValue2, PROGRESS_ACCUMULATE);
+ break;
// std case: high value at miscvalue1
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: /* FIXME: for online player only currently */
@@ -774,92 +822,27 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED:
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_HIGHEST);
break;
-
- // specialized cases
- case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST:
- {
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
-
- if (achievement->categoryId == CATEGORY_CHILDRENS_WEEK)
- {
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data || !data->Meets(GetPlayer(), NULL))
- continue;
- }
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
- {
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
- if (achievementCriteria->win_bg.bgMapID != GetPlayer()->GetMapId())
- continue;
-
- // those requirements couldn't be found in the dbc
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data || !data->Meets(GetPlayer(), unit))
- continue;
-
- SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_ACCUMULATE);
- break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
- {
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
- if (achievementCriteria->kill_creature.creatureID != miscValue1)
- continue;
-
- // those requirements couldn't be found in the dbc
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data || !data->Meets(GetPlayer(), unit))
- continue;
-
- SetCriteriaProgress(achievementCriteria, miscValue2, PROGRESS_ACCUMULATE);
+ // std. case: set at 1
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
+ case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
+ case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP:
+ case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM:
+ case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
+ SetCriteriaProgress(achievementCriteria, 1, PROGRESS_SET);
break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE:
- {
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue2)
- continue;
-
- // those requirements couldn't be found in the dbc
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data || !data->Meets(GetPlayer(), unit, miscValue1))
- continue;
- SetCriteriaProgress(achievementCriteria, miscValue2, PROGRESS_ACCUMULATE);
- break;
- }
+ // specialized cases
case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
- if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria))
- if (!data->Meets(GetPlayer(), unit))
- continue;
SetCriteriaProgress(achievementCriteria, GetPlayer()->getLevel());
break;
case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL:
- // update at loading or specific skill update
- if (miscValue1 && miscValue1 != achievementCriteria->reach_skill_level.skillID)
- continue;
if (uint32 skillvalue = GetPlayer()->GetBaseSkillValue(achievementCriteria->reach_skill_level.skillID))
SetCriteriaProgress(achievementCriteria, skillvalue);
break;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
- // update at loading or specific skill update
- if (miscValue1 && miscValue1 != achievementCriteria->learn_skill_level.skillID)
- continue;
if (uint32 maxSkillvalue = GetPlayer()->GetPureMaxSkillValue(achievementCriteria->learn_skill_level.skillID))
SetCriteriaProgress(achievementCriteria, maxSkillvalue);
break;
@@ -868,14 +851,12 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
SetCriteriaProgress(achievementCriteria, 1);
break;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
- {
SetCriteriaProgress(achievementCriteria, GetPlayer()->GetRewardedQuestCount());
break;
- }
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY:
{
time_t nextDailyResetTime = sWorld->GetNextDailyQuestsResetTime();
- CriteriaProgress *progress = GetCriteriaProgress(achievementCriteria);
+ CriteriaProgress const* progress = GetCriteriaProgress(achievementCriteria);
if (!miscValue1) // Login case.
{
@@ -904,10 +885,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
}
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE:
{
- // speedup for non-login case
- if (miscValue1 && miscValue1 != achievementCriteria->complete_quests_in_zone.zoneID)
- continue;
-
uint32 counter = 0;
const RewardedQuestSet &rewQuests = GetPlayer()->getRewardedQuests();
@@ -920,231 +897,11 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
SetCriteriaProgress(achievementCriteria, counter);
break;
}
- case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
- if (GetPlayer()->GetMapId() != achievementCriteria->complete_battleground.mapID)
- continue;
- SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_ACCUMULATE);
- break;
- case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
- if (GetPlayer()->GetMapId() != achievementCriteria->death_at_map.mapID)
- continue;
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
- {
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
- // skip wrong arena achievements, if not achievIdByArenaSlot then normal total death counter
- bool notfit = false;
- for (int j = 0; j < MAX_ARENA_SLOT; ++j)
- {
- if (achievIdByArenaSlot[j] == achievement->ID)
- {
- Battleground* bg = GetPlayer()->GetBattleground();
- if (!bg || !bg->isArena() || ArenaTeam::GetSlotByType(bg->GetArenaType()) != j)
- notfit = true;
-
- break;
- }
- }
- if (notfit)
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
- {
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
-
- Map const* map = GetPlayer()->IsInWorld() ? GetPlayer()->GetMap() : sMapMgr->FindMap(GetPlayer()->GetMapId(), GetPlayer()->GetInstanceId());
- if (!map || !map->IsDungeon())
- continue;
-
- // search case
- bool found = false;
- for (int j = 0; achievIdForDungeon[j][0]; ++j)
- {
- if (achievIdForDungeon[j][0] == achievement->ID)
- {
- if (map->IsRaid())
- {
- // if raid accepted (ignore difficulty)
- if (!achievIdForDungeon[j][2])
- break; // for
- }
- else if (GetPlayer()->GetDungeonDifficulty() == DUNGEON_DIFFICULTY_NORMAL)
- {
- // dungeon in normal mode accepted
- if (!achievIdForDungeon[j][1])
- break; // for
- }
- else
- {
- // dungeon in heroic mode accepted
- if (!achievIdForDungeon[j][3])
- break; // for
- }
-
- found = true;
- break; // for
- }
- }
- if (!found)
- continue;
-
- //FIXME: work only for instances where max == min for players
- if (map->ToInstanceMap()->GetMaxPlayers() != achievementCriteria->death_in_dungeon.manLimit)
- continue;
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
-
- }
- case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
- if (miscValue1 != achievementCriteria->killed_by_creature.creatureEntry)
- continue;
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
-
- // if team check required: must kill by opposition faction
- if (achievement->ID == 318 && miscValue2 == GetPlayer()->GetTeam())
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING:
- {
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
-
- // those requirements couldn't be found in the dbc
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data || !data->Meets(GetPlayer(), unit))
- continue;
-
// miscvalue1 is the ingame fallheight*100 as stored in dbc
SetCriteriaProgress(achievementCriteria, miscValue1);
break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
- if (miscValue2 != achievementCriteria->death_from.type)
- continue;
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
- {
- // if miscvalues != 0, it contains the questID.
- if (miscValue1)
- {
- if (miscValue1 != achievementCriteria->complete_quest.questID)
- continue;
- }
- else
- {
- // login case.
- if (!GetPlayer()->GetQuestRewardStatus(achievementCriteria->complete_quest.questID))
- continue;
- }
-
- if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria))
- if (!data->Meets(GetPlayer(), unit))
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1);
- break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET:
- case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2:
- {
- if (!miscValue1 || miscValue1 != achievementCriteria->be_spell_target.spellID)
- continue;
-
- // those requirements couldn't be found in the dbc
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data)
- continue;
-
- if (!data->Meets(GetPlayer(), unit))
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
- case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
- {
- if (!miscValue1 || miscValue1 != achievementCriteria->cast_spell.spellID)
- continue;
-
- // those requirements couldn't be found in the dbc
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data)
- continue;
-
- if (!data->Meets(GetPlayer(), unit))
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
- if (miscValue1 && miscValue1 != achievementCriteria->learn_spell.spellID)
- continue;
-
- if (GetPlayer()->HasSpell(achievementCriteria->learn_spell.spellID))
- SetCriteriaProgress(achievementCriteria, 1);
- break;
- case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE:
- {
- // miscvalue1=loot_type (note: 0 = LOOT_CORPSE and then it ignored)
- // miscvalue2=count of item loot
- if (!miscValue1 || !miscValue2)
- continue;
- if (miscValue1 != achievementCriteria->loot_type.lootType)
- continue;
-
- // zone specific
- if (achievementCriteria->loot_type.lootTypeCount == 1)
- {
- // those requirements couldn't be found in the dbc
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data || !data->Meets(GetPlayer(), unit))
- continue;
- }
-
- SetCriteriaProgress(achievementCriteria, miscValue2, PROGRESS_ACCUMULATE);
- break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
- // speedup for non-login case
- if (miscValue1 && achievementCriteria->own_item.itemID != miscValue1)
- continue;
- SetCriteriaProgress(achievementCriteria, miscValue2, PROGRESS_ACCUMULATE);
- break;
case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA:
- if (!miscValue1) // no update at login
- continue;
-
// additional requirements
if (achievementCriteria->additionalRequirements[0].additionalRequirement_type == ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE)
{
@@ -1160,198 +917,36 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
- case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM:
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
-
- if (achievementCriteria->use_item.itemID != miscValue1)
- continue;
-
- // Children's Week achievements have extra requirements
- if (achievement->categoryId == CATEGORY_CHILDRENS_WEEK)
- {
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data || !data->Meets(GetPlayer(), NULL))
- continue;
- }
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
- // You _have_ to loot that item, just owning it when logging in does _not_ count!
- if (!miscValue1)
- continue;
- if (miscValue1 != achievementCriteria->own_item.itemID)
- continue;
- SetCriteriaProgress(achievementCriteria, miscValue2, PROGRESS_ACCUMULATE);
- break;
- case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
- {
- WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(achievementCriteria->explore_area.areaReference);
- if (!worldOverlayEntry)
- break;
-
- bool matchFound = false;
- for (int j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j)
- {
- uint32 area_id = worldOverlayEntry->areatableID[j];
- if (!area_id) // array have 0 only in empty tail
- break;
-
- int32 exploreFlag = GetAreaFlagByAreaID(area_id);
- if (exploreFlag < 0)
- continue;
-
- uint32 playerIndexOffset = uint32(exploreFlag) / 32;
- uint32 mask = 1<< (uint32(exploreFlag) % 32);
-
- if (GetPlayer()->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask)
- {
- matchFound = true;
- break;
- }
- }
-
- if (matchFound)
- SetCriteriaProgress(achievementCriteria, 1);
- break;
- }
case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
SetCriteriaProgress(achievementCriteria, GetPlayer()->GetBankBagSlotCount());
break;
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
{
- // skip faction check only at loading
- if (miscValue1 && miscValue1 != achievementCriteria->gain_reputation.factionID)
- continue;
-
int32 reputation = GetPlayer()->GetReputationMgr().GetReputation(achievementCriteria->gain_reputation.factionID);
if (reputation > 0)
SetCriteriaProgress(achievementCriteria, reputation);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION:
- {
SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetExaltedFactionCount());
break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP:
- {
- // skip for login case
- if (!miscValue1)
- continue;
- SetCriteriaProgress(achievementCriteria, 1);
- break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM:
- {
- // miscvalue1 = itemid
- // miscvalue2 = itemSlot
- if (!miscValue1)
- continue;
-
- if (miscValue2 != achievementCriteria->equip_epic_item.itemSlot)
- continue;
-
- // check item level and quality via achievement_criteria_data
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data || !data->Meets(GetPlayer(), nullptr, miscValue1))
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1);
- break;
- }
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT:
{
- // miscvalue1 = itemid
- // miscvalue2 = diced value
- if (!miscValue1)
- continue;
- if (miscValue2 != achievementCriteria->roll_greed_on_loot.rollValue)
- continue;
-
- ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(miscValue1);
- if (!pProto)
+ ItemTemplate const* proto = sObjectMgr->GetItemTemplate(miscValue1);
+ if (!proto)
continue;
// check item level via achievement_criteria_data
AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data || !data->Meets(GetPlayer(), nullptr, pProto->ItemLevel))
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
- {
- // miscvalue1 = emote
- if (!miscValue1)
- continue;
- if (miscValue1 != achievementCriteria->do_emote.emoteID)
+ if (!data || !data->Meets(GetPlayer(), nullptr, proto->ItemLevel))
continue;
- if (achievementCriteria->do_emote.count)
- {
- // those requirements couldn't be found in the dbc
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data || !data->Meets(GetPlayer(), unit))
- continue;
- }
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
}
- case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE:
- case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE:
- {
- if (!miscValue1)
- continue;
-
- if (achievementCriteria->additionalRequirements[0].additionalRequirement_type == ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP)
- {
- if (GetPlayer()->GetMapId() != achievementCriteria->additionalRequirements[0].additionalRequirement_value)
- continue;
-
- // map specific case (BG in fact) expected player targeted damage/heal
- if (!unit || unit->GetTypeId() != TYPEID_PLAYER)
- continue;
- }
-
- SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_ACCUMULATE);
- break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
- // miscvalue1 = item_id
- if (!miscValue1)
- continue;
- if (miscValue1 != achievementCriteria->equip_item.itemID)
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1);
- break;
- case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
- // miscvalue1 = go entry
- if (!miscValue1)
- continue;
- if (miscValue1 != achievementCriteria->use_gameobject.goEntry)
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT:
- if (!miscValue1)
- continue;
- if (miscValue1 != achievementCriteria->fish_in_gameobject.goEntry)
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS:
{
- if (miscValue1 && miscValue1 != achievementCriteria->learn_skillline_spell.skillLine)
- continue;
-
uint32 spellCount = 0;
for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin();
spellIter != GetPlayer()->GetSpellMap().end();
@@ -1367,24 +962,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
SetCriteriaProgress(achievementCriteria, spellCount);
break;
}
- case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL:
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
-
- if (achievementCriteria->win_duel.duelCount)
- {
- // those requirements couldn't be found in the dbc
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data)
- continue;
-
- if (!data->Meets(GetPlayer(), unit))
- continue;
- }
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION:
SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetReveredFactionCount());
break;
@@ -1394,23 +971,8 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS:
SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetVisibleFactionCount());
break;
- case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM:
- case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM:
- {
- // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
- if (!miscValue1)
- continue;
- ItemTemplate const* proto = sObjectMgr->GetItemTemplate(miscValue1);
- if (!proto || proto->Quality < ITEM_QUALITY_EPIC)
- continue;
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- }
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE:
{
- if (miscValue1 && miscValue1 != achievementCriteria->learn_skill_line.skillLine)
- continue;
-
uint32 spellCount = 0;
for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin();
spellIter != GetPlayer()->GetSpellMap().end();
@@ -1427,72 +989,21 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL:
SetCriteriaProgress(achievementCriteria, GetPlayer()->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS));
break;
- case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS:
- if (!miscValue1 || miscValue1 != achievementCriteria->hk_class.classID)
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE:
- if (!miscValue1 || miscValue1 != achievementCriteria->hk_race.raceID)
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED:
SetCriteriaProgress(achievementCriteria, GetPlayer()->GetMoney(), PROGRESS_HIGHEST);
break;
case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS:
- {
if (!miscValue1)
{
uint32 points = 0;
- for (CompletedAchievementMap::iterator itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr)
- if (AchievementEntry const* pAchievement = sAchievementMgr->GetAchievement(itr->first))
- points += pAchievement->points;
+ for (CompletedAchievementMap::const_iterator itr = m_completedAchievements.begin(); itr != m_completedAchievements.end(); ++itr)
+ if (AchievementEntry const* completedAchievements = sAchievementMgr->GetAchievement(itr->first))
+ points += completedAchievements->points;
SetCriteriaProgress(achievementCriteria, points, PROGRESS_SET);
}
else
SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_ACCUMULATE);
break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE:
- {
- if (!miscValue1 || miscValue1 != achievementCriteria->bg_objective.objectiveId)
- continue;
-
- // those requirements couldn't be found in the dbc
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data || !data->Meets(GetPlayer(), unit))
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL:
- case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL:
- case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS:
- {
- // skip login update
- if (!miscValue1)
- continue;
-
- // those requirements couldn't be found in the dbc
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data || !data->Meets(GetPlayer(), unit))
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA:
- {
- if (!miscValue1 || miscValue1 != achievementCriteria->honorable_kill_at_area.areaID)
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- }
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING:
{
uint32 reqTeamType = achievementCriteria->highest_team_rating.teamtype;
@@ -1504,7 +1015,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_HIGHEST);
}
- else // login case
+ else // login case
{
for (uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot)
{
@@ -1520,7 +1031,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
break;
}
}
-
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING:
@@ -1534,7 +1044,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_HIGHEST);
}
- else // login case
+ else // login case
{
for (uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot)
{
@@ -1556,27 +1066,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
break;
}
- case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: // This also behaves like ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA
- {
- // Check map id requirement
- if (miscValue1 == achievementCriteria->win_arena.mapID)
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- }
- case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN:
- {
- // This criteria is only called directly after login - with expected miscvalue1 == 1
- if (!miscValue1)
- continue;
-
- // They have no proper requirements in dbc
- AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
- if (!data || !data->Meets(GetPlayer(), unit))
- continue;
-
- SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
- break;
- }
// std case: not exist in DBC, not triggered in code as result
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER:
@@ -2019,7 +1508,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement)
if (achievement->flags & ACHIEVEMENT_FLAG_COUNTER || HasAchieved(achievement->ID))
return;
- TC_LOG_INFO("achievement", "AchievementMgr::CompletedAchievement(%u). Player: %s (%u)",
+ TC_LOG_DEBUG("achievement", "AchievementMgr::CompletedAchievement(%u). Player: %s (%u)",
achievement->ID, m_player->GetName().c_str(), m_player->GetGUIDLow());
SendAchievementEarned(achievement);
@@ -2140,18 +1629,53 @@ bool AchievementMgr::HasAchieved(uint32 achievementId) const
return m_completedAchievements.find(achievementId) != m_completedAchievements.end();
}
-bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement)
+bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint32 miscValue1, uint32 miscValue2, Unit const* unit)
{
- if (DisableMgr::IsDisabledFor(DISABLE_TYPE_ACHIEVEMENT_CRITERIA, criteria->ID, NULL))
+ if (DisableMgr::IsDisabledFor(DISABLE_TYPE_ACHIEVEMENT_CRITERIA, criteria->ID, nullptr))
+ {
+ TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Disabled",
+ criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->requiredType));
return false;
+ }
if (achievement->mapID != -1 && GetPlayer()->GetMapId() != uint32(achievement->mapID))
+ {
+ TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s Achievement %u) Wrong map",
+ criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->requiredType), achievement->ID);
return false;
+ }
if ((achievement->requiredFaction == ACHIEVEMENT_FACTION_HORDE && GetPlayer()->GetTeam() != HORDE) ||
(achievement->requiredFaction == ACHIEVEMENT_FACTION_ALLIANCE && GetPlayer()->GetTeam() != ALLIANCE))
+ {
+ TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s Achievement %u) Wrong faction",
+ criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->requiredType), achievement->ID);
return false;
+ }
+
+ if (!RequirementsSatisfied(criteria, achievement, miscValue1, miscValue2, unit))
+ {
+ TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Requirements not satisfied",
+ criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->requiredType));
+ return false;
+ }
+ if (!ConditionsSatisfied(criteria))
+ {
+ TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Conditions not satisfied",
+ criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->requiredType));
+ return false;
+ }
+
+ // don't update already completed criteria
+ if (IsCompletedCriteria(criteria, achievement))
+ return false;
+
+ return true;
+}
+
+bool AchievementMgr::ConditionsSatisfied(AchievementCriteriaEntry const* criteria) const
+{
for (uint32 i = 0; i < MAX_CRITERIA_REQUIREMENTS; ++i)
{
if (!criteria->additionalRequirements[i].additionalRequirement_type)
@@ -2172,13 +1696,558 @@ bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria,
}
}
- // don't update already completed criteria
- if (IsCompletedCriteria(criteria, achievement))
- return false;
+ return true;
+}
+
+bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement, uint32 miscValue1, uint32 miscValue2, Unit const* unit) const
+{
+ switch (AchievementCriteriaTypes(achievementCriteria->requiredType))
+ {
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST:
+ case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING:
+ case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL:
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA:
+ case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP:
+ case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS:
+ case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS:
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS:
+ case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS:
+ case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD:
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING:
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER:
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL:
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY:
+ case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL:
+ case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN:
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL:
+ case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL:
+ case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE:
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS:
+ case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID:
+ case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD:
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED:
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED:
+ case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST:
+ case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED:
+ case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED:
+ case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN:
+ case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS:
+ case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS:
+ if (!miscValue1)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT:
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING:
+ case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION:
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION:
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION:
+ case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS:
+ case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL:
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED:
+ case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS:
+ break;
+
+ // specialized cases
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
+ if (!miscValue1)
+ return false;
+ if (achievementCriteria->win_bg.bgMapID != GetPlayer()->GetMapId())
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
+ if (!miscValue1)
+ return false;
+ if (achievementCriteria->kill_creature.creatureID != miscValue1)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL:
+ if (miscValue1 && miscValue1 != achievementCriteria->reach_skill_level.skillID)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
+ if (miscValue1 && miscValue1 != achievementCriteria->learn_skill_level.skillID)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE:
+ if (miscValue1 && miscValue1 != achievementCriteria->complete_quests_in_zone.zoneID)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
+ if (!miscValue1)
+ return false;
+ if (GetPlayer()->GetMapId() != achievementCriteria->complete_battleground.mapID)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
+ if (!miscValue1)
+ return false;
+ if (GetPlayer()->GetMapId() != achievementCriteria->death_at_map.mapID)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
+ if (!miscValue1)
+ return false;
+ for (uint8 j = 0; j < MAX_ARENA_SLOT; ++j)
+ {
+ if (achievIdByArenaSlot[j] == achievement->ID)
+ {
+ Battleground* bg = GetPlayer()->GetBattleground();
+ if (!bg || !bg->isArena() || ArenaTeam::GetSlotByType(bg->GetArenaType()) != j)
+ return false;
+ break;
+ }
+ }
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
+ {
+ if (!miscValue1)
+ return false;
+
+ Map const* map = GetPlayer()->IsInWorld() ? GetPlayer()->GetMap() : sMapMgr->FindMap(GetPlayer()->GetMapId(), GetPlayer()->GetInstanceId());
+ if (!map || !map->IsDungeon())
+ return false;
+
+ //FIXME: work only for instances where max == min for players
+ if (map->ToInstanceMap()->GetMaxPlayers() != achievementCriteria->death_in_dungeon.manLimit)
+ return false;
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
+ if (!miscValue1)
+ return false;
+ if (miscValue1 != achievementCriteria->killed_by_creature.creatureEntry)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
+ if (!miscValue1)
+ return false;
+ // if team check required: must kill by opposition faction
+ if (achievement->ID == 318 && miscValue2 == GetPlayer()->GetTeam())
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
+ if (!miscValue1)
+ return false;
+ if (miscValue2 != achievementCriteria->death_from.type)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
+ // if miscvalues != 0, it contains the questID.
+ if (miscValue1)
+ {
+ if (miscValue1 != achievementCriteria->complete_quest.questID)
+ return false;
+ }
+ else
+ {
+ // login case.
+ if (!GetPlayer()->GetQuestRewardStatus(achievementCriteria->complete_quest.questID))
+ return false;
+ }
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET:
+ case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2:
+ if (!miscValue1 || miscValue1 != achievementCriteria->be_spell_target.spellID)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
+ case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
+ if (!miscValue1 || miscValue1 != achievementCriteria->cast_spell.spellID)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
+ if (miscValue1 && miscValue1 != achievementCriteria->learn_spell.spellID)
+ return false;
+ if (!GetPlayer()->HasSpell(achievementCriteria->learn_spell.spellID))
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE:
+ // miscvalue1=loot_type (note: 0 = LOOT_CORPSE and then it ignored)
+ // miscvalue2=count of item loot
+ if (!miscValue1 || !miscValue2)
+ return false;
+ if (miscValue1 != achievementCriteria->loot_type.lootType)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
+ if (miscValue1 && achievementCriteria->own_item.itemID != miscValue1)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM:
+ if (!miscValue1)
+ return false;
+ if (achievementCriteria->use_item.itemID != miscValue1)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
+ if (!miscValue1)
+ return false;
+ if (miscValue1 != achievementCriteria->own_item.itemID)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
+ {
+ WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(achievementCriteria->explore_area.areaReference);
+ if (!worldOverlayEntry)
+ return false;
+
+ bool matchFound = false;
+ for (int j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j)
+ {
+ uint32 area_id = worldOverlayEntry->areatableID[j];
+ if (!area_id) // array have 0 only in empty tail
+ break;
+
+ int32 exploreFlag = GetAreaFlagByAreaID(area_id);
+ if (exploreFlag < 0)
+ continue;
+
+ uint32 playerIndexOffset = uint32(exploreFlag) / 32;
+ uint32 mask = 1 << (uint32(exploreFlag) % 32);
+
+ if (GetPlayer()->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask)
+ {
+ matchFound = true;
+ break;
+ }
+ }
+
+ if (!matchFound)
+ return false;
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
+ if (miscValue1 && miscValue1 != achievementCriteria->gain_reputation.factionID)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM:
+ // miscvalue1 = itemid
+ // miscvalue2 = itemSlot
+ if (!miscValue1)
+ return false;
+ if (miscValue2 != achievementCriteria->equip_epic_item.itemSlot)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT:
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT:
+ // miscvalue1 = itemid
+ // miscvalue2 = diced value
+ if (!miscValue1)
+ return false;
+ if (miscValue2 != achievementCriteria->roll_greed_on_loot.rollValue)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
+ // miscvalue1 = emote
+ if (!miscValue1)
+ return false;
+ if (miscValue1 != achievementCriteria->do_emote.emoteID)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE:
+ case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE:
+ if (!miscValue1)
+ return false;
+
+ if (achievementCriteria->additionalRequirements[0].additionalRequirement_type == ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP)
+ {
+ if (GetPlayer()->GetMapId() != achievementCriteria->additionalRequirements[0].additionalRequirement_value)
+ return false;
+
+ // map specific case (BG in fact) expected player targeted damage/heal
+ if (!unit || unit->GetTypeId() != TYPEID_PLAYER)
+ return false;
+ }
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
+ if (!miscValue1)
+ return false;
+ if (miscValue1 != achievementCriteria->equip_item.itemID)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
+ if (!miscValue1)
+ return false;
+ if (miscValue1 != achievementCriteria->use_gameobject.goEntry)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT:
+ if (!miscValue1)
+ return false;
+ if (miscValue1 != achievementCriteria->fish_in_gameobject.goEntry)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS:
+ if (miscValue1 && miscValue1 != achievementCriteria->learn_skillline_spell.skillLine)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM:
+ case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM:
+ {
+ if (!miscValue1)
+ return false;
+ ItemTemplate const* proto = sObjectMgr->GetItemTemplate(miscValue1);
+ if (!proto || proto->Quality < ITEM_QUALITY_EPIC)
+ return false;
+ break;
+ }
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE:
+ if (miscValue1 && miscValue1 != achievementCriteria->learn_skill_line.skillLine)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS:
+ if (!miscValue1 || miscValue1 != achievementCriteria->hk_class.classID)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE:
+ if (!miscValue1 || miscValue1 != achievementCriteria->hk_race.raceID)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE:
+ if (!miscValue1 || miscValue1 != achievementCriteria->bg_objective.objectiveId)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA:
+ if (!miscValue1 || miscValue1 != achievementCriteria->honorable_kill_at_area.areaID)
+ return false;
+ break;
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA:
+ if (miscValue1 != achievementCriteria->win_arena.mapID)
+ return false;
+ break;
+ default:
+ break;
+ }
return true;
}
+char const* AchievementGlobalMgr::GetCriteriaTypeString(uint32 type)
+{
+ return GetCriteriaTypeString(AchievementCriteriaTypes(type));
+}
+
+char const* AchievementGlobalMgr::GetCriteriaTypeString(AchievementCriteriaTypes type)
+{
+ switch (type)
+ {
+ case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
+ return "KILL_CREATURE";
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
+ return "TYPE_WIN_BG";
+ case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
+ return "REACH_LEVEL";
+ case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL:
+ return "REACH_SKILL_LEVEL";
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT:
+ return "COMPLETE_ACHIEVEMENT";
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
+ return "COMPLETE_QUEST_COUNT";
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY:
+ return "COMPLETE_DAILY_QUEST_DAILY";
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE:
+ return "COMPLETE_QUESTS_IN_ZONE";
+ case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE:
+ return "DAMAGE_DONE";
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST:
+ return "COMPLETE_DAILY_QUEST";
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
+ return "COMPLETE_BATTLEGROUND";
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
+ return "DEATH_AT_MAP";
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
+ return "DEATH";
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
+ return "DEATH_IN_DUNGEON";
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID:
+ return "COMPLETE_RAID";
+ case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
+ return "KILLED_BY_CREATURE";
+ case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
+ return "KILLED_BY_PLAYER";
+ case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING:
+ return "FALL_WITHOUT_DYING";
+ case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
+ return "DEATHS_FROM";
+ case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
+ return "COMPLETE_QUEST";
+ case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET:
+ return "BE_SPELL_TARGET";
+ case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
+ return "CAST_SPELL";
+ case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE:
+ return "BG_OBJECTIVE_CAPTURE";
+ case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA:
+ return "HONORABLE_KILL_AT_AREA";
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA:
+ return "WIN_ARENA";
+ case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA:
+ return "PLAY_ARENA";
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
+ return "LEARN_SPELL";
+ case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL:
+ return "HONORABLE_KILL";
+ case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
+ return "OWN_ITEM";
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA:
+ return "WIN_RATED_ARENA";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING:
+ return "HIGHEST_TEAM_RATING";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING:
+ return "HIGHEST_PERSONAL_RATING";
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
+ return "LEARN_SKILL_LEVEL";
+ case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM:
+ return "USE_ITEM";
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
+ return "LOOT_ITEM";
+ case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
+ return "EXPLORE_AREA";
+ case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
+ return "OWN_RANK";
+ case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
+ return "BUY_BANK_SLOT";
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
+ return "GAIN_REPUTATION";
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION:
+ return "GAIN_EXALTED_REPUTATION";
+ case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP:
+ return "VISIT_BARBER_SHOP";
+ case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM:
+ return "EQUIP_EPIC_ITEM";
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT:
+ return "ROLL_NEED_ON_LOOT";
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT:
+ return "GREED_ON_LOOT";
+ case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS:
+ return "HK_CLASS";
+ case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE:
+ return "HK_RACE";
+ case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
+ return "DO_EMOTE";
+ case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE:
+ return "HEALING_DONE";
+ case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS:
+ return "GET_KILLING_BLOWS";
+ case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
+ return "EQUIP_ITEM";
+ case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS:
+ return "MONEY_FROM_VENDORS";
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS:
+ return "GOLD_SPENT_FOR_TALENTS";
+ case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS:
+ return "NUMBER_OF_TALENT_RESETS";
+ case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD:
+ return "MONEY_FROM_QUEST_REWARD";
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING:
+ return "GOLD_SPENT_FOR_TRAVELLING";
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER:
+ return "GOLD_SPENT_AT_BARBER";
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL:
+ return "GOLD_SPENT_FOR_MAIL";
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY:
+ return "LOOT_MONEY";
+ case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
+ return "USE_GAMEOBJECT";
+ case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2:
+ return "BE_SPELL_TARGET2";
+ case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL:
+ return "SPECIAL_PVP_KILL";
+ case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT:
+ return "FISH_IN_GAMEOBJECT";
+ case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN:
+ return "ON_LOGIN";
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS:
+ return "LEARN_SKILLLINE_SPELLS";
+ case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL:
+ return "WIN_DUEL";
+ case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL:
+ return "LOSE_DUEL";
+ case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE:
+ return "KILL_CREATURE_TYPE";
+ case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS:
+ return "GOLD_EARNED_BY_AUCTIONS";
+ case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION:
+ return "CREATE_AUCTION";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID:
+ return "HIGHEST_AUCTION_BID";
+ case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS:
+ return "WON_AUCTIONS";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD:
+ return "HIGHEST_AUCTION_SOLD";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED:
+ return "HIGHEST_GOLD_VALUE_OWNED";
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION:
+ return "GAIN_REVERED_REPUTATION";
+ case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION:
+ return "GAIN_HONORED_REPUTATION";
+ case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS:
+ return "KNOWN_FACTIONS";
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM:
+ return "LOOT_EPIC_ITEM";
+ case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM:
+ return "RECEIVE_EPIC_ITEM";
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED:
+ return "ROLL_NEED";
+ case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED:
+ return "ROLL_GREED";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH:
+ return "HIGHEST_HEALTH";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER:
+ return "HIGHEST_POWER";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT:
+ return "HIGHEST_STAT";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER:
+ return "HIGHEST_SPELLPOWER";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR:
+ return "HIGHEST_ARMOR";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING:
+ return "HIGHEST_RATING";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT:
+ return "HIT_DEALT";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED:
+ return "HIT_RECEIVED";
+ case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED:
+ return "TOTAL_DAMAGE_RECEIVED";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST:
+ return "HIGHEST_HEAL_CAST";
+ case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED:
+ return "TOTAL_HEALING_RECEIVED";
+ case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED:
+ return "HIGHEST_HEALING_RECEIVED";
+ case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED:
+ return "QUEST_ABANDONED";
+ case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN:
+ return "FLIGHT_PATHS_TAKEN";
+ case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE:
+ return "LOOT_TYPE";
+ case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
+ return "CAST_SPELL2";
+ case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE:
+ return "LEARN_SKILL_LINE";
+ case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL:
+ return "EARN_HONORABLE_KILL";
+ case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS:
+ return "ACCEPTED_SUMMONINGS";
+ case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS:
+ return "EARN_ACHIEVEMENT_POINTS";
+ case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS:
+ return "USE_LFD_TO_GROUP_WITH_PLAYERS";
+ }
+ return "MISSING_TYPE";
+}
+
//==========================================================
void AchievementGlobalMgr::LoadAchievementCriteriaList()
{
@@ -2357,7 +2426,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
AchievementEntry const* achievement = sAchievementMgr->GetAchievement(criteria->referredAchievement);
if (!achievement)
continue;
- if (achievement->categoryId != CATEGORY_CHILDRENS_WEEK)
+ if (achievement->categoryId != CATEGORY_CHILDRENS_WEEK && achievement->ID != 1785)
continue;
break;
}
diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h
index f8869757e50..078229ea4c8 100644
--- a/src/server/game/Achievements/AchievementMgr.h
+++ b/src/server/game/Achievements/AchievementMgr.h
@@ -293,9 +293,12 @@ class AchievementMgr
void CompletedCriteriaFor(AchievementEntry const* achievement);
bool IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement);
bool IsCompletedAchievement(AchievementEntry const* entry);
- bool CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement);
+ bool CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint32 miscValue1, uint32 miscValue2, Unit const* unit);
void BuildAllDataPacket(WorldPacket* data) const;
+ bool ConditionsSatisfied(AchievementCriteriaEntry const* criteria) const;
+ bool RequirementsSatisfied(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint32 miscValue1, uint32 miscValue2, Unit const* unit) const;
+
Player* m_player;
CriteriaProgressMap m_criteriaProgress;
CompletedAchievementMap m_completedAchievements;
@@ -309,6 +312,9 @@ class AchievementGlobalMgr
~AchievementGlobalMgr() { }
public:
+ static char const* GetCriteriaTypeString(AchievementCriteriaTypes type);
+ static char const* GetCriteriaTypeString(uint32 type);
+
static AchievementGlobalMgr* instance()
{
static AchievementGlobalMgr instance;
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index ac2ceb78346..0235aa7e8b6 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -440,8 +440,6 @@ bool AuctionHouseObject::RemoveAuction(AuctionEntry* auction)
// we need to delete the entry, it is not referenced any more
delete auction;
- auction = NULL;
-
return wasInMap;
}
@@ -469,7 +467,7 @@ void AuctionHouseObject::Update()
continue;
///- Either cancel the auction if there was no bidder
- if (auction->bidder == 0)
+ if (auction->bidder == 0 && auction->bid == 0)
{
sAuctionMgr->SendAuctionExpiredMail(auction, trans);
sScriptMgr->OnAuctionExpire(this, auction);
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp
index 7e8ccb4bb23..c0c753100bc 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp
@@ -204,14 +204,24 @@ void AuctionBotConfig::GetConfigFromFile()
SetConfig(CONFIG_AHBOT_MINTIME, "AuctionHouseBot.MinTime", 1);
SetConfig(CONFIG_AHBOT_MAXTIME, "AuctionHouseBot.MaxTime", 72);
- SetConfigMinMax(CONFIG_AHBOT_BUYER_CHANCE_RATIO_ALLIANCE, "AuctionHouseBot.Buyer.Alliance.Chance.Ratio", 3, 1, 100);
- SetConfigMinMax(CONFIG_AHBOT_BUYER_CHANCE_RATIO_HORDE, "AuctionHouseBot.Buyer.Horde.Chance.Ratio", 3, 1, 100);
- SetConfigMinMax(CONFIG_AHBOT_BUYER_CHANCE_RATIO_NEUTRAL, "AuctionHouseBot.Buyer.Neutral.Chance.Ratio", 3, 1, 100);
SetConfigMinMax(CONFIG_AHBOT_BUYER_RECHECK_INTERVAL, "AuctionHouseBot.Buyer.Recheck.Interval", 20, 1, DAY / MINUTE);
+ SetConfig(CONFIG_AHBOT_BUYER_BASEPRICE_GRAY, "AuctionHouseBot.Buyer.Baseprice.Gray", 3504);
+ SetConfig(CONFIG_AHBOT_BUYER_BASEPRICE_WHITE, "AuctionHouseBot.Buyer.Baseprice.White", 5429);
+ SetConfig(CONFIG_AHBOT_BUYER_BASEPRICE_GREEN, "AuctionHouseBot.Buyer.Baseprice.Green", 21752);
+ SetConfig(CONFIG_AHBOT_BUYER_BASEPRICE_BLUE, "AuctionHouseBot.Buyer.Baseprice.Blue", 36463);
+ SetConfig(CONFIG_AHBOT_BUYER_BASEPRICE_PURPLE, "AuctionHouseBot.Buyer.Baseprice.Purple", 87124);
+ SetConfig(CONFIG_AHBOT_BUYER_BASEPRICE_ORANGE, "AuctionHouseBot.Buyer.Baseprice.Orange", 214347);
+ SetConfig(CONFIG_AHBOT_BUYER_BASEPRICE_YELLOW, "AuctionHouseBot.Buyer.Baseprice.Yellow", 407406);
+ SetConfig(CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_GRAY, "AuctionHouseBot.Buyer.ChanceMultiplier.Gray", 100);
+ SetConfig(CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_WHITE, "AuctionHouseBot.Buyer.ChanceMultiplier.White", 100);
+ SetConfig(CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_GREEN, "AuctionHouseBot.Buyer.ChanceMultiplier.Green", 100);
+ SetConfig(CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_BLUE, "AuctionHouseBot.Buyer.ChanceMultiplier.Blue", 100);
+ SetConfig(CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_PURPLE, "AuctionHouseBot.Buyer.ChanceMultiplier.Purple", 100);
+ SetConfig(CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_ORANGE, "AuctionHouseBot.Buyer.ChanceMultiplier.Orange", 100);
+ SetConfig(CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_YELLOW, "AuctionHouseBot.Buyer.ChanceMultiplier.Yellow", 100);
SetConfig(CONFIG_AHBOT_SELLER_ENABLED, "AuctionHouseBot.Seller.Enabled", false);
SetConfig(CONFIG_AHBOT_BUYER_ENABLED, "AuctionHouseBot.Buyer.Enabled", false);
- SetConfig(CONFIG_AHBOT_BUYPRICE_BUYER, "AuctionHouseBot.Buyer.Buyprice", true);
SetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MIN_REQ_LEVEL, "AuctionHouseBot.Class.Misc.Mount.ReqLevel.Min", 0);
SetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MAX_REQ_LEVEL, "AuctionHouseBot.Class.Misc.Mount.ReqLevel.Max", 0);
@@ -229,7 +239,7 @@ void AuctionBotConfig::GetConfigFromFile()
char const* AuctionBotConfig::GetHouseTypeName(AuctionHouseType houseType)
{
- static char const* names[MAX_AUCTION_HOUSE_TYPE] = { "Alliance", "Horde", "Neutral" };
+ static char const* names[MAX_AUCTION_HOUSE_TYPE] = { "Neutral", "Alliance", "Horde" };
return names[houseType];
}
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBot.h b/src/server/game/AuctionHouseBot/AuctionHouseBot.h
index 964262579e6..d7570c37d44 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBot.h
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.h
@@ -39,9 +39,9 @@ enum AuctionQuality
enum AuctionHouseType
{
- AUCTION_HOUSE_ALLIANCE = 0,
- AUCTION_HOUSE_HORDE = 1,
- AUCTION_HOUSE_NEUTRAL = 2
+ AUCTION_HOUSE_NEUTRAL = 0,
+ AUCTION_HOUSE_ALLIANCE = 1,
+ AUCTION_HOUSE_HORDE = 2
};
#define MAX_AUCTION_HOUSE_TYPE 3
@@ -110,10 +110,21 @@ enum AuctionBotConfigUInt32Values
CONFIG_AHBOT_CLASS_PERMANENT_PRICE_RATIO,
CONFIG_AHBOT_CLASS_MISC_PRICE_RATIO,
CONFIG_AHBOT_CLASS_GLYPH_PRICE_RATIO,
- CONFIG_AHBOT_BUYER_CHANCE_RATIO_ALLIANCE,
- CONFIG_AHBOT_BUYER_CHANCE_RATIO_HORDE,
- CONFIG_AHBOT_BUYER_CHANCE_RATIO_NEUTRAL,
CONFIG_AHBOT_BUYER_RECHECK_INTERVAL,
+ CONFIG_AHBOT_BUYER_BASEPRICE_GRAY,
+ CONFIG_AHBOT_BUYER_BASEPRICE_WHITE,
+ CONFIG_AHBOT_BUYER_BASEPRICE_GREEN,
+ CONFIG_AHBOT_BUYER_BASEPRICE_BLUE,
+ CONFIG_AHBOT_BUYER_BASEPRICE_PURPLE,
+ CONFIG_AHBOT_BUYER_BASEPRICE_ORANGE,
+ CONFIG_AHBOT_BUYER_BASEPRICE_YELLOW,
+ CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_GRAY,
+ CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_WHITE,
+ CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_GREEN,
+ CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_BLUE,
+ CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_PURPLE,
+ CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_ORANGE,
+ CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_YELLOW,
CONFIG_AHBOT_CLASS_MISC_MOUNT_MIN_REQ_LEVEL,
CONFIG_AHBOT_CLASS_MISC_MOUNT_MAX_REQ_LEVEL,
CONFIG_AHBOT_CLASS_MISC_MOUNT_MIN_SKILL_RANK,
@@ -143,7 +154,6 @@ enum AuctionBotConfigBoolValues
CONFIG_AHBOT_BIND_USE,
CONFIG_AHBOT_BIND_QUEST,
CONFIG_AHBOT_BUYPRICE_SELLER,
- CONFIG_AHBOT_BUYPRICE_BUYER,
CONFIG_AHBOT_SELLER_ENABLED,
CONFIG_AHBOT_BUYER_ENABLED,
CONFIG_AHBOT_LOCKBOX_ENABLED,
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp
index af60316cbec..64463948574 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp
@@ -20,7 +20,7 @@
#include "ItemPrototype.h"
#include "AuctionHouseBotBuyer.h"
-AuctionBotBuyer::AuctionBotBuyer(): _checkInterval(20)
+AuctionBotBuyer::AuctionBotBuyer() : _checkInterval(20 * MINUTE)
{
// Define faction for our main data class.
for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i)
@@ -48,391 +48,394 @@ bool AuctionBotBuyer::Initialize()
if (!activeHouse)
return false;
- //load Check interval
+ // load Check interval
_checkInterval = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_RECHECK_INTERVAL) * MINUTE;
- TC_LOG_DEBUG("ahbot", "AHBot buyer interval between 2 check = %u", _checkInterval);
+ TC_LOG_DEBUG("ahbot", "AHBot buyer interval is %u minutes", _checkInterval / MINUTE);
return true;
}
-void AuctionBotBuyer::LoadBuyerValues(BuyerConfiguration& config)
+void AuctionBotBuyer::LoadConfig()
{
- uint32 factionChance;
-
- switch (config.GetHouseType())
+ for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i)
{
- case AUCTION_HOUSE_ALLIANCE:
- config.BuyerPriceRatio = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ALLIANCE_PRICE_RATIO) + 50;
- factionChance = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_CHANCE_RATIO_ALLIANCE);
- break;
- case AUCTION_HOUSE_HORDE:
- config.BuyerPriceRatio = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_HORDE_PRICE_RATIO) + 50;
- factionChance = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_CHANCE_RATIO_HORDE);
- break;
- default:
- config.BuyerPriceRatio = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_NEUTRAL_PRICE_RATIO) + 50;
- factionChance = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_CHANCE_RATIO_NEUTRAL);
- break;
+ _houseConfig[i].BuyerEnabled = sAuctionBotConfig->GetConfigBuyerEnabled(AuctionHouseType(i));
+ if (_houseConfig[i].BuyerEnabled)
+ LoadBuyerValues(_houseConfig[i]);
}
+}
+
+void AuctionBotBuyer::LoadBuyerValues(BuyerConfiguration& /* config */)
+{
- config.FactionChance = 5000 * factionChance;
}
-void AuctionBotBuyer::LoadConfig()
+// Makes an AHbot buyer cycle for AH type if necessary
+bool AuctionBotBuyer::Update(AuctionHouseType houseType)
{
- for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i)
+ if (!sAuctionBotConfig->GetConfigBuyerEnabled(houseType))
+ return false;
+
+ TC_LOG_DEBUG("ahbot", "AHBot: %s buying ...", AuctionBotConfig::GetHouseTypeName(houseType));
+
+ BuyerConfiguration& config = _houseConfig[houseType];
+ uint32 eligibleItems = GetItemInformation(config);
+ if (eligibleItems)
{
- _houseConfig[i].BuyerEnabled = sAuctionBotConfig->GetConfigBuyerEnabled(AuctionHouseType(i));
- if (_houseConfig[i].BuyerEnabled)
- LoadBuyerValues(_houseConfig[i]);
+ // Prepare list of items to bid or buy - remove old items
+ PrepareListOfEntry(config);
+ // Process buying and bidding items
+ BuyAndBidItems(config);
}
+
+ return true;
}
-uint32 AuctionBotBuyer::GetBuyableEntry(BuyerConfiguration& config)
+// Collects information about item counts and minimum prices to SameItemInfo and updates EligibleItems - a list with new items eligible for bot to buy and bid
+// Returns count of items in AH that were eligible for being bought or bidded on by ahbot buyer (EligibleItems size)
+uint32 AuctionBotBuyer::GetItemInformation(BuyerConfiguration& config)
{
config.SameItemInfo.clear();
- uint32 count = 0;
time_t now = time(nullptr);
+ uint32 count = 0;
AuctionHouseObject* house = sAuctionMgr->GetAuctionsMap(config.GetHouseType());
for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = house->GetAuctionsBegin(); itr != house->GetAuctionsEnd(); ++itr)
{
AuctionEntry* entry = itr->second;
Item* item = sAuctionMgr->GetAItem(entry->itemGUIDLow);
- if (item)
+ if (!item)
+ continue;
+
+ BuyerItemInfo& itemInfo = config.SameItemInfo[item->GetEntry()];
+
+ // Update item entry's count and total bid prices
+ // This can be used later to determine the prices and chances to bid
+ uint32 itemBidPrice = entry->startbid / item->GetCount();
+ itemInfo.TotalBidPrice = itemInfo.TotalBidPrice + itemBidPrice;
+ itemInfo.BidItemCount++;
+
+ // Set minimum bid price
+ if (!itemInfo.MinBidPrice)
+ itemInfo.MinBidPrice = itemBidPrice;
+ else
+ itemBidPrice = std::min(itemInfo.MinBidPrice, itemBidPrice);
+
+ // Set minimum buyout price if item has buyout
+ if (entry->buyout)
+ {
+ // Update item entry's count and total buyout prices
+ // This can be used later to determine the prices and chances to buyout
+ uint32 itemBuyPrice = entry->buyout / item->GetCount();
+ itemInfo.TotalBuyPrice = itemInfo.TotalBuyPrice + itemBuyPrice;
+ itemInfo.BuyItemCount++;
+
+ if (!itemInfo.MinBuyPrice)
+ itemInfo.MinBuyPrice = itemBuyPrice;
+ else
+ itemInfo.MinBuyPrice = std::min(itemInfo.MinBuyPrice, itemBuyPrice);
+ }
+
+ // Add/update to EligibleItems if:
+ // has a bid by player or
+ // has no bids and not owned by bot
+ if ((entry->bid && entry->bidder) || (entry->owner && !entry->bid))
{
- ItemTemplate const * prototype = item->GetTemplate();
- if (prototype)
- {
- ++config.SameItemInfo[item->GetEntry()].ItemCount; // Structure constructor will make sure Element are correctly initialized if entry is created here.
- config.SameItemInfo[item->GetEntry()].BuyPrice = config.SameItemInfo[item->GetEntry()].BuyPrice + (itr->second->buyout / item->GetCount());
- config.SameItemInfo[item->GetEntry()].BidPrice = config.SameItemInfo[item->GetEntry()].BidPrice + (itr->second->startbid / item->GetCount());
- if (itr->second->buyout != 0)
- {
- if (itr->second->buyout / item->GetCount() < config.SameItemInfo[item->GetEntry()].MinBuyPrice)
- config.SameItemInfo[item->GetEntry()].MinBuyPrice = itr->second->buyout / item->GetCount();
- else if (config.SameItemInfo[item->GetEntry()].MinBuyPrice == 0)
- config.SameItemInfo[item->GetEntry()].MinBuyPrice = itr->second->buyout / item->GetCount();
- }
- if (itr->second->startbid / item->GetCount() < config.SameItemInfo[item->GetEntry()].MinBidPrice)
- config.SameItemInfo[item->GetEntry()].MinBidPrice = itr->second->startbid / item->GetCount();
- else if (config.SameItemInfo[item->GetEntry()].MinBidPrice == 0)
- config.SameItemInfo[item->GetEntry()].MinBidPrice = itr->second->startbid / item->GetCount();
-
- if (!entry->owner)
- {
-
- if (entry->bid != 0 && entry->bidder) // Add bid by player
- {
- config.CheckedEntry[entry->Id].LastExist = now;
- config.CheckedEntry[entry->Id].AuctionId = entry->Id;
- ++count;
- }
- }
- else
- {
- if (entry->bid != 0)
- {
- if (entry->bidder)
- {
- config.CheckedEntry[entry->Id].LastExist = now;
- config.CheckedEntry[entry->Id].AuctionId = entry->Id;
- ++count;
- }
- }
- else
- {
- config.CheckedEntry[entry->Id].LastExist = now;
- config.CheckedEntry[entry->Id].AuctionId = entry->Id;
- ++count;
- }
- }
- }
+ config.EligibleItems[entry->Id].LastExist = now;
+ config.EligibleItems[entry->Id].AuctionId = entry->Id;
+ ++count;
}
}
- TC_LOG_DEBUG("ahbot", "AHBot: %u items added to buyable vector for ah type: %u", count, config.GetHouseType());
+ TC_LOG_DEBUG("ahbot", "AHBot: %u items added to buyable/biddable vector for ah type: %u", count, config.GetHouseType());
TC_LOG_DEBUG("ahbot", "AHBot: SameItemInfo size = %u", (uint32)config.SameItemInfo.size());
return count;
}
-void AuctionBotBuyer::PrepareListOfEntry(BuyerConfiguration& config)
+// ahInfo can be NULL
+bool AuctionBotBuyer::RollBuyChance(const BuyerItemInfo* ahInfo, const Item* item, const AuctionEntry* auction, uint32 /*bidPrice*/)
{
- time_t now = time(nullptr) - 5;
+ if (!auction->buyout)
+ return false;
- for (CheckEntryMap::iterator itr = config.CheckedEntry.begin(); itr != config.CheckedEntry.end();)
- {
- if (itr->second.LastExist < (now - 5))
- config.CheckedEntry.erase(itr++);
- else
- ++itr;
- }
+ uint32 itemBuyPrice = auction->buyout / item->GetCount();
+ uint32 itemPrice = item->GetTemplate()->SellPrice ? item->GetTemplate()->SellPrice : GetVendorPrice(item->GetTemplate()->Quality);
+ // The AH cut needs to be added to the price, but we dont want a 100% chance to buy if the price is exactly AH default
+ itemPrice *= 1.4f;
- TC_LOG_DEBUG("ahbot", "AHBot: CheckedEntry size = %u", (uint32)config.CheckedEntry.size());
-}
+ // This value is between 0 and 100 and is used directly as the chance to buy or bid
+ // Value equal or above 100 means 100% chance and value below 0 means 0% chance
+ float chance = 100 / sqrt(itemBuyPrice / float(itemPrice));
-bool AuctionBotBuyer::IsBuyableEntry(uint32 buyoutPrice, double inGameBuyPrice, uint32 maxBuyablePrice, uint32 minBuyPrice, uint32 maxChance, uint32 chanceRatio)
-{
- double ratio = 0;
- uint32 chance = 0;
+ // If a player has bidded on item, have fifth of normal chance
+ if (auction->bidder)
+ chance = chance / 5;
- if (buyoutPrice <= minBuyPrice)
+ if (ahInfo)
{
- if (buyoutPrice <= maxBuyablePrice)
- chance = maxChance;
- else
- {
+ float avgBuyPrice = ahInfo->TotalBuyPrice / float(ahInfo->BuyItemCount);
- if (buyoutPrice > 0 && maxBuyablePrice > 0)
- {
- ratio = double(buyoutPrice) / double(maxBuyablePrice);
- if (ratio < 10)
- chance = maxChance - (ratio * maxChance / 10);
- else
- chance = 1;
- }
- }
- }
- else if (buyoutPrice <= inGameBuyPrice)
- {
- if (buyoutPrice <= maxBuyablePrice)
- chance = maxChance / 5;
- else
- {
+ TC_LOG_DEBUG("ahbot", "AHBot: buyout average: %.1f items with buyout: %u", avgBuyPrice, ahInfo->BuyItemCount);
- if (buyoutPrice > 0 && maxBuyablePrice > 0)
- {
- ratio = double(buyoutPrice) / double(maxBuyablePrice);
- if (ratio < 10)
- chance = (maxChance / 5) - (ratio * maxChance / 50);
- else
- chance = 1;
- }
- }
- }
- else if (buyoutPrice <= maxBuyablePrice)
- chance = maxChance / 10;
- else
- {
- if (buyoutPrice > 0 && maxBuyablePrice > 0)
+ // If there are more than 5 items on AH of this entry, try weigh in the average buyout price
+ if (ahInfo->BuyItemCount > 5)
{
- ratio = double(buyoutPrice) / double(maxBuyablePrice);
- if (ratio < 10)
- chance = (maxChance / 5) - (ratio* maxChance / 50);
- else
- chance = 0;
+ chance *= 1 / sqrt(itemBuyPrice / avgBuyPrice);
}
- else
- chance = 0;
}
- if (urand(1, chanceRatio) <= chance)
- {
- TC_LOG_DEBUG("ahbot", "AHBot: WIN BUY! Chance = %u, num = %u.", chance, chanceRatio);
- return true;
- }
- else
- {
- TC_LOG_DEBUG("ahbot", "AHBot: LOOSE BUY! Chance = %u, num = %u.", chance, chanceRatio);
- return false;
- }
+ // Add config weigh in for quality
+ chance *= GetChanceMultiplier(item->GetTemplate()->Quality) / 100.0f;
+
+ float rand = frand(0, 100);
+ bool win = rand <= chance;
+ TC_LOG_DEBUG("ahbot", "AHBot: %s BUY! chance = %.2f, price = %u, buyprice = %u.", win ? "WIN" : "LOSE", chance, itemPrice, itemBuyPrice);
+ return win;
}
-bool AuctionBotBuyer::IsBidableEntry(uint32 bidPrice, double inGameBuyPrice, double maxBidablePrice, uint32 minBidPrice, uint32 maxChance, uint32 chanceRatio)
+// ahInfo can be NULL
+bool AuctionBotBuyer::RollBidChance(const BuyerItemInfo* ahInfo, const Item* item, const AuctionEntry* auction, uint32 bidPrice)
{
- double ratio = 0;
- uint32 chance = 0;
+ uint32 itemBidPrice = bidPrice / item->GetCount();
+ uint32 itemPrice = item->GetTemplate()->SellPrice ? item->GetTemplate()->SellPrice : GetVendorPrice(item->GetTemplate()->Quality);
+ // The AH cut needs to be added to the price, but we dont want a 100% chance to buy if the price is exactly AH default
+ itemPrice *= 1.4f;
- if (bidPrice <= minBidPrice)
- {
- if (inGameBuyPrice != 0 && bidPrice < inGameBuyPrice - (inGameBuyPrice / 30))
- chance = maxChance;
- else
- {
- if (bidPrice < maxBidablePrice)
- {
- ratio = maxBidablePrice / bidPrice;
- if (ratio < 3)
- chance = maxChance / 500 * ratio;
- else
- chance = maxChance / 500;
- }
- }
- }
- else if (bidPrice < (inGameBuyPrice - (inGameBuyPrice / 30)))
- chance = (maxChance / 10);
- else
+ // This value is between 0 and 100 and is used directly as the chance to buy or bid
+ // Value equal or above 100 means 100% chance and value below 0 means 0% chance
+ float chance = 100 / sqrt(itemBidPrice / float(itemPrice));
+
+ if (ahInfo)
{
- if (bidPrice < maxBidablePrice)
+ float avgBidPrice = ahInfo->TotalBidPrice / float(ahInfo->BidItemCount);
+
+ TC_LOG_DEBUG("ahbot", "AHBot: Bid average: %.1f biddable item count: %u", avgBidPrice, ahInfo->BidItemCount);
+
+ // If there are more than 5 items on AH of this entry, try weigh in the average bid price
+ if (ahInfo->BidItemCount >= 5)
{
- ratio = maxBidablePrice / bidPrice;
- if (ratio < 4)
- chance = maxChance / 1000 * ratio;
- else
- chance = maxChance / 1000;
+ chance *= 1 / sqrt(itemBidPrice / avgBidPrice);
}
}
- if (urand(1, chanceRatio) <= chance)
- {
- TC_LOG_DEBUG("ahbot", "AHBot: WIN BID! Chance = %u, num = %u.", chance, chanceRatio);
- return true;
- }
- else
- {
- TC_LOG_DEBUG("ahbot", "AHBot: LOOSE BID! Chance = %u, num = %u.", chance, chanceRatio);
- return false;
- }
-}
+ // If a player has bidded on item, have fifth of normal chance
+ if (auction->bidder)
+ chance = chance / 5;
-void AuctionBotBuyer::PlaceBidToEntry(AuctionEntry* auction, uint32 bidPrice)
-{
- TC_LOG_DEBUG("ahbot", "AHBot: Bid placed to entry %u, %.2fg", auction->Id, float(bidPrice) / 10000.0f);
- auction->bid = bidPrice;
+ // Add config weigh in for quality
+ chance *= GetChanceMultiplier(item->GetTemplate()->Quality) / 100.0f;
+
+ float rand = frand(0, 100);
+ bool win = rand <= chance;
+ TC_LOG_DEBUG("ahbot", "AHBot: %s BID! chance = %.2f, price = %u, bidprice = %u.", win ? "WIN" : "LOSE", chance, itemPrice, itemBidPrice);
+ return win;
}
-void AuctionBotBuyer::BuyEntry(AuctionEntry* auction)
+// Removes items from EligibleItems that we shouldnt buy or bid on
+// The last existed time on them should be older than now
+void AuctionBotBuyer::PrepareListOfEntry(BuyerConfiguration& config)
{
- TC_LOG_DEBUG("ahbot", "AHBot: Entry %u bought at %.2fg", auction->Id, float(auction->buyout) / 10000.0f);
- auction->bid = auction->buyout;
+ // now - 5 seconds to leave out all old entries but keep the ones just updated a moment ago
+ time_t now = time(nullptr) - 5;
+
+ for (CheckEntryMap::iterator itr = config.EligibleItems.begin(); itr != config.EligibleItems.end();)
+ {
+ if (itr->second.LastExist < now)
+ config.EligibleItems.erase(itr++);
+ else
+ ++itr;
+ }
+
+ TC_LOG_DEBUG("ahbot", "AHBot: EligibleItems size = %u", (uint32)config.EligibleItems.size());
}
-void AuctionBotBuyer::AddNewAuctionBuyerBotBid(BuyerConfiguration& config)
+// Tries to bid and buy items based on their prices and chances set in configs
+void AuctionBotBuyer::BuyAndBidItems(BuyerConfiguration& config)
{
+ time_t now = time(nullptr);
AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(config.GetHouseType());
+ CheckEntryMap& items = config.EligibleItems;
- PrepareListOfEntry(config);
-
- time_t now = time(nullptr);
- uint32 buyCycles;
- if (config.CheckedEntry.size() > sAuctionBotConfig->GetItemPerCycleBoost())
+ // Max amount of items to buy or bid
+ uint32 cycles = sAuctionBotConfig->GetItemPerCycleNormal();
+ if (items.size() > sAuctionBotConfig->GetItemPerCycleBoost())
{
- buyCycles = sAuctionBotConfig->GetItemPerCycleBoost();
+ // set more cycles if there is a huge influx of items
+ cycles = sAuctionBotConfig->GetItemPerCycleBoost();
TC_LOG_DEBUG("ahbot", "AHBot: Boost value used for Buyer! (if this happens often adjust both ItemsPerCycle in worldserver.conf)");
}
- else
- buyCycles = sAuctionBotConfig->GetItemPerCycleNormal();
- for (CheckEntryMap::iterator itr = config.CheckedEntry.begin(); itr != config.CheckedEntry.end();)
+ // Process items eligible to be bidded or bought
+ CheckEntryMap::iterator itr = items.begin();
+ while (cycles && itr != items.end())
{
AuctionEntry* auction = auctionHouse->GetAuction(itr->second.AuctionId);
- if (!auction) // is auction not active now
+ if (!auction)
{
- TC_LOG_DEBUG("ahbot", "AHBot: Entry %u doesn't exists, perhaps bought already?",
- itr->second.AuctionId);
-
- config.CheckedEntry.erase(itr++);
+ TC_LOG_DEBUG("ahbot", "AHBot: Entry %u doesn't exists, perhaps bought already?", itr->second.AuctionId);
+ items.erase(itr++);
continue;
}
- if (itr->second.LastChecked != 0 && (now - itr->second.LastChecked) <= _checkInterval)
+ // Check if the item has been checked once before
+ // If it has been checked and it was recently, skip it
+ if (itr->second.LastChecked && (now - itr->second.LastChecked) <= _checkInterval)
{
TC_LOG_DEBUG("ahbot", "AHBot: In time interval wait for entry %u!", auction->Id);
++itr;
continue;
}
- if (buyCycles == 0)
- break;
-
- uint32 maxChance = 5000;
-
Item* item = sAuctionMgr->GetAItem(auction->itemGUIDLow);
- if (!item) // auction item not accessible, possible auction in payment pending mode
+ if (!item)
{
- config.CheckedEntry.erase(itr++);
+ // auction item not accessible, possible auction in payment pending mode
+ items.erase(itr++);
continue;
}
- ItemTemplate const* prototype = item->GetTemplate();
-
- uint32 basePrice = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYPRICE_BUYER) ? prototype->BuyPrice : prototype->SellPrice;
- basePrice *= item->GetCount();
-
- uint32 maxBuyablePrice = (basePrice * config.BuyerPriceRatio) / 100;
- BuyerItemInfoMap::iterator sameItemItr = config.SameItemInfo.find(item->GetEntry());
- uint32 buyoutPrice = auction->buyout / item->GetCount();
-
+ // price to bid if bidding
uint32 bidPrice;
- uint32 bidPriceByItem;
- uint32 minBidPrice;
- uint32 minBuyPrice;
if (auction->bid >= auction->startbid)
{
- bidPrice = auction->GetAuctionOutBid();
- bidPriceByItem = auction->bid / item->GetCount();
+ // get bid price to outbid previous bidder
+ bidPrice = auction->bid + auction->GetAuctionOutBid();
}
else
{
+ // no previous bidders - use starting bid
bidPrice = auction->startbid;
- bidPriceByItem = auction->startbid / item->GetCount();
}
- double inGameBuyPrice;
- double inGameBidPrice;
- if (sameItemItr == config.SameItemInfo.end())
- {
- inGameBuyPrice = 0;
- inGameBidPrice = 0;
- minBidPrice = 0;
- minBuyPrice = 0;
- }
- else
- {
- if (sameItemItr->second.ItemCount == 1)
- maxBuyablePrice = maxBuyablePrice * 5; // if only one item exist can be bought if the price is high too.
- inGameBuyPrice = sameItemItr->second.BuyPrice / sameItemItr->second.ItemCount;
- inGameBidPrice = sameItemItr->second.BidPrice / sameItemItr->second.ItemCount;
- minBidPrice = sameItemItr->second.MinBidPrice;
- minBuyPrice = sameItemItr->second.MinBuyPrice;
- }
+ const BuyerItemInfo* ahInfo = nullptr;
+ BuyerItemInfoMap::const_iterator sameItemItr = config.SameItemInfo.find(item->GetEntry());
+ if (sameItemItr != config.SameItemInfo.end())
+ ahInfo = &sameItemItr->second;
- uint32 maxBidablePrice = maxBuyablePrice - (maxBuyablePrice / 30); // Max Bidable price defined to 70% of max buyable price
+ TC_LOG_DEBUG("ahbot", "AHBot: Rolling for AHentry %u:", auction->Id);
- TC_LOG_DEBUG("ahbot", "AHBot: Auction added with data:");
- TC_LOG_DEBUG("ahbot", "AHBot: MaxPrice of Entry %u is %.1fg.", itr->second.AuctionId, double(maxBuyablePrice) / 10000.0);
- TC_LOG_DEBUG("ahbot", "AHBot: GamePrice buy=%.1fg, bid=%.1fg.", inGameBuyPrice / 10000, inGameBidPrice / 10000);
- TC_LOG_DEBUG("ahbot", "AHBot: Minimal price see in AH Buy=%ug, Bid=%ug.",
- minBuyPrice / 10000, minBidPrice / 10000);
- TC_LOG_DEBUG("ahbot", "AHBot: Actual Entry price, Buy=%ug, Bid=%ug.", buyoutPrice / 10000, bidPrice / 10000);
+ // Roll buy and bid chances
+ bool successBuy = RollBuyChance(ahInfo, item, auction, bidPrice);
+ bool successBid = RollBidChance(ahInfo, item, auction, bidPrice);
- if (!auction->owner) // Original auction owner
- maxChance = maxChance / 5; // if Owner is AHBot this mean player placed bid on this auction. We divide by 5 chance for AhBuyer to place bid on it. (This make more challenge than ignore entry)
- if (auction->buyout != 0) // Is the item directly buyable?
- {
- if (IsBuyableEntry(buyoutPrice, inGameBuyPrice, maxBuyablePrice, minBuyPrice, maxChance, config.FactionChance))
- {
- if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, minBidPrice, maxChance / 2, config.FactionChance))
- {
- if (urand(0, 5) == 0)
- PlaceBidToEntry(auction, bidPrice);
- else
- BuyEntry(auction);
- }
- else
- BuyEntry(auction);
- }
- else if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, minBidPrice, maxChance / 2, config.FactionChance))
- PlaceBidToEntry(auction, bidPrice);
- }
- else if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, minBidPrice, maxChance, config.FactionChance))
- PlaceBidToEntry(auction, bidPrice);
+ // If roll bidding succesfully and bid price is above buyout -> buyout
+ // If roll for buying was successful but not for bid, buyout directly
+ // If roll bidding was also successful, buy the entry with 20% chance
+ // - Better bid than buy since the item is bought by bot if no player bids after
+ // Otherwise bid if roll for bid was successful
+ if ((auction->buyout && successBid && bidPrice >= auction->buyout) ||
+ (successBuy && (!successBid || urand(1, 5) == 1)))
+ BuyEntry(auction, auctionHouse); // buyout
+ else if (successBid)
+ PlaceBidToEntry(auction, bidPrice); // bid
itr->second.LastChecked = now;
- --buyCycles;
-
+ --cycles;
++itr;
}
+
+ // Clear not needed entries
+ config.SameItemInfo.clear();
}
-bool AuctionBotBuyer::Update(AuctionHouseType houseType)
+uint32 AuctionBotBuyer::GetVendorPrice(uint32 quality)
{
- if (sAuctionBotConfig->GetConfigBuyerEnabled(houseType))
+ switch (quality)
{
- TC_LOG_DEBUG("ahbot", "AHBot: %s buying ...", AuctionBotConfig::GetHouseTypeName(houseType));
- if (GetBuyableEntry(_houseConfig[houseType]) > 0)
- AddNewAuctionBuyerBotBid(_houseConfig[houseType]);
- return true;
+ case ITEM_QUALITY_POOR:
+ return sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_BASEPRICE_GRAY);
+ case ITEM_QUALITY_NORMAL:
+ return sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_BASEPRICE_WHITE);
+ case ITEM_QUALITY_UNCOMMON:
+ return sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_BASEPRICE_GREEN);
+ case ITEM_QUALITY_RARE:
+ return sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_BASEPRICE_BLUE);
+ case ITEM_QUALITY_EPIC:
+ return sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_BASEPRICE_PURPLE);
+ case ITEM_QUALITY_LEGENDARY:
+ return sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_BASEPRICE_ORANGE);
+ case ITEM_QUALITY_ARTIFACT:
+ return sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_BASEPRICE_YELLOW);
+ default:
+ return 1 * SILVER;
}
+}
+
+uint32 AuctionBotBuyer::GetChanceMultiplier(uint32 quality)
+{
+ switch (quality)
+ {
+ case ITEM_QUALITY_POOR:
+ return sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_GRAY);
+ case ITEM_QUALITY_NORMAL:
+ return sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_WHITE);
+ case ITEM_QUALITY_UNCOMMON:
+ return sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_GREEN);
+ case ITEM_QUALITY_RARE:
+ return sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_BLUE);
+ case ITEM_QUALITY_EPIC:
+ return sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_PURPLE);
+ case ITEM_QUALITY_LEGENDARY:
+ return sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_ORANGE);
+ case ITEM_QUALITY_ARTIFACT:
+ return sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_CHANCEMULTIPLIER_YELLOW);
+ default:
+ return 100;
+ }
+}
+
+// Buys the auction and does necessary actions to complete the buyout
+void AuctionBotBuyer::BuyEntry(AuctionEntry* auction, AuctionHouseObject* auctionHouse)
+{
+ TC_LOG_DEBUG("ahbot", "AHBot: Entry %u bought at %.2fg", auction->Id, float(auction->buyout) / GOLD);
+
+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
+
+ // Send mail to previous bidder if any
+ if (auction->bidder)
+ sAuctionMgr->SendAuctionOutbiddedMail(auction, auction->buyout, NULL, trans);
+
+ // Set bot as bidder and set new bid amount
+ auction->bidder = 0;
+ auction->bid = auction->buyout;
+
+ // Mails must be under transaction control too to prevent data loss
+ sAuctionMgr->SendAuctionSalePendingMail(auction, trans);
+ sAuctionMgr->SendAuctionSuccessfulMail(auction, trans);
+ sAuctionMgr->SendAuctionWonMail(auction, trans);
+
+ // Delete auction from DB
+ auction->DeleteFromDB(trans);
+
+ // Remove auction item and auction from memory
+ sAuctionMgr->RemoveAItem(auction->itemGUIDLow);
+ auctionHouse->RemoveAuction(auction);
+
+ // Run SQLs
+ CharacterDatabase.CommitTransaction(trans);
+}
+
+// Bids on the auction and does the necessary actions for bidding
+void AuctionBotBuyer::PlaceBidToEntry(AuctionEntry* auction, uint32 bidPrice)
+{
+ TC_LOG_DEBUG("ahbot", "AHBot: Bid placed to entry %u, %.2fg", auction->Id, float(bidPrice) / GOLD);
+
+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
+
+ // Send mail to previous bidder if any
+ if (auction->bidder)
+ sAuctionMgr->SendAuctionOutbiddedMail(auction, bidPrice, NULL, trans);
+
+ // Set bot as bidder and set new bid amount
+ auction->bidder = 0;
+ auction->bid = bidPrice;
+
+ // Update auction to DB
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_AUCTION_BID);
+ stmt->setUInt32(0, auction->bidder);
+ stmt->setUInt32(1, auction->bid);
+ stmt->setUInt32(2, auction->Id);
+ trans->Append(stmt);
- return false;
+ // Run SQLs
+ CharacterDatabase.CommitTransaction(trans);
}
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h
index bd8d6e46f0e..c030731cb40 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h
@@ -24,7 +24,7 @@
struct BuyerAuctionEval
{
- BuyerAuctionEval(): AuctionId(0), LastChecked(0), LastExist(0) {}
+ BuyerAuctionEval() : AuctionId(0), LastChecked(0), LastExist(0) { }
uint32 AuctionId;
time_t LastChecked;
@@ -33,13 +33,14 @@ struct BuyerAuctionEval
struct BuyerItemInfo
{
- BuyerItemInfo(): ItemCount(0), BuyPrice(0), BidPrice(0), MinBuyPrice(0), MinBidPrice(0) {}
+ BuyerItemInfo() : BidItemCount(0), BuyItemCount(0), MinBuyPrice(0), MinBidPrice(0), TotalBuyPrice(0), TotalBidPrice(0) { }
- uint32 ItemCount;
- double BuyPrice;
- double BidPrice;
+ uint32 BidItemCount;
+ uint32 BuyItemCount;
uint32 MinBuyPrice;
uint32 MinBidPrice;
+ double TotalBuyPrice;
+ double TotalBidPrice;
};
typedef std::map<uint32, BuyerItemInfo> BuyerItemInfoMap;
@@ -47,7 +48,7 @@ typedef std::map<uint32, BuyerAuctionEval> CheckEntryMap;
struct BuyerConfiguration
{
- BuyerConfiguration(): FactionChance(3), BuyerEnabled(false), BuyerPriceRatio(100), _houseType(AUCTION_HOUSE_NEUTRAL) {}
+ BuyerConfiguration() : BuyerEnabled(false), _houseType(AUCTION_HOUSE_NEUTRAL) { }
void Initialize(AuctionHouseType houseType)
{
@@ -57,10 +58,8 @@ struct BuyerConfiguration
AuctionHouseType GetHouseType() const { return _houseType; }
BuyerItemInfoMap SameItemInfo;
- CheckEntryMap CheckedEntry;
- uint32 FactionChance;
+ CheckEntryMap EligibleItems;
bool BuyerEnabled;
- uint32 BuyerPriceRatio;
private:
AuctionHouseType _houseType;
@@ -78,19 +77,23 @@ public:
bool Update(AuctionHouseType houseType) override;
void LoadConfig();
- void AddNewAuctionBuyerBotBid(BuyerConfiguration& config);
+ void BuyAndBidItems(BuyerConfiguration& config);
private:
uint32 _checkInterval;
BuyerConfiguration _houseConfig[MAX_AUCTION_HOUSE_TYPE];
void LoadBuyerValues(BuyerConfiguration& config);
- bool IsBuyableEntry(uint32 buyoutPrice, double inGameBuyPrice, uint32 maxBuyablePrice, uint32 minBuyPrice, uint32 maxChance, uint32 chanceRatio);
- bool IsBidableEntry(uint32 bidPrice, double inGameBuyPrice, double maxBidablePrice, uint32 minBidPrice, uint32 maxChance, uint32 chanceRatio);
+
+ // ahInfo can be NULL
+ bool RollBuyChance(const BuyerItemInfo* ahInfo, const Item* item, const AuctionEntry* auction, uint32 bidPrice);
+ bool RollBidChance(const BuyerItemInfo* ahInfo, const Item* item, const AuctionEntry* auction, uint32 bidPrice);
void PlaceBidToEntry(AuctionEntry* auction, uint32 bidPrice);
- void BuyEntry(AuctionEntry* auction);
+ void BuyEntry(AuctionEntry* auction, AuctionHouseObject* auctionHouse);
void PrepareListOfEntry(BuyerConfiguration& config);
- uint32 GetBuyableEntry(BuyerConfiguration& config);
+ uint32 GetItemInformation(BuyerConfiguration& config);
+ uint32 GetVendorPrice(uint32 quality);
+ uint32 GetChanceMultiplier(uint32 quality);
};
#endif
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
index dff4077d569..733bd5e9ec8 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
@@ -44,14 +44,14 @@ bool AuctionBotSeller::Initialize()
{
std::stringstream includeStream(sAuctionBotConfig->GetAHBotIncludes());
std::string temp;
- while (getline(includeStream, temp, ','))
+ while (std::getline(includeStream, temp, ','))
includeItems.push_back(atoi(temp.c_str()));
}
{
std::stringstream excludeStream(sAuctionBotConfig->GetAHBotExcludes());
std::string temp;
- while (getline(excludeStream, temp, ','))
+ while (std::getline(excludeStream, temp, ','))
excludeItems.push_back(atoi(temp.c_str()));
}
diff --git a/src/server/game/Battlegrounds/ArenaTeam.cpp b/src/server/game/Battlegrounds/ArenaTeam.cpp
index 7ed05205f39..3b7e9ac3f33 100644
--- a/src/server/game/Battlegrounds/ArenaTeam.cpp
+++ b/src/server/game/Battlegrounds/ArenaTeam.cpp
@@ -179,7 +179,7 @@ bool ArenaTeam::AddMember(ObjectGuid playerGuid)
player->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_MEMBER, 1);
}
- TC_LOG_INFO("bg.arena", "Player: %s [%s] joined arena team type: %u [Id: %u, Name: %s].", playerName.c_str(), playerGuid.ToString().c_str(), GetType(), GetId(), GetName().c_str());
+ TC_LOG_DEBUG("bg.arena", "Player: %s [%s] joined arena team type: %u [Id: %u, Name: %s].", playerName.c_str(), playerGuid.ToString().c_str(), GetType(), GetId(), GetName().c_str());
return true;
}
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp
index e091df160a3..03b4fe3dea6 100644
--- a/src/server/game/Battlegrounds/Battleground.cpp
+++ b/src/server/game/Battlegrounds/Battleground.cpp
@@ -510,7 +510,7 @@ inline void Battleground::_ProcessJoin(uint32 diff)
if (!aura->IsPermanent()
&& aura->GetDuration() <= 30*IN_MILLISECONDS
&& aurApp->IsPositive()
- && (!(aura->GetSpellInfo()->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
+ && (!aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
&& (!aura->HasEffectType(SPELL_AURA_MOD_INVISIBILITY)))
player->RemoveAura(iter);
else
diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt
index eb8627efa44..2f7bc4a9c69 100644
--- a/src/server/game/CMakeLists.txt
+++ b/src/server/game/CMakeLists.txt
@@ -110,6 +110,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/SFMT
+ ${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/zlib
${CMAKE_SOURCE_DIR}/src/server/collision
${CMAKE_SOURCE_DIR}/src/server/collision/Management
diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp
index 44df1097dd4..3195de9b6bd 100644
--- a/src/server/game/Chat/Chat.cpp
+++ b/src/server/game/Chat/Chat.cpp
@@ -104,17 +104,6 @@ ChatCommand* ChatHandler::getCommandTable()
return commandTableCache;
}
-std::string ChatHandler::PGetParseString(uint32 entry, ...) const
-{
- const char *format = GetTrinityString(entry);
- char str[1024];
- va_list ap;
- va_start(ap, entry);
- vsnprintf(str, 1024, format, ap);
- va_end(ap);
- return std::string(str);
-}
-
char const* ChatHandler::GetTrinityString(uint32 entry) const
{
return m_session->GetTrinityString(entry);
@@ -258,27 +247,6 @@ void ChatHandler::SendSysMessage(uint32 entry)
SendSysMessage(GetTrinityString(entry));
}
-void ChatHandler::PSendSysMessage(uint32 entry, ...)
-{
- const char *format = GetTrinityString(entry);
- va_list ap;
- char str [2048];
- va_start(ap, entry);
- vsnprintf(str, 2048, format, ap);
- va_end(ap);
- SendSysMessage(str);
-}
-
-void ChatHandler::PSendSysMessage(const char *format, ...)
-{
- va_list ap;
- char str [2048];
- va_start(ap, format);
- vsnprintf(str, 2048, format, ap);
- va_end(ap);
- SendSysMessage(str);
-}
-
bool ChatHandler::ExecuteCommandInTable(ChatCommand* table, const char* text, std::string const& fullcmd)
{
char const* oldtext = text;
diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h
index d712740bd7d..ba59245cdaa 100644
--- a/src/server/game/Chat/Chat.h
+++ b/src/server/game/Chat/Chat.h
@@ -20,6 +20,7 @@
#define TRINITYCORE_CHAT_H
#include "SharedDefines.h"
+#include "StringFormat.h"
#include "WorldSession.h"
#include "RBAC.h"
@@ -68,9 +69,24 @@ class ChatHandler
virtual void SendSysMessage(char const* str);
void SendSysMessage(uint32 entry);
- void PSendSysMessage(char const* format, ...) ATTR_PRINTF(2, 3);
- void PSendSysMessage(uint32 entry, ...);
- std::string PGetParseString(uint32 entry, ...) const;
+
+ template<typename... Args>
+ void PSendSysMessage(const char* fmt, Args const&... args)
+ {
+ SendSysMessage(Trinity::StringFormat(fmt, args...).c_str());
+ }
+
+ template<typename... Args>
+ void PSendSysMessage(uint32 entry, Args const&... args)
+ {
+ SendSysMessage(PGetParseString(entry, args...).c_str());
+ }
+
+ template<typename... Args>
+ std::string PGetParseString(uint32 entry, Args const&... args) const
+ {
+ return Trinity::StringFormat(GetTrinityString(entry), args...);
+ }
bool ParseCommands(const char* text);
diff --git a/src/server/game/Chat/ChatLink.cpp b/src/server/game/Chat/ChatLink.cpp
index 1eb330cc9e1..732a770645b 100644
--- a/src/server/game/Chat/ChatLink.cpp
+++ b/src/server/game/Chat/ChatLink.cpp
@@ -285,7 +285,7 @@ bool SpellChatLink::ValidateName(char* buffer, const char* context)
ChatLink::ValidateName(buffer, context);
// spells with that flag have a prefix of "$PROFESSION: "
- if (_spell->Attributes & SPELL_ATTR0_TRADESPELL)
+ if (_spell->HasAttribute(SPELL_ATTR0_TRADESPELL))
{
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(_spell->Id);
if (bounds.first == bounds.second)
diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp
index 43057409b9b..cd108e54b9f 100644
--- a/src/server/game/Combat/ThreatManager.cpp
+++ b/src/server/game/Combat/ThreatManager.cpp
@@ -79,7 +79,7 @@ bool ThreatCalcHelper::isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellIn
return false;
// spell not causing threat
- if (threatSpell && threatSpell->AttributesEx & SPELL_ATTR1_NO_THREAT)
+ if (threatSpell && threatSpell->HasAttribute(SPELL_ATTR1_NO_THREAT))
return false;
ASSERT(hatingUnit->GetTypeId() == TYPEID_UNIT);
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index eb3d1708675..8400e4cee00 100644
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -99,7 +99,8 @@ ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[COND
{ "Distance", true, true, true },
{ "Alive", false, false, false },
{ "Health Value", true, true, false },
- { "Health Pct", true, true, false }
+ { "Health Pct", true, true, false },
+ { "Realm Achievement", true, false, false }
};
// Checks if object meets the condition
@@ -416,6 +417,13 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
condMeets = creature->GetCreatureTemplate()->type == ConditionValue1;
break;
}
+ case CONDITION_REALM_ACHIEVEMENT:
+ {
+ AchievementEntry const* achievement = sAchievementMgr->GetAchievement(ConditionValue1);
+ if (achievement && sAchievementMgr->IsRealmCompleted(achievement, std::numeric_limits<uint32>::max()))
+ condMeets = true;
+ break;
+ }
default:
condMeets = false;
break;
@@ -580,6 +588,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition()
case CONDITION_CREATURE_TYPE:
mask |= GRID_MAP_TYPE_MASK_CREATURE;
break;
+ case CONDITION_REALM_ACHIEVEMENT:
+ mask |= GRID_MAP_TYPE_MASK_ALL;
+ break;
default:
ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!");
break;
@@ -2056,6 +2067,16 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
case CONDITION_PHASEMASK:
case CONDITION_ALIVE:
break;
+ case CONDITION_REALM_ACHIEVEMENT:
+ {
+ AchievementEntry const* achievement = sAchievementMgr->GetAchievement(cond->ConditionValue1);
+ if (!achievement)
+ {
+ TC_LOG_ERROR("sql.sql", "%s has non existing realm first achivement id (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1);
+ return false;
+ }
+ break;
+ }
default:
break;
}
diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h
index 4ca27f0d986..1fdd011633e 100644
--- a/src/server/game/Conditions/ConditionMgr.h
+++ b/src/server/game/Conditions/ConditionMgr.h
@@ -72,7 +72,8 @@ enum ConditionTypes
CONDITION_ALIVE = 36, // 0 0 0 true if unit is alive
CONDITION_HP_VAL = 37, // hpVal ComparisonType 0 true if unit's hp matches given value
CONDITION_HP_PCT = 38, // hpPct ComparisonType 0 true if unit's hp matches given pct
- CONDITION_MAX = 39 // MAX
+ CONDITION_REALM_ACHIEVEMENT = 39, // achievement_id 0 0 true if realm achievement is complete
+ CONDITION_MAX = 40 // MAX
};
/*! Documentation on implementing a new ConditionSourceType:
diff --git a/src/server/game/DungeonFinding/LFG.cpp b/src/server/game/DungeonFinding/LFG.cpp
index ab06eff7148..8ec638128d8 100644
--- a/src/server/game/DungeonFinding/LFG.cpp
+++ b/src/server/game/DungeonFinding/LFG.cpp
@@ -91,9 +91,6 @@ std::string GetStateString(LfgState state)
case LFG_STATE_DUNGEON:
entry = LANG_LFG_STATE_DUNGEON;
break;
- case LFG_STATE_BOOT:
- entry = LANG_LFG_STATE_BOOT;
- break;
case LFG_STATE_FINISHED_DUNGEON:
entry = LANG_LFG_STATE_FINISHED_DUNGEON;
break;
diff --git a/src/server/game/DungeonFinding/LFG.h b/src/server/game/DungeonFinding/LFG.h
index 6145a2324b1..84a25ee49ad 100644
--- a/src/server/game/DungeonFinding/LFG.h
+++ b/src/server/game/DungeonFinding/LFG.h
@@ -64,8 +64,8 @@ enum LfgState
LFG_STATE_ROLECHECK, // Rolecheck active
LFG_STATE_QUEUED, // Queued
LFG_STATE_PROPOSAL, // Proposal active
- LFG_STATE_BOOT, // Vote kick active
- LFG_STATE_DUNGEON, // In LFG Group, in a Dungeon
+ //LFG_STATE_BOOT, // Vote kick active
+ LFG_STATE_DUNGEON = 5, // In LFG Group, in a Dungeon
LFG_STATE_FINISHED_DUNGEON, // In LFG Group, in a finished Dungeon
LFG_STATE_RAIDBROWSER // Using Raid finder
};
diff --git a/src/server/game/DungeonFinding/LFGGroupData.cpp b/src/server/game/DungeonFinding/LFGGroupData.cpp
index 2ab1e0b1e7e..aa6916a39a4 100644
--- a/src/server/game/DungeonFinding/LFGGroupData.cpp
+++ b/src/server/game/DungeonFinding/LFGGroupData.cpp
@@ -22,7 +22,7 @@ namespace lfg
{
LfgGroupData::LfgGroupData(): m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE),
- m_Leader(), m_Dungeon(0), m_KicksLeft(LFG_GROUP_MAX_KICKS)
+ m_Leader(), m_Dungeon(0), m_KicksLeft(LFG_GROUP_MAX_KICKS), m_VoteKickActive(false)
{ }
LfgGroupData::~LfgGroupData()
@@ -126,4 +126,14 @@ uint8 LfgGroupData::GetKicksLeft() const
return m_KicksLeft;
}
+void LfgGroupData::SetVoteKick(bool active)
+{
+ m_VoteKickActive = active;
+}
+
+bool LfgGroupData::IsVoteKickActive() const
+{
+ return m_VoteKickActive;
+}
+
} // namespace lfg
diff --git a/src/server/game/DungeonFinding/LFGGroupData.h b/src/server/game/DungeonFinding/LFGGroupData.h
index 8d8f1dc0f3d..b573e7c309e 100644
--- a/src/server/game/DungeonFinding/LFGGroupData.h
+++ b/src/server/game/DungeonFinding/LFGGroupData.h
@@ -66,6 +66,9 @@ class LfgGroupData
// VoteKick
uint8 GetKicksLeft() const;
+ void SetVoteKick(bool active);
+ bool IsVoteKickActive() const;
+
private:
// General
LfgState m_State; ///< State if group in LFG
@@ -76,6 +79,7 @@ class LfgGroupData
uint32 m_Dungeon; ///< Dungeon entry
// Vote Kick
uint8 m_KicksLeft; ///< Number of kicks left
+ bool m_VoteKickActive;
};
} // namespace lfg
diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp
index d670e0a2949..93ebeca9780 100644
--- a/src/server/game/DungeonFinding/LFGMgr.cpp
+++ b/src/server/game/DungeonFinding/LFGMgr.cpp
@@ -311,9 +311,8 @@ void LFGMgr::Update(uint32 diff)
ObjectGuid pguid = itVotes->first;
if (pguid != boot.victim)
SendLfgBootProposalUpdate(pguid, boot);
- SetState(pguid, LFG_STATE_DUNGEON);
}
- SetState(itBoot->first, LFG_STATE_DUNGEON);
+ SetVoteKick(itBoot->first, false);
BootsStore.erase(itBoot);
}
}
@@ -643,7 +642,6 @@ void LFGMgr::LeaveLfg(ObjectGuid guid)
break;
case LFG_STATE_DUNGEON:
case LFG_STATE_FINISHED_DUNGEON:
- case LFG_STATE_BOOT:
if (guid != gguid) // Player
SetState(guid, LFG_STATE_NONE);
break;
@@ -755,7 +753,7 @@ void LFGMgr::GetCompatibleDungeons(LfgDungeonSet& dungeons, GuidSet const& playe
{
ObjectGuid guid = (*it);
LfgLockMap const& cachedLockMap = GetLockedDungeons(guid);
- Player* player = ObjectAccessor::FindPlayer(guid);
+ Player* player = ObjectAccessor::FindConnectedPlayer(guid);
for (LfgLockMap::const_iterator it2 = cachedLockMap.begin(); it2 != cachedLockMap.end() && !dungeons.empty(); ++it2)
{
uint32 dungeonId = (it2->first & 0x00FFFFFF); // Compare dungeon ids
@@ -893,7 +891,7 @@ void LFGMgr::MakeNewGroup(LfgProposal const& proposal)
for (GuidList::const_iterator it = players.begin(); it != players.end(); ++it)
{
ObjectGuid pguid = (*it);
- Player* player = ObjectAccessor::FindPlayer(pguid);
+ Player* player = ObjectAccessor::FindConnectedPlayer(pguid);
if (!player)
continue;
@@ -1156,7 +1154,7 @@ void LFGMgr::RemoveProposal(LfgProposalContainer::iterator itProposal, LfgUpdate
*/
void LFGMgr::InitBoot(ObjectGuid gguid, ObjectGuid kicker, ObjectGuid victim, std::string const& reason)
{
- SetState(gguid, LFG_STATE_BOOT);
+ SetVoteKick(gguid, true);
LfgPlayerBoot& boot = BootsStore[gguid];
boot.inProgress = true;
@@ -1170,7 +1168,6 @@ void LFGMgr::InitBoot(ObjectGuid gguid, ObjectGuid kicker, ObjectGuid victim, st
for (GuidSet::const_iterator itr = players.begin(); itr != players.end(); ++itr)
{
ObjectGuid guid = (*itr);
- SetState(guid, LFG_STATE_BOOT);
boot.votes[guid] = LFG_ANSWER_PENDING;
}
@@ -1227,13 +1224,10 @@ void LFGMgr::UpdateBoot(ObjectGuid guid, bool accept)
{
ObjectGuid pguid = itVotes->first;
if (pguid != boot.victim)
- {
- SetState(pguid, LFG_STATE_DUNGEON);
SendLfgBootProposalUpdate(pguid, boot);
- }
}
- SetState(gguid, LFG_STATE_DUNGEON);
+ SetVoteKick(gguid, false);
if (agreeNum == LFG_GROUP_KICK_VOTES_NEEDED) // Vote passed - Kick player
{
if (Group* group = sGroupMgr->GetGroupByGUID(gguid.GetCounter()))
@@ -1495,12 +1489,12 @@ LfgState LFGMgr::GetState(ObjectGuid guid)
if (guid.IsGroup())
{
state = GroupsStore[guid].GetState();
- TC_LOG_TRACE("lfg.data.group.state.get", "Group: %s, State: %u", guid.ToString().c_str(), state);
+ TC_LOG_TRACE("lfg.data.group.state.get", "Group: %s, State: %s", guid.ToString().c_str(), GetStateString(state).c_str());
}
else
{
state = PlayersStore[guid].GetState();
- TC_LOG_TRACE("lfg.data.player.state.get", "Player: %s, State: %u", guid.ToString().c_str(), state);
+ TC_LOG_TRACE("lfg.data.player.state.get", "Player: %s, State: %s", guid.ToString().c_str(), GetStateString(state).c_str());
}
return state;
@@ -1523,6 +1517,16 @@ LfgState LFGMgr::GetOldState(ObjectGuid guid)
return state;
}
+bool LFGMgr::IsVoteKickActive(ObjectGuid gguid)
+{
+ ASSERT(gguid.IsGroup());
+
+ bool active = GroupsStore[gguid].IsVoteKickActive();
+ TC_LOG_TRACE("lfg.data.group.votekick.get", "Group: %s, Active: %d", gguid.ToString().c_str(), active);
+
+ return active;
+}
+
uint32 LFGMgr::GetDungeon(ObjectGuid guid, bool asId /*= true */)
{
uint32 dungeon = GroupsStore[guid].GetDungeon(asId);
@@ -1566,7 +1570,7 @@ LfgLockMap const LFGMgr::GetLockedDungeons(ObjectGuid guid)
{
TC_LOG_TRACE("lfg.data.player.dungeons.locked.get", "Player: %s, LockedDungeons.", guid.ToString().c_str());
LfgLockMap lock;
- Player* player = ObjectAccessor::FindPlayer(guid);
+ Player* player = ObjectAccessor::FindConnectedPlayer(guid);
if (!player)
{
TC_LOG_WARN("lfg.data.player.dungeons.locked.get", "Player: %s not ingame while retrieving his LockedDungeons.", guid.ToString().c_str());
@@ -1683,6 +1687,17 @@ void LFGMgr::SetState(ObjectGuid guid, LfgState state)
}
}
+void LFGMgr::SetVoteKick(ObjectGuid gguid, bool active)
+{
+ ASSERT(gguid.IsGroup());
+
+ LfgGroupData& data = GroupsStore[gguid];
+ TC_LOG_TRACE("lfg.data.group.votekick.set", "Group: %s, New state: %d, Previous: %d",
+ gguid.ToString().c_str(), active, data.IsVoteKickActive());
+
+ data.SetVoteKick(active);
+}
+
void LFGMgr::SetDungeon(ObjectGuid guid, uint32 dungeon)
{
TC_LOG_TRACE("lfg.data.group.dungeon.set", "Group: %s, Dungeon: %u", guid.ToString().c_str(), dungeon);
diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h
index 0e5fadc85cc..fda9a8b7ce9 100644
--- a/src/server/game/DungeonFinding/LFGMgr.h
+++ b/src/server/game/DungeonFinding/LFGMgr.h
@@ -322,6 +322,8 @@ class LFGMgr
LfgDungeonSet const& GetSelectedDungeons(ObjectGuid guid);
/// Get current lfg state
LfgState GetState(ObjectGuid guid);
+ /// Get current vote kick state
+ bool IsVoteKickActive(ObjectGuid gguid);
/// Get current dungeon
uint32 GetDungeon(ObjectGuid guid, bool asId = true);
/// Get the map id of the current dungeon
@@ -425,6 +427,7 @@ class LFGMgr
void SetSelectedDungeons(ObjectGuid guid, LfgDungeonSet const& dungeons);
void DecreaseKicksLeft(ObjectGuid guid);
void SetState(ObjectGuid guid, LfgState state);
+ void SetVoteKick(ObjectGuid gguid, bool active);
void RemovePlayerData(ObjectGuid guid);
void GetCompatibleDungeons(LfgDungeonSet& dungeons, GuidSet const& players, LfgLockPartyMap& lockMap, bool isContinue);
void _SaveToDB(ObjectGuid guid, uint32 db_guid);
diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp
index 683590cebe8..a7c0a1cfa67 100644
--- a/src/server/game/DungeonFinding/LFGQueue.cpp
+++ b/src/server/game/DungeonFinding/LFGQueue.cpp
@@ -377,7 +377,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check)
// Group with less that MAXGROUPSIZE members always compatible
if (check.size() == 1 && numPlayers != MAXGROUPSIZE)
{
- TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) sigle group. Compatibles", strGuids.c_str());
+ TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) single group. Compatibles", strGuids.c_str());
LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(check.front());
LfgCompatibilityData data(LFG_COMPATIBLES_WITH_LESS_PLAYERS);
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index a44ca68f79b..a3ce6d919c9 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -2697,7 +2697,7 @@ void Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target)
_focusSpell = focusSpell;
SetGuidValue(UNIT_FIELD_TARGET, target->GetGUID());
- if (focusSpell->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_DONT_TURN_DURING_CAST)
+ if (focusSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST))
AddUnitState(UNIT_STATE_ROTATING);
// Set serverside orientation if needed (needs to be after attribute check)
@@ -2716,7 +2716,7 @@ void Creature::ReleaseFocus(Spell const* focusSpell)
else
SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty);
- if (focusSpell->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_DONT_TURN_DURING_CAST)
+ if (focusSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST))
ClearUnitState(UNIT_STATE_ROTATING);
}
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index b5bcbfd221f..0b97499fc05 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1072,32 +1072,32 @@ ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& st
void MovementInfo::OutDebug()
{
- TC_LOG_INFO("misc", "MOVEMENT INFO");
- TC_LOG_INFO("misc", "%s", guid.ToString().c_str());
- TC_LOG_INFO("misc", "flags %u", flags);
- TC_LOG_INFO("misc", "flags2 %u", flags2);
- TC_LOG_INFO("misc", "time %u current time " UI64FMTD "", flags2, uint64(::time(NULL)));
- TC_LOG_INFO("misc", "position: `%s`", pos.ToString().c_str());
+ TC_LOG_DEBUG("misc", "MOVEMENT INFO");
+ TC_LOG_DEBUG("misc", "%s", guid.ToString().c_str());
+ TC_LOG_DEBUG("misc", "flags %u", flags);
+ TC_LOG_DEBUG("misc", "flags2 %u", flags2);
+ TC_LOG_DEBUG("misc", "time %u current time " UI64FMTD "", flags2, uint64(::time(NULL)));
+ TC_LOG_DEBUG("misc", "position: `%s`", pos.ToString().c_str());
if (flags & MOVEMENTFLAG_ONTRANSPORT)
{
- TC_LOG_INFO("misc", "TRANSPORT:");
- TC_LOG_INFO("misc", "%s", transport.guid.ToString().c_str());
- TC_LOG_INFO("misc", "position: `%s`", transport.pos.ToString().c_str());
- TC_LOG_INFO("misc", "seat: %i", transport.seat);
- TC_LOG_INFO("misc", "time: %u", transport.time);
+ TC_LOG_DEBUG("misc", "TRANSPORT:");
+ TC_LOG_DEBUG("misc", "%s", transport.guid.ToString().c_str());
+ TC_LOG_DEBUG("misc", "position: `%s`", transport.pos.ToString().c_str());
+ TC_LOG_DEBUG("misc", "seat: %i", transport.seat);
+ TC_LOG_DEBUG("misc", "time: %u", transport.time);
if (flags2 & MOVEMENTFLAG2_INTERPOLATED_MOVEMENT)
- TC_LOG_INFO("misc", "time2: %u", transport.time2);
+ TC_LOG_DEBUG("misc", "time2: %u", transport.time2);
}
if ((flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || (flags2 & MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING))
- TC_LOG_INFO("misc", "pitch: %f", pitch);
+ TC_LOG_DEBUG("misc", "pitch: %f", pitch);
- TC_LOG_INFO("misc", "fallTime: %u", fallTime);
+ TC_LOG_DEBUG("misc", "fallTime: %u", fallTime);
if (flags & MOVEMENTFLAG_FALLING)
- TC_LOG_INFO("misc", "j_zspeed: %f j_sinAngle: %f j_cosAngle: %f j_xyspeed: %f", jump.zspeed, jump.sinAngle, jump.cosAngle, jump.xyspeed);
+ TC_LOG_DEBUG("misc", "j_zspeed: %f j_sinAngle: %f j_cosAngle: %f j_xyspeed: %f", jump.zspeed, jump.sinAngle, jump.cosAngle, jump.xyspeed);
if (flags & MOVEMENTFLAG_SPLINE_ELEVATION)
- TC_LOG_INFO("misc", "splineElevation: %f", splineElevation);
+ TC_LOG_DEBUG("misc", "splineElevation: %f", splineElevation);
}
WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), LastUsedScriptID(0),
@@ -2255,6 +2255,13 @@ void WorldObject::GetCreatureListWithEntryInGrid(std::list<Creature*>& creatureL
cell.Visit(pair, visitor, *(this->GetMap()), *this, maxSearchRange);
}
+void WorldObject::GetPlayerListInGrid(std::list<Player*>& playerList, float maxSearchRange) const
+{
+ Trinity::AnyPlayerInObjectRangeCheck checker(this, maxSearchRange);
+ Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(this, playerList, checker);
+ this->VisitNearbyWorldObject(maxSearchRange, searcher);
+}
+
/*
namespace Trinity
{
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index 2aa1704f7d2..c48d8ff4d18 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -683,6 +683,7 @@ class WorldObject : public Object, public WorldLocation
void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& lList, uint32 uiEntry, float fMaxSearchRange) const;
void GetCreatureListWithEntryInGrid(std::list<Creature*>& lList, uint32 uiEntry, float fMaxSearchRange) const;
+ void GetPlayerListInGrid(std::list<Player*>& lList, float fMaxSearchRange) const;
void DestroyForNearbyPlayers();
virtual void UpdateObjectVisibility(bool forced = true);
diff --git a/src/server/game/Entities/Object/ObjectGuid.h b/src/server/game/Entities/Object/ObjectGuid.h
index be292751811..36dbdd72069 100644
--- a/src/server/game/Entities/Object/ObjectGuid.h
+++ b/src/server/game/Entities/Object/ObjectGuid.h
@@ -23,6 +23,7 @@
#include "ByteBuffer.h"
#include <functional>
+#include <unordered_set>
enum TypeID
{
@@ -202,6 +203,7 @@ typedef std::set<ObjectGuid> GuidSet;
typedef std::list<ObjectGuid> GuidList;
typedef std::deque<ObjectGuid> GuidDeque;
typedef std::vector<ObjectGuid> GuidVector;
+typedef std::unordered_set<ObjectGuid> GuidUnorderedSet;
// minimum buffer size for packed guid is 9 bytes
#define PACKED_GUID_MIN_BUFFER_SIZE 9
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index 5084031880d..fdfd1fa3d4d 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -1314,7 +1314,7 @@ void Pet::_LoadAuras(uint32 timediff)
}
aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, &damage[0]);
aura->ApplyForTargets();
- TC_LOG_INFO("entities.pet", "Added aura spellid %u, effectmask %u", spellInfo->Id, effmask);
+ TC_LOG_DEBUG("entities.pet", "Added aura spellid %u, effectmask %u", spellInfo->Id, effmask);
}
}
while (result->NextRow());
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 161fca432b4..e46448df133 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -3902,7 +3902,7 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const
// talent dependent passives activated at form apply have proper stance data
ShapeshiftForm form = GetShapeshiftForm();
bool need_cast = (!spellInfo->Stances || (form && (spellInfo->Stances & (1 << (form - 1)))) ||
- (!form && (spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_NEED_SHAPESHIFT)));
+ (!form && spellInfo->HasAttribute(SPELL_ATTR2_NOT_NEED_SHAPESHIFT)));
//Check CasterAuraStates
return need_cast && (!spellInfo->CasterAuraState || HasAuraState(AuraStateType(spellInfo->CasterAuraState)));
@@ -4218,7 +4218,7 @@ void Player::RemoveSpellCategoryCooldown(uint32 cat, bool update /* = false */)
void Player::RemoveArenaSpellCooldowns(bool removeActivePetCooldowns)
{
- // remove cooldowns on spells that have <= 10 min CD
+ // remove cooldowns on spells that have < 10 min CD
SpellCooldowns::iterator itr, next;
for (itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); itr = next)
@@ -4226,10 +4226,10 @@ void Player::RemoveArenaSpellCooldowns(bool removeActivePetCooldowns)
next = itr;
++next;
SpellInfo const* entry = sSpellMgr->GetSpellInfo(itr->first);
- // check if spellentry is present and if the cooldown is less or equal to 10 min
+ // check if spellentry is present and if the cooldown is less than 10 min
if (entry &&
- entry->RecoveryTime <= 10 * MINUTE * IN_MILLISECONDS &&
- entry->CategoryRecoveryTime <= 10 * MINUTE * IN_MILLISECONDS)
+ entry->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS &&
+ entry->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS)
{
// remove & notify
RemoveSpellCooldown(itr->first, true);
@@ -4830,10 +4830,22 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt32(0, guid);
trans->Append(stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_ARENA_STATS);
+ stmt->setUInt32(0, guid);
+ trans->Append(stmt);
+
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA);
stmt->setUInt32(0, guid);
trans->Append(stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_BGDATA);
+ stmt->setUInt32(0, guid);
+ trans->Append(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_BATTLEGROUND_RANDOM);
+ stmt->setUInt32(0, guid);
+ trans->Append(stmt);
+
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GIFT);
stmt->setUInt32(0, guid);
trans->Append(stmt);
@@ -4923,10 +4935,6 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt32(0, guid);
trans->Append(stmt);
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_BGDATA);
- stmt->setUInt32(0, guid);
- trans->Append(stmt);
-
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GLYPHS);
stmt->setUInt32(0, guid);
trans->Append(stmt);
@@ -4955,6 +4963,10 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt32(0, guid);
trans->Append(stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_STATS);
+ stmt->setUInt32(0, guid);
+ trans->Append(stmt);
+
CharacterDatabase.CommitTransaction(trans);
break;
}
@@ -5002,7 +5014,7 @@ void Player::DeleteOldCharacters()
*/
void Player::DeleteOldCharacters(uint32 keepDays)
{
- TC_LOG_INFO("entities.player", "Player::DeleteOldChars: Deleting all characters which have been deleted %u days before...", keepDays);
+ TC_LOG_INFO("entities.player", "Player::DeleteOldChars: Removing characters older than %u day(s)", keepDays);
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_OLD_CHARS);
stmt->setUInt32(0, uint32(time(NULL) - time_t(keepDays * DAY)));
@@ -5010,7 +5022,7 @@ void Player::DeleteOldCharacters(uint32 keepDays)
if (result)
{
- TC_LOG_DEBUG("entities.player", "Player::DeleteOldChars: Found " UI64FMTD " character(s) to delete", result->GetRowCount());
+ TC_LOG_DEBUG("entities.player", "Player::DeleteOldChars: " UI64FMTD " character(s) to remove", result->GetRowCount());
do
{
Field* fields = result->Fetch();
@@ -6636,20 +6648,20 @@ void Player::SendActionButtons(uint32 state) const
}
GetSession()->SendPacket(&data);
- TC_LOG_INFO("network", "SMSG_ACTION_BUTTONS sent '%u' spec '%u' Sent", GetGUIDLow(), m_activeSpec);
+ TC_LOG_DEBUG("network", "SMSG_ACTION_BUTTONS sent '%u' spec '%u' Sent", GetGUIDLow(), m_activeSpec);
}
bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type)
{
if (button >= MAX_ACTION_BUTTONS)
{
- TC_LOG_ERROR("entities.player", "Action %u not added into button %u for player %s (GUID: %u): button must be < %u", action, button, GetName().c_str(), GetGUIDLow(), MAX_ACTION_BUTTONS );
+ TC_LOG_DEBUG("entities.player", "Action %u not added into button %u for player %s (GUID: %u): button must be < %u", action, button, GetName().c_str(), GetGUIDLow(), MAX_ACTION_BUTTONS );
return false;
}
if (action >= MAX_ACTION_BUTTON_ACTION_VALUE)
{
- TC_LOG_ERROR("entities.player", "Action %u not added into button %u for player %s (GUID: %u): action must be < %u", action, button, GetName().c_str(), GetGUIDLow(), MAX_ACTION_BUTTON_ACTION_VALUE);
+ TC_LOG_DEBUG("entities.player", "Action %u not added into button %u for player %s (GUID: %u): action must be < %u", action, button, GetName().c_str(), GetGUIDLow(), MAX_ACTION_BUTTON_ACTION_VALUE);
return false;
}
@@ -6658,20 +6670,20 @@ bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type)
case ACTION_BUTTON_SPELL:
if (!sSpellMgr->GetSpellInfo(action))
{
- TC_LOG_ERROR("entities.player", "Spell action %u not added into button %u for player %s (GUID: %u): spell not exist", action, button, GetName().c_str(), GetGUIDLow());
+ TC_LOG_DEBUG("entities.player", "Spell action %u not added into button %u for player %s (GUID: %u): spell not exist", action, button, GetName().c_str(), GetGUIDLow());
return false;
}
if (!HasSpell(action))
{
- TC_LOG_ERROR("entities.player", "Spell action %u not added into button %u for player %s (GUID: %u): player don't known this spell", action, button, GetName().c_str(), GetGUIDLow());
+ TC_LOG_DEBUG("entities.player", "Spell action %u not added into button %u for player %s (GUID: %u): player don't known this spell", action, button, GetName().c_str(), GetGUIDLow());
return false;
}
break;
case ACTION_BUTTON_ITEM:
if (!sObjectMgr->GetItemTemplate(action))
{
- TC_LOG_ERROR("entities.player", "Item action %u not added into button %u for player %s (GUID: %u): item not exist", action, button, GetName().c_str(), GetGUIDLow());
+ TC_LOG_DEBUG("entities.player", "Item action %u not added into button %u for player %s (GUID: %u): item not exist", action, button, GetName().c_str(), GetGUIDLow());
return false;
}
break;
@@ -6681,7 +6693,7 @@ bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type)
case ACTION_BUTTON_EQSET:
break;
default:
- TC_LOG_ERROR("entities.player", "Unknown action type %u", type);
+ TC_LOG_DEBUG("entities.player", "Unknown action type %u", type);
return false; // other cases not checked at this moment
}
@@ -6883,7 +6895,7 @@ void Player::CheckAreaExploreAndOutdoor()
GiveXP(XP, NULL);
SendExplorationExperience(area, XP);
}
- TC_LOG_INFO("entities.player", "Player %u discovered a new area: %u", GetGUIDLow(), area);
+ TC_LOG_DEBUG("entities.player", "Player %u discovered a new area: %u", GetGUIDLow(), area);
}
}
}
@@ -7763,7 +7775,7 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply)
if (item->IsBroken())
return;
- TC_LOG_INFO("entities.player.items", "applying mods for item %u ", item->GetGUIDLow());
+ TC_LOG_DEBUG("entities.player.items", "applying mods for item %u ", item->GetGUIDLow());
uint8 attacktype = Player::GetAttackBySlot(slot);
@@ -9774,7 +9786,7 @@ uint32 Player::GetXPRestBonus(uint32 xp)
SetRestBonus(GetRestBonus() - rested_bonus);
- TC_LOG_INFO("entities.player", "Player gain %u xp (+ %u Rested Bonus). Rested points=%f", xp+rested_bonus, rested_bonus, GetRestBonus());
+ TC_LOG_DEBUG("entities.player", "Player gain %u xp (+ %u Rested Bonus). Rested points=%f", xp+rested_bonus, rested_bonus, GetRestBonus());
return rested_bonus;
}
@@ -17999,7 +18011,7 @@ void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff)
aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, &damage[0]);
aura->ApplyForTargets();
- TC_LOG_INFO("entities.player", "Added aura spellid %u, effectmask %u", spellInfo->Id, effmask);
+ TC_LOG_DEBUG("entities.player", "Added aura spellid %u, effectmask %u", spellInfo->Id, effmask);
}
}
while (result->NextRow());
@@ -19086,7 +19098,7 @@ bool Player::Satisfy(AccessRequirement const* ar, uint32 target_map, bool report
else if (mapDiff->hasErrorMessage) // if (missingAchievement) covered by this case
SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY, target_difficulty);
else if (missingItem)
- GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, sObjectMgr->GetItemTemplate(missingItem)->Name1.c_str());
+ GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(missingItem))->Name1.c_str());
else if (LevelMin)
GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED), LevelMin);
}
@@ -19732,6 +19744,7 @@ void Player::_SaveInventory(SQLTransaction& trans)
m_itemUpdateQueue.clear();
}
+
void Player::_SaveMail(SQLTransaction& trans)
{
if (!m_mailsLoaded)
@@ -20670,8 +20683,6 @@ void Player::PetSpellInitialize()
if (!pet)
return;
- TC_LOG_DEBUG("entities.pet", "Pet Spells Groups");
-
CharmInfo* charmInfo = pet->GetCharmInfo();
WorldPacket data(SMSG_PET_SPELLS, 8+2+4+4+4*MAX_UNIT_ACTION_BAR_INDEX+1+1);
@@ -20682,6 +20693,8 @@ void Player::PetSpellInitialize()
data << uint8(charmInfo->GetCommandState());
data << uint16(0); // Flags, mostly unknown
+ TC_LOG_DEBUG("entities.pet", "Player::PetspellInitialize: Creating spellgroups for summoned pet");
+
// action bar loop
charmInfo->BuildActionBar(&data);
@@ -22043,7 +22056,7 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite
if (rec > 0)
ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, rec, spell);
- if (catrec > 0 && !(spellInfo->AttributesEx6 & SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS))
+ if (catrec > 0 && !spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS))
ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, catrec, spell);
if (int32 cooldownMod = GetTotalAuraModifier(SPELL_AURA_MOD_COOLDOWN))
@@ -22138,6 +22151,34 @@ void Player::SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId /*= 0*/
data << uint32(spellInfo->Id);
data << uint64(GetGUID());
SendDirectMessage(&data);
+
+ uint32 cat = spellInfo->GetCategory();
+ if (cat && spellInfo->CategoryRecoveryTime)
+ {
+ SpellCategoryStore::const_iterator ct = sSpellsByCategoryStore.find(cat);
+ if (ct != sSpellsByCategoryStore.end())
+ {
+ SpellCategorySet const& catSet = ct->second;
+ for (SpellCooldowns::const_iterator i = m_spellCooldowns.begin(); i != m_spellCooldowns.end(); ++i)
+ {
+ if (i->first == spellInfo->Id) // skip main spell, already handled above
+ continue;
+
+ SpellInfo const* spellInfo2 = sSpellMgr->GetSpellInfo(i->first);
+ if (!spellInfo2 || !spellInfo2->IsCooldownStartedOnEvent())
+ continue;
+
+ if (catSet.find(i->first) != catSet.end())
+ {
+ // Send activate cooldown timer (possible 0) at client side
+ WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8);
+ data << uint32(i->first);
+ data << uint64(GetGUID());
+ SendDirectMessage(&data);
+ }
+ }
+ }
+ }
}
void Player::UpdatePotionCooldown(Spell* spell)
@@ -22532,13 +22573,13 @@ bool Player::IsVisibleGloballyFor(Player const* u) const
}
template<class T>
-inline void UpdateVisibilityOf_helper(GuidSet& s64, T* target, std::set<Unit*>& /*v*/)
+inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, T* target, std::set<Unit*>& /*v*/)
{
s64.insert(target->GetGUID());
}
template<>
-inline void UpdateVisibilityOf_helper(GuidSet& s64, GameObject* target, std::set<Unit*>& /*v*/)
+inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, GameObject* target, std::set<Unit*>& /*v*/)
{
// @HACK: This is to prevent objects like deeprun tram from disappearing when player moves far from its spawn point while riding it
if ((target->GetGOInfo()->type != GAMEOBJECT_TYPE_TRANSPORT))
@@ -22546,14 +22587,14 @@ inline void UpdateVisibilityOf_helper(GuidSet& s64, GameObject* target, std::set
}
template<>
-inline void UpdateVisibilityOf_helper(GuidSet& s64, Creature* target, std::set<Unit*>& v)
+inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Creature* target, std::set<Unit*>& v)
{
s64.insert(target->GetGUID());
v.insert(target);
}
template<>
-inline void UpdateVisibilityOf_helper(GuidSet& s64, Player* target, std::set<Unit*>& v)
+inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Player* target, std::set<Unit*>& v)
{
s64.insert(target->GetGUID());
v.insert(target);
@@ -22615,7 +22656,7 @@ void Player::UpdateTriggerVisibility()
UpdateData udata;
WorldPacket packet;
- for (GuidSet::iterator itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
+ for (auto itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
{
if (itr->IsCreature())
{
@@ -23674,7 +23715,7 @@ void Player::UpdateForQuestWorldObjects()
UpdateData udata;
WorldPacket packet;
- for (GuidSet::iterator itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
+ for (auto itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
{
if (itr->IsGameObject())
{
@@ -23863,7 +23904,7 @@ bool Player::HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item cons
bool Player::CanNoReagentCast(SpellInfo const* spellInfo) const
{
// don't take reagents for spells with SPELL_ATTR5_NO_REAGENT_WHILE_PREP
- if (spellInfo->AttributesEx5 & SPELL_ATTR5_NO_REAGENT_WHILE_PREP &&
+ if (spellInfo->HasAttribute(SPELL_ATTR5_NO_REAGENT_WHILE_PREP) &&
HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION))
return true;
@@ -24166,18 +24207,6 @@ void Player::UpdateAreaDependentAuras(uint32 newArea)
if (itr->second->autocast && itr->second->IsFitToRequirements(this, m_zoneUpdateId, newArea))
if (!HasAura(itr->second->spellId))
CastSpell(this, itr->second->spellId, true);
-
- if (newArea == 4273 && GetVehicleCreatureBase() && GetPositionX() > 400) // Ulduar
- {
- switch (GetVehicleBase()->GetEntry())
- {
- case 33062:
- case 33109:
- case 33060:
- GetVehicleCreatureBase()->DespawnOrUnsummon();
- break;
- }
- }
}
uint32 Player::GetCorpseReclaimDelay(bool pvp) const
@@ -24308,7 +24337,7 @@ PartyResult Player::CanUninviteFromGroup(ObjectGuid guidMember) const
return ERR_PARTY_LFG_BOOT_LIMIT;
lfg::LfgState state = sLFGMgr->GetState(gguid);
- if (state == lfg::LFG_STATE_BOOT)
+ if (sLFGMgr->IsVoteKickActive(gguid))
return ERR_PARTY_LFG_BOOT_IN_PROGRESS;
if (grp->GetMembersCount() <= lfg::LFG_GROUP_KICK_VOTES_NEEDED)
@@ -24815,7 +24844,7 @@ void Player::RestoreBaseRune(uint8 index)
{
AuraEffect const* aura = m_runes->runes[index].ConvertAura;
// If rune was converted by a non-pasive aura that still active we should keep it converted
- if (aura && !(aura->GetSpellInfo()->Attributes & SPELL_ATTR0_PASSIVE))
+ if (aura && !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_PASSIVE))
return;
ConvertRune(index, GetBaseRune(index));
SetRuneConvertAura(index, NULL);
@@ -25047,6 +25076,7 @@ void Player::_LoadSkills(PreparedQueryResult result)
// SetPQuery(PLAYER_LOGIN_QUERY_LOADSKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = '%u'", GUID_LOPART(m_guid));
uint32 count = 0;
+ std::unordered_map<uint32, uint32> loadedSkillValues;
if (result)
{
do
@@ -25114,8 +25144,7 @@ void Player::_LoadSkills(PreparedQueryResult result)
SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(count), 0);
mSkillStatus.insert(SkillStatusMap::value_type(skill, SkillStatusData(count, SKILL_UNCHANGED)));
-
- LearnSkillRewardedSpells(skill, value);
+ loadedSkillValues[skill] = value;
++count;
@@ -25128,6 +25157,10 @@ void Player::_LoadSkills(PreparedQueryResult result)
while (result->NextRow());
}
+ // Learn skill rewarded spells after all skills have been loaded to prevent learning a skill from them before its loaded with proper value from DB
+ for (auto& skill : loadedSkillValues)
+ LearnSkillRewardedSpells(skill.first, skill.second);
+
for (; count < PLAYER_MAX_SKILLS; ++count)
{
SetUInt32Value(PLAYER_SKILL_INDEX(count), 0);
@@ -25429,7 +25462,7 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
LearnSpell(spellid, false);
AddTalent(spellid, m_activeSpec, true);
- TC_LOG_INFO("entities.player", "TalentID: %u Rank: %u Spell: %u Spec: %u\n", talentId, talentRank, spellid, m_activeSpec);
+ TC_LOG_DEBUG("entities.player", "TalentID: %u Rank: %u Spell: %u Spec: %u\n", talentId, talentRank, spellid, m_activeSpec);
// update free talent points
SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
@@ -25564,7 +25597,7 @@ void Player::LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRa
// learn! (other talent ranks will unlearned at learning)
pet->learnSpell(spellid);
- TC_LOG_INFO("entities.player", "PetTalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid);
+ TC_LOG_DEBUG("entities.player", "PetTalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid);
// update free talent points
pet->SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 61141192cd1..1e928c80f3c 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2170,7 +2170,7 @@ class Player : public Unit, public GridObject<Player>
WorldLocation GetStartPosition() const;
// currently visible objects at player client
- GuidSet m_clientGUIDs;
+ GuidUnorderedSet m_clientGUIDs;
bool HaveAtClient(WorldObject const* u) const;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index fdd91368704..f44c14a12dd 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -589,7 +589,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
// interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
if (spellProto)
{
- if (!(spellProto->AttributesEx4 & SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS))
+ if (!spellProto->HasAttribute(SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS))
victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, spellProto->Id);
}
else
@@ -777,7 +777,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
if (damagetype != NODAMAGE && damage)
{
if (victim != this && victim->GetTypeId() == TYPEID_PLAYER && // does not support creature push_back
- (!spellProto || !(spellProto->AttributesEx7 & SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE)))
+ (!spellProto || !spellProto->HasAttribute(SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE)))
{
if (damagetype != DOT)
if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
@@ -981,7 +981,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
uint32 crTypeMask = victim->GetCreatureTypeMask();
// Spells with SPELL_ATTR4_FIXED_DAMAGE ignore resilience because their damage is based off another spell's damage.
- if (!(spellInfo->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE))
+ if (!spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
{
if (IsDamageReducedByArmor(damageSchoolMask, spellInfo))
damage = CalcArmorReducedDamage(victim, damage, spellInfo, attackType);
@@ -1459,7 +1459,7 @@ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* s
if (spellInfo)
{
// there are spells with no specific attribute but they have "ignores armor" in tooltip
- if (spellInfo->AttributesCu & SPELL_ATTR0_CU_IGNORE_ARMOR)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_ARMOR))
return false;
// bleeding effects are not reduced by armor
@@ -1560,7 +1560,7 @@ uint32 Unit::CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, Spell
return 0;
// Ignore spells that can't be resisted
- if (spellInfo && spellInfo->AttributesEx4 & SPELL_ATTR4_IGNORE_RESISTANCES)
+ if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR4_IGNORE_RESISTANCES))
return 0;
uint32 const BOSS_LEVEL = 83;
@@ -2234,15 +2234,15 @@ void Unit::SendMeleeAttackStop(Unit* victim)
TC_LOG_DEBUG("entities.unit", "WORLD: Sent SMSG_ATTACKSTOP");
if (victim)
- TC_LOG_INFO("entities.unit", "%s %u stopped attacking %s %u", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow(), (victim->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), victim->GetGUIDLow());
+ TC_LOG_DEBUG("entities.unit", "%s %u stopped attacking %s %u", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow(), (victim->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), victim->GetGUIDLow());
else
- TC_LOG_INFO("entities.unit", "%s %u stopped attacking", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow());
+ TC_LOG_DEBUG("entities.unit", "%s %u stopped attacking", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow());
}
bool Unit::isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType)
{
// These spells can't be blocked
- if (spellProto && spellProto->Attributes & SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK)
+ if (spellProto && spellProto->HasAttribute(SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK))
return false;
if (victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION) || victim->HasInArc(float(M_PI), this))
@@ -2309,7 +2309,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
{
// Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
// resist and deflect chances
- if (spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
+ if (spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
return SPELL_MISS_NONE;
WeaponAttackType attType = BASE_ATTACK;
@@ -2357,10 +2357,10 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
bool canDodge = true;
bool canParry = true;
- bool canBlock = (spellInfo->AttributesEx3 & SPELL_ATTR3_BLOCKABLE_SPELL) != 0;
+ bool canBlock = spellInfo->HasAttribute(SPELL_ATTR3_BLOCKABLE_SPELL);
// Same spells cannot be parry/dodge
- if (spellInfo->Attributes & SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK))
return SPELL_MISS_NONE;
// Chance resist mechanic
@@ -2400,7 +2400,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
}
else // Only deterrence as of 3.3.5
{
- if (spellInfo->AttributesCu & SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET))
canParry = false;
}
}
@@ -2491,7 +2491,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo)
{
// Can`t miss on dead target (on skinning for example)
- if ((!victim->IsAlive() && victim->GetTypeId() != TYPEID_PLAYER) || spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
+ if ((!victim->IsAlive() && victim->GetTypeId() != TYPEID_PLAYER) || spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
return SPELL_MISS_NONE;
SpellSchoolMask schoolMask = spellInfo->GetSchoolMask();
@@ -3089,7 +3089,7 @@ bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAu
{
if (!skipInstant || m_currentSpells[CURRENT_GENERIC_SPELL]->GetCastTime())
{
- if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
+ if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS)))
return true;
}
}
@@ -3097,7 +3097,7 @@ bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAu
if (!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
(m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED))
{
- if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
+ if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS)))
return true;
}
// autorepeat spells may be finished or delayed, but they are still considered cast
@@ -3232,7 +3232,7 @@ Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8
castItemGUID = castItem->GetGUID();
// find current aura from spell and change it's stackamount, or refresh it's duration
- if (Aura* foundAura = GetOwnedAura(newAura->Id, casterGUID, (newAura->AttributesCu & SPELL_ATTR0_CU_ENCHANT_PROC) ? castItemGUID : ObjectGuid::Empty, 0))
+ if (Aura* foundAura = GetOwnedAura(newAura->Id, casterGUID, newAura->HasAttribute(SPELL_ATTR0_CU_ENCHANT_PROC) ? castItemGUID : ObjectGuid::Empty, 0))
{
// effect masks do not match
// extremely rare case
@@ -3743,7 +3743,7 @@ void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId
// Call OnDispel hook on AuraScript
aura->CallScriptDispel(&dispelInfo);
- if (aura->GetSpellInfo()->AttributesEx7 & SPELL_ATTR7_DISPEL_CHARGES)
+ if (aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES))
aura->ModCharges(-dispelInfo.GetRemovedCharges(), AURA_REMOVE_BY_ENEMY_SPELL);
else
aura->ModStackAmount(-dispelInfo.GetRemovedCharges(), AURA_REMOVE_BY_ENEMY_SPELL);
@@ -3788,7 +3788,7 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, U
}
}
- bool stealCharge = (aura->GetSpellInfo()->AttributesEx7 & SPELL_ATTR7_DISPEL_CHARGES) != 0;
+ bool stealCharge = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
// Cast duration to unsigned to prevent permanent aura's such as Righteous Fury being permanently added to caster
uint32 dur = std::min(2u * MINUTE * IN_MILLISECONDS, uint32(aura->GetDuration()));
@@ -4046,9 +4046,9 @@ void Unit::RemoveArenaAuras()
{
AuraApplication const* aurApp = iter->second;
Aura const* aura = aurApp->GetBase();
- if (!(aura->GetSpellInfo()->AttributesEx4 & SPELL_ATTR4_UNK21) // don't remove stances, shadowform, pally/hunter auras
+ if (!aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_UNK21) // don't remove stances, shadowform, pally/hunter auras
&& !aura->IsPassive() // don't remove passive auras
- && (aurApp->IsPositive() || !(aura->GetSpellInfo()->AttributesEx3 & SPELL_ATTR3_DEATH_PERSISTENT))) // not negative death persistent auras
+ && (aurApp->IsPositive() || !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR3_DEATH_PERSISTENT))) // not negative death persistent auras
RemoveAura(iter);
else
++iter;
@@ -4308,7 +4308,7 @@ void Unit::GetDispellableAuraList(Unit* caster, uint32 dispelMask, DispelCharges
// The charges / stack amounts don't count towards the total number of auras that can be dispelled.
// Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
// Polymorph instead of 1 / (5 + 1) -> 16%.
- bool dispel_charges = (aura->GetSpellInfo()->AttributesEx7 & SPELL_ATTR7_DISPEL_CHARGES) != 0;
+ bool dispel_charges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount();
if (charges > 0)
dispelList.push_back(std::make_pair(aura, charges));
@@ -9602,7 +9602,7 @@ bool Unit::IsMagnet() const
Unit* Unit::GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo)
{
// Patch 1.2 notes: Spell Reflection no longer reflects abilities
- if (spellInfo->Attributes & SPELL_ATTR0_ABILITY || spellInfo->AttributesEx & SPELL_ATTR1_CANT_BE_REDIRECTED || spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR1_CANT_BE_REDIRECTED) || spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return victim;
Unit::AuraEffectList const& magnetAuras = victim->GetAuraEffectsByType(SPELL_AURA_SPELL_MAGNET);
@@ -9854,7 +9854,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
return pdamage;
// Some spells don't benefit from done mods
- if (spellProto->AttributesEx3 & SPELL_ATTR3_NO_DONE_BONUS)
+ if (spellProto->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS))
return pdamage;
// For totems get damage bonus from owner
@@ -9985,7 +9985,7 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage
return 1.0f;
// Some spells don't benefit from pct done mods
- if (spellProto->AttributesEx6 & SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS)
+ if (spellProto->HasAttribute(SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS))
return 1.0f;
// For totems pct done mods are calculated when its calculation is run on the player in SpellDamageBonusDone.
@@ -10009,7 +10009,7 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage
{
if ((*i)->GetSpellInfo()->EquippedItemClass == -1)
AddPct(DoneTotalMod, (*i)->GetAmount());
- else if (!((*i)->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0))
+ else if (!(*i)->GetSpellInfo()->HasAttribute(SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0))
AddPct(DoneTotalMod, (*i)->GetAmount());
else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellInfo()))
AddPct(DoneTotalMod, (*i)->GetAmount());
@@ -10324,7 +10324,7 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui
}
}
// Spells with SPELL_ATTR4_FIXED_DAMAGE should only benefit from mechanic damage mod auras.
- if (!(spellProto->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE))
+ if (!spellProto->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
{
// get all auras from caster that allow the spell to ignore resistance (sanctified wrath)
AuraEffectList const& IgnoreResistAuras = caster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
@@ -10454,7 +10454,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
return 0.0f;
// not critting spell
- if ((spellProto->AttributesEx2 & SPELL_ATTR2_CANT_CRIT))
+ if (spellProto->HasAttribute(SPELL_ATTR2_CANT_CRIT))
return 0.0f;
float crit_chance = 0.0f;
@@ -11063,7 +11063,7 @@ bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask) const
bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
{
- if (spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return false;
uint32 shoolMask = spellInfo->GetSchoolMask();
@@ -11096,7 +11096,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const
if (itr->type == spellInfo->Id)
return true;
- if (spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return false;
if (spellInfo->Dispel)
@@ -11154,7 +11154,7 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
if (!spellInfo || !spellInfo->Effects[index].IsEffect())
return false;
- if (spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return false;
// If m_immuneToEffect type contain this effect type, IMMUNE effect.
@@ -11177,7 +11177,7 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
SpellImmuneList const& list = m_spellImmune[IMMUNITY_STATE];
for (SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
if (itr->type == aura)
- if (!(spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT))
+ if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
return true;
// Check for immune to application of harmful magical effects
@@ -11252,7 +11252,7 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType
// Some spells don't benefit from pct done mods
if (spellProto)
- if (!(spellProto->AttributesEx6 & SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS))
+ if (!spellProto->HasAttribute(SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS))
{
AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
@@ -11261,7 +11261,7 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType
{
if ((*i)->GetSpellInfo()->EquippedItemClass == -1)
AddPct(DoneTotalMod, (*i)->GetAmount());
- else if (!((*i)->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0))
+ else if (!(*i)->GetSpellInfo()->HasAttribute(SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0))
AddPct(DoneTotalMod, (*i)->GetAmount());
else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellInfo()))
AddPct(DoneTotalMod, (*i)->GetAmount());
@@ -11523,7 +11523,7 @@ void Unit::ApplySpellDispelImmunity(const SpellInfo* spellProto, DispelType type
{
ApplySpellImmune(spellProto->Id, IMMUNITY_DISPEL, type, apply);
- if (apply && spellProto->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
+ if (apply && spellProto->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
{
// Create dispel mask by dispel type
uint32 dispelMask = SpellInfo::GetDispelMask(type);
@@ -11864,7 +11864,7 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
return false;
// can't attack invisible (ignore stealth for aoe spells) also if the area being looked at is from a spell use the dynamic object created instead of the casting unit.
- if ((!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && (obj ? !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()) : !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea())))
+ if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && (obj ? !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()) : !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea())))
return false;
// can't attack dead
@@ -11872,7 +11872,7 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
return false;
// can't attack untargetable
- if ((!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_CAN_TARGET_UNTARGETABLE))
+ if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE))
&& target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
return false;
@@ -11981,7 +11981,7 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co
return false;
// can't assist invisible
- if ((!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()))
+ if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()))
return false;
// can't assist dead
@@ -11989,11 +11989,11 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co
return false;
// can't assist untargetable
- if ((!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_CAN_TARGET_UNTARGETABLE))
+ if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE))
&& target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
return false;
- if (!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
+ if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
{
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE))
{
@@ -12040,7 +12040,7 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co
// PvC case - player can assist creature only if has specific type flags
// !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) &&
else if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE)
- && (!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
+ && (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
&& !((target->GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_PVP)))
{
if (Creature const* creatureTarget = target->ToCreature())
@@ -12822,7 +12822,7 @@ int32 Unit::ModSpellDuration(SpellInfo const* spellProto, Unit const* target, in
return duration;
// some auras are not affected by duration modifiers
- if (spellProto->AttributesEx7 & SPELL_ATTR7_IGNORE_DURATION_MODS)
+ if (spellProto->HasAttribute(SPELL_ATTR7_IGNORE_DURATION_MODS))
return duration;
// cut duration only of negative effects
@@ -12926,17 +12926,17 @@ void Unit::ModSpellCastTime(SpellInfo const* spellInfo, int32 & castTime, Spell*
if (!spellInfo || castTime < 0)
return;
- if (spellInfo->IsChanneled() && !(spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION))
+ if (spellInfo->IsChanneled() && !spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION))
return;
// called from caster
if (Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell);
- if (!((spellInfo->Attributes & (SPELL_ATTR0_ABILITY | SPELL_ATTR0_TRADESPELL)) || (spellInfo->AttributesEx3 & SPELL_ATTR3_NO_DONE_BONUS)) &&
+ if (!(spellInfo->HasAttribute(SPELL_ATTR0_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR0_TRADESPELL) || spellInfo->HasAttribute(SPELL_ATTR0_TRADESPELL) || spellInfo->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS)) &&
((GetTypeId() == TYPEID_PLAYER && spellInfo->SpellFamilyName) || GetTypeId() == TYPEID_UNIT))
castTime = int32(float(castTime) * GetFloatValue(UNIT_MOD_CAST_SPEED));
- else if (spellInfo->Attributes & SPELL_ATTR0_REQ_AMMO && !(spellInfo->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG))
+ else if (spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) && !spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG))
castTime = int32(float(castTime) * m_modAttackSpeedPct[RANGED_ATTACK]);
else if (spellInfo->SpellVisual[0] == 3881 && HasAura(67556)) // cooking with Chef Hat.
castTime = 500;
@@ -13711,7 +13711,7 @@ void CharmInfo::InitPossessCreateSpells()
{
uint32 spellId = _unit->ToCreature()->m_spells[i];
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
- if (spellInfo && !(spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD))
+ if (spellInfo && !spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD))
{
if (spellInfo->IsPassive())
_unit->CastSpell(_unit, spellInfo, true);
@@ -13739,7 +13739,7 @@ void CharmInfo::InitCharmCreateSpells()
uint32 spellId = _unit->ToCreature()->m_spells[x];
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
- if (!spellInfo || spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD)
+ if (!spellInfo || spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD))
{
_charmspells[x].SetActionAndType(spellId, ACT_DISABLED);
continue;
@@ -14126,7 +14126,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
continue;
// Triggered spells not triggering additional spells
- bool triggered = !(spellProto->AttributesEx3 & SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED) ?
+ bool triggered = !spellProto->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED) ?
(procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_DONE_TRAP_ACTIVATION)) : false;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
@@ -14183,7 +14183,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
cooldown = i->spellProcEvent->cooldown;
// Note: must SetCantProc(false) before return
- if (spellInfo->AttributesEx3 & SPELL_ATTR3_DISABLE_PROC)
+ if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
SetCantProc(true);
bool handled = i->aura->CallScriptProcHandlers(aurApp, eventInfo);
@@ -14378,7 +14378,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
i->aura->CallScriptAfterProcHandlers(aurApp, eventInfo);
- if (spellInfo->AttributesEx3 & SPELL_ATTR3_DISABLE_PROC)
+ if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
SetCantProc(false);
}
@@ -15053,7 +15053,7 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, SpellInfo const
// Additional checks for triggered spells (ignore trap casts)
if (procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_DONE_TRAP_ACTIVATION))
{
- if (!(spellProto->AttributesEx3 & SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED))
+ if (!spellProto->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED))
return false;
}
@@ -16213,7 +16213,7 @@ Aura* Unit::AddAura(uint32 spellId, Unit* target)
if (!spellInfo)
return NULL;
- if (!target->IsAlive() && !(spellInfo->Attributes & SPELL_ATTR0_PASSIVE) && !(spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD))
+ if (!target->IsAlive() && !spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE) && !spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_DEAD))
return NULL;
return AddAura(spellInfo, MAX_EFFECT_MASK, target);
@@ -17316,30 +17316,30 @@ void Unit::StopAttackFaction(uint32 faction_id)
void Unit::OutDebugInfo() const
{
TC_LOG_ERROR("entities.unit", "Unit::OutDebugInfo");
- TC_LOG_INFO("entities.unit", "%s name %s", GetGUID().ToString().c_str(), GetName().c_str());
- TC_LOG_INFO("entities.unit", "Owner %s, Minion %s, Charmer %s, Charmed %s", GetOwnerGUID().ToString().c_str(), GetMinionGUID().ToString().c_str(), GetCharmerGUID().ToString().c_str(), GetCharmGUID().ToString().c_str());
- TC_LOG_INFO("entities.unit", "In world %u, unit type mask %u", (uint32)(IsInWorld() ? 1 : 0), m_unitTypeMask);
+ TC_LOG_DEBUG("entities.unit", "%s name %s", GetGUID().ToString().c_str(), GetName().c_str());
+ TC_LOG_DEBUG("entities.unit", "Owner %s, Minion %s, Charmer %s, Charmed %s", GetOwnerGUID().ToString().c_str(), GetMinionGUID().ToString().c_str(), GetCharmerGUID().ToString().c_str(), GetCharmGUID().ToString().c_str());
+ TC_LOG_DEBUG("entities.unit", "In world %u, unit type mask %u", (uint32)(IsInWorld() ? 1 : 0), m_unitTypeMask);
if (IsInWorld())
- TC_LOG_INFO("entities.unit", "Mapid %u", GetMapId());
+ TC_LOG_DEBUG("entities.unit", "Mapid %u", GetMapId());
std::ostringstream o;
o << "Summon Slot: ";
for (uint32 i = 0; i < MAX_SUMMON_SLOT; ++i)
o << m_SummonSlot[i].ToString() << ", ";
- TC_LOG_INFO("entities.unit", "%s", o.str().c_str());
+ TC_LOG_DEBUG("entities.unit", "%s", o.str().c_str());
o.str("");
o << "Controlled List: ";
for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
o << (*itr)->GetGUID().ToString() << ", ";
- TC_LOG_INFO("entities.unit", "%s", o.str().c_str());
+ TC_LOG_DEBUG("entities.unit", "%s", o.str().c_str());
o.str("");
o << "Aura List: ";
for (AuraApplicationMap::const_iterator itr = m_appliedAuras.begin(); itr != m_appliedAuras.end(); ++itr)
o << itr->first << ", ";
- TC_LOG_INFO("entities.unit", "%s", o.str().c_str());
+ TC_LOG_DEBUG("entities.unit", "%s", o.str().c_str());
o.str("");
if (IsVehicle())
@@ -17348,11 +17348,11 @@ void Unit::OutDebugInfo() const
for (SeatMap::iterator itr = GetVehicleKit()->Seats.begin(); itr != GetVehicleKit()->Seats.end(); ++itr)
if (Unit* passenger = ObjectAccessor::GetUnit(*GetVehicleBase(), itr->second.Passenger.Guid))
o << passenger->GetGUID().ToString() << ", ";
- TC_LOG_INFO("entities.unit", "%s", o.str().c_str());
+ TC_LOG_DEBUG("entities.unit", "%s", o.str().c_str());
}
if (GetVehicle())
- TC_LOG_INFO("entities.unit", "On vehicle %u.", GetVehicleBase()->GetEntry());
+ TC_LOG_DEBUG("entities.unit", "On vehicle %u.", GetVehicleBase()->GetEntry());
}
uint32 Unit::GetRemainingPeriodicAmount(ObjectGuid caster, uint32 spellId, AuraType auraType, uint8 effectIndex) const
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index d07ec212d0c..1db9183fbe4 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -3893,6 +3893,8 @@ void ObjectMgr::BuildPlayerLevelInfo(uint8 race, uint8 _class, uint8 level, Play
}
}
+int32 const ReputationMgr::Reputation_Cap;
+
void ObjectMgr::LoadQuests()
{
uint32 oldMSTime = getMSTime();
@@ -7078,6 +7080,7 @@ void ObjectMgr::LoadReputationSpilloverTemplate()
continue;
}
+ bool invalidSpilloverFaction = false;
for (uint32 i = 0; i < MAX_SPILLOVER_FACTIONS; ++i)
{
if (repTemplate.faction[i])
@@ -7087,47 +7090,28 @@ void ObjectMgr::LoadReputationSpilloverTemplate()
if (!factionSpillover)
{
TC_LOG_ERROR("sql.sql", "Spillover faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template` for faction %u, skipping", repTemplate.faction[i], factionId);
- continue;
+ invalidSpilloverFaction = true;
+ break;
}
if (factionSpillover->reputationListID < 0)
{
TC_LOG_ERROR("sql.sql", "Spillover faction (faction.dbc) %u for faction %u in `reputation_spillover_template` can not be listed for client, and then useless, skipping", repTemplate.faction[i], factionId);
- continue;
+ invalidSpilloverFaction = true;
+ break;
}
if (repTemplate.faction_rank[i] >= MAX_REPUTATION_RANK)
{
TC_LOG_ERROR("sql.sql", "Rank %u used in `reputation_spillover_template` for spillover faction %u is not valid, skipping", repTemplate.faction_rank[i], repTemplate.faction[i]);
- continue;
+ invalidSpilloverFaction = true;
+ break;
}
}
}
- FactionEntry const* factionEntry0 = sFactionStore.LookupEntry(repTemplate.faction[0]);
- if (repTemplate.faction[0] && !factionEntry0)
- {
- TC_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[0]);
- continue;
- }
- FactionEntry const* factionEntry1 = sFactionStore.LookupEntry(repTemplate.faction[1]);
- if (repTemplate.faction[1] && !factionEntry1)
- {
- TC_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[1]);
- continue;
- }
- FactionEntry const* factionEntry2 = sFactionStore.LookupEntry(repTemplate.faction[2]);
- if (repTemplate.faction[2] && !factionEntry2)
- {
- TC_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[2]);
- continue;
- }
- FactionEntry const* factionEntry3 = sFactionStore.LookupEntry(repTemplate.faction[3]);
- if (repTemplate.faction[3] && !factionEntry3)
- {
- TC_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[3]);
+ if (invalidSpilloverFaction)
continue;
- }
_repSpilloverTemplateStore[factionId] = repTemplate;
@@ -8619,7 +8603,6 @@ void ObjectMgr::LoadBroadcastTexts()
}
_broadcastTextStore.rehash(result->GetRowCount());
- uint32 count = 0;
do
{
@@ -8645,26 +8628,23 @@ void ObjectMgr::LoadBroadcastTexts()
{
if (!sSoundEntriesStore.LookupEntry(bct.SoundId))
{
- TC_LOG_INFO("sql.sql", "BroadcastText (Id: %u) in table `broadcast_text` has SoundId %u but sound does not exist. Skipped.", bct.Id, bct.SoundId);
- // don't load bct of higher expansions
- continue;
+ TC_LOG_DEBUG("broadcasttext", "BroadcastText (Id: %u) in table `broadcast_text` has SoundId %u but sound does not exist.", bct.Id, bct.SoundId);
+ bct.SoundId = 0;
}
}
if (!GetLanguageDescByID(bct.Language))
{
- TC_LOG_INFO("sql.sql", "BroadcastText (Id: %u) in table `broadcast_text` using Language %u but Language does not exist. Skipped.", bct.Id, bct.Language);
- // don't load bct of higher expansions
- continue;
+ TC_LOG_DEBUG("broadcasttext", "BroadcastText (Id: %u) in table `broadcast_text` using Language %u but Language does not exist.", bct.Id, bct.Language);
+ bct.Language = LANG_UNIVERSAL;
}
if (bct.EmoteId0)
{
if (!sEmotesStore.LookupEntry(bct.EmoteId0))
{
- TC_LOG_INFO("sql.sql", "BroadcastText (Id: %u) in table `broadcast_text` has EmoteId0 %u but emote does not exist. Skipped.", bct.Id, bct.EmoteId0);
- // don't load bct of higher expansions
- continue;
+ TC_LOG_DEBUG("broadcasttext", "BroadcastText (Id: %u) in table `broadcast_text` has EmoteId0 %u but emote does not exist.", bct.Id, bct.EmoteId0);
+ bct.EmoteId0 = 0;
}
}
@@ -8672,9 +8652,8 @@ void ObjectMgr::LoadBroadcastTexts()
{
if (!sEmotesStore.LookupEntry(bct.EmoteId1))
{
- TC_LOG_INFO("sql.sql", "BroadcastText (Id: %u) in table `broadcast_text` has EmoteId1 %u but emote does not exist. Skipped.", bct.Id, bct.EmoteId1);
- // don't load bct of higher expansions
- continue;
+ TC_LOG_DEBUG("broadcasttext", "BroadcastText (Id: %u) in table `broadcast_text` has EmoteId1 %u but emote does not exist.", bct.Id, bct.EmoteId1);
+ bct.EmoteId1 = 0;
}
}
@@ -8682,19 +8661,16 @@ void ObjectMgr::LoadBroadcastTexts()
{
if (!sEmotesStore.LookupEntry(bct.EmoteId2))
{
- TC_LOG_INFO("sql.sql", "BroadcastText (Id: %u) in table `broadcast_text` has EmoteId2 %u but emote does not exist. Skipped.", bct.Id, bct.EmoteId2);
- // don't load bct of higher expansions
- continue;
+ TC_LOG_DEBUG("broadcasttext", "BroadcastText (Id: %u) in table `broadcast_text` has EmoteId2 %u but emote does not exist.", bct.Id, bct.EmoteId2);
+ bct.EmoteId2 = 0;
}
}
_broadcastTextStore[bct.Id] = bct;
-
- ++count;
}
while (result->NextRow());
- TC_LOG_INFO("server.loading", ">> Loaded %u broadcast texts in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " broadcast texts in %u ms", _broadcastTextStore.size(), GetMSTimeDiffToNow(oldMSTime));
}
void ObjectMgr::LoadBroadcastTextLocales()
@@ -8720,8 +8696,7 @@ void ObjectMgr::LoadBroadcastTextLocales()
BroadcastTextContainer::iterator bct = _broadcastTextStore.find(id);
if (bct == _broadcastTextStore.end())
{
- TC_LOG_INFO("sql.sql", "BroadcastText (Id: %u) in table `locales_broadcast_text` does not exist or is incompatible. Skipped!", id);
- // don't load bct of higher expansions
+ TC_LOG_ERROR("sql.sql", "BroadcastText (Id: %u) in table `locales_broadcast_text` does not exist. Skipped!", id);
continue;
}
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
index e14910bdf5e..abe302d2d3d 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
@@ -65,7 +65,7 @@ void VisibleNotifier::SendToSelf()
}
}
- for (GuidSet::const_iterator it = vis_guids.begin(); it != vis_guids.end(); ++it)
+ for (auto it = vis_guids.begin(); it != vis_guids.end(); ++it)
{
i_player.m_clientGUIDs.erase(*it);
i_data.AddOutOfRangeGUID(*it);
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h
index 5eb726084b3..ccf9748e67a 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.h
@@ -43,7 +43,7 @@ namespace Trinity
Player &i_player;
UpdateData i_data;
std::set<Unit*> i_visibleNow;
- GuidSet vis_guids;
+ GuidUnorderedSet vis_guids;
VisibleNotifier(Player &player) : i_player(player), vis_guids(player.m_clientGUIDs) { }
template<class T> void Visit(GridRefManager<T> &m);
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index d9124551c63..5664cbb6e4b 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -1808,7 +1808,7 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const*
return ERR_BATTLEGROUND_NONE; // ERR_GROUP_JOIN_BATTLEGROUND_TOO_MANY handled on client side
// get a player as reference, to compare other players' stats to (arena team id, queue id based on level, etc.)
- Player* reference = GetFirstMember()->GetSource();
+ Player* reference = ASSERT_NOTNULL(GetFirstMember())->GetSource();
// no reference found, can't join this way
if (!reference)
return ERR_BATTLEGROUND_JOIN_FAILED;
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 0fcaa47a5e2..9ff2041ee92 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -70,7 +70,7 @@ void WorldSession::HandlePetAction(WorldPacket& recvData)
// used also for charmed creature
Unit* pet = ObjectAccessor::GetUnit(*_player, guid1);
- TC_LOG_INFO("network", "HandlePetAction: %s - flag: %u, spellid: %u, target: %s.", guid1.ToString().c_str(), uint32(flag), spellid, guid2.ToString().c_str());
+ TC_LOG_DEBUG("network", "HandlePetAction: %s - flag: %u, spellid: %u, target: %s.", guid1.ToString().c_str(), uint32(flag), spellid, guid2.ToString().c_str());
if (!pet)
{
@@ -89,7 +89,7 @@ void WorldSession::HandlePetAction(WorldPacket& recvData)
SpellInfo const* spell = (flag == ACT_ENABLED || flag == ACT_PASSIVE) ? sSpellMgr->GetSpellInfo(spellid) : NULL;
if (!spell)
return;
- if (!(spell->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD))
+ if (!spell->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD))
return;
}
@@ -398,7 +398,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
void WorldSession::HandlePetNameQuery(WorldPacket& recvData)
{
- TC_LOG_INFO("network", "HandlePetNameQuery. CMSG_PET_NAME_QUERY");
+ TC_LOG_DEBUG("network", "WORLD: Received CMSG_PET_NAME_QUERY");
uint32 petnumber;
ObjectGuid petguid;
@@ -465,7 +465,7 @@ bool WorldSession::CheckStableMaster(ObjectGuid guid)
void WorldSession::HandlePetSetAction(WorldPacket& recvData)
{
- TC_LOG_INFO("network", "HandlePetSetAction. CMSG_PET_SET_ACTION");
+ TC_LOG_DEBUG("network", "WORLD: Received CMSG_PET_SET_ACTION");
ObjectGuid petguid;
uint8 count;
@@ -545,7 +545,7 @@ void WorldSession::HandlePetSetAction(WorldPacket& recvData)
uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(data[i]);
uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]);
- TC_LOG_INFO("network", "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X",
+ TC_LOG_DEBUG("network", "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X",
_player->GetName().c_str(), position[i], spell_id, uint32(act_state));
//if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add
@@ -582,7 +582,7 @@ void WorldSession::HandlePetSetAction(WorldPacket& recvData)
void WorldSession::HandlePetRename(WorldPacket& recvData)
{
- TC_LOG_INFO("network", "HandlePetRename. CMSG_PET_RENAME");
+ TC_LOG_DEBUG("network", "WORLD: Received CMSG_PET_RENAME");
ObjectGuid petguid;
uint8 isdeclined;
@@ -670,7 +670,7 @@ void WorldSession::HandlePetAbandon(WorldPacket& recvData)
{
ObjectGuid guid;
recvData >> guid; //pet guid
- TC_LOG_INFO("network", "HandlePetAbandon. CMSG_PET_ABANDON %s", guid.ToString().c_str());
+ TC_LOG_DEBUG("network", "WORLD: Received CMSG_PET_ABANDON %s", guid.ToString().c_str());
if (!_player->IsInWorld())
return;
@@ -696,7 +696,7 @@ void WorldSession::HandlePetAbandon(WorldPacket& recvData)
void WorldSession::HandlePetSpellAutocastOpcode(WorldPacket& recvPacket)
{
- TC_LOG_INFO("network", "CMSG_PET_SPELL_AUTOCAST");
+ TC_LOG_DEBUG("network", "WORLD: Received CMSG_PET_SPELL_AUTOCAST");
ObjectGuid guid;
uint32 spellid;
uint8 state; //1 for on, 0 for off
@@ -744,7 +744,7 @@ void WorldSession::HandlePetSpellAutocastOpcode(WorldPacket& recvPacket)
void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
{
- TC_LOG_DEBUG("network", "WORLD: CMSG_PET_CAST_SPELL");
+ TC_LOG_DEBUG("network", "WORLD: Received CMSG_PET_CAST_SPELL");
ObjectGuid guid;
uint8 castCount;
@@ -846,7 +846,7 @@ void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, Dec
void WorldSession::HandlePetLearnTalent(WorldPacket& recvData)
{
- TC_LOG_DEBUG("network", "WORLD: CMSG_PET_LEARN_TALENT");
+ TC_LOG_DEBUG("network", "WORLD: Received CMSG_PET_LEARN_TALENT");
ObjectGuid guid;
uint32 talentId, requestedRank;
@@ -858,7 +858,7 @@ void WorldSession::HandlePetLearnTalent(WorldPacket& recvData)
void WorldSession::HandleLearnPreviewTalentsPet(WorldPacket& recvData)
{
- TC_LOG_DEBUG("network", "CMSG_LEARN_PREVIEW_TALENTS_PET");
+ TC_LOG_DEBUG("network", "WORLD: Received CMSG_LEARN_PREVIEW_TALENTS_PET");
ObjectGuid guid;
recvData >> guid;
diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp
index d6d7e3b9876..3c6258b2d7c 100644
--- a/src/server/game/Handlers/QuestHandler.cpp
+++ b/src/server/game/Handlers/QuestHandler.cpp
@@ -458,6 +458,12 @@ void WorldSession::HandleQuestConfirmAccept(WorldPacket& recvData)
if (!_player->IsInSameRaidWith(originalPlayer))
return;
+ if (!originalPlayer->CanShareQuest(questId))
+ return;
+
+ if (!_player->CanTakeQuest(quest, true))
+ return;
+
if (_player->CanAddQuest(quest, true))
_player->AddQuestAndCheckCompletion(quest, NULL); // NULL, this prevent DB script from duplicate running
@@ -621,7 +627,7 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket
WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4);
data << uint32(count); // placeholder
- for (GuidSet::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr)
+ for (auto itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr)
{
uint32 questStatus = DIALOG_STATUS_NONE;
diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
index c4bd892d3cf..fede3e30211 100644
--- a/src/server/game/Handlers/SpellHandler.cpp
+++ b/src/server/game/Handlers/SpellHandler.cpp
@@ -417,7 +417,7 @@ void WorldSession::HandleCancelAuraOpcode(WorldPacket& recvPacket)
return;
// not allow remove spells with attr SPELL_ATTR0_CANT_CANCEL
- if (spellInfo->Attributes & SPELL_ATTR0_CANT_CANCEL)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_CANT_CANCEL))
return;
// channeled spell case (it currently cast then)
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index db6a2c98379..52b866850a6 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -1832,7 +1832,7 @@ void LoadLootTemplates_Spell()
{
// not report about not trainable spells (optionally supported by DB)
// ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example
- if (!(spellInfo->Attributes & SPELL_ATTR0_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR0_TRADESPELL))
+ if (!spellInfo->HasAttribute(SPELL_ATTR0_NOT_SHAPESHIFT) || spellInfo->HasAttribute(SPELL_ATTR0_TRADESPELL))
{
LootTemplates_Spell.ReportNonExistingId(spell_id, "Spell", spellInfo->Id);
}
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 49f7bc86081..b4066b2257e 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -80,7 +80,10 @@ bool Map::ExistMap(uint32 mapid, int gx, int gy)
FILE* pf = fopen(fileName, "rb");
if (!pf)
- TC_LOG_ERROR("maps", "Map file '%s': does not exist!", fileName);
+ {
+ TC_LOG_ERROR("maps", "Map file '%s' does not exist!", fileName);
+ TC_LOG_ERROR("maps", "Please place MAP-files (*.map) in the appropriate directory (%s), or correct the DataDir setting in your worldserver.conf file.", (sWorld->GetDataPath()+"maps/").c_str());
+ }
else
{
map_fileheader header;
@@ -109,7 +112,8 @@ bool Map::ExistVMap(uint32 mapid, int gx, int gy)
if (!exists)
{
std::string name = vmgr->getDirFileName(mapid, gx, gy);
- TC_LOG_ERROR("maps", "VMap file '%s' is missing or points to wrong version of vmap file. Redo vmaps with latest version of vmap_assembler.exe.", (sWorld->GetDataPath()+"vmaps/"+name).c_str());
+ TC_LOG_ERROR("maps", "VMap file '%s' does not exist", (sWorld->GetDataPath()+"vmaps/"+name).c_str());
+ TC_LOG_ERROR("maps", "Please place VMAP-files (*.vmtree and *.vmtile) in the vmap-directory (%s), or correct the DataDir setting in your worldserver.conf file.", (sWorld->GetDataPath()+"vmaps/").c_str());
return false;
}
}
@@ -126,9 +130,9 @@ void Map::LoadMMap(int gx, int gy)
bool mmapLoadResult = MMAP::MMapFactory::createOrGetMMapManager()->loadMap((sWorld->GetDataPath() + "mmaps").c_str(), GetId(), gx, gy);
if (mmapLoadResult)
- TC_LOG_INFO("maps", "MMAP loaded name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
+ TC_LOG_DEBUG("maps", "MMAP loaded name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
else
- TC_LOG_INFO("maps", "Could not load MMAP name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
+ TC_LOG_ERROR("maps", "Could not load MMAP name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
}
void Map::LoadVMap(int gx, int gy)
@@ -140,10 +144,10 @@ void Map::LoadVMap(int gx, int gy)
switch (vmapLoadResult)
{
case VMAP::VMAP_LOAD_RESULT_OK:
- TC_LOG_INFO("maps", "VMAP loaded name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
+ TC_LOG_DEBUG("maps", "VMAP loaded name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
break;
case VMAP::VMAP_LOAD_RESULT_ERROR:
- TC_LOG_INFO("maps", "Could not load VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
+ TC_LOG_ERROR("maps", "Could not load VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
break;
case VMAP::VMAP_LOAD_RESULT_IGNORED:
TC_LOG_DEBUG("maps", "Ignored VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
@@ -173,7 +177,7 @@ void Map::LoadMap(int gx, int gy, bool reload)
//map already load, delete it before reloading (Is it necessary? Do we really need the ability the reload maps during runtime?)
if (GridMaps[gx][gy])
{
- TC_LOG_INFO("maps", "Unloading previously loaded map %u before reloading.", GetId());
+ TC_LOG_DEBUG("maps", "Unloading previously loaded map %u before reloading.", GetId());
sScriptMgr->OnUnloadGridMap(this, GridMaps[gx][gy], gx, gy);
delete (GridMaps[gx][gy]);
@@ -185,7 +189,7 @@ void Map::LoadMap(int gx, int gy, bool reload)
int len = sWorld->GetDataPath().length() + strlen("maps/%03u%02u%02u.map") + 1;
tmp = new char[len];
snprintf(tmp, len, (char *)(sWorld->GetDataPath() + "maps/%03u%02u%02u.map").c_str(), GetId(), gx, gy);
- TC_LOG_INFO("maps", "Loading map %s", tmp);
+ TC_LOG_DEBUG("maps", "Loading map %s", tmp);
// loading data
GridMaps[gx][gy] = new GridMap();
if (!GridMaps[gx][gy]->loadData(tmp))
@@ -2497,7 +2501,7 @@ void Map::UpdateObjectsVisibilityFor(Player* player, Cell cell, CellCoord cellpa
void Map::SendInitSelf(Player* player)
{
- TC_LOG_INFO("maps", "Creating player data for himself %u", player->GetGUIDLow());
+ TC_LOG_DEBUG("maps", "Creating player data for himself %u", player->GetGUIDLow());
UpdateData data;
@@ -2849,7 +2853,7 @@ bool InstanceMap::CanEnter(Player* player)
uint32 maxPlayers = GetMaxPlayers();
if (GetPlayersCountExceptGMs() >= maxPlayers)
{
- TC_LOG_INFO("maps", "MAP: Instance '%u' of map '%s' cannot have more than '%u' players. Player '%s' rejected", GetInstanceId(), GetMapName(), maxPlayers, player->GetName().c_str());
+ TC_LOG_WARN("maps", "MAP: Instance '%u' of map '%s' cannot have more than '%u' players. Player '%s' rejected", GetInstanceId(), GetMapName(), maxPlayers, player->GetName().c_str());
player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAX_PLAYERS);
return false;
}
@@ -2918,7 +2922,7 @@ bool InstanceMap::AddPlayerToMap(Player* player)
InstanceSave* mapSave = sInstanceSaveMgr->GetInstanceSave(GetInstanceId());
if (!mapSave)
{
- TC_LOG_INFO("maps", "InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId());
+ TC_LOG_DEBUG("maps", "InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId());
mapSave = sInstanceSaveMgr->AddInstanceSave(GetId(), GetInstanceId(), Difficulty(GetSpawnMode()), 0, true);
}
@@ -2994,7 +2998,7 @@ bool InstanceMap::AddPlayerToMap(Player* player)
// first player enters (no players yet)
SetResetSchedule(false);
- TC_LOG_INFO("maps", "MAP: Player '%s' entered instance '%u' of map '%s'", player->GetName().c_str(), GetInstanceId(), GetMapName());
+ TC_LOG_DEBUG("maps", "MAP: Player '%s' entered instance '%u' of map '%s'", player->GetName().c_str(), GetInstanceId(), GetMapName());
// initialize unload state
m_unloadTimer = 0;
m_resetAfterUnload = false;
@@ -3020,7 +3024,7 @@ void InstanceMap::Update(const uint32 t_diff)
void InstanceMap::RemovePlayerFromMap(Player* player, bool remove)
{
- TC_LOG_INFO("maps", "MAP: Removing player '%s' from instance '%u' of map '%s' before relocating to another map", player->GetName().c_str(), GetInstanceId(), GetMapName());
+ TC_LOG_DEBUG("maps", "MAP: Removing player '%s' from instance '%u' of map '%s' before relocating to another map", player->GetName().c_str(), GetInstanceId(), GetMapName());
//if last player set unload timer
if (!m_unloadTimer && m_mapRefManager.getSize() == 1)
m_unloadTimer = m_unloadWhenEmpty ? MIN_UNLOAD_DELAY : std::max(sWorld->getIntConfig(CONFIG_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY);
@@ -3253,7 +3257,7 @@ bool BattlegroundMap::AddPlayerToMap(Player* player)
void BattlegroundMap::RemovePlayerFromMap(Player* player, bool remove)
{
- TC_LOG_INFO("maps", "MAP: Removing player '%s' from bg '%u' of map '%s' before relocating to another map", player->GetName().c_str(), GetInstanceId(), GetMapName());
+ TC_LOG_DEBUG("maps", "MAP: Removing player '%s' from bg '%u' of map '%s' before relocating to another map", player->GetName().c_str(), GetInstanceId(), GetMapName());
Map::RemovePlayerFromMap(player, remove);
}
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 8131984224f..9bae8fbdfae 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -207,7 +207,8 @@ enum TrinityStrings
LANG_LIQUID_STATUS = 175,
LANG_INVALID_GAMEOBJECT_TYPE = 176,
LANG_GAMEOBJECT_DAMAGED = 177,
- // Room for more level 1 178-199 not used
+ LANG_GRID_POSITION = 178,
+ // Room for more level 1 179-199 not used
// level 2 chat
LANG_NO_SELECTION = 200,
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 0775a9a299a..685bcd338a9 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -427,7 +427,7 @@ enum SpellAttr4
SPELL_ATTR4_UNK4 = 0x00000010, // 4 This will no longer cause guards to attack on use??
SPELL_ATTR4_UNK5 = 0x00000020, // 5
SPELL_ATTR4_NOT_STEALABLE = 0x00000040, // 6 although such auras might be dispellable, they cannot be stolen
- SPELL_ATTR4_TRIGGERED = 0x00000080, // 7 spells forced to be triggered
+ SPELL_ATTR4_CAN_CAST_WHILE_CASTING = 0x00000080, // 7 Can be cast while another cast is in progress - see CanCastWhileCasting(SpellRec const*,CGUnit_C *,int &)
SPELL_ATTR4_FIXED_DAMAGE = 0x00000100, // 8 Ignores resilience and any (except mechanic related) damage or % damage taken auras on target.
SPELL_ATTR4_TRIGGER_ACTIVATE = 0x00000200, // 9 initially disabled / trigger activate from event (Execute, Riposte, Deep Freeze end other)
SPELL_ATTR4_SPELL_VS_EXTEND_COST = 0x00000400, // 10 Rogue Shiv have this flag
diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp
index 298e534d58e..bda3ad851c8 100644
--- a/src/server/game/Movement/MotionMaster.cpp
+++ b/src/server/game/Movement/MotionMaster.cpp
@@ -387,6 +387,43 @@ void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float spee
Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED);
}
+void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount)
+{
+ float step = 2 * float(M_PI) / stepCount * (clockwise ? -1.0f : 1.0f);
+ Position const& pos = { x, y, z, 0.0f };
+ float angle = pos.GetAngle(_owner->GetPositionX(), _owner->GetPositionY());
+
+ Movement::MoveSplineInit init(_owner);
+
+ for (uint8 i = 0; i < stepCount; angle += step, ++i)
+ {
+ G3D::Vector3 point;
+ point.x = x + radius * cosf(angle);
+ point.y = y + radius * sinf(angle);
+
+ if (_owner->IsFlying())
+ point.z = z;
+ else
+ point.z = _owner->GetMap()->GetHeight(_owner->GetPhaseMask(), point.x, point.y, z);
+
+ init.Path().push_back(point);
+ }
+
+ if (_owner->IsFlying())
+ {
+ init.SetFly();
+ init.SetCyclic();
+ init.SetAnimation(Movement::ToFly);
+ }
+ else
+ {
+ init.SetWalk(true);
+ init.SetCyclic();
+ }
+
+ init.Launch();
+}
+
void MotionMaster::MoveFall(uint32 id /*=0*/)
{
// use larger distance for vmap height search than in most other cases
@@ -647,7 +684,7 @@ void MotionMaster::DirectDelete(_Ty curr)
void MotionMaster::DelayedDelete(_Ty curr)
{
- TC_LOG_FATAL("misc", "Unit (Entry %u) is trying to delete its updating MG (Type %u)!", _owner->GetEntry(), curr->GetMovementGeneratorType());
+ TC_LOG_FATAL("misc", "Unit (Entry %u) is trying to delete its updating Movement Generator (Type %u)!", _owner->GetEntry(), curr->GetMovementGeneratorType());
if (isStatic(curr))
return;
if (!_expList)
diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h
index 2821cd5a59b..0b547d96e7f 100644
--- a/src/server/game/Movement/MotionMaster.h
+++ b/src/server/game/Movement/MotionMaster.h
@@ -184,6 +184,7 @@ class MotionMaster //: private std::stack<MovementGenerator *>
void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = EVENT_JUMP)
{ MoveJump(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speedXY, speedZ, id); };
void MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id = EVENT_JUMP);
+ void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount);
void MoveFall(uint32 id = 0);
void MoveSeekAssistance(float x, float y, float z);
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index ed1ea7f4b17..a382bf9547e 100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -379,9 +379,9 @@ void FlightPathMovementGenerator::PreloadEndGrid()
// Load the grid
if (endMap)
{
- TC_LOG_INFO("misc", "Preloading rid (%f, %f) for map %u at node index %u/%u", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path->size()-1));
+ TC_LOG_DEBUG("misc", "Preloading rid (%f, %f) for map %u at node index %u/%u", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path->size()-1));
endMap->LoadGrid(_endGridX, _endGridY);
}
else
- TC_LOG_INFO("misc", "Unable to determine map to preload flightmaster grid");
+ TC_LOG_DEBUG("misc", "Unable to determine map to preload flightmaster grid");
}
diff --git a/src/server/game/Movement/Spline/MoveSpline.cpp b/src/server/game/Movement/Spline/MoveSpline.cpp
index d3fa03c1238..1beeebbbad3 100644
--- a/src/server/game/Movement/Spline/MoveSpline.cpp
+++ b/src/server/game/Movement/Spline/MoveSpline.cpp
@@ -147,7 +147,7 @@ void MoveSpline::init_spline(const MoveSplineInitArgs& args)
/// @todo what to do in such cases? problem is in input data (all points are at same coords)
if (spline.length() < minimal_duration)
{
- TC_LOG_ERROR("misc", "MoveSpline::init_spline: zero length spline, wrong input data?");
+ TC_LOG_DEBUG("misc", "MoveSpline::init_spline: zero length spline, wrong input data?");
spline.set_length(spline.last(), spline.isCyclic() ? 1000 : 1);
}
point_Idx = spline.first();
diff --git a/src/server/game/Reputation/ReputationMgr.cpp b/src/server/game/Reputation/ReputationMgr.cpp
index ad71381a1de..b99cb677ba0 100644
--- a/src/server/game/Reputation/ReputationMgr.cpp
+++ b/src/server/game/Reputation/ReputationMgr.cpp
@@ -297,7 +297,7 @@ bool ReputationMgr::SetReputation(FactionEntry const* factionEntry, int32 standi
{
// bonuses are already given, so just modify standing by rate
int32 spilloverRep = int32(standing * repTemplate->faction_rate[i]);
- SetOneFactionReputation(sFactionStore.LookupEntry(repTemplate->faction[i]), spilloverRep, incremental);
+ SetOneFactionReputation(sFactionStore.AssertEntry(repTemplate->faction[i]), spilloverRep, incremental);
}
}
}
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index 025184ff6ef..8be5da91c32 100644
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -356,7 +356,6 @@ void AddSC_dustwallow_marsh();
void AddSC_felwood();
void AddSC_feralas();
void AddSC_moonglade();
-void AddSC_mulgore();
void AddSC_orgrimmar();
void AddSC_silithus();
void AddSC_stonetalon_mountains();
@@ -426,7 +425,8 @@ void AddSC_boss_heigan();
void AddSC_boss_gothik();
void AddSC_boss_thaddius();
void AddSC_instance_naxxramas();
-void AddSC_boss_magus_telestra(); //The Nexus Nexus
+void AddSC_boss_nexus_commanders(); // The Nexus Nexus
+void AddSC_boss_magus_telestra();
void AddSC_boss_anomalus();
void AddSC_boss_ormorok();
void AddSC_boss_keristrasza();
@@ -1061,7 +1061,6 @@ void AddKalimdorScripts()
AddSC_felwood();
AddSC_feralas();
AddSC_moonglade();
- AddSC_mulgore();
AddSC_orgrimmar();
AddSC_silithus();
AddSC_stonetalon_mountains();
@@ -1255,7 +1254,8 @@ void AddNorthrendScripts()
AddSC_boss_gothik();
AddSC_boss_thaddius();
AddSC_instance_naxxramas();
- AddSC_boss_magus_telestra(); //The Nexus Nexus
+ AddSC_boss_nexus_commanders(); // The Nexus Nexus
+ AddSC_boss_magus_telestra();
AddSC_boss_anomalus();
AddSC_boss_ormorok();
AddSC_boss_keristrasza();
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index 628452d120c..aed829a7b57 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -182,9 +182,8 @@ struct TSpellSummary
uint8 Effects; // set of enum SelectEffect
} *SpellSummary;
-ScriptMgr::ScriptMgr() : _scriptCount(0)
+ScriptMgr::ScriptMgr() : _scriptCount(0), _scheduledScripts(0)
{
- _scheduledScripts = 0;
}
ScriptMgr::~ScriptMgr() { }
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index e290b13c635..a226f1b7ed2 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -1142,7 +1142,7 @@ class ScriptMgr
uint32 _scriptCount;
//atomic op counter for active scripts amount
- std::atomic_long _scheduledScripts;
+ std::atomic<uint32> _scheduledScripts;
};
#endif
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index b6b1a4992af..fa50fd56576 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -218,8 +218,8 @@ void WorldSession::SendPacket(WorldPacket* packet)
{
uint64 minTime = uint64(cur_time - lastTime);
uint64 fullTime = uint64(lastTime - firstTime);
- TC_LOG_INFO("misc", "Send all time packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f time: %u", sendPacketCount, sendPacketBytes, float(sendPacketCount)/fullTime, float(sendPacketBytes)/fullTime, uint32(fullTime));
- TC_LOG_INFO("misc", "Send last min packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f", sendLastPacketCount, sendLastPacketBytes, float(sendLastPacketCount)/minTime, float(sendLastPacketBytes)/minTime);
+ TC_LOG_DEBUG("misc", "Send all time packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f time: %u", sendPacketCount, sendPacketBytes, float(sendPacketCount)/fullTime, float(sendPacketBytes)/fullTime, uint32(fullTime));
+ TC_LOG_DEBUG("misc", "Send last min packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f", sendLastPacketCount, sendLastPacketBytes, float(sendLastPacketCount)/minTime, float(sendLastPacketBytes)/minTime);
lastTime = cur_time;
sendLastPacketCount = 1;
@@ -981,7 +981,7 @@ void WorldSession::ReadAddonsInfo(WorldPacket &data)
addonInfo >> enabled >> crc >> unk1;
- TC_LOG_INFO("misc", "ADDON: Name: %s, Enabled: 0x%x, CRC: 0x%x, Unknown2: 0x%x", addonName.c_str(), enabled, crc, unk1);
+ TC_LOG_DEBUG("misc", "ADDON: Name: %s, Enabled: 0x%x, CRC: 0x%x, Unknown2: 0x%x", addonName.c_str(), enabled, crc, unk1);
AddonInfo addon(addonName, enabled, crc, 2, true);
@@ -989,15 +989,15 @@ void WorldSession::ReadAddonsInfo(WorldPacket &data)
if (savedAddon)
{
if (addon.CRC != savedAddon->CRC)
- TC_LOG_INFO("misc", "ADDON: %s was known, but didn't match known CRC (0x%x)!", addon.Name.c_str(), savedAddon->CRC);
+ TC_LOG_ERROR("misc", "ADDON: %s was known, but didn't match known CRC (0x%x)!", addon.Name.c_str(), savedAddon->CRC);
else
- TC_LOG_INFO("misc", "ADDON: %s was known, CRC is correct (0x%x)", addon.Name.c_str(), savedAddon->CRC);
+ TC_LOG_DEBUG("misc", "ADDON: %s was known, CRC is correct (0x%x)", addon.Name.c_str(), savedAddon->CRC);
}
else
{
AddonMgr::SaveAddon(addon);
- TC_LOG_INFO("misc", "ADDON: %s (0x%x) was not known, saving...", addon.Name.c_str(), addon.CRC);
+ TC_LOG_DEBUG("misc", "ADDON: %s (0x%x) was not known, saving...", addon.Name.c_str(), addon.CRC);
}
/// @todo Find out when to not use CRC/pubkey, and other possible states.
@@ -1048,7 +1048,7 @@ void WorldSession::SendAddonsInfo()
data << uint8(usepk);
if (usepk) // if CRC is wrong, add public key (client need it)
{
- TC_LOG_INFO("misc", "ADDON: CRC (0x%x) for addon %s is wrong (does not match expected 0x%x), sending pubkey",
+ TC_LOG_DEBUG("misc", "ADDON: CRC (0x%x) for addon %s is wrong (does not match expected 0x%x), sending pubkey",
itr->CRC, itr->Name.c_str(), STANDARD_ADDON_CRC);
data.append(addonPublicKey, sizeof(addonPublicKey));
@@ -1262,7 +1262,7 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co
return true;
case POLICY_KICK:
{
- TC_LOG_INFO("network", "AntiDOS: Player kicked!");
+ TC_LOG_WARN("network", "AntiDOS: Player kicked!");
Session->KickPlayer();
return false;
}
@@ -1278,7 +1278,7 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co
case BAN_IP: nameOrIp = Session->GetRemoteAddress(); break;
}
sWorld->BanAccount(bm, nameOrIp, duration, "DOS (Packet Flooding/Spoofing", "Server: AutoDOS");
- TC_LOG_INFO("network", "AntiDOS: Player automatically banned for %u seconds.", duration);
+ TC_LOG_WARN("network", "AntiDOS: Player automatically banned for %u seconds.", duration);
Session->KickPlayer();
return false;
}
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index 5b1d9497953..0bb864de0ed 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -146,14 +146,12 @@ bool WorldSocket::ReadDataHandler()
uint16 opcode = uint16(header->cmd);
- std::string opcodeName = GetOpcodeNameForLogging(opcode);
-
WorldPacket packet(opcode, std::move(_packetBuffer));
if (sPacketLog->CanLogPacket())
sPacketLog->LogPacket(packet, CLIENT_TO_SERVER, GetRemoteIpAddress(), GetRemotePort());
- TC_LOG_TRACE("network.opcode", "C->S: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), opcodeName.c_str());
+ TC_LOG_TRACE("network.opcode", "C->S: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(opcode).c_str());
switch (opcode)
{
@@ -170,7 +168,7 @@ bool WorldSocket::ReadDataHandler()
HandleAuthSession(packet);
break;
case CMSG_KEEP_ALIVE:
- TC_LOG_DEBUG("network", "%s", opcodeName.c_str());
+ TC_LOG_DEBUG("network", "%s", GetOpcodeNameForLogging(opcode).c_str());
sScriptMgr->OnPacketReceive(_worldSession, packet);
break;
default:
@@ -257,7 +255,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
recvPacket >> unk4;
recvPacket.read(digest, 20);
- TC_LOG_INFO("network", "WorldSocket::HandleAuthSession: client %u, serverId %u, account %s, loginServerType %u, clientseed %u, realmIndex %u",
+ TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: client %u, serverId %u, account %s, loginServerType %u, clientseed %u, realmIndex %u",
clientBuild,
serverId,
account.c_str(),
@@ -429,7 +427,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType)
{
SendAuthResponseError(AUTH_UNAVAILABLE);
- TC_LOG_INFO("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
+ TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
sScriptMgr->OnFailedAccountLogin(id);
DelayedCloseSocket();
return;
diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp
index 947bd62860c..e83d39cb922 100644
--- a/src/server/game/Server/WorldSocketMgr.cpp
+++ b/src/server/game/Server/WorldSocketMgr.cpp
@@ -46,6 +46,8 @@ WorldSocketMgr::WorldSocketMgr() : BaseSocketMgr(), _socketSendBufferSize(-1), m
{
}
+int const boost::asio::socket_base::max_connections;
+
bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port)
{
_tcpNoDelay = sConfigMgr->GetBoolDefault("Network.TcpNodelay", true);
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index e5b8cd111bc..5366326a022 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -542,11 +542,11 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load)
// Haste modifies periodic time of channeled spells
if (m_spellInfo->IsChanneled())
{
- if (m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION))
caster->ModSpellCastTime(m_spellInfo, m_amplitude);
}
// and periodic time of auras affected by SPELL_AURA_PERIODIC_HASTE
- else if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION)
+ else if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION))
m_amplitude = int32(m_amplitude * caster->GetFloatValue(UNIT_MOD_CAST_SPEED));
}
}
@@ -555,7 +555,7 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load)
{
m_tickNumber = m_amplitude ? GetBase()->GetDuration() / m_amplitude : 0;
m_periodicTimer = m_amplitude ? GetBase()->GetDuration() % m_amplitude : 0;
- if (m_spellInfo->AttributesEx5 & SPELL_ATTR5_START_PERIODIC_AT_APPLY)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR5_START_PERIODIC_AT_APPLY))
++m_tickNumber;
}
else // aura just created or reapplied
@@ -571,7 +571,7 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load)
{
m_periodicTimer = 0;
// Start periodic on next tick or at aura apply
- if (m_amplitude && !(m_spellInfo->AttributesEx5 & SPELL_ATTR5_START_PERIODIC_AT_APPLY))
+ if (m_amplitude && !m_spellInfo->HasAttribute(SPELL_ATTR5_START_PERIODIC_AT_APPLY))
m_periodicTimer += m_amplitude;
}
}
@@ -1133,7 +1133,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
continue;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
- if (!spellInfo || !(spellInfo->Attributes & (SPELL_ATTR0_PASSIVE | SPELL_ATTR0_HIDDEN_CLIENTSIDE)))
+ if (!spellInfo || !(spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE) || spellInfo->HasAttribute(SPELL_ATTR0_HIDDEN_CLIENTSIDE)))
continue;
if (spellInfo->Stances & (1<<(GetMiscValue()-1)))
@@ -1148,7 +1148,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
if (GlyphPropertiesEntry const* glyph = sGlyphPropertiesStore.LookupEntry(glyphId))
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(glyph->SpellId);
- if (!spellInfo || !(spellInfo->Attributes & (SPELL_ATTR0_PASSIVE | SPELL_ATTR0_HIDDEN_CLIENTSIDE)))
+ if (!spellInfo || !(spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE) || spellInfo->HasAttribute(SPELL_ATTR0_HIDDEN_CLIENTSIDE)))
continue;
if (spellInfo->Stances & (1<<(GetMiscValue()-1)))
target->CastSpell(target, glyph->SpellId, true, NULL, this);
@@ -3243,7 +3243,7 @@ void AuraEffect::HandleModStateImmunityMask(AuraApplication const* aurApp, uint8
for (std::list <AuraType>::iterator iter = aura_immunity_list.begin(); iter != aura_immunity_list.end(); ++iter)
target->ApplySpellImmune(GetId(), IMMUNITY_STATE, *iter, apply);
- if (apply && GetSpellInfo()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
+ if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
{
target->RemoveAurasWithMechanic(mechanic_immunity_list, AURA_REMOVE_BY_DEFAULT, GetId());
for (std::list <AuraType>::iterator iter = aura_immunity_list.begin(); iter != aura_immunity_list.end(); ++iter)
@@ -3300,7 +3300,7 @@ void AuraEffect::HandleModMechanicImmunity(AuraApplication const* aurApp, uint8
break;
}
- if (apply && GetSpellInfo()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
+ if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
target->RemoveAurasWithMechanic(mechanic, AURA_REMOVE_BY_DEFAULT, GetId());
}
@@ -3336,7 +3336,7 @@ void AuraEffect::HandleAuraModStateImmunity(AuraApplication const* aurApp, uint8
target->ApplySpellImmune(GetId(), IMMUNITY_STATE, GetMiscValue(), apply);
- if (apply && GetSpellInfo()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
+ if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
target->RemoveAurasByType(AuraType(GetMiscValue()), ObjectGuid::Empty, GetBase());
}
@@ -3372,13 +3372,13 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
// remove all flag auras (they are positive, but they must be removed when you are immune)
- if (GetSpellInfo()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY
- && GetSpellInfo()->AttributesEx2 & SPELL_ATTR2_DAMAGE_REDUCED_SHIELD)
+ if (GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
+ && GetSpellInfo()->HasAttribute(SPELL_ATTR2_DAMAGE_REDUCED_SHIELD))
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
/// @todo optimalize this cycle - use RemoveAurasWithInterruptFlags call or something else
if ((apply)
- && GetSpellInfo()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY
+ && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
&& GetSpellInfo()->IsPositive()) //Only positive immunity removes auras
{
uint32 school_mask = GetMiscValue();
@@ -3759,7 +3759,7 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8
// recalculate current HP/MP after applying aura modifications (only for spells with SPELL_ATTR0_UNK4 0x00000010 flag)
// this check is total bullshit i think
- if (GetMiscValue() == STAT_STAMINA && (m_spellInfo->Attributes & SPELL_ATTR0_ABILITY))
+ if (GetMiscValue() == STAT_STAMINA && m_spellInfo->HasAttribute(SPELL_ATTR0_ABILITY))
target->SetHealth(std::max<uint32>(uint32(healthPct * target->GetMaxHealth() * 0.01f), (alive ? 1 : 0)));
}
@@ -5901,7 +5901,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
else
damage = uint32(target->CountPctFromMaxHealth(damage));
- if (!(m_spellInfo->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura)
{
damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
@@ -5918,13 +5918,13 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target);
int32 dmg = damage;
- if (!(GetSpellInfo()->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE))
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
caster->ApplyResilience(target, NULL, &dmg, crit, CR_CRIT_TAKEN_SPELL);
damage = dmg;
caster->CalcAbsorbResist(target, GetSpellInfo()->GetSchoolMask(), DOT, damage, &absorb, &resist, GetSpellInfo());
- TC_LOG_INFO("spells", "PeriodicTick: %s attacked %s for %u dmg inflicted by %u absorb is %u",
+ TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s attacked %s for %u dmg inflicted by %u absorb is %u",
GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId(), absorb);
caster->DealDamageMods(target, damage, &absorb);
@@ -5979,7 +5979,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellDamagePctDone(target, m_spellInfo, DOT);
else
damage = std::max(int32(damage * GetDonePct()), 0);
-
+
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
// Calculate armor mitigation
@@ -5990,7 +5990,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
damage = damageReductedArmor;
}
- if (!(m_spellInfo->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura)
{
damage = uint32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
@@ -6007,7 +6007,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target);
int32 dmg = damage;
- if (!(GetSpellInfo()->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE))
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
caster->ApplyResilience(target, NULL, &dmg, crit, CR_CRIT_TAKEN_SPELL);
damage = dmg;
@@ -6016,7 +6016,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
if (target->GetHealth() < damage)
damage = uint32(target->GetHealth());
- TC_LOG_INFO("spells", "PeriodicTick: %s health leech of %s for %u dmg inflicted by %u abs is %u",
+ TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s health leech of %s for %u dmg inflicted by %u abs is %u",
GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId(), absorb);
caster->SendSpellNonMeleeDamageLog(target, GetId(), damage, GetSpellInfo()->GetSchoolMask(), absorb, resist, false, 0, crit);
@@ -6083,7 +6083,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
}
// heal for caster damage (must be alive)
- if (target != caster && GetSpellInfo()->AttributesEx2 & SPELL_ATTR2_HEALTH_FUNNEL && !caster->IsAlive())
+ if (target != caster && GetSpellInfo()->HasAttribute(SPELL_ATTR2_HEALTH_FUNNEL) && !caster->IsAlive())
return;
// don't regen when permanent aura target has full power
@@ -6160,7 +6160,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
if (crit)
damage = caster->SpellCriticalHealingBonus(m_spellInfo, damage, target);
- TC_LOG_INFO("spells", "PeriodicTick: %s heal of %s for %u health inflicted by %u",
+ TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s heal of %s for %u health inflicted by %u",
GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId());
uint32 absorb = 0;
@@ -6177,7 +6177,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
// Health Funnel
// damage caster for heal amount
- if (target != caster && GetSpellInfo()->AttributesEx2 & SPELL_ATTR2_HEALTH_FUNNEL)
+ if (target != caster && GetSpellInfo()->HasAttribute(SPELL_ATTR2_HEALTH_FUNNEL))
{
uint32 funnelDamage = GetSpellInfo()->ManaPerSecond; // damage is not affected by spell power
@@ -6231,7 +6231,7 @@ void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) con
drainAmount = maxmana;
}
- TC_LOG_INFO("spells", "PeriodicTick: %s power leech of %s for %u dmg inflicted by %u",
+ TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s power leech of %s for %u dmg inflicted by %u",
GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), drainAmount, GetId());
// resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
@@ -6292,7 +6292,7 @@ void AuraEffect::HandleObsModPowerAuraTick(Unit* target, Unit* caster) const
// ignore negative values (can be result apply spellmods to aura damage
uint32 amount = std::max(m_amount, 0) * target->GetMaxPower(powerType) /100;
- TC_LOG_INFO("spells", "PeriodicTick: %s energize %s for %u dmg inflicted by %u",
+ TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s energize %s for %u dmg inflicted by %u",
GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), amount, GetId());
SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f, false);
@@ -6308,7 +6308,7 @@ void AuraEffect::HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) cons
{
Powers powerType = Powers(GetMiscValue());
- if (target->GetTypeId() == TYPEID_PLAYER && target->getPowerType() != powerType && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
+ if (target->GetTypeId() == TYPEID_PLAYER && target->getPowerType() != powerType && !m_spellInfo->HasAttribute(SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
return;
if (!target->IsAlive() || !target->GetMaxPower(powerType))
@@ -6330,7 +6330,7 @@ void AuraEffect::HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) cons
SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f, false);
target->SendPeriodicAuraLog(&pInfo);
- TC_LOG_INFO("spells", "PeriodicTick: %s energize %s for %u dmg inflicted by %u",
+ TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s energize %s for %u dmg inflicted by %u",
GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), amount, GetId());
int32 gain = target->ModifyPower(powerType, amount);
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 93a4c96b92f..0ba059b1952 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -191,7 +191,7 @@ void AuraApplication::BuildUpdatePacket(ByteBuffer& data, bool remove) const
Aura const* aura = GetBase();
data << uint32(aura->GetId());
uint32 flags = _flags;
- if (aura->GetMaxDuration() > 0 && !(aura->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_HIDE_DURATION))
+ if (aura->GetMaxDuration() > 0 && !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR5_HIDE_DURATION))
flags |= AFLAG_DURATION;
data << uint8(flags);
data << uint8(aura->GetCasterLevel());
@@ -749,12 +749,13 @@ void Aura::SetDuration(int32 duration, bool withMods)
void Aura::RefreshDuration(bool withMods)
{
- if (withMods)
+ Unit* caster = GetCaster();
+ if (withMods && caster)
{
int32 duration = m_spellInfo->GetMaxDuration();
// Calculate duration of periodics affected by haste.
- if (GetCaster()->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION)
- duration = int32(duration * GetCaster()->GetFloatValue(UNIT_MOD_CAST_SPEED));
+ if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION))
+ duration = int32(duration * caster->GetFloatValue(UNIT_MOD_CAST_SPEED));
SetMaxDuration(duration);
SetDuration(duration);
@@ -1813,7 +1814,7 @@ bool Aura::CanStackWith(Aura const* existingAura) const
if (existingAura->GetSpellInfo()->IsChanneled())
return true;
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_STACK_FOR_DIFF_CASTERS)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_STACK_FOR_DIFF_CASTERS))
return true;
// check same periodic auras
@@ -1865,7 +1866,7 @@ bool Aura::CanStackWith(Aura const* existingAura) const
if (m_spellInfo->IsMultiSlotAura() && !IsArea())
return true;
if (GetCastItemGUID() && existingAura->GetCastItemGUID())
- if (GetCastItemGUID() != existingAura->GetCastItemGUID() && (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_ENCHANT_PROC))
+ if (GetCastItemGUID() != existingAura->GetCastItemGUID() && m_spellInfo->HasAttribute(SPELL_ATTR0_CU_ENCHANT_PROC))
return true;
// same spell with same caster should not stack
return false;
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index ac45461b333..6abcd578411 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -161,8 +161,8 @@ class Aura
{
return GetCasterGUID() == target->GetGUID()
&& m_spellInfo->Stances
- && !(m_spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_NEED_SHAPESHIFT)
- && !(m_spellInfo->Attributes & SPELL_ATTR0_NOT_SHAPESHIFT);
+ && !m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_NEED_SHAPESHIFT)
+ && !m_spellInfo->HasAttribute(SPELL_ATTR0_NOT_SHAPESHIFT);
}
bool CanBeSaved() const;
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 8e415b06745..c31386cd496 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -482,23 +482,23 @@ void SpellCastTargets::Update(Unit* caster)
void SpellCastTargets::OutDebug() const
{
if (!m_targetMask)
- TC_LOG_INFO("spells", "No targets");
+ TC_LOG_DEBUG("spells", "No targets");
- TC_LOG_INFO("spells", "target mask: %u", m_targetMask);
+ TC_LOG_DEBUG("spells", "target mask: %u", m_targetMask);
if (m_targetMask & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_GAMEOBJECT_MASK))
- TC_LOG_INFO("spells", "Object target: %s", m_objectTargetGUID.ToString().c_str());
+ TC_LOG_DEBUG("spells", "Object target: %s", m_objectTargetGUID.ToString().c_str());
if (m_targetMask & TARGET_FLAG_ITEM)
- TC_LOG_INFO("spells", "Item target: %s", m_itemTargetGUID.ToString().c_str());
+ TC_LOG_DEBUG("spells", "Item target: %s", m_itemTargetGUID.ToString().c_str());
if (m_targetMask & TARGET_FLAG_TRADE_ITEM)
- TC_LOG_INFO("spells", "Trade item target: %s", m_itemTargetGUID.ToString().c_str());
+ TC_LOG_DEBUG("spells", "Trade item target: %s", m_itemTargetGUID.ToString().c_str());
if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
- TC_LOG_INFO("spells", "Source location: transport guid:%s trans offset: %s position: %s", m_src._transportGUID.ToString().c_str(), m_src._transportOffset.ToString().c_str(), m_src._position.ToString().c_str());
+ TC_LOG_DEBUG("spells", "Source location: transport guid:%s trans offset: %s position: %s", m_src._transportGUID.ToString().c_str(), m_src._transportOffset.ToString().c_str(), m_src._position.ToString().c_str());
if (m_targetMask & TARGET_FLAG_DEST_LOCATION)
- TC_LOG_INFO("spells", "Destination location: transport guid:%s trans offset: %s position: %s", m_dst._transportGUID.ToString().c_str(), m_dst._transportOffset.ToString().c_str(), m_dst._position.ToString().c_str());
+ TC_LOG_DEBUG("spells", "Destination location: transport guid:%s trans offset: %s position: %s", m_dst._transportGUID.ToString().c_str(), m_dst._transportOffset.ToString().c_str(), m_dst._position.ToString().c_str());
if (m_targetMask & TARGET_FLAG_STRING)
- TC_LOG_INFO("spells", "String: %s", m_strTarget.c_str());
- TC_LOG_INFO("spells", "speed: %f", m_speed);
- TC_LOG_INFO("spells", "elevation: %f", m_elevation);
+ TC_LOG_DEBUG("spells", "String: %s", m_strTarget.c_str());
+ TC_LOG_DEBUG("spells", "speed: %f", m_speed);
+ TC_LOG_DEBUG("spells", "elevation: %f", m_elevation);
}
SpellValue::SpellValue(SpellInfo const* proto)
@@ -512,7 +512,7 @@ SpellValue::SpellValue(SpellInfo const* proto)
Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID, bool skipCheck) :
m_spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(info, caster)),
-m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster)
+m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster)
, m_spellValue(new SpellValue(m_spellInfo)), m_preGeneratedPath(PathGenerator(m_caster))
{
m_customError = SPELL_CUSTOM_ERROR_NONE;
@@ -533,7 +533,7 @@ m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharme
switch (m_spellInfo->DmgClass)
{
case SPELL_DAMAGE_CLASS_MELEE:
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_REQ_OFFHAND)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_REQ_OFFHAND))
m_attackType = OFF_ATTACK;
else
m_attackType = BASE_ATTACK;
@@ -543,7 +543,7 @@ m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharme
break;
default:
// Wands
- if (m_spellInfo->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG))
m_attackType = RANGED_ATTACK;
else
m_attackType = BASE_ATTACK;
@@ -574,8 +574,8 @@ m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharme
m_spellState = SPELL_STATE_NULL;
_triggeredCastFlags = triggerFlags;
- if (info->AttributesEx4 & SPELL_ATTR4_TRIGGERED)
- _triggeredCastFlags = TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT);
+ if (info->HasAttribute(SPELL_ATTR4_CAN_CAST_WHILE_CASTING))
+ _triggeredCastFlags = TriggerCastFlags(uint32(_triggeredCastFlags) | TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_CAST_DIRECTLY);
m_CastItem = NULL;
m_castItemGUID.Clear();
@@ -615,8 +615,8 @@ m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharme
// Determine if spell can be reflected back to the caster
// Patch 1.2 notes: Spell Reflection no longer reflects abilities
- m_canReflect = m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !(m_spellInfo->Attributes & SPELL_ATTR0_ABILITY)
- && !(m_spellInfo->AttributesEx & SPELL_ATTR1_CANT_BE_REFLECTED) && !(m_spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ m_canReflect = m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !m_spellInfo->HasAttribute(SPELL_ATTR0_ABILITY)
+ && !m_spellInfo->HasAttribute(SPELL_ATTR1_CANT_BE_REFLECTED) && !m_spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
&& !m_spellInfo->IsPassive() && !m_spellInfo->IsPositive();
CleanupTargetList();
@@ -1749,11 +1749,11 @@ uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList*
default:
break;
}
- if (!(m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_DEAD))
retMask &= ~GRID_MAP_TYPE_MASK_CORPSE;
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS))
retMask &= GRID_MAP_TYPE_MASK_CORPSE | GRID_MAP_TYPE_MASK_PLAYER;
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_GHOSTS))
retMask &= GRID_MAP_TYPE_MASK_PLAYER;
if (condList)
@@ -1843,7 +1843,7 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
}
// chain lightning/heal spells and similar - allow to jump at larger distance and go out of los
- bool isBouncingFar = (m_spellInfo->AttributesEx4 & SPELL_ATTR4_AREA_TARGET_CHAIN
+ bool isBouncingFar = (m_spellInfo->HasAttribute(SPELL_ATTR4_AREA_TARGET_CHAIN)
|| m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_NONE
|| m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC);
@@ -1944,7 +1944,7 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
break;
case SPELL_DAMAGE_CLASS_RANGED:
// Auto attack
- if (m_spellInfo->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG))
{
m_procAttacker = PROC_FLAG_DONE_RANGED_AUTO_ATTACK;
m_procVictim = PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK;
@@ -1958,7 +1958,7 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
default:
if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON &&
m_spellInfo->EquippedItemSubClassMask & (1<<ITEM_SUBCLASS_WEAPON_WAND)
- && m_spellInfo->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG) // Wands auto attack
+ && m_spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG)) // Wands auto attack
{
m_procAttacker = PROC_FLAG_DONE_RANGED_AUTO_ATTACK;
m_procVictim = PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK;
@@ -1990,8 +1990,8 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
if (!(m_procAttacker & PROC_FLAG_DONE_RANGED_AUTO_ATTACK))
{
if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS &&
- (m_spellInfo->AttributesEx2 & SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC ||
- m_spellInfo->AttributesEx3 & SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2))
+ (m_spellInfo->HasAttribute(SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC) ||
+ m_spellInfo->HasAttribute(SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2)))
m_procEx |= PROC_EX_INTERNAL_CANT_PROC;
else if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS)
m_procEx |= PROC_EX_INTERNAL_TRIGGERED;
@@ -2275,7 +2275,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
m_spellAura = NULL; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied
//Spells with this flag cannot trigger if effect is cast on self
- bool canEffectTrigger = !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_CANT_TRIGGER_PROC) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2);
+ bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2);
Unit* spellHitTarget = NULL;
if (missInfo == SPELL_MISS_NONE) // In case spell hit target, do all effect on that target
@@ -2395,7 +2395,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
{
caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
- if (caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->Attributes & SPELL_ATTR0_STOP_ATTACK_TARGET) == 0 &&
+ if (caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) == 0 &&
(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx);
}
@@ -2415,7 +2415,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
caster->ProcDamageAndSpell(unit, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
// Failed Pickpocket, reveal rogue
- if (missInfo == SPELL_MISS_RESIST && m_spellInfo->AttributesCu & SPELL_ATTR0_CU_PICKPOCKET && unitTarget->GetTypeId() == TYPEID_UNIT)
+ if (missInfo == SPELL_MISS_RESIST && m_spellInfo->HasAttribute(SPELL_ATTR0_CU_PICKPOCKET) && unitTarget->GetTypeId() == TYPEID_UNIT)
{
m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK);
if (unitTarget->ToCreature()->IsAIEnabled)
@@ -2425,9 +2425,9 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (missInfo != SPELL_MISS_EVADE && !m_caster->IsFriendlyTo(unit) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)))
{
- m_caster->CombatStart(unit, !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO));
+ m_caster->CombatStart(unit, !m_spellInfo->HasAttribute(SPELL_ATTR3_NO_INITIAL_AGGRO));
- if (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_AURA_CC)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_AURA_CC))
if (!unit->IsStandState())
unit->SetStandState(UNIT_STAND_STATE_STAND);
}
@@ -2514,7 +2514,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
{
unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_HITBYSPELL);
/// @todo This is a hack. But we do not know what types of stealth should be interrupted by CC
- if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_AURA_CC) && unit->IsControlledByPlayer())
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_AURA_CC) && unit->IsControlledByPlayer())
unit->RemoveAurasByType(SPELL_AURA_MOD_STEALTH);
}
else if (m_caster->IsFriendlyTo(unit))
@@ -2532,7 +2532,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
if (m_caster->GetTypeId() == TYPEID_PLAYER)
m_caster->ToPlayer()->UpdatePvP(true);
}
- if (unit->IsInCombat() && !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO))
+ if (unit->IsInCombat() && !m_spellInfo->HasAttribute(SPELL_ATTR3_NO_INITIAL_AGGRO))
{
m_caster->SetInCombatState(unit->GetCombatTimer() > 0, unit);
unit->getHostileRefManager().threatAssist(m_caster, 0.0f);
@@ -2625,7 +2625,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
if (m_spellInfo->IsChanneled())
m_originalCaster->ModSpellCastTime(aurSpellInfo, duration, this);
// and duration of auras affected by SPELL_AURA_PERIODIC_HASTE
- else if (m_originalCaster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, aurSpellInfo) || m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION)
+ else if (m_originalCaster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, aurSpellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION))
duration = int32(duration * m_originalCaster->GetFloatValue(UNIT_MOD_CAST_SPEED));
if (duration != m_spellAura->GetMaxDuration())
@@ -3192,7 +3192,7 @@ void Spell::cast(bool skipCheck)
SendSpellGo();
// Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
- if ((m_spellInfo->Speed > 0.0f && !m_spellInfo->IsChanneled()) || m_spellInfo->AttributesEx4 & SPELL_ATTR4_UNK4)
+ if ((m_spellInfo->Speed > 0.0f && !m_spellInfo->IsChanneled()) || m_spellInfo->HasAttribute(SPELL_ATTR4_UNK4))
{
// Remove used for cast item if need (it can be already NULL after TakeReagents call
// in case delayed spell remove item at cast delay start
@@ -3592,7 +3592,7 @@ void Spell::finish(bool ok)
break;
}
}
- if (!found && !(m_spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
+ if (!found && !m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
{
m_caster->resetAttackTimer(BASE_ATTACK);
if (m_caster->haveOffhandWeapon())
@@ -3618,7 +3618,7 @@ void Spell::finish(bool ok)
}
// Stop Attack for some spells
- if (m_spellInfo->Attributes & SPELL_ATTR0_STOP_ATTACK_TARGET)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET))
m_caster->AttackStop();
}
@@ -3783,7 +3783,7 @@ void Spell::SendSpellStart()
if ((IsTriggered() && !m_spellInfo->IsAutoRepeatRangedSpell()) || m_triggeredByAuraSpell)
castFlags |= CAST_FLAG_PENDING;
- if (m_spellInfo->Attributes & SPELL_ATTR0_REQ_AMMO)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO))
castFlags |= CAST_FLAG_AMMO;
if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
(m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsPet()))
@@ -3836,7 +3836,7 @@ void Spell::SendSpellGo()
if ((IsTriggered() && !m_spellInfo->IsAutoRepeatRangedSpell()) || m_triggeredByAuraSpell)
castFlags |= CAST_FLAG_PENDING;
- if (m_spellInfo->Attributes & SPELL_ATTR0_REQ_AMMO)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO))
castFlags |= CAST_FLAG_AMMO; // arrows/bullets visual
if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
@@ -4230,7 +4230,7 @@ void Spell::SendResurrectRequest(Player* target)
data << uint8(m_caster->GetTypeId() == TYPEID_PLAYER ? 0 : 1); // "you'll be afflicted with resurrection sickness"
// override delay sent with SMSG_CORPSE_RECLAIM_DELAY, set instant resurrection for spells with this attribute
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_RESURRECTION_TIMER)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_RESURRECTION_TIMER))
data << uint32(0);
target->GetSession()->SendPacket(&data);
}
@@ -4561,8 +4561,8 @@ void Spell::HandleThreatSpells()
if (m_UniqueTargetInfo.empty())
return;
- if ((m_spellInfo->AttributesEx & SPELL_ATTR1_NO_THREAT) ||
- (m_spellInfo->AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR1_NO_THREAT) ||
+ m_spellInfo->HasAttribute(SPELL_ATTR3_NO_INITIAL_AGGRO))
return;
float threat = 0.0f;
@@ -4573,7 +4573,7 @@ void Spell::HandleThreatSpells()
threat += threatEntry->flatMod;
}
- else if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_NO_INITIAL_THREAT) == 0)
+ else if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NO_INITIAL_THREAT) == 0)
threat += m_spellInfo->SpellLevel;
// past this point only multiplicative effects occur
@@ -4634,11 +4634,11 @@ void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOT
SpellCastResult Spell::CheckCast(bool strict)
{
// check death state
- if (!m_caster->IsAlive() && !(m_spellInfo->Attributes & SPELL_ATTR0_PASSIVE) && !((m_spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD) || (IsTriggered() && !m_triggeredByAuraSpell)))
+ if (!m_caster->IsAlive() && !m_spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE) && !(m_spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD) || (IsTriggered() && !m_triggeredByAuraSpell)))
return SPELL_FAILED_CASTER_DEAD;
// check cooldowns to prevent cheating
- if (m_caster->GetTypeId() == TYPEID_PLAYER && !(m_spellInfo->Attributes & SPELL_ATTR0_PASSIVE))
+ if (m_caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE))
{
//can cast triggered (by aura only?) spells while have this flag
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE) && m_caster->ToPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY))
@@ -4657,7 +4657,7 @@ SpellCastResult Spell::CheckCast(bool strict)
return SPELL_FAILED_NOT_READY;
}
- if (m_spellInfo->AttributesEx7 & SPELL_ATTR7_IS_CHEAT_SPELL && !m_caster->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR7_IS_CHEAT_SPELL) && !m_caster->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS))
{
m_customError = SPELL_CUSTOM_ERROR_GM_ONLY;
return SPELL_FAILED_CUSTOM_ERROR;
@@ -4675,11 +4675,11 @@ SpellCastResult Spell::CheckCast(bool strict)
if (m_caster->GetTypeId() == TYPEID_PLAYER && VMAP::VMapFactory::createOrGetVMapManager()->isLineOfSightCalcEnabled())
{
- if (m_spellInfo->Attributes & SPELL_ATTR0_OUTDOORS_ONLY &&
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_OUTDOORS_ONLY) &&
!m_caster->GetMap()->IsOutdoors(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ()))
return SPELL_FAILED_ONLY_OUTDOORS;
- if (m_spellInfo->Attributes & SPELL_ATTR0_INDOORS_ONLY &&
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_INDOORS_ONLY) &&
m_caster->GetMap()->IsOutdoors(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ()))
return SPELL_FAILED_ONLY_INDOORS;
}
@@ -4705,7 +4705,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (shapeError != SPELL_CAST_OK)
return shapeError;
- if ((m_spellInfo->Attributes & SPELL_ATTR0_ONLY_STEALTHED) && !(m_caster->HasStealthAura()))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_ONLY_STEALTHED) && !(m_caster->HasStealthAura()))
return SPELL_FAILED_ONLY_STEALTHED;
}
}
@@ -4791,7 +4791,7 @@ SpellCastResult Spell::CheckCast(bool strict)
// those spells may have incorrect target entries or not filled at all (for example 15332)
// such spells when learned are not targeting anyone using targeting system, they should apply directly to caster instead
// also, such casts shouldn't be sent to client
- if (!((m_spellInfo->Attributes & SPELL_ATTR0_PASSIVE) && (!m_targets.GetUnitTarget() || m_targets.GetUnitTarget() == m_caster)))
+ if (!(m_spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE) && (!m_targets.GetUnitTarget() || m_targets.GetUnitTarget() == m_caster)))
{
// Check explicit target for m_originalCaster - todo: get rid of such workarounds
SpellCastResult castResult = m_spellInfo->CheckExplicitTarget(m_originalCaster ? m_originalCaster : m_caster, m_targets.GetObjectTarget(), m_targets.GetItemTarget());
@@ -4808,11 +4808,11 @@ SpellCastResult Spell::CheckCast(bool strict)
if (target != m_caster)
{
// Must be behind the target
- if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET) && target->HasInArc(static_cast<float>(M_PI), m_caster))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET) && target->HasInArc(static_cast<float>(M_PI), m_caster))
return SPELL_FAILED_NOT_BEHIND;
// Target must be facing you
- if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER) && !target->HasInArc(static_cast<float>(M_PI), m_caster))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER) && !target->HasInArc(static_cast<float>(M_PI), m_caster))
return SPELL_FAILED_NOT_INFRONT;
if (m_caster->GetEntry() != WORLD_TRIGGER) // Ignore LOS for gameobjects casts (wrongly cast by a trigger)
@@ -4822,7 +4822,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (DynamicObject* dynObj = m_caster->GetDynObject(m_triggeredByAuraSpell->Id))
losTarget = dynObj;
- if (!(m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !target->IsWithinLOSInMap(losTarget))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !target->IsWithinLOSInMap(losTarget))
return SPELL_FAILED_LINE_OF_SIGHT;
}
}
@@ -4834,7 +4834,7 @@ SpellCastResult Spell::CheckCast(bool strict)
float x, y, z;
m_targets.GetDstPos()->GetPosition(x, y, z);
- if (!(m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !m_caster->IsWithinLOS(x, y, z))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !m_caster->IsWithinLOS(x, y, z))
return SPELL_FAILED_LINE_OF_SIGHT;
}
@@ -4855,15 +4855,15 @@ SpellCastResult Spell::CheckCast(bool strict)
}
// Spell cast only in battleground
- if ((m_spellInfo->AttributesEx3 & SPELL_ATTR3_BATTLEGROUND) && m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_BATTLEGROUND) && m_caster->GetTypeId() == TYPEID_PLAYER)
if (!m_caster->ToPlayer()->InBattleground())
return SPELL_FAILED_ONLY_BATTLEGROUNDS;
// do not allow spells to be cast in arenas
// - with greater than 10 min CD without SPELL_ATTR4_USABLE_IN_ARENA flag
// - with SPELL_ATTR4_NOT_USABLE_IN_ARENA flag
- if ((m_spellInfo->AttributesEx4 & SPELL_ATTR4_NOT_USABLE_IN_ARENA) ||
- (m_spellInfo->GetRecoveryTime() > 10 * MINUTE * IN_MILLISECONDS && !(m_spellInfo->AttributesEx4 & SPELL_ATTR4_USABLE_IN_ARENA)))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR4_NOT_USABLE_IN_ARENA) ||
+ (m_spellInfo->GetRecoveryTime() > 10 * MINUTE * IN_MILLISECONDS && !m_spellInfo->HasAttribute(SPELL_ATTR4_USABLE_IN_ARENA)))
if (MapEntry const* mapEntry = sMapStore.LookupEntry(m_caster->GetMapId()))
if (mapEntry->IsBattleArena())
return SPELL_FAILED_NOT_IN_ARENA;
@@ -4881,7 +4881,7 @@ SpellCastResult Spell::CheckCast(bool strict)
// not let players cast spells at mount (and let do it to creatures)
if (m_caster->IsMounted() && m_caster->GetTypeId() == TYPEID_PLAYER && !(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE) &&
- !m_spellInfo->IsPassive() && !(m_spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_MOUNTED))
+ !m_spellInfo->IsPassive() && !m_spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_MOUNTED))
{
if (m_caster->IsInFlight())
return SPELL_FAILED_NOT_ON_TAXI;
@@ -4938,7 +4938,7 @@ SpellCastResult Spell::CheckCast(bool strict)
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_DISPEL)
{
- if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->AttributesEx & SPELL_ATTR1_MELEE_COMBAT_START)
+ if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->HasAttribute(SPELL_ATTR1_MELEE_COMBAT_START))
{
hasDispellableAura = true;
break;
@@ -5522,7 +5522,7 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
SpellCastResult Spell::CheckCasterAuras() const
{
// spells totally immuned to caster auras (wsg flag drop, give marks etc)
- if (m_spellInfo->AttributesEx6 & SPELL_ATTR6_IGNORE_CASTER_AURAS)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CASTER_AURAS))
return SPELL_CAST_OK;
uint8 school_immune = 0;
@@ -5531,7 +5531,7 @@ SpellCastResult Spell::CheckCasterAuras() const
// Check if the spell grants school or mechanic immunity.
// We use bitmasks so the loop is done only once and not on every aura check below.
- if (m_spellInfo->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
{
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
@@ -5547,7 +5547,7 @@ SpellCastResult Spell::CheckCasterAuras() const
mechanic_immune = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
}
- bool usableInStun = (m_spellInfo->AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_STUNNED) != 0;
+ bool usableInStun = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED);
// Glyph of Pain Suppression
// there is no other way to handle it
@@ -5579,9 +5579,9 @@ SpellCastResult Spell::CheckCasterAuras() const
else
prevented_reason = SPELL_FAILED_STUNNED;
}
- else if (unitflag & UNIT_FLAG_CONFUSED && !(m_spellInfo->AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_CONFUSED))
+ else if (unitflag & UNIT_FLAG_CONFUSED && !m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED))
prevented_reason = SPELL_FAILED_CONFUSED;
- else if (unitflag & UNIT_FLAG_FLEEING && !(m_spellInfo->AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_FEARED))
+ else if (unitflag & UNIT_FLAG_FLEEING && !m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED))
prevented_reason = SPELL_FAILED_FLEEING;
else if (unitflag & UNIT_FLAG_SILENCED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
prevented_reason = SPELL_FAILED_SILENCED;
@@ -5601,7 +5601,7 @@ SpellCastResult Spell::CheckCasterAuras() const
SpellInfo const* auraInfo = aura->GetSpellInfo();
if (auraInfo->GetAllEffectsMechanicMask() & mechanic_immune)
continue;
- if (auraInfo->GetSchoolMask() & school_immune && !(auraInfo->AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE))
+ if (auraInfo->GetSchoolMask() & school_immune && !auraInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE))
continue;
if (auraInfo->GetDispelMask() & dispel_immune)
continue;
@@ -5619,11 +5619,11 @@ SpellCastResult Spell::CheckCasterAuras() const
return SPELL_FAILED_STUNNED;
break;
case SPELL_AURA_MOD_CONFUSE:
- if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_CONFUSED))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED))
return SPELL_FAILED_CONFUSED;
break;
case SPELL_AURA_MOD_FEAR:
- if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_FEARED))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED))
return SPELL_FAILED_FLEEING;
break;
case SPELL_AURA_MOD_SILENCE:
@@ -6260,7 +6260,7 @@ SpellCastResult Spell::CheckItems()
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT) && m_spellInfo->EquippedItemClass >=0)
{
// main hand weapon required
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_MAIN_HAND)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_MAIN_HAND))
{
Item* item = m_caster->ToPlayer()->GetWeaponForAttack(BASE_ATTACK);
@@ -6274,7 +6274,7 @@ SpellCastResult Spell::CheckItems()
}
// offhand hand weapon required
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_REQ_OFFHAND)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_REQ_OFFHAND))
{
Item* item = m_caster->ToPlayer()->GetWeaponForAttack(OFF_ATTACK);
@@ -6324,7 +6324,7 @@ void Spell::Delayed() // only called in DealDamage()
else
m_timer += delaytime;
- TC_LOG_INFO("spells", "Spell %u partially interrupted for (%d) ms at damage", m_spellInfo->Id, delaytime);
+ TC_LOG_DEBUG("spells", "Spell %u partially interrupted for (%d) ms at damage", m_spellInfo->Id, delaytime);
WorldPacket data(SMSG_SPELL_DELAYED, 8+4);
data << m_caster->GetPackGUID();
@@ -6463,11 +6463,11 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* lo
}
// check for ignore LOS on the effect itself
- if (m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS))
return true;
// if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour
- if (IsTriggered() && m_triggeredByAuraSpell && (m_triggeredByAuraSpell->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_triggeredByAuraSpell->Id, NULL, SPELL_DISABLE_LOS)))
+ if (IsTriggered() && m_triggeredByAuraSpell && (m_triggeredByAuraSpell->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_triggeredByAuraSpell->Id, NULL, SPELL_DISABLE_LOS)))
return true;
/// @todo shit below shouldn't be here, but it's temporary
@@ -6518,7 +6518,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* lo
bool Spell::IsNextMeleeSwingSpell() const
{
- return (m_spellInfo->Attributes & SPELL_ATTR0_ON_NEXT_SWING) != 0;
+ return m_spellInfo->HasAttribute(SPELL_ATTR0_ON_NEXT_SWING);
}
bool Spell::IsAutoActionResetSpell() const
@@ -6697,7 +6697,7 @@ void Spell::HandleLaunchPhase()
if (m_applyMultiplierMask & (1 << i))
multiplier[i] = m_spellInfo->Effects[i].CalcDamageMultiplier(m_originalCaster, this);
- bool usesAmmo = (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_DIRECT_DAMAGE) != 0;
+ bool usesAmmo = m_spellInfo->HasAttribute(SPELL_ATTR0_CU_DIRECT_DAMAGE);
Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_ABILITY_CONSUME_NO_AMMO);
for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
{
@@ -7140,7 +7140,7 @@ void Spell::CallScriptDestinationTargetSelectHandlers(SpellDestination& target,
bool Spell::CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToCheck)
{
// Skip if there are not any script
- if (!m_loadedScripts.size())
+ if (m_loadedScripts.empty())
return true;
for (std::list<SpellScript*>::iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
@@ -7162,7 +7162,7 @@ bool Spell::CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToC
bool Spell::CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura) const
{
- bool only_on_caster = (triggeredByAura && (triggeredByAura->AttributesEx4 & SPELL_ATTR4_PROC_ONLY_ON_CASTER));
+ bool only_on_caster = (triggeredByAura && triggeredByAura->HasAttribute(SPELL_ATTR4_PROC_ONLY_ON_CASTER));
// If triggeredByAura has SPELL_ATTR4_PROC_ONLY_ON_CASTER then it can only proc on a cast spell with TARGET_UNIT_CASTER
for (uint8 i = 0;i < MAX_SPELL_EFFECTS; ++i)
{
@@ -7401,12 +7401,12 @@ WorldObjectSpellConeTargetCheck::WorldObjectSpellConeTargetCheck(float coneAngle
bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target)
{
- if (_spellInfo->AttributesCu & SPELL_ATTR0_CU_CONE_BACK)
+ if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_BACK))
{
if (!_caster->isInBack(target, _coneAngle))
return false;
}
- else if (_spellInfo->AttributesCu & SPELL_ATTR0_CU_CONE_LINE)
+ else if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_LINE))
{
if (!_caster->HasInLine(target, _caster->GetObjectSize()))
return false;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 651f28d3590..7a2f15b3370 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -324,7 +324,7 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
case SPELLFAMILY_GENERIC:
{
// Meteor like spells (divided damage to targets)
- if (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_SHARE_DAMAGE)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_SHARE_DAMAGE))
{
uint32 count = 0;
for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
@@ -1755,7 +1755,7 @@ void Spell::EffectEnergize(SpellEffIndex effIndex)
Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue);
- if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
+ if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !m_spellInfo->HasAttribute(SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
return;
if (unitTarget->GetMaxPower(power) == 0)
@@ -1870,7 +1870,7 @@ void Spell::EffectEnergizePct(SpellEffIndex effIndex)
Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue);
- if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
+ if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !m_spellInfo->HasAttribute(SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
return;
uint32 maxPower = unitTarget->GetMaxPower(power);
@@ -4226,7 +4226,7 @@ void Spell::EffectStuck(SpellEffIndex /*effIndex*/)
return;
TC_LOG_DEBUG("spells", "Spell Effect: Stuck");
- TC_LOG_INFO("spells", "Player %s (guid %u) used auto-unstuck future at map %u (%f, %f, %f)", player->GetName().c_str(), player->GetGUIDLow(), player->GetMapId(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
+ TC_LOG_DEBUG("spells", "Player %s (guid %u) used auto-unstuck future at map %u (%f, %f, %f)", player->GetName().c_str(), player->GetGUIDLow(), player->GetMapId(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
if (player->IsInFlight())
return;
@@ -4819,8 +4819,8 @@ void Spell::EffectLeapBack(SpellEffIndex effIndex)
if (!unitTarget)
return;
- float speedxy = float(m_spellInfo->Effects[effIndex].MiscValue)/10;
- float speedz = float(damage/10);
+ float speedxy = m_spellInfo->Effects[effIndex].MiscValue / 10.f;
+ float speedz = damage/ 10.f;
//1891: Disengage
m_caster->JumpTo(speedxy, speedz, m_spellInfo->SpellIconID != 1891);
}
@@ -5344,13 +5344,13 @@ void Spell::EffectStealBeneficialBuff(SpellEffIndex effIndex)
if ((aura->GetSpellInfo()->GetDispelMask()) & dispelMask)
{
// Need check for passive? this
- if (!aurApp->IsPositive() || aura->IsPassive() || aura->GetSpellInfo()->AttributesEx4 & SPELL_ATTR4_NOT_STEALABLE)
+ if (!aurApp->IsPositive() || aura->IsPassive() || aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_NOT_STEALABLE))
continue;
// The charges / stack amounts don't count towards the total number of auras that can be dispelled.
// Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
// Polymorph instead of 1 / (5 + 1) -> 16%.
- bool dispel_charges = (aura->GetSpellInfo()->AttributesEx7 & SPELL_ATTR7_DISPEL_CHARGES) != 0;
+ bool dispel_charges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount();
if (charges > 0)
steal_list.push_back(std::make_pair(aura, charges));
@@ -5852,7 +5852,7 @@ void Spell::EffectCastButtons(SpellEffIndex effIndex)
if (!p_caster->HasSpell(spell_id) || p_caster->HasSpellCooldown(spell_id))
continue;
- if (!(spellInfo->AttributesEx7 & SPELL_ATTR7_SUMMON_PLAYER_TOTEM))
+ if (!spellInfo->HasAttribute(SPELL_ATTR7_SUMMON_PLAYER_TOTEM))
continue;
uint32 cost = spellInfo->CalcPowerCost(m_caster, spellInfo->GetSchoolMask());
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 6215f8cfa0a..862521a068c 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -453,7 +453,7 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const
// amount multiplication based on caster's level
if (!caster->IsControlledByPlayer() &&
_spellInfo->SpellLevel && _spellInfo->SpellLevel != caster->getLevel() &&
- !basePointsPerLevel && (_spellInfo->Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION))
+ !basePointsPerLevel && _spellInfo->HasAttribute(SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION))
{
bool canEffectScale = false;
switch (Effect)
@@ -1049,14 +1049,14 @@ bool SpellInfo::NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell) con
bool SpellInfo::IsPassive() const
{
- return (Attributes & SPELL_ATTR0_PASSIVE) != 0;
+ return HasAttribute(SPELL_ATTR0_PASSIVE);
}
bool SpellInfo::IsAutocastable() const
{
- if (Attributes & SPELL_ATTR0_PASSIVE)
+ if (HasAttribute(SPELL_ATTR0_PASSIVE))
return false;
- if (AttributesEx & SPELL_ATTR1_UNAUTOCASTABLE_BY_PET)
+ if (HasAttribute(SPELL_ATTR1_UNAUTOCASTABLE_BY_PET))
return false;
return true;
}
@@ -1107,37 +1107,37 @@ bool SpellInfo::IsMultiSlotAura() const
bool SpellInfo::IsStackableOnOneSlotWithDifferentCasters() const
{
/// TODO: Re-verify meaning of SPELL_ATTR3_STACK_FOR_DIFF_CASTERS and update conditions here
- return StackAmount > 1 && !IsChanneled() && !(AttributesEx3 & SPELL_ATTR3_STACK_FOR_DIFF_CASTERS);
+ return StackAmount > 1 && !IsChanneled() && !HasAttribute(SPELL_ATTR3_STACK_FOR_DIFF_CASTERS);
}
bool SpellInfo::IsCooldownStartedOnEvent() const
{
- return Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE || (CategoryEntry && CategoryEntry->Flags & SPELL_CATEGORY_FLAG_COOLDOWN_STARTS_ON_EVENT);
+ return HasAttribute(SPELL_ATTR0_DISABLED_WHILE_ACTIVE) || (CategoryEntry && CategoryEntry->Flags & SPELL_CATEGORY_FLAG_COOLDOWN_STARTS_ON_EVENT);
}
bool SpellInfo::IsDeathPersistent() const
{
- return (AttributesEx3 & SPELL_ATTR3_DEATH_PERSISTENT) != 0;
+ return HasAttribute(SPELL_ATTR3_DEATH_PERSISTENT);
}
bool SpellInfo::IsRequiringDeadTarget() const
{
- return (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS) != 0;
+ return HasAttribute(SPELL_ATTR3_ONLY_TARGET_GHOSTS);
}
bool SpellInfo::IsAllowingDeadTarget() const
{
- return AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD || Targets & (TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_DEAD);
+ return HasAttribute(SPELL_ATTR2_CAN_TARGET_DEAD) || Targets & (TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_DEAD);
}
bool SpellInfo::CanBeUsedInCombat() const
{
- return !(Attributes & SPELL_ATTR0_CANT_USED_IN_COMBAT);
+ return !HasAttribute(SPELL_ATTR0_CANT_USED_IN_COMBAT);
}
bool SpellInfo::IsPositive() const
{
- return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE);
+ return !HasAttribute(SPELL_ATTR0_CU_NEGATIVE);
}
bool SpellInfo::IsPositiveEffect(uint8 effIndex) const
@@ -1146,27 +1146,27 @@ bool SpellInfo::IsPositiveEffect(uint8 effIndex) const
{
default:
case 0:
- return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE_EFF0);
+ return !HasAttribute(SPELL_ATTR0_CU_NEGATIVE_EFF0);
case 1:
- return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE_EFF1);
+ return !HasAttribute(SPELL_ATTR0_CU_NEGATIVE_EFF1);
case 2:
- return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE_EFF2);
+ return !HasAttribute(SPELL_ATTR0_CU_NEGATIVE_EFF2);
}
}
bool SpellInfo::IsChanneled() const
{
- return (AttributesEx & (SPELL_ATTR1_CHANNELED_1 | SPELL_ATTR1_CHANNELED_2)) != 0;
+ return HasAttribute(SPELL_ATTR1_CHANNELED_1) || HasAttribute(SPELL_ATTR1_CHANNELED_2);
}
bool SpellInfo::NeedsComboPoints() const
{
- return (AttributesEx & (SPELL_ATTR1_REQ_COMBO_POINTS1 | SPELL_ATTR1_REQ_COMBO_POINTS2)) != 0;
+ return HasAttribute(SPELL_ATTR1_REQ_COMBO_POINTS1) || HasAttribute(SPELL_ATTR1_REQ_COMBO_POINTS2);
}
bool SpellInfo::IsBreakingStealth() const
{
- return !(AttributesEx & SPELL_ATTR1_NOT_BREAK_STEALTH);
+ return !HasAttribute(SPELL_ATTR1_NOT_BREAK_STEALTH);
}
bool SpellInfo::IsRangedWeaponSpell() const
@@ -1177,12 +1177,12 @@ bool SpellInfo::IsRangedWeaponSpell() const
bool SpellInfo::IsAutoRepeatRangedSpell() const
{
- return (AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG) != 0;
+ return HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG);
}
bool SpellInfo::IsAffectedBySpellMods() const
{
- return !(AttributesEx3 & SPELL_ATTR3_NO_DONE_BONUS);
+ return !HasAttribute(SPELL_ATTR3_NO_DONE_BONUS);
}
bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const
@@ -1205,11 +1205,11 @@ bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const
bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const
{
// these spells pierce all avalible spells (Resurrection Sickness for example)
- if (Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ if (HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return true;
// these spells (Cyclone for example) can pierce all... // ...but not these (Divine shield, Ice block, Cyclone and Banish for example)
- if ((AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY || aura->Mechanic == MECHANIC_BANISH)))
+ if ((HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE)) && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY || aura->Mechanic == MECHANIC_BANISH)))
return true;
return false;
@@ -1218,15 +1218,15 @@ bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const
bool SpellInfo::CanDispelAura(SpellInfo const* aura) const
{
// These spells (like Mass Dispel) can dispell all auras, except death persistent ones (like Dungeon and Battleground Deserter)
- if (Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY && !aura->IsDeathPersistent())
+ if (HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) && !aura->IsDeathPersistent())
return true;
// These auras (like Divine Shield) can't be dispelled
- if (aura->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ if (aura->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return false;
// These auras (Cyclone for example) are not dispelable
- if (aura->AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE)
+ if (aura->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE))
return false;
return true;
@@ -1235,7 +1235,7 @@ bool SpellInfo::CanDispelAura(SpellInfo const* aura) const
bool SpellInfo::IsSingleTarget() const
{
// all other single target spells have if it has AttributesEx5
- if (AttributesEx5 & SPELL_ATTR5_SINGLE_TARGET_SPELL)
+ if (HasAttribute(SPELL_ATTR5_SINGLE_TARGET_SPELL))
return true;
switch (GetSpellSpecific())
@@ -1332,7 +1332,7 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const
if (actAsShifted)
{
- if (Attributes & SPELL_ATTR0_NOT_SHAPESHIFT) // not while shapeshifted
+ if (HasAttribute(SPELL_ATTR0_NOT_SHAPESHIFT)) // not while shapeshifted
return SPELL_FAILED_NOT_SHAPESHIFT;
else if (Stances != 0) // needs other shapeshift
return SPELL_FAILED_ONLY_SHAPESHIFT;
@@ -1340,7 +1340,7 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const
else
{
// needs shapeshift
- if (!(AttributesEx2 & SPELL_ATTR2_NOT_NEED_SHAPESHIFT) && Stances != 0)
+ if (!HasAttribute(SPELL_ATTR2_NOT_NEED_SHAPESHIFT) && Stances != 0)
return SPELL_FAILED_ONLY_SHAPESHIFT;
}
@@ -1379,7 +1379,7 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
}
// continent limitation (virtual continent)
- if (AttributesEx4 & SPELL_ATTR4_CAST_ONLY_IN_OUTLAND)
+ if (HasAttribute(SPELL_ATTR4_CAST_ONLY_IN_OUTLAND))
{
uint32 v_map = GetVirtualMapForMapAndZone(map_id, zone_id);
MapEntry const* mapEntry = sMapStore.LookupEntry(v_map);
@@ -1388,7 +1388,7 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
}
// raid instance limitation
- if (AttributesEx6 & SPELL_ATTR6_NOT_IN_RAID_INSTANCE)
+ if (HasAttribute(SPELL_ATTR6_NOT_IN_RAID_INSTANCE))
{
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
if (!mapEntry || mapEntry->IsRaid())
@@ -1493,11 +1493,11 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* target, bool implicit) const
{
- if (AttributesEx & SPELL_ATTR1_CANT_TARGET_SELF && caster == target)
+ if (HasAttribute(SPELL_ATTR1_CANT_TARGET_SELF) && caster == target)
return SPELL_FAILED_BAD_TARGETS;
// check visibility - ignore stealth for implicit (area) targets
- if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE) && !caster->CanSeeOrDetect(target, implicit))
+ if (!HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE) && !caster->CanSeeOrDetect(target, implicit))
return SPELL_FAILED_BAD_TARGETS;
Unit const* unitTarget = target->ToUnit();
@@ -1505,7 +1505,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
// creature/player specific target checks
if (unitTarget)
{
- if (AttributesEx & SPELL_ATTR1_CANT_TARGET_IN_COMBAT)
+ if (HasAttribute(SPELL_ATTR1_CANT_TARGET_IN_COMBAT))
{
if (unitTarget->IsInCombat())
return SPELL_FAILED_TARGET_AFFECTING_COMBAT;
@@ -1517,9 +1517,9 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
}
// only spells with SPELL_ATTR3_ONLY_TARGET_GHOSTS can target ghosts
- if (((AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS) != 0) != unitTarget->HasAuraType(SPELL_AURA_GHOST))
+ if (HasAttribute(SPELL_ATTR3_ONLY_TARGET_GHOSTS) != unitTarget->HasAuraType(SPELL_AURA_GHOST))
{
- if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS)
+ if (HasAttribute(SPELL_ATTR3_ONLY_TARGET_GHOSTS))
return SPELL_FAILED_TARGET_NOT_GHOST;
else
return SPELL_FAILED_BAD_TARGETS;
@@ -1530,12 +1530,12 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
if (caster->GetTypeId() == TYPEID_PLAYER)
{
// Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells)
- if (AttributesEx2 & SPELL_ATTR2_CANT_TARGET_TAPPED)
+ if (HasAttribute(SPELL_ATTR2_CANT_TARGET_TAPPED))
if (Creature const* targetCreature = unitTarget->ToCreature())
if (targetCreature->hasLootRecipient() && !targetCreature->isTappedBy(caster->ToPlayer()))
return SPELL_FAILED_CANT_CAST_ON_TAPPED;
- if (AttributesCu & SPELL_ATTR0_CU_PICKPOCKET)
+ if (HasAttribute(SPELL_ATTR0_CU_PICKPOCKET))
{
if (unitTarget->GetTypeId() == TYPEID_PLAYER)
return SPELL_FAILED_BAD_TARGETS;
@@ -1575,21 +1575,21 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
else return SPELL_CAST_OK;
// corpseOwner and unit specific target checks
- if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS && !unitTarget->ToPlayer())
+ if (HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS) && !unitTarget->ToPlayer())
return SPELL_FAILED_TARGET_NOT_PLAYER;
if (!IsAllowingDeadTarget() && !unitTarget->IsAlive())
return SPELL_FAILED_TARGETS_DEAD;
// check this flag only for implicit targets (chain and area), allow to explicitly target units for spells like Shield of Righteousness
- if (implicit && AttributesEx6 & SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED && !unitTarget->CanFreeMove())
+ if (implicit && HasAttribute(SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED) && !unitTarget->CanFreeMove())
return SPELL_FAILED_BAD_TARGETS;
// checked in Unit::IsValidAttack/AssistTarget, shouldn't be checked for ENTRY targets
- //if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
+ //if (!HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
// return SPELL_FAILED_BAD_TARGETS;
- //if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_POSSESSED_FRIENDS)
+ //if (!HasAttribute(SPELL_ATTR6_CAN_TARGET_POSSESSED_FRIENDS)
if (!CheckTargetCreatureType(unitTarget))
{
@@ -1705,7 +1705,7 @@ SpellCastResult SpellInfo::CheckVehicle(Unit const* caster) const
checkMask = VEHICLE_SEAT_FLAG_CAN_ATTACK;
VehicleSeatEntry const* vehicleSeat = vehicle->GetSeatForPassenger(caster);
- if (!(AttributesEx6 & SPELL_ATTR6_CASTABLE_WHILE_ON_VEHICLE) && !(Attributes & SPELL_ATTR0_CASTABLE_WHILE_MOUNTED)
+ if (!HasAttribute(SPELL_ATTR6_CASTABLE_WHILE_ON_VEHICLE) && !HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_MOUNTED)
&& (vehicleSeat->m_flags & checkMask) != checkMask)
return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW;
@@ -2106,7 +2106,7 @@ uint32 SpellInfo::CalcCastTime(Spell* spell /*= NULL*/) const
if (spell)
spell->GetCaster()->ModSpellCastTime(this, castTime, spell);
- if (Attributes & SPELL_ATTR0_REQ_AMMO && (!IsAutoRepeatRangedSpell()))
+ if (HasAttribute(SPELL_ATTR0_REQ_AMMO) && (!IsAutoRepeatRangedSpell()))
castTime += 500;
return (castTime > 0) ? uint32(castTime) : 0;
@@ -2147,7 +2147,7 @@ uint32 SpellInfo::GetRecoveryTime() const
int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const
{
// Spell drain all exist power on cast (Only paladin lay of Hands)
- if (AttributesEx & SPELL_ATTR1_DRAIN_ALL_POWER)
+ if (HasAttribute(SPELL_ATTR1_DRAIN_ALL_POWER))
{
// If power type - health drain all
if (PowerType == POWER_HEALTH)
@@ -2193,7 +2193,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) c
powerCost += caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school);
// Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost)
- if (AttributesEx4 & SPELL_ATTR4_SPELL_VS_EXTEND_COST)
+ if (HasAttribute(SPELL_ATTR4_SPELL_VS_EXTEND_COST))
{
uint32 speed = 0;
if (SpellShapeshiftEntry const* ss = sSpellShapeshiftStore.LookupEntry(caster->GetShapeshiftForm()))
@@ -2201,7 +2201,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) c
else
{
WeaponAttackType slot = BASE_ATTACK;
- if (AttributesEx3 & SPELL_ATTR3_REQ_OFFHAND)
+ if (HasAttribute(SPELL_ATTR3_REQ_OFFHAND))
slot = OFF_ATTACK;
speed = caster->GetAttackTime(slot);
@@ -2216,7 +2216,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) c
if (!caster->IsControlledByPlayer())
{
- if (Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION)
+ if (HasAttribute(SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION))
{
GtNPCManaCostScalerEntry const* spellScaler = sGtNPCManaCostScalerStore.LookupEntry(SpellLevel - 1);
GtNPCManaCostScalerEntry const* casterScaler = sGtNPCManaCostScalerStore.LookupEntry(caster->getLevel() - 1);
@@ -2361,7 +2361,7 @@ void SpellInfo::_InitializeExplicitTargetMask()
bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const
{
// not found a single positive spell with this attribute
- if (Attributes & SPELL_ATTR0_NEGATIVE_1)
+ if (HasAttribute(SPELL_ATTR0_NEGATIVE_1))
return false;
switch (SpellFamilyName)
@@ -2542,7 +2542,7 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const
if (Effects[effIndex].TargetA.GetTarget() != TARGET_UNIT_CASTER)
return false;
// but not this if this first effect (didn't find better check)
- if (Attributes & SPELL_ATTR0_NEGATIVE_1 && effIndex == 0)
+ if (HasAttribute(SPELL_ATTR0_NEGATIVE_1) && effIndex == 0)
return false;
break;
case SPELL_AURA_MECHANIC_IMMUNITY:
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index d9c062e77fd..f2808a089e1 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -376,6 +376,16 @@ public:
bool HasAura(AuraType aura) const;
bool HasAreaAuraEffect() const;
+ inline bool HasAttribute(SpellAttr0 attribute) const { return !!(Attributes & attribute); }
+ inline bool HasAttribute(SpellAttr1 attribute) const { return !!(AttributesEx & attribute); }
+ inline bool HasAttribute(SpellAttr2 attribute) const { return !!(AttributesEx2 & attribute); }
+ inline bool HasAttribute(SpellAttr3 attribute) const { return !!(AttributesEx3 & attribute); }
+ inline bool HasAttribute(SpellAttr4 attribute) const { return !!(AttributesEx4 & attribute); }
+ inline bool HasAttribute(SpellAttr5 attribute) const { return !!(AttributesEx5 & attribute); }
+ inline bool HasAttribute(SpellAttr6 attribute) const { return !!(AttributesEx6 & attribute); }
+ inline bool HasAttribute(SpellAttr7 attribute) const { return !!(AttributesEx7 & attribute); }
+ inline bool HasAttribute(SpellCustomAttributes customAttribute) const { return !!(AttributesCu & customAttribute); }
+
bool IsExplicitDiscovery() const;
bool IsLootCrafting() const;
bool IsQuestTame() const;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index db16a7312ea..b9f046670cc 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -2238,7 +2238,7 @@ void SpellMgr::LoadEnchantCustomAttr()
continue;
/// @todo find a better check
- if (!(spellInfo->AttributesEx2 & SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA) || !(spellInfo->Attributes & SPELL_ATTR0_NOT_SHAPESHIFT))
+ if (!spellInfo->HasAttribute(SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA) || !spellInfo->HasAttribute(SPELL_ATTR0_NOT_SHAPESHIFT))
continue;
for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j)
@@ -2959,6 +2959,8 @@ void SpellMgr::LoadSpellInfoCorrections()
switch (spellInfo->Id)
{
case 53096: // Quetz'lun's Judgment
+ case 70743: // AoD Special
+ case 70614: // AoD Special - Vegard
spellInfo->MaxAffectedTargets = 1;
break;
case 42436: // Drink! (Brewfest)
@@ -3729,7 +3731,7 @@ void SpellMgr::LoadSpellInfoCorrections()
case 45440: // Steam Tonk Controller
case 60256: // Collect Sample
// Crashes client on pressing ESC
- spellInfo->AttributesEx4 &= ~SPELL_ATTR4_TRIGGERED;
+ spellInfo->AttributesEx4 &= ~SPELL_ATTR4_CAN_CAST_WHILE_CASTING;
break;
// ISLE OF CONQUEST SPELLS
//
@@ -3746,7 +3748,7 @@ void SpellMgr::LoadSpellInfoCorrections()
{
case SPELLFAMILY_PALADIN:
// Seals of the Pure should affect Seal of Righteousness
- if (spellInfo->SpellIconID == 25 && spellInfo->Attributes & SPELL_ATTR0_PASSIVE)
+ if (spellInfo->SpellIconID == 25 && spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE))
spellInfo->Effects[EFFECT_0].SpellClassMask[1] |= 0x20000000;
break;
case SPELLFAMILY_DEATHKNIGHT:
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 555f89aad8f..84f22f2f1a9 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -940,6 +940,12 @@ void World::LoadConfigSettings(bool reload)
}
m_bool_configs[CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY] = sConfigMgr->GetBoolDefault("SaveRespawnTimeImmediately", true);
+ if (!m_bool_configs[CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY])
+ {
+ TC_LOG_WARN("server.loading", "SaveRespawnTimeImmediately triggers assertions when disabled, overridden to Enabled");
+ m_bool_configs[CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY] = true;
+ }
+
m_bool_configs[CONFIG_WEATHER] = sConfigMgr->GetBoolDefault("ActivateWeather", true);
m_int_configs[CONFIG_DISABLE_BREATHING] = sConfigMgr->GetIntDefault("DisableWaterBreath", SEC_CONSOLE);
@@ -1334,7 +1340,7 @@ void World::SetInitialWorldSettings()
!MapManager::ExistMapAndVMap(530, 10349.6f, -6357.29f) ||
!MapManager::ExistMapAndVMap(530, -3961.64f, -13931.2f))))
{
- TC_LOG_ERROR("server.loading", "Correct *.map files not found in path '%smaps' or *.vmtree/*.vmtile files in '%svmaps'. Please place *.map/*.vmtree/*.vmtile files in appropriate directories or correct the DataDir value in the worldserver.conf file.", m_dataPath.c_str(), m_dataPath.c_str());
+ TC_LOG_FATAL("server.loading", "Unable to load critical files - server shutting down !!!");
exit(1);
}
@@ -3018,7 +3024,7 @@ void World::ResetRandomBG()
{
TC_LOG_INFO("misc", "Random BG status reset for all characters.");
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_BATTLEGROUND_RANDOM);
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_BATTLEGROUND_RANDOM_ALL);
CharacterDatabase.Execute(stmt);
for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt
index e7d08d69805..8bf84c32447 100644
--- a/src/server/scripts/CMakeLists.txt
+++ b/src/server/scripts/CMakeLists.txt
@@ -50,6 +50,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/SFMT
+ ${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/zlib
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp
index 5d6cdb3fb63..ccd82aa3ef9 100644
--- a/src/server/scripts/Commands/cs_debug.cpp
+++ b/src/server/scripts/Commands/cs_debug.cpp
@@ -299,7 +299,7 @@ public:
else if (commentToken[1] == '/')
{
std::string str;
- getline(ifs, str);
+ std::getline(ifs, str);
continue;
}
// regular data
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 0e86823aa7c..dea2a5216e7 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -237,7 +237,8 @@ public:
zoneId, (zoneEntry ? zoneEntry->area_name[handler->GetSessionDbcLocale()] : unknown),
areaId, (areaEntry ? areaEntry->area_name[handler->GetSessionDbcLocale()] : unknown),
object->GetPhaseMask(),
- object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), object->GetOrientation(),
+ object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), object->GetOrientation());
+ handler->PSendSysMessage(LANG_GRID_POSITION,
cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), object->GetInstanceId(),
zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap, haveMMap);
diff --git a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp
index 59f2ce1a2c9..92c3f83034d 100644
--- a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp
+++ b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp
@@ -360,17 +360,17 @@ public:
case GOSSIP_ACTION_INFO_DEF+3:
player->CLOSE_GOSSIP_MENU();
pBarnesAI->m_uiEventId = EVENT_OZ;
- TC_LOG_INFO("scripts", "player (%s) manually set Opera event to EVENT_OZ", player->GetGUID().ToString().c_str());
+ TC_LOG_DEBUG("scripts", "player (%s) manually set Opera event to EVENT_OZ", player->GetGUID().ToString().c_str());
break;
case GOSSIP_ACTION_INFO_DEF+4:
player->CLOSE_GOSSIP_MENU();
pBarnesAI->m_uiEventId = EVENT_HOOD;
- TC_LOG_INFO("scripts", "player (%s) manually set Opera event to EVENT_HOOD", player->GetGUID().ToString().c_str());
+ TC_LOG_DEBUG("scripts", "player (%s) manually set Opera event to EVENT_HOOD", player->GetGUID().ToString().c_str());
break;
case GOSSIP_ACTION_INFO_DEF+5:
player->CLOSE_GOSSIP_MENU();
pBarnesAI->m_uiEventId = EVENT_RAJ;
- TC_LOG_INFO("scripts", "player (%s) manually set Opera event to EVENT_RAJ", player->GetGUID().ToString().c_str());
+ TC_LOG_DEBUG("scripts", "player (%s) manually set Opera event to EVENT_RAJ", player->GetGUID().ToString().c_str());
break;
}
diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp
index 3db0e1092fd..326360428d2 100644
--- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp
@@ -174,7 +174,7 @@ public:
anchor->GetContactPoint(me, anchorX, anchorY, z, 1.0f);
playerGUID = target->GetGUID();
- Talk(SAY_EVENT_START);
+ Talk(SAY_EVENT_START, target);
}
void UpdateAI(uint32 diff) override
diff --git a/src/server/scripts/EasternKingdoms/SunkenTemple/sunken_temple.cpp b/src/server/scripts/EasternKingdoms/SunkenTemple/sunken_temple.cpp
index 3ced85f09a2..97be139cefe 100644
--- a/src/server/scripts/EasternKingdoms/SunkenTemple/sunken_temple.cpp
+++ b/src/server/scripts/EasternKingdoms/SunkenTemple/sunken_temple.cpp
@@ -36,19 +36,27 @@ EndContentData */
# at_malfurion_Stormrage_trigger
#####*/
-class at_malfurion_stormrage : public AreaTriggerScript
+enum MalfurionMisc
{
-public:
- at_malfurion_stormrage() : AreaTriggerScript("at_malfurion_stormrage") { }
+ NPC_MALFURION_STORMRAGE = 15362,
+ QUEST_ERANIKUS_TYRANT_OF_DREAMS = 8733,
+ QUEST_THE_CHARGE_OF_DRAGONFLIGHTS = 8555,
+};
- bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/) override
- {
- if (player->GetInstanceScript() && !player->FindNearestCreature(15362, 15))
- player->SummonCreature(15362, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), -1.52f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 100000);
- return false;
- }
+class at_malfurion_stormrage : public AreaTriggerScript
+{
+ public:
+ at_malfurion_stormrage() : AreaTriggerScript("at_malfurion_stormrage") { }
+ bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/) override
+ {
+ if (player->GetInstanceScript() && !player->FindNearestCreature(NPC_MALFURION_STORMRAGE, 15.0f) &&
+ player->GetQuestStatus(QUEST_THE_CHARGE_OF_DRAGONFLIGHTS) == QUEST_STATUS_REWARDED && player->GetQuestStatus(QUEST_ERANIKUS_TYRANT_OF_DREAMS) != QUEST_STATUS_REWARDED)
+ player->SummonCreature(NPC_MALFURION_STORMRAGE, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), -1.52f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 100000);
+ return false;
+ }
};
+
/*#####
# go_atalai_statue
#####*/
diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp
index ea56494f0f9..421f3d771a0 100644
--- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp
+++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp
@@ -207,7 +207,7 @@ public:
void DamageTaken(Unit* /*done_by*/, uint32 &damage) override
{
- if (damage > me->GetHealth() && events.IsInPhase(PHASE_ONE))
+ if (damage >= me->GetHealth() && events.IsInPhase(PHASE_ONE))
{
damage = 0;
me->RemoveAllAuras();
diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp
index 01ac3920082..1a98c081570 100644
--- a/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp
+++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp
@@ -689,54 +689,57 @@ class boss_alyson_antille : public CreatureScript
}
};
-struct boss_gazakrothAI : public boss_hexlord_addAI
+class boss_gazakroth : public CreatureScript
{
- boss_gazakrothAI(Creature* creature) : boss_hexlord_addAI(creature)
- {
- Initialize();
- }
-
- void Initialize()
- {
- firebolt_timer = 2000;
- }
+ public:
- uint32 firebolt_timer;
+ boss_gazakroth() : CreatureScript("boss_gazakroth") { }
+
+ struct boss_gazakrothAI : public boss_hexlord_addAI
+ {
+ boss_gazakrothAI(Creature* creature) : boss_hexlord_addAI(creature)
+ {
+ Initialize();
+ }
- void Reset() override
- {
- Initialize();
- boss_hexlord_addAI::Reset();
- }
+ void Initialize()
+ {
+ firebolt_timer = 2 * IN_MILLISECONDS;
+ }
+
+ void Reset() override
+ {
+ Initialize();
+ boss_hexlord_addAI::Reset();
+ }
- void AttackStart(Unit* who) override
- {
- if (!who)
- return;
+ void AttackStart(Unit* who) override
+ {
+ AttackStartCaster(who, 20.0f);
+ }
- if (who->isTargetableForAttack())
- {
- if (me->Attack(who, false))
+ void UpdateAI(uint32 diff) override
{
- me->GetMotionMaster()->MoveChase(who, 20);
- me->AddThreat(who, 0.0f);
+ if (!UpdateVictim())
+ return;
+
+ if (firebolt_timer <= diff)
+ {
+ DoCastVictim(SPELL_FIREBOLT, false);
+ firebolt_timer = 0.7 * IN_MILLISECONDS;
+ } else firebolt_timer -= diff;
+
+ boss_hexlord_addAI::UpdateAI(diff);
}
- }
- }
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
+ private:
+ uint32 firebolt_timer;
+ };
- if (firebolt_timer <= diff)
+ CreatureAI* GetAI(Creature* creature) const override
{
- DoCastVictim(SPELL_FIREBOLT, false);
- firebolt_timer = 700;
- } else firebolt_timer -= diff;
-
- boss_hexlord_addAI::UpdateAI(diff);
- }
+ return GetInstanceAI<boss_gazakrothAI>(creature);
+ }
};
class boss_lord_raadan : public CreatureScript
@@ -1062,7 +1065,7 @@ void AddSC_boss_hex_lord_malacrass()
{
new boss_hexlord_malacrass();
new boss_thurg();
- // new boss_gazakroth();
+ new boss_gazakroth();
new boss_lord_raadan();
new boss_darkheart();
new boss_slither();
diff --git a/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp b/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp
index 898e3f9a2cb..ecfd705cf4d 100644
--- a/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp
+++ b/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp
@@ -92,7 +92,7 @@ public:
me->SetWalk(false);
break;
case 115:
- player->AreaExploredOrEventHappens(QUEST_MISSING_IN_ACTION);
+ player->GroupEventHappens(QUEST_MISSING_IN_ACTION, me);
timer = 2000;
phase = 4;
break;
diff --git a/src/server/scripts/EasternKingdoms/zone_undercity.cpp b/src/server/scripts/EasternKingdoms/zone_undercity.cpp
index 9ce694fb76c..ca281bab60a 100644
--- a/src/server/scripts/EasternKingdoms/zone_undercity.cpp
+++ b/src/server/scripts/EasternKingdoms/zone_undercity.cpp
@@ -40,25 +40,44 @@ EndContentData */
enum Sylvanas
{
- QUEST_JOURNEY_TO_UNDERCITY = 9180,
- EMOTE_LAMENT_END = 0,
- SAY_LAMENT_END = 1,
+ QUEST_JOURNEY_TO_UNDERCITY = 9180,
- SOUND_CREDIT = 10896,
- ENTRY_HIGHBORNE_LAMENTER = 21628,
- ENTRY_HIGHBORNE_BUNNY = 21641,
+ EMOTE_LAMENT_END = 0,
+ SAY_LAMENT_END = 1,
+ EMOTE_LAMENT = 2,
- SPELL_HIGHBORNE_AURA = 37090,
- SPELL_SYLVANAS_CAST = 36568,
- SPELL_RIBBON_OF_SOULS = 34432, // the real one to use might be 37099
+ // Ambassador Sunsorrow
+ SAY_SUNSORROW_WHISPER = 0,
+
+ SOUND_CREDIT = 10896,
+
+ NPC_HIGHBORNE_LAMENTER = 21628,
+ NPC_HIGHBORNE_BUNNY = 21641,
+ NPC_AMBASSADOR_SUNSORROW = 16287,
+
+ SPELL_HIGHBORNE_AURA = 37090,
+ SPELL_SYLVANAS_CAST = 36568,
+ //SPELL_RIBBON_OF_SOULS = 34432, the real one to use might be 37099
+ SPELL_RIBBON_OF_SOULS = 37099,
// Combat spells
- SPELL_BLACK_ARROW = 59712,
- SPELL_FADE = 20672,
- SPELL_FADE_BLINK = 29211,
- SPELL_MULTI_SHOT = 59713,
- SPELL_SHOT = 59710,
- SPELL_SUMMON_SKELETON = 59711
+ SPELL_BLACK_ARROW = 59712,
+ SPELL_FADE = 20672,
+ SPELL_FADE_BLINK = 29211,
+ SPELL_MULTI_SHOT = 59713,
+ SPELL_SHOT = 59710,
+ SPELL_SUMMON_SKELETON = 59711,
+
+ // Events
+ EVENT_FADE = 1,
+ EVENT_SUMMON_SKELETON = 2,
+ EVENT_BLACK_ARROW = 3,
+ EVENT_SHOOT = 4,
+ EVENT_MULTI_SHOT = 5,
+ EVENT_LAMENT_OF_THE_HIGHBORN = 6,
+ EVENT_SUNSORROW_WHISPER = 7,
+
+ GUID_EVENT_INVOKER = 1,
};
float HighborneLoc[4][3]=
@@ -77,26 +96,14 @@ class npc_lady_sylvanas_windrunner : public CreatureScript
public:
npc_lady_sylvanas_windrunner() : CreatureScript("npc_lady_sylvanas_windrunner") { }
- bool OnQuestReward(Player* /*player*/, Creature* creature, const Quest *_Quest, uint32 /*slot*/) override
+ bool OnQuestReward(Player* player, Creature* creature, const Quest *_Quest, uint32 /*slot*/) override
{
if (_Quest->GetQuestId() == QUEST_JOURNEY_TO_UNDERCITY)
- {
- ENSURE_AI(npc_lady_sylvanas_windrunner::npc_lady_sylvanas_windrunnerAI, creature->AI())->LamentEvent = true;
- ENSURE_AI(npc_lady_sylvanas_windrunner::npc_lady_sylvanas_windrunnerAI, creature->AI())->DoPlaySoundToSet(creature, SOUND_CREDIT);
- creature->CastSpell(creature, SPELL_SYLVANAS_CAST, false);
-
- for (uint8 i = 0; i < 4; ++i)
- creature->SummonCreature(ENTRY_HIGHBORNE_LAMENTER, HighborneLoc[i][0], HighborneLoc[i][1], HIGHBORNE_LOC_Y, HighborneLoc[i][2], TEMPSUMMON_TIMED_DESPAWN, 160000);
- }
+ creature->AI()->SetGUID(player->GetGUID(), GUID_EVENT_INVOKER);
return true;
}
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_lady_sylvanas_windrunnerAI(creature);
- }
-
struct npc_lady_sylvanas_windrunnerAI : public ScriptedAI
{
npc_lady_sylvanas_windrunnerAI(Creature* creature) : ScriptedAI(creature)
@@ -106,41 +113,51 @@ public:
void Initialize()
{
- LamentEventTimer = 5000;
LamentEvent = false;
targetGUID.Clear();
-
- FadeTimer = 30000;
- SummonSkeletonTimer = 20000;
- BlackArrowTimer = 15000;
- ShotTimer = 8000;
- MultiShotTimer = 10000;
+ playerGUID.Clear();
}
- uint32 LamentEventTimer;
- bool LamentEvent;
- ObjectGuid targetGUID;
-
- uint32 FadeTimer;
- uint32 SummonSkeletonTimer;
- uint32 BlackArrowTimer;
- uint32 ShotTimer;
- uint32 MultiShotTimer;
-
void Reset() override
{
Initialize();
+ _events.Reset();
}
- void EnterCombat(Unit* /*who*/) override { }
+ void EnterCombat(Unit* /*who*/) override
+ {
+ _events.ScheduleEvent(EVENT_FADE, 30000);
+ _events.ScheduleEvent(EVENT_SUMMON_SKELETON, 20000);
+ _events.ScheduleEvent(EVENT_BLACK_ARROW, 15000);
+ _events.ScheduleEvent(EVENT_SHOOT, 8000);
+ _events.ScheduleEvent(EVENT_MULTI_SHOT, 10000);
+ }
+
+ void SetGUID(ObjectGuid guid, int32 type) override
+ {
+ if (type == GUID_EVENT_INVOKER)
+ {
+ Talk(EMOTE_LAMENT);
+ DoPlaySoundToSet(me, SOUND_CREDIT);
+ DoCast(me, SPELL_SYLVANAS_CAST, false);
+ playerGUID = guid;
+ LamentEvent = true;
+
+ for (uint8 i = 0; i < 4; ++i)
+ me->SummonCreature(NPC_HIGHBORNE_LAMENTER, HighborneLoc[i][0], HighborneLoc[i][1], HIGHBORNE_LOC_Y, HighborneLoc[i][2], TEMPSUMMON_TIMED_DESPAWN, 160000);
+
+ _events.ScheduleEvent(EVENT_LAMENT_OF_THE_HIGHBORN, 2000);
+ _events.ScheduleEvent(EVENT_SUNSORROW_WHISPER, 10000);
+ }
+ }
void JustSummoned(Creature* summoned) override
{
- if (summoned->GetEntry() == ENTRY_HIGHBORNE_BUNNY)
+ if (summoned->GetEntry() == NPC_HIGHBORNE_BUNNY)
{
if (Creature* target = ObjectAccessor::GetCreature(*summoned, targetGUID))
{
- target->MonsterMoveWithSpeed(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0);
+ target->GetMotionMaster()->MoveJump(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ() + 15.0f, 0);
target->SetPosition(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0.0f);
summoned->CastSpell(target, SPELL_RIBBON_OF_SOULS, false);
}
@@ -152,75 +169,86 @@ public:
void UpdateAI(uint32 diff) override
{
- if (LamentEvent)
- {
- if (LamentEventTimer <= diff)
- {
- DoSummon(ENTRY_HIGHBORNE_BUNNY, me, 10.0f, 3000, TEMPSUMMON_TIMED_DESPAWN);
-
- LamentEventTimer = 2000;
- if (!me->HasAura(SPELL_SYLVANAS_CAST))
- {
- Talk(SAY_LAMENT_END);
- Talk(EMOTE_LAMENT_END);
- LamentEvent = false;
- }
- } else LamentEventTimer -= diff;
- }
-
- if (!UpdateVictim())
+ if (!UpdateVictim() && !LamentEvent)
return;
- // Combat spells
-
- if (FadeTimer <= diff)
- {
- DoCast(me, SPELL_FADE);
- // add a blink to simulate a stealthed movement and reappearing elsewhere
- DoCast(me, SPELL_FADE_BLINK);
- FadeTimer = 30000 + rand32() % 5000;
- // if the victim is out of melee range she cast multi shot
- if (Unit* victim = me->GetVictim())
- if (me->GetDistance(victim) > 10.0f)
- DoCast(victim, SPELL_MULTI_SHOT);
- } else FadeTimer -= diff;
-
- if (SummonSkeletonTimer <= diff)
- {
- DoCast(me, SPELL_SUMMON_SKELETON);
- SummonSkeletonTimer = 20000 + rand32() % 10000;
- } else SummonSkeletonTimer -= diff;
-
- if (BlackArrowTimer <= diff)
- {
- if (Unit* victim = me->GetVictim())
- {
- DoCast(victim, SPELL_BLACK_ARROW);
- BlackArrowTimer = 15000 + rand32() % 5000;
- }
- } else BlackArrowTimer -= diff;
+ _events.Update(diff);
- if (ShotTimer <= diff)
- {
- if (Unit* victim = me->GetVictim())
- {
- DoCast(victim, SPELL_SHOT);
- ShotTimer = 8000 + rand32() % 2000;
- }
- } else ShotTimer -= diff;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- if (MultiShotTimer <= diff)
+ while (uint32 eventId = _events.ExecuteEvent())
{
- if (Unit* victim = me->GetVictim())
+ switch (eventId)
{
- DoCast(victim, SPELL_MULTI_SHOT);
- MultiShotTimer = 10000 + rand32() % 3000;
+ case EVENT_FADE:
+ DoCast(me, SPELL_FADE);
+ // add a blink to simulate a stealthed movement and reappearing elsewhere
+ DoCast(me, SPELL_FADE_BLINK);
+ // if the victim is out of melee range she cast multi shot
+ if (Unit* victim = me->GetVictim())
+ if (me->GetDistance(victim) > 10.0f)
+ DoCast(victim, SPELL_MULTI_SHOT);
+ _events.ScheduleEvent(EVENT_FADE, urand(30000, 35000));
+ break;
+ case EVENT_SUMMON_SKELETON:
+ DoCast(me, SPELL_SUMMON_SKELETON);
+ _events.ScheduleEvent(EVENT_SUMMON_SKELETON, urand(20000, 30000));
+ break;
+ case EVENT_BLACK_ARROW:
+ if (Unit* victim = me->GetVictim())
+ DoCast(victim, SPELL_BLACK_ARROW);
+ _events.ScheduleEvent(EVENT_BLACK_ARROW, urand(15000, 20000));
+ break;
+ case EVENT_SHOOT:
+ if (Unit* victim = me->GetVictim())
+ DoCast(victim, SPELL_SHOT);
+ _events.ScheduleEvent(EVENT_SHOOT, urand(8000, 10000));
+ break;
+ case EVENT_MULTI_SHOT:
+ if (Unit* victim = me->GetVictim())
+ DoCast(victim, SPELL_MULTI_SHOT);
+ _events.ScheduleEvent(EVENT_MULTI_SHOT, urand(10000, 13000));
+ break;
+ case EVENT_LAMENT_OF_THE_HIGHBORN:
+ if (!me->HasAura(SPELL_SYLVANAS_CAST))
+ {
+ Talk(SAY_LAMENT_END);
+ Talk(EMOTE_LAMENT_END);
+ LamentEvent = false;
+ me->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL);
+ Reset();
+ }
+ else
+ {
+ DoSummon(NPC_HIGHBORNE_BUNNY, me, 10.0f, 3000, TEMPSUMMON_TIMED_DESPAWN);
+ _events.ScheduleEvent(EVENT_LAMENT_OF_THE_HIGHBORN, 2000);
+ }
+ break;
+ case EVENT_SUNSORROW_WHISPER:
+ if (Creature* ambassador = me->FindNearestCreature(NPC_AMBASSADOR_SUNSORROW, 20.0f))
+ if (Player* player = ObjectAccessor::GetPlayer(*me, playerGUID))
+ ambassador->AI()->Talk(SAY_SUNSORROW_WHISPER, player);
+ break;
+ default:
+ break;
}
- } else MultiShotTimer -= diff;
+ }
DoMeleeAttackIfReady();
}
+
+ private:
+ EventMap _events;
+ bool LamentEvent;
+ ObjectGuid targetGUID;
+ ObjectGuid playerGUID;
};
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_lady_sylvanas_windrunnerAI(creature);
+ }
};
/*######
diff --git a/src/server/scripts/Kalimdor/CMakeLists.txt b/src/server/scripts/Kalimdor/CMakeLists.txt
index 9a68973b8d1..ce8d0cfbcfd 100644
--- a/src/server/scripts/Kalimdor/CMakeLists.txt
+++ b/src/server/scripts/Kalimdor/CMakeLists.txt
@@ -92,7 +92,6 @@ set(scripts_STAT_SRCS
Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp
Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h
Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp
- Kalimdor/zone_mulgore.cpp
Kalimdor/zone_bloodmyst_isle.cpp
Kalimdor/zone_thunder_bluff.cpp
Kalimdor/zone_azshara.cpp
diff --git a/src/server/scripts/Kalimdor/RazorfenKraul/razorfen_kraul.cpp b/src/server/scripts/Kalimdor/RazorfenKraul/razorfen_kraul.cpp
index a7c17a9df3e..f4a7e1f4185 100644
--- a/src/server/scripts/Kalimdor/RazorfenKraul/razorfen_kraul.cpp
+++ b/src/server/scripts/Kalimdor/RazorfenKraul/razorfen_kraul.cpp
@@ -136,131 +136,7 @@ public:
}
};
-enum SnufflenoseGopher
-{
- NPC_SNUFFLENOSE_GOPHER = 4781,
- GO_BLUELEAF_TUBBER = 20920,
- ACTION_FIND_NEW_TUBBER = 0,
- POINT_TUBBER = 0
-};
-
-struct npc_snufflenose_gopher : public CreatureScript
-{
-public:
- npc_snufflenose_gopher() : CreatureScript("npc_snufflenose_gopher") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_snufflenose_gopherAI(creature);
- }
-
- struct npc_snufflenose_gopherAI : public PetAI
- {
- npc_snufflenose_gopherAI(Creature* creature) : PetAI(creature)
- {
- IsMovementActive = false;
- }
-
- void Reset() override
- {
- IsMovementActive = false;
- TargetTubberGUID.Clear();
- }
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type == POINT_MOTION_TYPE && id == POINT_TUBBER)
- {
- if (GameObject* go = me->GetMap()->GetGameObject(TargetTubberGUID))
- {
- go->SetRespawnTime(5 * MINUTE);
- go->Refresh();
- go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);
- }
-
- IsMovementActive = false;
- }
- else
- PetAI::MovementInform(type, id);
- }
-
- void DoFindNewTubber()
- {
- std::list<GameObject*> tubbersInRange;
- GetGameObjectListWithEntryInGrid(tubbersInRange, me, GO_BLUELEAF_TUBBER, 40.0f);
-
- if (tubbersInRange.empty())
- return;
-
- tubbersInRange.remove_if([](GameObject* go)
- {
- return go->isSpawned() || !go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);
- });
-
- tubbersInRange.sort(Trinity::ObjectDistanceOrderPred(me));
-
- GameObject* nearestTubber = tubbersInRange.front();
- if (!nearestTubber)
- return;
-
- TargetTubberGUID = nearestTubber->GetGUID();
-
- // XFurry was wrong...
- me->GetMotionMaster()->MovePoint(POINT_TUBBER, nearestTubber->GetPositionX(),
- nearestTubber->GetPositionY(),
- nearestTubber->GetPositionZ());
- IsMovementActive = true;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!IsMovementActive)
- PetAI::UpdateAI(diff);
- }
-
- void DoAction(int32 action) override
- {
- if (action == ACTION_FIND_NEW_TUBBER)
- DoFindNewTubber();
- }
-
-
- bool IsMovementActive;
- ObjectGuid TargetTubberGUID;
- };
-};
-
-class spell_snufflenose_command : public SpellScriptLoader
-{
- public:
- spell_snufflenose_command() : SpellScriptLoader("spell_snufflenose_command") { }
-
- class spell_snufflenose_commandSpellScript : public SpellScript
- {
- PrepareSpellScript(spell_snufflenose_commandSpellScript);
-
- void HandleEffect(SpellEffIndex /*effIndex*/)
- {
- if (Creature* target = GetHitCreature())
- if (target->GetEntry() == NPC_SNUFFLENOSE_GOPHER)
- target->AI()->DoAction(ACTION_FIND_NEW_TUBBER);
- }
-
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_snufflenose_commandSpellScript::HandleEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_snufflenose_commandSpellScript();
- }
-};
-
void AddSC_razorfen_kraul()
{
- new npc_snufflenose_gopher();
new npc_willix();
- new spell_snufflenose_command();
}
diff --git a/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp b/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
index 390fd3e529f..ca5e4697c35 100644
--- a/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
+++ b/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
@@ -29,6 +29,7 @@ EndContentData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "PassiveAI.h"
#include "Player.h"
/*######
@@ -48,14 +49,18 @@ class npc_webbed_creature : public CreatureScript
public:
npc_webbed_creature() : CreatureScript("npc_webbed_creature") { }
- struct npc_webbed_creatureAI : public ScriptedAI
+ struct npc_webbed_creatureAI : public NullCreatureAI
{
- npc_webbed_creatureAI(Creature* creature) : ScriptedAI(creature) { }
+ npc_webbed_creatureAI(Creature* creature) : NullCreatureAI(creature) { }
void Reset() override { }
void EnterCombat(Unit* /*who*/) override { }
+ void AttackStart(Unit* /*who*/) override { }
+
+ void MoveInLineOfSight(Unit* /*who*/) override { }
+
void JustDied(Unit* killer) override
{
uint32 spawnCreatureID = 0;
diff --git a/src/server/scripts/Kalimdor/zone_felwood.cpp b/src/server/scripts/Kalimdor/zone_felwood.cpp
index cdf04b1d4cc..91b9ce08010 100644
--- a/src/server/scripts/Kalimdor/zone_felwood.cpp
+++ b/src/server/scripts/Kalimdor/zone_felwood.cpp
@@ -100,7 +100,44 @@ public:
}
};
+/*######
+## at_ancient_leaf
+######*/
+
+enum AncientMisc
+{
+ QUEST_ANCIENT_LEAF = 7632,
+ NPC_VARTRUS = 14524,
+ NPC_STOMA = 14525,
+ NPC_HASTAT = 14526,
+ CREATURE_GROUP_ANCIENTS = 1
+};
+
+class at_ancient_leaf : public AreaTriggerScript
+{
+ public:
+ at_ancient_leaf() : AreaTriggerScript("at_ancient_leaf") { }
+
+ bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override
+ {
+ if (player->IsGameMaster() || !player->IsAlive())
+ return false;
+
+ // Handle Call Ancients event start - The area trigger summons 3 ancients
+ if ((player->GetQuestStatus(QUEST_ANCIENT_LEAF) == QUEST_STATUS_COMPLETE) || (player->GetQuestStatus(QUEST_ANCIENT_LEAF) == QUEST_STATUS_REWARDED))
+ {
+ // If ancients are already spawned, skip the rest
+ if (GetClosestCreatureWithEntry(player, NPC_VARTRUS, 50.0f) || GetClosestCreatureWithEntry(player, NPC_STOMA, 50.0f) || GetClosestCreatureWithEntry(player, NPC_HASTAT, 50.0f))
+ return true;
+
+ player->GetMap()->SummonCreatureGroup(CREATURE_GROUP_ANCIENTS);
+ }
+ return false;
+ }
+};
+
void AddSC_felwood()
{
new npcs_riverbreeze_and_silversky();
+ new at_ancient_leaf();
}
diff --git a/src/server/scripts/Kalimdor/zone_mulgore.cpp b/src/server/scripts/Kalimdor/zone_mulgore.cpp
deleted file mode 100644
index 0d0ef218885..00000000000
--- a/src/server/scripts/Kalimdor/zone_mulgore.cpp
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* ScriptData
-SDName: Mulgore
-SD%Complete: 100
-SDComment: Support for quest: 11129, 772
-SDCategory: Mulgore
-EndScriptData */
-
-/* ContentData
-npc_kyle_frenzied
-npc_plains_vision
-EndContentData */
-
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-#include "ScriptedGossip.h"
-#include "Player.h"
-#include "SpellInfo.h"
-
-/*#####
-# npc_kyle_frenzied
-######*/
-
-enum KyleFrenzied
-{
- EMOTE_SEE_LUNCH = 0,
- EMOTE_EAT_LUNCH = 1,
- EMOTE_DANCE = 2,
-
- SPELL_LUNCH = 42222,
- NPC_KYLE_FRENZIED = 23616,
- NPC_KYLE_FRIENDLY = 23622,
- POINT_ID = 1
-};
-
-class npc_kyle_frenzied : public CreatureScript
-{
-public:
- npc_kyle_frenzied() : CreatureScript("npc_kyle_frenzied") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_kyle_frenziedAI(creature);
- }
-
- struct npc_kyle_frenziedAI : public ScriptedAI
- {
- npc_kyle_frenziedAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- }
-
- void Initialize()
- {
- EventActive = false;
- IsMovingToLunch = false;
- PlayerGUID.Clear();
- EventTimer = 5000;
- EventPhase = 0;
- }
-
- bool EventActive;
- bool IsMovingToLunch;
- ObjectGuid PlayerGUID;
- uint32 EventTimer;
- uint8 EventPhase;
-
- void Reset() override
- {
- Initialize();
-
- if (me->GetEntry() == NPC_KYLE_FRIENDLY)
- me->UpdateEntry(NPC_KYLE_FRENZIED);
- }
-
- void SpellHit(Unit* Caster, SpellInfo const* Spell) override
- {
- if (!me->GetVictim() && !EventActive && Spell->Id == SPELL_LUNCH)
- {
- if (Caster->GetTypeId() == TYPEID_PLAYER)
- PlayerGUID = Caster->GetGUID();
-
- if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE)
- {
- me->GetMotionMaster()->MovementExpired();
- me->GetMotionMaster()->MoveIdle();
- me->StopMoving();
- }
-
- EventActive = true;
- Talk(EMOTE_SEE_LUNCH);
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_CREATURE_SPECIAL);
- }
- }
-
- void MovementInform(uint32 Type, uint32 PointId) override
- {
- if (Type != POINT_MOTION_TYPE || !EventActive)
- return;
-
- if (PointId == POINT_ID)
- IsMovingToLunch = false;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (EventActive)
- {
- if (IsMovingToLunch)
- return;
-
- if (EventTimer <= diff)
- {
- EventTimer = 5000;
- ++EventPhase;
-
- switch (EventPhase)
- {
- case 1:
- if (Unit* unit = ObjectAccessor::GetUnit(*me, PlayerGUID))
- {
- if (GameObject* go = unit->GetGameObject(SPELL_LUNCH))
- {
- IsMovingToLunch = true;
- me->GetMotionMaster()->MovePoint(POINT_ID, go->GetPositionX(), go->GetPositionY(), go->GetPositionZ());
- }
- }
- break;
- case 2:
- Talk(EMOTE_EAT_LUNCH);
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_USE_STANDING);
- break;
- case 3:
- if (Player* unit = ObjectAccessor::GetPlayer(*me, PlayerGUID))
- unit->TalkedToCreature(me->GetEntry(), me->GetGUID());
-
- me->UpdateEntry(NPC_KYLE_FRIENDLY);
- break;
- case 4:
- EventTimer = 30000;
- Talk(EMOTE_DANCE);
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DANCESPECIAL);
- break;
- case 5:
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE);
- Reset();
- me->GetMotionMaster()->Clear();
- break;
- }
- }
- else
- EventTimer -= diff;
- }
- }
- };
-
-};
-
-/*#####
-# npc_plains_vision
-######*/
-
-Position const wpPlainVision[50] =
-{
- {-2226.32f, -408.095f, -9.36235f, 0.0f},
- {-2203.04f, -437.212f, -5.72498f, 0.0f},
- {-2163.91f, -457.851f, -7.09049f, 0.0f},
- {-2123.87f, -448.137f, -9.29591f, 0.0f},
- {-2104.66f, -427.166f, -6.49513f, 0.0f},
- {-2101.48f, -422.826f, -5.3567f, 0.0f},
- {-2097.56f, -417.083f, -7.16716f, 0.0f},
- {-2084.87f, -398.626f, -9.88973f, 0.0f},
- {-2072.71f, -382.324f, -10.2488f, 0.0f},
- {-2054.05f, -356.728f, -6.22468f, 0.0f},
- {-2051.8f, -353.645f, -5.35791f, 0.0f},
- {-2049.08f, -349.912f, -6.15723f, 0.0f},
- {-2030.6f, -310.724f, -9.59302f, 0.0f},
- {-2002.15f, -249.308f, -10.8124f, 0.0f},
- {-1972.85f, -195.811f, -10.6316f, 0.0f},
- {-1940.93f, -147.652f, -11.7055f, 0.0f},
- {-1888.06f, -81.943f, -11.4404f, 0.0f},
- {-1837.05f, -34.0109f, -12.258f, 0.0f},
- {-1796.12f, -14.6462f, -10.3581f, 0.0f},
- {-1732.61f, -4.27746f, -10.0213f, 0.0f},
- {-1688.94f, -0.829945f, -11.7103f, 0.0f},
- {-1681.32f, 13.0313f, -9.48056f, 0.0f},
- {-1677.04f, 36.8349f, -7.10318f, 0.0f},
- {-1675.2f, 68.559f, -8.95384f, 0.0f},
- {-1676.57f, 89.023f, -9.65104f, 0.0f},
- {-1678.16f, 110.939f, -10.1782f, 0.0f},
- {-1677.86f, 128.681f, -5.73869f, 0.0f},
- {-1675.27f, 144.324f, -3.47916f, 0.0f},
- {-1671.7f, 163.169f, -1.23098f, 0.0f},
- {-1666.61f, 181.584f, 5.26145f, 0.0f},
- {-1661.51f, 196.154f, 8.95252f, 0.0f},
- {-1655.47f, 210.811f, 8.38727f, 0.0f},
- {-1647.07f, 226.947f, 5.27755f, 0.0f},
- {-1621.65f, 232.91f, 2.69579f, 0.0f},
- {-1600.23f, 237.641f, 2.98539f, 0.0f},
- {-1576.07f, 242.546f, 4.66541f, 0.0f},
- {-1554.57f, 248.494f, 6.60377f, 0.0f},
- {-1547.53f, 259.302f, 10.6741f, 0.0f},
- {-1541.7f, 269.847f, 16.4418f, 0.0f},
- {-1539.83f, 278.989f, 21.0597f, 0.0f},
- {-1540.16f, 290.219f, 27.8247f, 0.0f},
- {-1538.99f, 298.983f, 34.0032f, 0.0f},
- {-1540.38f, 307.337f, 41.3557f, 0.0f},
- {-1536.61f, 314.884f, 48.0179f, 0.0f},
- {-1532.42f, 323.277f, 55.6667f, 0.0f},
- {-1528.77f, 329.774f, 61.1525f, 0.0f},
- {-1525.65f, 333.18f, 63.2161f, 0.0f},
- {-1517.01f, 350.713f, 62.4286f, 0.0f},
- {-1511.39f, 362.537f, 62.4539f, 0.0f},
- {-1508.68f, 366.822f, 62.733f, 0.0f}
-};
-
-class npc_plains_vision : public CreatureScript
-{
-public:
- npc_plains_vision() : CreatureScript("npc_plains_vision") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_plains_visionAI(creature);
- }
-
- struct npc_plains_visionAI : public ScriptedAI
- {
- npc_plains_visionAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- }
-
- void Initialize()
- {
- WayPointId = 0;
- newWaypoint = true;
- amountWP = 49;
- }
-
- bool newWaypoint;
- uint8 WayPointId;
- uint8 amountWP;
-
- void Reset() override
- {
- Initialize();
- }
-
- void EnterCombat(Unit* /*who*/) override { }
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type != POINT_MOTION_TYPE)
- return;
-
- if (id < amountWP)
- {
- ++WayPointId;
- newWaypoint = true;
- }
- else
- {
- me->setDeathState(JUST_DIED);
- me->RemoveCorpse();
- }
- }
-
- void UpdateAI(uint32 /*diff*/) override
- {
- if (newWaypoint)
- {
- me->GetMotionMaster()->MovePoint(WayPointId, wpPlainVision[WayPointId]);
- newWaypoint = false;
- }
- }
- };
-
-};
-
-/*#####
-#
-######*/
-
-void AddSC_mulgore()
-{
- new npc_kyle_frenzied();
- new npc_plains_vision();
-}
diff --git a/src/server/scripts/Kalimdor/zone_the_barrens.cpp b/src/server/scripts/Kalimdor/zone_the_barrens.cpp
index c167bc700f7..eab104d8df2 100644
--- a/src/server/scripts/Kalimdor/zone_the_barrens.cpp
+++ b/src/server/scripts/Kalimdor/zone_the_barrens.cpp
@@ -659,6 +659,7 @@ public:
if (quest->GetQuestId() == QUEST_ESCAPE)
{
creature->setFaction(FACTION_RATCHET);
+ creature->AI()->Talk(SAY_START);
if (npc_escortAI* pEscortAI = CAST_AI(npc_wizzlecrank_shredder::npc_wizzlecrank_shredderAI, creature->AI()))
pEscortAI->Start(true, false, player->GetGUID());
}
diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt
index e04dcf0ec96..66d9021223f 100644
--- a/src/server/scripts/Northrend/CMakeLists.txt
+++ b/src/server/scripts/Northrend/CMakeLists.txt
@@ -78,8 +78,7 @@ set(scripts_STAT_SRCS
Northrend/Nexus/Oculus/boss_urom.cpp
Northrend/Nexus/Oculus/oculus.cpp
Northrend/Nexus/Oculus/instance_oculus.cpp
- Northrend/Nexus/Nexus/boss_commander_kolurg.cpp
- Northrend/Nexus/Nexus/boss_commander_stoutbeard.cpp
+ Northrend/Nexus/Nexus/boss_nexus_commanders.cpp
Northrend/Nexus/Nexus/boss_ormorok.cpp
Northrend/Nexus/Nexus/boss_magus_telestra.cpp
Northrend/Nexus/Nexus/instance_nexus.cpp
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp
index 4f883fd7e90..23bfd773a9b 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp
@@ -255,12 +255,6 @@ class instance_trial_of_the_crusader : public InstanceMapScript
if (GetBossState(BOSS_VALKIRIES) == SPECIAL)
state = DONE;
break;
- case DONE:
- if (instance->GetPlayers().getFirst()->GetSource()->GetTeam() == ALLIANCE)
- EventStage = 4020;
- else
- EventStage = 4030;
- break;
default:
break;
}
@@ -336,7 +330,7 @@ class instance_trial_of_the_crusader : public InstanceMapScript
if (type < MAX_ENCOUNTERS)
{
- TC_LOG_INFO("scripts", "[ToCr] BossState(type %u) %u = state %u;", type, GetBossState(type), state);
+ TC_LOG_DEBUG("scripts", "[ToCr] BossState(type %u) %u = state %u;", type, GetBossState(type), state);
if (state == FAIL)
{
if (instance->IsHeroic())
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp
index 16526b694e9..974bd4672f1 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp
@@ -133,7 +133,7 @@ class npc_announcer_toc10 : public CreatureScript
char const* _message = "We are ready!";
- if (player->IsInCombat() || instance->IsEncounterInProgress() || instance->GetData(TYPE_EVENT))
+ if (player->IsInCombat() || instance->IsEncounterInProgress())
return true;
uint8 i = 0;
@@ -199,17 +199,11 @@ class npc_announcer_toc10 : public CreatureScript
}
else if (instance->GetBossState(BOSS_LICH_KING) != DONE)
{
- if (GameObject* floor = ObjectAccessor::GetGameObject(*player, instance->GetGuidData(GO_ARGENT_COLISEUM_FLOOR)))
- floor->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED);
-
- creature->CastSpell(creature, SPELL_CORPSE_TELEPORT, false);
- creature->CastSpell(creature, SPELL_DESTROY_FLOOR_KNOCKUP, false);
-
- if (!ObjectAccessor::GetCreature(*creature, instance->GetGuidData(NPC_ANUBARAK)))
- creature->SummonCreature(NPC_ANUBARAK, AnubarakLoc[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME);
-
- if (creature->IsVisible())
- creature->SetVisible(false);
+ if (creature->GetMap()->GetPlayers().getFirst()->GetSource()->GetTeam() == ALLIANCE)
+ instance->SetData(TYPE_EVENT, 4020);
+ else
+ instance->SetData(TYPE_EVENT, 4030);
+ instance->SetBossState(BOSS_LICH_KING, NOT_STARTED);
}
creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
return true;
diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp
index 97c4372f0e6..0b829c2c6dd 100644
--- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp
@@ -27,7 +27,7 @@ enum Yells
SAY_SLAY = 1,
SAY_DEATH = 2,
SAY_SOUL_STORM = 3,
- SAY_CORRUPT_SOUL = 4,
+ SAY_CORRUPT_SOUL = 4
};
enum Spells
@@ -39,9 +39,9 @@ enum Spells
SPELL_TELEPORT = 68988,
SPELL_FEAR = 68950,
SPELL_SOULSTORM = 68872,
- SPELL_SOULSTORM_CHANNEL = 69008, // pre-fight
- SPELL_SOULSTORM_VISUAL = 68870, // pre-cast soulstorm
- SPELL_PURPLE_BANISH_VISUAL = 68862 // Used by Soul Fragment (Aura)
+ SPELL_SOULSTORM_CHANNEL = 69008, // Pre-fight
+ SPELL_SOULSTORM_VISUAL = 68870, // Pre-cast Soulstorm
+ SPELL_PURPLE_BANISH_VISUAL = 68862 // Used by Soul Fragment (Aura)
};
enum Events
@@ -50,7 +50,7 @@ enum Events
EVENT_SHADOW_BOLT = 2,
EVENT_CORRUPT_SOUL = 3,
EVENT_SOULSTORM = 4,
- EVENT_FEAR = 5,
+ EVENT_FEAR = 5
};
enum CombatPhases
@@ -59,6 +59,11 @@ enum CombatPhases
PHASE_2 = 2
};
+enum Misc
+{
+ DATA_SOUL_POWER = 1
+};
+
class boss_bronjahm : public CreatureScript
{
public:
@@ -73,33 +78,30 @@ class boss_bronjahm : public CreatureScript
void Reset() override
{
- events.Reset();
+ _Reset();
events.SetPhase(PHASE_1);
events.ScheduleEvent(EVENT_SHADOW_BOLT, 2000);
events.ScheduleEvent(EVENT_MAGIC_BANE, urand(8000, 20000));
events.ScheduleEvent(EVENT_CORRUPT_SOUL, urand(25000, 35000), 0, PHASE_1);
-
- instance->SetBossState(DATA_BRONJAHM, NOT_STARTED);
}
- void JustReachedHome() override
- {
- DoCast(me, SPELL_SOULSTORM_CHANNEL, true);
- }
+ void JustReachedHome() override
+ {
+ _JustReachedHome();
+ DoCast(me, SPELL_SOULSTORM_CHANNEL, true);
+ }
void EnterCombat(Unit* /*who*/) override
{
+ _EnterCombat();
Talk(SAY_AGGRO);
me->RemoveAurasDueToSpell(SPELL_SOULSTORM_CHANNEL);
-
- instance->SetBossState(DATA_BRONJAHM, IN_PROGRESS);
}
void JustDied(Unit* /*killer*/) override
{
+ _JustDied();
Talk(SAY_DEATH);
-
- instance->SetBossState(DATA_BRONJAHM, DONE);
}
void KilledUnit(Unit* who) override
@@ -128,6 +130,23 @@ class boss_bronjahm : public CreatureScript
summon->CastSpell(summon, SPELL_PURPLE_BANISH_VISUAL, true);
}
+ uint32 GetData(uint32 type) const override
+ {
+ if (type == DATA_SOUL_POWER)
+ {
+ uint32 count = 0;
+ for (ObjectGuid const& guid : summons)
+ {
+ if (Creature* summon = ObjectAccessor::GetCreature(*me, guid))
+ if (summon->GetEntry() == NPC_CORRUPTED_SOUL_FRAGMENT && summon->IsAlive())
+ ++count;
+ }
+ return count;
+ }
+
+ return 0;
+ }
+
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
@@ -143,13 +162,21 @@ class boss_bronjahm : public CreatureScript
switch (eventId)
{
case EVENT_MAGIC_BANE:
- DoCastVictim(SPELL_MAGIC_S_BANE);
+ DoCastAOE(SPELL_MAGIC_S_BANE);
events.ScheduleEvent(EVENT_MAGIC_BANE, urand(8000, 20000));
break;
case EVENT_SHADOW_BOLT:
- if (!me->IsWithinMeleeRange(me->GetVictim()))
+ if (events.IsInPhase(PHASE_2))
+ {
DoCastVictim(SPELL_SHADOW_BOLT);
- events.ScheduleEvent(EVENT_SHADOW_BOLT, 2000);
+ events.ScheduleEvent(EVENT_SHADOW_BOLT, urand(1, 2) * IN_MILLISECONDS);
+ }
+ else
+ {
+ if (!me->IsWithinMeleeRange(me->GetVictim()))
+ DoCastVictim(SPELL_SHADOW_BOLT);
+ events.ScheduleEvent(EVENT_SHADOW_BOLT, 2 * IN_MILLISECONDS);
+ }
break;
case EVENT_CORRUPT_SOUL:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true))
@@ -165,8 +192,7 @@ class boss_bronjahm : public CreatureScript
me->CastSpell(me, SPELL_SOULSTORM, false);
break;
case EVENT_FEAR:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true))
- me->CastCustomSpell(SPELL_FEAR, SPELLVALUE_MAX_TARGETS, 1, target, false);
+ me->CastCustomSpell(SPELL_FEAR, SPELLVALUE_MAX_TARGETS, 1, nullptr, false);
events.ScheduleEvent(EVENT_FEAR, urand(8000, 12000), 0, PHASE_2);
break;
default:
@@ -174,7 +200,8 @@ class boss_bronjahm : public CreatureScript
}
}
- DoMeleeAttackIfReady();
+ if (!events.IsInPhase(PHASE_2))
+ DoMeleeAttackIfReady();
}
};
@@ -201,17 +228,11 @@ class npc_corrupted_soul_fragment : public CreatureScript
if (type != CHASE_MOTION_TYPE)
return;
- if (TempSummon* summ = me->ToTempSummon())
- {
- ObjectGuid BronjahmGUID(instance->GetGuidData(DATA_BRONJAHM));
- if (BronjahmGUID.GetCounter() != id)
- return;
-
- if (Creature* bronjahm = ObjectAccessor::GetCreature(*me, BronjahmGUID))
- me->CastSpell(bronjahm, SPELL_CONSUME_SOUL, true);
+ if (instance->GetGuidData(DATA_BRONJAHM).GetCounter() != id)
+ return;
- summ->UnSummon();
- }
+ me->CastSpell((Unit*)nullptr, SPELL_CONSUME_SOUL, true);
+ me->DespawnOrUnsummon();
}
private:
@@ -220,7 +241,7 @@ class npc_corrupted_soul_fragment : public CreatureScript
CreatureAI* GetAI(Creature* creature) const override
{
- return GetInstanceAI<npc_corrupted_soul_fragmentAI>(creature);
+ return GetInstanceAI<npc_corrupted_soul_fragmentAI>(creature, FoSScriptName);
}
};
@@ -238,12 +259,10 @@ class spell_bronjahm_magic_bane : public SpellScriptLoader
if (GetHitUnit()->getPowerType() != POWER_MANA)
return;
- const int32 maxDamage = GetCaster()->GetMap()->GetSpawnMode() == 1 ? 15000 : 10000;
- int32 newDamage = GetHitDamage();
- newDamage += GetHitUnit()->GetMaxPower(POWER_MANA)/2;
- newDamage = std::min<int32>(maxDamage, newDamage);
+ int32 const maxDamage = GetCaster()->GetMap()->IsHeroic() ? 15000 : 10000;
+ int32 newDamage = GetHitDamage() + (GetHitUnit()->GetMaxPower(POWER_MANA) / 2);
- SetHitDamage(newDamage);
+ SetHitDamage(std::min<int32>(maxDamage, newDamage));
}
void Register() override
@@ -261,7 +280,7 @@ class spell_bronjahm_magic_bane : public SpellScriptLoader
class spell_bronjahm_consume_soul : public SpellScriptLoader
{
public:
- spell_bronjahm_consume_soul() : SpellScriptLoader("spell_bronjahm_consume_soul") { }
+ spell_bronjahm_consume_soul() : SpellScriptLoader("spell_bronjahm_consume_soul") { }
class spell_bronjahm_consume_soul_SpellScript : public SpellScript
{
@@ -285,38 +304,22 @@ class spell_bronjahm_consume_soul : public SpellScriptLoader
}
};
-class spell_bronjahm_soulstorm_channel : public SpellScriptLoader
+static uint32 const SoulstormVisualSpells[] =
{
- public:
- spell_bronjahm_soulstorm_channel() : SpellScriptLoader("spell_bronjahm_soulstorm_channel") { }
-
- class spell_bronjahm_soulstorm_channel_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_bronjahm_soulstorm_channel_AuraScript);
-
- void HandlePeriodicTick(AuraEffect const* /*aurEff*/)
- {
- PreventDefaultAction();
- for (uint32 i = 68904; i <= 68907; ++i)
- GetTarget()->CastSpell(GetTarget(), i, true);
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_bronjahm_soulstorm_channel_AuraScript::HandlePeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_bronjahm_soulstorm_channel_AuraScript();
- }
+ 68904,
+ 68886,
+ 68905,
+ 68896,
+ 68906,
+ 68897,
+ 68907,
+ 68898
};
class spell_bronjahm_soulstorm_visual : public SpellScriptLoader
{
public:
- spell_bronjahm_soulstorm_visual() : SpellScriptLoader("spell_bronjahm_soulstorm_visual") { }
+ spell_bronjahm_soulstorm_visual(char const* scriptName) : SpellScriptLoader(scriptName) { }
class spell_bronjahm_soulstorm_visual_AuraScript : public AuraScript
{
@@ -325,11 +328,7 @@ class spell_bronjahm_soulstorm_visual : public SpellScriptLoader
void HandlePeriodicTick(AuraEffect const* aurEff)
{
PreventDefaultAction();
- if (aurEff->GetTickNumber()%5)
- return;
- GetTarget()->CastSpell(GetTarget(), 68886, true);
- for (uint32 i = 68896; i <= 68898; ++i)
- GetTarget()->CastSpell(GetTarget(), i, true);
+ GetTarget()->CastSpell(GetTarget(), SoulstormVisualSpells[aurEff->GetTickNumber() % 8], true);
}
void Register() override
@@ -344,21 +343,6 @@ class spell_bronjahm_soulstorm_visual : public SpellScriptLoader
}
};
-class DistanceCheck
-{
- public:
- explicit DistanceCheck(Unit* _caster) : caster(_caster) { }
-
- bool operator() (WorldObject* unit) const
- {
- if (caster->GetExactDist2d(unit) <= 10.0f)
- return true;
- return false;
- }
-
- Unit* caster;
-};
-
class spell_bronjahm_soulstorm_targeting : public SpellScriptLoader
{
public:
@@ -368,25 +352,19 @@ class spell_bronjahm_soulstorm_targeting : public SpellScriptLoader
{
PrepareSpellScript(spell_bronjahm_soulstorm_targeting_SpellScript);
- void FilterTargetsInitial(std::list<WorldObject*>& targets)
- {
- targets.remove_if(DistanceCheck(GetCaster()));
- sharedTargets = targets;
- }
-
- // use the same target for first and second effect
- void FilterTargetsSubsequent(std::list<WorldObject*>& targets)
+ void FilterTargets(std::list<WorldObject*>& targets)
{
- targets = sharedTargets;
+ Unit* caster = GetCaster();
+ targets.remove_if([caster](WorldObject* target)
+ {
+ return caster->GetExactDist2d(target) <= 10.0f;
+ });
}
void Register() override
{
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_bronjahm_soulstorm_targeting_SpellScript::FilterTargetsInitial, EFFECT_1, TARGET_UNIT_DEST_AREA_ENEMY);
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_bronjahm_soulstorm_targeting_SpellScript::FilterTargetsSubsequent, EFFECT_2, TARGET_UNIT_DEST_AREA_ENEMY);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_bronjahm_soulstorm_targeting_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY);
}
-
- std::list<WorldObject*> sharedTargets;
};
SpellScript* GetSpellScript() const override
@@ -395,13 +373,25 @@ class spell_bronjahm_soulstorm_targeting : public SpellScriptLoader
}
};
+class achievement_bronjahm_soul_power : public AchievementCriteriaScript
+{
+ public:
+ achievement_bronjahm_soul_power() : AchievementCriteriaScript("achievement_bronjahm_soul_power") { }
+
+ bool OnCheck(Player* /*source*/, Unit* target) override
+ {
+ return target && target->GetAI()->GetData(DATA_SOUL_POWER) >= 4;
+ }
+};
+
void AddSC_boss_bronjahm()
{
new boss_bronjahm();
new npc_corrupted_soul_fragment();
new spell_bronjahm_magic_bane();
new spell_bronjahm_consume_soul();
- new spell_bronjahm_soulstorm_channel();
- new spell_bronjahm_soulstorm_visual();
+ new spell_bronjahm_soulstorm_visual("spell_bronjahm_soulstorm_channel");
+ new spell_bronjahm_soulstorm_visual("spell_bronjahm_soulstorm_visual");
new spell_bronjahm_soulstorm_targeting();
+ new achievement_bronjahm_soul_power();
}
diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp
index 2f1d4943019..d5f00757039 100644
--- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp
@@ -128,7 +128,7 @@ class boss_devourer_of_souls : public CreatureScript
struct boss_devourer_of_soulsAI : public BossAI
{
- boss_devourer_of_soulsAI(Creature* creature) : BossAI(creature, DATA_DEVOURER_EVENT)
+ boss_devourer_of_soulsAI(Creature* creature) : BossAI(creature, DATA_DEVOURER_OF_SOULS)
{
Initialize();
beamAngle = 0.f;
@@ -143,20 +143,17 @@ class boss_devourer_of_souls : public CreatureScript
void Reset() override
{
+ _Reset();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
me->SetDisplayId(DISPLAY_ANGER);
me->SetReactState(REACT_AGGRESSIVE);
- events.Reset();
- summons.DespawnAll();
-
Initialize();
-
- instance->SetData(DATA_DEVOURER_EVENT, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
+ _EnterCombat();
Talk(SAY_FACE_AGGRO);
if (!me->FindNearestCreature(NPC_CRUCIBLE_OF_SOULS, 60)) // Prevent double spawn
@@ -166,8 +163,6 @@ class boss_devourer_of_souls : public CreatureScript
events.ScheduleEvent(EVENT_WELL_OF_SOULS, 30000);
events.ScheduleEvent(EVENT_UNLEASHED_SOULS, 20000);
events.ScheduleEvent(EVENT_WAILING_SOULS, urand(60000, 70000));
-
- instance->SetData(DATA_DEVOURER_EVENT, IN_PROGRESS);
}
void KilledUnit(Unit* victim) override
@@ -175,7 +170,7 @@ class boss_devourer_of_souls : public CreatureScript
if (victim->GetTypeId() != TYPEID_PLAYER)
return;
- int32 textId = 0;
+ uint8 textId = 0;
switch (me->GetDisplayId())
{
case DISPLAY_ANGER:
@@ -197,14 +192,12 @@ class boss_devourer_of_souls : public CreatureScript
void JustDied(Unit* /*killer*/) override
{
- summons.DespawnAll();
+ _JustDied();
Position spawnPoint = {5618.139f, 2451.873f, 705.854f, 0};
Talk(SAY_FACE_DEATH);
- instance->SetData(DATA_DEVOURER_EVENT, DONE);
-
int32 entryIndex;
if (instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
entryIndex = 0;
@@ -402,11 +395,6 @@ class spell_devourer_of_souls_mirrored_soul_proc : public SpellScriptLoader
return true;
}
- bool Load() override
- {
- return true;
- }
-
bool CheckProc(ProcEventInfo& /*eventInfo*/)
{
return GetCaster() && GetCaster()->IsAlive();
diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.h b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.h
index 054e5d5a7bd..ddbc117e7fd 100644
--- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.h
+++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.h
@@ -15,38 +15,44 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef DEF_FORGE_OF_SOULS_H
-#define DEF_FORGE_OF_SOULS_H
+#ifndef FORGE_OF_SOULS_H_
+#define FORGE_OF_SOULS_H_
#define FoSScriptName "instance_forge_of_souls"
#define DataHeader "FOS"
+uint32 const EncounterCount = 2;
+
enum Data
{
- DATA_BRONJAHM = 0,
- DATA_DEVOURER = 1,
- DATA_DEVOURER_EVENT = 2,
- DATA_TEAM_IN_INSTANCE = 3,
+ // Encounter states and GUIDs
+ DATA_BRONJAHM = 0,
+ DATA_DEVOURER_OF_SOULS = 1,
+
+ // Additional Data
+ DATA_TEAM_IN_INSTANCE = 2
};
enum Creatures
{
- CREATURE_BRONJAHM = 36497,
- CREATURE_DEVOURER = 36502,
-
- NPC_SYLVANAS_PART1 = 37596,
- NPC_SYLVANAS_PART2 = 38161,
- NPC_JAINA_PART1 = 37597,
- NPC_JAINA_PART2 = 38160,
- NPC_KALIRA = 37583,
- NPC_ELANDRA = 37774,
- NPC_LORALEN = 37779,
- NPC_KORELN = 37582,
- NPC_CHAMPION_1_HORDE = 37584,
- NPC_CHAMPION_2_HORDE = 37587,
- NPC_CHAMPION_3_HORDE = 37588,
- NPC_CHAMPION_1_ALLIANCE = 37496,
- NPC_CHAMPION_2_ALLIANCE = 37497,
- NPC_CRUCIBLE_OF_SOULS = 37094,
+ NPC_BRONJAHM = 36497,
+ NPC_DEVOURER = 36502,
+ NPC_CORRUPTED_SOUL_FRAGMENT = 36535,
+
+ NPC_SYLVANAS_PART1 = 37596,
+ NPC_SYLVANAS_PART2 = 38161,
+ NPC_JAINA_PART1 = 37597,
+ NPC_JAINA_PART2 = 38160,
+ NPC_KALIRA = 37583,
+ NPC_ELANDRA = 37774,
+ NPC_LORALEN = 37779,
+ NPC_KORELN = 37582,
+ NPC_CHAMPION_1_HORDE = 37584,
+ NPC_CHAMPION_2_HORDE = 37587,
+ NPC_CHAMPION_3_HORDE = 37588,
+ NPC_CHAMPION_1_ALLIANCE = 37496,
+ NPC_CHAMPION_2_ALLIANCE = 37497,
+ NPC_CRUCIBLE_OF_SOULS = 37094
};
-#endif
+
+#endif // FORGE_OF_SOULS_H_
diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp
index 8b586ea7fc2..db7628ebada 100644
--- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp
@@ -20,13 +20,6 @@
#include "forge_of_souls.h"
#include "Player.h"
-#define MAX_ENCOUNTER 2
-
-/* Forge of Souls encounters:
-0- Bronjahm, The Godfather of Souls
-1- The Devourer of Souls
-*/
-
class instance_forge_of_souls : public InstanceMapScript
{
public:
@@ -37,7 +30,7 @@ class instance_forge_of_souls : public InstanceMapScript
instance_forge_of_souls_InstanceScript(Map* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
- SetBossNumber(MAX_ENCOUNTER);
+ SetBossNumber(EncounterCount);
teamInInstance = 0;
}
@@ -60,10 +53,10 @@ class instance_forge_of_souls : public InstanceMapScript
switch (creature->GetEntry())
{
- case CREATURE_BRONJAHM:
+ case NPC_BRONJAHM:
bronjahm = creature->GetGUID();
break;
- case CREATURE_DEVOURER:
+ case NPC_DEVOURER:
devourerOfSouls = creature->GetGUID();
break;
case NPC_SYLVANAS_PART1:
@@ -100,7 +93,7 @@ class instance_forge_of_souls : public InstanceMapScript
{
case DATA_BRONJAHM:
return bronjahm;
- case DATA_DEVOURER:
+ case DATA_DEVOURER_OF_SOULS:
return devourerOfSouls;
default:
break;
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
index 7b80db7dd39..927ebfbc55c 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
@@ -21,6 +21,7 @@
#include "SpellScript.h"
#include "Transport.h"
#include "Player.h"
+#include "MoveSplineInit.h"
#include "halls_of_reflection.h"
enum Text
@@ -342,6 +343,20 @@ class npc_jaina_or_sylvanas_intro_hor : public CreatureScript
public:
npc_jaina_or_sylvanas_intro_hor() : CreatureScript("npc_jaina_or_sylvanas_intro_hor") { }
+ bool OnGossipHello(Player* player, Creature* creature) override
+ {
+ // override default gossip
+ if (InstanceScript* instance = creature->GetInstanceScript())
+ if (instance->GetData(DATA_QUEL_DELAR_EVENT) == IN_PROGRESS || instance->GetData(DATA_QUEL_DELAR_EVENT) == SPECIAL)
+ {
+ player->PlayerTalkClass->ClearMenus();
+ return true;
+ }
+
+ // load default gossip
+ return false;
+ }
+
struct npc_jaina_or_sylvanas_intro_horAI : public ScriptedAI
{
npc_jaina_or_sylvanas_intro_horAI(Creature* creature) : ScriptedAI(creature)
@@ -1998,6 +2013,13 @@ class at_hor_intro_start : public AreaTriggerScript
if (_instance->GetData(DATA_INTRO_EVENT) == NOT_STARTED)
_instance->SetData(DATA_INTRO_EVENT, IN_PROGRESS);
+ if (player->HasAura(SPELL_QUEL_DELAR_COMPULSION) && (player->GetQuestStatus(QUEST_HALLS_OF_REFLECTION_ALLIANCE) == QUEST_STATUS_INCOMPLETE ||
+ player->GetQuestStatus(QUEST_HALLS_OF_REFLECTION_HORDE) == QUEST_STATUS_INCOMPLETE) && _instance->GetData(DATA_QUEL_DELAR_EVENT) == NOT_STARTED)
+ {
+ _instance->SetData(DATA_QUEL_DELAR_EVENT, IN_PROGRESS);
+ _instance->SetGuidData(DATA_QUEL_DELAR_INVOKER, player->GetGUID());
+ }
+
return true;
}
};
@@ -2330,6 +2352,374 @@ class npc_lumbering_abomination : public CreatureScript
}
};
+enum QuelDelarUther
+{
+ ACTION_UTHER_START_SCREAM = 1,
+ ACTION_UTHER_OUTRO = 2,
+
+ EVENT_UTHER_1 = 1,
+ EVENT_UTHER_2 = 2,
+ EVENT_UTHER_3 = 3,
+ EVENT_UTHER_4 = 4,
+ EVENT_UTHER_5 = 5,
+ EVENT_UTHER_6 = 6,
+ EVENT_UTHER_7 = 7,
+ EVENT_UTHER_8 = 8,
+ EVENT_UTHER_9 = 9,
+ EVENT_UTHER_10 = 10,
+ EVENT_UTHER_11 = 11,
+ EVENT_UTHER_FACING = 12,
+ EVENT_UTHER_KNEEL = 13,
+
+ SAY_UTHER_QUEL_DELAR_1 = 16,
+ SAY_UTHER_QUEL_DELAR_2 = 17,
+ SAY_UTHER_QUEL_DELAR_3 = 18,
+ SAY_UTHER_QUEL_DELAR_4 = 19,
+ SAY_UTHER_QUEL_DELAR_5 = 20,
+ SAY_UTHER_QUEL_DELAR_6 = 21,
+
+ SPELL_ESSENCE_OF_CAPTURED_1 = 73036
+};
+
+enum QuelDelarSword
+{
+ SPELL_WHIRLWIND_VISUAL = 70300,
+ SPELL_HEROIC_STRIKE = 29426,
+ SPELL_WHIRLWIND = 67716,
+ SPELL_BLADESTORM = 67541,
+
+ NPC_QUEL_DELAR = 37158,
+ POINT_TAKE_OFF = 1,
+
+ EVENT_QUEL_DELAR_INIT = 1,
+ EVENT_QUEL_DELAR_FLIGHT_INIT = 2,
+ EVENT_QUEL_DELAR_FLIGHT = 3,
+ EVENT_QUEL_DELAR_LAND = 4,
+ EVENT_QUEL_DELAR_FIGHT = 5,
+ EVENT_QUEL_DELAR_BLADESTORM = 6,
+ EVENT_QUEL_DELAR_HEROIC_STRIKE = 7,
+ EVENT_QUEL_DELAR_WHIRLWIND = 8,
+
+ SAY_QUEL_DELAR_SWORD = 0
+};
+
+enum QuelDelarMisc
+{
+ SAY_FROSTMOURNE_BUNNY = 0,
+ SPELL_QUEL_DELAR_WILL = 70698
+};
+
+Position const QuelDelarCenterPos = { 5309.259f, 2006.390f, 718.046f, 0.0f };
+Position const QuelDelarSummonPos = { 5298.473f, 1994.852f, 709.424f, 3.979351f };
+Position const QuelDelarMovement[] =
+{
+ { 5292.870f, 1998.950f, 718.046f, 0.0f },
+ { 5295.819f, 1991.912f, 707.707f, 0.0f },
+ { 5295.301f, 1989.782f, 708.696f, 0.0f }
+};
+
+Position const UtherQuelDelarMovement[] =
+{
+ { 5336.830f, 1981.700f, 709.319f, 0.0f },
+ { 5314.350f, 1993.440f, 707.726f, 0.0f }
+};
+
+class npc_uther_quel_delar : public CreatureScript
+{
+ public:
+ npc_uther_quel_delar() : CreatureScript("npc_uther_quel_delar") { }
+
+ struct npc_uther_quel_delarAI : public ScriptedAI
+ {
+ npc_uther_quel_delarAI(Creature* creature) : ScriptedAI(creature)
+ {
+ _instance = me->GetInstanceScript();
+ }
+
+ void Reset() override
+ {
+ // Prevent to break Uther in intro event during instance encounter
+ if (_instance->GetData(DATA_QUEL_DELAR_EVENT) != IN_PROGRESS && _instance->GetData(DATA_QUEL_DELAR_EVENT) != SPECIAL)
+ return;
+
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_UTHER_1, 1);
+ }
+
+ void DamageTaken(Unit* /*attacker*/, uint32& damage) override
+ {
+ if (damage >= me->GetHealth())
+ damage = me->GetHealth() - 1;
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_UTHER_START_SCREAM:
+ _instance->SetData(DATA_QUEL_DELAR_EVENT, SPECIAL);
+ _events.ScheduleEvent(EVENT_UTHER_2, 0);
+ break;
+ case ACTION_UTHER_OUTRO:
+ _events.ScheduleEvent(EVENT_UTHER_6, 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void MovementInform(uint32 /*type*/, uint32 pointId) override
+ {
+ switch (pointId)
+ {
+ case 1:
+ _events.ScheduleEvent(EVENT_UTHER_FACING, 1000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ // Prevent to break Uther in intro event during instance encounter
+ if (_instance->GetData(DATA_QUEL_DELAR_EVENT) != IN_PROGRESS && _instance->GetData(DATA_QUEL_DELAR_EVENT) != SPECIAL)
+ return;
+
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_UTHER_1:
+ Talk(SAY_UTHER_QUEL_DELAR_1);
+ break;
+ case EVENT_UTHER_2:
+ if (Creature* bunny = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_FROSTMOURNE_ALTAR_BUNNY)))
+ if (Unit* target = ObjectAccessor::GetPlayer(*me, _instance->GetGuidData(DATA_QUEL_DELAR_INVOKER)))
+ bunny->CastSpell(target, SPELL_QUEL_DELAR_WILL, true);
+ _events.ScheduleEvent(EVENT_UTHER_3, 2000);
+ break;
+ case EVENT_UTHER_3:
+ me->SummonCreature(NPC_QUEL_DELAR, QuelDelarSummonPos);
+ _events.ScheduleEvent(EVENT_UTHER_4, 2000);
+ break;
+ case EVENT_UTHER_4:
+ Talk(SAY_UTHER_QUEL_DELAR_2);
+ _events.ScheduleEvent(EVENT_UTHER_5, 8000);
+ break;
+ case EVENT_UTHER_5:
+ me->GetMotionMaster()->MovePoint(1, UtherQuelDelarMovement[0]);
+ break;
+ case EVENT_UTHER_6:
+ me->SetWalk(true);
+ me->GetMotionMaster()->MovePoint(0, UtherQuelDelarMovement[1]);
+ _events.ScheduleEvent(EVENT_UTHER_7, 5000);
+ break;
+ case EVENT_UTHER_7:
+ Talk(SAY_UTHER_QUEL_DELAR_3);
+ _events.ScheduleEvent(EVENT_UTHER_8, 12000);
+ break;
+ case EVENT_UTHER_8:
+ Talk(SAY_UTHER_QUEL_DELAR_4);
+ _events.ScheduleEvent(EVENT_UTHER_9, 7000);
+ break;
+ case EVENT_UTHER_9:
+ Talk(SAY_UTHER_QUEL_DELAR_5);
+ _events.ScheduleEvent(EVENT_UTHER_10, 10000);
+ break;
+ case EVENT_UTHER_10:
+ Talk(SAY_UTHER_QUEL_DELAR_6);
+ _events.ScheduleEvent(EVENT_UTHER_11, 5000);
+ break;
+ case EVENT_UTHER_11:
+ DoCast(me, SPELL_ESSENCE_OF_CAPTURED_1, true);
+ me->DespawnOrUnsummon(3000);
+ _instance->SetData(DATA_QUEL_DELAR_EVENT, DONE);
+ break;
+ case EVENT_UTHER_FACING:
+ if (Creature* bunny = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_FROSTMOURNE_ALTAR_BUNNY)))
+ me->SetFacingToObject(bunny);
+ _events.ScheduleEvent(EVENT_UTHER_KNEEL, 1000);
+ break;
+ case EVENT_UTHER_KNEEL:
+ me->HandleEmoteCommand(EMOTE_STATE_KNEEL);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap _events;
+ InstanceScript* _instance;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetHallsOfReflectionAI<npc_uther_quel_delarAI>(creature);
+ }
+};
+
+class npc_quel_delar_sword : public CreatureScript
+{
+ public:
+ npc_quel_delar_sword() : CreatureScript("npc_quel_delar_sword") { }
+
+ struct npc_quel_delar_swordAI : public ScriptedAI
+ {
+ npc_quel_delar_swordAI(Creature* creature) : ScriptedAI(creature)
+ {
+ _instance = me->GetInstanceScript();
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid2);
+ _intro = true;
+ }
+
+ void Reset() override
+ {
+ _events.Reset();
+ me->SetSpeed(MOVE_FLIGHT, 4.5f, true);
+ DoCast(SPELL_WHIRLWIND_VISUAL);
+ if (_intro)
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_INIT, 0);
+ else
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
+ }
+
+ void EnterCombat(Unit* /*victim*/) override
+ {
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_HEROIC_STRIKE, 4000);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_BLADESTORM, 6000);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_WHIRLWIND, 6000);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Creature* uther = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_UTHER_QUEL_DELAR)))
+ uther->AI()->DoAction(ACTION_UTHER_OUTRO);
+ }
+
+ void MovementInform(uint32 type, uint32 pointId) override
+ {
+ if (type != EFFECT_MOTION_TYPE)
+ return;
+
+ switch (pointId)
+ {
+ case POINT_TAKE_OFF:
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_FLIGHT, 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ if (!UpdateVictim())
+ {
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_QUEL_DELAR_INIT:
+ if (Creature* bunny = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_FROSTMOURNE_ALTAR_BUNNY)))
+ bunny->AI()->Talk(SAY_FROSTMOURNE_BUNNY);
+ _intro = false;
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_FLIGHT_INIT, 2500);
+ break;
+ case EVENT_QUEL_DELAR_FLIGHT_INIT:
+ me->GetMotionMaster()->MoveTakeoff(POINT_TAKE_OFF, QuelDelarMovement[0]);
+ break;
+ case EVENT_QUEL_DELAR_FLIGHT:
+ {
+ me->GetMotionMaster()->MoveCirclePath(QuelDelarCenterPos.GetPositionX(), QuelDelarCenterPos.GetPositionY(), 718.046f, 18.0f, true, 16);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_LAND, 15000);
+ break;
+ }
+ case EVENT_QUEL_DELAR_LAND:
+ me->StopMoving();
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveLand(0, QuelDelarMovement[1]);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_FIGHT, 6000);
+ break;
+ case EVENT_QUEL_DELAR_FIGHT:
+ Talk(SAY_QUEL_DELAR_SWORD);
+ me->GetMotionMaster()->MovePoint(0, QuelDelarMovement[2]);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_QUEL_DELAR_BLADESTORM:
+ DoCast(me, SPELL_BLADESTORM);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_BLADESTORM, 10000);
+ break;
+ case EVENT_QUEL_DELAR_HEROIC_STRIKE:
+ DoCastVictim(SPELL_HEROIC_STRIKE);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_HEROIC_STRIKE, 6000);
+ break;
+ case EVENT_QUEL_DELAR_WHIRLWIND:
+ DoCastAOE(SPELL_WHIRLWIND);
+ _events.ScheduleEvent(EVENT_QUEL_DELAR_WHIRLWIND, 1000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ }
+
+ private:
+ EventMap _events;
+ InstanceScript* _instance;
+ bool _intro;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetHallsOfReflectionAI<npc_quel_delar_swordAI>(creature);
+ }
+};
+
+// 5660
+class at_hor_uther_quel_delar_start : public AreaTriggerScript
+{
+ public:
+ at_hor_uther_quel_delar_start() : AreaTriggerScript("at_hor_uther_quel_delar_start") { }
+
+ bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override
+ {
+ if (player->IsGameMaster())
+ return true;
+
+ InstanceScript* _instance = player->GetInstanceScript();
+
+ if (_instance->GetData(DATA_QUEL_DELAR_EVENT) == IN_PROGRESS)
+ if (Creature* uther = ObjectAccessor::GetCreature(*player, _instance->GetGuidData(DATA_UTHER_QUEL_DELAR)))
+ uther->AI()->DoAction(ACTION_UTHER_START_SCREAM);
+
+ return true;
+ }
+};
+
// 72900 - Start Halls of Reflection Quest AE
class spell_hor_start_halls_of_reflection_quest_ae : public SpellScriptLoader
{
@@ -2447,6 +2837,7 @@ void AddSC_halls_of_reflection()
new at_hor_waves_restarter();
new at_hor_impenetrable_door();
new at_hor_shadow_throne();
+ new at_hor_uther_quel_delar_start();
new npc_jaina_or_sylvanas_intro_hor();
new npc_jaina_or_sylvanas_escape_hor();
new npc_the_lich_king_escape_hor();
@@ -2461,6 +2852,8 @@ void AddSC_halls_of_reflection()
new npc_raging_ghoul();
new npc_risen_witch_doctor();
new npc_lumbering_abomination();
+ new npc_uther_quel_delar();
+ new npc_quel_delar_sword();
new spell_hor_start_halls_of_reflection_quest_ae();
new spell_hor_evasion();
new spell_hor_gunship_cannon_fire();
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h
index 9594617fa9a..d2f9ab5d262 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h
@@ -46,7 +46,13 @@ enum DataTypes
DATA_ESCAPE_LEADER = 10,
DATA_ICEWALL = 11,
DATA_ICEWALL_TARGET = 12,
- DATA_GUNSHIP = 13
+ DATA_GUNSHIP = 13,
+
+ // Quest stuff
+ DATA_QUEL_DELAR_EVENT = 14,
+ DATA_FROSTMOURNE_ALTAR_BUNNY = 15,
+ DATA_UTHER_QUEL_DELAR = 16,
+ DATA_QUEL_DELAR_INVOKER = 17
};
enum CreatureIds
@@ -131,7 +137,8 @@ enum InstanceEvents
EVENT_NEXT_WAVE = 2,
EVENT_DO_WIPE = 3,
EVENT_ADD_WAVE = 4,
- EVENT_SPAWN_ESCAPE_EVENT = 5
+ EVENT_SPAWN_ESCAPE_EVENT = 5,
+ EVENT_QUEL_DELAR_SUMMON_UTHER = 6
};
enum InstanceEventIds
@@ -160,7 +167,17 @@ enum InstanceSpells
// Gunship
SPELL_GUNSHIP_CANNON_FIRE = 70017,
SPELL_GUNSHIP_CANNON_FIRE_MISSILE_ALLIANCE = 70021,
- SPELL_GUNSHIP_CANNON_FIRE_MISSILE_HORDE = 70246
+ SPELL_GUNSHIP_CANNON_FIRE_MISSILE_HORDE = 70246,
+
+ // Halls of Reflection quest
+ SPELL_QUEL_DELAR_COMPULSION = 70013,
+ SPELL_ESSENCE_OF_CAPTURED = 70720
+};
+
+enum InstanceQuests
+{
+ QUEST_HALLS_OF_REFLECTION_ALLIANCE = 24480,
+ QUEST_HALLS_OF_REFLECTION_HORDE = 24561
};
enum InstanceWorldStates
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
index ea2a1539f1c..660a639487f 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
@@ -73,6 +73,8 @@ Position const SpawnPos[] =
{ 5299.250f, 2035.998f, 707.7781f, 5.026548f }
};
+Position const UtherQuelDalarPos = { 5302.001f, 1988.698f, 707.7781f, 3.700098f };
+
class instance_halls_of_reflection : public InstanceMapScript
{
public:
@@ -89,6 +91,7 @@ class instance_halls_of_reflection : public InstanceMapScript
_waveCount = 0;
_introState = NOT_STARTED;
_frostswornGeneralState = NOT_STARTED;
+ _quelDelarState = NOT_STARTED;
events.Reset();
}
@@ -159,6 +162,9 @@ class instance_halls_of_reflection : public InstanceMapScript
case NPC_ICE_WALL_TARGET:
IcewallTargetGUID = creature->GetGUID();
break;
+ case NPC_UTHER:
+ UtherGUID = creature->GetGUID();
+ break;
default:
break;
}
@@ -439,6 +445,18 @@ class instance_halls_of_reflection : public InstanceMapScript
HandleGameObject(ShadowThroneDoorGUID, true);
_frostswornGeneralState = data;
break;
+ case DATA_QUEL_DELAR_EVENT:
+ if (data == IN_PROGRESS)
+ {
+ if (_quelDelarState == NOT_STARTED)
+ {
+ if (Creature* bunny = instance->GetCreature(FrostmourneAltarBunnyGUID))
+ bunny->CastSpell((Unit*)NULL, SPELL_ESSENCE_OF_CAPTURED);
+ events.ScheduleEvent(EVENT_QUEL_DELAR_SUMMON_UTHER, 2000);
+ }
+ }
+ _quelDelarState = data;
+ break;
default:
break;
}
@@ -446,6 +464,18 @@ class instance_halls_of_reflection : public InstanceMapScript
SaveToDB();
}
+ void SetGuidData(uint32 type, ObjectGuid data) override
+ {
+ switch (type)
+ {
+ case DATA_QUEL_DELAR_INVOKER:
+ QuelDelarInvokerGUID = data;
+ break;
+ default:
+ break;
+ }
+ }
+
// wave scheduling, checked when wave npcs die
void OnUnitDeath(Unit* unit) override
{
@@ -491,6 +521,9 @@ class instance_halls_of_reflection : public InstanceMapScript
case EVENT_SPAWN_ESCAPE_EVENT:
SpawnEscapeEvent();
break;
+ case EVENT_QUEL_DELAR_SUMMON_UTHER:
+ instance->SummonCreature(NPC_UTHER, UtherQuelDalarPos);
+ break;
}
}
@@ -649,6 +682,8 @@ class instance_halls_of_reflection : public InstanceMapScript
return _introState;
case DATA_FROSTSWORN_GENERAL:
return _frostswornGeneralState;
+ case DATA_QUEL_DELAR_EVENT:
+ return _quelDelarState;
default:
break;
}
@@ -682,6 +717,12 @@ class instance_halls_of_reflection : public InstanceMapScript
return IcewallGUID;
case DATA_ICEWALL_TARGET:
return IcewallTargetGUID;
+ case DATA_FROSTMOURNE_ALTAR_BUNNY:
+ return FrostmourneAltarBunnyGUID;
+ case DATA_UTHER_QUEL_DELAR:
+ return UtherGUID;
+ case DATA_QUEL_DELAR_INVOKER:
+ return QuelDelarInvokerGUID;
default:
break;
}
@@ -691,7 +732,7 @@ class instance_halls_of_reflection : public InstanceMapScript
void WriteSaveDataMore(std::ostringstream& data) override
{
- data << _introState << ' ' << _frostswornGeneralState;
+ data << _introState << ' ' << _frostswornGeneralState << ' ' << _quelDelarState;
}
void ReadSaveDataMore(std::istringstream& data) override
@@ -708,6 +749,12 @@ class instance_halls_of_reflection : public InstanceMapScript
SetData(DATA_FROSTSWORN_GENERAL, DONE);
else
SetData(DATA_FROSTSWORN_GENERAL, NOT_STARTED);
+
+ data >> temp;
+ if (temp == DONE)
+ SetData(DATA_QUEL_DELAR_EVENT, DONE);
+ else
+ SetData(DATA_QUEL_DELAR_EVENT, NOT_STARTED);
}
private:
@@ -731,6 +778,7 @@ class instance_halls_of_reflection : public InstanceMapScript
uint32 _waveCount;
uint32 _introState;
uint32 _frostswornGeneralState;
+ uint32 _quelDelarState;
EventMap events;
GuidSet waveGuidList[8];
@@ -740,6 +788,8 @@ class instance_halls_of_reflection : public InstanceMapScript
ObjectGuid CaptainGUID;
ObjectGuid IcewallGUID;
ObjectGuid IcewallTargetGUID;
+ ObjectGuid QuelDelarInvokerGUID;
+ ObjectGuid UtherGUID;
GuidSet GunshipCannonGUIDs;
GuidSet GunshipStairGUIDs;
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
index 4c6fd0f2fcc..63082808e03 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
@@ -1259,7 +1259,7 @@ class spell_putricide_mutated_plague : public SpellScriptLoader
return;
uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell;
- SpellInfo const* spell = sSpellMgr->GetSpellInfo(triggerSpell);
+ SpellInfo const* spell = sSpellMgr->EnsureSpellInfo(triggerSpell);
spell = sSpellMgr->GetSpellForDifficultyFromSpell(spell, caster);
int32 damage = spell->Effects[EFFECT_0].CalcValue(caster);
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
index 4d7b9ec42b4..d56a3f80f75 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
@@ -18,7 +18,7 @@
#include "ObjectMgr.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
-#include "SpellAuras.h"
+#include "SpellAuraEffects.h"
#include "GridNotifiers.h"
#include "icecrown_citadel.h"
@@ -213,7 +213,7 @@ class boss_rotface : public CreatureScript
}
break;
case EVENT_MUTATED_INFECTION:
- me->CastCustomSpell(SPELL_MUTATED_INFECTION, SPELLVALUE_MAX_TARGETS, 1, NULL, false);
+ DoCastAOE(SPELL_MUTATED_INFECTION);
events.ScheduleEvent(EVENT_MUTATED_INFECTION, infectionCooldown);
break;
case EVENT_VILE_GAS:
@@ -509,13 +509,6 @@ class spell_rotface_mutated_infection : public SpellScriptLoader
{
PrepareSpellScript(spell_rotface_mutated_infection_SpellScript);
- public:
- spell_rotface_mutated_infection_SpellScript()
- {
- _target = nullptr;
- }
-
- private:
void FilterTargets(std::list<WorldObject*>& targets)
{
// remove targets with this aura already
@@ -527,14 +520,6 @@ class spell_rotface_mutated_infection : public SpellScriptLoader
WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets);
targets.clear();
targets.push_back(target);
- _target = target;
- }
-
- void ReplaceTargets(std::list<WorldObject*>& targets)
- {
- targets.clear();
- if (_target)
- targets.push_back(_target);
}
void NotifyTargets()
@@ -546,19 +531,43 @@ class spell_rotface_mutated_infection : public SpellScriptLoader
void Register() override
{
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rotface_mutated_infection_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rotface_mutated_infection_SpellScript::ReplaceTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY);
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rotface_mutated_infection_SpellScript::ReplaceTargets, EFFECT_2, TARGET_UNIT_SRC_AREA_ENEMY);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rotface_mutated_infection_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
AfterHit += SpellHitFn(spell_rotface_mutated_infection_SpellScript::NotifyTargets);
}
+ };
+
+ class spell_rotface_mutated_infection_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_rotface_mutated_infection_AuraScript);
- WorldObject* _target;
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ if (!sSpellMgr->GetSpellInfo(uint32(spellInfo->Effects[EFFECT_2].CalcValue())))
+ return false;
+ return true;
+ }
+
+ void HandleEffectRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ target->CastSpell(target, uint32(GetSpellInfo()->Effects[EFFECT_2].CalcValue()), true, nullptr, aurEff, GetCasterGUID());
+ }
+
+ void Register() override
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_rotface_mutated_infection_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL);
+ }
};
SpellScript* GetSpellScript() const override
{
return new spell_rotface_mutated_infection_SpellScript();
}
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_rotface_mutated_infection_AuraScript();
+ }
};
class spell_rotface_little_ooze_combine : public SpellScriptLoader
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
index ae0e00cb849..07816ebbe39 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
@@ -2417,6 +2417,7 @@ class spell_the_lich_king_defile : public SpellScriptLoader
void CorrectRange(std::list<WorldObject*>& targets)
{
targets.remove_if(ExactDistanceCheck(GetCaster(), 10.0f * GetCaster()->GetObjectScale()));
+ targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_HARVEST_SOUL_VALKYR));
}
void ChangeDamageAndGrow()
diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
index 43069f10464..6c3b2187325 100644
--- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
+++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
@@ -520,11 +520,7 @@ public:
_despawned = false;
break;
case ACTION_CYCLIC_MOVEMENT:
- Movement::MoveSplineInit init(me);
- FillCirclePath(MalygosPositions[3], 120.0f, 283.2763f, init.Path(), true);
- init.SetFly();
- init.SetCyclic();
- init.Launch();
+ me->GetMotionMaster()->MoveCirclePath(MalygosPositions[3].GetPositionX(), MalygosPositions[3].GetPositionY(), 283.2763f, 120.0f, true, 16);
break;
}
}
@@ -1020,22 +1016,6 @@ public:
}
private:
- // Used to generate perfect cyclic movements (Enter Circle).
- void FillCirclePath(Position const& centerPos, float radius, float z, Movement::PointsArray& path, bool clockwise)
- {
- float step = clockwise ? float(-M_PI) / 8.0f : float(M_PI) / 8.0f;
- float angle = centerPos.GetAngle(me->GetPositionX(), me->GetPositionY());
-
- for (uint8 i = 0; i < 16; angle += step, ++i)
- {
- G3D::Vector3 point;
- point.x = centerPos.GetPositionX() + radius * cosf(angle);
- point.y = centerPos.GetPositionY() + radius * sinf(angle);
- point.z = z; // Don't use any height getters unless all bugs are fixed.
- path.push_back(point);
- }
- }
-
uint8 _phase; // Counter for phases used with a getter.
uint8 _summonDeaths; // Keeps count of arcane trash.
uint8 _preparingPulsesChecker; // In retail they use 2 preparing pulses with 7 sec CD, after they pass 2 seconds.
@@ -1326,11 +1306,7 @@ public:
{
if (action < ACTION_DELAYED_DESPAWN)
{
- Movement::MoveSplineInit init(me);
- FillCirclePath(MalygosPositions[3], 35.0f, 282.3402f, init.Path(), true);
- init.SetFly();
- init.SetCyclic();
- init.Launch();
+ me->GetMotionMaster()->MoveCirclePath(MalygosPositions[3].GetPositionX(), MalygosPositions[3].GetPositionY(), 282.3402f, 35.0f, true, 16);
}
else
{
@@ -1339,21 +1315,6 @@ public:
}
private:
- void FillCirclePath(Position const& centerPos, float radius, float z, Movement::PointsArray& path, bool clockwise)
- {
- float step = clockwise ? float(-M_PI) / 9.0f : float(M_PI) / 9.0f;
- float angle = centerPos.GetAngle(me->GetPositionX(), me->GetPositionY());
-
- for (uint8 i = 0; i < 18; angle += step, ++i)
- {
- G3D::Vector3 point;
- point.x = centerPos.GetPositionX() + radius * cosf(angle);
- point.y = centerPos.GetPositionY() + radius * sinf(angle);
- point.z = z; // Don't use any height getters unless all bugs are fixed.
- path.push_back(point);
- }
- }
-
InstanceScript* _instance;
};
diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_kolurg.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_kolurg.cpp
deleted file mode 100644
index fc56f541a4b..00000000000
--- a/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_kolurg.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* Script Data Start
-SDName: Boss Commander Kolurg
-SDAuthor: LordVanMartin
-SD%Complete:
-SDComment: Only Alliance Heroic
-SDCategory:
-Script Data End */
-
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-
-enum Spells
-{
- SPELL_BATTLE_SHOUT = 31403,
- SPELL_CHARGE = 60067,
- SPELL_FRIGHTENING_SHOUT = 19134,
- SPELL_WHIRLWIND_1 = 38619,
- SPELL_WHIRLWIND_2 = 38618
-
-};
-
-//not used
-//Yell
-#define SAY_AGGRO -1576024
-#define SAY_KILL -1576025
-#define SAY_DEATH -1576026
-
-class boss_commander_kolurg : public CreatureScript
-{
-public:
- boss_commander_kolurg() : CreatureScript("boss_commander_kolurg") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new boss_commander_kolurgAI(creature);
- }
-
- struct boss_commander_kolurgAI : public ScriptedAI
- {
- boss_commander_kolurgAI(Creature* creature) : ScriptedAI(creature) { }
-
- void Reset() override { }
- void EnterCombat(Unit* /*who*/) override { }
- void AttackStart(Unit* /*who*/) override { }
- void MoveInLineOfSight(Unit* /*who*/) override { }
-
- void UpdateAI(uint32 /*diff*/) override
- {
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- DoMeleeAttackIfReady();
- }
- void JustDied(Unit* /*killer*/) override { }
- };
-
-};
-
-void AddSC_boss_commander_kolurg()
-{
- new boss_commander_kolurg();
-}
diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_stoutbeard.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_stoutbeard.cpp
deleted file mode 100644
index ff08038d898..00000000000
--- a/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_stoutbeard.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* Script Data Start
-SDName: Boss Commander Stoutbeard
-SDAuthor: LordVanMartin
-SD%Complete:
-SDComment: Only Horde Heroic
-SDCategory:
-Script Data End */
-
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-
-enum CommanderStoutbeard
-{
- SPELL_BATTLE_SHOUT = 31403,
- SPELL_CHARGE = 60067,
- SPELL_FRIGHTENING_SHOUT = 19134,
- SPELL_WHIRLWIND_1 = 38619,
- SPELL_WHIRLWIND_2 = 38618
-};
-
-
-class boss_commander_stoutbeard : public CreatureScript
-{
-public:
- boss_commander_stoutbeard() : CreatureScript("boss_commander_stoutbeard") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new boss_commander_stoutbeardAI(creature);
- }
-
- struct boss_commander_stoutbeardAI : public ScriptedAI
- {
- boss_commander_stoutbeardAI(Creature* creature) : ScriptedAI(creature) { }
-
- void Reset() override { }
- void AttackStart(Unit* /*who*/) override { }
- void MoveInLineOfSight(Unit* /*who*/) override { }
-
- void UpdateAI(uint32 /*diff*/) override
- {
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- DoMeleeAttackIfReady();
- }
- };
-
-};
-
-void AddSC_boss_commander_stoutbeard()
-{
- new boss_commander_stoutbeard();
-}
diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_nexus_commanders.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_nexus_commanders.cpp
new file mode 100644
index 00000000000..d40f9fecc6a
--- /dev/null
+++ b/src/server/scripts/Northrend/Nexus/Nexus/boss_nexus_commanders.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "nexus.h"
+
+enum Spells
+{
+ SPELL_BATTLE_SHOUT = 31403,
+ SPELL_CHARGE = 60067,
+ SPELL_FRIGHTENING_SHOUT = 19134,
+ SPELL_WHIRLWIND = 38618,
+ SPELL_FROZEN_PRISON = 47543
+};
+
+enum Yells
+{
+ SAY_AGGRO = 0,
+ SAY_KILL = 1,
+ SAY_DEATH = 2
+};
+
+enum Events
+{
+ EVENT_CHARGE_COMMANDER = 1,
+ EVENT_WHIRLWIND,
+ EVENT_FRIGHTENING_SHOUT
+};
+
+class boss_nexus_commanders : public CreatureScript
+{
+ public:
+ boss_nexus_commanders() : CreatureScript("boss_nexus_commanders") { }
+
+ struct boss_nexus_commandersAI : public BossAI
+ {
+ boss_nexus_commandersAI(Creature* creature) : BossAI(creature, DATA_COMMANDER) { }
+
+ void EnterCombat(Unit* /*who*/) override
+ {
+ _EnterCombat();
+ Talk(SAY_AGGRO);
+ me->RemoveAurasDueToSpell(SPELL_FROZEN_PRISON);
+ DoCast(me, SPELL_BATTLE_SHOUT);
+
+ events.ScheduleEvent(EVENT_CHARGE_COMMANDER, urand(3000, 4000));
+ events.ScheduleEvent(EVENT_WHIRLWIND, urand(6000, 8000));
+ events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, urand(13000, 15000));
+ }
+
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_CHARGE_COMMANDER:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_CHARGE);
+ events.ScheduleEvent(EVENT_CHARGE_COMMANDER, urand(11000, 15000));
+ break;
+ case EVENT_WHIRLWIND:
+ DoCast(me, SPELL_WHIRLWIND);
+ events.ScheduleEvent(EVENT_WHIRLWIND, urand(19500, 25000));
+ break;
+ case EVENT_FRIGHTENING_SHOUT:
+ DoCastAOE(SPELL_FRIGHTENING_SHOUT);
+ events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, urand(45000, 55000));
+ break;
+ default:
+ break;
+ }
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ Talk(SAY_DEATH);
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_KILL);
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_nexus_commandersAI>(creature);
+ }
+};
+
+void AddSC_boss_nexus_commanders()
+{
+ new boss_nexus_commanders();
+}
diff --git a/src/server/scripts/Northrend/Nexus/Nexus/nexus.h b/src/server/scripts/Northrend/Nexus/Nexus/nexus.h
index 90866ea83f8..c48c7323301 100644
--- a/src/server/scripts/Northrend/Nexus/Nexus/nexus.h
+++ b/src/server/scripts/Northrend/Nexus/Nexus/nexus.h
@@ -21,32 +21,33 @@
#define NexusScriptName "instance_nexus"
#define DataHeader "NEX"
-uint32 const EncounterCount = 4;
+uint32 const EncounterCount = 5;
enum DataTypes
{
- DATA_MAGUS_TELESTRA = 0,
- DATA_ANOMALUS = 1,
- DATA_ORMOROK = 2,
- DATA_KERISTRASZA = 3,
+ DATA_COMMANDER = 0,
+ DATA_MAGUS_TELESTRA = 1,
+ DATA_ANOMALUS = 2,
+ DATA_ORMOROK = 3,
+ DATA_KERISTRASZA = 4,
- ANOMALUS_CONTAINMET_SPHERE = 4,
- ORMOROKS_CONTAINMET_SPHERE = 5,
- TELESTRAS_CONTAINMET_SPHERE = 6
+ ANOMALUS_CONTAINMET_SPHERE = 5,
+ ORMOROKS_CONTAINMET_SPHERE = 6,
+ TELESTRAS_CONTAINMET_SPHERE = 7
};
enum CreatureIds
{
NPC_ANOMALUS = 26763,
NPC_KERISTRASZA = 26723,
-
+
// Alliance
NPC_ALLIANCE_BERSERKER = 26800,
NPC_ALLIANCE_RANGER = 26802,
NPC_ALLIANCE_CLERIC = 26805,
NPC_ALLIANCE_COMMANDER = 27949,
NPC_COMMANDER_STOUTBEARD = 26796,
-
+
// Horde
NPC_HORDE_BERSERKER = 26799,
NPC_HORDE_RANGER = 26801,
@@ -59,7 +60,7 @@ enum GameObjectIds
{
GO_ANOMALUS_CONTAINMET_SPHERE = 188527,
GO_ORMOROKS_CONTAINMET_SPHERE = 188528,
- GO_TELESTRAS_CONTAINMET_SPHERE = 188526
+ GO_TELESTRAS_CONTAINMET_SPHERE = 188526
};
#endif
diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp
index 7bc8a5300f4..536cae08483 100644
--- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp
+++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp
@@ -29,7 +29,7 @@ EndScriptData */
#include "Player.h"
#include "SpellInfo.h"
-enum Enums
+enum Texts
{
SAY_AGGRO = 0,
SAY_FORGE = 1,
@@ -38,29 +38,50 @@ enum Enums
SAY_DEATH = 4,
EMOTE_TO_ANVIL = 5,
EMOTE_SHATTER = 6,
+};
+enum Spells
+{
SPELL_HEAT = 52387,
SPELL_SHATTERING_STOMP = 52237,
-
SPELL_TEMPER = 52238,
SPELL_TEMPER_DUMMY = 52654,
-
SPELL_SUMMON_MOLTEN_GOLEM = 52405,
+ SPELL_FORGE_VISUAL = 52654,
// Molten Golem
SPELL_BLAST_WAVE = 23113,
SPELL_IMMOLATION_STRIKE = 52433,
SPELL_SHATTER = 52429,
+};
+enum Events
+{
+ EVENT_PAUSE = 1,
+ EVENT_SHATTERING_STOMP = 2,
+ EVENT_SHATTER = 3,
+ EVENT_FORGE_CAST = 4,
+
+ // Molten Golem
+ EVENT_BLAST = 5,
+ EVENT_IMMOLATION = 6
+};
+
+enum Npcs
+{
NPC_VOLKHAN_ANVIL = 28823,
NPC_MOLTEN_GOLEM = 28695,
NPC_BRITTLE_GOLEM = 28681,
-
MAX_GOLEM = 2,
-
DATA_SHATTER_RESISTANT = 2042
};
+enum Phases
+{
+ PHASE_INTRO = 1,
+ PHASE_NORMAL
+};
+
/*######
## Boss Volkhan
######*/
@@ -68,68 +89,44 @@ class boss_volkhan : public CreatureScript
{
public:
boss_volkhan() : CreatureScript("boss_volkhan") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_volkhanAI>(creature);
- }
-
- struct boss_volkhanAI : public ScriptedAI
+
+ struct boss_volkhanAI : public BossAI
{
- boss_volkhanAI(Creature* creature) : ScriptedAI(creature)
+ boss_volkhanAI(Creature* creature) : BossAI(creature, DATA_VOLKHAN)
{
Initialize();
- instance = creature->GetInstanceScript();
}
void Initialize()
{
- m_bIsStriking = false;
- m_bHasTemper = false;
+ m_bIsStriking = false;
+ m_bHasTemper = false;
m_bCanShatterGolem = false;
-
- m_uiPause_Timer = 3500;
- m_uiShatteringStomp_Timer = 0;
- m_uiShatter_Timer = 5000;
- m_uiDelay_Timer = 1000;
- m_uiSummonPhase = 0;
- GolemsShattered = 0;
+ m_uiDelay_Timer = 1000;
+ m_uiSummonPhase = 0;
+ GolemsShattered = 0;
m_uiHealthAmountModifier = 1;
}
- InstanceScript* instance;
-
- GuidList m_lGolemGUIDList;
-
- bool m_bHasTemper;
- bool m_bIsStriking;
- bool m_bCanShatterGolem;
-
- uint8 GolemsShattered;
- uint32 m_uiPause_Timer;
- uint32 m_uiShatteringStomp_Timer;
- uint32 m_uiShatter_Timer;
- uint32 m_uiDelay_Timer;
- uint32 m_uiSummonPhase;
-
- uint32 m_uiHealthAmountModifier;
-
void Reset() override
{
Initialize();
-
+ _Reset();
DespawnGolem();
m_lGolemGUIDList.clear();
-
- instance->SetBossState(DATA_VOLKHAN, NOT_STARTED);
+ events.SetPhase(PHASE_INTRO);
+ events.ScheduleEvent(EVENT_FORGE_CAST, 2 * IN_MILLISECONDS, 0, PHASE_INTRO);
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
-
- instance->SetBossState(DATA_VOLKHAN, IN_PROGRESS);
+ events.SetPhase(PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_PAUSE, 3.5 * IN_MILLISECONDS, 0, PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_SHATTERING_STOMP, 0 * IN_MILLISECONDS, 0, PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_SHATTER, 5 * IN_MILLISECONDS, 0, PHASE_NORMAL);
+ _EnterCombat();
}
void AttackStart(Unit* who) override
@@ -150,7 +147,7 @@ public:
Talk(SAY_DEATH);
DespawnGolem();
- instance->SetBossState(DATA_VOLKHAN, DONE);
+ _JustDied();
}
void KilledUnit(Unit* who) override
@@ -224,59 +221,61 @@ public:
return 0;
}
- void UpdateAI(uint32 uiDiff) override
+ void UpdateAI(uint32 diff) override
{
- if (!UpdateVictim())
+ // Return since we have no target and are in CombatPhase
+ if (events.IsInPhase(PHASE_NORMAL) && !UpdateVictim())
return;
- if (m_bIsStriking)
- {
- if (m_uiPause_Timer <= uiDiff)
- {
- if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE)
- if (me->GetVictim())
- me->GetMotionMaster()->MoveChase(me->GetVictim());
-
- m_bHasTemper = false;
- m_bIsStriking = false;
- m_uiPause_Timer = 3500;
- }
- else
- m_uiPause_Timer -= uiDiff;
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
return;
- }
- // When to start shatter? After 60, 40 or 20% hp?
- if (!m_bHasTemper && m_uiHealthAmountModifier >= 3)
+ while (uint32 eventId = events.ExecuteEvent())
{
- if (m_uiShatteringStomp_Timer <= uiDiff)
+ switch (eventId)
{
- // Should he stomp even if he has no brittle golem to shatter?
- Talk(SAY_STOMP);
-
- DoCast(me, SPELL_SHATTERING_STOMP);
+ case EVENT_PAUSE:
+ if (m_bIsStriking)
+ {
+ if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE)
+ if (me->GetVictim())
+ me->GetMotionMaster()->MoveChase(me->GetVictim());
- Talk(EMOTE_SHATTER);
+ m_bHasTemper = false;
+ m_bIsStriking = false;
+ events.ScheduleEvent(EVENT_PAUSE, 3.5 * IN_MILLISECONDS, 0, PHASE_NORMAL);
+ }
+ break;
+ case EVENT_SHATTERING_STOMP:
+ if (!m_bHasTemper && m_uiHealthAmountModifier >= 3)
+ {
+ // Should he stomp even if he has no brittle golem to shatter?
+ Talk(SAY_STOMP);
- m_uiShatteringStomp_Timer = 30000;
- m_bCanShatterGolem = true;
- }
- else
- m_uiShatteringStomp_Timer -= uiDiff;
- }
+ DoCast(me, SPELL_SHATTERING_STOMP);
- // Shatter Golems 3 seconds after Shattering Stomp
- if (m_bCanShatterGolem)
- {
- if (m_uiShatter_Timer <= uiDiff)
- {
- ShatterGolem();
- m_uiShatter_Timer = 3000;
- m_bCanShatterGolem = false;
+ Talk(EMOTE_SHATTER);
+ events.ScheduleEvent(EVENT_SHATTERING_STOMP, 30 * IN_MILLISECONDS, 0, PHASE_NORMAL);
+ m_bCanShatterGolem = true;
+ }
+ break;
+ case EVENT_SHATTER:
+ if (m_bCanShatterGolem)
+ {
+ ShatterGolem();
+ events.ScheduleEvent(EVENT_SHATTER, 3 * IN_MILLISECONDS, 0, PHASE_NORMAL);
+ m_bCanShatterGolem = false;
+ }
+ break;
+ case EVENT_FORGE_CAST:
+ DoCast(me, SPELL_FORGE_VISUAL);
+ events.ScheduleEvent(EVENT_FORGE_CAST, 15 * IN_MILLISECONDS, 0, PHASE_INTRO);
+ break;
+ default:
+ break;
}
- else
- m_uiShatter_Timer -= uiDiff;
}
// Health check
@@ -302,12 +301,10 @@ public:
me->GetMotionMaster()->MoveTargetedHome();
m_uiSummonPhase = 2; // Set Next Phase
break;
-
case 2:
// 2 - Check if reached Anvil
// This is handled in: void JustReachedHome() override
break;
-
case 3:
// 3 - Cast Temper on the Anvil
if (Unit* target = GetClosestCreatureWithEntry(me, NPC_VOLKHAN_ANVIL, 1000.0f, true))
@@ -319,10 +316,9 @@ public:
m_uiDelay_Timer = 1000; // Delay 2 seconds before next phase can begin
m_uiSummonPhase = 4; // Set Next Phase
break;
-
case 4:
// 4 - Wait for delay to expire
- if (m_uiDelay_Timer <= uiDiff)
+ if (m_uiDelay_Timer <= diff)
{
if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 0))
{
@@ -333,9 +329,8 @@ public:
m_uiSummonPhase = 5;
}
else
- m_uiDelay_Timer -= uiDiff;
+ m_uiDelay_Timer -= diff;
break;
-
case 5:
// 5 - Spawn the Golems
if (Creature* creatureTarget = GetClosestCreatureWithEntry(me, NPC_VOLKHAN_ANVIL, 1000.0f, true))
@@ -349,13 +344,30 @@ public:
DoMeleeAttackIfReady();
}
+
+ private:
+ GuidList m_lGolemGUIDList;
+ uint32 m_uiHealthAmountModifier;
+ uint8 GolemsShattered;
+ uint32 m_uiDelay_Timer;
+ uint32 m_uiSummonPhase;
+
+ bool m_bHasTemper;
+ bool m_bIsStriking;
+ bool m_bCanShatterGolem;
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_volkhanAI>(creature);
+ }
+
};
/*######
## npc_molten_golem
######*/
+
class npc_molten_golem : public CreatureScript
{
public:
@@ -376,18 +388,12 @@ public:
void Initialize()
{
m_bIsFrozen = false;
-
- m_uiBlast_Timer = 20000;
- m_uiDeathDelay_Timer = 0;
- m_uiImmolation_Timer = 5000;
+ events.ScheduleEvent(EVENT_BLAST, 20 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_IMMOLATION, 5 * IN_MILLISECONDS);
}
bool m_bIsFrozen;
- uint32 m_uiBlast_Timer;
- uint32 m_uiDeathDelay_Timer;
- uint32 m_uiImmolation_Timer;
-
void Reset() override
{
Initialize();
@@ -433,30 +439,39 @@ public:
me->DespawnOrUnsummon();
}
- void UpdateAI(uint32 uiDiff) override
+ void UpdateAI(uint32 diff) override
{
// Return since we have no target or if we are frozen
if (!UpdateVictim() || m_bIsFrozen)
return;
- if (m_uiBlast_Timer <= uiDiff)
- {
- DoCast(me, SPELL_BLAST_WAVE);
- m_uiBlast_Timer = 20000;
- }
- else
- m_uiBlast_Timer -= uiDiff;
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- if (m_uiImmolation_Timer <= uiDiff)
+ while (uint32 eventId = events.ExecuteEvent())
{
- DoCastVictim(SPELL_IMMOLATION_STRIKE);
- m_uiImmolation_Timer = 5000;
+ switch (eventId)
+ {
+ case EVENT_BLAST:
+ DoCast(me, SPELL_BLAST_WAVE);
+ events.ScheduleEvent(EVENT_BLAST, 20 * IN_MILLISECONDS);
+ break;
+ case EVENT_IMMOLATION:
+ DoCastVictim(SPELL_IMMOLATION_STRIKE);
+ events.ScheduleEvent(EVENT_BLAST, 5 * IN_MILLISECONDS);
+ break;
+ default:
+ break;
+ }
}
- else
- m_uiImmolation_Timer -= uiDiff;
DoMeleeAttackIfReady();
}
+
+ private:
+ EventMap events;
};
};
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
index a682e405d08..a7a9f8dde88 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
@@ -1126,30 +1126,11 @@ class npc_ominous_cloud : public CreatureScript
DoCast(me, SPELL_OMINOUS_CLOUD_VISUAL);
}
- void FillCirclePath(Position const& centerPos, float radius, float z, Movement::PointsArray& path, bool clockwise)
- {
- float step = clockwise ? float(-M_PI) / 8.0f : float(M_PI) / 8.0f;
- float angle = centerPos.GetAngle(me->GetPositionX(), me->GetPositionY());
-
- for (uint8 i = 0; i < 16; angle += step, ++i)
- {
- G3D::Vector3 point;
- point.x = centerPos.GetPositionX() + radius * cosf(angle);
- point.y = centerPos.GetPositionY() + radius * sinf(angle);
- point.z = me->GetMap()->GetHeight(me->GetPhaseMask(), point.x, point.y, z + 5.0f);
- path.push_back(point);
- }
- }
-
void UpdateAI(uint32 /*diff*/) override { }
void DoAction(int32 action) override
{
- Movement::MoveSplineInit init(me);
- FillCirclePath(YoggSaronSpawnPos, me->GetDistance2d(YoggSaronSpawnPos.GetPositionX(), YoggSaronSpawnPos.GetPositionY()), me->GetPositionZ(), init.Path(), action != 0);
- init.SetWalk(true);
- init.SetCyclic();
- init.Launch();
+ me->GetMotionMaster()->MoveCirclePath(YoggSaronSpawnPos.GetPositionX(), YoggSaronSpawnPos.GetPositionY(), me->GetPositionZ() + 5.0f, me->GetDistance2d(YoggSaronSpawnPos.GetPositionX(), YoggSaronSpawnPos.GetPositionY()), true, 16);
}
};
diff --git a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp
index d1df244b733..90fd936e853 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp
@@ -26,9 +26,6 @@ enum Spells
SPELL_SUMMON_VOID_SENTRY = 54369,
SPELL_VOID_SHIFT = 54361,
H_SPELL_VOID_SHIFT = 59743,
-
- SPELL_ZURAMAT_ADD_2 = 54342,
- H_SPELL_ZURAMAT_ADD_2 = 59747
};
enum Creatures
@@ -192,12 +189,6 @@ public:
Talk(SAY_SLAY);
}
- void JustSummoned(Creature* summon) override
- {
- summon->AI()->AttackStart(me->GetVictim());
- summon->CastSpell((Unit*)NULL, SPELL_ZURAMAT_ADD_2);
- summon->SetPhaseMask(17, true);
- }
};
};
diff --git a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp
index 3e3ce5cde75..a462c68e084 100644
--- a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp
+++ b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp
@@ -133,6 +133,7 @@ public:
uiCyanigosaEventTimer = 3 * IN_MILLISECONDS;
bActive = false;
+ bWiped = false;
bIsDoorSpellCast = false;
bCrystalActivated = false;
defenseless = true;
diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp
index 9a577516126..4aea36e3fe7 100644
--- a/src/server/scripts/Northrend/zone_borean_tundra.cpp
+++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp
@@ -29,7 +29,6 @@ npc_corastrasza
npc_sinkhole_kill_credit
npc_khunok_the_behemoth
npc_nerubar_victim
-npc_keristrasza
npc_nesingwary_trapper
npc_lurgglbr
npc_nexus_drake_hatchling
@@ -223,48 +222,6 @@ public:
};
/*######
-## npc_keristrasza
-######*/
-
-enum Keristrasza
-{
- SPELL_TELEPORT_TO_SARAGOSA = 46772
-};
-
-#define GOSSIP_HELLO_KERI "I am prepared to face Saragosa!"
-
-class npc_keristrasza : public CreatureScript
-{
-public:
- npc_keristrasza() : CreatureScript("npc_keristrasza") { }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (creature->IsQuestGiver())
- player->PrepareQuestMenu(creature->GetGUID());
-
- if (player->GetQuestStatus(11957) == QUEST_STATUS_INCOMPLETE)
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_KERI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
-
- player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID());
-
- return true;
- }
-
- bool OnGossipSelect(Player* player, Creature* /*creature*/, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- if (action == GOSSIP_ACTION_INFO_DEF + 1)
- {
- player->CLOSE_GOSSIP_MENU();
- player->CastSpell(player, SPELL_TELEPORT_TO_SARAGOSA, true);
- }
-
- return true;
- }
-};
-
-/*######
## npc_corastrasza
######*/
@@ -438,6 +395,9 @@ enum NesingwaryTrapper
GO_CARIBOU_TRAP_15 = 188008,
SPELL_TRAPPED = 46104,
+
+ // Texts
+ SAY_NESINGWARY_1 = 0
};
#define CaribouTrapsNum 15
@@ -514,7 +474,7 @@ public:
phase = 3;
break;
case 3:
- //Talk(SAY_NESINGWARY_1);
+ Talk(SAY_NESINGWARY_1);
phaseTimer = 2000;
phase = 4;
break;
@@ -2488,7 +2448,6 @@ void AddSC_borean_tundra()
{
new npc_sinkhole_kill_credit();
new npc_khunok_the_behemoth();
- new npc_keristrasza();
new npc_corastrasza();
new npc_iruk();
new npc_nerubar_victim();
diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp
index bfdea4a1435..bb1e88ce158 100644
--- a/src/server/scripts/Northrend/zone_storm_peaks.cpp
+++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp
@@ -641,97 +641,6 @@ enum JokkumScriptcast
EVENT_KROLMIR_9 = 24,
};
-class npc_king_jokkum_vehicle : public CreatureScript
-{
-public:
- npc_king_jokkum_vehicle() : CreatureScript("npc_king_jokkum_vehicle") { }
-
- struct npc_king_jokkum_vehicleAI : public VehicleAI
- {
- npc_king_jokkum_vehicleAI(Creature* creature) : VehicleAI(creature)
- {
- pathEnd = false;
- }
-
- void Reset() override
- {
- playerGUID.Clear();
- pathEnd = false;
- }
-
- void OnCharmed(bool /*apply*/) override { }
-
- void PassengerBoarded(Unit* who, int8 /*seat*/, bool apply) override
- {
- if (apply)
- {
- playerGUID = who->GetGUID();
- Talk(SAY_HOLD_ON, who);
- me->CastSpell(who, SPELL_JOKKUM_KILL_CREDIT, true);
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
- me->GetMotionMaster()->MovePath(PATH_JOKKUM, false);
- }
- }
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type != WAYPOINT_MOTION_TYPE)
- return;
-
- if (pathEnd)
- {
- if (id == 4)
- {
-
- }
- }
- else
- {
- if (id == 19)
- {
- pathEnd = true;
- me->SetFacingTo(0.418879f);
- Talk(SAY_JOKKUM_1);
- if (Player* player = ObjectAccessor::GetPlayer(*me, playerGUID))
- me->CastSpell(player, SPELL_PLAYER_CAST_VERANUS_SUMMON);
- me->CastSpell(me, SPELL_EJECT_ALL_PASSENGERS);
-
- }
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!pathEnd)
- return;
-
- events.Update(diff);
-
- while (uint32 eventId = events.ExecuteEvent())
- {
- switch (eventId)
- {
- case EVENT_KROLMIR_1:
- Talk(SAY_JOKKUM_2);
- events.ScheduleEvent(EVENT_KROLMIR_2, 4000);
- break;
- }
- }
- }
-
- private:
- EventMap events;
- ObjectGuid playerGUID;
- bool pathEnd;
-
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_king_jokkum_vehicleAI(creature);
- }
-};
-
class spell_jokkum_scriptcast : public SpellScriptLoader
{
public: spell_jokkum_scriptcast() : SpellScriptLoader("spell_jokkum_scriptcast") { }
@@ -855,7 +764,6 @@ void AddSC_storm_peaks()
new npc_icefang();
new npc_hyldsmeet_protodrake();
new npc_brann_bronzebeard_keystone();
- new npc_king_jokkum_vehicle();
new spell_jokkum_scriptcast();
new spell_veranus_summon();
new spell_close_rift();
diff --git a/src/server/scripts/Northrend/zone_zuldrak.cpp b/src/server/scripts/Northrend/zone_zuldrak.cpp
index f73930181f0..91c796a6e69 100644
--- a/src/server/scripts/Northrend/zone_zuldrak.cpp
+++ b/src/server/scripts/Northrend/zone_zuldrak.cpp
@@ -313,7 +313,7 @@ public:
{
player->KilledMonsterCredit(gymerDummy->GetEntry(), gymerDummy->GetGUID());
gymerDummy->CastSpell(gymerDummy, SPELL_GYMER_LOCK_EXPLOSION, true);
- gymerDummy->DespawnOrUnsummon();
+ gymerDummy->DespawnOrUnsummon(4 * IN_MILLISECONDS);
}
}
return true;
diff --git a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp
index 728b164cc04..e4369f0348d 100644
--- a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp
+++ b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp
@@ -93,15 +93,12 @@ enum Factions
FACTION_COMBAT = 1868
};
-enum SetData
+enum Actions
{
- SETDATA_DATA = 1,
- SETDATA_RESET = 1,
- SETDATA_CHANNELER_DIED = 2,
- SETDATA_START_SPAWNING = 3,
- SETDATA_STOP_SPAWNING = 4,
- SETDATA_DESPAWN_ALL_SPAWNS = 5,
- SETDATA_START_ATTACK_AKAMA = 6
+ ACTION_CHANNELER_DIED = 1,
+ ACTION_START_SPAWNING = 2,
+ ACTION_STOP_SPAWNING = 3,
+ ACTION_DESPAWN_ALL_SPAWNS = 4,
};
enum Events
@@ -158,12 +155,11 @@ class boss_shade_of_akama : public CreatureScript
public:
boss_shade_of_akama() : CreatureScript("boss_shade_of_akama") { }
- struct boss_shade_of_akamaAI : public ScriptedAI
+ struct boss_shade_of_akamaAI : public BossAI
{
- boss_shade_of_akamaAI(Creature* creature) : ScriptedAI(creature)
+ boss_shade_of_akamaAI(Creature* creature) : BossAI(creature, DATA_SHADE_OF_AKAMA)
{
Initialize();
- instance = creature->GetInstanceScript();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
@@ -177,6 +173,7 @@ public:
void Reset() override
{
+ _Reset();
if (!HasKilledAkamaAndReseting)
{
for (GuidList::const_iterator itr = Channelers.begin(); itr != Channelers.end(); ++itr)
@@ -185,7 +182,7 @@ public:
for (GuidList::const_iterator itr = Spawners.begin(); itr != Spawners.end(); ++itr)
if (Creature* Spawner = ObjectAccessor::GetCreature(*me, *itr))
- Spawner->AI()->SetData(SETDATA_DATA, SETDATA_DESPAWN_ALL_SPAWNS);
+ Spawner->AI()->DoAction(ACTION_DESPAWN_ALL_SPAWNS);
events.ScheduleEvent(EVENT_FIND_CHANNELERS_SPAWNERS, 3000);
events.ScheduleEvent(EVENT_RESET_ENCOUNTER, 5000);
@@ -197,11 +194,6 @@ public:
Initialize();
}
- void JustDied(Unit* /*killer*/) override
- {
- instance->SetBossState(DATA_SHADE_OF_AKAMA, DONE);
- }
-
void EnterCombat(Unit* /*who*/) override { }
void AttackStart(Unit* who) override
@@ -216,9 +208,9 @@ public:
ScriptedAI::AttackStart(who);
}
- void SetData(uint32 data, uint32 value) override
+ void DoAction(int32 actionId) override
{
- if (data == SETDATA_DATA && value == SETDATA_CHANNELER_DIED)
+ if (actionId == ACTION_CHANNELER_DIED)
me->RemoveAuraFromStack(SPELL_SHADE_SOUL_CHANNEL_2);
UpdateSpeed();
@@ -314,7 +306,7 @@ public:
for (GuidList::const_iterator itr = Spawners.begin(); itr != Spawners.end(); ++itr)
if (Creature* Spawner = ObjectAccessor::GetCreature(*me, *itr))
- Spawner->AI()->SetData(SETDATA_DATA, SETDATA_START_SPAWNING);
+ Spawner->AI()->DoAction(ACTION_START_SPAWNING);
break;
}
case EVENT_START_ATTACK_AKAMA:
@@ -353,7 +345,7 @@ public:
for (GuidList::const_iterator itr = Spawners.begin(); itr != Spawners.end(); ++itr)
if (Creature* Spawner = ObjectAccessor::GetCreature(*me, *itr))
- Spawner->AI()->SetData(SETDATA_DATA, SETDATA_DESPAWN_ALL_SPAWNS);
+ Spawner->AI()->DoAction(ACTION_DESPAWN_ALL_SPAWNS);
events.ScheduleEvent(EVENT_FIND_CHANNELERS_SPAWNERS, 10000);
events.ScheduleEvent(EVENT_RESET_ENCOUNTER, 20000);
@@ -378,7 +370,7 @@ public:
for (GuidList::const_iterator itr = Spawners.begin(); itr != Spawners.end(); ++itr)
if (Creature* Spawner = ObjectAccessor::GetCreature(*me, *itr))
- Spawner->AI()->SetData(SETDATA_DATA, SETDATA_STOP_SPAWNING);
+ Spawner->AI()->DoAction(ACTION_STOP_SPAWNING);
}
}
}
@@ -390,8 +382,6 @@ public:
public:
bool HasKilledAkama;
private:
- InstanceScript* instance;
- EventMap events;
GuidList Channelers;
GuidList Spawners;
bool akamaReached;
@@ -433,9 +423,11 @@ public:
void Reset() override
{
me->setFaction(FACTION_FRIENDLY);
- me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
DoCast(me, SPELL_STEALTH);
Initialize();
+
+ if (instance->GetBossState(DATA_SHADE_OF_AKAMA) != DONE)
+ me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
}
void JustDied(Unit* /*killer*/) override
@@ -581,7 +573,7 @@ public:
void JustDied(Unit* /*killer*/) override
{
if (Creature* Shade = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_SHADE_OF_AKAMA)))
- Shade->AI()->SetData(SETDATA_DATA, SETDATA_CHANNELER_DIED);
+ Shade->AI()->DoAction(ACTION_CHANNELER_DIED);
}
void EnterCombat(Unit* /*who*/) override { }
@@ -603,7 +595,7 @@ public:
else
{
me->InterruptSpell(CURRENT_CHANNELED_SPELL);
- Shade->AI()->SetData(SETDATA_DATA, SETDATA_CHANNELER_DIED);
+ Shade->AI()->DoAction(ACTION_CHANNELER_DIED);
}
}
events.ScheduleEvent(EVENT_CHANNEL, 2000);
@@ -663,36 +655,33 @@ public:
Summons.Summon(summon);
}
- void SetData(uint32 data, uint32 value) override
+ void DoAction(int32 actionId) override
{
- if (data == SETDATA_DATA)
- {
- doSpawning = true;
+ doSpawning = true;
- switch (value)
- {
- case SETDATA_START_SPAWNING:
- if (leftSide)
- {
- events.ScheduleEvent(EVENT_SPAWN_WAVE_B, 100);
- events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_SORCERER, urand(2000, 5000));
- }
- else
- {
- events.ScheduleEvent(EVENT_SPAWN_WAVE_B, 10000);
- events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_DEFENDER, urand(2000, 5000));
- }
- break;
- case SETDATA_STOP_SPAWNING:
- doSpawning = false;
- break;
- case SETDATA_DESPAWN_ALL_SPAWNS:
- doSpawning = false;
- Summons.DespawnAll();
- break;
- default:
- break;
- }
+ switch (actionId)
+ {
+ case ACTION_START_SPAWNING:
+ if (leftSide)
+ {
+ events.ScheduleEvent(EVENT_SPAWN_WAVE_B, 100);
+ events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_SORCERER, urand(2000, 5000));
+ }
+ else
+ {
+ events.ScheduleEvent(EVENT_SPAWN_WAVE_B, 10000);
+ events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_DEFENDER, urand(2000, 5000));
+ }
+ break;
+ case ACTION_STOP_SPAWNING:
+ doSpawning = false;
+ break;
+ case ACTION_DESPAWN_ALL_SPAWNS:
+ doSpawning = false;
+ Summons.DespawnAll();
+ break;
+ default:
+ break;
}
}
@@ -778,23 +767,16 @@ public:
}
}
- summonerGuid.Clear();
Initialize();
}
void JustDied(Unit* /*killer*/) override
{
if (Creature* Shade = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_SHADE_OF_AKAMA)))
- Shade->AI()->SetData(SETDATA_DATA, SETDATA_CHANNELER_DIED);
+ Shade->AI()->DoAction(ACTION_CHANNELER_DIED);
me->DespawnOrUnsummon(5000);
}
- void IsSummonedBy(Unit* /*summoner*/) override
- {
- if (Creature* summoner = (ObjectAccessor::GetCreature((*me), summonerGuid)))
- ENSURE_AI(npc_creature_generator_akama::npc_creature_generator_akamaAI, summoner->AI())->JustSummoned(me);
- }
-
void EnterCombat(Unit* /*who*/) override { }
void AttackStart(Unit* who) override
@@ -824,7 +806,7 @@ public:
else
{
me->InterruptSpell(CURRENT_CHANNELED_SPELL);
- Shade->AI()->SetData(SETDATA_DATA, SETDATA_CHANNELER_DIED);
+ Shade->AI()->DoAction(ACTION_CHANNELER_DIED);
switchToCombat = true;
if (Unit* target = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE)))
AttackStart(target);
@@ -855,7 +837,6 @@ public:
private:
InstanceScript* instance;
EventMap events;
- ObjectGuid summonerGuid;
bool startedBanishing;
bool switchToCombat;
};
@@ -884,8 +865,6 @@ public:
void Reset() override
{
- summonerGuid.Clear();
-
if (Unit* target = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE)))
AttackStart(target);
}
@@ -895,12 +874,6 @@ public:
me->DespawnOrUnsummon(5000);
}
- void IsSummonedBy(Unit* /*summoner*/) override
- {
- if (Creature* summoner = (ObjectAccessor::GetCreature((*me), summonerGuid)))
- ENSURE_AI(npc_creature_generator_akama::npc_creature_generator_akamaAI, summoner->AI())->JustSummoned(me);
- }
-
void EnterCombat(Unit* /*who*/) override
{
events.ScheduleEvent(EVENT_HEROIC_STRIKE, 5000);
@@ -947,7 +920,6 @@ public:
private:
InstanceScript* instance;
EventMap events;
- ObjectGuid summonerGuid;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -974,8 +946,6 @@ public:
void Reset() override
{
- summonerGuid.Clear();
-
if (Unit* target = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE)))
AttackStart(target);
}
@@ -985,12 +955,6 @@ public:
me->DespawnOrUnsummon(5000);
}
- void IsSummonedBy(Unit* /*summoner*/) override
- {
- if (Creature* summoner = (ObjectAccessor::GetCreature((*me), summonerGuid)))
- ENSURE_AI(npc_creature_generator_akama::npc_creature_generator_akamaAI, summoner->AI())->JustSummoned(me);
- }
-
void EnterCombat(Unit* /*who*/) override
{
events.ScheduleEvent(EVENT_DEBILITATING_POISON, urand(500, 2000));
@@ -1027,7 +991,6 @@ public:
private:
InstanceScript* instance;
EventMap events;
- ObjectGuid summonerGuid;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -1054,8 +1017,6 @@ public:
void Reset() override
{
- summonerGuid.Clear();
-
if (Unit* target = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE)))
AttackStart(target);
}
@@ -1065,12 +1026,6 @@ public:
me->DespawnOrUnsummon(5000);
}
- void IsSummonedBy(Unit* /*summoner*/) override
- {
- if (Creature* summoner = (ObjectAccessor::GetCreature((*me), summonerGuid)))
- ENSURE_AI(npc_creature_generator_akama::npc_creature_generator_akamaAI, summoner->AI())->JustSummoned(me);
- }
-
void EnterCombat(Unit* /*who*/) override
{
events.ScheduleEvent(EVENT_RAIN_OF_FIRE, 18000);
@@ -1107,7 +1062,6 @@ public:
private:
InstanceScript* instance;
EventMap events;
- ObjectGuid summonerGuid;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -1137,7 +1091,6 @@ public:
{
spiritMend = false;
chainHeal = false;
- summonerGuid.Clear();
}
void Reset() override
@@ -1153,12 +1106,6 @@ public:
me->DespawnOrUnsummon(5000);
}
- void IsSummonedBy(Unit* /*summoner*/) override
- {
- if (Creature* summoner = (ObjectAccessor::GetCreature((*me), summonerGuid)))
- ENSURE_AI(npc_creature_generator_akama::npc_creature_generator_akamaAI, summoner->AI())->JustSummoned(me);
- }
-
void EnterCombat(Unit* /*who*/) override
{
events.ScheduleEvent(EVENT_SPIRIT_HEAL, urand (5000, 6000));
@@ -1208,7 +1155,6 @@ public:
private:
InstanceScript* instance;
EventMap events;
- ObjectGuid summonerGuid;
bool spiritMend;
bool chainHeal;
};
diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp
index 2407f3980de..9ffc151b3b9 100644
--- a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp
+++ b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp
@@ -338,6 +338,13 @@ class npc_warden_mellichar : public CreatureScript
IsRunning = true;
}
+ void JustSummoned(Creature* summon) override
+ {
+ DoZoneInCombat(summon);
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ summon->AI()->AttackStart(target);
+ }
+
bool CanProgress()
{
if (Phase == 7 && instance->GetData(DATA_WARDEN_4) == DONE)
diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp
index 50b77aac410..213f31b280f 100644
--- a/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp
+++ b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp
@@ -283,7 +283,10 @@ class boss_harbinger_skyriss_illusion : public CreatureScript
{
boss_harbinger_skyriss_illusionAI(Creature* creature) : ScriptedAI(creature) { }
- void Reset() override { }
+ void Reset() override
+ {
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ }
void EnterCombat(Unit* /*who*/) override { }
};
diff --git a/src/server/shared/CMakeLists.txt b/src/server/shared/CMakeLists.txt
index fb86ac7db18..5f319191c14 100644
--- a/src/server/shared/CMakeLists.txt
+++ b/src/server/shared/CMakeLists.txt
@@ -59,7 +59,7 @@ include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
${CMAKE_SOURCE_DIR}/dep/SFMT
- ${CMAKE_SOURCE_DIR}/dep/sockets/include
+ ${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/utf8cpp
${CMAKE_SOURCE_DIR}/src/server
${CMAKE_CURRENT_SOURCE_DIR}
diff --git a/src/server/shared/Cryptography/BigNumber.cpp b/src/server/shared/Cryptography/BigNumber.cpp
index 434268097fe..7b353eb5616 100644
--- a/src/server/shared/Cryptography/BigNumber.cpp
+++ b/src/server/shared/Cryptography/BigNumber.cpp
@@ -171,19 +171,20 @@ bool BigNumber::isZero() const
std::unique_ptr<uint8[]> BigNumber::AsByteArray(int32 minSize, bool littleEndian)
{
- int length = (minSize >= GetNumBytes()) ? minSize : GetNumBytes();
+ int numBytes = GetNumBytes();
+ int length = (minSize >= numBytes) ? minSize : numBytes;
uint8* array = new uint8[length];
// If we need more bytes than length of BigNumber set the rest to 0
- if (length > GetNumBytes())
+ if (length > numBytes)
memset((void*)array, 0, length);
BN_bn2bin(_bn, (unsigned char *)array);
// openssl's BN stores data internally in big endian format, reverse if little endian desired
if (littleEndian)
- std::reverse(array, array + length);
+ std::reverse(array, array + numBytes);
std::unique_ptr<uint8[]> ret(array);
return ret;
diff --git a/src/server/shared/DataStores/DBCStore.h b/src/server/shared/DataStores/DBCStore.h
index 10d4ff1bec9..1cb67a4235e 100644
--- a/src/server/shared/DataStores/DBCStore.h
+++ b/src/server/shared/DataStores/DBCStore.h
@@ -87,6 +87,13 @@ class DBCStorage
return (id >= nCount) ? NULL : indexTable.asT[id];
}
+ T const* AssertEntry(uint32 id) const
+ {
+ T const* entry = LookupEntry(id);
+ ASSERT(entry);
+ return entry;
+ }
+
uint32 GetNumRows() const { return nCount; }
char const* GetFormat() const { return fmt; }
uint32 GetFieldCount() const { return fieldCount; }
diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h
index 5a06ad69a1d..f0ddbe91ad8 100644
--- a/src/server/shared/Database/DatabaseWorkerPool.h
+++ b/src/server/shared/Database/DatabaseWorkerPool.h
@@ -29,6 +29,8 @@
#include "QueryHolder.h"
#include "AdhocStatement.h"
+#include <mysqld_error.h>
+
#define MIN_MYSQL_SERVER_VERSION 50100u
#define MIN_MYSQL_CLIENT_VERSION 50100u
@@ -368,7 +370,8 @@ class DatabaseWorkerPool
void DirectCommitTransaction(SQLTransaction& transaction)
{
T* con = GetFreeConnection();
- if (con->ExecuteTransaction(transaction))
+ int errorCode = con->ExecuteTransaction(transaction);
+ if (!errorCode)
{
con->Unlock(); // OK, operation succesful
return;
@@ -376,12 +379,12 @@ class DatabaseWorkerPool
//! Handle MySQL Errno 1213 without extending deadlock to the core itself
/// @todo More elegant way
- if (con->GetLastError() == 1213)
+ if (errorCode == ER_LOCK_DEADLOCK)
{
uint8 loopBreaker = 5;
for (uint8 i = 0; i < loopBreaker; ++i)
{
- if (con->ExecuteTransaction(transaction))
+ if (!con->ExecuteTransaction(transaction))
break;
}
}
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
index 265b0578841..c8632b8a3c2 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
@@ -60,7 +60,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_CHAR_POSITION_XYZ, "SELECT map, position_x, position_y, position_z FROM characters WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_POSITION, "SELECT position_x, position_y, position_z, orientation, map, taxi_path FROM characters WHERE guid = ?", CONNECTION_SYNCH);
- PrepareStatement(CHAR_DEL_BATTLEGROUND_RANDOM, "DELETE FROM character_battleground_random", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_BATTLEGROUND_RANDOM_ALL, "DELETE FROM character_battleground_random", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_BATTLEGROUND_RANDOM, "DELETE FROM character_battleground_random WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_BATTLEGROUND_RANDOM, "INSERT INTO character_battleground_random (guid) VALUES (?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER, "SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, "
@@ -300,6 +301,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_ARENA_TEAM_MEMBER, "DELETE FROM arena_team_member WHERE arenaTeamId = ? AND guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_ARENA_TEAM_STATS, "UPDATE arena_team SET rating = ?, weekGames = ?, weekWins = ?, seasonGames = ?, seasonWins = ?, rank = ? WHERE arenaTeamId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_ARENA_TEAM_MEMBER, "UPDATE arena_team_member SET personalRating = ?, weekGames = ?, weekWins = ?, seasonGames = ?, seasonWins = ? WHERE arenaTeamId = ? AND guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_CHARACTER_ARENA_STATS, "DELETE FROM character_arena_stats WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_REP_CHARACTER_ARENA_STATS, "REPLACE INTO character_arena_stats (guid, slot, matchMakerRating) VALUES (?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_PLAYER_ARENA_TEAMS, "SELECT arena_team_member.arenaTeamId FROM arena_team_member JOIN arena_team ON arena_team_member.arenaTeamId = arena_team.arenaTeamId WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_UPD_ARENA_TEAM_NAME, "UPDATE arena_team SET name = ? WHERE arenaTeamId = ?", CONNECTION_ASYNC);
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h
index f7ff5b9186e..e56a24d6865 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.h
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.h
@@ -72,6 +72,7 @@ enum CharacterDatabaseStatements
CHAR_SEL_CHAR_POSITION_XYZ,
CHAR_SEL_CHAR_POSITION,
+ CHAR_DEL_BATTLEGROUND_RANDOM_ALL,
CHAR_DEL_BATTLEGROUND_RANDOM,
CHAR_INS_BATTLEGROUND_RANDOM,
@@ -253,6 +254,7 @@ enum CharacterDatabaseStatements
CHAR_DEL_ARENA_TEAM_MEMBER,
CHAR_UPD_ARENA_TEAM_STATS,
CHAR_UPD_ARENA_TEAM_MEMBER,
+ CHAR_DEL_CHARACTER_ARENA_STATS,
CHAR_REP_CHARACTER_ARENA_STATS,
CHAR_SEL_PLAYER_ARENA_TEAMS,
CHAR_UPD_ARENA_TEAM_NAME,
diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp
index bea229df184..1a9f973d47b 100644
--- a/src/server/shared/Database/MySQLConnection.cpp
+++ b/src/server/shared/Database/MySQLConnection.cpp
@@ -359,11 +359,11 @@ void MySQLConnection::CommitTransaction()
Execute("COMMIT");
}
-bool MySQLConnection::ExecuteTransaction(SQLTransaction& transaction)
+int MySQLConnection::ExecuteTransaction(SQLTransaction& transaction)
{
std::list<SQLElementData> const& queries = transaction->m_queries;
if (queries.empty())
- return false;
+ return -1;
BeginTransaction();
@@ -380,8 +380,9 @@ bool MySQLConnection::ExecuteTransaction(SQLTransaction& transaction)
if (!Execute(stmt))
{
TC_LOG_WARN("sql.sql", "Transaction aborted. %u queries not executed.", (uint32)queries.size());
+ int errorCode = GetLastError();
RollbackTransaction();
- return false;
+ return errorCode;
}
}
break;
@@ -392,8 +393,9 @@ bool MySQLConnection::ExecuteTransaction(SQLTransaction& transaction)
if (!Execute(sql))
{
TC_LOG_WARN("sql.sql", "Transaction aborted. %u queries not executed.", (uint32)queries.size());
+ int errorCode = GetLastError();
RollbackTransaction();
- return false;
+ return errorCode;
}
}
break;
@@ -406,7 +408,7 @@ bool MySQLConnection::ExecuteTransaction(SQLTransaction& transaction)
// and not while iterating over every element.
CommitTransaction();
- return true;
+ return 0;
}
MySQLPreparedStatement* MySQLConnection::GetPreparedStatement(uint32 index)
diff --git a/src/server/shared/Database/MySQLConnection.h b/src/server/shared/Database/MySQLConnection.h
index 33f17d02228..d486f5b4679 100644
--- a/src/server/shared/Database/MySQLConnection.h
+++ b/src/server/shared/Database/MySQLConnection.h
@@ -86,7 +86,7 @@ class MySQLConnection
void BeginTransaction();
void RollbackTransaction();
void CommitTransaction();
- bool ExecuteTransaction(SQLTransaction& transaction);
+ int ExecuteTransaction(SQLTransaction& transaction);
operator bool () const { return m_Mysql != NULL; }
void Ping() { mysql_ping(m_Mysql); }
diff --git a/src/server/shared/Database/Transaction.cpp b/src/server/shared/Database/Transaction.cpp
index 3dee865267b..9f36d198bde 100644
--- a/src/server/shared/Database/Transaction.cpp
+++ b/src/server/shared/Database/Transaction.cpp
@@ -17,6 +17,9 @@
#include "DatabaseEnv.h"
#include "Transaction.h"
+#include <mysqld_error.h>
+
+std::mutex TransactionTask::_deadlockLock;
//- Append a raw ad-hoc query to the transaction
void Transaction::Append(const char* sql)
@@ -74,14 +77,17 @@ void Transaction::Cleanup()
bool TransactionTask::Execute()
{
- if (m_conn->ExecuteTransaction(m_trans))
+ int errorCode = m_conn->ExecuteTransaction(m_trans);
+ if (!errorCode)
return true;
- if (m_conn->GetLastError() == 1213)
+ if (errorCode == ER_LOCK_DEADLOCK)
{
+ // Make sure only 1 async thread retries a transaction so they don't keep dead-locking each other
+ std::lock_guard<std::mutex> lock(_deadlockLock);
uint8 loopBreaker = 5; // Handle MySQL Errno 1213 without extending deadlock to the core itself
for (uint8 i = 0; i < loopBreaker; ++i)
- if (m_conn->ExecuteTransaction(m_trans))
+ if (!m_conn->ExecuteTransaction(m_trans))
return true;
}
diff --git a/src/server/shared/Database/Transaction.h b/src/server/shared/Database/Transaction.h
index cf6aa98b386..83d59006ddc 100644
--- a/src/server/shared/Database/Transaction.h
+++ b/src/server/shared/Database/Transaction.h
@@ -66,6 +66,7 @@ class TransactionTask : public SQLOperation
bool Execute() override;
SQLTransaction m_trans;
+ static std::mutex _deadlockLock;
};
#endif
diff --git a/src/server/shared/Debugging/Errors.h b/src/server/shared/Debugging/Errors.h
index df770c2aa47..4d4624b63dd 100644
--- a/src/server/shared/Debugging/Errors.h
+++ b/src/server/shared/Debugging/Errors.h
@@ -49,4 +49,10 @@ namespace Trinity
#define ASSERT WPAssert
+template <typename T> inline T* ASSERT_NOTNULL(T* pointer)
+{
+ ASSERT(pointer);
+ return pointer;
+}
+
#endif
diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp
index e9f4f9ca9ac..f8f641a9ea7 100644
--- a/src/server/shared/Debugging/WheatyExceptionReport.cpp
+++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp
@@ -1068,7 +1068,7 @@ bool logChildren)
{
case btChar:
case btStdString:
- FormatOutputValue(buffer, basicType, length, (PVOID)offset, sizeof(buffer));
+ FormatOutputValue(buffer, basicType, length, (PVOID)offset, sizeof(buffer), elementsCount);
symbolDetails.top().Value = buffer;
break;
default:
@@ -1196,7 +1196,8 @@ void WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer,
BasicType basicType,
DWORD64 length,
PVOID pAddress,
-size_t bufferSize)
+size_t bufferSize,
+size_t countOverride)
{
__try
{
@@ -1204,10 +1205,15 @@ size_t bufferSize)
{
case btChar:
{
- if (strlen((char*)pAddress) > bufferSize - 6)
+ // Special case handling for char[] type
+ if (countOverride != 0)
+ length = countOverride;
+ else
+ length = strlen((char*)pAddress);
+ if (length > bufferSize - 6)
pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, (char*)pAddress);
else
- pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", (char*)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s\"", length, (char*)pAddress);
break;
}
case btStdString:
diff --git a/src/server/shared/Debugging/WheatyExceptionReport.h b/src/server/shared/Debugging/WheatyExceptionReport.h
index 9137b91aac9..b7731daaa2b 100644
--- a/src/server/shared/Debugging/WheatyExceptionReport.h
+++ b/src/server/shared/Debugging/WheatyExceptionReport.h
@@ -172,7 +172,7 @@ class WheatyExceptionReport
static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, const char*, char*, bool, bool);
- static void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize);
+ static void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize, size_t countOverride = 0);
static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase);
static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address);
diff --git a/src/server/shared/Logging/Appender.cpp b/src/server/shared/Logging/Appender.cpp
index dff931e3da8..ca40a857419 100644
--- a/src/server/shared/Logging/Appender.cpp
+++ b/src/server/shared/Logging/Appender.cpp
@@ -18,6 +18,10 @@
#include "Appender.h"
#include "Common.h"
#include "Util.h"
+#include "StringFormat.h"
+
+#include <utility>
+#include <sstream>
std::string LogMessage::getTimeStr(time_t time)
{
@@ -68,38 +72,36 @@ void Appender::setLogLevel(LogLevel _level)
level = _level;
}
-void Appender::write(LogMessage& message)
+void Appender::write(LogMessage* message)
{
- if (!level || level > message.level)
+ if (!level || level > message->level)
return;
- message.prefix.clear();
+ std::ostringstream ss;
+
if (flags & APPENDER_FLAGS_PREFIX_TIMESTAMP)
- message.prefix.append(message.getTimeStr());
+ ss << message->getTimeStr();
if (flags & APPENDER_FLAGS_PREFIX_LOGLEVEL)
{
- if (!message.prefix.empty())
- message.prefix.push_back(' ');
+ if (ss.rdbuf()->in_avail() == 0)
+ ss << ' ';
- char text[MAX_QUERY_LEN];
- snprintf(text, MAX_QUERY_LEN, "%-5s", Appender::getLogLevelString(message.level));
- message.prefix.append(text);
+ ss << Trinity::StringFormat("%-5s", Appender::getLogLevelString(message->level));
}
if (flags & APPENDER_FLAGS_PREFIX_LOGFILTERTYPE)
{
- if (!message.prefix.empty())
- message.prefix.push_back(' ');
+ if (ss.rdbuf()->in_avail() == 0)
+ ss << ' ';
- message.prefix.push_back('[');
- message.prefix.append(message.type);
- message.prefix.push_back(']');
+ ss << '[' << message->type << ']';
}
- if (!message.prefix.empty())
- message.prefix.push_back(' ');
+ if (ss.rdbuf()->in_avail() == 0)
+ ss << ' ';
+ message->prefix = std::move(ss.str());
_write(message);
}
diff --git a/src/server/shared/Logging/Appender.h b/src/server/shared/Logging/Appender.h
index 6f38eb6aaf7..38c45b3bcf1 100644
--- a/src/server/shared/Logging/Appender.h
+++ b/src/server/shared/Logging/Appender.h
@@ -21,6 +21,7 @@
#include <unordered_map>
#include <string>
#include <time.h>
+#include <type_traits>
#include "Define.h"
// Values assigned have their equivalent in enum ACE_Log_Priority
@@ -57,16 +58,16 @@ enum AppenderFlags
struct LogMessage
{
- LogMessage(LogLevel _level, std::string const& _type, std::string const& _text)
- : level(_level), type(_type), text(_text), mtime(time(NULL))
+ LogMessage(LogLevel _level, std::string const& _type, std::string&& _text)
+ : level(_level), type(_type), text(std::forward<std::string>(_text)), mtime(time(NULL))
{ }
static std::string getTimeStr(time_t time);
std::string getTimeStr();
- LogLevel level;
- std::string type;
- std::string text;
+ LogLevel const level;
+ std::string const type;
+ std::string const text;
std::string prefix;
std::string param1;
time_t mtime;
@@ -91,11 +92,11 @@ class Appender
AppenderFlags getFlags() const;
void setLogLevel(LogLevel);
- void write(LogMessage& message);
+ void write(LogMessage* message);
static const char* getLogLevelString(LogLevel level);
private:
- virtual void _write(LogMessage const& /*message*/) = 0;
+ virtual void _write(LogMessage const* /*message*/) = 0;
uint8 id;
std::string name;
diff --git a/src/server/shared/Logging/AppenderConsole.cpp b/src/server/shared/Logging/AppenderConsole.cpp
index ae27337fb9a..2efa4db4d2e 100644
--- a/src/server/shared/Logging/AppenderConsole.cpp
+++ b/src/server/shared/Logging/AppenderConsole.cpp
@@ -158,14 +158,14 @@ void AppenderConsole::ResetColor(bool stdout_stream)
#endif
}
-void AppenderConsole::_write(LogMessage const& message)
+void AppenderConsole::_write(LogMessage const* message)
{
- bool stdout_stream = !(message.level == LOG_LEVEL_ERROR || message.level == LOG_LEVEL_FATAL);
+ bool stdout_stream = !(message->level == LOG_LEVEL_ERROR || message->level == LOG_LEVEL_FATAL);
if (_colored)
{
uint8 index;
- switch (message.level)
+ switch (message->level)
{
case LOG_LEVEL_TRACE:
index = 5;
@@ -189,9 +189,9 @@ void AppenderConsole::_write(LogMessage const& message)
}
SetColor(stdout_stream, _colors[index]);
- utf8printf(stdout_stream ? stdout : stderr, "%s%s", message.prefix.c_str(), message.text.c_str());
+ utf8printf(stdout_stream ? stdout : stderr, "%s%s\n", message->prefix.c_str(), message->text.c_str());
ResetColor(stdout_stream);
}
else
- utf8printf(stdout_stream ? stdout : stderr, "%s%s", message.prefix.c_str(), message.text.c_str());
+ utf8printf(stdout_stream ? stdout : stderr, "%s%s\n", message->prefix.c_str(), message->text.c_str());
}
diff --git a/src/server/shared/Logging/AppenderConsole.h b/src/server/shared/Logging/AppenderConsole.h
index 0f9536b3111..0acf7636e35 100644
--- a/src/server/shared/Logging/AppenderConsole.h
+++ b/src/server/shared/Logging/AppenderConsole.h
@@ -51,7 +51,7 @@ class AppenderConsole: public Appender
private:
void SetColor(bool stdout_stream, ColorTypes color);
void ResetColor(bool stdout_stream);
- void _write(LogMessage const& message) override;
+ void _write(LogMessage const* message) override;
bool _colored;
ColorTypes _colors[MaxLogLevels];
};
diff --git a/src/server/shared/Logging/AppenderDB.cpp b/src/server/shared/Logging/AppenderDB.cpp
index d297d6d08d3..8a329ea3a0f 100644
--- a/src/server/shared/Logging/AppenderDB.cpp
+++ b/src/server/shared/Logging/AppenderDB.cpp
@@ -23,18 +23,18 @@ AppenderDB::AppenderDB(uint8 id, std::string const& name, LogLevel level)
AppenderDB::~AppenderDB() { }
-void AppenderDB::_write(LogMessage const& message)
+void AppenderDB::_write(LogMessage const* message)
{
// Avoid infinite loop, PExecute triggers Logging with "sql.sql" type
- if (!enabled || !message.type.find("sql"))
+ if (!enabled || (message->type.find("sql") != std::string::npos))
return;
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_LOG);
- stmt->setUInt64(0, message.mtime);
+ stmt->setUInt64(0, message->mtime);
stmt->setUInt32(1, realmId);
- stmt->setString(2, message.type);
- stmt->setUInt8(3, uint8(message.level));
- stmt->setString(4, message.text);
+ stmt->setString(2, message->type);
+ stmt->setUInt8(3, uint8(message->level));
+ stmt->setString(4, message->text);
LoginDatabase.Execute(stmt);
}
diff --git a/src/server/shared/Logging/AppenderDB.h b/src/server/shared/Logging/AppenderDB.h
index e20ceaf77b4..09affdb46f1 100644
--- a/src/server/shared/Logging/AppenderDB.h
+++ b/src/server/shared/Logging/AppenderDB.h
@@ -31,7 +31,7 @@ class AppenderDB: public Appender
private:
uint32 realmId;
bool enabled;
- void _write(LogMessage const& message) override;
+ void _write(LogMessage const* message) override;
};
#endif
diff --git a/src/server/shared/Logging/AppenderFile.cpp b/src/server/shared/Logging/AppenderFile.cpp
index 07a88a367ae..3892adbe3be 100644
--- a/src/server/shared/Logging/AppenderFile.cpp
+++ b/src/server/shared/Logging/AppenderFile.cpp
@@ -43,21 +43,21 @@ AppenderFile::~AppenderFile()
CloseFile();
}
-void AppenderFile::_write(LogMessage const& message)
+void AppenderFile::_write(LogMessage const* message)
{
- bool exceedMaxSize = maxFileSize > 0 && (fileSize.load() + message.Size()) > maxFileSize;
+ bool exceedMaxSize = maxFileSize > 0 && (fileSize.load() + message->Size()) > maxFileSize;
if (dynamicName)
{
char namebuf[TRINITY_PATH_MAX];
- snprintf(namebuf, TRINITY_PATH_MAX, filename.c_str(), message.param1.c_str());
+ snprintf(namebuf, TRINITY_PATH_MAX, filename.c_str(), message->param1.c_str());
// always use "a" with dynamic name otherwise it could delete the log we wrote in last _write() call
FILE* file = OpenFile(namebuf, "a", backup || exceedMaxSize);
if (!file)
return;
- fprintf(file, "%s%s", message.prefix.c_str(), message.text.c_str());
+ fprintf(file, "%s%s", message->prefix.c_str(), message->text.c_str());
fflush(file);
- fileSize += uint64(message.Size());
+ fileSize += uint64(message->Size());
fclose(file);
return;
}
@@ -67,9 +67,9 @@ void AppenderFile::_write(LogMessage const& message)
if (!logfile)
return;
- fprintf(logfile, "%s%s", message.prefix.c_str(), message.text.c_str());
+ fprintf(logfile, "%s%s\n", message->prefix.c_str(), message->text.c_str());
fflush(logfile);
- fileSize += uint64(message.Size());
+ fileSize += uint64(message->Size());
}
FILE* AppenderFile::OpenFile(std::string const &filename, std::string const &mode, bool backup)
diff --git a/src/server/shared/Logging/AppenderFile.h b/src/server/shared/Logging/AppenderFile.h
index 23651fc1129..36afdd23ad1 100644
--- a/src/server/shared/Logging/AppenderFile.h
+++ b/src/server/shared/Logging/AppenderFile.h
@@ -30,7 +30,7 @@ class AppenderFile: public Appender
private:
void CloseFile();
- void _write(LogMessage const& message) override;
+ void _write(LogMessage const* message) override;
FILE* logfile;
std::string filename;
std::string logDir;
diff --git a/src/server/shared/Logging/Log.cpp b/src/server/shared/Logging/Log.cpp
index 4bf4dacb302..c9a4432039f 100644
--- a/src/server/shared/Logging/Log.cpp
+++ b/src/server/shared/Logging/Log.cpp
@@ -199,6 +199,9 @@ void Log::CreateLoggerFromConfig(std::string const& appenderName)
return;
}
+ if (level < lowestLogLevel)
+ lowestLogLevel = level;
+
logger.Create(name, level);
//fprintf(stdout, "Log::CreateLoggerFromConfig: Created Logger %s, Level %u\n", name.c_str(), level);
@@ -261,30 +264,18 @@ void Log::ReadLoggersFromConfig()
}
}
-void Log::vlog(std::string const& filter, LogLevel level, char const* str, va_list argptr)
-{
- char text[MAX_QUERY_LEN];
- vsnprintf(text, MAX_QUERY_LEN, str, argptr);
- write(new LogMessage(level, filter, text));
-}
-
-void Log::write(LogMessage* msg) const
+void Log::write(std::unique_ptr<LogMessage>&& msg) const
{
Logger const* logger = GetLoggerByType(msg->type);
- msg->text.append("\n");
if (_ioService)
{
- auto logOperation = std::shared_ptr<LogOperation>(new LogOperation(logger, msg));
+ auto logOperation = std::shared_ptr<LogOperation>(new LogOperation(logger, std::forward<std::unique_ptr<LogMessage>>(msg)));
_ioService->post(_strand->wrap([logOperation](){ logOperation->call(); }));
-
}
else
- {
- logger->write(*msg);
- delete msg;
- }
+ logger->write(msg.get());
}
std::string Log::GetTimestampStr()
@@ -321,6 +312,9 @@ bool Log::SetLogLevel(std::string const& name, const char* newLevelc, bool isLog
return false;
it->second.setLogLevel(newLevel);
+
+ if (newLevel != LOG_LEVEL_DISABLED && newLevel < lowestLogLevel)
+ lowestLogLevel = newLevel;
}
else
{
@@ -343,40 +337,20 @@ void Log::outCharDump(char const* str, uint32 accountId, uint64 guid, char const
ss << "== START DUMP == (account: " << accountId << " guid: " << guid << " name: " << name
<< ")\n" << str << "\n== END DUMP ==\n";
- LogMessage* msg = new LogMessage(LOG_LEVEL_INFO, "entities.player.dump", ss.str());
+ std::unique_ptr<LogMessage> msg(new LogMessage(LOG_LEVEL_INFO, "entities.player.dump", ss.str()));
std::ostringstream param;
param << guid << '_' << name;
msg->param1 = param.str();
- write(msg);
-}
-
-void Log::outCommand(uint32 account, const char * str, ...)
-{
- if (!str || !ShouldLog("commands.gm", LOG_LEVEL_INFO))
- return;
-
- va_list ap;
- va_start(ap, str);
- char text[MAX_QUERY_LEN];
- vsnprintf(text, MAX_QUERY_LEN, str, ap);
- va_end(ap);
-
- LogMessage* msg = new LogMessage(LOG_LEVEL_INFO, "commands.gm", text);
-
- std::ostringstream ss;
- ss << account;
- msg->param1 = ss.str();
-
- write(msg);
+ write(std::move(msg));
}
void Log::SetRealmId(uint32 id)
{
for (AppenderMap::iterator it = appenders.begin(); it != appenders.end(); ++it)
if (it->second && it->second->getType() == APPENDER_DB)
- ((AppenderDB *)it->second)->setRealmId(id);
+ static_cast<AppenderDB*>(it->second)->setRealmId(id);
}
void Log::Close()
@@ -394,6 +368,7 @@ void Log::LoadFromConfig()
{
Close();
+ lowestLogLevel = LOG_LEVEL_FATAL;
AppenderId = 0;
m_logsDir = sConfigMgr->GetStringDefault("LogsDir", "");
if (!m_logsDir.empty())
diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h
index 1d67ff87f76..20d83d2dcf0 100644
--- a/src/server/shared/Logging/Log.h
+++ b/src/server/shared/Logging/Log.h
@@ -22,12 +22,14 @@
#include "Define.h"
#include "Appender.h"
#include "Logger.h"
-#include <stdarg.h>
+#include "StringFormat.h"
#include <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
+#include <stdarg.h>
#include <unordered_map>
#include <string>
+#include <memory>
#define LOGGER_ROOT "root"
@@ -59,17 +61,34 @@ class Log
bool ShouldLog(std::string const& type, LogLevel level) const;
bool SetLogLevel(std::string const& name, char const* level, bool isLogger = true);
- void outMessage(std::string const& f, LogLevel level, char const* str, ...) ATTR_PRINTF(4, 5);
+ template<typename... Args>
+ inline void outMessage(std::string const& filter, LogLevel const level, const char* fmt, Args const&... args)
+ {
+ write(std::move(std::unique_ptr<LogMessage>(new LogMessage(level, filter, std::move(Trinity::StringFormat(fmt, args...))))));
+ }
+
+ template<typename... Args>
+ void outCommand(uint32 account, const char* fmt, Args const&... args)
+ {
+ if (!ShouldLog("commands.gm", LOG_LEVEL_INFO))
+ return;
+
+ std::unique_ptr<LogMessage> msg(new LogMessage(LOG_LEVEL_INFO, "commands.gm", std::move(Trinity::StringFormat(fmt, args...))));
+
+ std::ostringstream ss;
+ ss << account;
+ msg->param1 = ss.str();
+
+ write(std::move(msg));
+ }
- void outCommand(uint32 account, const char * str, ...) ATTR_PRINTF(3, 4);
void outCharDump(char const* str, uint32 account_id, uint64 guid, char const* name);
void SetRealmId(uint32 id);
private:
static std::string GetTimestampStr();
- void vlog(std::string const& f, LogLevel level, char const* str, va_list argptr);
- void write(LogMessage* msg) const;
+ void write(std::unique_ptr<LogMessage>&& msg) const;
Logger const* GetLoggerByType(std::string const& type) const;
Appender* GetAppenderByName(std::string const& name);
@@ -82,6 +101,7 @@ class Log
AppenderMap appenders;
LoggerMap loggers;
uint8 AppenderId;
+ LogLevel lowestLogLevel;
std::string m_logsDir;
std::string m_logsTimestamp;
@@ -113,6 +133,10 @@ inline bool Log::ShouldLog(std::string const& type, LogLevel level) const
// Speed up in cases where requesting "Type.sub1.sub2" but only configured
// Logger "Type"
+ // Don't even look for a logger if the LogLevel is lower than lowest log levels across all loggers
+ if (level < lowestLogLevel)
+ return false;
+
Logger const* logger = GetLoggerByType(type);
if (!logger)
return false;
@@ -121,23 +145,34 @@ inline bool Log::ShouldLog(std::string const& type, LogLevel level) const
return logLevel != LOG_LEVEL_DISABLED && logLevel <= level;
}
-inline void Log::outMessage(std::string const& filter, LogLevel level, const char * str, ...)
-{
- va_list ap;
- va_start(ap, str);
-
- vlog(filter, level, str, ap);
-
- va_end(ap);
-}
-
#define sLog Log::instance()
+#define LOG_EXCEPTION_FREE(filterType__, level__, ...) \
+ { \
+ try \
+ { \
+ sLog->outMessage(filterType__, level__, __VA_ARGS__); \
+ } \
+ catch (std::exception& e) \
+ { \
+ sLog->outMessage("server", LOG_LEVEL_ERROR, "Wrong format occurred (%s) at %s:%u.", \
+ e.what(), __FILE__, __LINE__); \
+ } \
+ }
+
#if PLATFORM != PLATFORM_WINDOWS
+void check_args(const char* format, ...) ATTR_PRINTF(1, 2);
+
+// This will catch format errors on build time
#define TC_LOG_MESSAGE_BODY(filterType__, level__, ...) \
do { \
if (sLog->ShouldLog(filterType__, level__)) \
- sLog->outMessage(filterType__, level__, __VA_ARGS__); \
+ { \
+ if (false) \
+ check_args(__VA_ARGS__); \
+ \
+ LOG_EXCEPTION_FREE(filterType__, level__, __VA_ARGS__); \
+ } \
} while (0)
#else
#define TC_LOG_MESSAGE_BODY(filterType__, level__, ...) \
@@ -145,7 +180,7 @@ inline void Log::outMessage(std::string const& filter, LogLevel level, const cha
__pragma(warning(disable:4127)) \
do { \
if (sLog->ShouldLog(filterType__, level__)) \
- sLog->outMessage(filterType__, level__, __VA_ARGS__); \
+ LOG_EXCEPTION_FREE(filterType__, level__, __VA_ARGS__); \
} while (0) \
__pragma(warning(pop))
#endif
diff --git a/src/server/shared/Logging/LogOperation.cpp b/src/server/shared/Logging/LogOperation.cpp
index 9afb28a49c2..bcd923c705e 100644
--- a/src/server/shared/Logging/LogOperation.cpp
+++ b/src/server/shared/Logging/LogOperation.cpp
@@ -18,14 +18,8 @@
#include "LogOperation.h"
#include "Logger.h"
-LogOperation::~LogOperation()
-{
- delete msg;
-}
-
int LogOperation::call()
{
- if (logger && msg)
- logger->write(*msg);
+ logger->write(msg.get());
return 0;
}
diff --git a/src/server/shared/Logging/LogOperation.h b/src/server/shared/Logging/LogOperation.h
index b8655413273..ffdd35c3c09 100644
--- a/src/server/shared/Logging/LogOperation.h
+++ b/src/server/shared/Logging/LogOperation.h
@@ -18,23 +18,25 @@
#ifndef LOGOPERATION_H
#define LOGOPERATION_H
+#include <memory>
+
class Logger;
struct LogMessage;
class LogOperation
{
public:
- LogOperation(Logger const* _logger, LogMessage* _msg)
- : logger(_logger), msg(_msg)
+ LogOperation(Logger const* _logger, std::unique_ptr<LogMessage>&& _msg)
+ : logger(_logger), msg(std::forward<std::unique_ptr<LogMessage>>(_msg))
{ }
- ~LogOperation();
+ ~LogOperation() { }
int call();
protected:
Logger const* logger;
- LogMessage* msg;
+ std::unique_ptr<LogMessage> msg;
};
#endif
diff --git a/src/server/shared/Logging/Logger.cpp b/src/server/shared/Logging/Logger.cpp
index 615732deb30..3b02eb47575 100644
--- a/src/server/shared/Logging/Logger.cpp
+++ b/src/server/shared/Logging/Logger.cpp
@@ -50,9 +50,9 @@ void Logger::setLogLevel(LogLevel _level)
level = _level;
}
-void Logger::write(LogMessage& message) const
+void Logger::write(LogMessage* message) const
{
- if (!level || level > message.level || message.text.empty())
+ if (!level || level > message->level || message->text.empty())
{
//fprintf(stderr, "Logger::write: Logger %s, Level %u. Msg %s Level %u WRONG LEVEL MASK OR EMPTY MSG\n", getName().c_str(), getLogLevel(), message.text.c_str(), message.level);
return;
diff --git a/src/server/shared/Logging/Logger.h b/src/server/shared/Logging/Logger.h
index a81ee8d7bd2..1aee75c5d72 100644
--- a/src/server/shared/Logging/Logger.h
+++ b/src/server/shared/Logging/Logger.h
@@ -32,7 +32,7 @@ class Logger
std::string const& getName() const;
LogLevel getLogLevel() const;
void setLogLevel(LogLevel level);
- void write(LogMessage& message) const;
+ void write(LogMessage* message) const;
private:
std::string name;
diff --git a/src/server/shared/Networking/Socket.h b/src/server/shared/Networking/Socket.h
index f6bf3976b85..f7a1b954cb0 100644
--- a/src/server/shared/Networking/Socket.h
+++ b/src/server/shared/Networking/Socket.h
@@ -34,7 +34,9 @@
using boost::asio::ip::tcp;
#define READ_BLOCK_SIZE 4096
-#define TC_SOCKET_USE_IOCP BOOST_ASIO_HAS_IOCP
+#ifdef BOOST_ASIO_HAS_IOCP
+#define TC_SOCKET_USE_IOCP
+#endif
template<class T>
class Socket : public std::enable_shared_from_this<T>
diff --git a/src/server/shared/Networking/SocketMgr.h b/src/server/shared/Networking/SocketMgr.h
index df57baf257e..2078ae90c62 100644
--- a/src/server/shared/Networking/SocketMgr.h
+++ b/src/server/shared/Networking/SocketMgr.h
@@ -99,7 +99,7 @@ public:
}
catch (boost::system::system_error const& err)
{
- TC_LOG_INFO("network", "Failed to retrieve client's remote address %s", err.what());
+ TC_LOG_WARN("network", "Failed to retrieve client's remote address %s", err.what());
}
}
diff --git a/src/server/shared/Utilities/StringFormat.h b/src/server/shared/Utilities/StringFormat.h
new file mode 100644
index 00000000000..70d9aefb14d
--- /dev/null
+++ b/src/server/shared/Utilities/StringFormat.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TRINITYCORE_STRING_FORMAT_H
+#define TRINITYCORE_STRING_FORMAT_H
+
+#include <format.h>
+
+namespace Trinity
+{
+ //! Default TC string format function
+ template<typename... Args>
+ inline std::string StringFormat(const char* fmt, Args const&... args)
+ {
+ return fmt::sprintf(fmt, args...);
+ }
+}
+
+#endif
diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt
index 97180fb36a0..ce9ae8d5219 100644
--- a/src/server/worldserver/CMakeLists.txt
+++ b/src/server/worldserver/CMakeLists.txt
@@ -47,6 +47,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/dep/gsoap
${CMAKE_SOURCE_DIR}/dep/sockets/include
${CMAKE_SOURCE_DIR}/dep/SFMT
+ ${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/src/server/collision
${CMAKE_SOURCE_DIR}/src/server/collision/Management
${CMAKE_SOURCE_DIR}/src/server/collision/Models
@@ -168,6 +169,7 @@ target_link_libraries(worldserver
g3dlib
gsoap
Detour
+ format
${JEMALLOC_LIBRARY}
${READLINE_LIBRARY}
${TERMCAP_LIBRARY}
diff --git a/src/server/worldserver/RemoteAccess/RASession.h b/src/server/worldserver/RemoteAccess/RASession.h
index d272f323c6a..efd2106fdd1 100644
--- a/src/server/worldserver/RemoteAccess/RASession.h
+++ b/src/server/worldserver/RemoteAccess/RASession.h
@@ -30,8 +30,6 @@ using boost::asio::ip::tcp;
const size_t bufferSize = 4096;
-#define BUFFER_SIZE 4096
-
class RASession : public std::enable_shared_from_this <RASession>
{
public:
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index eaef902addc..ecb5824b1c5 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -3029,33 +3029,54 @@ AuctionHouseBot.Buyer.Horde.Enabled = 0
AuctionHouseBot.Buyer.Neutral.Enabled = 0
#
-# AuctionHouseBot.BuyPrice.Buyer
-# Description: Should the Buyer use BuyPrice or SellPrice to determine Bid Prices
-# Default: 1 - (use BuyPrice)
-# 0 - (use SellPrice)
-
-AuctionHouseBot.Buyer.Buyprice = 1
+# AuctionHouseBot.Buyer.Baseprice.QUALITY
+# Description: Base sellprices in copper for non priced items for each quality.
+# The default values are based on average item prices of each quality.
+# Defaults: Gray 3504
+# White 5429
+# Green 21752
+# Blue 36463
+# Purple 87124
+# Orange 214347
+# Yellow 407406
+
+AuctionHouseBot.Buyer.Baseprice.Gray = 3504
+AuctionHouseBot.Buyer.Baseprice.White = 5429
+AuctionHouseBot.Buyer.Baseprice.Green = 21752
+AuctionHouseBot.Buyer.Baseprice.Blue = 36463
+AuctionHouseBot.Buyer.Baseprice.Purple = 87124
+AuctionHouseBot.Buyer.Baseprice.Orange = 214347
+AuctionHouseBot.Buyer.Baseprice.Yellow = 407406
+
+#
+# AuctionHouseBot.Buyer.ChanceMultiplier.QUALITY
+# Description: Multipliers for the buy/bid chances for each quality. 100 means the chance is 100% of the original,
+# 1 would mean 1 % of the original and 200 would mean 200% of the original chance.
+# Defaults: Gray 100
+# White 100
+# Green 100
+# Blue 100
+# Purple 100
+# Orange 100
+# Yellow 100
+
+AuctionHouseBot.Buyer.ChanceMultiplier.Gray = 100
+AuctionHouseBot.Buyer.ChanceMultiplier.White = 100
+AuctionHouseBot.Buyer.ChanceMultiplier.Green = 100
+AuctionHouseBot.Buyer.ChanceMultiplier.Blue = 100
+AuctionHouseBot.Buyer.ChanceMultiplier.Purple = 100
+AuctionHouseBot.Buyer.ChanceMultiplier.Orange = 100
+AuctionHouseBot.Buyer.ChanceMultiplier.Yellow = 100
#
# AuctionHouseBot.Buyer.Recheck.Interval
-# Description: This specifies the time interval (in minutes) between two evaluations of the same selled item.
-# The lesser this value is, the more chances you give for item to be bought by ahbot.
+# Description: This specifies the time interval (in minutes) between two evaluations of the same sold item.
+# The smaller this value is, the more chances you give for an item to be bought by ahbot.
# Default: 20 (20min.)
AuctionHouseBot.Buyer.Recheck.Interval = 20
#
-# AuctionHouseBot.Buyer.Alliance.Chance.Ratio
-# Description: Chance ratio for the buyer to buy an item. Higher the value, lesser the probability
-# Example: 3 (1 out of 3 change, that is, 33%).
-# Default: 3
-#
-
-AuctionHouseBot.Buyer.Alliance.Chance.Ratio = 3
-AuctionHouseBot.Buyer.Horde.Chance.Ratio = 3
-AuctionHouseBot.Buyer.Neutral.Chance.Ratio = 3
-
-#
###################################################################################################
###################################################################################################
@@ -3192,6 +3213,7 @@ Logger.sql.sql=5,Console DBErrors
#Logger.scripts.ai=3,Console Server
#Logger.server.authserver=3,Console Server
#Logger.spells=3,Console Server
+#Logger.spells.periodic=3,Console Server
#Logger.sql.dev=3,Console Server
#Logger.sql.driver=3,Console Server
#Logger.warden=3,Console Server