From 62200e8d022479ff057b6898380e1dd8374d2ec2 Mon Sep 17 00:00:00 2001 From: XTZGZoReX Date: Sun, 6 Jun 2010 22:55:56 +0200 Subject: * Even more restructuring of the game library. --HG-- branch : trunk --- .../game/AI/AuctionHouseBot/AuctionHouseBot.cpp | 1860 ----- .../game/AI/AuctionHouseBot/AuctionHouseBot.h | 1225 --- src/server/game/AI/CombatAI.cpp | 370 - src/server/game/AI/CombatAI.h | 129 - src/server/game/AI/CoreAI/CombatAI.cpp | 370 + src/server/game/AI/CoreAI/CombatAI.h | 129 + src/server/game/AI/CoreAI/GuardAI.cpp | 137 + src/server/game/AI/CoreAI/GuardAI.h | 55 + src/server/game/AI/CoreAI/PassiveAI.cpp | 81 + src/server/game/AI/CoreAI/PassiveAI.h | 86 + src/server/game/AI/CoreAI/PetAI.cpp | 471 ++ src/server/game/AI/CoreAI/PetAI.h | 64 + src/server/game/AI/CoreAI/ReactorAI.cpp | 59 + src/server/game/AI/CoreAI/ReactorAI.h | 40 + src/server/game/AI/CoreAI/TotemAI.cpp | 116 + src/server/game/AI/CoreAI/TotemAI.h | 47 + src/server/game/AI/CoreAI/UnitAI.cpp | 327 + src/server/game/AI/CoreAI/UnitAI.h | 161 + src/server/game/AI/GuardAI.cpp | 137 - src/server/game/AI/GuardAI.h | 55 - src/server/game/AI/PassiveAI.cpp | 81 - src/server/game/AI/PassiveAI.h | 86 - src/server/game/AI/PetAI.cpp | 471 -- src/server/game/AI/PetAI.h | 64 - src/server/game/AI/ReactorAI.cpp | 59 - src/server/game/AI/ReactorAI.h | 40 - src/server/game/AI/TotemAI.cpp | 116 - src/server/game/AI/TotemAI.h | 47 - src/server/game/AI/UnitAI.cpp | 327 - src/server/game/AI/UnitAI.h | 161 - src/server/game/Account/AccountMgr.cpp | 246 - src/server/game/Account/AccountMgr.h | 64 - src/server/game/Accounts/AccountMgr.cpp | 246 + src/server/game/Accounts/AccountMgr.h | 64 + src/server/game/Addons/AddonHandler.cpp | 234 - src/server/game/Addons/AddonHandler.h | 41 - .../AuctionHouseBot/AuctionHouseBot.cpp | 1860 +++++ .../AuctionHouse/AuctionHouseBot/AuctionHouseBot.h | 1225 +++ .../game/AuctionHouse/AuctionHouseHandler.cpp | 664 -- src/server/game/BattleGrounds/ArenaTeamHandler.cpp | 391 - src/server/game/BattleGrounds/BattleGroundAA.cpp | 84 - src/server/game/BattleGrounds/BattleGroundAA.h | 53 - src/server/game/BattleGrounds/BattleGroundAB.cpp | 715 -- src/server/game/BattleGrounds/BattleGroundAB.h | 301 - src/server/game/BattleGrounds/BattleGroundAV.cpp | 1490 ---- src/server/game/BattleGrounds/BattleGroundAV.h | 1614 ---- src/server/game/BattleGrounds/BattleGroundBE.cpp | 201 - src/server/game/BattleGrounds/BattleGroundBE.h | 78 - src/server/game/BattleGrounds/BattleGroundDS.cpp | 182 - src/server/game/BattleGrounds/BattleGroundDS.h | 89 - src/server/game/BattleGrounds/BattleGroundEY.cpp | 938 --- src/server/game/BattleGrounds/BattleGroundEY.h | 410 - .../game/BattleGrounds/BattleGroundHandler.cpp | 803 -- src/server/game/BattleGrounds/BattleGroundIC.cpp | 132 - src/server/game/BattleGrounds/BattleGroundIC.h | 64 - src/server/game/BattleGrounds/BattleGroundNA.cpp | 177 - src/server/game/BattleGrounds/BattleGroundNA.h | 76 - src/server/game/BattleGrounds/BattleGroundRB.cpp | 81 - src/server/game/BattleGrounds/BattleGroundRB.h | 54 - src/server/game/BattleGrounds/BattleGroundRL.cpp | 176 - src/server/game/BattleGrounds/BattleGroundRL.h | 72 - src/server/game/BattleGrounds/BattleGroundRV.cpp | 234 - src/server/game/BattleGrounds/BattleGroundRV.h | 140 - src/server/game/BattleGrounds/BattleGroundSA.cpp | 822 -- src/server/game/BattleGrounds/BattleGroundSA.h | 384 - src/server/game/BattleGrounds/BattleGroundWS.cpp | 841 -- src/server/game/BattleGrounds/BattleGroundWS.h | 223 - .../game/BattleGrounds/Zones/BattleGroundAA.cpp | 84 + .../game/BattleGrounds/Zones/BattleGroundAA.h | 53 + .../game/BattleGrounds/Zones/BattleGroundAB.cpp | 715 ++ .../game/BattleGrounds/Zones/BattleGroundAB.h | 301 + .../game/BattleGrounds/Zones/BattleGroundAV.cpp | 1490 ++++ .../game/BattleGrounds/Zones/BattleGroundAV.h | 1614 ++++ .../game/BattleGrounds/Zones/BattleGroundBE.cpp | 201 + .../game/BattleGrounds/Zones/BattleGroundBE.h | 78 + .../game/BattleGrounds/Zones/BattleGroundDS.cpp | 182 + .../game/BattleGrounds/Zones/BattleGroundDS.h | 89 + .../game/BattleGrounds/Zones/BattleGroundEY.cpp | 938 +++ .../game/BattleGrounds/Zones/BattleGroundEY.h | 410 + .../game/BattleGrounds/Zones/BattleGroundIC.cpp | 132 + .../game/BattleGrounds/Zones/BattleGroundIC.h | 64 + .../game/BattleGrounds/Zones/BattleGroundNA.cpp | 177 + .../game/BattleGrounds/Zones/BattleGroundNA.h | 76 + .../game/BattleGrounds/Zones/BattleGroundRB.cpp | 81 + .../game/BattleGrounds/Zones/BattleGroundRB.h | 54 + .../game/BattleGrounds/Zones/BattleGroundRL.cpp | 176 + .../game/BattleGrounds/Zones/BattleGroundRL.h | 72 + .../game/BattleGrounds/Zones/BattleGroundRV.cpp | 234 + .../game/BattleGrounds/Zones/BattleGroundRV.h | 140 + .../game/BattleGrounds/Zones/BattleGroundSA.cpp | 822 ++ .../game/BattleGrounds/Zones/BattleGroundSA.h | 384 + .../game/BattleGrounds/Zones/BattleGroundWS.cpp | 841 ++ .../game/BattleGrounds/Zones/BattleGroundWS.h | 223 + src/server/game/Calendar/CalendarHandler.cpp | 318 - src/server/game/Chat/Channel.cpp | 1102 --- src/server/game/Chat/Channel.h | 292 - src/server/game/Chat/ChannelHandler.cpp | 323 - src/server/game/Chat/ChannelMgr.cpp | 110 - src/server/game/Chat/ChannelMgr.h | 57 - src/server/game/Chat/Channels/Channel.cpp | 1102 +++ src/server/game/Chat/Channels/Channel.h | 292 + src/server/game/Chat/Channels/ChannelMgr.cpp | 110 + src/server/game/Chat/Channels/ChannelMgr.h | 57 + src/server/game/Chat/ChatHandler.cpp | 756 -- src/server/game/Chat/Commands/Debugcmds.cpp | 1127 +++ src/server/game/Chat/Commands/Level0.cpp | 295 + src/server/game/Chat/Commands/Level1.cpp | 2960 +++++++ src/server/game/Chat/Commands/Level2.cpp | 4526 ++++++++++ src/server/game/Chat/Commands/Level3.cpp | 7743 +++++++++++++++++ src/server/game/Chat/Debugcmds.cpp | 1127 --- src/server/game/Chat/Level0.cpp | 295 - src/server/game/Chat/Level1.cpp | 2960 ------- src/server/game/Chat/Level2.cpp | 4526 ---------- src/server/game/Chat/Level3.cpp | 7743 ----------------- src/server/game/Combat/CombatHandler.cpp | 91 - src/server/game/Combat/UnitEvents.h | 139 + src/server/game/ConditionMgr/ConditionMgr.cpp | 1145 --- src/server/game/ConditionMgr/ConditionMgr.h | 167 - src/server/game/Conditions/ConditionMgr.cpp | 1145 +++ src/server/game/Conditions/ConditionMgr.h | 167 + src/server/game/DungeonFinding/LFG.h | 72 + src/server/game/DungeonFinding/LFGMgr.cpp | 1100 +++ src/server/game/DungeonFinding/LFGMgr.h | 279 + src/server/game/Entities/Corpse/Corpse.cpp | 243 + src/server/game/Entities/Corpse/Corpse.h | 97 + src/server/game/Entities/Creature/NPCHandler.cpp | 869 -- src/server/game/Entities/Creature/NPCHandler.h | 79 - .../game/Entities/DynamicObject/DynamicObject.cpp | 189 + .../game/Entities/DynamicObject/DynamicObject.h | 61 + src/server/game/Entities/Item/Bag.cpp | 235 - src/server/game/Entities/Item/Bag.h | 75 - src/server/game/Entities/Item/Container/Bag.cpp | 235 + src/server/game/Entities/Item/Container/Bag.h | 75 + src/server/game/Entities/Item/ItemHandler.cpp | 1430 ---- src/server/game/Entities/Object/Corpse.cpp | 243 - src/server/game/Entities/Object/Corpse.h | 97 - src/server/game/Entities/Object/DynamicObject.cpp | 189 - src/server/game/Entities/Object/DynamicObject.h | 61 - src/server/game/Entities/Object/ObjectAccessor.cpp | 375 - src/server/game/Entities/Object/ObjectAccessor.h | 257 - src/server/game/Entities/Object/ObjectMgr.cpp | 8724 -------------------- src/server/game/Entities/Object/ObjectMgr.h | 1085 --- .../game/Entities/Object/ObjectPosSelector.cpp | 157 + .../game/Entities/Object/ObjectPosSelector.h | 155 + src/server/game/Entities/Object/UpdateData.cpp | 157 - src/server/game/Entities/Object/UpdateData.h | 74 - src/server/game/Entities/Object/UpdateFields.h | 435 - src/server/game/Entities/Object/UpdateMask.h | 127 - .../game/Entities/Object/Updates/UpdateData.cpp | 157 + .../game/Entities/Object/Updates/UpdateData.h | 74 + .../game/Entities/Object/Updates/UpdateFields.h | 435 + .../game/Entities/Object/Updates/UpdateMask.h | 127 + src/server/game/Entities/Pet/PetHandler.cpp | 813 -- .../game/Entities/Player/CharacterHandler.cpp | 1406 ---- src/server/game/Entities/Player/DuelHandler.cpp | 84 - src/server/game/Entities/Player/MiscHandler.cpp | 1721 ---- .../game/Entities/Player/PetitionsHandler.cpp | 938 --- src/server/game/Entities/Player/TicketHandler.cpp | 161 - src/server/game/Entities/Player/TradeHandler.cpp | 656 -- .../game/Entities/Player/VoiceChatHandler.cpp | 50 - src/server/game/Entities/Transport/Transports.cpp | 589 ++ src/server/game/Entities/Transport/Transports.h | 108 + src/server/game/Events/GlobalEvents.cpp | 87 - src/server/game/Events/GlobalEvents.h | 32 - src/server/game/Events/UnitEvents.h | 139 - src/server/game/Globals/Formulas.h | 164 - src/server/game/Globals/GlobalEvents.cpp | 87 + src/server/game/Globals/GlobalEvents.h | 32 + src/server/game/Globals/Language.h | 1007 --- src/server/game/Globals/ObjectAccessor.cpp | 375 + src/server/game/Globals/ObjectAccessor.h | 257 + src/server/game/Globals/ObjectMgr.cpp | 8724 ++++++++++++++++++++ src/server/game/Globals/ObjectMgr.h | 1085 +++ src/server/game/Globals/SharedDefines.h | 2772 ------- src/server/game/Groups/GroupHandler.cpp | 940 --- src/server/game/Guilds/GuildHandler.cpp | 1225 --- src/server/game/LookingForGroup/LFG.h | 72 - src/server/game/LookingForGroup/LFGHandler.cpp | 251 - src/server/game/LookingForGroup/LFGMgr.cpp | 1100 --- src/server/game/LookingForGroup/LFGMgr.h | 279 - src/server/game/Loot/LootHandler.cpp | 549 -- src/server/game/Map/Cell/Cell.h | 177 - src/server/game/Map/Cell/CellImpl.h | 297 - src/server/game/Map/Grid/GridDefines.h | 193 - src/server/game/Map/Grid/GridNotifiers.cpp | 353 - src/server/game/Map/Grid/GridNotifiers.h | 1232 --- src/server/game/Map/Grid/GridNotifiersImpl.h | 453 - src/server/game/Map/Grid/GridStates.cpp | 76 - src/server/game/Map/Grid/GridStates.h | 76 - src/server/game/Map/Grid/ObjectGridLoader.cpp | 325 - src/server/game/Map/Grid/ObjectGridLoader.h | 134 - src/server/game/Map/Map.cpp | 3936 --------- src/server/game/Map/Map.h | 689 -- src/server/game/Map/MapInstanced.cpp | 268 - src/server/game/Map/MapInstanced.h | 80 - src/server/game/Map/MapManager.cpp | 395 - src/server/game/Map/MapManager.h | 158 - src/server/game/Map/MapRefManager.h | 45 - src/server/game/Map/MapReference.h | 53 - src/server/game/Map/MapUpdater.cpp | 129 - src/server/game/Map/MapUpdater.h | 40 - src/server/game/Map/ObjectPosSelector.cpp | 157 - src/server/game/Map/ObjectPosSelector.h | 155 - src/server/game/Map/ZoneScript.h | 51 - src/server/game/Maps/Cell/Cell.h | 177 + src/server/game/Maps/Cell/CellImpl.h | 297 + src/server/game/Maps/Grid/GridDefines.h | 193 + src/server/game/Maps/Grid/GridNotifiers.cpp | 353 + src/server/game/Maps/Grid/GridNotifiers.h | 1232 +++ src/server/game/Maps/Grid/GridNotifiersImpl.h | 453 + src/server/game/Maps/Grid/GridStates.cpp | 76 + src/server/game/Maps/Grid/GridStates.h | 76 + src/server/game/Maps/Grid/ObjectGridLoader.cpp | 325 + src/server/game/Maps/Grid/ObjectGridLoader.h | 134 + src/server/game/Maps/Map.cpp | 3936 +++++++++ src/server/game/Maps/Map.h | 689 ++ src/server/game/Maps/MapInstanced.cpp | 268 + src/server/game/Maps/MapInstanced.h | 80 + src/server/game/Maps/MapManager.cpp | 395 + src/server/game/Maps/MapManager.h | 158 + src/server/game/Maps/MapRefManager.h | 45 + src/server/game/Maps/MapReference.h | 53 + src/server/game/Maps/MapUpdater.cpp | 129 + src/server/game/Maps/MapUpdater.h | 40 + src/server/game/Maps/ZoneScript.h | 51 + src/server/game/Miscellaneous/Formulas.h | 164 + src/server/game/Miscellaneous/Language.h | 1007 +++ src/server/game/Miscellaneous/SharedDefines.h | 2772 +++++++ src/server/game/Movement/MovementGenerator.cpp | 27 + src/server/game/Movement/MovementGenerator.h | 102 + src/server/game/Movement/MovementGeneratorImpl.h | 34 + .../MovementGenerators/MovementGenerator.cpp | 27 - .../MovementGenerators/MovementGenerator.h | 102 - .../MovementGenerators/MovementGeneratorImpl.h | 34 - src/server/game/Movement/MovementHandler.cpp | 746 -- src/server/game/Movement/Path.h | 88 - src/server/game/Movement/TaxiHandler.cpp | 287 - src/server/game/Movement/Transports.cpp | 589 -- src/server/game/Movement/Transports.h | 108 - src/server/game/Movement/WaypointManager.cpp | 152 - src/server/game/Movement/WaypointManager.h | 68 - src/server/game/Movement/Waypoints/Path.h | 88 + .../game/Movement/Waypoints/WaypointManager.cpp | 152 + .../game/Movement/Waypoints/WaypointManager.h | 68 + src/server/game/Opcodes/Opcodes.cpp | 1338 --- src/server/game/Opcodes/Opcodes.h | 1378 ---- src/server/game/OutdoorPvP/OutdoorPvPEP.cpp | 765 -- src/server/game/OutdoorPvP/OutdoorPvPEP.h | 280 - src/server/game/OutdoorPvP/OutdoorPvPHP.cpp | 332 - src/server/game/OutdoorPvP/OutdoorPvPHP.h | 118 - src/server/game/OutdoorPvP/OutdoorPvPNA.cpp | 664 -- src/server/game/OutdoorPvP/OutdoorPvPNA.h | 297 - src/server/game/OutdoorPvP/OutdoorPvPSI.cpp | 227 - src/server/game/OutdoorPvP/OutdoorPvPSI.h | 75 - src/server/game/OutdoorPvP/OutdoorPvPTF.cpp | 310 - src/server/game/OutdoorPvP/OutdoorPvPTF.h | 117 - src/server/game/OutdoorPvP/OutdoorPvPZM.cpp | 423 - src/server/game/OutdoorPvP/OutdoorPvPZM.h | 219 - src/server/game/OutdoorPvP/Zones/OutdoorPvPEP.cpp | 765 ++ src/server/game/OutdoorPvP/Zones/OutdoorPvPEP.h | 280 + src/server/game/OutdoorPvP/Zones/OutdoorPvPHP.cpp | 332 + src/server/game/OutdoorPvP/Zones/OutdoorPvPHP.h | 118 + src/server/game/OutdoorPvP/Zones/OutdoorPvPNA.cpp | 664 ++ src/server/game/OutdoorPvP/Zones/OutdoorPvPNA.h | 297 + src/server/game/OutdoorPvP/Zones/OutdoorPvPSI.cpp | 227 + src/server/game/OutdoorPvP/Zones/OutdoorPvPSI.h | 75 + src/server/game/OutdoorPvP/Zones/OutdoorPvPTF.cpp | 310 + src/server/game/OutdoorPvP/Zones/OutdoorPvPTF.h | 117 + src/server/game/OutdoorPvP/Zones/OutdoorPvPZM.cpp | 423 + src/server/game/OutdoorPvP/Zones/OutdoorPvPZM.h | 219 + src/server/game/PrecompiledHeaders/ScriptedPch.cpp | 6 + src/server/game/PrecompiledHeaders/ScriptedPch.h | 32 + src/server/game/Quests/QueryHandler.cpp | 539 -- src/server/game/Quests/QuestHandler.cpp | 721 -- src/server/game/ScriptMgr/ScriptLoader.cpp | 1023 --- src/server/game/ScriptMgr/ScriptLoader.h | 10 - src/server/game/ScriptMgr/ScriptMgr.cpp | 549 -- src/server/game/ScriptMgr/ScriptMgr.h | 163 - src/server/game/ScriptMgr/ScriptSystem.cpp | 248 - src/server/game/ScriptMgr/ScriptSystem.h | 100 - src/server/game/ScriptMgr/ScriptedPch.cpp | 6 - src/server/game/ScriptMgr/ScriptedPch.h | 32 - src/server/game/Scripting/ScriptLoader.cpp | 1023 +++ src/server/game/Scripting/ScriptLoader.h | 10 + src/server/game/Scripting/ScriptMgr.cpp | 549 ++ src/server/game/Scripting/ScriptMgr.h | 163 + src/server/game/Scripting/ScriptSystem.cpp | 248 + src/server/game/Scripting/ScriptSystem.h | 100 + .../game/Server/Protocol/Handlers/AddonHandler.cpp | 234 + .../game/Server/Protocol/Handlers/AddonHandler.h | 41 + .../Server/Protocol/Handlers/ArenaTeamHandler.cpp | 391 + .../Protocol/Handlers/AuctionHouseHandler.cpp | 664 ++ .../Protocol/Handlers/BattleGroundHandler.cpp | 803 ++ .../Server/Protocol/Handlers/CalendarHandler.cpp | 318 + .../Server/Protocol/Handlers/ChannelHandler.cpp | 323 + .../Server/Protocol/Handlers/CharacterHandler.cpp | 1406 ++++ .../game/Server/Protocol/Handlers/ChatHandler.cpp | 756 ++ .../Server/Protocol/Handlers/CombatHandler.cpp | 91 + .../game/Server/Protocol/Handlers/DuelHandler.cpp | 84 + .../game/Server/Protocol/Handlers/GroupHandler.cpp | 940 +++ .../game/Server/Protocol/Handlers/GuildHandler.cpp | 1225 +++ .../game/Server/Protocol/Handlers/ItemHandler.cpp | 1430 ++++ .../game/Server/Protocol/Handlers/LFGHandler.cpp | 251 + .../game/Server/Protocol/Handlers/LootHandler.cpp | 549 ++ .../game/Server/Protocol/Handlers/MiscHandler.cpp | 1721 ++++ .../Server/Protocol/Handlers/MovementHandler.cpp | 746 ++ .../game/Server/Protocol/Handlers/NPCHandler.cpp | 869 ++ .../game/Server/Protocol/Handlers/NPCHandler.h | 79 + .../game/Server/Protocol/Handlers/PetHandler.cpp | 813 ++ .../Server/Protocol/Handlers/PetitionsHandler.cpp | 938 +++ .../game/Server/Protocol/Handlers/QueryHandler.cpp | 539 ++ .../game/Server/Protocol/Handlers/QuestHandler.cpp | 721 ++ .../game/Server/Protocol/Handlers/SkillHandler.cpp | 95 + .../game/Server/Protocol/Handlers/SpellHandler.cpp | 649 ++ .../game/Server/Protocol/Handlers/TaxiHandler.cpp | 287 + .../Server/Protocol/Handlers/TicketHandler.cpp | 161 + .../game/Server/Protocol/Handlers/TradeHandler.cpp | 656 ++ .../Server/Protocol/Handlers/VoiceChatHandler.cpp | 50 + src/server/game/Server/Protocol/Opcodes.cpp | 1338 +++ src/server/game/Server/Protocol/Opcodes.h | 1378 ++++ src/server/game/Server/Protocol/WorldLog.cpp | 122 + src/server/game/Server/Protocol/WorldLog.h | 63 + src/server/game/Server/WorldSession.cpp | 959 +++ src/server/game/Server/WorldSession.h | 829 ++ src/server/game/Server/WorldSocket.cpp | 1064 +++ src/server/game/Server/WorldSocket.h | 223 + src/server/game/Server/WorldSocketMgr.cpp | 369 + src/server/game/Server/WorldSocketMgr.h | 80 + src/server/game/Skills/SkillHandler.cpp | 95 - src/server/game/Spells/SpellHandler.cpp | 649 -- src/server/game/World/WorldLog.cpp | 122 - src/server/game/World/WorldLog.h | 63 - src/server/game/World/WorldSession.cpp | 959 --- src/server/game/World/WorldSession.h | 829 -- src/server/game/World/WorldSocket.cpp | 1064 --- src/server/game/World/WorldSocket.h | 223 - src/server/game/World/WorldSocketMgr.cpp | 369 - src/server/game/World/WorldSocketMgr.h | 80 - 338 files changed, 93332 insertions(+), 93332 deletions(-) delete mode 100644 src/server/game/AI/AuctionHouseBot/AuctionHouseBot.cpp delete mode 100644 src/server/game/AI/AuctionHouseBot/AuctionHouseBot.h delete mode 100644 src/server/game/AI/CombatAI.cpp delete mode 100644 src/server/game/AI/CombatAI.h create mode 100644 src/server/game/AI/CoreAI/CombatAI.cpp create mode 100644 src/server/game/AI/CoreAI/CombatAI.h create mode 100644 src/server/game/AI/CoreAI/GuardAI.cpp create mode 100644 src/server/game/AI/CoreAI/GuardAI.h create mode 100644 src/server/game/AI/CoreAI/PassiveAI.cpp create mode 100644 src/server/game/AI/CoreAI/PassiveAI.h create mode 100644 src/server/game/AI/CoreAI/PetAI.cpp create mode 100644 src/server/game/AI/CoreAI/PetAI.h create mode 100644 src/server/game/AI/CoreAI/ReactorAI.cpp create mode 100644 src/server/game/AI/CoreAI/ReactorAI.h create mode 100644 src/server/game/AI/CoreAI/TotemAI.cpp create mode 100644 src/server/game/AI/CoreAI/TotemAI.h create mode 100644 src/server/game/AI/CoreAI/UnitAI.cpp create mode 100644 src/server/game/AI/CoreAI/UnitAI.h delete mode 100644 src/server/game/AI/GuardAI.cpp delete mode 100644 src/server/game/AI/GuardAI.h delete mode 100644 src/server/game/AI/PassiveAI.cpp delete mode 100644 src/server/game/AI/PassiveAI.h delete mode 100644 src/server/game/AI/PetAI.cpp delete mode 100644 src/server/game/AI/PetAI.h delete mode 100644 src/server/game/AI/ReactorAI.cpp delete mode 100644 src/server/game/AI/ReactorAI.h delete mode 100644 src/server/game/AI/TotemAI.cpp delete mode 100644 src/server/game/AI/TotemAI.h delete mode 100644 src/server/game/AI/UnitAI.cpp delete mode 100644 src/server/game/AI/UnitAI.h delete mode 100644 src/server/game/Account/AccountMgr.cpp delete mode 100644 src/server/game/Account/AccountMgr.h create mode 100644 src/server/game/Accounts/AccountMgr.cpp create mode 100644 src/server/game/Accounts/AccountMgr.h delete mode 100644 src/server/game/Addons/AddonHandler.cpp delete mode 100644 src/server/game/Addons/AddonHandler.h create mode 100644 src/server/game/AuctionHouse/AuctionHouseBot/AuctionHouseBot.cpp create mode 100644 src/server/game/AuctionHouse/AuctionHouseBot/AuctionHouseBot.h delete mode 100644 src/server/game/AuctionHouse/AuctionHouseHandler.cpp delete mode 100644 src/server/game/BattleGrounds/ArenaTeamHandler.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundAA.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundAA.h delete mode 100644 src/server/game/BattleGrounds/BattleGroundAB.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundAB.h delete mode 100644 src/server/game/BattleGrounds/BattleGroundAV.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundAV.h delete mode 100644 src/server/game/BattleGrounds/BattleGroundBE.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundBE.h delete mode 100644 src/server/game/BattleGrounds/BattleGroundDS.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundDS.h delete mode 100644 src/server/game/BattleGrounds/BattleGroundEY.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundEY.h delete mode 100644 src/server/game/BattleGrounds/BattleGroundHandler.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundIC.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundIC.h delete mode 100644 src/server/game/BattleGrounds/BattleGroundNA.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundNA.h delete mode 100644 src/server/game/BattleGrounds/BattleGroundRB.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundRB.h delete mode 100644 src/server/game/BattleGrounds/BattleGroundRL.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundRL.h delete mode 100644 src/server/game/BattleGrounds/BattleGroundRV.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundRV.h delete mode 100644 src/server/game/BattleGrounds/BattleGroundSA.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundSA.h delete mode 100644 src/server/game/BattleGrounds/BattleGroundWS.cpp delete mode 100644 src/server/game/BattleGrounds/BattleGroundWS.h create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundAA.cpp create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundAA.h create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundAB.cpp create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundAB.h create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundAV.cpp create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundAV.h create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundBE.cpp create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundBE.h create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundDS.cpp create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundDS.h create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundEY.cpp create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundEY.h create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundIC.cpp create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundIC.h create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundNA.cpp create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundNA.h create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundRB.cpp create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundRB.h create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundRL.cpp create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundRL.h create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundRV.cpp create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundRV.h create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundSA.cpp create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundSA.h create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundWS.cpp create mode 100644 src/server/game/BattleGrounds/Zones/BattleGroundWS.h delete mode 100644 src/server/game/Calendar/CalendarHandler.cpp delete mode 100644 src/server/game/Chat/Channel.cpp delete mode 100644 src/server/game/Chat/Channel.h delete mode 100644 src/server/game/Chat/ChannelHandler.cpp delete mode 100644 src/server/game/Chat/ChannelMgr.cpp delete mode 100644 src/server/game/Chat/ChannelMgr.h create mode 100644 src/server/game/Chat/Channels/Channel.cpp create mode 100644 src/server/game/Chat/Channels/Channel.h create mode 100644 src/server/game/Chat/Channels/ChannelMgr.cpp create mode 100644 src/server/game/Chat/Channels/ChannelMgr.h delete mode 100644 src/server/game/Chat/ChatHandler.cpp create mode 100644 src/server/game/Chat/Commands/Debugcmds.cpp create mode 100644 src/server/game/Chat/Commands/Level0.cpp create mode 100644 src/server/game/Chat/Commands/Level1.cpp create mode 100644 src/server/game/Chat/Commands/Level2.cpp create mode 100644 src/server/game/Chat/Commands/Level3.cpp delete mode 100644 src/server/game/Chat/Debugcmds.cpp delete mode 100644 src/server/game/Chat/Level0.cpp delete mode 100644 src/server/game/Chat/Level1.cpp delete mode 100644 src/server/game/Chat/Level2.cpp delete mode 100644 src/server/game/Chat/Level3.cpp delete mode 100644 src/server/game/Combat/CombatHandler.cpp create mode 100644 src/server/game/Combat/UnitEvents.h delete mode 100644 src/server/game/ConditionMgr/ConditionMgr.cpp delete mode 100644 src/server/game/ConditionMgr/ConditionMgr.h create mode 100644 src/server/game/Conditions/ConditionMgr.cpp create mode 100644 src/server/game/Conditions/ConditionMgr.h create mode 100644 src/server/game/DungeonFinding/LFG.h create mode 100644 src/server/game/DungeonFinding/LFGMgr.cpp create mode 100644 src/server/game/DungeonFinding/LFGMgr.h create mode 100644 src/server/game/Entities/Corpse/Corpse.cpp create mode 100644 src/server/game/Entities/Corpse/Corpse.h delete mode 100644 src/server/game/Entities/Creature/NPCHandler.cpp delete mode 100644 src/server/game/Entities/Creature/NPCHandler.h create mode 100644 src/server/game/Entities/DynamicObject/DynamicObject.cpp create mode 100644 src/server/game/Entities/DynamicObject/DynamicObject.h delete mode 100644 src/server/game/Entities/Item/Bag.cpp delete mode 100644 src/server/game/Entities/Item/Bag.h create mode 100644 src/server/game/Entities/Item/Container/Bag.cpp create mode 100644 src/server/game/Entities/Item/Container/Bag.h delete mode 100644 src/server/game/Entities/Item/ItemHandler.cpp delete mode 100644 src/server/game/Entities/Object/Corpse.cpp delete mode 100644 src/server/game/Entities/Object/Corpse.h delete mode 100644 src/server/game/Entities/Object/DynamicObject.cpp delete mode 100644 src/server/game/Entities/Object/DynamicObject.h delete mode 100644 src/server/game/Entities/Object/ObjectAccessor.cpp delete mode 100644 src/server/game/Entities/Object/ObjectAccessor.h delete mode 100644 src/server/game/Entities/Object/ObjectMgr.cpp delete mode 100644 src/server/game/Entities/Object/ObjectMgr.h create mode 100644 src/server/game/Entities/Object/ObjectPosSelector.cpp create mode 100644 src/server/game/Entities/Object/ObjectPosSelector.h delete mode 100644 src/server/game/Entities/Object/UpdateData.cpp delete mode 100644 src/server/game/Entities/Object/UpdateData.h delete mode 100644 src/server/game/Entities/Object/UpdateFields.h delete mode 100644 src/server/game/Entities/Object/UpdateMask.h create mode 100644 src/server/game/Entities/Object/Updates/UpdateData.cpp create mode 100644 src/server/game/Entities/Object/Updates/UpdateData.h create mode 100644 src/server/game/Entities/Object/Updates/UpdateFields.h create mode 100644 src/server/game/Entities/Object/Updates/UpdateMask.h delete mode 100644 src/server/game/Entities/Pet/PetHandler.cpp delete mode 100644 src/server/game/Entities/Player/CharacterHandler.cpp delete mode 100644 src/server/game/Entities/Player/DuelHandler.cpp delete mode 100644 src/server/game/Entities/Player/MiscHandler.cpp delete mode 100644 src/server/game/Entities/Player/PetitionsHandler.cpp delete mode 100644 src/server/game/Entities/Player/TicketHandler.cpp delete mode 100644 src/server/game/Entities/Player/TradeHandler.cpp delete mode 100644 src/server/game/Entities/Player/VoiceChatHandler.cpp create mode 100644 src/server/game/Entities/Transport/Transports.cpp create mode 100644 src/server/game/Entities/Transport/Transports.h delete mode 100644 src/server/game/Events/GlobalEvents.cpp delete mode 100644 src/server/game/Events/GlobalEvents.h delete mode 100644 src/server/game/Events/UnitEvents.h delete mode 100644 src/server/game/Globals/Formulas.h create mode 100644 src/server/game/Globals/GlobalEvents.cpp create mode 100644 src/server/game/Globals/GlobalEvents.h delete mode 100644 src/server/game/Globals/Language.h create mode 100644 src/server/game/Globals/ObjectAccessor.cpp create mode 100644 src/server/game/Globals/ObjectAccessor.h create mode 100644 src/server/game/Globals/ObjectMgr.cpp create mode 100644 src/server/game/Globals/ObjectMgr.h delete mode 100644 src/server/game/Globals/SharedDefines.h delete mode 100644 src/server/game/Groups/GroupHandler.cpp delete mode 100644 src/server/game/Guilds/GuildHandler.cpp delete mode 100644 src/server/game/LookingForGroup/LFG.h delete mode 100644 src/server/game/LookingForGroup/LFGHandler.cpp delete mode 100644 src/server/game/LookingForGroup/LFGMgr.cpp delete mode 100644 src/server/game/LookingForGroup/LFGMgr.h delete mode 100644 src/server/game/Loot/LootHandler.cpp delete mode 100644 src/server/game/Map/Cell/Cell.h delete mode 100644 src/server/game/Map/Cell/CellImpl.h delete mode 100644 src/server/game/Map/Grid/GridDefines.h delete mode 100644 src/server/game/Map/Grid/GridNotifiers.cpp delete mode 100644 src/server/game/Map/Grid/GridNotifiers.h delete mode 100644 src/server/game/Map/Grid/GridNotifiersImpl.h delete mode 100644 src/server/game/Map/Grid/GridStates.cpp delete mode 100644 src/server/game/Map/Grid/GridStates.h delete mode 100644 src/server/game/Map/Grid/ObjectGridLoader.cpp delete mode 100644 src/server/game/Map/Grid/ObjectGridLoader.h delete mode 100644 src/server/game/Map/Map.cpp delete mode 100644 src/server/game/Map/Map.h delete mode 100644 src/server/game/Map/MapInstanced.cpp delete mode 100644 src/server/game/Map/MapInstanced.h delete mode 100644 src/server/game/Map/MapManager.cpp delete mode 100644 src/server/game/Map/MapManager.h delete mode 100644 src/server/game/Map/MapRefManager.h delete mode 100644 src/server/game/Map/MapReference.h delete mode 100644 src/server/game/Map/MapUpdater.cpp delete mode 100644 src/server/game/Map/MapUpdater.h delete mode 100644 src/server/game/Map/ObjectPosSelector.cpp delete mode 100644 src/server/game/Map/ObjectPosSelector.h delete mode 100644 src/server/game/Map/ZoneScript.h create mode 100644 src/server/game/Maps/Cell/Cell.h create mode 100644 src/server/game/Maps/Cell/CellImpl.h create mode 100644 src/server/game/Maps/Grid/GridDefines.h create mode 100644 src/server/game/Maps/Grid/GridNotifiers.cpp create mode 100644 src/server/game/Maps/Grid/GridNotifiers.h create mode 100644 src/server/game/Maps/Grid/GridNotifiersImpl.h create mode 100644 src/server/game/Maps/Grid/GridStates.cpp create mode 100644 src/server/game/Maps/Grid/GridStates.h create mode 100644 src/server/game/Maps/Grid/ObjectGridLoader.cpp create mode 100644 src/server/game/Maps/Grid/ObjectGridLoader.h create mode 100644 src/server/game/Maps/Map.cpp create mode 100644 src/server/game/Maps/Map.h create mode 100644 src/server/game/Maps/MapInstanced.cpp create mode 100644 src/server/game/Maps/MapInstanced.h create mode 100644 src/server/game/Maps/MapManager.cpp create mode 100644 src/server/game/Maps/MapManager.h create mode 100644 src/server/game/Maps/MapRefManager.h create mode 100644 src/server/game/Maps/MapReference.h create mode 100644 src/server/game/Maps/MapUpdater.cpp create mode 100644 src/server/game/Maps/MapUpdater.h create mode 100644 src/server/game/Maps/ZoneScript.h create mode 100644 src/server/game/Miscellaneous/Formulas.h create mode 100644 src/server/game/Miscellaneous/Language.h create mode 100644 src/server/game/Miscellaneous/SharedDefines.h create mode 100644 src/server/game/Movement/MovementGenerator.cpp create mode 100644 src/server/game/Movement/MovementGenerator.h create mode 100644 src/server/game/Movement/MovementGeneratorImpl.h delete mode 100644 src/server/game/Movement/MovementGenerators/MovementGenerator.cpp delete mode 100644 src/server/game/Movement/MovementGenerators/MovementGenerator.h delete mode 100644 src/server/game/Movement/MovementGenerators/MovementGeneratorImpl.h delete mode 100644 src/server/game/Movement/MovementHandler.cpp delete mode 100644 src/server/game/Movement/Path.h delete mode 100644 src/server/game/Movement/TaxiHandler.cpp delete mode 100644 src/server/game/Movement/Transports.cpp delete mode 100644 src/server/game/Movement/Transports.h delete mode 100644 src/server/game/Movement/WaypointManager.cpp delete mode 100644 src/server/game/Movement/WaypointManager.h create mode 100644 src/server/game/Movement/Waypoints/Path.h create mode 100644 src/server/game/Movement/Waypoints/WaypointManager.cpp create mode 100644 src/server/game/Movement/Waypoints/WaypointManager.h delete mode 100644 src/server/game/Opcodes/Opcodes.cpp delete mode 100644 src/server/game/Opcodes/Opcodes.h delete mode 100644 src/server/game/OutdoorPvP/OutdoorPvPEP.cpp delete mode 100644 src/server/game/OutdoorPvP/OutdoorPvPEP.h delete mode 100644 src/server/game/OutdoorPvP/OutdoorPvPHP.cpp delete mode 100644 src/server/game/OutdoorPvP/OutdoorPvPHP.h delete mode 100644 src/server/game/OutdoorPvP/OutdoorPvPNA.cpp delete mode 100644 src/server/game/OutdoorPvP/OutdoorPvPNA.h delete mode 100644 src/server/game/OutdoorPvP/OutdoorPvPSI.cpp delete mode 100644 src/server/game/OutdoorPvP/OutdoorPvPSI.h delete mode 100644 src/server/game/OutdoorPvP/OutdoorPvPTF.cpp delete mode 100644 src/server/game/OutdoorPvP/OutdoorPvPTF.h delete mode 100644 src/server/game/OutdoorPvP/OutdoorPvPZM.cpp delete mode 100644 src/server/game/OutdoorPvP/OutdoorPvPZM.h create mode 100644 src/server/game/OutdoorPvP/Zones/OutdoorPvPEP.cpp create mode 100644 src/server/game/OutdoorPvP/Zones/OutdoorPvPEP.h create mode 100644 src/server/game/OutdoorPvP/Zones/OutdoorPvPHP.cpp create mode 100644 src/server/game/OutdoorPvP/Zones/OutdoorPvPHP.h create mode 100644 src/server/game/OutdoorPvP/Zones/OutdoorPvPNA.cpp create mode 100644 src/server/game/OutdoorPvP/Zones/OutdoorPvPNA.h create mode 100644 src/server/game/OutdoorPvP/Zones/OutdoorPvPSI.cpp create mode 100644 src/server/game/OutdoorPvP/Zones/OutdoorPvPSI.h create mode 100644 src/server/game/OutdoorPvP/Zones/OutdoorPvPTF.cpp create mode 100644 src/server/game/OutdoorPvP/Zones/OutdoorPvPTF.h create mode 100644 src/server/game/OutdoorPvP/Zones/OutdoorPvPZM.cpp create mode 100644 src/server/game/OutdoorPvP/Zones/OutdoorPvPZM.h create mode 100644 src/server/game/PrecompiledHeaders/ScriptedPch.cpp create mode 100644 src/server/game/PrecompiledHeaders/ScriptedPch.h delete mode 100644 src/server/game/Quests/QueryHandler.cpp delete mode 100644 src/server/game/Quests/QuestHandler.cpp delete mode 100644 src/server/game/ScriptMgr/ScriptLoader.cpp delete mode 100644 src/server/game/ScriptMgr/ScriptLoader.h delete mode 100644 src/server/game/ScriptMgr/ScriptMgr.cpp delete mode 100644 src/server/game/ScriptMgr/ScriptMgr.h delete mode 100644 src/server/game/ScriptMgr/ScriptSystem.cpp delete mode 100644 src/server/game/ScriptMgr/ScriptSystem.h delete mode 100644 src/server/game/ScriptMgr/ScriptedPch.cpp delete mode 100644 src/server/game/ScriptMgr/ScriptedPch.h create mode 100644 src/server/game/Scripting/ScriptLoader.cpp create mode 100644 src/server/game/Scripting/ScriptLoader.h create mode 100644 src/server/game/Scripting/ScriptMgr.cpp create mode 100644 src/server/game/Scripting/ScriptMgr.h create mode 100644 src/server/game/Scripting/ScriptSystem.cpp create mode 100644 src/server/game/Scripting/ScriptSystem.h create mode 100644 src/server/game/Server/Protocol/Handlers/AddonHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/AddonHandler.h create mode 100644 src/server/game/Server/Protocol/Handlers/ArenaTeamHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/CalendarHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/ChatHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/CombatHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/DuelHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/GroupHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/GuildHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/ItemHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/LFGHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/LootHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/MiscHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/MovementHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/NPCHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/NPCHandler.h create mode 100644 src/server/game/Server/Protocol/Handlers/PetHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/QueryHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/QuestHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/SkillHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/SpellHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/TicketHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/TradeHandler.cpp create mode 100644 src/server/game/Server/Protocol/Handlers/VoiceChatHandler.cpp create mode 100644 src/server/game/Server/Protocol/Opcodes.cpp create mode 100644 src/server/game/Server/Protocol/Opcodes.h create mode 100644 src/server/game/Server/Protocol/WorldLog.cpp create mode 100644 src/server/game/Server/Protocol/WorldLog.h create mode 100644 src/server/game/Server/WorldSession.cpp create mode 100644 src/server/game/Server/WorldSession.h create mode 100644 src/server/game/Server/WorldSocket.cpp create mode 100644 src/server/game/Server/WorldSocket.h create mode 100644 src/server/game/Server/WorldSocketMgr.cpp create mode 100644 src/server/game/Server/WorldSocketMgr.h delete mode 100644 src/server/game/Skills/SkillHandler.cpp delete mode 100644 src/server/game/Spells/SpellHandler.cpp delete mode 100644 src/server/game/World/WorldLog.cpp delete mode 100644 src/server/game/World/WorldLog.h delete mode 100644 src/server/game/World/WorldSession.cpp delete mode 100644 src/server/game/World/WorldSession.h delete mode 100644 src/server/game/World/WorldSocket.cpp delete mode 100644 src/server/game/World/WorldSocket.h delete mode 100644 src/server/game/World/WorldSocketMgr.cpp delete mode 100644 src/server/game/World/WorldSocketMgr.h (limited to 'src') diff --git a/src/server/game/AI/AuctionHouseBot/AuctionHouseBot.cpp b/src/server/game/AI/AuctionHouseBot/AuctionHouseBot.cpp deleted file mode 100644 index ebbf48e6476..00000000000 --- a/src/server/game/AI/AuctionHouseBot/AuctionHouseBot.cpp +++ /dev/null @@ -1,1860 +0,0 @@ -#include "ObjectMgr.h" -#include "AuctionHouseMgr.h" -#include "AuctionHouseBot.h" -#include - -#include "Policies/SingletonImp.h" -INSTANTIATE_SINGLETON_1(AuctionHouseBot); - -using namespace std; -vector npcItems; -vector lootItems; -vector greyTradeGoodsBin; -vector whiteTradeGoodsBin; -vector greenTradeGoodsBin; -vector blueTradeGoodsBin; -vector purpleTradeGoodsBin; -vector orangeTradeGoodsBin; -vector yellowTradeGoodsBin; -vector greyItemsBin; -vector whiteItemsBin; -vector greenItemsBin; -vector blueItemsBin; -vector purpleItemsBin; -vector orangeItemsBin; -vector yellowItemsBin; -AuctionHouseBot::AuctionHouseBot() -{ - debug_Out = false; - debug_Out_Filters = false; - AHBSeller = false; - AHBBuyer = false; - - //Begin Filters - - Vendor_Items = false; - Loot_Items = false; - Other_Items = false; - Vendor_TGs = false; - Loot_TGs = false; - Other_TGs = false; - - No_Bind = false; - Bind_When_Picked_Up = false; - Bind_When_Equipped = false; - Bind_When_Use = false; - Bind_Quest_Item = false; - - DisableBeta_PTR_Unused = false; - DisablePermEnchant = false; - DisableConjured = false; - DisableGems = false; - DisableMoney = false; - DisableMoneyLoot = false; - DisableLootable = false; - DisableKeys = false; - DisableDuration = false; - DisableBOP_Or_Quest_NoReqLevel = false; - - DisableWarriorItems = false; - DisablePaladinItems = false; - DisableHunterItems = false; - DisableRogueItems = false; - DisablePriestItems = false; - DisableDKItems = false; - DisableShamanItems = false; - DisableMageItems = false; - DisableWarlockItems = false; - DisableUnusedClassItems = false; - DisableDruidItems = false; - - DisableItemsBelowLevel = 0; - DisableItemsAboveLevel = 0; - DisableTGsBelowLevel = 0; - DisableTGsAboveLevel = 0; - DisableItemsBelowGUID = 0; - DisableItemsAboveGUID = 0; - DisableTGsBelowGUID = 0; - DisableTGsAboveGUID = 0; - DisableItemsBelowReqLevel = 0; - DisableItemsAboveReqLevel = 0; - DisableTGsBelowReqLevel = 0; - DisableTGsAboveReqLevel = 0; - DisableItemsBelowReqSkillRank = 0; - DisableItemsAboveReqSkillRank = 0; - DisableTGsBelowReqSkillRank = 0; - DisableTGsAboveReqSkillRank = 0; - - //End Filters - - _lastrun_a = time(NULL); - _lastrun_h = time(NULL); - _lastrun_n = time(NULL); - - AllianceConfig = AHBConfig(2); - HordeConfig = AHBConfig(6); - NeutralConfig = AHBConfig(7); -} - -AuctionHouseBot::~AuctionHouseBot() -{ -} - -void AuctionHouseBot::addNewAuctions(Player *AHBplayer, AHBConfig *config) -{ - if (!AHBSeller) - { - if (debug_Out) sLog.outError("AHSeller: Disabled"); - return; - } - - uint32 minItems = config->GetMinItems(); - uint32 maxItems = config->GetMaxItems(); - - if (maxItems == 0) - { - //if (debug_Out) sLog.outString("AHSeller: Auctions disabled"); - return; - } - - AuctionHouseEntry const* ahEntry = auctionmgr.GetAuctionHouseEntry(config->GetAHFID()); - if (!ahEntry) - { - return; - } - AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(config->GetAHFID()); - if (!auctionHouse) - { - return; - } - - uint32 auctions = auctionHouse->Getcount(); - - if (auctions >= minItems) - { - //if (debug_Out) sLog.outString("AHSeller: Auctions above minimum"); - return; - } - - if (auctions >= maxItems) - { - //if (debug_Out) sLog.outString("AHSeller: Auctions at or above maximum"); - return; - } - - uint32 items = 0; - if ((maxItems - auctions) >= ItemsPerCycle) - items = ItemsPerCycle; - else - items = (maxItems - auctions); - - if (debug_Out) sLog.outString("AHSeller: Adding %u Auctions", items); - - uint32 AuctioneerGUID = 0; - - switch (config->GetAHID()) - { - case 2: - AuctioneerGUID = 79707; //Human in stormwind. - break; - case 6: - AuctioneerGUID = 4656; //orc in Orgrimmar - break; - case 7: - AuctioneerGUID = 23442; //goblin in GZ - break; - default: - if (debug_Out) sLog.outError("AHSeller: GetAHID() - Default switch reached"); - AuctioneerGUID = 23442; //default to neutral 7 - break; - } - - if (debug_Out) sLog.outString("AHSeller: Current Auctineer GUID is %u", AuctioneerGUID); - - uint32 greyTGcount = config->GetPercents(AHB_GREY_TG); - uint32 whiteTGcount = config->GetPercents(AHB_WHITE_TG); - uint32 greenTGcount = config->GetPercents(AHB_GREEN_TG); - uint32 blueTGcount = config->GetPercents(AHB_BLUE_TG); - uint32 purpleTGcount = config->GetPercents(AHB_PURPLE_TG); - uint32 orangeTGcount = config->GetPercents(AHB_ORANGE_TG); - uint32 yellowTGcount = config->GetPercents(AHB_YELLOW_TG); - uint32 greyIcount = config->GetPercents(AHB_GREY_I); - uint32 whiteIcount = config->GetPercents(AHB_WHITE_I); - uint32 greenIcount = config->GetPercents(AHB_GREEN_I); - uint32 blueIcount = config->GetPercents(AHB_BLUE_I); - uint32 purpleIcount = config->GetPercents(AHB_PURPLE_I); - uint32 orangeIcount = config->GetPercents(AHB_ORANGE_I); - uint32 yellowIcount = config->GetPercents(AHB_YELLOW_I); -/* uint32 total = greyTGcount + whiteTGcount + greenTGcount + blueTGcount - + purpleTGcount + orangeTGcount + yellowTGcount - + whiteIcount + greenIcount + blueIcount + purpleIcount - + orangeIcount + yellowIcount; -*/ - uint32 greyTGoods = config->GetItemCounts(AHB_GREY_TG); - uint32 whiteTGoods = config->GetItemCounts(AHB_WHITE_TG); - uint32 greenTGoods = config->GetItemCounts(AHB_GREEN_TG); - uint32 blueTGoods = config->GetItemCounts(AHB_BLUE_TG); - uint32 purpleTGoods = config->GetItemCounts(AHB_PURPLE_TG); - uint32 orangeTGoods = config->GetItemCounts(AHB_ORANGE_TG); - uint32 yellowTGoods = config->GetItemCounts(AHB_YELLOW_TG); - - uint32 greyItems = config->GetItemCounts(AHB_GREY_I); - uint32 whiteItems = config->GetItemCounts(AHB_WHITE_I); - uint32 greenItems = config->GetItemCounts(AHB_GREEN_I); - uint32 blueItems = config->GetItemCounts(AHB_BLUE_I); - uint32 purpleItems = config->GetItemCounts(AHB_PURPLE_I); - uint32 orangeItems = config->GetItemCounts(AHB_ORANGE_I); - uint32 yellowItems = config->GetItemCounts(AHB_YELLOW_I); - if (debug_Out) sLog.outString("AHSeller: %u items", items); - - // only insert a few at a time, so as not to peg the processor - for (uint32 cnt = 1; cnt <= items; cnt++) - { - if (debug_Out) sLog.outString("AHSeller: %u count", cnt); - uint32 itemID = 0; - uint32 itemColor = 99; - uint32 loopbreaker = 0; - while (itemID == 0 && loopbreaker <= 50) - { - ++loopbreaker; - uint32 choice = urand(0, 13); - itemColor = choice; - switch (choice) - { - case 0: - { - if ((greyItemsBin.size() > 0) && (greyItems < greyIcount)) - itemID = greyItemsBin[urand(0, greyItemsBin.size() - 1)]; - else continue; - break; - } - case 1: - { - if ((whiteItemsBin.size() > 0) && (whiteItems < whiteIcount)) - itemID = whiteItemsBin[urand(0, whiteItemsBin.size() - 1)]; - else continue; - break; - } - case 2: - { - if ((greenItemsBin.size() > 0) && (greenItems < greenIcount)) - itemID = greenItemsBin[urand(0, greenItemsBin.size() - 1)]; - else continue; - break; - } - case 3: - { - if ((blueItemsBin.size() > 0) && (blueItems < blueIcount)) - itemID = blueItemsBin[urand(0, blueItemsBin.size() - 1)]; - else continue; - break; - } - case 4: - { - if ((purpleItemsBin.size() > 0) && (purpleItems < purpleIcount)) - itemID = purpleItemsBin[urand(0, purpleItemsBin.size() - 1)]; - else continue; - break; - } - case 5: - { - if ((orangeItemsBin.size() > 0) && (orangeItems < orangeIcount)) - itemID = orangeItemsBin[urand(0, orangeItemsBin.size() - 1)]; - else continue; - break; - } - case 6: - { - if ((yellowItemsBin.size() > 0) && (yellowItems < yellowIcount)) - itemID = yellowItemsBin[urand(0, yellowItemsBin.size() - 1)]; - else continue; - break; - } - case 7: - { - if ((greyTradeGoodsBin.size() > 0) && (greyTGoods < greyTGcount)) - itemID = greyTradeGoodsBin[urand(0, greyTradeGoodsBin.size() - 1)]; - else continue; - break; - } - case 8: - { - if ((whiteTradeGoodsBin.size() > 0) && (whiteTGoods < whiteTGcount)) - itemID = whiteTradeGoodsBin[urand(0, whiteTradeGoodsBin.size() - 1)]; - else continue; - break; - } - case 9: - { - if ((greenTradeGoodsBin.size() > 0) && (greenTGoods < greenTGcount)) - itemID = greenTradeGoodsBin[urand(0, greenTradeGoodsBin.size() - 1)]; - else continue; - break; - } - case 10: - { - if ((blueTradeGoodsBin.size() > 0) && (blueTGoods < blueTGcount)) - itemID = blueTradeGoodsBin[urand(0, blueTradeGoodsBin.size() - 1)]; - else continue; - break; - } - case 11: - { - if ((purpleTradeGoodsBin.size() > 0) && (purpleTGoods < purpleTGcount)) - itemID = purpleTradeGoodsBin[urand(0, purpleTradeGoodsBin.size() - 1)]; - else continue; - break; - } - case 12: - { - if ((orangeTradeGoodsBin.size() > 0) && (orangeTGoods < orangeTGcount)) - itemID = orangeTradeGoodsBin[urand(0, orangeTradeGoodsBin.size() - 1)]; - else continue; - break; - } - case 13: - { - if ((yellowTradeGoodsBin.size() > 0) && (yellowTGoods < yellowTGcount)) - itemID = yellowTradeGoodsBin[urand(0, yellowTradeGoodsBin.size() - 1)]; - else continue; - break; - } - default: - { - if (debug_Out) sLog.outError("AHSeller: itemID Switch - Default Reached"); - break; - } - } - - if (itemID == 0) - { - if (debug_Out) sLog.outError("AHSeller: Item::CreateItem() - ItemID is 0"); - continue; - } - - ItemPrototype const* prototype = objmgr.GetItemPrototype(itemID); - if (prototype == NULL) - { - if (debug_Out) sLog.outError("AHSeller: Huh?!?! prototype == NULL"); - continue; - } - - Item* item = Item::CreateItem(itemID, 1, AHBplayer); - if (item == NULL) - { - if (debug_Out) sLog.outError("AHSeller: Item::CreateItem() returned NULL"); - break; - } - item->AddToUpdateQueueOf(AHBplayer); - - uint32 randomPropertyId = Item::GenerateItemRandomPropertyId(itemID); - if (randomPropertyId != 0) - item->SetItemRandomProperties(randomPropertyId); - - uint64 buyoutPrice = 0; - uint64 bidPrice = 0; - uint32 stackCount = 1; - - switch (SellMethod) - { - case 0: - buyoutPrice = prototype->SellPrice; - break; - case 1: - buyoutPrice = prototype->BuyPrice; - break; - } - - if ((prototype->Quality >= 0) && (prototype->Quality <= AHB_MAX_QUALITY)) - { - if (config->GetMaxStack(prototype->Quality) > 1 && item->GetMaxStackCount() > 1) - stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(prototype->Quality))); - else if (config->GetMaxStack(prototype->Quality) == 0 && item->GetMaxStackCount() > 1) - stackCount = urand(1, item->GetMaxStackCount()); - else - stackCount = 1; - buyoutPrice *= urand(config->GetMinPrice(prototype->Quality), config->GetMaxPrice(prototype->Quality)); - buyoutPrice /= 100; - bidPrice = buyoutPrice * urand(config->GetMinBidPrice(prototype->Quality), config->GetMaxBidPrice(prototype->Quality)); - bidPrice /= 100; - } - else - { - // quality is something it shouldn't be, let's get out of here - if (debug_Out) sLog.outError("AHBuyer: Quality %u not Supported", prototype->Quality); - item->RemoveFromUpdateQueueOf(AHBplayer); - continue; - } - - uint32 etime = urand(1,3); - switch(etime) - { - case 1: - etime = 43200; - break; - case 2: - etime = 86400; - break; - case 3: - etime = 172800; - break; - default: - etime = 86400; - break; - } - item->SetCount(stackCount); - - uint32 dep = auctionmgr.GetAuctionDeposit(ahEntry, etime, item); - - AuctionEntry* auctionEntry = new AuctionEntry; - auctionEntry->Id = objmgr.GenerateAuctionID(); - auctionEntry->auctioneer = AuctioneerGUID; - auctionEntry->item_guidlow = item->GetGUIDLow(); - auctionEntry->item_template = item->GetEntry(); - auctionEntry->owner = AHBplayer->GetGUIDLow(); - auctionEntry->startbid = bidPrice * stackCount; - auctionEntry->buyout = buyoutPrice * stackCount; - auctionEntry->bidder = 0; - auctionEntry->bid = 0; - auctionEntry->deposit = dep; - auctionEntry->expire_time = (time_t) etime + time(NULL); - auctionEntry->auctionHouseEntry = ahEntry; - item->SaveToDB(); - item->RemoveFromUpdateQueueOf(AHBplayer); - auctionmgr.AddAItem(item); - auctionHouse->AddAuction(auctionEntry); - auctionEntry->SaveToDB(); - - switch(itemColor) - { - case 0: - ++greyItems; - break; - case 1: - ++whiteItems; - break; - case 2: - ++greenItems; - break; - case 3: - ++blueItems; - break; - case 4: - ++purpleItems; - break; - case 5: - ++orangeItems; - break; - case 6: - ++yellowItems; - break; - case 7: - ++greyTGoods; - break; - case 8: - ++whiteTGoods; - break; - case 9: - ++greenTGoods; - break; - case 10: - ++blueTGoods; - break; - case 11: - ++purpleTGoods; - break; - case 12: - ++orangeTGoods; - break; - case 13: - ++yellowTGoods; - break; - default: - break; - } - } - } -} -void AuctionHouseBot::addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, WorldSession *session) -{ - if (!AHBBuyer) - { - if (debug_Out) sLog.outError("AHBuyer: Disabled"); - return; - } - - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT id FROM auctionhouse WHERE itemowner<>%u AND buyguid<>%u", AHBplayerGUID, AHBplayerGUID); - - if (!result) - return; - - if (result->GetRowCount() == 0) - return; - - // Fetches content of selected AH - AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(config->GetAHFID()); - vector possibleBids; - - do - { - uint32 tmpdata = result->Fetch()->GetUInt32(); - possibleBids.push_back(tmpdata); - }while (result->NextRow()); - - for (uint32 count = 1; count <= config->GetBidsPerInterval(); ++count) - { - // Do we have anything to bid? If not, stop here. - if (possibleBids.empty()) - { - //if (debug_Out) sLog.outString("AHBuyer: I have no items to bid on."); - count = config->GetBidsPerInterval(); - continue; - } - - // Choose random auction from possible auctions - uint32 vectorPos = urand(0, possibleBids.size() - 1); - vector::iterator iter = possibleBids.begin(); - advance(iter, vectorPos); - - // from auctionhousehandler.cpp, creates auction pointer & player pointer - AuctionEntry* auction = auctionHouse->GetAuction(*iter); - - // Erase the auction from the vector to prevent bidding on item in next iteration. - possibleBids.erase(iter); - - if (!auction) - continue; - - // get exact item information - Item *pItem = auctionmgr.GetAItem(auction->item_guidlow); - if (!pItem) - { - if (debug_Out) sLog.outError("AHBuyer: Item %u doesn't exist, perhaps bought already?", auction->item_guidlow); - continue; - } - - // get item prototype - ItemPrototype const* prototype = objmgr.GetItemPrototype(auction->item_template); - - // check which price we have to use, startbid or if it is bidded already - uint32 currentprice; - if (auction->bid) - currentprice = auction->bid; - else - currentprice = auction->startbid; - - // Prepare portion from maximum bid - double bidrate = static_cast(urand(1, 100)) / 100; - long double bidMax = 0; - - // check that bid has acceptable value and take bid based on vendorprice, stacksize and quality - switch (BuyMethod) - { - case 0: - { - if ((prototype->Quality >= 0) && (prototype->Quality <= AHB_MAX_QUALITY)) - { - if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(prototype->Quality)) - bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(prototype->Quality); - } - else - { - // quality is something it shouldn't be, let's get out of here - if (debug_Out) sLog.outError("AHBuyer: Quality %u not Supported", prototype->Quality); - continue; - } - break; - } - case 1: - { - if ((prototype->Quality >= 0) && (prototype->Quality <= AHB_MAX_QUALITY)) - { - if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(prototype->Quality)) - bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(prototype->Quality); - } - else - { - // quality is something it shouldn't be, let's get out of here - if (debug_Out) sLog.outError("AHBuyer: Quality %u not Supported", prototype->Quality); - continue; - } - break; - } - } - - // check some special items, and do recalculating to their prices - switch (prototype->Class) - { - // ammo - case 6: - bidMax = 0; - break; - default: - break; - } - - if (bidMax == 0) - { - // quality check failed to get bidmax, let's get out of here - continue; - } - - // Calculate our bid - long double bidvalue = currentprice + ((bidMax - currentprice) * bidrate); - // Convert to uint32 - uint32 bidprice = static_cast(bidvalue); - - // Check our bid is high enough to be valid. If not, correct it to minimum. - if ((currentprice + auction->GetAuctionOutBid()) > bidprice) - bidprice = currentprice + auction->GetAuctionOutBid(); - - if (debug_Out) - { - sLog.outString("-------------------------------------------------"); - sLog.outString("AHBuyer: Info for Auction #%u:", auction->Id); - sLog.outString("AHBuyer: AuctionHouse: %u", auction->GetHouseId()); - sLog.outString("AHBuyer: Auctioneer: %u", auction->auctioneer); - sLog.outString("AHBuyer: Owner: %u", auction->owner); - sLog.outString("AHBuyer: Bidder: %u", auction->bidder); - sLog.outString("AHBuyer: Starting Bid: %u", auction->startbid); - sLog.outString("AHBuyer: Current Bid: %u", currentprice); - sLog.outString("AHBuyer: Buyout: %u", auction->buyout); - sLog.outString("AHBuyer: Deposit: %u", auction->deposit); - sLog.outString("AHBuyer: Expire Time: %u", auction->expire_time); - sLog.outString("AHBuyer: Bid Rate: %f", bidrate); - sLog.outString("AHBuyer: Bid Max: %f", bidMax); - sLog.outString("AHBuyer: Bid Value: %f", bidvalue); - sLog.outString("AHBuyer: Bid Price: %u", bidprice); - sLog.outString("AHBuyer: Item GUID: %u", auction->item_guidlow); - sLog.outString("AHBuyer: Item Template: %u", auction->item_template); - sLog.outString("AHBuyer: Item Info:"); - sLog.outString("AHBuyer: Item ID: %u", prototype->ItemId); - sLog.outString("AHBuyer: Buy Price: %u", prototype->BuyPrice); - sLog.outString("AHBuyer: Sell Price: %u", prototype->SellPrice); - sLog.outString("AHBuyer: Bonding: %u", prototype->Bonding); - sLog.outString("AHBuyer: Quality: %u", prototype->Quality); - sLog.outString("AHBuyer: Item Level: %u", prototype->ItemLevel); - sLog.outString("AHBuyer: Ammo Type: %u", prototype->AmmoType); - sLog.outString("-------------------------------------------------"); - } - - // Check whether we do normal bid, or buyout - if ((bidprice < auction->buyout) || (auction->buyout == 0)) - { - - if (auction->bidder > 0) - { - if (auction->bidder == AHBplayer->GetGUIDLow()) - { - //pl->ModifyMoney(-int32(price - auction->bid)); - } - else - { - // mail to last bidder and return money - session->SendAuctionOutbiddedMail(auction , bidprice); - //pl->ModifyMoney(-int32(price)); - } - } - - auction->bidder = AHBplayer->GetGUIDLow(); - auction->bid = bidprice; - - // Saving auction into database - CharacterDatabase.PExecute("UPDATE auctionhouse SET buyguid = '%u',lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id); - } - else - { - //buyout - if ((auction->bidder) && (AHBplayer->GetGUIDLow() != auction->bidder)) - { - session->SendAuctionOutbiddedMail(auction, auction->buyout); - } - auction->bidder = AHBplayer->GetGUIDLow(); - auction->bid = auction->buyout; - - // Send mails to buyer & seller - auctionmgr.SendAuctionSalePendingMail(auction); - auctionmgr.SendAuctionSuccessfulMail(auction); - auctionmgr.SendAuctionWonMail(auction); - auction->DeleteFromDB(); - uint32 item_template = auction->item_template; - auctionmgr.RemoveAItem(auction->item_guidlow); - auctionHouse->RemoveAuction(auction, item_template); - } - } -} - -void AuctionHouseBot::Update() -{ - time_t _newrun = time(NULL); - if ((!AHBSeller) && (!AHBBuyer)) - return; - - WorldSession _session(AHBplayerAccount, NULL, SEC_PLAYER, true, 0, LOCALE_enUS); - Player _AHBplayer(&_session); - _AHBplayer.Initialize(AHBplayerGUID); - ObjectAccessor::Instance().AddObject(&_AHBplayer); - - // Add New Bids - if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) - { - addNewAuctions(&_AHBplayer, &AllianceConfig); - if (((_newrun - _lastrun_a) >= (AllianceConfig.GetBiddingInterval() * MINUTE)) && (AllianceConfig.GetBidsPerInterval() > 0)) - { - //if (debug_Out) sLog.outString("AHBuyer: %u seconds have passed since last bid", (_newrun - _lastrun_a)); - //if (debug_Out) sLog.outString("AHBuyer: Bidding on Alliance Auctions"); - addNewAuctionBuyerBotBid(&_AHBplayer, &AllianceConfig, &_session); - _lastrun_a = _newrun; - } - - addNewAuctions(&_AHBplayer, &HordeConfig); - if (((_newrun - _lastrun_h) >= (HordeConfig.GetBiddingInterval() * MINUTE)) && (HordeConfig.GetBidsPerInterval() > 0)) - { - //if (debug_Out) sLog.outString("AHBuyer: %u seconds have passed since last bid", (_newrun - _lastrun_h)); - //if (debug_Out) sLog.outString("AHBuyer: Bidding on Horde Auctions"); - addNewAuctionBuyerBotBid(&_AHBplayer, &HordeConfig, &_session); - _lastrun_h = _newrun; - } - } - - addNewAuctions(&_AHBplayer, &NeutralConfig); - if (((_newrun - _lastrun_n) >= (NeutralConfig.GetBiddingInterval() * MINUTE)) && (NeutralConfig.GetBidsPerInterval() > 0)) - { - //if (debug_Out) sLog.outString("AHBuyer: %u seconds have passed since last bid", (_newrun - _lastrun_n)); - //if (debug_Out) sLog.outString("AHBuyer: Bidding on Neutral Auctions"); - addNewAuctionBuyerBotBid(&_AHBplayer, &NeutralConfig, &_session); - _lastrun_n = _newrun; - } - ObjectAccessor::Instance().RemoveObject(&_AHBplayer); -} - -void AuctionHouseBot::Initialize() -{ - debug_Out = sConfig.GetBoolDefault("AuctionHouseBot.DEBUG", false); - debug_Out_Filters = sConfig.GetBoolDefault("AuctionHouseBot.DEBUG_FILTERS", false); - - AHBSeller = sConfig.GetBoolDefault("AuctionHouseBot.EnableSeller", false); - AHBBuyer = sConfig.GetBoolDefault("AuctionHouseBot.EnableBuyer", false); - SellMethod = sConfig.GetBoolDefault("AuctionHouseBot.UseBuyPriceForSeller", false); - BuyMethod = sConfig.GetBoolDefault("AuctionHouseBot.UseBuyPriceForBuyer", false); - - AHBplayerAccount = sConfig.GetIntDefault("AuctionHouseBot.Account", 0); - AHBplayerGUID = sConfig.GetIntDefault("AuctionHouseBot.GUID", 0); - ItemsPerCycle = sConfig.GetIntDefault("AuctionHouseBot.ItemsPerCycle", 200); - - //Begin Filters - - Vendor_Items = sConfig.GetBoolDefault("AuctionHouseBot.VendorItems", false); - Loot_Items = sConfig.GetBoolDefault("AuctionHouseBot.LootItems", true); - Other_Items = sConfig.GetBoolDefault("AuctionHouseBot.OtherItems", false); - Vendor_TGs = sConfig.GetBoolDefault("AuctionHouseBot.VendorTradeGoods", false); - Loot_TGs = sConfig.GetBoolDefault("AuctionHouseBot.LootTradeGoods", true); - Other_TGs = sConfig.GetBoolDefault("AuctionHouseBot.OtherTradeGoods", false); - - No_Bind = sConfig.GetBoolDefault("AuctionHouseBot.No_Bind", true); - Bind_When_Picked_Up = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Picked_Up", false); - Bind_When_Equipped = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Equipped", true); - Bind_When_Use = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Use", true); - Bind_Quest_Item = sConfig.GetBoolDefault("AuctionHouseBot.Bind_Quest_Item", false); - - DisableBeta_PTR_Unused = sConfig.GetBoolDefault("AuctionHouseBot.DisableBeta_PTR_Unused", false); - DisablePermEnchant = sConfig.GetBoolDefault("AuctionHouseBot.DisablePermEnchant", false); - DisableConjured = sConfig.GetBoolDefault("AuctionHouseBot.DisableConjured", false); - DisableGems = sConfig.GetBoolDefault("AuctionHouseBot.DisableGems", false); - DisableMoney = sConfig.GetBoolDefault("AuctionHouseBot.DisableMoney", false); - DisableMoneyLoot = sConfig.GetBoolDefault("AuctionHouseBot.DisableMoneyLoot", false); - DisableLootable = sConfig.GetBoolDefault("AuctionHouseBot.DisableLootable", false); - DisableKeys = sConfig.GetBoolDefault("AuctionHouseBot.DisableKeys", false); - DisableDuration = sConfig.GetBoolDefault("AuctionHouseBot.DisableDuration", false); - DisableBOP_Or_Quest_NoReqLevel = sConfig.GetBoolDefault("AuctionHouseBot.DisableBOP_Or_Quest_NoReqLevel", false); - - DisableWarriorItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableWarriorItems", false); - DisablePaladinItems = sConfig.GetBoolDefault("AuctionHouseBot.DisablePaladinItems", false); - DisableHunterItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableHunterItems", false); - DisableRogueItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableRogueItems", false); - DisablePriestItems = sConfig.GetBoolDefault("AuctionHouseBot.DisablePriestItems", false); - DisableDKItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableDKItems", false); - DisableShamanItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableShamanItems", false); - DisableMageItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableMageItems", false); - DisableWarlockItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableWarlockItems", false); - DisableUnusedClassItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableUnusedClassItems", false); - DisableDruidItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableDruidItems", false); - - DisableItemsBelowLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowLevel", 0); - DisableItemsAboveLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveLevel", 0); - DisableTGsBelowLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowLevel", 0); - DisableTGsAboveLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveLevel", 0); - DisableItemsBelowGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowGUID", 0); - DisableItemsAboveGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveGUID", 0); - DisableTGsBelowGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowGUID", 0); - DisableTGsAboveGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveGUID", 0); - DisableItemsBelowReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowReqLevel", 0); - DisableItemsAboveReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveReqLevel", 0); - DisableTGsBelowReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowReqLevel", 0); - DisableTGsAboveReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveReqLevel", 0); - DisableItemsBelowReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowReqSkillRank", 0); - DisableItemsAboveReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveReqSkillRank", 0); - DisableTGsBelowReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowReqSkillRank", 0); - DisableTGsAboveReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveReqSkillRank", 0); - - //End Filters - if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) - { - LoadValues(&AllianceConfig); - LoadValues(&HordeConfig); - } - LoadValues(&NeutralConfig); - - // - // check if the AHBot account/GUID in the config actually exists - // - - if ((AHBplayerAccount != 0) || (AHBplayerGUID != 0)) - { - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT 1 FROM characters WHERE account = %u AND guid = %u", AHBplayerAccount, AHBplayerGUID); - if (!result) - { - sLog.outError("AuctionHouseBot: The account/GUID-information set for your AHBot is incorrect (account: %u guid: %u)", AHBplayerAccount, AHBplayerGUID); - return; - } - } - - if (AHBSeller) - { - QueryResult_AutoPtr results = QueryResult_AutoPtr(NULL); - char npcQuery[] = "SELECT distinct item FROM npc_vendor"; - results = WorldDatabase.Query(npcQuery); - if (results != NULL) - { - do - { - Field* fields = results->Fetch(); - npcItems.push_back(fields[0].GetUInt32()); - - } while (results->NextRow()); - } - else - { - if (debug_Out) sLog.outString("AuctionHouseBot: \"%s\" failed", npcQuery); - } - - char lootQuery[] = "SELECT item FROM creature_loot_template UNION " - "SELECT item FROM reference_loot_template UNION " - "SELECT item FROM disenchant_loot_template UNION " - "SELECT item FROM fishing_loot_template UNION " - "SELECT item FROM gameobject_loot_template UNION " - "SELECT item FROM item_loot_template UNION " - "SELECT item FROM milling_loot_template UNION " - "SELECT item FROM pickpocketing_loot_template UNION " - "SELECT item FROM prospecting_loot_template UNION " - "SELECT item FROM skinning_loot_template"; - - results = WorldDatabase.Query(lootQuery); - if (results != NULL) - { - do - { - Field* fields = results->Fetch(); - lootItems.push_back(fields[0].GetUInt32()); - - } while (results->NextRow()); - } - else - { - if (debug_Out) sLog.outString("AuctionHouseBot: \"%s\" failed", lootQuery); - } - - for (uint32 itemID = 0; itemID < sItemStorage.MaxEntry; itemID++) - { - ItemPrototype const* prototype = objmgr.GetItemPrototype(itemID); - - if (prototype == NULL) - continue; - - switch (prototype->Bonding) - { - case NO_BIND: - if (!No_Bind) - continue; - break; - case BIND_WHEN_PICKED_UP: - if (!Bind_When_Picked_Up) - continue; - break; - case BIND_WHEN_EQUIPED: - if (!Bind_When_Equipped) - continue; - break; - case BIND_WHEN_USE: - if (!Bind_When_Use) - continue; - break; - case BIND_QUEST_ITEM: - if (!Bind_Quest_Item) - continue; - break; - default: - continue; - break; - } - - switch (SellMethod) - { - case 0: - if (prototype->SellPrice == 0) - continue; - break; - case 1: - if (prototype->BuyPrice == 0) - continue; - break; - } - - if ((prototype->Quality < 0) || (prototype->Quality > 6)) - continue; - - if ((Vendor_Items == 0) && !(prototype->Class == ITEM_CLASS_TRADE_GOODS)) - { - bool isVendorItem = false; - - for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorItem); i++) - { - if (itemID == npcItems[i]) - isVendorItem = true; - } - - if (isVendorItem) - continue; - } - - if ((Vendor_TGs == 0) && (prototype->Class == ITEM_CLASS_TRADE_GOODS)) - { - bool isVendorTG = false; - - for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorTG); i++) - { - if (itemID == npcItems[i]) - isVendorTG = true; - } - - if (isVendorTG) - continue; - } - - if ((Loot_Items == 0) && !(prototype->Class == ITEM_CLASS_TRADE_GOODS)) - { - bool isLootItem = false; - - for (unsigned int i = 0; (i < lootItems.size()) && (!isLootItem); i++) - { - if (itemID == lootItems[i]) - isLootItem = true; - } - - if (isLootItem) - continue; - } - - if ((Loot_TGs == 0) && (prototype->Class == ITEM_CLASS_TRADE_GOODS)) - { - bool isLootTG = false; - - for (unsigned int i = 0; (i < lootItems.size()) && (!isLootTG); i++) - { - if (itemID == lootItems[i]) - isLootTG = true; - } - - if (isLootTG) - continue; - } - - if ((Other_Items == 0) && !(prototype->Class == ITEM_CLASS_TRADE_GOODS)) - { - bool isVendorItem = false; - bool isLootItem = false; - - for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorItem); i++) - { - if (itemID == npcItems[i]) - isVendorItem = true; - } - for (unsigned int i = 0; (i < lootItems.size()) && (!isLootItem); i++) - { - if (itemID == lootItems[i]) - isLootItem = true; - } - if ((!isLootItem) && (!isVendorItem)) - continue; - } - - if ((Other_TGs == 0) && (prototype->Class == ITEM_CLASS_TRADE_GOODS)) - { - bool isVendorTG = false; - bool isLootTG = false; - - for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorTG); i++) - { - if (itemID == npcItems[i]) - isVendorTG = true; - } - for (unsigned int i = 0; (i < lootItems.size()) && (!isLootTG); i++) - { - if (itemID == lootItems[i]) - isLootTG = true; - } - if ((!isLootTG) && (!isVendorTG)) - continue; - } - - //TODO:Make list of items and create a vector - // Disable PTR/Beta/Unused items - if ((DisableBeta_PTR_Unused) && ((prototype->ItemId == 21878) || (prototype->ItemId == 27774) || (prototype->ItemId == 27811) || (prototype->ItemId == 28117) || (prototype->ItemId == 28112))) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (PTR/Beta/Unused Item)", prototype->ItemId); - continue; - } - - // Disable permanent enchants items - if ((DisablePermEnchant) && (prototype->Class == ITEM_CLASS_PERMANENT)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Permanent Enchant Item)", prototype->ItemId); - continue; - } - - // Disable conjured items - if ((DisableConjured) && (prototype->IsConjuredConsumable())) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Conjured Consumable)", prototype->ItemId); - continue; - } - - // Disable gems - if ((DisableGems) && (prototype->Class == ITEM_CLASS_GEM)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Gem)", prototype->ItemId); - continue; - } - - // Disable money - if ((DisableMoney) && (prototype->Class == ITEM_CLASS_MONEY)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Money)", prototype->ItemId); - continue; - } - - // Disable moneyloot - if ((DisableMoneyLoot) && (prototype->MinMoneyLoot > 0)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (MoneyLoot)", prototype->ItemId); - continue; - } - - // Disable lootable items - if ((DisableLootable) && (prototype->Flags & 4)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Lootable Item)", prototype->ItemId); - continue; - } - - // Disable Keys - if ((DisableKeys) && (prototype->Class == ITEM_CLASS_KEY)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Quest Item)", prototype->ItemId); - continue; - } - - // Disable items with duration - if ((DisableDuration) && (prototype->Duration > 0)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Has a Duration)", prototype->ItemId); - continue; - } - - // Disable items which are BOP or Quest Items and have a required level lower than the item level - if ((DisableBOP_Or_Quest_NoReqLevel) && ((prototype->Bonding == BIND_WHEN_PICKED_UP || prototype->Bonding == BIND_QUEST_ITEM) && (prototype->RequiredLevel < prototype->ItemLevel))) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (BOP or BQI and Required Level is less than Item Level)", prototype->ItemId); - continue; - } - - // Disable items specifically for Warrior - if ((DisableWarriorItems) && (prototype->AllowableClass == 1)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Warrior Item)", prototype->ItemId); - continue; - } - - // Disable items specifically for Paladin - if ((DisablePaladinItems) && (prototype->AllowableClass == 2)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Paladin Item)", prototype->ItemId); - continue; - } - - // Disable items specifically for Hunter - if ((DisableHunterItems) && (prototype->AllowableClass == 4)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Hunter Item)", prototype->ItemId); - continue; - } - - // Disable items specifically for Rogue - if ((DisableRogueItems) && (prototype->AllowableClass == 8)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Rogue Item)", prototype->ItemId); - continue; - } - - // Disable items specifically for Priest - if ((DisablePriestItems) && (prototype->AllowableClass == 16)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Priest Item)", prototype->ItemId); - continue; - } - - // Disable items specifically for DK - if ((DisableDKItems) && (prototype->AllowableClass == 32)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (DK Item)", prototype->ItemId); - continue; - } - - // Disable items specifically for Shaman - if ((DisableShamanItems) && (prototype->AllowableClass == 64)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Shaman Item)", prototype->ItemId); - continue; - } - - // Disable items specifically for Mage - if ((DisableMageItems) && (prototype->AllowableClass == 128)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Mage Item)", prototype->ItemId); - continue; - } - - // Disable items specifically for Warlock - if ((DisableWarlockItems) && (prototype->AllowableClass == 256)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Warlock Item)", prototype->ItemId); - continue; - } - - // Disable items specifically for Unused Class - if ((DisableUnusedClassItems) && (prototype->AllowableClass == 512)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Unused Item)", prototype->ItemId); - continue; - } - - // Disable items specifically for Druid - if ((DisableDruidItems) && (prototype->AllowableClass == 1024)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Druid Item)", prototype->ItemId); - continue; - } - - // Disable Items below level X - if ((DisableItemsBelowLevel) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel < DisableItemsBelowLevel)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel); - continue; - } - - // Disable Items above level X - if ((DisableItemsAboveLevel) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel > DisableItemsAboveLevel)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel); - continue; - } - - // Disable Trade Goods below level X - if ((DisableTGsBelowLevel) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel < DisableTGsBelowLevel)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Trade Good %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel); - continue; - } - - // Disable Trade Goods above level X - if ((DisableTGsAboveLevel) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel > DisableTGsAboveLevel)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Trade Good %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel); - continue; - } - - // Disable Items below GUID X - if ((DisableItemsBelowGUID) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId < DisableItemsBelowGUID)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel); - continue; - } - - // Disable Items above GUID X - if ((DisableItemsAboveGUID) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId > DisableItemsAboveGUID)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel); - continue; - } - - // Disable Trade Goods below GUID X - if ((DisableTGsBelowGUID) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId < DisableTGsBelowGUID)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel); - continue; - } - - // Disable Trade Goods above GUID X - if ((DisableTGsAboveGUID) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId > DisableTGsAboveGUID)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel); - continue; - } - - // Disable Items for level lower than X - if ((DisableItemsBelowReqLevel) && (prototype->RequiredLevel < DisableItemsBelowReqLevel)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel); - continue; - } - - // Disable Items for level higher than X - if ((DisableItemsAboveReqLevel) && (prototype->RequiredLevel > DisableItemsAboveReqLevel)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel); - continue; - } - - // Disable Trade Goods for level lower than X - if ((DisableTGsBelowReqLevel) && (prototype->RequiredLevel < DisableTGsBelowReqLevel)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Trade Good %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel); - continue; - } - - // Disable Trade Goods for level higher than X - if ((DisableTGsAboveReqLevel) && (prototype->RequiredLevel > DisableTGsAboveReqLevel)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Trade Good %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel); - continue; - } - - // Disable Items that require skill lower than X - if ((DisableItemsBelowReqSkillRank) && (prototype->RequiredSkillRank < DisableItemsBelowReqSkillRank)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank); - continue; - } - - // Disable Items that require skill higher than X - if ((DisableItemsAboveReqSkillRank) && (prototype->RequiredSkillRank > DisableItemsAboveReqSkillRank)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank); - continue; - } - - // Disable Trade Goods that require skill lower than X - if ((DisableTGsBelowReqSkillRank) && (prototype->RequiredSkillRank < DisableTGsBelowReqSkillRank)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank); - continue; - } - - // Disable Trade Goods that require skill higher than X - if ((DisableTGsAboveReqSkillRank) && (prototype->RequiredSkillRank > DisableTGsAboveReqSkillRank)) - { - if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank); - continue; - } - - switch (prototype->Quality) - { - case AHB_GREY: - if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - greyTradeGoodsBin.push_back(itemID); - else - greyItemsBin.push_back(itemID); - break; - - case AHB_WHITE: - if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - whiteTradeGoodsBin.push_back(itemID); - else - whiteItemsBin.push_back(itemID); - break; - - case AHB_GREEN: - if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - greenTradeGoodsBin.push_back(itemID); - else - greenItemsBin.push_back(itemID); - break; - - case AHB_BLUE: - if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - blueTradeGoodsBin.push_back(itemID); - else - blueItemsBin.push_back(itemID); - break; - - case AHB_PURPLE: - if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - purpleTradeGoodsBin.push_back(itemID); - else - purpleItemsBin.push_back(itemID); - break; - - case AHB_ORANGE: - if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - orangeTradeGoodsBin.push_back(itemID); - else - orangeItemsBin.push_back(itemID); - break; - - case AHB_YELLOW: - if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - yellowTradeGoodsBin.push_back(itemID); - else - yellowItemsBin.push_back(itemID); - break; - } - } - - if ((greyTradeGoodsBin.size() == 0) && - (whiteTradeGoodsBin.size() == 0) && - (greenTradeGoodsBin.size() == 0) && - (blueTradeGoodsBin.size() == 0) && - (purpleTradeGoodsBin.size() == 0) && - (orangeTradeGoodsBin.size() == 0) && - (yellowTradeGoodsBin.size() == 0) && - (greyItemsBin.size() == 0) && - (whiteItemsBin.size() == 0) && - (greenItemsBin.size() == 0) && - (blueItemsBin.size() == 0) && - (purpleItemsBin.size() == 0) && - (orangeItemsBin.size() == 0) && - (yellowItemsBin.size() == 0)) - { - sLog.outError("AuctionHouseBot: No items"); - AHBSeller = 0; - } - - sLog.outString("AuctionHouseBot:"); - sLog.outString("loaded %u grey trade goods", greyTradeGoodsBin.size()); - sLog.outString("loaded %u white trade goods", whiteTradeGoodsBin.size()); - sLog.outString("loaded %u green trade goods", greenTradeGoodsBin.size()); - sLog.outString("loaded %u blue trade goods", blueTradeGoodsBin.size()); - sLog.outString("loaded %u purple trade goods", purpleTradeGoodsBin.size()); - sLog.outString("loaded %u orange trade goods", orangeTradeGoodsBin.size()); - sLog.outString("loaded %u yellow trade goods", yellowTradeGoodsBin.size()); - sLog.outString("loaded %u grey items", greyItemsBin.size()); - sLog.outString("loaded %u white items", whiteItemsBin.size()); - sLog.outString("loaded %u green items", greenItemsBin.size()); - sLog.outString("loaded %u blue items", blueItemsBin.size()); - sLog.outString("loaded %u purple items", purpleItemsBin.size()); - sLog.outString("loaded %u orange items", orangeItemsBin.size()); - sLog.outString("loaded %u yellow items", yellowItemsBin.size()); - } - sLog.outString("AuctionHouseBot and AuctionHouseBuyer have been loaded."); -} - -void AuctionHouseBot::IncrementItemCounts(AuctionEntry* ah) -{ - // from auctionhousehandler.cpp, creates auction pointer & player pointer - - // get exact item information - Item *pItem = auctionmgr.GetAItem(ah->item_guidlow); - if (!pItem) - { - if (debug_Out) sLog.outError("AHBot: Item %u doesn't exist, perhaps bought already?", ah->item_guidlow); - return; - } - - // get item prototype - ItemPrototype const* prototype = objmgr.GetItemPrototype(ah->item_template); - - AHBConfig *config; - - FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(ah->GetHouseFaction()); - if (!u_entry) - { - if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Neutral", ah->GetHouseFaction()); - config = &NeutralConfig; - } - else if (u_entry->ourMask & FACTION_MASK_ALLIANCE) - { - if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Alliance", ah->GetHouseFaction()); - config = &AllianceConfig; - } - else if (u_entry->ourMask & FACTION_MASK_HORDE) - { - if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Horde", ah->GetHouseFaction()); - config = &HordeConfig; - } - else - { - if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Neutral", ah->GetHouseFaction()); - config = &NeutralConfig; - } - - config->IncItemCounts(prototype->Class, prototype->Quality); -} - -void AuctionHouseBot::DecrementItemCounts(AuctionEntry* ah, uint32 item_template) -{ - // get item prototype - ItemPrototype const* prototype = objmgr.GetItemPrototype(item_template); - - AHBConfig *config; - - FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(ah->GetHouseFaction()); - if (!u_entry) - { - if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Neutral", ah->GetHouseFaction()); - config = &NeutralConfig; - } - else if (u_entry->ourMask & FACTION_MASK_ALLIANCE) - { - if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Alliance", ah->GetHouseFaction()); - config = &AllianceConfig; - } - else if (u_entry->ourMask & FACTION_MASK_HORDE) - { - if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Horde", ah->GetHouseFaction()); - config = &HordeConfig; - } - else - { - if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Neutral", ah->GetHouseFaction()); - config = &NeutralConfig; - } - - config->DecItemCounts(prototype->Class, prototype->Quality); -} - -void AuctionHouseBot::Commands(uint32 command, uint32 ahMapID, uint32 col, char* args) -{ - AHBConfig *config = NULL; - switch (ahMapID) - { - case 2: - config = &AllianceConfig; - break; - case 6: - config = &HordeConfig; - break; - case 7: - config = &NeutralConfig; - break; - } - std::string color; - switch (col) - { - case AHB_GREY: - color = "grey"; - break; - case AHB_WHITE: - color = "white"; - break; - case AHB_GREEN: - color = "green"; - break; - case AHB_BLUE: - color = "blue"; - break; - case AHB_PURPLE: - color = "purple"; - break; - case AHB_ORANGE: - color = "orange"; - break; - case AHB_YELLOW: - color = "yellow"; - break; - default: - break; - } - switch (command) - { - case 0: //ahexpire - { - AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(config->GetAHFID()); - - AuctionHouseObject::AuctionEntryMap::iterator itr; - itr = auctionHouse->GetAuctionsBegin(); - - while (itr != auctionHouse->GetAuctionsEnd()) - { - if (itr->second->owner == AHBplayerGUID) - { - itr->second->expire_time = sWorld.GetGameTime(); - uint32 id = itr->second->Id; - uint32 expire_time = itr->second->expire_time; - CharacterDatabase.PExecute("UPDATE auctionhouse SET time = '%u' WHERE id = '%u'", expire_time, id); - } - ++itr; - } - } - break; - case 1: //min items - { - char * param1 = strtok(args, " "); - uint32 minItems = (uint32) strtoul(param1, NULL, 0); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET minitems = '%u' WHERE auctionhouse = '%u'", minItems, ahMapID); - config->SetMinItems(minItems); - } - break; - case 2: //max items - { - char * param1 = strtok(args, " "); - uint32 maxItems = (uint32) strtoul(param1, NULL, 0); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxitems = '%u' WHERE auctionhouse = '%u'", maxItems, ahMapID); - config->SetMaxItems(maxItems); - } - break; - case 3: //min time Deprecated (Place holder for future commands) - break; - case 4: //max time Deprecated (Place holder for future commands) - break; - case 5: //percentages - { - char * param1 = strtok(args, " "); - char * param2 = strtok(NULL, " "); - char * param3 = strtok(NULL, " "); - char * param4 = strtok(NULL, " "); - char * param5 = strtok(NULL, " "); - char * param6 = strtok(NULL, " "); - char * param7 = strtok(NULL, " "); - char * param8 = strtok(NULL, " "); - char * param9 = strtok(NULL, " "); - char * param10 = strtok(NULL, " "); - char * param11 = strtok(NULL, " "); - char * param12 = strtok(NULL, " "); - char * param13 = strtok(NULL, " "); - char * param14 = strtok(NULL, " "); - uint32 greytg = (uint32) strtoul(param1, NULL, 0); - uint32 whitetg = (uint32) strtoul(param2, NULL, 0); - uint32 greentg = (uint32) strtoul(param3, NULL, 0); - uint32 bluetg = (uint32) strtoul(param4, NULL, 0); - uint32 purpletg = (uint32) strtoul(param5, NULL, 0); - uint32 orangetg = (uint32) strtoul(param6, NULL, 0); - uint32 yellowtg = (uint32) strtoul(param7, NULL, 0); - uint32 greyi = (uint32) strtoul(param8, NULL, 0); - uint32 whitei = (uint32) strtoul(param9, NULL, 0); - uint32 greeni = (uint32) strtoul(param10, NULL, 0); - uint32 bluei = (uint32) strtoul(param11, NULL, 0); - uint32 purplei = (uint32) strtoul(param12, NULL, 0); - uint32 orangei = (uint32) strtoul(param13, NULL, 0); - uint32 yellowi = (uint32) strtoul(param14, NULL, 0); - - CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentgreytradegoods = '%u' WHERE auctionhouse = '%u'", greytg, ahMapID); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentwhitetradegoods = '%u' WHERE auctionhouse = '%u'", whitetg, ahMapID); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentgreentradegoods = '%u' WHERE auctionhouse = '%u'", greentg, ahMapID); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentbluetradegoods = '%u' WHERE auctionhouse = '%u'", bluetg, ahMapID); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentpurpletradegoods = '%u' WHERE auctionhouse = '%u'", purpletg, ahMapID); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentorangetradegoods = '%u' WHERE auctionhouse = '%u'", orangetg, ahMapID); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentyellowtradegoods = '%u' WHERE auctionhouse = '%u'", yellowtg, ahMapID); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentgreyitems = '%u' WHERE auctionhouse = '%u'", greyi, ahMapID); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentwhiteitems = '%u' WHERE auctionhouse = '%u'", whitei, ahMapID); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentgreenitems = '%u' WHERE auctionhouse = '%u'", greeni, ahMapID); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentblueitems = '%u' WHERE auctionhouse = '%u'", bluei, ahMapID); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentpurpleitems = '%u' WHERE auctionhouse = '%u'", purplei, ahMapID); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentorangeitems = '%u' WHERE auctionhouse = '%u'", orangei, ahMapID); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentyellowitems = '%u' WHERE auctionhouse = '%u'", yellowi, ahMapID); - CharacterDatabase.CommitTransaction(); - config->SetPercentages(greytg, whitetg, greentg, bluetg, purpletg, orangetg, yellowtg, greyi, whitei, greeni, bluei, purplei, orangei, yellowi); - } - break; - case 6: //min prices - { - char * param1 = strtok(args, " "); - uint32 minPrice = (uint32) strtoul(param1, NULL, 0); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET minprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), minPrice, ahMapID); - config->SetMinPrice(col, minPrice); - } - break; - case 7: //max prices - { - char * param1 = strtok(args, " "); - uint32 maxPrice = (uint32) strtoul(param1, NULL, 0); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), maxPrice, ahMapID); - config->SetMaxPrice(col, maxPrice); - } - break; - case 8: //min bid price - { - char * param1 = strtok(args, " "); - uint32 minBidPrice = (uint32) strtoul(param1, NULL, 0); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET minbidprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), minBidPrice, ahMapID); - config->SetMinBidPrice(col, minBidPrice); - } - break; - case 9: //max bid price - { - char * param1 = strtok(args, " "); - uint32 maxBidPrice = (uint32) strtoul(param1, NULL, 0); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxbidprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), maxBidPrice, ahMapID); - config->SetMaxBidPrice(col, maxBidPrice); - } - break; - case 10: //max stacks - { - char * param1 = strtok(args, " "); - uint32 maxStack = (uint32) strtoul(param1, NULL, 0); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxstack%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), maxStack, ahMapID); - config->SetMaxStack(col, maxStack); - } - break; - case 11: //buyer bid prices - { - char * param1 = strtok(args, " "); - uint32 buyerPrice = (uint32) strtoul(param1, NULL, 0); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET buyerprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), buyerPrice, ahMapID); - config->SetBuyerPrice(col, buyerPrice); - } - break; - case 12: //buyer bidding interval - { - char * param1 = strtok(args, " "); - uint32 bidInterval = (uint32) strtoul(param1, NULL, 0); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET buyerbiddinginterval = '%u' WHERE auctionhouse = '%u'", bidInterval, ahMapID); - config->SetBiddingInterval(bidInterval); - } - break; - case 13: //buyer bids per interval - { - char * param1 = strtok(args, " "); - uint32 bidsPerInterval = (uint32) strtoul(param1, NULL, 0); - CharacterDatabase.PExecute("UPDATE auctionhousebot SET buyerbidsperinterval = '%u' WHERE auctionhouse = '%u'", bidsPerInterval, ahMapID); - config->SetBidsPerInterval(bidsPerInterval); - } - break; - default: - break; - } -} - -void AuctionHouseBot::LoadValues(AHBConfig *config) -{ - if (debug_Out) sLog.outString("Start Settings for %s Auctionhouses:", CharacterDatabase.PQuery("SELECT name FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetString()); - if (AHBSeller) - { - //load min and max items - config->SetMinItems(CharacterDatabase.PQuery("SELECT minitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxItems(CharacterDatabase.PQuery("SELECT maxitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - //load percentages - uint32 greytg = CharacterDatabase.PQuery("SELECT percentgreytradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); - uint32 whitetg = CharacterDatabase.PQuery("SELECT percentwhitetradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); - uint32 greentg = CharacterDatabase.PQuery("SELECT percentgreentradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); - uint32 bluetg = CharacterDatabase.PQuery("SELECT percentbluetradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); - uint32 purpletg = CharacterDatabase.PQuery("SELECT percentpurpletradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); - uint32 orangetg = CharacterDatabase.PQuery("SELECT percentorangetradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); - uint32 yellowtg = CharacterDatabase.PQuery("SELECT percentyellowtradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); - uint32 greyi = CharacterDatabase.PQuery("SELECT percentgreyitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); - uint32 whitei = CharacterDatabase.PQuery("SELECT percentwhiteitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); - uint32 greeni = CharacterDatabase.PQuery("SELECT percentgreenitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); - uint32 bluei = CharacterDatabase.PQuery("SELECT percentblueitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); - uint32 purplei = CharacterDatabase.PQuery("SELECT percentpurpleitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); - uint32 orangei = CharacterDatabase.PQuery("SELECT percentorangeitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); - uint32 yellowi = CharacterDatabase.PQuery("SELECT percentyellowitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); - config->SetPercentages(greytg, whitetg, greentg, bluetg, purpletg, orangetg, yellowtg, greyi, whitei, greeni, bluei, purplei, orangei, yellowi); - //load min and max prices - config->SetMinPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT minpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT maxpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMinPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT minpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT maxpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMinPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT minpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT maxpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMinPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT minpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT maxpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMinPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT minpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT maxpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMinPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT minpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT maxpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMinPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT minpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT maxpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - //load min and max bid prices - config->SetMinBidPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT minbidpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxBidPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT maxbidpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMinBidPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT minbidpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxBidPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT maxbidpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMinBidPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT minbidpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxBidPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT maxbidpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMinBidPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT minbidpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxBidPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT maxbidpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMinBidPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT minbidpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxBidPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT maxbidpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMinBidPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT minbidpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxBidPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT maxbidpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMinBidPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT minbidpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxBidPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT maxbidpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - //load max stacks - config->SetMaxStack(AHB_GREY, CharacterDatabase.PQuery("SELECT maxstackgrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxStack(AHB_WHITE, CharacterDatabase.PQuery("SELECT maxstackwhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxStack(AHB_GREEN, CharacterDatabase.PQuery("SELECT maxstackgreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxStack(AHB_BLUE, CharacterDatabase.PQuery("SELECT maxstackblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxStack(AHB_PURPLE, CharacterDatabase.PQuery("SELECT maxstackpurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxStack(AHB_ORANGE, CharacterDatabase.PQuery("SELECT maxstackorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetMaxStack(AHB_YELLOW, CharacterDatabase.PQuery("SELECT maxstackyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if (debug_Out) - { - sLog.outString("minItems = %u", config->GetMinItems()); - sLog.outString("maxItems = %u", config->GetMaxItems()); - sLog.outString("percentGreyTradeGoods = %u", config->GetPercentages(AHB_GREY_TG)); - sLog.outString("percentWhiteTradeGoods = %u", config->GetPercentages(AHB_WHITE_TG)); - sLog.outString("percentGreenTradeGoods = %u", config->GetPercentages(AHB_GREEN_TG)); - sLog.outString("percentBlueTradeGoods = %u", config->GetPercentages(AHB_BLUE_TG)); - sLog.outString("percentPurpleTradeGoods = %u", config->GetPercentages(AHB_PURPLE_TG)); - sLog.outString("percentOrangeTradeGoods = %u", config->GetPercentages(AHB_ORANGE_TG)); - sLog.outString("percentYellowTradeGoods = %u", config->GetPercentages(AHB_YELLOW_TG)); - sLog.outString("percentGreyItems = %u", config->GetPercentages(AHB_GREY_I)); - sLog.outString("percentWhiteItems = %u", config->GetPercentages(AHB_WHITE_I)); - sLog.outString("percentGreenItems = %u", config->GetPercentages(AHB_GREEN_I)); - sLog.outString("percentBlueItems = %u", config->GetPercentages(AHB_BLUE_I)); - sLog.outString("percentPurpleItems = %u", config->GetPercentages(AHB_PURPLE_I)); - sLog.outString("percentOrangeItems = %u", config->GetPercentages(AHB_ORANGE_I)); - sLog.outString("percentYellowItems = %u", config->GetPercentages(AHB_YELLOW_I)); - sLog.outString("minPriceGrey = %u", config->GetMinPrice(AHB_GREY)); - sLog.outString("maxPriceGrey = %u", config->GetMaxPrice(AHB_GREY)); - sLog.outString("minPriceWhite = %u", config->GetMinPrice(AHB_WHITE)); - sLog.outString("maxPriceWhite = %u", config->GetMaxPrice(AHB_WHITE)); - sLog.outString("minPriceGreen = %u", config->GetMinPrice(AHB_GREEN)); - sLog.outString("maxPriceGreen = %u", config->GetMaxPrice(AHB_GREEN)); - sLog.outString("minPriceBlue = %u", config->GetMinPrice(AHB_BLUE)); - sLog.outString("maxPriceBlue = %u", config->GetMaxPrice(AHB_BLUE)); - sLog.outString("minPricePurple = %u", config->GetMinPrice(AHB_PURPLE)); - sLog.outString("maxPricePurple = %u", config->GetMaxPrice(AHB_PURPLE)); - sLog.outString("minPriceOrange = %u", config->GetMinPrice(AHB_ORANGE)); - sLog.outString("maxPriceOrange = %u", config->GetMaxPrice(AHB_ORANGE)); - sLog.outString("minPriceYellow = %u", config->GetMinPrice(AHB_YELLOW)); - sLog.outString("maxPriceYellow = %u", config->GetMaxPrice(AHB_YELLOW)); - sLog.outString("minBidPriceGrey = %u", config->GetMinBidPrice(AHB_GREY)); - sLog.outString("maxBidPriceGrey = %u", config->GetMaxBidPrice(AHB_GREY)); - sLog.outString("minBidPriceWhite = %u", config->GetMinBidPrice(AHB_WHITE)); - sLog.outString("maxBidPriceWhite = %u", config->GetMaxBidPrice(AHB_WHITE)); - sLog.outString("minBidPriceGreen = %u", config->GetMinBidPrice(AHB_GREEN)); - sLog.outString("maxBidPriceGreen = %u", config->GetMaxBidPrice(AHB_GREEN)); - sLog.outString("minBidPriceBlue = %u", config->GetMinBidPrice(AHB_BLUE)); - sLog.outString("maxBidPriceBlue = %u", config->GetMinBidPrice(AHB_BLUE)); - sLog.outString("minBidPricePurple = %u", config->GetMinBidPrice(AHB_PURPLE)); - sLog.outString("maxBidPricePurple = %u", config->GetMaxBidPrice(AHB_PURPLE)); - sLog.outString("minBidPriceOrange = %u", config->GetMinBidPrice(AHB_ORANGE)); - sLog.outString("maxBidPriceOrange = %u", config->GetMaxBidPrice(AHB_ORANGE)); - sLog.outString("minBidPriceYellow = %u", config->GetMinBidPrice(AHB_YELLOW)); - sLog.outString("maxBidPriceYellow = %u", config->GetMaxBidPrice(AHB_YELLOW)); - sLog.outString("maxStackGrey = %u", config->GetMaxStack(AHB_GREY)); - sLog.outString("maxStackWhite = %u", config->GetMaxStack(AHB_WHITE)); - sLog.outString("maxStackGreen = %u", config->GetMaxStack(AHB_GREEN)); - sLog.outString("maxStackBlue = %u", config->GetMaxStack(AHB_BLUE)); - sLog.outString("maxStackPurple = %u", config->GetMaxStack(AHB_PURPLE)); - sLog.outString("maxStackOrange = %u", config->GetMaxStack(AHB_ORANGE)); - sLog.outString("maxStackYellow = %u", config->GetMaxStack(AHB_YELLOW)); - } - //AuctionHouseEntry const* ahEntry = auctionmgr.GetAuctionHouseEntry(config->GetAHFID()); - AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(config->GetAHFID()); - - config->ResetItemCounts(); - uint32 auctions = auctionHouse->Getcount(); - - if (auctions) - { - for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionHouse->GetAuctionsBegin(); itr != auctionHouse->GetAuctionsEnd(); ++itr) - { - AuctionEntry *Aentry = itr->second; - Item *item = auctionmgr.GetAItem(Aentry->item_guidlow); - if (item) - { - ItemPrototype const *prototype = item->GetProto(); - if (prototype) - { - switch (prototype->Quality) - { - case 0: - if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - config->IncItemCounts(AHB_GREY_TG); - else - config->IncItemCounts(AHB_GREY_I); - break; - case 1: - if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - config->IncItemCounts(AHB_WHITE_TG); - else - config->IncItemCounts(AHB_WHITE_I); - break; - case 2: - if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - config->IncItemCounts(AHB_GREEN_TG); - else - config->IncItemCounts(AHB_GREEN_I); - break; - case 3: - if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - config->IncItemCounts(AHB_BLUE_TG); - else - config->IncItemCounts(AHB_BLUE_I); - break; - case 4: - if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - config->IncItemCounts(AHB_PURPLE_TG); - else - config->IncItemCounts(AHB_PURPLE_I); - break; - case 5: - if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - config->IncItemCounts(AHB_ORANGE_TG); - else - config->IncItemCounts(AHB_ORANGE_I); - break; - case 6: - if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - config->IncItemCounts(AHB_YELLOW_TG); - else - config->IncItemCounts(AHB_YELLOW_I); - break; - } - } - } - } - } - if (debug_Out) - { - sLog.outString("Current Items in %s Auctionhouses:", CharacterDatabase.PQuery("SELECT name FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetString()); - sLog.outString("Grey Trade Goods\t%u\tGrey Items\t%u", config->GetItemCounts(AHB_GREY_TG), config->GetItemCounts(AHB_GREY_I)); - sLog.outString("White Trade Goods\t%u\tWhite Items\t%u", config->GetItemCounts(AHB_WHITE_TG), config->GetItemCounts(AHB_WHITE_I)); - sLog.outString("Green Trade Goods\t%u\tGreen Items\t%u", config->GetItemCounts(AHB_GREEN_TG), config->GetItemCounts(AHB_GREEN_I)); - sLog.outString("Blue Trade Goods\t%u\tBlue Items\t%u", config->GetItemCounts(AHB_BLUE_TG), config->GetItemCounts(AHB_BLUE_I)); - sLog.outString("Purple Trade Goods\t%u\tPurple Items\t%u", config->GetItemCounts(AHB_PURPLE_TG), config->GetItemCounts(AHB_PURPLE_I)); - sLog.outString("Orange Trade Goods\t%u\tOrange Items\t%u", config->GetItemCounts(AHB_ORANGE_TG), config->GetItemCounts(AHB_ORANGE_I)); - sLog.outString("Yellow Trade Goods\t%u\tYellow Items\t%u", config->GetItemCounts(AHB_YELLOW_TG), config->GetItemCounts(AHB_YELLOW_I)); - } - } - if (AHBBuyer) - { - //load buyer bid prices - config->SetBuyerPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT buyerpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetBuyerPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT buyerpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetBuyerPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT buyerpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetBuyerPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT buyerpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetBuyerPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT buyerpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetBuyerPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT buyerpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - config->SetBuyerPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT buyerpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - //load bidding interval - config->SetBiddingInterval(CharacterDatabase.PQuery("SELECT buyerbiddinginterval FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - //load bids per interval - config->SetBidsPerInterval(CharacterDatabase.PQuery("SELECT buyerbidsperinterval FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if (debug_Out) - { - sLog.outString("buyerPriceGrey = %u", config->GetBuyerPrice(AHB_GREY)); - sLog.outString("buyerPriceWhite = %u", config->GetBuyerPrice(AHB_WHITE)); - sLog.outString("buyerPriceGreen = %u", config->GetBuyerPrice(AHB_GREEN)); - sLog.outString("buyerPriceBlue = %u", config->GetBuyerPrice(AHB_BLUE)); - sLog.outString("buyerPricePurple = %u", config->GetBuyerPrice(AHB_PURPLE)); - sLog.outString("buyerPriceOrange = %u", config->GetBuyerPrice(AHB_ORANGE)); - sLog.outString("buyerPriceYellow = %u", config->GetBuyerPrice(AHB_YELLOW)); - sLog.outString("buyerBiddingInterval = %u", config->GetBiddingInterval()); - sLog.outString("buyerBidsPerInterval = %u", config->GetBidsPerInterval()); - } - } - if (debug_Out) sLog.outString("End Settings for %s Auctionhouses:", CharacterDatabase.PQuery("SELECT name FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetString()); -} diff --git a/src/server/game/AI/AuctionHouseBot/AuctionHouseBot.h b/src/server/game/AI/AuctionHouseBot/AuctionHouseBot.h deleted file mode 100644 index 208a09aa0b2..00000000000 --- a/src/server/game/AI/AuctionHouseBot/AuctionHouseBot.h +++ /dev/null @@ -1,1225 +0,0 @@ -#ifndef AUCTION_HOUSE_BOT_H -#define AUCTION_HOUSE_BOT_H - -#include "World.h" -#include "Config/ConfigEnv.h" -#include "ItemPrototype.h" - -#define AHB_GREY 0 -#define AHB_WHITE 1 -#define AHB_GREEN 2 -#define AHB_BLUE 3 -#define AHB_PURPLE 4 -#define AHB_ORANGE 5 -#define AHB_YELLOW 6 -#define AHB_MAX_QUALITY 6 -#define AHB_GREY_TG 0 -#define AHB_WHITE_TG 1 -#define AHB_GREEN_TG 2 -#define AHB_BLUE_TG 3 -#define AHB_PURPLE_TG 4 -#define AHB_ORANGE_TG 5 -#define AHB_YELLOW_TG 6 -#define AHB_GREY_I 7 -#define AHB_WHITE_I 8 -#define AHB_GREEN_I 9 -#define AHB_BLUE_I 10 -#define AHB_PURPLE_I 11 -#define AHB_ORANGE_I 12 -#define AHB_YELLOW_I 13 - -class AHBConfig -{ -private: - uint32 AHID; - uint32 AHFID; - uint32 minItems; - uint32 maxItems; - uint32 percentGreyTradeGoods; - uint32 percentWhiteTradeGoods; - uint32 percentGreenTradeGoods; - uint32 percentBlueTradeGoods; - uint32 percentPurpleTradeGoods; - uint32 percentOrangeTradeGoods; - uint32 percentYellowTradeGoods; - uint32 percentGreyItems; - uint32 percentWhiteItems; - uint32 percentGreenItems; - uint32 percentBlueItems; - uint32 percentPurpleItems; - uint32 percentOrangeItems; - uint32 percentYellowItems; - uint32 minPriceGrey; - uint32 maxPriceGrey; - uint32 minBidPriceGrey; - uint32 maxBidPriceGrey; - uint32 maxStackGrey; - uint32 minPriceWhite; - uint32 maxPriceWhite; - uint32 minBidPriceWhite; - uint32 maxBidPriceWhite; - uint32 maxStackWhite; - uint32 minPriceGreen; - uint32 maxPriceGreen; - uint32 minBidPriceGreen; - uint32 maxBidPriceGreen; - uint32 maxStackGreen; - uint32 minPriceBlue; - uint32 maxPriceBlue; - uint32 minBidPriceBlue; - uint32 maxBidPriceBlue; - uint32 maxStackBlue; - uint32 minPricePurple; - uint32 maxPricePurple; - uint32 minBidPricePurple; - uint32 maxBidPricePurple; - uint32 maxStackPurple; - uint32 minPriceOrange; - uint32 maxPriceOrange; - uint32 minBidPriceOrange; - uint32 maxBidPriceOrange; - uint32 maxStackOrange; - uint32 minPriceYellow; - uint32 maxPriceYellow; - uint32 minBidPriceYellow; - uint32 maxBidPriceYellow; - uint32 maxStackYellow; - - uint32 buyerPriceGrey; - uint32 buyerPriceWhite; - uint32 buyerPriceGreen; - uint32 buyerPriceBlue; - uint32 buyerPricePurple; - uint32 buyerPriceOrange; - uint32 buyerPriceYellow; - uint32 buyerBiddingInterval; - uint32 buyerBidsPerInterval; - - uint32 greytgp; - uint32 whitetgp; - uint32 greentgp; - uint32 bluetgp; - uint32 purpletgp; - uint32 orangetgp; - uint32 yellowtgp; - uint32 greyip; - uint32 whiteip; - uint32 greenip; - uint32 blueip; - uint32 purpleip; - uint32 orangeip; - uint32 yellowip; - - uint32 greyTGoods; - uint32 whiteTGoods; - uint32 greenTGoods; - uint32 blueTGoods; - uint32 purpleTGoods; - uint32 orangeTGoods; - uint32 yellowTGoods; - - uint32 greyItems; - uint32 whiteItems; - uint32 greenItems; - uint32 blueItems; - uint32 purpleItems; - uint32 orangeItems; - uint32 yellowItems; - -public: - AHBConfig(uint32 ahid) - { - AHID = ahid; - switch(ahid) - { - case 2: - AHFID = 55; - break; - case 6: - AHFID = 29; - break; - case 7: - AHFID = 120; - break; - default: - AHFID = 120; - break; - } - } - AHBConfig() - { - } - uint32 GetAHID() - { - return AHID; - } - uint32 GetAHFID() - { - return AHFID; - } - void SetMinItems(uint32 value) - { - minItems = value; - } - uint32 GetMinItems() - { - if ((minItems == 0) && (maxItems)) - return maxItems; - else if ((maxItems) && (minItems > maxItems)) - return maxItems; - else - return minItems; - } - void SetMaxItems(uint32 value) - { - maxItems = value; - CalculatePercents(); - } - uint32 GetMaxItems() - { - return maxItems; - } - void SetPercentages(uint32 greytg, uint32 whitetg, uint32 greentg, uint32 bluetg, uint32 purpletg, uint32 orangetg, uint32 yellowtg, uint32 greyi, uint32 whitei, uint32 greeni, uint32 bluei, uint32 purplei, uint32 orangei, uint32 yellowi) - { - uint32 totalPercent = greytg + whitetg + greentg + bluetg + purpletg + orangetg + yellowtg + greyi + whitei + greeni + bluei + purplei + orangei + yellowi; - - if (totalPercent == 0) - { - maxItems = 0; - } - else if (totalPercent != 100) - { - greytg = 0; - whitetg = 27; - greentg = 12; - bluetg = 10; - purpletg = 1; - orangetg = 0; - yellowtg = 0; - greyi = 0; - whitei = 10; - greeni = 30; - bluei = 8; - purplei = 2; - orangei = 0; - yellowi = 0; - } - percentGreyTradeGoods = greytg; - percentWhiteTradeGoods = whitetg; - percentGreenTradeGoods = greentg; - percentBlueTradeGoods = bluetg; - percentPurpleTradeGoods = purpletg; - percentOrangeTradeGoods = orangetg; - percentYellowTradeGoods = yellowtg; - percentGreyItems = greyi; - percentWhiteItems = whitei; - percentGreenItems = greeni; - percentBlueItems = bluei; - percentPurpleItems = purplei; - percentOrangeItems = orangei; - percentYellowItems = yellowi; - CalculatePercents(); - } - uint32 GetPercentages(uint32 color) - { - switch(color) - { - case AHB_GREY_TG: - return percentGreyTradeGoods; - break; - case AHB_WHITE_TG: - return percentWhiteTradeGoods; - break; - case AHB_GREEN_TG: - return percentGreenTradeGoods; - break; - case AHB_BLUE_TG: - return percentBlueTradeGoods; - break; - case AHB_PURPLE_TG: - return percentPurpleTradeGoods; - break; - case AHB_ORANGE_TG: - return percentOrangeTradeGoods; - break; - case AHB_YELLOW_TG: - return percentYellowTradeGoods; - break; - case AHB_GREY_I: - return percentGreyItems; - break; - case AHB_WHITE_I: - return percentWhiteItems; - break; - case AHB_GREEN_I: - return percentGreenItems; - break; - case AHB_BLUE_I: - return percentBlueItems; - break; - case AHB_PURPLE_I: - return percentPurpleItems; - break; - case AHB_ORANGE_I: - return percentOrangeItems; - break; - case AHB_YELLOW_I: - return percentYellowItems; - break; - default: - return 0; - break; - } - } - void SetMinPrice(uint32 color, uint32 value) - { - switch(color) - { - case AHB_GREY: - minPriceGrey = value; - break; - case AHB_WHITE: - minPriceWhite = value; - break; - case AHB_GREEN: - minPriceGreen = value; - break; - case AHB_BLUE: - minPriceBlue = value; - break; - case AHB_PURPLE: - minPricePurple = value; - break; - case AHB_ORANGE: - minPriceOrange = value; - break; - case AHB_YELLOW: - minPriceYellow = value; - break; - default: - break; - } - } - uint32 GetMinPrice(uint32 color) - { - switch(color) - { - case AHB_GREY: - { - if (minPriceGrey == 0) - return 100; - else if (minPriceGrey > maxPriceGrey) - return maxPriceGrey; - else - return minPriceGrey; - break; - } - case AHB_WHITE: - { - if (minPriceWhite == 0) - return 150; - else if (minPriceWhite > maxPriceWhite) - return maxPriceWhite; - else - return minPriceWhite; - break; - } - case AHB_GREEN: - { - if (minPriceGreen == 0) - return 200; - else if (minPriceGreen > maxPriceGreen) - return maxPriceGreen; - else - return minPriceGreen; - break; - } - case AHB_BLUE: - { - if (minPriceBlue == 0) - return 250; - else if (minPriceBlue > maxPriceBlue) - return maxPriceBlue; - else - return minPriceBlue; - break; - } - case AHB_PURPLE: - { - if (minPricePurple == 0) - return 300; - else if (minPricePurple > maxPricePurple) - return maxPricePurple; - else - return minPricePurple; - break; - } - case AHB_ORANGE: - { - if (minPriceOrange == 0) - return 400; - else if (minPriceOrange > maxPriceOrange) - return maxPriceOrange; - else - return minPriceOrange; - break; - } - case AHB_YELLOW: - { - if (minPriceYellow == 0) - return 500; - else if (minPriceYellow > maxPriceYellow) - return maxPriceYellow; - else - return minPriceYellow; - break; - } - default: - { - return 0; - break; - } - } - } - void SetMaxPrice(uint32 color, uint32 value) - { - switch(color) - { - case AHB_GREY: - maxPriceGrey = value; - break; - case AHB_WHITE: - maxPriceWhite = value; - break; - case AHB_GREEN: - maxPriceGreen = value; - break; - case AHB_BLUE: - maxPriceBlue = value; - break; - case AHB_PURPLE: - maxPricePurple = value; - break; - case AHB_ORANGE: - maxPriceOrange = value; - break; - case AHB_YELLOW: - maxPriceYellow = value; - break; - default: - break; - } - } - uint32 GetMaxPrice(uint32 color) - { - switch(color) - { - case AHB_GREY: - { - if (maxPriceGrey == 0) - return 150; - else - return maxPriceGrey; - break; - } - case AHB_WHITE: - { - if (maxPriceWhite == 0) - return 250; - else - return maxPriceWhite; - break; - } - case AHB_GREEN: - { - if (maxPriceGreen == 0) - return 300; - else - return maxPriceGreen; - break; - } - case AHB_BLUE: - { - if (maxPriceBlue == 0) - return 350; - else - return maxPriceBlue; - break; - } - case AHB_PURPLE: - { - if (maxPricePurple == 0) - return 450; - else - return maxPricePurple; - break; - } - case AHB_ORANGE: - { - if (maxPriceOrange == 0) - return 550; - else - return maxPriceOrange; - break; - } - case AHB_YELLOW: - { - if (maxPriceYellow == 0) - return 650; - else - return maxPriceYellow; - break; - } - default: - { - return 0; - break; - } - } - } - void SetMinBidPrice(uint32 color, uint32 value) - { - switch(color) - { - case AHB_GREY: - minBidPriceGrey = value; - break; - case AHB_WHITE: - minBidPriceWhite = value; - break; - case AHB_GREEN: - minBidPriceGreen = value; - break; - case AHB_BLUE: - minBidPriceBlue = value; - break; - case AHB_PURPLE: - minBidPricePurple = value; - break; - case AHB_ORANGE: - minBidPriceOrange = value; - break; - case AHB_YELLOW: - minBidPriceYellow = value; - break; - default: - break; - } - } - uint32 GetMinBidPrice(uint32 color) - { - switch(color) - { - case AHB_GREY: - { - if (minBidPriceGrey > 100) - return 100; - else - return minBidPriceGrey; - break; - } - case AHB_WHITE: - { - if (minBidPriceWhite > 100) - return 100; - else - return minBidPriceWhite; - break; - } - case AHB_GREEN: - { - if (minBidPriceGreen > 100) - return 100; - else - return minBidPriceGreen; - break; - } - case AHB_BLUE: - { - if (minBidPriceBlue > 100) - return 100; - else - return minBidPriceBlue; - break; - } - case AHB_PURPLE: - { - if (minBidPricePurple > 100) - return 100; - else - return minBidPricePurple; - break; - } - case AHB_ORANGE: - { - if (minBidPriceOrange > 100) - return 100; - else - return minBidPriceOrange; - break; - } - case AHB_YELLOW: - { - if (minBidPriceYellow > 100) - return 100; - else - return minBidPriceYellow; - break; - } - default: - { - return 0; - break; - } - } - } - void SetMaxBidPrice(uint32 color, uint32 value) - { - switch(color) - { - case AHB_GREY: - maxBidPriceGrey = value; - break; - case AHB_WHITE: - maxBidPriceWhite = value; - break; - case AHB_GREEN: - maxBidPriceGreen = value; - break; - case AHB_BLUE: - maxBidPriceBlue = value; - break; - case AHB_PURPLE: - maxBidPricePurple = value; - break; - case AHB_ORANGE: - maxBidPriceOrange = value; - break; - case AHB_YELLOW: - maxBidPriceYellow = value; - break; - default: - break; - } - } - uint32 GetMaxBidPrice(uint32 color) - { - switch(color) - { - case AHB_GREY: - { - if (maxBidPriceGrey > 100) - return 100; - else - return maxBidPriceGrey; - break; - } - case AHB_WHITE: - { - if (maxBidPriceWhite > 100) - return 100; - else - return maxBidPriceWhite; - break; - } - case AHB_GREEN: - { - if (maxBidPriceGreen > 100) - return 100; - else - return maxBidPriceGreen; - break; - } - case AHB_BLUE: - { - if (maxBidPriceBlue > 100) - return 100; - else - return maxBidPriceBlue; - break; - } - case AHB_PURPLE: - { - if (maxBidPricePurple > 100) - return 100; - else - return maxBidPricePurple; - break; - } - case AHB_ORANGE: - { - if (maxBidPriceOrange > 100) - return 100; - else - return maxBidPriceOrange; - break; - } - case AHB_YELLOW: - { - if (maxBidPriceYellow > 100) - return 100; - else - return maxBidPriceYellow; - break; - } - default: - { - return 0; - break; - } - } - } - void SetMaxStack(uint32 color, uint32 value) - { - switch(color) - { - case AHB_GREY: - maxStackGrey = value; - break; - case AHB_WHITE: - maxStackWhite = value; - break; - case AHB_GREEN: - maxStackGreen = value; - break; - case AHB_BLUE: - maxStackBlue = value; - break; - case AHB_PURPLE: - maxStackPurple = value; - break; - case AHB_ORANGE: - maxStackOrange = value; - break; - case AHB_YELLOW: - maxStackYellow = value; - break; - default: - break; - } - } - uint32 GetMaxStack(uint32 color) - { - switch(color) - { - case AHB_GREY: - { - return maxStackGrey; - break; - } - case AHB_WHITE: - { - return maxStackWhite; - break; - } - case AHB_GREEN: - { - return maxStackGreen; - break; - } - case AHB_BLUE: - { - return maxStackBlue; - break; - } - case AHB_PURPLE: - { - return maxStackPurple; - break; - } - case AHB_ORANGE: - { - return maxStackOrange; - break; - } - case AHB_YELLOW: - { - return maxStackYellow; - break; - } - default: - { - return 0; - break; - } - } - } - void SetBuyerPrice(uint32 color, uint32 value) - { - switch(color) - { - case AHB_GREY: - buyerPriceGrey = value; - break; - case AHB_WHITE: - buyerPriceWhite = value; - break; - case AHB_GREEN: - buyerPriceGreen = value; - break; - case AHB_BLUE: - buyerPriceBlue = value; - break; - case AHB_PURPLE: - buyerPricePurple = value; - break; - case AHB_ORANGE: - buyerPriceOrange = value; - break; - case AHB_YELLOW: - buyerPriceYellow = value; - break; - default: - break; - } - } - uint32 GetBuyerPrice(uint32 color) - { - switch(color) - { - case AHB_GREY: - return buyerPriceGrey; - break; - case AHB_WHITE: - return buyerPriceWhite; - break; - case AHB_GREEN: - return buyerPriceGreen; - break; - case AHB_BLUE: - return buyerPriceBlue; - break; - case AHB_PURPLE: - return buyerPricePurple; - break; - case AHB_ORANGE: - return buyerPriceOrange; - break; - case AHB_YELLOW: - return buyerPriceYellow; - break; - default: - return 0; - break; - } - } - void SetBiddingInterval(uint32 value) - { - buyerBiddingInterval = value; - } - uint32 GetBiddingInterval() - { - return buyerBiddingInterval; - } - void CalculatePercents() - { - greytgp = (uint32) (((double)percentGreyTradeGoods / 100.0) * maxItems); - whitetgp = (uint32) (((double)percentWhiteTradeGoods / 100.0) * maxItems); - greentgp = (uint32) (((double)percentGreenTradeGoods / 100.0) * maxItems); - bluetgp = (uint32) (((double)percentBlueTradeGoods / 100.0) * maxItems); - purpletgp = (uint32) (((double)percentPurpleTradeGoods / 100.0) * maxItems); - orangetgp = (uint32) (((double)percentOrangeTradeGoods / 100.0) * maxItems); - yellowtgp = (uint32) (((double)percentYellowTradeGoods / 100.0) * maxItems); - greyip = (uint32) (((double)percentGreyItems / 100.0) * maxItems); - whiteip = (uint32) (((double)percentWhiteItems / 100.0) * maxItems); - greenip = (uint32) (((double)percentGreenItems / 100.0) * maxItems); - blueip = (uint32) (((double)percentBlueItems / 100.0) * maxItems); - purpleip = (uint32) (((double)percentPurpleItems / 100.0) * maxItems); - orangeip = (uint32) (((double)percentOrangeItems / 100.0) * maxItems); - yellowip = (uint32) (((double)percentYellowItems / 100.0) * maxItems); - uint32 total = greytgp + whitetgp + greentgp + bluetgp + purpletgp + orangetgp + yellowtgp + greyip + whiteip + greenip + blueip + purpleip + orangeip + yellowip; - int32 diff = (maxItems - total); - if (diff < 0) - { - if ((whiteip - diff) > 0) - whiteip -= diff; - else if ((greenip - diff) > 0) - greenip -= diff; - } - else if (diff < 0) - { - whiteip += diff; - } - } - uint32 GetPercents(uint32 color) - { - switch(color) - { - case AHB_GREY_TG: - return greytgp; - break; - case AHB_WHITE_TG: - return whitetgp; - break; - case AHB_GREEN_TG: - return greentgp; - break; - case AHB_BLUE_TG: - return bluetgp; - break; - case AHB_PURPLE_TG: - return purpletgp; - break; - case AHB_ORANGE_TG: - return orangetgp; - break; - case AHB_YELLOW_TG: - return yellowtgp; - break; - case AHB_GREY_I: - return greyip; - break; - case AHB_WHITE_I: - return whiteip; - break; - case AHB_GREEN_I: - return greenip; - break; - case AHB_BLUE_I: - return blueip; - break; - case AHB_PURPLE_I: - return purpleip; - break; - case AHB_ORANGE_I: - return orangeip; - break; - case AHB_YELLOW_I: - return yellowip; - break; - default: - return 0; - break; - } - } - - void DecItemCounts(uint32 Class, uint32 Quality) - { - switch(Class) - { - case ITEM_CLASS_TRADE_GOODS: - DecItemCounts(Quality); - break; - default: - DecItemCounts(Quality + 7); - break; - } - } - - void DecItemCounts(uint32 color) - { - switch(color) - { - case AHB_GREY_TG: - --greyTGoods; - break; - case AHB_WHITE_TG: - --whiteTGoods; - break; - case AHB_GREEN_TG: - --greenTGoods; - break; - case AHB_BLUE_TG: - --blueTGoods; - break; - case AHB_PURPLE_TG: - --purpleTGoods; - break; - case AHB_ORANGE_TG: - --orangeTGoods; - break; - case AHB_YELLOW_TG: - --yellowTGoods; - break; - case AHB_GREY_I: - --greyItems; - break; - case AHB_WHITE_I: - --whiteItems; - break; - case AHB_GREEN_I: - --greenItems; - break; - case AHB_BLUE_I: - --blueItems; - break; - case AHB_PURPLE_I: - --purpleItems; - break; - case AHB_ORANGE_I: - --orangeItems; - break; - case AHB_YELLOW_I: - --yellowItems; - break; - default: - break; - } - } - - void IncItemCounts(uint32 Class, uint32 Quality) - { - switch(Class) - { - case ITEM_CLASS_TRADE_GOODS: - IncItemCounts(Quality); - break; - default: - IncItemCounts(Quality + 7); - break; - } - } - - void IncItemCounts(uint32 color) - { - switch(color) - { - case AHB_GREY_TG: - ++greyTGoods; - break; - case AHB_WHITE_TG: - ++whiteTGoods; - break; - case AHB_GREEN_TG: - ++greenTGoods; - break; - case AHB_BLUE_TG: - ++blueTGoods; - break; - case AHB_PURPLE_TG: - ++purpleTGoods; - break; - case AHB_ORANGE_TG: - ++orangeTGoods; - break; - case AHB_YELLOW_TG: - ++yellowTGoods; - break; - case AHB_GREY_I: - ++greyItems; - break; - case AHB_WHITE_I: - ++whiteItems; - break; - case AHB_GREEN_I: - ++greenItems; - break; - case AHB_BLUE_I: - ++blueItems; - break; - case AHB_PURPLE_I: - ++purpleItems; - break; - case AHB_ORANGE_I: - ++orangeItems; - break; - case AHB_YELLOW_I: - ++yellowItems; - break; - default: - break; - } - } - - void ResetItemCounts() - { - greyTGoods = 0; - whiteTGoods = 0; - greenTGoods = 0; - blueTGoods = 0; - purpleTGoods = 0; - orangeTGoods = 0; - yellowTGoods = 0; - - greyItems = 0; - whiteItems = 0; - greenItems = 0; - blueItems = 0; - purpleItems = 0; - orangeItems = 0; - yellowItems = 0; - } - - uint32 TotalItemCounts() - { - return( - greyTGoods + - whiteTGoods + - greenTGoods + - blueTGoods + - purpleTGoods + - orangeTGoods + - yellowTGoods + - - greyItems + - whiteItems + - greenItems + - blueItems + - purpleItems + - orangeItems + - yellowItems); - } - - uint32 GetItemCounts(uint32 color) - { - switch(color) - { - case AHB_GREY_TG: - return greyTGoods; - break; - case AHB_WHITE_TG: - return whiteTGoods; - break; - case AHB_GREEN_TG: - return greenTGoods; - break; - case AHB_BLUE_TG: - return blueTGoods; - break; - case AHB_PURPLE_TG: - return purpleTGoods; - break; - case AHB_ORANGE_TG: - return orangeTGoods; - break; - case AHB_YELLOW_TG: - return yellowTGoods; - break; - case AHB_GREY_I: - return greyItems; - break; - case AHB_WHITE_I: - return whiteItems; - break; - case AHB_GREEN_I: - return greenItems; - break; - case AHB_BLUE_I: - return blueItems; - break; - case AHB_PURPLE_I: - return purpleItems; - break; - case AHB_ORANGE_I: - return orangeItems; - break; - case AHB_YELLOW_I: - return yellowItems; - break; - default: - return 0; - break; - } - } - void SetBidsPerInterval(uint32 value) - { - buyerBidsPerInterval = value; - } - uint32 GetBidsPerInterval() - { - return buyerBidsPerInterval; - } - ~AHBConfig() - { - } -}; -class AuctionHouseBot -{ -private: - - bool debug_Out; - bool debug_Out_Filters; - - bool AHBSeller; - bool AHBBuyer; - bool BuyMethod; - bool SellMethod; - - uint32 AHBplayerAccount; - uint32 AHBplayerGUID; - uint32 ItemsPerCycle; - - //Begin Filters - - bool Vendor_Items; - bool Loot_Items; - bool Other_Items; - bool Vendor_TGs; - bool Loot_TGs; - bool Other_TGs; - - bool No_Bind; - bool Bind_When_Picked_Up; - bool Bind_When_Equipped; - bool Bind_When_Use; - bool Bind_Quest_Item; - - bool DisableBeta_PTR_Unused; - bool DisablePermEnchant; - bool DisableConjured; - bool DisableGems; - bool DisableMoney; - bool DisableMoneyLoot; - bool DisableLootable; - bool DisableKeys; - bool DisableDuration; - bool DisableBOP_Or_Quest_NoReqLevel; - - bool DisableWarriorItems; - bool DisablePaladinItems; - bool DisableHunterItems; - bool DisableRogueItems; - bool DisablePriestItems; - bool DisableDKItems; - bool DisableShamanItems; - bool DisableMageItems; - bool DisableWarlockItems; - bool DisableUnusedClassItems; - bool DisableDruidItems; - - uint32 DisableItemsBelowLevel; - uint32 DisableItemsAboveLevel; - uint32 DisableTGsBelowLevel; - uint32 DisableTGsAboveLevel; - uint32 DisableItemsBelowGUID; - uint32 DisableItemsAboveGUID; - uint32 DisableTGsBelowGUID; - uint32 DisableTGsAboveGUID; - uint32 DisableItemsBelowReqLevel; - uint32 DisableItemsAboveReqLevel; - uint32 DisableTGsBelowReqLevel; - uint32 DisableTGsAboveReqLevel; - uint32 DisableItemsBelowReqSkillRank; - uint32 DisableItemsAboveReqSkillRank; - uint32 DisableTGsBelowReqSkillRank; - uint32 DisableTGsAboveReqSkillRank; - - //End Filters - - AHBConfig AllianceConfig; - AHBConfig HordeConfig; - AHBConfig NeutralConfig; - - time_t _lastrun_a; - time_t _lastrun_h; - time_t _lastrun_n; - - inline uint32 minValue(uint32 a, uint32 b) { return a <= b ? a : b; }; - void addNewAuctions(Player *AHBplayer, AHBConfig *config); - void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, WorldSession *session); - -public: - AuctionHouseBot(); - ~AuctionHouseBot(); - void Update(); - void Initialize(); - void LoadValues(AHBConfig*); - void DecrementItemCounts(AuctionEntry* ah, uint32 item_template); - void IncrementItemCounts(AuctionEntry* ah); - void Commands(uint32, uint32, uint32, char*); - uint32 GetAHBplayerGUID() { return AHBplayerGUID; }; -}; - -#define auctionbot Trinity::Singleton::Instance() - -#endif diff --git a/src/server/game/AI/CombatAI.cpp b/src/server/game/AI/CombatAI.cpp deleted file mode 100644 index 0d0ff17ffd7..00000000000 --- a/src/server/game/AI/CombatAI.cpp +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "CombatAI.h" -#include "SpellMgr.h" -#include "Vehicle.h" - -int AggressorAI::Permissible(const Creature *creature) -{ - // have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight - if (!creature->isCivilian() && !creature->IsNeutralToAll()) - return PERMIT_BASE_PROACTIVE; - - return PERMIT_BASE_NO; -} - -void AggressorAI::UpdateAI(const uint32 /*diff*/) -{ - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); -} - -// some day we will delete these useless things -int CombatAI::Permissible(const Creature * /*creature*/) -{ - return PERMIT_BASE_NO; -} - -int ArchorAI::Permissible(const Creature * /*creature*/) -{ - return PERMIT_BASE_NO; -} - -int TurretAI::Permissible(const Creature * /*creature*/) -{ - return PERMIT_BASE_NO; -} - -int AOEAI::Permissible(const Creature * /*creature*/) -{ - return PERMIT_BASE_NO; -} - -int VehicleAI::Permissible(const Creature * /*creature*/) -{ - return PERMIT_BASE_NO; -} - -void CombatAI::InitializeAI() -{ - for (uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) - if (me->m_spells[i] && GetSpellStore()->LookupEntry(me->m_spells[i])) - spells.push_back(me->m_spells[i]); - - CreatureAI::InitializeAI(); -} - -void CombatAI::Reset() -{ - events.Reset(); -} - -void CombatAI::JustDied(Unit *killer) -{ - for (SpellVct::iterator i = spells.begin(); i != spells.end(); ++i) - if (AISpellInfo[*i].condition == AICOND_DIE) - me->CastSpell(killer, *i, true); -} - -void CombatAI::EnterCombat(Unit *who) -{ - for (SpellVct::iterator i = spells.begin(); i != spells.end(); ++i) - { - if (AISpellInfo[*i].condition == AICOND_AGGRO) - me->CastSpell(who, *i, false); - else if (AISpellInfo[*i].condition == AICOND_COMBAT) - events.ScheduleEvent(*i, AISpellInfo[*i].cooldown + rand()%AISpellInfo[*i].cooldown); - } -} - -void CombatAI::UpdateAI(const uint32 diff) -{ - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->hasUnitState(UNIT_STAT_CASTING)) - return; - - if (uint32 spellId = events.ExecuteEvent()) - { - DoCast(spellId); - events.ScheduleEvent(spellId, AISpellInfo[spellId].cooldown + rand()%AISpellInfo[spellId].cooldown); - } - else - DoMeleeAttackIfReady(); -} - -///////////////// -//CasterAI -///////////////// - -void CasterAI::InitializeAI() -{ - CombatAI::InitializeAI(); - - float m_attackDist = 30.0f; - for (SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr) - if (AISpellInfo[*itr].condition == AICOND_COMBAT && m_attackDist > GetAISpellInfo(*itr)->maxRange) - m_attackDist = GetAISpellInfo(*itr)->maxRange; - if (m_attackDist == 30.0f) - m_attackDist = MELEE_RANGE; -} - -void CasterAI::EnterCombat(Unit *who) -{ - if (spells.empty()) - return; - - uint32 spell = rand()%spells.size(); - uint32 count = 0; - for (SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr, ++count) - { - if (AISpellInfo[*itr].condition == AICOND_AGGRO) - me->CastSpell(who, *itr, false); - else if (AISpellInfo[*itr].condition == AICOND_COMBAT) - { - uint32 cooldown = GetAISpellInfo(*itr)->realCooldown; - if (count == spell) - { - DoCast(spells[spell]); - cooldown += me->GetCurrentSpellCastTime(*itr); - } - events.ScheduleEvent(*itr, cooldown); - } - } -} - -void CasterAI::UpdateAI(const uint32 diff) -{ - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->hasUnitState(UNIT_STAT_CASTING)) - return; - - if (uint32 spellId = events.ExecuteEvent()) - { - DoCast(spellId); - uint32 casttime = me->GetCurrentSpellCastTime(spellId); - events.ScheduleEvent(spellId, (casttime ? casttime : 500) + GetAISpellInfo(spellId)->realCooldown); - } -} - -////////////// -//ArchorAI -////////////// - -ArchorAI::ArchorAI(Creature *c) : CreatureAI(c) -{ - if (!me->m_spells[0]) - sLog.outError("ArchorAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry()); - - m_minRange = GetSpellMinRange(me->m_spells[0], false); - if (!m_minRange) - m_minRange = MELEE_RANGE; - me->m_CombatDistance = GetSpellMaxRange(me->m_spells[0], false); - me->m_SightDistance = me->m_CombatDistance; -} - -void ArchorAI::AttackStart(Unit *who) -{ - if (!who) - return; - - if (me->IsWithinCombatRange(who, m_minRange)) - { - if (me->Attack(who, true) && !who->IsFlying()) - me->GetMotionMaster()->MoveChase(who); - } - else - { - if (me->Attack(who, false) && !who->IsFlying()) - me->GetMotionMaster()->MoveChase(who, me->m_CombatDistance); - } - - if (who->IsFlying()) - me->GetMotionMaster()->MoveIdle(); -} - -void ArchorAI::UpdateAI(const uint32 /*diff*/) -{ - if (!UpdateVictim()) - return; - - if (!me->IsWithinCombatRange(me->getVictim(), m_minRange)) - DoSpellAttackIfReady(me->m_spells[0]); - else - DoMeleeAttackIfReady(); -} - -////////////// -//TurretAI -////////////// - -TurretAI::TurretAI(Creature *c) : CreatureAI(c) -{ - if (!me->m_spells[0]) - sLog.outError("TurretAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry()); - - m_minRange = GetSpellMinRange(me->m_spells[0], false); - me->m_CombatDistance = GetSpellMaxRange(me->m_spells[0], false); - me->m_SightDistance = me->m_CombatDistance; -} - -bool TurretAI::CanAIAttack(const Unit * /*who*/) const -{ - // TODO: use one function to replace it - if (!me->IsWithinCombatRange(me->getVictim(), me->m_CombatDistance) - || m_minRange && me->IsWithinCombatRange(me->getVictim(), m_minRange)) - return false; - return true; -} - -void TurretAI::AttackStart(Unit *who) -{ - if (who) - me->Attack(who, false); -} - -void TurretAI::UpdateAI(const uint32 /*diff*/) -{ - if (!UpdateVictim()) - return; - - DoSpellAttackIfReady(me->m_spells[0]); -} - -////////////// -//AOEAI -////////////// - -AOEAI::AOEAI(Creature *c) : CreatureAI(c) -{ - if (!me->m_spells[0]) - sLog.outError("AOEAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry()); - - me->SetVisibility(VISIBILITY_ON);//visible to see all spell anims - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);//can't be targeted - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_1);//can't be damaged - me->SetDisplayId(11686);//invisible model,around a size of a player -} - -bool AOEAI::CanAIAttack(const Unit * /*who*/) const -{ - return false; -} - -void AOEAI::AttackStart(Unit * /*who*/) -{ -} - -void AOEAI::UpdateAI(const uint32 /*diff*/) -{ - if (!me->HasAura(me->m_spells[0])) - me->CastSpell(me, me->m_spells[0],false); -} - -////////////// -//VehicleAI -////////////// - -VehicleAI::VehicleAI(Creature *c) : CreatureAI(c), m_vehicle(c->GetVehicleKit()), m_IsVehicleInUse(false), m_ConditionsTimer(VEHICLE_CONDITION_CHECK_TIME) -{ - LoadConditions(); - m_DoDismiss = false; - m_DismissTimer = VEHICLE_DISMISS_TIME; -} - - -//NOTE: VehicleAI::UpdateAI runs even while the vehicle is mounted -void VehicleAI::UpdateAI(const uint32 diff) -{ - CheckConditions(diff); - - if (m_DoDismiss) - { - if (m_DismissTimer < diff) - { - m_DoDismiss = false; - me->SetVisibility(VISIBILITY_OFF); - me->ForcedDespawn(); - }else m_DismissTimer -= diff; - } -} - -void VehicleAI::Reset() -{ - me->SetVisibility(VISIBILITY_ON); - - m_vehicle->Reset(); -} - -void VehicleAI::OnCharmed(bool apply) -{ - if (m_IsVehicleInUse && !apply && !conditions.empty())//was used and has conditions - { - m_DoDismiss = true;//needs reset - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE); - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - } - else if (apply) - m_DoDismiss = false;//in use again - m_DismissTimer = VEHICLE_DISMISS_TIME;//reset timer - m_IsVehicleInUse = apply; -} - -void VehicleAI::LoadConditions() -{ - conditions = sConditionMgr.GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, me->GetEntry()); - if (!conditions.empty()) - { - sLog.outDebug("VehicleAI::LoadConditions: loaded %u conditions", uint32(conditions.size())); - } -} - -void VehicleAI::CheckConditions(const uint32 diff) -{ - if(m_ConditionsTimer < diff) - { - if (!conditions.empty()) - { - for (SeatMap::iterator itr = m_vehicle->m_Seats.begin(); itr != m_vehicle->m_Seats.end(); ++itr) - if (Unit *passenger = itr->second.passenger) - { - if (Player* plr = passenger->ToPlayer()) - { - if (!sConditionMgr.IsPlayerMeetToConditions(plr, conditions)) - { - plr->ExitVehicle(); - return;//check other pessanger in next tick - } - } - } - } - m_ConditionsTimer = VEHICLE_CONDITION_CHECK_TIME; - } else m_ConditionsTimer -= diff; -} \ No newline at end of file diff --git a/src/server/game/AI/CombatAI.h b/src/server/game/AI/CombatAI.h deleted file mode 100644 index 8626b38dd37..00000000000 --- a/src/server/game/AI/CombatAI.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_COMBATAI_H -#define TRINITY_COMBATAI_H - -#include "CreatureAI.h" -#include "CreatureAIImpl.h" -#include "ConditionMgr.h" - -class Creature; - -class AggressorAI : public CreatureAI -{ - public: - explicit AggressorAI(Creature *c) : CreatureAI(c) {} - - void UpdateAI(const uint32); - static int Permissible(const Creature *); -}; - -typedef std::vector SpellVct; - -class CombatAI : public CreatureAI -{ - public: - explicit CombatAI(Creature *c) : CreatureAI(c) {} - - void InitializeAI(); - void Reset(); - void EnterCombat(Unit* who); - void JustDied(Unit *killer); - void UpdateAI(const uint32 diff); - static int Permissible(const Creature *); - protected: - EventMap events; - SpellVct spells; -}; - -class CasterAI : public CombatAI -{ - public: - explicit CasterAI(Creature *c) : CombatAI(c) { m_attackDist = MELEE_RANGE; } - void InitializeAI(); - void AttackStart(Unit * victim) { AttackStartCaster(victim, m_attackDist); } - void UpdateAI(const uint32 diff); - void EnterCombat(Unit * /*who*/); - private: - float m_attackDist; -}; - -struct ArchorAI : public CreatureAI -{ - public: - explicit ArchorAI(Creature *c); - void AttackStart(Unit *who); - void UpdateAI(const uint32 diff); - - static int Permissible(const Creature *); - protected: - float m_minRange; -}; - -struct TurretAI : public CreatureAI -{ - public: - explicit TurretAI(Creature *c); - bool CanAIAttack(const Unit *who) const; - void AttackStart(Unit *who); - void UpdateAI(const uint32 diff); - - static int Permissible(const Creature *); - protected: - float m_minRange; -}; - -struct AOEAI : public CreatureAI -{ - public: - explicit AOEAI(Creature *c); - bool CanAIAttack(const Unit *who) const; - void AttackStart(Unit *who); - void UpdateAI(const uint32 diff); - - static int Permissible(const Creature *); -}; -#define VEHICLE_CONDITION_CHECK_TIME 1000 -#define VEHICLE_DISMISS_TIME 5000 -struct VehicleAI : public CreatureAI -{ - public: - explicit VehicleAI(Creature *c); - - void UpdateAI(const uint32 diff); - static int Permissible(const Creature *); - void Reset(); - void MoveInLineOfSight(Unit *) {} - void AttackStart(Unit *) {} - void OnCharmed(bool apply); - - private: - Vehicle* m_vehicle; - bool m_IsVehicleInUse; - void LoadConditions(); - void CheckConditions(const uint32 diff); - ConditionList conditions; - uint32 m_ConditionsTimer; - bool m_DoDismiss; - uint32 m_DismissTimer; -}; - -#endif diff --git a/src/server/game/AI/CoreAI/CombatAI.cpp b/src/server/game/AI/CoreAI/CombatAI.cpp new file mode 100644 index 00000000000..0d0ff17ffd7 --- /dev/null +++ b/src/server/game/AI/CoreAI/CombatAI.cpp @@ -0,0 +1,370 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "CombatAI.h" +#include "SpellMgr.h" +#include "Vehicle.h" + +int AggressorAI::Permissible(const Creature *creature) +{ + // have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight + if (!creature->isCivilian() && !creature->IsNeutralToAll()) + return PERMIT_BASE_PROACTIVE; + + return PERMIT_BASE_NO; +} + +void AggressorAI::UpdateAI(const uint32 /*diff*/) +{ + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); +} + +// some day we will delete these useless things +int CombatAI::Permissible(const Creature * /*creature*/) +{ + return PERMIT_BASE_NO; +} + +int ArchorAI::Permissible(const Creature * /*creature*/) +{ + return PERMIT_BASE_NO; +} + +int TurretAI::Permissible(const Creature * /*creature*/) +{ + return PERMIT_BASE_NO; +} + +int AOEAI::Permissible(const Creature * /*creature*/) +{ + return PERMIT_BASE_NO; +} + +int VehicleAI::Permissible(const Creature * /*creature*/) +{ + return PERMIT_BASE_NO; +} + +void CombatAI::InitializeAI() +{ + for (uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) + if (me->m_spells[i] && GetSpellStore()->LookupEntry(me->m_spells[i])) + spells.push_back(me->m_spells[i]); + + CreatureAI::InitializeAI(); +} + +void CombatAI::Reset() +{ + events.Reset(); +} + +void CombatAI::JustDied(Unit *killer) +{ + for (SpellVct::iterator i = spells.begin(); i != spells.end(); ++i) + if (AISpellInfo[*i].condition == AICOND_DIE) + me->CastSpell(killer, *i, true); +} + +void CombatAI::EnterCombat(Unit *who) +{ + for (SpellVct::iterator i = spells.begin(); i != spells.end(); ++i) + { + if (AISpellInfo[*i].condition == AICOND_AGGRO) + me->CastSpell(who, *i, false); + else if (AISpellInfo[*i].condition == AICOND_COMBAT) + events.ScheduleEvent(*i, AISpellInfo[*i].cooldown + rand()%AISpellInfo[*i].cooldown); + } +} + +void CombatAI::UpdateAI(const uint32 diff) +{ + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->hasUnitState(UNIT_STAT_CASTING)) + return; + + if (uint32 spellId = events.ExecuteEvent()) + { + DoCast(spellId); + events.ScheduleEvent(spellId, AISpellInfo[spellId].cooldown + rand()%AISpellInfo[spellId].cooldown); + } + else + DoMeleeAttackIfReady(); +} + +///////////////// +//CasterAI +///////////////// + +void CasterAI::InitializeAI() +{ + CombatAI::InitializeAI(); + + float m_attackDist = 30.0f; + for (SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr) + if (AISpellInfo[*itr].condition == AICOND_COMBAT && m_attackDist > GetAISpellInfo(*itr)->maxRange) + m_attackDist = GetAISpellInfo(*itr)->maxRange; + if (m_attackDist == 30.0f) + m_attackDist = MELEE_RANGE; +} + +void CasterAI::EnterCombat(Unit *who) +{ + if (spells.empty()) + return; + + uint32 spell = rand()%spells.size(); + uint32 count = 0; + for (SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr, ++count) + { + if (AISpellInfo[*itr].condition == AICOND_AGGRO) + me->CastSpell(who, *itr, false); + else if (AISpellInfo[*itr].condition == AICOND_COMBAT) + { + uint32 cooldown = GetAISpellInfo(*itr)->realCooldown; + if (count == spell) + { + DoCast(spells[spell]); + cooldown += me->GetCurrentSpellCastTime(*itr); + } + events.ScheduleEvent(*itr, cooldown); + } + } +} + +void CasterAI::UpdateAI(const uint32 diff) +{ + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->hasUnitState(UNIT_STAT_CASTING)) + return; + + if (uint32 spellId = events.ExecuteEvent()) + { + DoCast(spellId); + uint32 casttime = me->GetCurrentSpellCastTime(spellId); + events.ScheduleEvent(spellId, (casttime ? casttime : 500) + GetAISpellInfo(spellId)->realCooldown); + } +} + +////////////// +//ArchorAI +////////////// + +ArchorAI::ArchorAI(Creature *c) : CreatureAI(c) +{ + if (!me->m_spells[0]) + sLog.outError("ArchorAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry()); + + m_minRange = GetSpellMinRange(me->m_spells[0], false); + if (!m_minRange) + m_minRange = MELEE_RANGE; + me->m_CombatDistance = GetSpellMaxRange(me->m_spells[0], false); + me->m_SightDistance = me->m_CombatDistance; +} + +void ArchorAI::AttackStart(Unit *who) +{ + if (!who) + return; + + if (me->IsWithinCombatRange(who, m_minRange)) + { + if (me->Attack(who, true) && !who->IsFlying()) + me->GetMotionMaster()->MoveChase(who); + } + else + { + if (me->Attack(who, false) && !who->IsFlying()) + me->GetMotionMaster()->MoveChase(who, me->m_CombatDistance); + } + + if (who->IsFlying()) + me->GetMotionMaster()->MoveIdle(); +} + +void ArchorAI::UpdateAI(const uint32 /*diff*/) +{ + if (!UpdateVictim()) + return; + + if (!me->IsWithinCombatRange(me->getVictim(), m_minRange)) + DoSpellAttackIfReady(me->m_spells[0]); + else + DoMeleeAttackIfReady(); +} + +////////////// +//TurretAI +////////////// + +TurretAI::TurretAI(Creature *c) : CreatureAI(c) +{ + if (!me->m_spells[0]) + sLog.outError("TurretAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry()); + + m_minRange = GetSpellMinRange(me->m_spells[0], false); + me->m_CombatDistance = GetSpellMaxRange(me->m_spells[0], false); + me->m_SightDistance = me->m_CombatDistance; +} + +bool TurretAI::CanAIAttack(const Unit * /*who*/) const +{ + // TODO: use one function to replace it + if (!me->IsWithinCombatRange(me->getVictim(), me->m_CombatDistance) + || m_minRange && me->IsWithinCombatRange(me->getVictim(), m_minRange)) + return false; + return true; +} + +void TurretAI::AttackStart(Unit *who) +{ + if (who) + me->Attack(who, false); +} + +void TurretAI::UpdateAI(const uint32 /*diff*/) +{ + if (!UpdateVictim()) + return; + + DoSpellAttackIfReady(me->m_spells[0]); +} + +////////////// +//AOEAI +////////////// + +AOEAI::AOEAI(Creature *c) : CreatureAI(c) +{ + if (!me->m_spells[0]) + sLog.outError("AOEAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry()); + + me->SetVisibility(VISIBILITY_ON);//visible to see all spell anims + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);//can't be targeted + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_1);//can't be damaged + me->SetDisplayId(11686);//invisible model,around a size of a player +} + +bool AOEAI::CanAIAttack(const Unit * /*who*/) const +{ + return false; +} + +void AOEAI::AttackStart(Unit * /*who*/) +{ +} + +void AOEAI::UpdateAI(const uint32 /*diff*/) +{ + if (!me->HasAura(me->m_spells[0])) + me->CastSpell(me, me->m_spells[0],false); +} + +////////////// +//VehicleAI +////////////// + +VehicleAI::VehicleAI(Creature *c) : CreatureAI(c), m_vehicle(c->GetVehicleKit()), m_IsVehicleInUse(false), m_ConditionsTimer(VEHICLE_CONDITION_CHECK_TIME) +{ + LoadConditions(); + m_DoDismiss = false; + m_DismissTimer = VEHICLE_DISMISS_TIME; +} + + +//NOTE: VehicleAI::UpdateAI runs even while the vehicle is mounted +void VehicleAI::UpdateAI(const uint32 diff) +{ + CheckConditions(diff); + + if (m_DoDismiss) + { + if (m_DismissTimer < diff) + { + m_DoDismiss = false; + me->SetVisibility(VISIBILITY_OFF); + me->ForcedDespawn(); + }else m_DismissTimer -= diff; + } +} + +void VehicleAI::Reset() +{ + me->SetVisibility(VISIBILITY_ON); + + m_vehicle->Reset(); +} + +void VehicleAI::OnCharmed(bool apply) +{ + if (m_IsVehicleInUse && !apply && !conditions.empty())//was used and has conditions + { + m_DoDismiss = true;//needs reset + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + } + else if (apply) + m_DoDismiss = false;//in use again + m_DismissTimer = VEHICLE_DISMISS_TIME;//reset timer + m_IsVehicleInUse = apply; +} + +void VehicleAI::LoadConditions() +{ + conditions = sConditionMgr.GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, me->GetEntry()); + if (!conditions.empty()) + { + sLog.outDebug("VehicleAI::LoadConditions: loaded %u conditions", uint32(conditions.size())); + } +} + +void VehicleAI::CheckConditions(const uint32 diff) +{ + if(m_ConditionsTimer < diff) + { + if (!conditions.empty()) + { + for (SeatMap::iterator itr = m_vehicle->m_Seats.begin(); itr != m_vehicle->m_Seats.end(); ++itr) + if (Unit *passenger = itr->second.passenger) + { + if (Player* plr = passenger->ToPlayer()) + { + if (!sConditionMgr.IsPlayerMeetToConditions(plr, conditions)) + { + plr->ExitVehicle(); + return;//check other pessanger in next tick + } + } + } + } + m_ConditionsTimer = VEHICLE_CONDITION_CHECK_TIME; + } else m_ConditionsTimer -= diff; +} \ No newline at end of file diff --git a/src/server/game/AI/CoreAI/CombatAI.h b/src/server/game/AI/CoreAI/CombatAI.h new file mode 100644 index 00000000000..8626b38dd37 --- /dev/null +++ b/src/server/game/AI/CoreAI/CombatAI.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_COMBATAI_H +#define TRINITY_COMBATAI_H + +#include "CreatureAI.h" +#include "CreatureAIImpl.h" +#include "ConditionMgr.h" + +class Creature; + +class AggressorAI : public CreatureAI +{ + public: + explicit AggressorAI(Creature *c) : CreatureAI(c) {} + + void UpdateAI(const uint32); + static int Permissible(const Creature *); +}; + +typedef std::vector SpellVct; + +class CombatAI : public CreatureAI +{ + public: + explicit CombatAI(Creature *c) : CreatureAI(c) {} + + void InitializeAI(); + void Reset(); + void EnterCombat(Unit* who); + void JustDied(Unit *killer); + void UpdateAI(const uint32 diff); + static int Permissible(const Creature *); + protected: + EventMap events; + SpellVct spells; +}; + +class CasterAI : public CombatAI +{ + public: + explicit CasterAI(Creature *c) : CombatAI(c) { m_attackDist = MELEE_RANGE; } + void InitializeAI(); + void AttackStart(Unit * victim) { AttackStartCaster(victim, m_attackDist); } + void UpdateAI(const uint32 diff); + void EnterCombat(Unit * /*who*/); + private: + float m_attackDist; +}; + +struct ArchorAI : public CreatureAI +{ + public: + explicit ArchorAI(Creature *c); + void AttackStart(Unit *who); + void UpdateAI(const uint32 diff); + + static int Permissible(const Creature *); + protected: + float m_minRange; +}; + +struct TurretAI : public CreatureAI +{ + public: + explicit TurretAI(Creature *c); + bool CanAIAttack(const Unit *who) const; + void AttackStart(Unit *who); + void UpdateAI(const uint32 diff); + + static int Permissible(const Creature *); + protected: + float m_minRange; +}; + +struct AOEAI : public CreatureAI +{ + public: + explicit AOEAI(Creature *c); + bool CanAIAttack(const Unit *who) const; + void AttackStart(Unit *who); + void UpdateAI(const uint32 diff); + + static int Permissible(const Creature *); +}; +#define VEHICLE_CONDITION_CHECK_TIME 1000 +#define VEHICLE_DISMISS_TIME 5000 +struct VehicleAI : public CreatureAI +{ + public: + explicit VehicleAI(Creature *c); + + void UpdateAI(const uint32 diff); + static int Permissible(const Creature *); + void Reset(); + void MoveInLineOfSight(Unit *) {} + void AttackStart(Unit *) {} + void OnCharmed(bool apply); + + private: + Vehicle* m_vehicle; + bool m_IsVehicleInUse; + void LoadConditions(); + void CheckConditions(const uint32 diff); + ConditionList conditions; + uint32 m_ConditionsTimer; + bool m_DoDismiss; + uint32 m_DismissTimer; +}; + +#endif diff --git a/src/server/game/AI/CoreAI/GuardAI.cpp b/src/server/game/AI/CoreAI/GuardAI.cpp new file mode 100644 index 00000000000..19d5b5d8354 --- /dev/null +++ b/src/server/game/AI/CoreAI/GuardAI.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "GuardAI.h" +#include "Errors.h" +#include "Player.h" +#include "ObjectAccessor.h" +#include "World.h" +#include "CreatureAIImpl.h" + +int GuardAI::Permissible(const Creature *creature) +{ + if (creature->isGuard()) + return PERMIT_BASE_SPECIAL; + + return PERMIT_BASE_NO; +} + +GuardAI::GuardAI(Creature *c) : CreatureAI(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK) +{ +} + +void GuardAI::MoveInLineOfSight(Unit *u) +{ + // Ignore Z for flying creatures + if (!me->canFly() && me->GetDistanceZ(u) > CREATURE_Z_ATTACK_RANGE) + return; + + if (!me->getVictim() && me->canAttack(u) && + (u->IsHostileToPlayers() || me->IsHostileTo(u) /*|| u->getVictim() && me->IsFriendlyTo(u->getVictim())*/) && + u->isInAccessiblePlaceFor(me)) + { + float attackRadius = me->GetAttackDistance(u); + if (me->IsWithinDistInMap(u,attackRadius)) + { + //Need add code to let guard support player + AttackStart(u); + //u->RemoveAurasByType(SPELL_AURA_MOD_STEALTH); + } + } +} + +void GuardAI::EnterEvadeMode() +{ + if (!me->isAlive()) + { + DEBUG_LOG("Creature stopped attacking because he is dead [guid=%u]", me->GetGUIDLow()); + me->GetMotionMaster()->MoveIdle(); + + i_state = STATE_NORMAL; + + i_victimGuid = 0; + me->CombatStop(true); + me->DeleteThreatList(); + return; + } + + Unit* victim = ObjectAccessor::GetUnit(*me, i_victimGuid); + + if (!victim) + { + DEBUG_LOG("Creature stopped attacking because victim does not exist [guid=%u]", me->GetGUIDLow()); + } + else if (!victim ->isAlive()) + { + DEBUG_LOG("Creature stopped attacking because victim is dead [guid=%u]", me->GetGUIDLow()); + } + else if (victim ->HasStealthAura()) + { + DEBUG_LOG("Creature stopped attacking because victim is using stealth [guid=%u]", me->GetGUIDLow()); + } + else if (victim ->isInFlight()) + { + DEBUG_LOG("Creature stopped attacking because victim is flying away [guid=%u]", me->GetGUIDLow()); + } + else + { + DEBUG_LOG("Creature stopped attacking because victim outran him [guid=%u]", me->GetGUIDLow()); + } + + me->RemoveAllAuras(); + me->DeleteThreatList(); + i_victimGuid = 0; + me->CombatStop(true); + i_state = STATE_NORMAL; + + // Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead + if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) + me->GetMotionMaster()->MoveTargetedHome(); +} + +void GuardAI::UpdateAI(const uint32 /*diff*/) +{ + // update i_victimGuid if me->getVictim() !=0 and changed + if (!UpdateVictim()) + return; + + i_victimGuid = me->getVictim()->GetGUID(); + + if (me->isAttackReady()) + { + if (me->IsWithinMeleeRange(me->getVictim())) + { + me->AttackerStateUpdate(me->getVictim()); + me->resetAttackTimer(); + } + } +} + +bool GuardAI::IsVisible(Unit *pl) const +{ + return me->IsWithinDist(pl,sWorld.getConfig(CONFIG_SIGHT_GUARDER)) + && pl->isVisibleForOrDetect(me,true); +} + +void GuardAI::JustDied(Unit *killer) +{ + if (Player* pkiller = killer->GetCharmerOrOwnerPlayerOrPlayerItself()) + me->SendZoneUnderAttackMessage(pkiller); +} diff --git a/src/server/game/AI/CoreAI/GuardAI.h b/src/server/game/AI/CoreAI/GuardAI.h new file mode 100644 index 00000000000..73e3692a770 --- /dev/null +++ b/src/server/game/AI/CoreAI/GuardAI.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_GUARDAI_H +#define TRINITY_GUARDAI_H + +#include "CreatureAI.h" +#include "Timer.h" + +class Creature; + +class GuardAI : public CreatureAI +{ + enum GuardState + { + STATE_NORMAL = 1, + STATE_LOOK_AT_VICTIM = 2 + }; + + public: + + explicit GuardAI(Creature *c); + + void MoveInLineOfSight(Unit *); + void EnterEvadeMode(); + void JustDied(Unit *); + bool IsVisible(Unit *) const; + + void UpdateAI(const uint32); + static int Permissible(const Creature *); + + private: + uint64 i_victimGuid; + GuardState i_state; + TimeTracker i_tracker; +}; +#endif + diff --git a/src/server/game/AI/CoreAI/PassiveAI.cpp b/src/server/game/AI/CoreAI/PassiveAI.cpp new file mode 100644 index 00000000000..c6c92f6df04 --- /dev/null +++ b/src/server/game/AI/CoreAI/PassiveAI.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PassiveAI.h" +#include "Creature.h" +#include "TemporarySummon.h" + +PassiveAI::PassiveAI(Creature *c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); } +PossessedAI::PossessedAI(Creature *c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); } +NullCreatureAI::NullCreatureAI(Creature *c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); } + +void PassiveAI::UpdateAI(const uint32) +{ + if (me->isInCombat() && me->getAttackers().empty()) + EnterEvadeMode(); +} + +void PossessedAI::AttackStart(Unit *target) +{ + me->Attack(target, true); +} + +void PossessedAI::UpdateAI(const uint32 /*diff*/) +{ + if (me->getVictim()) + { + if (!me->canAttack(me->getVictim())) + me->AttackStop(); + else + DoMeleeAttackIfReady(); + } +} + +void PossessedAI::JustDied(Unit * /*u*/) +{ + // We died while possessed, disable our loot + me->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); +} + +void PossessedAI::KilledUnit(Unit* victim) +{ + // We killed a creature, disable victim's loot + if (victim->GetTypeId() == TYPEID_UNIT) + victim->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); +} + +void CritterAI::DamageTaken(Unit * /*done_by*/, uint32 &) +{ + if (!me->hasUnitState(UNIT_STAT_FLEEING)) + me->SetControlled(true, UNIT_STAT_FLEEING); +} + +void CritterAI::EnterEvadeMode() +{ + if (me->hasUnitState(UNIT_STAT_FLEEING)) + me->SetControlled(false, UNIT_STAT_FLEEING); + CreatureAI::EnterEvadeMode(); +} + +void TriggerAI::IsSummonedBy(Unit *summoner) +{ + if (me->m_spells[0]) + me->CastSpell(me, me->m_spells[0], false, 0, 0, summoner->GetGUID()); +} diff --git a/src/server/game/AI/CoreAI/PassiveAI.h b/src/server/game/AI/CoreAI/PassiveAI.h new file mode 100644 index 00000000000..c13e2d1a63c --- /dev/null +++ b/src/server/game/AI/CoreAI/PassiveAI.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_PASSIVEAI_H +#define TRINITY_PASSIVEAI_H + +#include "CreatureAI.h" +//#include "CreatureAIImpl.h" + +class PassiveAI : public CreatureAI +{ + public: + explicit PassiveAI(Creature *c); + + void MoveInLineOfSight(Unit *) {} + void AttackStart(Unit *) {} + void UpdateAI(const uint32); + + static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; } +}; + +class PossessedAI : public CreatureAI +{ + public: + explicit PossessedAI(Creature *c); + + void MoveInLineOfSight(Unit *) {} + void AttackStart(Unit *target); + void UpdateAI(const uint32); + void EnterEvadeMode() {} + + void JustDied(Unit*); + void KilledUnit(Unit* victim); + + static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; } +}; + +class NullCreatureAI : public CreatureAI +{ + public: + explicit NullCreatureAI(Creature *c); + + void MoveInLineOfSight(Unit *) {} + void AttackStart(Unit *) {} + void UpdateAI(const uint32) {} + void EnterEvadeMode() {} + void OnCharmed(bool /*apply*/) {} + + static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; } +}; + +class CritterAI : public PassiveAI +{ + public: + explicit CritterAI(Creature *c) : PassiveAI(c) {} + + void DamageTaken(Unit *done_by, uint32 & /*damage*/); + void EnterEvadeMode(); +}; + +class TriggerAI : public NullCreatureAI +{ + public: + explicit TriggerAI(Creature *c) : NullCreatureAI(c) {} + void IsSummonedBy(Unit *summoner); +}; + +#endif + diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp new file mode 100644 index 00000000000..09ec8fae53f --- /dev/null +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -0,0 +1,471 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PetAI.h" +#include "Errors.h" +#include "Pet.h" +#include "Player.h" +#include "DBCStores.h" +#include "Spell.h" +#include "ObjectAccessor.h" +#include "SpellMgr.h" +#include "Creature.h" +#include "World.h" +#include "Util.h" + +int PetAI::Permissible(const Creature *creature) +{ + if (creature->isPet()) + return PERMIT_BASE_SPECIAL; + + return PERMIT_BASE_NO; +} + +PetAI::PetAI(Creature *c) : CreatureAI(c), i_tracker(TIME_INTERVAL_LOOK) +{ + m_AllySet.clear(); + UpdateAllies(); +} + +void PetAI::EnterEvadeMode() +{ +} + +bool PetAI::_needToStop() const +{ + // This is needed for charmed creatures, as once their target was reset other effects can trigger threat + if (me->isCharmed() && me->getVictim() == me->GetCharmer()) + return true; + + return !me->canAttack(me->getVictim()); +} + +void PetAI::_stopAttack() +{ + if (!me->isAlive()) + { + DEBUG_LOG("Creature stoped attacking cuz his dead [guid=%u]", me->GetGUIDLow()); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveIdle(); + me->CombatStop(); + me->getHostileRefManager().deleteReferences(); + + return; + } + + me->AttackStop(); + me->GetCharmInfo()->SetIsCommandAttack(false); + HandleReturnMovement(); +} + +void PetAI::UpdateAI(const uint32 diff) +{ + if (!me->isAlive()) + return; + + Unit* owner = me->GetCharmerOrOwner(); + + if (m_updateAlliesTimer <= diff) + // UpdateAllies self set update timer + UpdateAllies(); + else + m_updateAlliesTimer -= diff; + + // me->getVictim() can't be used for check in case stop fighting, me->getVictim() clear at Unit death etc. + if (me->getVictim()) + { + if (_needToStop()) + { + DEBUG_LOG("Pet AI stoped attacking [guid=%u]", me->GetGUIDLow()); + _stopAttack(); + return; + } + + DoMeleeAttackIfReady(); + } + else if (owner && me->GetCharmInfo()) //no victim + { + Unit *nextTarget = SelectNextTarget(); + + if (nextTarget) + AttackStart(nextTarget); + else + HandleReturnMovement(); + } + else if (owner && !me->hasUnitState(UNIT_STAT_FOLLOW)) // no charm info and no victim + me->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST, me->GetFollowAngle()); + + if (!me->GetCharmInfo()) + return; + + // Autocast (casted only in combat or persistent spells in any state) + if (me->GetGlobalCooldown() == 0 && !me->hasUnitState(UNIT_STAT_CASTING)) + { + typedef std::vector > TargetSpellList; + TargetSpellList targetSpellStore; + + for (uint8 i = 0; i < me->GetPetAutoSpellSize(); ++i) + { + uint32 spellID = me->GetPetAutoSpellOnPos(i); + if (!spellID) + continue; + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID); + if (!spellInfo) + continue; + + // ignore some combinations of combat state and combat/noncombat spells + if (!me->getVictim()) + { + // ignore attacking spells, and allow only self/around spells + if (!IsPositiveSpell(spellInfo->Id)) + continue; + + // non combat spells allowed + // only pet spells have IsNonCombatSpell and not fit this reqs: + // Consume Shadows, Lesser Invisibility, so ignore checks for its + if (!IsNonCombatSpell(spellInfo)) + { + // allow only spell without spell cost or with spell cost but not duration limit + int32 duration = GetSpellDuration(spellInfo); + if ((spellInfo->manaCost || spellInfo->ManaCostPercentage || spellInfo->manaPerSecond) && duration > 0) + continue; + + // allow only spell without cooldown > duration + int32 cooldown = GetSpellRecoveryTime(spellInfo); + if (cooldown >= 0 && duration >= 0 && cooldown > duration) + continue; + } + } + else + { + // just ignore non-combat spells + if (IsNonCombatSpell(spellInfo)) + continue; + } + + Spell *spell = new Spell(me, spellInfo, false, 0); + + // Fix to allow pets on STAY to autocast + if (me->getVictim() && _CanAttack(me->getVictim()) && spell->CanAutoCast(me->getVictim())) + { + targetSpellStore.push_back(std::make_pair(me->getVictim(), spell)); + continue; + } + else + { + bool spellUsed = false; + for (std::set::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar) + { + Unit* Target = ObjectAccessor::GetUnit(*me,*tar); + + //only buff targets that are in combat, unless the spell can only be cast while out of combat + if (!Target) + continue; + + if (spell->CanAutoCast(Target)) + { + targetSpellStore.push_back(std::make_pair(Target, spell)); + spellUsed = true; + break; + } + } + if (!spellUsed) + delete spell; + } + } + + //found units to cast on to + if (!targetSpellStore.empty()) + { + uint32 index = urand(0, targetSpellStore.size() - 1); + + Spell* spell = targetSpellStore[index].second; + Unit* target = targetSpellStore[index].first; + + targetSpellStore.erase(targetSpellStore.begin() + index); + + SpellCastTargets targets; + targets.setUnitTarget(target); + + if (!me->HasInArc(M_PI, target)) + { + me->SetInFront(target); + if (target && target->GetTypeId() == TYPEID_PLAYER) + me->SendUpdateToPlayer(target->ToPlayer()); + + if (owner && owner->GetTypeId() == TYPEID_PLAYER) + me->SendUpdateToPlayer(owner->ToPlayer()); + } + + me->AddCreatureSpellCooldown(spell->m_spellInfo->Id); + + spell->prepare(&targets); + } + + // deleted cached Spell objects + for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr) + delete itr->second; + } +} + +void PetAI::UpdateAllies() +{ + Unit* owner = me->GetCharmerOrOwner(); + Group *pGroup = NULL; + + m_updateAlliesTimer = 10*IN_MILISECONDS; //update friendly targets every 10 seconds, lesser checks increase performance + + if (!owner) + return; + else if (owner->GetTypeId() == TYPEID_PLAYER) + pGroup = owner->ToPlayer()->GetGroup(); + + //only pet and owner/not in group->ok + if (m_AllySet.size() == 2 && !pGroup) + return; + //owner is in group; group members filled in already (no raid -> subgroupcount = whole count) + if (pGroup && !pGroup->isRaidGroup() && m_AllySet.size() == (pGroup->GetMembersCount() + 2)) + return; + + m_AllySet.clear(); + m_AllySet.insert(me->GetGUID()); + if (pGroup) //add group + { + for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* Target = itr->getSource(); + if (!Target || !pGroup->SameSubGroup((Player*)owner, Target)) + continue; + + if (Target->GetGUID() == owner->GetGUID()) + continue; + + m_AllySet.insert(Target->GetGUID()); + } + } + else //remove group + m_AllySet.insert(owner->GetGUID()); +} + +void PetAI::KilledUnit(Unit *victim) +{ + // Called from Unit::Kill() in case where pet or owner kills something + // if owner killed this victim, pet may still be attacking something else + if (me->getVictim() && me->getVictim() != victim) + return; + + // Clear target just in case. May help problem where health / focus / mana + // regen gets stuck. Also resets attack command. + // Can't use _stopAttack() because that activates movement handlers and ignores + // next target selection + me->AttackStop(); + me->GetCharmInfo()->SetIsCommandAttack(false); + + Unit *nextTarget = SelectNextTarget(); + + if (nextTarget) + AttackStart(nextTarget); + else + HandleReturnMovement(); // Return +} + +void PetAI::AttackStart(Unit *target) +{ + // Overrides Unit::AttackStart to correctly evaluate Pet states + + // Check all pet states to decide if we can attack this target + if (!_CanAttack(target)) + return; + + // We can attack, should we chase or not? + if (me->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW)) + DoAttack(target,true); // FOLLOW, attack with chase + else + { + if (me->GetCharmInfo()->IsCommandAttack()) + DoAttack(target,true); // STAY or FOLLOW, player clicked "attack" so attack with chase + else + DoAttack(target,false); // STAY, target in range, attack not clicked so attack without chase + } +} + +Unit *PetAI::SelectNextTarget() +{ + // Provides next target selection after current target death + + // Passive pets don't do next target selection + if (me->HasReactState(REACT_PASSIVE)) + return NULL; + + // Check pet's attackers first to prevent dragging mobs back + // to owner + if (me->getAttackerForHelper()) + return me->getAttackerForHelper(); + + // Check owner's attackers if pet didn't have any + if (me->GetCharmerOrOwner()->getAttackerForHelper()) + return me->GetCharmerOrOwner()->getAttackerForHelper(); + + // 3.0.2 - Pets now start attacking their owners target in defensive mode as soon as the hunter does + if (me->GetCharmerOrOwner()->getVictim()) + return me->GetCharmerOrOwner()->getVictim(); + + // Default + return NULL; +} + +void PetAI::HandleReturnMovement() +{ + // Handles moving the pet back to stay or owner + + if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY)) + { + if (!me->GetCharmInfo()->IsAtStay() && !me->GetCharmInfo()->IsReturning()) + { + // Return to previous position where stay was clicked + if (!me->GetCharmInfo()->IsCommandAttack()) + { + float x,y,z; + + me->GetCharmInfo()->GetStayPosition(x, y, z); + me->GetCharmInfo()->SetIsReturning(true); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MovePoint(me->GetGUIDLow(),x,y,z); + } + } + } + else // COMMAND_FOLLOW + { + if (!me->GetCharmInfo()->IsFollowing() && !me->GetCharmInfo()->IsReturning()) + { + if (!me->GetCharmInfo()->IsCommandAttack()) + { + me->GetCharmInfo()->SetIsReturning(true); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveFollow(me->GetCharmerOrOwner(), PET_FOLLOW_DIST, me->GetFollowAngle()); + } + } + } + +} + +void PetAI::DoAttack(Unit *target, bool chase) +{ + // Handles attack with or without chase and also resets all + // PetAI flags for next update / creature kill + + // me->GetCharmInfo()->SetIsCommandAttack(false); + + // The following conditions are true if chase == true + // (Follow && (Aggressive || Defensive)) + // ((Stay || Follow) && (Passive && player clicked attack)) + + if (chase) + { + if (me->Attack(target,true)) + { + me->GetCharmInfo()->SetIsAtStay(false); + me->GetCharmInfo()->SetIsFollowing(false); + me->GetCharmInfo()->SetIsReturning(false); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveChase(target); + } + } + else // (Stay && ((Aggressive || Defensive) && In Melee Range))) + { + me->GetCharmInfo()->SetIsAtStay(true); + me->GetCharmInfo()->SetIsFollowing(false); + me->GetCharmInfo()->SetIsReturning(false); + me->Attack(target,true); + } +} + +void PetAI::MovementInform(uint32 moveType, uint32 data) +{ + // Receives notification when pet reaches stay or follow owner + switch (moveType) + { + case POINT_MOTION_TYPE: + { + // Pet is returning to where stay was clicked. data should be + // pet's GUIDLow since we set that as the waypoint ID + if (data == me->GetGUIDLow() && me->GetCharmInfo()->IsReturning()) + { + me->GetCharmInfo()->SetIsAtStay(true); + me->GetCharmInfo()->SetIsReturning(false); + me->GetCharmInfo()->SetIsFollowing(false); + me->GetCharmInfo()->SetIsCommandAttack(false); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveIdle(); + } + } + break; + + case TARGETED_MOTION_TYPE: + { + // If data is owner's GUIDLow then we've reached follow point, + // otherwise we're probably chasing a creature + if (me->GetCharmerOrOwner() && me->GetCharmInfo() && data == me->GetCharmerOrOwner()->GetGUIDLow() && me->GetCharmInfo()->IsReturning()) + { + me->GetCharmInfo()->SetIsAtStay(false); + me->GetCharmInfo()->SetIsReturning(false); + me->GetCharmInfo()->SetIsFollowing(true); + me->GetCharmInfo()->SetIsCommandAttack(false); + me->addUnitState(UNIT_STAT_FOLLOW); + } + } + break; + + default: + break; + } +} + +bool PetAI::_CanAttack(Unit *target) +{ + // Evaluates wether a pet can attack a specific + // target based on CommandState, ReactState and other flags + + // Returning - check first since pets returning ignore attacks + if (me->GetCharmInfo()->IsReturning()) + return false; + + // Passive - check now so we don't have to worry about passive in later checks + if (me->HasReactState(REACT_PASSIVE)) + return me->GetCharmInfo()->IsCommandAttack(); + + // Pets commanded to attack should not stop their approach if attacked by another creature + if (me->getVictim() && (me->getVictim() != target)) + return !me->GetCharmInfo()->IsCommandAttack(); + + // From this point on, pet will always be either aggressive or defensive + + // Stay - can attack if target is within range or commanded to + if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY)) + return (me->IsWithinMeleeRange(target, MIN_MELEE_REACH) || me->GetCharmInfo()->IsCommandAttack()); + + // Follow + if (me->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW)) + return true; + + // default, though we shouldn't ever get here + return false; +} diff --git a/src/server/game/AI/CoreAI/PetAI.h b/src/server/game/AI/CoreAI/PetAI.h new file mode 100644 index 00000000000..f6087a129ae --- /dev/null +++ b/src/server/game/AI/CoreAI/PetAI.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_PETAI_H +#define TRINITY_PETAI_H + +#include "CreatureAI.h" +#include "Timer.h" + +class Creature; +class Spell; + +class PetAI : public CreatureAI +{ + public: + + explicit PetAI(Creature *c); + + void EnterEvadeMode(); + void JustDied(Unit * /*who*/) { _stopAttack(); } + + void UpdateAI(const uint32); + static int Permissible(const Creature *); + + void KilledUnit(Unit * /*victim*/); + void AttackStart(Unit *target); + void MovementInform(uint32 moveType, uint32 data); + + private: + bool _isVisible(Unit *) const; + bool _needToStop(void) const; + void _stopAttack(void); + + void UpdateAllies(); + + TimeTracker i_tracker; + bool inCombat; + std::set m_AllySet; + uint32 m_updateAlliesTimer; + + Unit *SelectNextTarget(); + void HandleReturnMovement(); + void DoAttack(Unit *target, bool chase); + bool _CanAttack(Unit *target); +}; +#endif + diff --git a/src/server/game/AI/CoreAI/ReactorAI.cpp b/src/server/game/AI/CoreAI/ReactorAI.cpp new file mode 100644 index 00000000000..fdca6314747 --- /dev/null +++ b/src/server/game/AI/CoreAI/ReactorAI.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ByteBuffer.h" +#include "ReactorAI.h" +#include "Errors.h" +#include "Log.h" +#include "ObjectAccessor.h" +#include "CreatureAIImpl.h" + +#define REACTOR_VISIBLE_RANGE (26.46f) + +int +ReactorAI::Permissible(const Creature *creature) +{ + if (creature->isCivilian() || creature->IsNeutralToAll()) + return PERMIT_BASE_REACTIVE; + + return PERMIT_BASE_NO; +} + +void +ReactorAI::MoveInLineOfSight(Unit *) +{ +} + +void +ReactorAI::UpdateAI(const uint32 /*time_diff*/) +{ + // update i_victimGuid if me->getVictim() !=0 and changed + if (!UpdateVictim()) + return; + + if (me->isAttackReady()) + { + if (me->IsWithinMeleeRange(me->getVictim())) + { + me->AttackerStateUpdate(me->getVictim()); + me->resetAttackTimer(); + } + } +} diff --git a/src/server/game/AI/CoreAI/ReactorAI.h b/src/server/game/AI/CoreAI/ReactorAI.h new file mode 100644 index 00000000000..ae4e6403962 --- /dev/null +++ b/src/server/game/AI/CoreAI/ReactorAI.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_REACTORAI_H +#define TRINITY_REACTORAI_H + +#include "CreatureAI.h" + +class Unit; + +class ReactorAI : public CreatureAI +{ + public: + + explicit ReactorAI(Creature *c) : CreatureAI(c) {} + + void MoveInLineOfSight(Unit *); + + void UpdateAI(const uint32); + static int Permissible(const Creature *); +}; +#endif + diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp new file mode 100644 index 00000000000..a6464f189e8 --- /dev/null +++ b/src/server/game/AI/CoreAI/TotemAI.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "TotemAI.h" +#include "Totem.h" +#include "Creature.h" +#include "DBCStores.h" +#include "ObjectAccessor.h" +#include "SpellMgr.h" + +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" + +int +TotemAI::Permissible(const Creature *creature) +{ + if (creature->isTotem()) + return PERMIT_BASE_PROACTIVE; + + return PERMIT_BASE_NO; +} + +TotemAI::TotemAI(Creature *c) : CreatureAI(c), i_victimGuid(0) +{ + assert(c->isTotem()); +} + +void +TotemAI::MoveInLineOfSight(Unit *) +{ +} + +void TotemAI::EnterEvadeMode() +{ + me->CombatStop(true); +} + +void +TotemAI::UpdateAI(const uint32 /*diff*/) +{ + if (me->ToTotem()->GetTotemType() != TOTEM_ACTIVE) + return; + + if (!me->isAlive() || me->IsNonMeleeSpellCasted(false)) + return; + + // Search spell + SpellEntry const *spellInfo = sSpellStore.LookupEntry(me->ToTotem()->GetSpell()); + if (!spellInfo) + return; + + // Get spell range + SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); + float max_range = GetSpellMaxRangeForHostile(srange); + + // SPELLMOD_RANGE not applied in this place just because not existence range mods for attacking totems + + // pointer to appropriate target if found any + Unit* victim = i_victimGuid ? ObjectAccessor::GetUnit(*me, i_victimGuid) : NULL; + + // Search victim if no, not attackable, or out of range, or friendly (possible in case duel end) + if (!victim || + !victim->isTargetableForAttack() || !me->IsWithinDistInMap(victim, max_range) || + me->IsFriendlyTo(victim) || !victim->isVisibleForOrDetect(me,false)) + { + victim = NULL; + Trinity::NearestAttackableUnitInObjectRangeCheck u_check(me, me, max_range); + Trinity::UnitLastSearcher checker(me, victim, u_check); + me->VisitNearbyObject(max_range, checker); + } + + // If have target + if (victim) + { + // remember + i_victimGuid = victim->GetGUID(); + + // attack + me->SetInFront(victim); // client change orientation by self + me->CastSpell(victim, me->ToTotem()->GetSpell(), false); + } + else + i_victimGuid = 0; +} + +void +TotemAI::AttackStart(Unit *) +{ + // Sentry totem sends ping on attack + if (me->GetEntry() == SENTRY_TOTEM_ENTRY && me->GetOwner()->GetTypeId() == TYPEID_PLAYER) + { + WorldPacket data(MSG_MINIMAP_PING, (8+4+4)); + data << me->GetGUID(); + data << me->GetPositionX(); + data << me->GetPositionY(); + ((Player*)me->GetOwner())->GetSession()->SendPacket(&data); + } +} diff --git a/src/server/game/AI/CoreAI/TotemAI.h b/src/server/game/AI/CoreAI/TotemAI.h new file mode 100644 index 00000000000..34f4dfa9945 --- /dev/null +++ b/src/server/game/AI/CoreAI/TotemAI.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_TOTEMAI_H +#define TRINITY_TOTEMAI_H + +#include "CreatureAI.h" +#include "Timer.h" + +class Creature; +class Totem; + +class TotemAI : public CreatureAI +{ + public: + + explicit TotemAI(Creature *c); + + void MoveInLineOfSight(Unit *); + void AttackStart(Unit *); + void EnterEvadeMode(); + + void UpdateAI(const uint32); + static int Permissible(const Creature *); + + private: + uint64 i_victimGuid; +}; +#endif + diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp new file mode 100644 index 00000000000..a156ec573d9 --- /dev/null +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "UnitAI.h" +#include "Player.h" +#include "Creature.h" +#include "SpellAuras.h" +#include "SpellAuraEffects.h" +#include "SpellMgr.h" +#include "CreatureAIImpl.h" + +void UnitAI::AttackStart(Unit *victim) +{ + if (victim && me->Attack(victim, true)) + me->GetMotionMaster()->MoveChase(victim); +} + +void UnitAI::AttackStartCaster(Unit *victim, float dist) +{ + if (victim && me->Attack(victim, false)) + me->GetMotionMaster()->MoveChase(victim, dist); +} + +void UnitAI::DoMeleeAttackIfReady() +{ + if (me->hasUnitState(UNIT_STAT_CASTING)) + return; + + //Make sure our attack is ready and we aren't currently casting before checking distance + if (me->isAttackReady()) + { + //If we are within range melee the target + if (me->IsWithinMeleeRange(me->getVictim())) + { + me->AttackerStateUpdate(me->getVictim()); + me->resetAttackTimer(); + } + } + if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK)) + { + //If we are within range melee the target + if (me->IsWithinMeleeRange(me->getVictim())) + { + me->AttackerStateUpdate(me->getVictim(), OFF_ATTACK); + me->resetAttackTimer(OFF_ATTACK); + } + } +} + +bool UnitAI::DoSpellAttackIfReady(uint32 spell) +{ + if (me->hasUnitState(UNIT_STAT_CASTING)) + return true; + + if (me->isAttackReady()) + { + if (me->IsWithinCombatRange(me->getVictim(), GetSpellMaxRange(spell, false))) + { + me->CastSpell(me->getVictim(), spell, false); + me->resetAttackTimer(); + } + else + return false; + } + return true; +} + +// default predicate function to select target based on distance, player and/or aura criteria +struct DefaultTargetSelector : public std::unary_function +{ + const Unit *me; + float m_dist; + bool m_playerOnly; + int32 m_aura; + + // pUnit: the reference unit + // dist: if 0: ignored, if > 0: maximum distance to the reference unit, if < 0: minimum distance to the reference unit + // playerOnly: self explaining + // aura: if 0: ignored, if > 0: the target shall have the aura, if < 0, the target shall NOT have the aura + DefaultTargetSelector(const Unit *pUnit, float dist, bool playerOnly, int32 aura) : me(pUnit), m_dist(dist), m_playerOnly(playerOnly), m_aura(aura) {} + + bool operator() (const Unit *pTarget) + { + if (!me) + return false; + + if (!pTarget) + return false; + + if (m_playerOnly && (pTarget->GetTypeId() != TYPEID_PLAYER)) + return false; + + if (m_dist > 0.0f && !me->IsWithinCombatRange(pTarget, m_dist)) + return false; + + if (m_dist < 0.0f && me->IsWithinCombatRange(pTarget, -m_dist)) + return false; + + if (m_aura) + { + if (m_aura > 0) + { + if (!pTarget->HasAura(m_aura)) + return false; + } + else + { + if (pTarget->HasAura(m_aura)) + return false; + } + } + + return true; + } +}; + +Unit* UnitAI::SelectTarget(SelectAggroTarget targetType, uint32 position, float dist, bool playerOnly, int32 aura) +{ + return SelectTarget(targetType, position, DefaultTargetSelector(me, dist, playerOnly, aura)); +} + +void UnitAI::SelectTargetList(std::list &targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly, int32 aura) +{ + const std::list &threatlist = me->getThreatManager().getThreatList(); + + if (threatlist.empty()) + return; + + DefaultTargetSelector targetSelector(me, dist,playerOnly, aura); + for (std::list::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) + if (targetSelector((*itr)->getTarget())) + targetList.push_back((*itr)->getTarget()); + + if (targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) + targetList.sort(Trinity::ObjectDistanceOrderPred(me)); + + if (targetType == SELECT_TARGET_FARTHEST || targetType == SELECT_TARGET_BOTTOMAGGRO) + targetList.reverse(); + + if (targetList.size() < num) + return; + + if (targetType == SELECT_TARGET_RANDOM) + { + while (num < targetList.size()) { + std::list::iterator itr = targetList.begin(); + advance(itr, urand(0, targetList.size()-1)); + targetList.erase(itr); + } + } + else + targetList.resize(num); +} + +float UnitAI::DoGetSpellMaxRange(uint32 spellId, bool positive) +{ + return GetSpellMaxRange(spellId, positive); +} + +void UnitAI::DoAddAuraToAllHostilePlayers(uint32 spellid) +{ + if (me->isInCombat()) + { + std::list& threatlist = me->getThreatManager().getThreatList(); + for (std::list::iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) + { + if (Unit *pTemp = Unit::GetUnit(*me,(*itr)->getUnitGuid())) + if (pTemp->GetTypeId() == TYPEID_PLAYER) + me->AddAura(spellid, pTemp); + } + }else + return; +} + +void UnitAI::DoCastToAllHostilePlayers(uint32 spellid, bool triggered) +{ + if (me->isInCombat()) + { + std::list& threatlist = me->getThreatManager().getThreatList(); + for (std::list::iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) + { + if (Unit *pTemp = Unit::GetUnit(*me,(*itr)->getUnitGuid())) + if (pTemp->GetTypeId() == TYPEID_PLAYER) + me->CastSpell(pTemp, spellid, triggered); + } + }else + return; +} + +void UnitAI::DoCast(uint32 spellId) +{ + Unit *target = NULL; + //sLog.outError("aggre %u %u", spellId, (uint32)AISpellInfo[spellId].target); + switch(AISpellInfo[spellId].target) + { + default: + case AITARGET_SELF: target = me; break; + case AITARGET_VICTIM: target = me->getVictim(); break; + case AITARGET_ENEMY: + { + const SpellEntry * spellInfo = GetSpellStore()->LookupEntry(spellId); + bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY; + //float range = GetSpellMaxRange(spellInfo, false); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, GetSpellMaxRange(spellInfo, false), playerOnly); + break; + } + case AITARGET_ALLY: target = me; break; + case AITARGET_BUFF: target = me; break; + case AITARGET_DEBUFF: + { + const SpellEntry * spellInfo = GetSpellStore()->LookupEntry(spellId); + bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY; + float range = GetSpellMaxRange(spellInfo, false); + + DefaultTargetSelector targetSelector(me, range, playerOnly, -(int32)spellId); + if (!(spellInfo->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE) + && !(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM) + && targetSelector(me->getVictim())) + target = me->getVictim(); + else + target = SelectTarget(SELECT_TARGET_RANDOM, 0, targetSelector); + break; + } + } + + if (target) + me->CastSpell(target, spellId, false); +} + +#define UPDATE_TARGET(a) {if (AIInfo->targettarget=a;} + +void UnitAI::FillAISpellInfo() +{ + AISpellInfo = new AISpellInfoType[GetSpellStore()->GetNumRows()]; + + AISpellInfoType *AIInfo = AISpellInfo; + const SpellEntry * spellInfo; + + for (uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i, ++AIInfo) + { + spellInfo = GetSpellStore()->LookupEntry(i); + if (!spellInfo) + continue; + + if (spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD) + AIInfo->condition = AICOND_DIE; + else if (IsPassiveSpell(i) || GetSpellDuration(spellInfo) == -1) + AIInfo->condition = AICOND_AGGRO; + else + AIInfo->condition = AICOND_COMBAT; + + if (AIInfo->cooldown < spellInfo->RecoveryTime) + AIInfo->cooldown = spellInfo->RecoveryTime; + + if (!GetSpellMaxRange(spellInfo, false)) + UPDATE_TARGET(AITARGET_SELF) + else + { + for (uint32 j = 0; j < 3; ++j) + { + uint32 targetType = spellInfo->EffectImplicitTargetA[j]; + + if (targetType == TARGET_UNIT_TARGET_ENEMY + || targetType == TARGET_DST_TARGET_ENEMY) + UPDATE_TARGET(AITARGET_VICTIM) + else if (targetType == TARGET_UNIT_AREA_ENEMY_DST) + UPDATE_TARGET(AITARGET_ENEMY) + + if (spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA) + { + if (targetType == TARGET_UNIT_TARGET_ENEMY) + UPDATE_TARGET(AITARGET_DEBUFF) + else if (IsPositiveSpell(i)) + UPDATE_TARGET(AITARGET_BUFF) + } + } + } + AIInfo->realCooldown = spellInfo->RecoveryTime + spellInfo->StartRecoveryTime; + SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); + if (srange) + AIInfo->maxRange = srange->maxRangeHostile * 3 / 4; + } +} + +//Enable PlayerAI when charmed +void PlayerAI::OnCharmed(bool apply) { me->IsAIEnabled = apply; } + +void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/) +{ + Creature *charmer = me->GetCharmer()->ToCreature(); + + //kill self if charm aura has infinite duration + if (charmer->IsInEvadeMode()) + { + Unit::AuraEffectList const& auras = me->GetAuraEffectsByType(SPELL_AURA_MOD_CHARM); + for (Unit::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) + if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetBase()->IsPermanent()) + { + charmer->Kill(me); + return; + } + } + + if (!charmer->isInCombat()) + me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, me->GetFollowAngle()); + + Unit *target = me->getVictim(); + if (!target || !charmer->canAttack(target)) + AttackStart(charmer->SelectNearestTargetInAttackDistance()); +} diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h new file mode 100644 index 00000000000..62b7090a2d0 --- /dev/null +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_UNITAI_H +#define TRINITY_UNITAI_H + +#include "Platform/Define.h" +#include +#include "Unit.h" + +class Unit; +class Player; +struct AISpellInfoType; + +//Selection method used by SelectTarget +enum SelectAggroTarget +{ + SELECT_TARGET_RANDOM = 0, //Just selects a random target + SELECT_TARGET_TOPAGGRO, //Selects targes from top aggro to bottom + SELECT_TARGET_BOTTOMAGGRO, //Selects targets from bottom aggro to top + SELECT_TARGET_NEAREST, + SELECT_TARGET_FARTHEST, +}; + +class UnitAI +{ + protected: + Unit * const me; + public: + explicit UnitAI(Unit *u) : me(u) {} + virtual ~UnitAI() {} + + virtual bool CanAIAttack(const Unit * /*who*/) const { return true; } + virtual void AttackStart(Unit *); + virtual void UpdateAI(const uint32 diff) = 0; + + virtual void InitializeAI() { if (!me->isDead()) Reset(); } + + virtual void Reset() {}; + + // Called when unit is charmed + virtual void OnCharmed(bool apply) = 0; + + // Pass parameters between AI + virtual void DoAction(const int32 /*param*/ = 0) {} + virtual uint32 GetData(uint32 /*id = 0*/) { return 0; } + virtual void SetData(uint32 /*id*/, uint32 /*value*/) {} + virtual void SetGUID(const uint64 &/*guid*/, int32 /*id*/ = 0) {} + virtual uint64 GetGUID(int32 /*id*/ = 0) { return 0; } + + Unit* SelectTarget(SelectAggroTarget targetType, uint32 position = 0, float dist = 0.0f, bool playerOnly = false, int32 aura = 0); + void SelectTargetList(std::list &targetList, uint32 num, SelectAggroTarget targetType, float dist = 0.0f, bool playerOnly = false, int32 aura = 0); + + // Select the targets satifying the predicate. + // predicate shall extend std::unary_function + template Unit* SelectTarget(SelectAggroTarget targetType, uint32 position, PREDICATE predicate) + { + const std::list &threatlist = me->getThreatManager().getThreatList(); + std::list targetList; + + if (position >= threatlist.size()) + return NULL; + + for (std::list::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) + { + HostileReference* ref = (*itr); + if (predicate(ref->getTarget())) + targetList.push_back(ref->getTarget()); + } + + if (position >= targetList.size()) + return NULL; + + if (targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) + targetList.sort(Trinity::ObjectDistanceOrderPred(me)); + + switch(targetType) + { + case SELECT_TARGET_NEAREST: + case SELECT_TARGET_TOPAGGRO: + { + std::list::iterator itr = targetList.begin(); + advance(itr, position); + return *itr; + } + break; + + case SELECT_TARGET_FARTHEST: + case SELECT_TARGET_BOTTOMAGGRO: + { + std::list::reverse_iterator ritr = targetList.rbegin(); + advance(ritr, position); + return *ritr; + } + break; + + case SELECT_TARGET_RANDOM: + { + std::list::iterator itr = targetList.begin(); + advance(itr, urand(position, targetList.size()-1)); + return *itr; + } + break; + } + + return NULL; + } + + void AttackStartCaster(Unit *victim, float dist); + + void DoAddAuraToAllHostilePlayers(uint32 spellid); + void DoCast(uint32 spellId); + void DoCast(Unit* victim, uint32 spellId, bool triggered = false); + void DoCastToAllHostilePlayers(uint32 spellid, bool triggered = false); + void DoCastVictim(uint32 spellId, bool triggered = false); + void DoCastAOE(uint32 spellId, bool triggered = false); + + float DoGetSpellMaxRange(uint32 spellId, bool positive = false); + + void DoMeleeAttackIfReady(); + bool DoSpellAttackIfReady(uint32 spell); + + static AISpellInfoType *AISpellInfo; + static void FillAISpellInfo(); +}; + +class PlayerAI : public UnitAI +{ + protected: + Player* const me; + public: + explicit PlayerAI(Player *p) : UnitAI((Unit*)p), me(p) {} + + void OnCharmed(bool apply); +}; + +class SimpleCharmedAI : public PlayerAI +{ + public: + void UpdateAI(const uint32 diff); + SimpleCharmedAI(Player *p): PlayerAI(p) {} +}; + +#endif diff --git a/src/server/game/AI/GuardAI.cpp b/src/server/game/AI/GuardAI.cpp deleted file mode 100644 index 19d5b5d8354..00000000000 --- a/src/server/game/AI/GuardAI.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "GuardAI.h" -#include "Errors.h" -#include "Player.h" -#include "ObjectAccessor.h" -#include "World.h" -#include "CreatureAIImpl.h" - -int GuardAI::Permissible(const Creature *creature) -{ - if (creature->isGuard()) - return PERMIT_BASE_SPECIAL; - - return PERMIT_BASE_NO; -} - -GuardAI::GuardAI(Creature *c) : CreatureAI(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK) -{ -} - -void GuardAI::MoveInLineOfSight(Unit *u) -{ - // Ignore Z for flying creatures - if (!me->canFly() && me->GetDistanceZ(u) > CREATURE_Z_ATTACK_RANGE) - return; - - if (!me->getVictim() && me->canAttack(u) && - (u->IsHostileToPlayers() || me->IsHostileTo(u) /*|| u->getVictim() && me->IsFriendlyTo(u->getVictim())*/) && - u->isInAccessiblePlaceFor(me)) - { - float attackRadius = me->GetAttackDistance(u); - if (me->IsWithinDistInMap(u,attackRadius)) - { - //Need add code to let guard support player - AttackStart(u); - //u->RemoveAurasByType(SPELL_AURA_MOD_STEALTH); - } - } -} - -void GuardAI::EnterEvadeMode() -{ - if (!me->isAlive()) - { - DEBUG_LOG("Creature stopped attacking because he is dead [guid=%u]", me->GetGUIDLow()); - me->GetMotionMaster()->MoveIdle(); - - i_state = STATE_NORMAL; - - i_victimGuid = 0; - me->CombatStop(true); - me->DeleteThreatList(); - return; - } - - Unit* victim = ObjectAccessor::GetUnit(*me, i_victimGuid); - - if (!victim) - { - DEBUG_LOG("Creature stopped attacking because victim does not exist [guid=%u]", me->GetGUIDLow()); - } - else if (!victim ->isAlive()) - { - DEBUG_LOG("Creature stopped attacking because victim is dead [guid=%u]", me->GetGUIDLow()); - } - else if (victim ->HasStealthAura()) - { - DEBUG_LOG("Creature stopped attacking because victim is using stealth [guid=%u]", me->GetGUIDLow()); - } - else if (victim ->isInFlight()) - { - DEBUG_LOG("Creature stopped attacking because victim is flying away [guid=%u]", me->GetGUIDLow()); - } - else - { - DEBUG_LOG("Creature stopped attacking because victim outran him [guid=%u]", me->GetGUIDLow()); - } - - me->RemoveAllAuras(); - me->DeleteThreatList(); - i_victimGuid = 0; - me->CombatStop(true); - i_state = STATE_NORMAL; - - // Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) - me->GetMotionMaster()->MoveTargetedHome(); -} - -void GuardAI::UpdateAI(const uint32 /*diff*/) -{ - // update i_victimGuid if me->getVictim() !=0 and changed - if (!UpdateVictim()) - return; - - i_victimGuid = me->getVictim()->GetGUID(); - - if (me->isAttackReady()) - { - if (me->IsWithinMeleeRange(me->getVictim())) - { - me->AttackerStateUpdate(me->getVictim()); - me->resetAttackTimer(); - } - } -} - -bool GuardAI::IsVisible(Unit *pl) const -{ - return me->IsWithinDist(pl,sWorld.getConfig(CONFIG_SIGHT_GUARDER)) - && pl->isVisibleForOrDetect(me,true); -} - -void GuardAI::JustDied(Unit *killer) -{ - if (Player* pkiller = killer->GetCharmerOrOwnerPlayerOrPlayerItself()) - me->SendZoneUnderAttackMessage(pkiller); -} diff --git a/src/server/game/AI/GuardAI.h b/src/server/game/AI/GuardAI.h deleted file mode 100644 index 73e3692a770..00000000000 --- a/src/server/game/AI/GuardAI.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_GUARDAI_H -#define TRINITY_GUARDAI_H - -#include "CreatureAI.h" -#include "Timer.h" - -class Creature; - -class GuardAI : public CreatureAI -{ - enum GuardState - { - STATE_NORMAL = 1, - STATE_LOOK_AT_VICTIM = 2 - }; - - public: - - explicit GuardAI(Creature *c); - - void MoveInLineOfSight(Unit *); - void EnterEvadeMode(); - void JustDied(Unit *); - bool IsVisible(Unit *) const; - - void UpdateAI(const uint32); - static int Permissible(const Creature *); - - private: - uint64 i_victimGuid; - GuardState i_state; - TimeTracker i_tracker; -}; -#endif - diff --git a/src/server/game/AI/PassiveAI.cpp b/src/server/game/AI/PassiveAI.cpp deleted file mode 100644 index c6c92f6df04..00000000000 --- a/src/server/game/AI/PassiveAI.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "PassiveAI.h" -#include "Creature.h" -#include "TemporarySummon.h" - -PassiveAI::PassiveAI(Creature *c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); } -PossessedAI::PossessedAI(Creature *c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); } -NullCreatureAI::NullCreatureAI(Creature *c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); } - -void PassiveAI::UpdateAI(const uint32) -{ - if (me->isInCombat() && me->getAttackers().empty()) - EnterEvadeMode(); -} - -void PossessedAI::AttackStart(Unit *target) -{ - me->Attack(target, true); -} - -void PossessedAI::UpdateAI(const uint32 /*diff*/) -{ - if (me->getVictim()) - { - if (!me->canAttack(me->getVictim())) - me->AttackStop(); - else - DoMeleeAttackIfReady(); - } -} - -void PossessedAI::JustDied(Unit * /*u*/) -{ - // We died while possessed, disable our loot - me->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); -} - -void PossessedAI::KilledUnit(Unit* victim) -{ - // We killed a creature, disable victim's loot - if (victim->GetTypeId() == TYPEID_UNIT) - victim->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); -} - -void CritterAI::DamageTaken(Unit * /*done_by*/, uint32 &) -{ - if (!me->hasUnitState(UNIT_STAT_FLEEING)) - me->SetControlled(true, UNIT_STAT_FLEEING); -} - -void CritterAI::EnterEvadeMode() -{ - if (me->hasUnitState(UNIT_STAT_FLEEING)) - me->SetControlled(false, UNIT_STAT_FLEEING); - CreatureAI::EnterEvadeMode(); -} - -void TriggerAI::IsSummonedBy(Unit *summoner) -{ - if (me->m_spells[0]) - me->CastSpell(me, me->m_spells[0], false, 0, 0, summoner->GetGUID()); -} diff --git a/src/server/game/AI/PassiveAI.h b/src/server/game/AI/PassiveAI.h deleted file mode 100644 index c13e2d1a63c..00000000000 --- a/src/server/game/AI/PassiveAI.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_PASSIVEAI_H -#define TRINITY_PASSIVEAI_H - -#include "CreatureAI.h" -//#include "CreatureAIImpl.h" - -class PassiveAI : public CreatureAI -{ - public: - explicit PassiveAI(Creature *c); - - void MoveInLineOfSight(Unit *) {} - void AttackStart(Unit *) {} - void UpdateAI(const uint32); - - static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; } -}; - -class PossessedAI : public CreatureAI -{ - public: - explicit PossessedAI(Creature *c); - - void MoveInLineOfSight(Unit *) {} - void AttackStart(Unit *target); - void UpdateAI(const uint32); - void EnterEvadeMode() {} - - void JustDied(Unit*); - void KilledUnit(Unit* victim); - - static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; } -}; - -class NullCreatureAI : public CreatureAI -{ - public: - explicit NullCreatureAI(Creature *c); - - void MoveInLineOfSight(Unit *) {} - void AttackStart(Unit *) {} - void UpdateAI(const uint32) {} - void EnterEvadeMode() {} - void OnCharmed(bool /*apply*/) {} - - static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; } -}; - -class CritterAI : public PassiveAI -{ - public: - explicit CritterAI(Creature *c) : PassiveAI(c) {} - - void DamageTaken(Unit *done_by, uint32 & /*damage*/); - void EnterEvadeMode(); -}; - -class TriggerAI : public NullCreatureAI -{ - public: - explicit TriggerAI(Creature *c) : NullCreatureAI(c) {} - void IsSummonedBy(Unit *summoner); -}; - -#endif - diff --git a/src/server/game/AI/PetAI.cpp b/src/server/game/AI/PetAI.cpp deleted file mode 100644 index 09ec8fae53f..00000000000 --- a/src/server/game/AI/PetAI.cpp +++ /dev/null @@ -1,471 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "PetAI.h" -#include "Errors.h" -#include "Pet.h" -#include "Player.h" -#include "DBCStores.h" -#include "Spell.h" -#include "ObjectAccessor.h" -#include "SpellMgr.h" -#include "Creature.h" -#include "World.h" -#include "Util.h" - -int PetAI::Permissible(const Creature *creature) -{ - if (creature->isPet()) - return PERMIT_BASE_SPECIAL; - - return PERMIT_BASE_NO; -} - -PetAI::PetAI(Creature *c) : CreatureAI(c), i_tracker(TIME_INTERVAL_LOOK) -{ - m_AllySet.clear(); - UpdateAllies(); -} - -void PetAI::EnterEvadeMode() -{ -} - -bool PetAI::_needToStop() const -{ - // This is needed for charmed creatures, as once their target was reset other effects can trigger threat - if (me->isCharmed() && me->getVictim() == me->GetCharmer()) - return true; - - return !me->canAttack(me->getVictim()); -} - -void PetAI::_stopAttack() -{ - if (!me->isAlive()) - { - DEBUG_LOG("Creature stoped attacking cuz his dead [guid=%u]", me->GetGUIDLow()); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveIdle(); - me->CombatStop(); - me->getHostileRefManager().deleteReferences(); - - return; - } - - me->AttackStop(); - me->GetCharmInfo()->SetIsCommandAttack(false); - HandleReturnMovement(); -} - -void PetAI::UpdateAI(const uint32 diff) -{ - if (!me->isAlive()) - return; - - Unit* owner = me->GetCharmerOrOwner(); - - if (m_updateAlliesTimer <= diff) - // UpdateAllies self set update timer - UpdateAllies(); - else - m_updateAlliesTimer -= diff; - - // me->getVictim() can't be used for check in case stop fighting, me->getVictim() clear at Unit death etc. - if (me->getVictim()) - { - if (_needToStop()) - { - DEBUG_LOG("Pet AI stoped attacking [guid=%u]", me->GetGUIDLow()); - _stopAttack(); - return; - } - - DoMeleeAttackIfReady(); - } - else if (owner && me->GetCharmInfo()) //no victim - { - Unit *nextTarget = SelectNextTarget(); - - if (nextTarget) - AttackStart(nextTarget); - else - HandleReturnMovement(); - } - else if (owner && !me->hasUnitState(UNIT_STAT_FOLLOW)) // no charm info and no victim - me->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST, me->GetFollowAngle()); - - if (!me->GetCharmInfo()) - return; - - // Autocast (casted only in combat or persistent spells in any state) - if (me->GetGlobalCooldown() == 0 && !me->hasUnitState(UNIT_STAT_CASTING)) - { - typedef std::vector > TargetSpellList; - TargetSpellList targetSpellStore; - - for (uint8 i = 0; i < me->GetPetAutoSpellSize(); ++i) - { - uint32 spellID = me->GetPetAutoSpellOnPos(i); - if (!spellID) - continue; - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID); - if (!spellInfo) - continue; - - // ignore some combinations of combat state and combat/noncombat spells - if (!me->getVictim()) - { - // ignore attacking spells, and allow only self/around spells - if (!IsPositiveSpell(spellInfo->Id)) - continue; - - // non combat spells allowed - // only pet spells have IsNonCombatSpell and not fit this reqs: - // Consume Shadows, Lesser Invisibility, so ignore checks for its - if (!IsNonCombatSpell(spellInfo)) - { - // allow only spell without spell cost or with spell cost but not duration limit - int32 duration = GetSpellDuration(spellInfo); - if ((spellInfo->manaCost || spellInfo->ManaCostPercentage || spellInfo->manaPerSecond) && duration > 0) - continue; - - // allow only spell without cooldown > duration - int32 cooldown = GetSpellRecoveryTime(spellInfo); - if (cooldown >= 0 && duration >= 0 && cooldown > duration) - continue; - } - } - else - { - // just ignore non-combat spells - if (IsNonCombatSpell(spellInfo)) - continue; - } - - Spell *spell = new Spell(me, spellInfo, false, 0); - - // Fix to allow pets on STAY to autocast - if (me->getVictim() && _CanAttack(me->getVictim()) && spell->CanAutoCast(me->getVictim())) - { - targetSpellStore.push_back(std::make_pair(me->getVictim(), spell)); - continue; - } - else - { - bool spellUsed = false; - for (std::set::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar) - { - Unit* Target = ObjectAccessor::GetUnit(*me,*tar); - - //only buff targets that are in combat, unless the spell can only be cast while out of combat - if (!Target) - continue; - - if (spell->CanAutoCast(Target)) - { - targetSpellStore.push_back(std::make_pair(Target, spell)); - spellUsed = true; - break; - } - } - if (!spellUsed) - delete spell; - } - } - - //found units to cast on to - if (!targetSpellStore.empty()) - { - uint32 index = urand(0, targetSpellStore.size() - 1); - - Spell* spell = targetSpellStore[index].second; - Unit* target = targetSpellStore[index].first; - - targetSpellStore.erase(targetSpellStore.begin() + index); - - SpellCastTargets targets; - targets.setUnitTarget(target); - - if (!me->HasInArc(M_PI, target)) - { - me->SetInFront(target); - if (target && target->GetTypeId() == TYPEID_PLAYER) - me->SendUpdateToPlayer(target->ToPlayer()); - - if (owner && owner->GetTypeId() == TYPEID_PLAYER) - me->SendUpdateToPlayer(owner->ToPlayer()); - } - - me->AddCreatureSpellCooldown(spell->m_spellInfo->Id); - - spell->prepare(&targets); - } - - // deleted cached Spell objects - for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr) - delete itr->second; - } -} - -void PetAI::UpdateAllies() -{ - Unit* owner = me->GetCharmerOrOwner(); - Group *pGroup = NULL; - - m_updateAlliesTimer = 10*IN_MILISECONDS; //update friendly targets every 10 seconds, lesser checks increase performance - - if (!owner) - return; - else if (owner->GetTypeId() == TYPEID_PLAYER) - pGroup = owner->ToPlayer()->GetGroup(); - - //only pet and owner/not in group->ok - if (m_AllySet.size() == 2 && !pGroup) - return; - //owner is in group; group members filled in already (no raid -> subgroupcount = whole count) - if (pGroup && !pGroup->isRaidGroup() && m_AllySet.size() == (pGroup->GetMembersCount() + 2)) - return; - - m_AllySet.clear(); - m_AllySet.insert(me->GetGUID()); - if (pGroup) //add group - { - for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* Target = itr->getSource(); - if (!Target || !pGroup->SameSubGroup((Player*)owner, Target)) - continue; - - if (Target->GetGUID() == owner->GetGUID()) - continue; - - m_AllySet.insert(Target->GetGUID()); - } - } - else //remove group - m_AllySet.insert(owner->GetGUID()); -} - -void PetAI::KilledUnit(Unit *victim) -{ - // Called from Unit::Kill() in case where pet or owner kills something - // if owner killed this victim, pet may still be attacking something else - if (me->getVictim() && me->getVictim() != victim) - return; - - // Clear target just in case. May help problem where health / focus / mana - // regen gets stuck. Also resets attack command. - // Can't use _stopAttack() because that activates movement handlers and ignores - // next target selection - me->AttackStop(); - me->GetCharmInfo()->SetIsCommandAttack(false); - - Unit *nextTarget = SelectNextTarget(); - - if (nextTarget) - AttackStart(nextTarget); - else - HandleReturnMovement(); // Return -} - -void PetAI::AttackStart(Unit *target) -{ - // Overrides Unit::AttackStart to correctly evaluate Pet states - - // Check all pet states to decide if we can attack this target - if (!_CanAttack(target)) - return; - - // We can attack, should we chase or not? - if (me->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW)) - DoAttack(target,true); // FOLLOW, attack with chase - else - { - if (me->GetCharmInfo()->IsCommandAttack()) - DoAttack(target,true); // STAY or FOLLOW, player clicked "attack" so attack with chase - else - DoAttack(target,false); // STAY, target in range, attack not clicked so attack without chase - } -} - -Unit *PetAI::SelectNextTarget() -{ - // Provides next target selection after current target death - - // Passive pets don't do next target selection - if (me->HasReactState(REACT_PASSIVE)) - return NULL; - - // Check pet's attackers first to prevent dragging mobs back - // to owner - if (me->getAttackerForHelper()) - return me->getAttackerForHelper(); - - // Check owner's attackers if pet didn't have any - if (me->GetCharmerOrOwner()->getAttackerForHelper()) - return me->GetCharmerOrOwner()->getAttackerForHelper(); - - // 3.0.2 - Pets now start attacking their owners target in defensive mode as soon as the hunter does - if (me->GetCharmerOrOwner()->getVictim()) - return me->GetCharmerOrOwner()->getVictim(); - - // Default - return NULL; -} - -void PetAI::HandleReturnMovement() -{ - // Handles moving the pet back to stay or owner - - if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY)) - { - if (!me->GetCharmInfo()->IsAtStay() && !me->GetCharmInfo()->IsReturning()) - { - // Return to previous position where stay was clicked - if (!me->GetCharmInfo()->IsCommandAttack()) - { - float x,y,z; - - me->GetCharmInfo()->GetStayPosition(x, y, z); - me->GetCharmInfo()->SetIsReturning(true); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MovePoint(me->GetGUIDLow(),x,y,z); - } - } - } - else // COMMAND_FOLLOW - { - if (!me->GetCharmInfo()->IsFollowing() && !me->GetCharmInfo()->IsReturning()) - { - if (!me->GetCharmInfo()->IsCommandAttack()) - { - me->GetCharmInfo()->SetIsReturning(true); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveFollow(me->GetCharmerOrOwner(), PET_FOLLOW_DIST, me->GetFollowAngle()); - } - } - } - -} - -void PetAI::DoAttack(Unit *target, bool chase) -{ - // Handles attack with or without chase and also resets all - // PetAI flags for next update / creature kill - - // me->GetCharmInfo()->SetIsCommandAttack(false); - - // The following conditions are true if chase == true - // (Follow && (Aggressive || Defensive)) - // ((Stay || Follow) && (Passive && player clicked attack)) - - if (chase) - { - if (me->Attack(target,true)) - { - me->GetCharmInfo()->SetIsAtStay(false); - me->GetCharmInfo()->SetIsFollowing(false); - me->GetCharmInfo()->SetIsReturning(false); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveChase(target); - } - } - else // (Stay && ((Aggressive || Defensive) && In Melee Range))) - { - me->GetCharmInfo()->SetIsAtStay(true); - me->GetCharmInfo()->SetIsFollowing(false); - me->GetCharmInfo()->SetIsReturning(false); - me->Attack(target,true); - } -} - -void PetAI::MovementInform(uint32 moveType, uint32 data) -{ - // Receives notification when pet reaches stay or follow owner - switch (moveType) - { - case POINT_MOTION_TYPE: - { - // Pet is returning to where stay was clicked. data should be - // pet's GUIDLow since we set that as the waypoint ID - if (data == me->GetGUIDLow() && me->GetCharmInfo()->IsReturning()) - { - me->GetCharmInfo()->SetIsAtStay(true); - me->GetCharmInfo()->SetIsReturning(false); - me->GetCharmInfo()->SetIsFollowing(false); - me->GetCharmInfo()->SetIsCommandAttack(false); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveIdle(); - } - } - break; - - case TARGETED_MOTION_TYPE: - { - // If data is owner's GUIDLow then we've reached follow point, - // otherwise we're probably chasing a creature - if (me->GetCharmerOrOwner() && me->GetCharmInfo() && data == me->GetCharmerOrOwner()->GetGUIDLow() && me->GetCharmInfo()->IsReturning()) - { - me->GetCharmInfo()->SetIsAtStay(false); - me->GetCharmInfo()->SetIsReturning(false); - me->GetCharmInfo()->SetIsFollowing(true); - me->GetCharmInfo()->SetIsCommandAttack(false); - me->addUnitState(UNIT_STAT_FOLLOW); - } - } - break; - - default: - break; - } -} - -bool PetAI::_CanAttack(Unit *target) -{ - // Evaluates wether a pet can attack a specific - // target based on CommandState, ReactState and other flags - - // Returning - check first since pets returning ignore attacks - if (me->GetCharmInfo()->IsReturning()) - return false; - - // Passive - check now so we don't have to worry about passive in later checks - if (me->HasReactState(REACT_PASSIVE)) - return me->GetCharmInfo()->IsCommandAttack(); - - // Pets commanded to attack should not stop their approach if attacked by another creature - if (me->getVictim() && (me->getVictim() != target)) - return !me->GetCharmInfo()->IsCommandAttack(); - - // From this point on, pet will always be either aggressive or defensive - - // Stay - can attack if target is within range or commanded to - if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY)) - return (me->IsWithinMeleeRange(target, MIN_MELEE_REACH) || me->GetCharmInfo()->IsCommandAttack()); - - // Follow - if (me->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW)) - return true; - - // default, though we shouldn't ever get here - return false; -} diff --git a/src/server/game/AI/PetAI.h b/src/server/game/AI/PetAI.h deleted file mode 100644 index f6087a129ae..00000000000 --- a/src/server/game/AI/PetAI.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_PETAI_H -#define TRINITY_PETAI_H - -#include "CreatureAI.h" -#include "Timer.h" - -class Creature; -class Spell; - -class PetAI : public CreatureAI -{ - public: - - explicit PetAI(Creature *c); - - void EnterEvadeMode(); - void JustDied(Unit * /*who*/) { _stopAttack(); } - - void UpdateAI(const uint32); - static int Permissible(const Creature *); - - void KilledUnit(Unit * /*victim*/); - void AttackStart(Unit *target); - void MovementInform(uint32 moveType, uint32 data); - - private: - bool _isVisible(Unit *) const; - bool _needToStop(void) const; - void _stopAttack(void); - - void UpdateAllies(); - - TimeTracker i_tracker; - bool inCombat; - std::set m_AllySet; - uint32 m_updateAlliesTimer; - - Unit *SelectNextTarget(); - void HandleReturnMovement(); - void DoAttack(Unit *target, bool chase); - bool _CanAttack(Unit *target); -}; -#endif - diff --git a/src/server/game/AI/ReactorAI.cpp b/src/server/game/AI/ReactorAI.cpp deleted file mode 100644 index fdca6314747..00000000000 --- a/src/server/game/AI/ReactorAI.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ByteBuffer.h" -#include "ReactorAI.h" -#include "Errors.h" -#include "Log.h" -#include "ObjectAccessor.h" -#include "CreatureAIImpl.h" - -#define REACTOR_VISIBLE_RANGE (26.46f) - -int -ReactorAI::Permissible(const Creature *creature) -{ - if (creature->isCivilian() || creature->IsNeutralToAll()) - return PERMIT_BASE_REACTIVE; - - return PERMIT_BASE_NO; -} - -void -ReactorAI::MoveInLineOfSight(Unit *) -{ -} - -void -ReactorAI::UpdateAI(const uint32 /*time_diff*/) -{ - // update i_victimGuid if me->getVictim() !=0 and changed - if (!UpdateVictim()) - return; - - if (me->isAttackReady()) - { - if (me->IsWithinMeleeRange(me->getVictim())) - { - me->AttackerStateUpdate(me->getVictim()); - me->resetAttackTimer(); - } - } -} diff --git a/src/server/game/AI/ReactorAI.h b/src/server/game/AI/ReactorAI.h deleted file mode 100644 index ae4e6403962..00000000000 --- a/src/server/game/AI/ReactorAI.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_REACTORAI_H -#define TRINITY_REACTORAI_H - -#include "CreatureAI.h" - -class Unit; - -class ReactorAI : public CreatureAI -{ - public: - - explicit ReactorAI(Creature *c) : CreatureAI(c) {} - - void MoveInLineOfSight(Unit *); - - void UpdateAI(const uint32); - static int Permissible(const Creature *); -}; -#endif - diff --git a/src/server/game/AI/TotemAI.cpp b/src/server/game/AI/TotemAI.cpp deleted file mode 100644 index a6464f189e8..00000000000 --- a/src/server/game/AI/TotemAI.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "TotemAI.h" -#include "Totem.h" -#include "Creature.h" -#include "DBCStores.h" -#include "ObjectAccessor.h" -#include "SpellMgr.h" - -#include "GridNotifiers.h" -#include "GridNotifiersImpl.h" -#include "CellImpl.h" - -int -TotemAI::Permissible(const Creature *creature) -{ - if (creature->isTotem()) - return PERMIT_BASE_PROACTIVE; - - return PERMIT_BASE_NO; -} - -TotemAI::TotemAI(Creature *c) : CreatureAI(c), i_victimGuid(0) -{ - assert(c->isTotem()); -} - -void -TotemAI::MoveInLineOfSight(Unit *) -{ -} - -void TotemAI::EnterEvadeMode() -{ - me->CombatStop(true); -} - -void -TotemAI::UpdateAI(const uint32 /*diff*/) -{ - if (me->ToTotem()->GetTotemType() != TOTEM_ACTIVE) - return; - - if (!me->isAlive() || me->IsNonMeleeSpellCasted(false)) - return; - - // Search spell - SpellEntry const *spellInfo = sSpellStore.LookupEntry(me->ToTotem()->GetSpell()); - if (!spellInfo) - return; - - // Get spell range - SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); - float max_range = GetSpellMaxRangeForHostile(srange); - - // SPELLMOD_RANGE not applied in this place just because not existence range mods for attacking totems - - // pointer to appropriate target if found any - Unit* victim = i_victimGuid ? ObjectAccessor::GetUnit(*me, i_victimGuid) : NULL; - - // Search victim if no, not attackable, or out of range, or friendly (possible in case duel end) - if (!victim || - !victim->isTargetableForAttack() || !me->IsWithinDistInMap(victim, max_range) || - me->IsFriendlyTo(victim) || !victim->isVisibleForOrDetect(me,false)) - { - victim = NULL; - Trinity::NearestAttackableUnitInObjectRangeCheck u_check(me, me, max_range); - Trinity::UnitLastSearcher checker(me, victim, u_check); - me->VisitNearbyObject(max_range, checker); - } - - // If have target - if (victim) - { - // remember - i_victimGuid = victim->GetGUID(); - - // attack - me->SetInFront(victim); // client change orientation by self - me->CastSpell(victim, me->ToTotem()->GetSpell(), false); - } - else - i_victimGuid = 0; -} - -void -TotemAI::AttackStart(Unit *) -{ - // Sentry totem sends ping on attack - if (me->GetEntry() == SENTRY_TOTEM_ENTRY && me->GetOwner()->GetTypeId() == TYPEID_PLAYER) - { - WorldPacket data(MSG_MINIMAP_PING, (8+4+4)); - data << me->GetGUID(); - data << me->GetPositionX(); - data << me->GetPositionY(); - ((Player*)me->GetOwner())->GetSession()->SendPacket(&data); - } -} diff --git a/src/server/game/AI/TotemAI.h b/src/server/game/AI/TotemAI.h deleted file mode 100644 index 34f4dfa9945..00000000000 --- a/src/server/game/AI/TotemAI.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_TOTEMAI_H -#define TRINITY_TOTEMAI_H - -#include "CreatureAI.h" -#include "Timer.h" - -class Creature; -class Totem; - -class TotemAI : public CreatureAI -{ - public: - - explicit TotemAI(Creature *c); - - void MoveInLineOfSight(Unit *); - void AttackStart(Unit *); - void EnterEvadeMode(); - - void UpdateAI(const uint32); - static int Permissible(const Creature *); - - private: - uint64 i_victimGuid; -}; -#endif - diff --git a/src/server/game/AI/UnitAI.cpp b/src/server/game/AI/UnitAI.cpp deleted file mode 100644 index a156ec573d9..00000000000 --- a/src/server/game/AI/UnitAI.cpp +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "UnitAI.h" -#include "Player.h" -#include "Creature.h" -#include "SpellAuras.h" -#include "SpellAuraEffects.h" -#include "SpellMgr.h" -#include "CreatureAIImpl.h" - -void UnitAI::AttackStart(Unit *victim) -{ - if (victim && me->Attack(victim, true)) - me->GetMotionMaster()->MoveChase(victim); -} - -void UnitAI::AttackStartCaster(Unit *victim, float dist) -{ - if (victim && me->Attack(victim, false)) - me->GetMotionMaster()->MoveChase(victim, dist); -} - -void UnitAI::DoMeleeAttackIfReady() -{ - if (me->hasUnitState(UNIT_STAT_CASTING)) - return; - - //Make sure our attack is ready and we aren't currently casting before checking distance - if (me->isAttackReady()) - { - //If we are within range melee the target - if (me->IsWithinMeleeRange(me->getVictim())) - { - me->AttackerStateUpdate(me->getVictim()); - me->resetAttackTimer(); - } - } - if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK)) - { - //If we are within range melee the target - if (me->IsWithinMeleeRange(me->getVictim())) - { - me->AttackerStateUpdate(me->getVictim(), OFF_ATTACK); - me->resetAttackTimer(OFF_ATTACK); - } - } -} - -bool UnitAI::DoSpellAttackIfReady(uint32 spell) -{ - if (me->hasUnitState(UNIT_STAT_CASTING)) - return true; - - if (me->isAttackReady()) - { - if (me->IsWithinCombatRange(me->getVictim(), GetSpellMaxRange(spell, false))) - { - me->CastSpell(me->getVictim(), spell, false); - me->resetAttackTimer(); - } - else - return false; - } - return true; -} - -// default predicate function to select target based on distance, player and/or aura criteria -struct DefaultTargetSelector : public std::unary_function -{ - const Unit *me; - float m_dist; - bool m_playerOnly; - int32 m_aura; - - // pUnit: the reference unit - // dist: if 0: ignored, if > 0: maximum distance to the reference unit, if < 0: minimum distance to the reference unit - // playerOnly: self explaining - // aura: if 0: ignored, if > 0: the target shall have the aura, if < 0, the target shall NOT have the aura - DefaultTargetSelector(const Unit *pUnit, float dist, bool playerOnly, int32 aura) : me(pUnit), m_dist(dist), m_playerOnly(playerOnly), m_aura(aura) {} - - bool operator() (const Unit *pTarget) - { - if (!me) - return false; - - if (!pTarget) - return false; - - if (m_playerOnly && (pTarget->GetTypeId() != TYPEID_PLAYER)) - return false; - - if (m_dist > 0.0f && !me->IsWithinCombatRange(pTarget, m_dist)) - return false; - - if (m_dist < 0.0f && me->IsWithinCombatRange(pTarget, -m_dist)) - return false; - - if (m_aura) - { - if (m_aura > 0) - { - if (!pTarget->HasAura(m_aura)) - return false; - } - else - { - if (pTarget->HasAura(m_aura)) - return false; - } - } - - return true; - } -}; - -Unit* UnitAI::SelectTarget(SelectAggroTarget targetType, uint32 position, float dist, bool playerOnly, int32 aura) -{ - return SelectTarget(targetType, position, DefaultTargetSelector(me, dist, playerOnly, aura)); -} - -void UnitAI::SelectTargetList(std::list &targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly, int32 aura) -{ - const std::list &threatlist = me->getThreatManager().getThreatList(); - - if (threatlist.empty()) - return; - - DefaultTargetSelector targetSelector(me, dist,playerOnly, aura); - for (std::list::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) - if (targetSelector((*itr)->getTarget())) - targetList.push_back((*itr)->getTarget()); - - if (targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) - targetList.sort(Trinity::ObjectDistanceOrderPred(me)); - - if (targetType == SELECT_TARGET_FARTHEST || targetType == SELECT_TARGET_BOTTOMAGGRO) - targetList.reverse(); - - if (targetList.size() < num) - return; - - if (targetType == SELECT_TARGET_RANDOM) - { - while (num < targetList.size()) { - std::list::iterator itr = targetList.begin(); - advance(itr, urand(0, targetList.size()-1)); - targetList.erase(itr); - } - } - else - targetList.resize(num); -} - -float UnitAI::DoGetSpellMaxRange(uint32 spellId, bool positive) -{ - return GetSpellMaxRange(spellId, positive); -} - -void UnitAI::DoAddAuraToAllHostilePlayers(uint32 spellid) -{ - if (me->isInCombat()) - { - std::list& threatlist = me->getThreatManager().getThreatList(); - for (std::list::iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) - { - if (Unit *pTemp = Unit::GetUnit(*me,(*itr)->getUnitGuid())) - if (pTemp->GetTypeId() == TYPEID_PLAYER) - me->AddAura(spellid, pTemp); - } - }else - return; -} - -void UnitAI::DoCastToAllHostilePlayers(uint32 spellid, bool triggered) -{ - if (me->isInCombat()) - { - std::list& threatlist = me->getThreatManager().getThreatList(); - for (std::list::iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) - { - if (Unit *pTemp = Unit::GetUnit(*me,(*itr)->getUnitGuid())) - if (pTemp->GetTypeId() == TYPEID_PLAYER) - me->CastSpell(pTemp, spellid, triggered); - } - }else - return; -} - -void UnitAI::DoCast(uint32 spellId) -{ - Unit *target = NULL; - //sLog.outError("aggre %u %u", spellId, (uint32)AISpellInfo[spellId].target); - switch(AISpellInfo[spellId].target) - { - default: - case AITARGET_SELF: target = me; break; - case AITARGET_VICTIM: target = me->getVictim(); break; - case AITARGET_ENEMY: - { - const SpellEntry * spellInfo = GetSpellStore()->LookupEntry(spellId); - bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY; - //float range = GetSpellMaxRange(spellInfo, false); - target = SelectTarget(SELECT_TARGET_RANDOM, 0, GetSpellMaxRange(spellInfo, false), playerOnly); - break; - } - case AITARGET_ALLY: target = me; break; - case AITARGET_BUFF: target = me; break; - case AITARGET_DEBUFF: - { - const SpellEntry * spellInfo = GetSpellStore()->LookupEntry(spellId); - bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY; - float range = GetSpellMaxRange(spellInfo, false); - - DefaultTargetSelector targetSelector(me, range, playerOnly, -(int32)spellId); - if (!(spellInfo->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE) - && !(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM) - && targetSelector(me->getVictim())) - target = me->getVictim(); - else - target = SelectTarget(SELECT_TARGET_RANDOM, 0, targetSelector); - break; - } - } - - if (target) - me->CastSpell(target, spellId, false); -} - -#define UPDATE_TARGET(a) {if (AIInfo->targettarget=a;} - -void UnitAI::FillAISpellInfo() -{ - AISpellInfo = new AISpellInfoType[GetSpellStore()->GetNumRows()]; - - AISpellInfoType *AIInfo = AISpellInfo; - const SpellEntry * spellInfo; - - for (uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i, ++AIInfo) - { - spellInfo = GetSpellStore()->LookupEntry(i); - if (!spellInfo) - continue; - - if (spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD) - AIInfo->condition = AICOND_DIE; - else if (IsPassiveSpell(i) || GetSpellDuration(spellInfo) == -1) - AIInfo->condition = AICOND_AGGRO; - else - AIInfo->condition = AICOND_COMBAT; - - if (AIInfo->cooldown < spellInfo->RecoveryTime) - AIInfo->cooldown = spellInfo->RecoveryTime; - - if (!GetSpellMaxRange(spellInfo, false)) - UPDATE_TARGET(AITARGET_SELF) - else - { - for (uint32 j = 0; j < 3; ++j) - { - uint32 targetType = spellInfo->EffectImplicitTargetA[j]; - - if (targetType == TARGET_UNIT_TARGET_ENEMY - || targetType == TARGET_DST_TARGET_ENEMY) - UPDATE_TARGET(AITARGET_VICTIM) - else if (targetType == TARGET_UNIT_AREA_ENEMY_DST) - UPDATE_TARGET(AITARGET_ENEMY) - - if (spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA) - { - if (targetType == TARGET_UNIT_TARGET_ENEMY) - UPDATE_TARGET(AITARGET_DEBUFF) - else if (IsPositiveSpell(i)) - UPDATE_TARGET(AITARGET_BUFF) - } - } - } - AIInfo->realCooldown = spellInfo->RecoveryTime + spellInfo->StartRecoveryTime; - SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); - if (srange) - AIInfo->maxRange = srange->maxRangeHostile * 3 / 4; - } -} - -//Enable PlayerAI when charmed -void PlayerAI::OnCharmed(bool apply) { me->IsAIEnabled = apply; } - -void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/) -{ - Creature *charmer = me->GetCharmer()->ToCreature(); - - //kill self if charm aura has infinite duration - if (charmer->IsInEvadeMode()) - { - Unit::AuraEffectList const& auras = me->GetAuraEffectsByType(SPELL_AURA_MOD_CHARM); - for (Unit::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) - if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetBase()->IsPermanent()) - { - charmer->Kill(me); - return; - } - } - - if (!charmer->isInCombat()) - me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, me->GetFollowAngle()); - - Unit *target = me->getVictim(); - if (!target || !charmer->canAttack(target)) - AttackStart(charmer->SelectNearestTargetInAttackDistance()); -} diff --git a/src/server/game/AI/UnitAI.h b/src/server/game/AI/UnitAI.h deleted file mode 100644 index 62b7090a2d0..00000000000 --- a/src/server/game/AI/UnitAI.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_UNITAI_H -#define TRINITY_UNITAI_H - -#include "Platform/Define.h" -#include -#include "Unit.h" - -class Unit; -class Player; -struct AISpellInfoType; - -//Selection method used by SelectTarget -enum SelectAggroTarget -{ - SELECT_TARGET_RANDOM = 0, //Just selects a random target - SELECT_TARGET_TOPAGGRO, //Selects targes from top aggro to bottom - SELECT_TARGET_BOTTOMAGGRO, //Selects targets from bottom aggro to top - SELECT_TARGET_NEAREST, - SELECT_TARGET_FARTHEST, -}; - -class UnitAI -{ - protected: - Unit * const me; - public: - explicit UnitAI(Unit *u) : me(u) {} - virtual ~UnitAI() {} - - virtual bool CanAIAttack(const Unit * /*who*/) const { return true; } - virtual void AttackStart(Unit *); - virtual void UpdateAI(const uint32 diff) = 0; - - virtual void InitializeAI() { if (!me->isDead()) Reset(); } - - virtual void Reset() {}; - - // Called when unit is charmed - virtual void OnCharmed(bool apply) = 0; - - // Pass parameters between AI - virtual void DoAction(const int32 /*param*/ = 0) {} - virtual uint32 GetData(uint32 /*id = 0*/) { return 0; } - virtual void SetData(uint32 /*id*/, uint32 /*value*/) {} - virtual void SetGUID(const uint64 &/*guid*/, int32 /*id*/ = 0) {} - virtual uint64 GetGUID(int32 /*id*/ = 0) { return 0; } - - Unit* SelectTarget(SelectAggroTarget targetType, uint32 position = 0, float dist = 0.0f, bool playerOnly = false, int32 aura = 0); - void SelectTargetList(std::list &targetList, uint32 num, SelectAggroTarget targetType, float dist = 0.0f, bool playerOnly = false, int32 aura = 0); - - // Select the targets satifying the predicate. - // predicate shall extend std::unary_function - template Unit* SelectTarget(SelectAggroTarget targetType, uint32 position, PREDICATE predicate) - { - const std::list &threatlist = me->getThreatManager().getThreatList(); - std::list targetList; - - if (position >= threatlist.size()) - return NULL; - - for (std::list::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) - { - HostileReference* ref = (*itr); - if (predicate(ref->getTarget())) - targetList.push_back(ref->getTarget()); - } - - if (position >= targetList.size()) - return NULL; - - if (targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) - targetList.sort(Trinity::ObjectDistanceOrderPred(me)); - - switch(targetType) - { - case SELECT_TARGET_NEAREST: - case SELECT_TARGET_TOPAGGRO: - { - std::list::iterator itr = targetList.begin(); - advance(itr, position); - return *itr; - } - break; - - case SELECT_TARGET_FARTHEST: - case SELECT_TARGET_BOTTOMAGGRO: - { - std::list::reverse_iterator ritr = targetList.rbegin(); - advance(ritr, position); - return *ritr; - } - break; - - case SELECT_TARGET_RANDOM: - { - std::list::iterator itr = targetList.begin(); - advance(itr, urand(position, targetList.size()-1)); - return *itr; - } - break; - } - - return NULL; - } - - void AttackStartCaster(Unit *victim, float dist); - - void DoAddAuraToAllHostilePlayers(uint32 spellid); - void DoCast(uint32 spellId); - void DoCast(Unit* victim, uint32 spellId, bool triggered = false); - void DoCastToAllHostilePlayers(uint32 spellid, bool triggered = false); - void DoCastVictim(uint32 spellId, bool triggered = false); - void DoCastAOE(uint32 spellId, bool triggered = false); - - float DoGetSpellMaxRange(uint32 spellId, bool positive = false); - - void DoMeleeAttackIfReady(); - bool DoSpellAttackIfReady(uint32 spell); - - static AISpellInfoType *AISpellInfo; - static void FillAISpellInfo(); -}; - -class PlayerAI : public UnitAI -{ - protected: - Player* const me; - public: - explicit PlayerAI(Player *p) : UnitAI((Unit*)p), me(p) {} - - void OnCharmed(bool apply); -}; - -class SimpleCharmedAI : public PlayerAI -{ - public: - void UpdateAI(const uint32 diff); - SimpleCharmedAI(Player *p): PlayerAI(p) {} -}; - -#endif diff --git a/src/server/game/Account/AccountMgr.cpp b/src/server/game/Account/AccountMgr.cpp deleted file mode 100644 index 52906fb5454..00000000000 --- a/src/server/game/Account/AccountMgr.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Database/DatabaseEnv.h" -#include "Policies/SingletonImp.h" - -#include "AccountMgr.h" -#include "ObjectAccessor.h" -#include "Player.h" -#include "Util.h" -#include "Auth/Sha1.h" - -extern DatabaseType LoginDatabase; - -INSTANTIATE_SINGLETON_1(AccountMgr); - -AccountMgr::AccountMgr() -{} - -AccountMgr::~AccountMgr() -{} - -AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password) -{ - if (utf8length(username) > MAX_ACCOUNT_STR) - return AOR_NAME_TOO_LONG; // username's too long - - normalizeString(username); - normalizeString(password); - - if (GetId(username)) - { - return AOR_NAME_ALREDY_EXIST; // username does already exist - } - - if (!LoginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s','%s',NOW())", username.c_str(), CalculateShaPassHash(username, password).c_str())) - return AOR_DB_INTERNAL_ERROR; // unexpected error - LoginDatabase.Execute("INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist,account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL"); - - return AOR_OK; // everything's fine -} - -AccountOpResult AccountMgr::DeleteAccount(uint32 accid) -{ - QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid); - if (!result) - return AOR_NAME_NOT_EXIST; // account doesn't exist - - result = CharacterDatabase.PQuery("SELECT guid FROM characters WHERE account='%d'",accid); - if (result) - { - do - { - Field *fields = result->Fetch(); - uint32 guidlo = fields[0].GetUInt32(); - uint64 guid = MAKE_NEW_GUID(guidlo, 0, HIGHGUID_PLAYER); - - // kick if player currently - if (Player* p = ObjectAccessor::GetObjectInWorld(guid, (Player*)NULL)) - { - WorldSession* s = p->GetSession(); - s->KickPlayer(); // mark session to remove at next session list update - s->LogoutPlayer(false); // logout player without waiting next session list update - } - - Player::DeleteFromDB(guid, accid, false); // no need to update realm characters - } while (result->NextRow()); - } - - // table realm specific but common for all characters of account for realm - CharacterDatabase.PExecute("DELETE FROM character_tutorial WHERE account = '%u'",accid); - CharacterDatabase.PExecute("DELETE FROM account_data WHERE account = '%u'",accid); - - LoginDatabase.BeginTransaction(); - - bool res = - LoginDatabase.PExecute("DELETE FROM account WHERE id='%d'", accid) && - LoginDatabase.PExecute("DELETE FROM account_access WHERE id ='%d'", accid) && - LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid); - - LoginDatabase.CommitTransaction(); - - if (!res) - return AOR_DB_INTERNAL_ERROR; // unexpected error; - - return AOR_OK; -} - -AccountOpResult AccountMgr::ChangeUsername(uint32 accid, std::string new_uname, std::string new_passwd) -{ - QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid); - if (!result) - return AOR_NAME_NOT_EXIST; // account doesn't exist - - if (utf8length(new_uname) > MAX_ACCOUNT_STR) - return AOR_NAME_TOO_LONG; - - if (utf8length(new_passwd) > MAX_ACCOUNT_STR) - return AOR_PASS_TOO_LONG; - - normalizeString(new_uname); - normalizeString(new_passwd); - - std::string safe_new_uname = new_uname; - LoginDatabase.escape_string(safe_new_uname); - - if (!LoginDatabase.PExecute("UPDATE account SET v='0',s='0',username='%s',sha_pass_hash='%s' WHERE id='%d'", safe_new_uname.c_str(), - CalculateShaPassHash(new_uname, new_passwd).c_str(), accid)) - return AOR_DB_INTERNAL_ERROR; // unexpected error - - return AOR_OK; -} - -AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd) -{ - std::string username; - - if (!GetName(accid, username)) - return AOR_NAME_NOT_EXIST; // account doesn't exist - - if (utf8length(new_passwd) > MAX_ACCOUNT_STR) - return AOR_PASS_TOO_LONG; - - normalizeString(username); - normalizeString(new_passwd); - - // also reset s and v to force update at next realmd login - if (!LoginDatabase.PExecute("UPDATE account SET v='0', s='0', sha_pass_hash='%s' WHERE id='%d'", - CalculateShaPassHash(username, new_passwd).c_str(), accid)) - return AOR_DB_INTERNAL_ERROR; // unexpected error - - return AOR_OK; -} - -uint32 AccountMgr::GetId(std::string username) -{ - LoginDatabase.escape_string(username); - QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'", username.c_str()); - if (!result) - return 0; - else - { - uint32 id = (*result)[0].GetUInt32(); - return id; - } -} - -uint32 AccountMgr::GetSecurity(uint32 acc_id) -{ - QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT gmlevel FROM account_access WHERE id = '%u'", acc_id); - if (result) - { - uint32 sec = (*result)[0].GetUInt32(); - return sec; - } - - return 0; -} - -uint32 AccountMgr::GetSecurity(uint32 acc_id, int32 realm_id) -{ - QueryResult_AutoPtr result = (realm_id == -1) - ? LoginDatabase.PQuery("SELECT gmlevel FROM account_access WHERE id = '%u' AND RealmID = '%d'", acc_id, realm_id) - : LoginDatabase.PQuery("SELECT gmlevel FROM account_access WHERE id = '%u' AND (RealmID = '%d' OR RealmID = '-1')", acc_id, realm_id); - if (result) - { - uint32 sec = (*result)[0].GetUInt32(); - return sec; - } - - return 0; -} - -bool AccountMgr::GetName(uint32 acc_id, std::string &name) -{ - QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT username FROM account WHERE id = '%u'", acc_id); - if (result) - { - name = (*result)[0].GetCppString(); - return true; - } - - return false; -} - -bool AccountMgr::CheckPassword(uint32 accid, std::string passwd) -{ - std::string username; - if (!GetName(accid, username)) - return false; - - normalizeString(username); - normalizeString(passwd); - - QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d' AND sha_pass_hash='%s'", accid, CalculateShaPassHash(username, passwd).c_str()); - if (result) - return true; - - return false; -} - -bool AccountMgr::normalizeString(std::string& utf8str) -{ - wchar_t wstr_buf[MAX_ACCOUNT_STR+1]; - - size_t wstr_len = MAX_ACCOUNT_STR; - if (!Utf8toWStr(utf8str,wstr_buf,wstr_len)) - return false; - - std::transform(&wstr_buf[0], wstr_buf+wstr_len, &wstr_buf[0], wcharToUpperOnlyLatin); - - return WStrToUtf8(wstr_buf,wstr_len,utf8str); -} - -std::string AccountMgr::CalculateShaPassHash(std::string& name, std::string& password) -{ - Sha1Hash sha; - sha.Initialize(); - sha.UpdateData(name); - sha.UpdateData(":"); - sha.UpdateData(password); - sha.Finalize(); - - std::string encoded; - hexEncodeByteArray(sha.GetDigest(), sha.GetLength(), encoded); - - return encoded; -} - diff --git a/src/server/game/Account/AccountMgr.h b/src/server/game/Account/AccountMgr.h deleted file mode 100644 index b017bf1836a..00000000000 --- a/src/server/game/Account/AccountMgr.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ACCMGR_H -#define _ACCMGR_H - -#include - -#include "Common.h" -#include "Policies/Singleton.h" - -enum AccountOpResult -{ - AOR_OK, - AOR_NAME_TOO_LONG, - AOR_PASS_TOO_LONG, - AOR_NAME_ALREDY_EXIST, - AOR_NAME_NOT_EXIST, - AOR_DB_INTERNAL_ERROR -}; - -#define MAX_ACCOUNT_STR 16 - -class AccountMgr -{ - public: - AccountMgr(); - ~AccountMgr(); - - AccountOpResult CreateAccount(std::string username, std::string password); - AccountOpResult DeleteAccount(uint32 accid); - AccountOpResult ChangeUsername(uint32 accid, std::string new_uname, std::string new_passwd); - AccountOpResult ChangePassword(uint32 accid, std::string new_passwd); - bool CheckPassword(uint32 accid, std::string passwd); - - uint32 GetId(std::string username); - uint32 GetSecurity(uint32 acc_id); - uint32 GetSecurity(uint32 acc_id, int32 realm_id); - bool GetName(uint32 acc_id, std::string &name); - std::string CalculateShaPassHash(std::string& name, std::string& password); - - static bool normalizeString(std::string& utf8str); -}; - -#define accmgr Trinity::Singleton::Instance() -#endif - diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp new file mode 100644 index 00000000000..52906fb5454 --- /dev/null +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Database/DatabaseEnv.h" +#include "Policies/SingletonImp.h" + +#include "AccountMgr.h" +#include "ObjectAccessor.h" +#include "Player.h" +#include "Util.h" +#include "Auth/Sha1.h" + +extern DatabaseType LoginDatabase; + +INSTANTIATE_SINGLETON_1(AccountMgr); + +AccountMgr::AccountMgr() +{} + +AccountMgr::~AccountMgr() +{} + +AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password) +{ + if (utf8length(username) > MAX_ACCOUNT_STR) + return AOR_NAME_TOO_LONG; // username's too long + + normalizeString(username); + normalizeString(password); + + if (GetId(username)) + { + return AOR_NAME_ALREDY_EXIST; // username does already exist + } + + if (!LoginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s','%s',NOW())", username.c_str(), CalculateShaPassHash(username, password).c_str())) + return AOR_DB_INTERNAL_ERROR; // unexpected error + LoginDatabase.Execute("INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist,account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL"); + + return AOR_OK; // everything's fine +} + +AccountOpResult AccountMgr::DeleteAccount(uint32 accid) +{ + QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid); + if (!result) + return AOR_NAME_NOT_EXIST; // account doesn't exist + + result = CharacterDatabase.PQuery("SELECT guid FROM characters WHERE account='%d'",accid); + if (result) + { + do + { + Field *fields = result->Fetch(); + uint32 guidlo = fields[0].GetUInt32(); + uint64 guid = MAKE_NEW_GUID(guidlo, 0, HIGHGUID_PLAYER); + + // kick if player currently + if (Player* p = ObjectAccessor::GetObjectInWorld(guid, (Player*)NULL)) + { + WorldSession* s = p->GetSession(); + s->KickPlayer(); // mark session to remove at next session list update + s->LogoutPlayer(false); // logout player without waiting next session list update + } + + Player::DeleteFromDB(guid, accid, false); // no need to update realm characters + } while (result->NextRow()); + } + + // table realm specific but common for all characters of account for realm + CharacterDatabase.PExecute("DELETE FROM character_tutorial WHERE account = '%u'",accid); + CharacterDatabase.PExecute("DELETE FROM account_data WHERE account = '%u'",accid); + + LoginDatabase.BeginTransaction(); + + bool res = + LoginDatabase.PExecute("DELETE FROM account WHERE id='%d'", accid) && + LoginDatabase.PExecute("DELETE FROM account_access WHERE id ='%d'", accid) && + LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid); + + LoginDatabase.CommitTransaction(); + + if (!res) + return AOR_DB_INTERNAL_ERROR; // unexpected error; + + return AOR_OK; +} + +AccountOpResult AccountMgr::ChangeUsername(uint32 accid, std::string new_uname, std::string new_passwd) +{ + QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid); + if (!result) + return AOR_NAME_NOT_EXIST; // account doesn't exist + + if (utf8length(new_uname) > MAX_ACCOUNT_STR) + return AOR_NAME_TOO_LONG; + + if (utf8length(new_passwd) > MAX_ACCOUNT_STR) + return AOR_PASS_TOO_LONG; + + normalizeString(new_uname); + normalizeString(new_passwd); + + std::string safe_new_uname = new_uname; + LoginDatabase.escape_string(safe_new_uname); + + if (!LoginDatabase.PExecute("UPDATE account SET v='0',s='0',username='%s',sha_pass_hash='%s' WHERE id='%d'", safe_new_uname.c_str(), + CalculateShaPassHash(new_uname, new_passwd).c_str(), accid)) + return AOR_DB_INTERNAL_ERROR; // unexpected error + + return AOR_OK; +} + +AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd) +{ + std::string username; + + if (!GetName(accid, username)) + return AOR_NAME_NOT_EXIST; // account doesn't exist + + if (utf8length(new_passwd) > MAX_ACCOUNT_STR) + return AOR_PASS_TOO_LONG; + + normalizeString(username); + normalizeString(new_passwd); + + // also reset s and v to force update at next realmd login + if (!LoginDatabase.PExecute("UPDATE account SET v='0', s='0', sha_pass_hash='%s' WHERE id='%d'", + CalculateShaPassHash(username, new_passwd).c_str(), accid)) + return AOR_DB_INTERNAL_ERROR; // unexpected error + + return AOR_OK; +} + +uint32 AccountMgr::GetId(std::string username) +{ + LoginDatabase.escape_string(username); + QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'", username.c_str()); + if (!result) + return 0; + else + { + uint32 id = (*result)[0].GetUInt32(); + return id; + } +} + +uint32 AccountMgr::GetSecurity(uint32 acc_id) +{ + QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT gmlevel FROM account_access WHERE id = '%u'", acc_id); + if (result) + { + uint32 sec = (*result)[0].GetUInt32(); + return sec; + } + + return 0; +} + +uint32 AccountMgr::GetSecurity(uint32 acc_id, int32 realm_id) +{ + QueryResult_AutoPtr result = (realm_id == -1) + ? LoginDatabase.PQuery("SELECT gmlevel FROM account_access WHERE id = '%u' AND RealmID = '%d'", acc_id, realm_id) + : LoginDatabase.PQuery("SELECT gmlevel FROM account_access WHERE id = '%u' AND (RealmID = '%d' OR RealmID = '-1')", acc_id, realm_id); + if (result) + { + uint32 sec = (*result)[0].GetUInt32(); + return sec; + } + + return 0; +} + +bool AccountMgr::GetName(uint32 acc_id, std::string &name) +{ + QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT username FROM account WHERE id = '%u'", acc_id); + if (result) + { + name = (*result)[0].GetCppString(); + return true; + } + + return false; +} + +bool AccountMgr::CheckPassword(uint32 accid, std::string passwd) +{ + std::string username; + if (!GetName(accid, username)) + return false; + + normalizeString(username); + normalizeString(passwd); + + QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d' AND sha_pass_hash='%s'", accid, CalculateShaPassHash(username, passwd).c_str()); + if (result) + return true; + + return false; +} + +bool AccountMgr::normalizeString(std::string& utf8str) +{ + wchar_t wstr_buf[MAX_ACCOUNT_STR+1]; + + size_t wstr_len = MAX_ACCOUNT_STR; + if (!Utf8toWStr(utf8str,wstr_buf,wstr_len)) + return false; + + std::transform(&wstr_buf[0], wstr_buf+wstr_len, &wstr_buf[0], wcharToUpperOnlyLatin); + + return WStrToUtf8(wstr_buf,wstr_len,utf8str); +} + +std::string AccountMgr::CalculateShaPassHash(std::string& name, std::string& password) +{ + Sha1Hash sha; + sha.Initialize(); + sha.UpdateData(name); + sha.UpdateData(":"); + sha.UpdateData(password); + sha.Finalize(); + + std::string encoded; + hexEncodeByteArray(sha.GetDigest(), sha.GetLength(), encoded); + + return encoded; +} + diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h new file mode 100644 index 00000000000..b017bf1836a --- /dev/null +++ b/src/server/game/Accounts/AccountMgr.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ACCMGR_H +#define _ACCMGR_H + +#include + +#include "Common.h" +#include "Policies/Singleton.h" + +enum AccountOpResult +{ + AOR_OK, + AOR_NAME_TOO_LONG, + AOR_PASS_TOO_LONG, + AOR_NAME_ALREDY_EXIST, + AOR_NAME_NOT_EXIST, + AOR_DB_INTERNAL_ERROR +}; + +#define MAX_ACCOUNT_STR 16 + +class AccountMgr +{ + public: + AccountMgr(); + ~AccountMgr(); + + AccountOpResult CreateAccount(std::string username, std::string password); + AccountOpResult DeleteAccount(uint32 accid); + AccountOpResult ChangeUsername(uint32 accid, std::string new_uname, std::string new_passwd); + AccountOpResult ChangePassword(uint32 accid, std::string new_passwd); + bool CheckPassword(uint32 accid, std::string passwd); + + uint32 GetId(std::string username); + uint32 GetSecurity(uint32 acc_id); + uint32 GetSecurity(uint32 acc_id, int32 realm_id); + bool GetName(uint32 acc_id, std::string &name); + std::string CalculateShaPassHash(std::string& name, std::string& password); + + static bool normalizeString(std::string& utf8str); +}; + +#define accmgr Trinity::Singleton::Instance() +#endif + diff --git a/src/server/game/Addons/AddonHandler.cpp b/src/server/game/Addons/AddonHandler.cpp deleted file mode 100644 index a9c8101d7b1..00000000000 --- a/src/server/game/Addons/AddonHandler.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "zlib/zlib.h" - -#include "AddonHandler.h" -#include "Database/DatabaseEnv.h" -#include "Policies/SingletonImp.h" -#include "Opcodes.h" - -#include "Log.h" - -INSTANTIATE_SINGLETON_1( AddonHandler ); - -AddonHandler::AddonHandler() -{ -} - -AddonHandler::~AddonHandler() -{ -} - -bool AddonHandler::BuildAddonPacket(WorldPacket *Source, WorldPacket *Target) -{ - ByteBuffer AddOnPacked; - uLongf AddonRealSize; - uint32 CurrentPosition; - uint32 TempValue; - - unsigned char tdata[256] = - { - 0xC3, 0x5B, 0x50, 0x84, 0xB9, 0x3E, 0x32, 0x42, 0x8C, 0xD0, 0xC7, 0x48, 0xFA, 0x0E, 0x5D, 0x54, - 0x5A, 0xA3, 0x0E, 0x14, 0xBA, 0x9E, 0x0D, 0xB9, 0x5D, 0x8B, 0xEE, 0xB6, 0x84, 0x93, 0x45, 0x75, - 0xFF, 0x31, 0xFE, 0x2F, 0x64, 0x3F, 0x3D, 0x6D, 0x07, 0xD9, 0x44, 0x9B, 0x40, 0x85, 0x59, 0x34, - 0x4E, 0x10, 0xE1, 0xE7, 0x43, 0x69, 0xEF, 0x7C, 0x16, 0xFC, 0xB4, 0xED, 0x1B, 0x95, 0x28, 0xA8, - 0x23, 0x76, 0x51, 0x31, 0x57, 0x30, 0x2B, 0x79, 0x08, 0x50, 0x10, 0x1C, 0x4A, 0x1A, 0x2C, 0xC8, - 0x8B, 0x8F, 0x05, 0x2D, 0x22, 0x3D, 0xDB, 0x5A, 0x24, 0x7A, 0x0F, 0x13, 0x50, 0x37, 0x8F, 0x5A, - 0xCC, 0x9E, 0x04, 0x44, 0x0E, 0x87, 0x01, 0xD4, 0xA3, 0x15, 0x94, 0x16, 0x34, 0xC6, 0xC2, 0xC3, - 0xFB, 0x49, 0xFE, 0xE1, 0xF9, 0xDA, 0x8C, 0x50, 0x3C, 0xBE, 0x2C, 0xBB, 0x57, 0xED, 0x46, 0xB9, - 0xAD, 0x8B, 0xC6, 0xDF, 0x0E, 0xD6, 0x0F, 0xBE, 0x80, 0xB3, 0x8B, 0x1E, 0x77, 0xCF, 0xAD, 0x22, - 0xCF, 0xB7, 0x4B, 0xCF, 0xFB, 0xF0, 0x6B, 0x11, 0x45, 0x2D, 0x7A, 0x81, 0x18, 0xF2, 0x92, 0x7E, - 0x98, 0x56, 0x5D, 0x5E, 0x69, 0x72, 0x0A, 0x0D, 0x03, 0x0A, 0x85, 0xA2, 0x85, 0x9C, 0xCB, 0xFB, - 0x56, 0x6E, 0x8F, 0x44, 0xBB, 0x8F, 0x02, 0x22, 0x68, 0x63, 0x97, 0xBC, 0x85, 0xBA, 0xA8, 0xF7, - 0xB5, 0x40, 0x68, 0x3C, 0x77, 0x86, 0x6F, 0x4B, 0xD7, 0x88, 0xCA, 0x8A, 0xD7, 0xCE, 0x36, 0xF0, - 0x45, 0x6E, 0xD5, 0x64, 0x79, 0x0F, 0x17, 0xFC, 0x64, 0xDD, 0x10, 0x6F, 0xF3, 0xF5, 0xE0, 0xA6, - 0xC3, 0xFB, 0x1B, 0x8C, 0x29, 0xEF, 0x8E, 0xE5, 0x34, 0xCB, 0xD1, 0x2A, 0xCE, 0x79, 0xC3, 0x9A, - 0x0D, 0x36, 0xEA, 0x01, 0xE0, 0xAA, 0x91, 0x20, 0x54, 0xF0, 0x72, 0xD8, 0x1E, 0xC7, 0x89, 0xD2 - }; - - // broken addon packet, can't be received from real client - if (Source->rpos() + 4 > Source->size()) - return false; - - *Source >> TempValue; // get real size of the packed structure - - // empty addon packet, nothing process, can't be received from real client - if(!TempValue) - return false; - - AddonRealSize = TempValue; // temp value because ZLIB only excepts uLongf - - CurrentPosition = Source->rpos(); // get the position of the pointer in the structure - - AddOnPacked.resize(AddonRealSize); // resize target for zlib action - - if (!uncompress(const_cast(AddOnPacked.contents()), &AddonRealSize, const_cast((*Source).contents() + CurrentPosition), (*Source).size() - CurrentPosition)!= Z_OK) - { - Target->Initialize(SMSG_ADDON_INFO); - - uint32 addonsCount; - AddOnPacked >> addonsCount; // addons count? - - for(uint32 i = 0; i < addonsCount; ++i) - { - std::string addonName; - uint8 enabled; - uint32 crc, unk2; - - // check next addon data format correctness - if(AddOnPacked.rpos()+1 > AddOnPacked.size()) - return false; - - AddOnPacked >> addonName; - - // recheck next addon data format correctness - if(AddOnPacked.rpos()+1+4+4 > AddOnPacked.size()) - return false; - - AddOnPacked >> enabled >> crc >> unk2; - - sLog.outDebug("ADDON: Name: %s, Enabled: 0x%x, CRC: 0x%x, Unknown2: 0x%x", addonName.c_str(), enabled, crc, unk2); - - uint8 state = (enabled ? 2 : 1); - *Target << uint8(state); - - uint8 unk1 = (enabled ? 1 : 0); - *Target << uint8(unk1); - if (unk1) - { - uint8 unk2 = (crc != 0x4c1c776d); // If addon is Standard addon CRC - *Target << uint8(unk2); - if (unk2) - Target->append(tdata, sizeof(tdata)); - - *Target << uint32(0); - } - - uint8 unk3 = (enabled ? 0 : 1); - *Target << uint8(unk3); - if (unk3) - { - // String, 256 (null terminated?) - *Target << uint8(0); - } - } - - uint32 unk4; - AddOnPacked >> unk4; - - uint32 count = 0; - *Target << uint32(count); - /*for(uint32 i = 0; i < count; ++i) - { - uint32 - string (16 bytes) - string (16 bytes) - uint32 - }*/ - - if(AddOnPacked.rpos() != AddOnPacked.size()) - sLog.outDebug("packet under read!"); - } - else - { - sLog.outError("Addon packet uncompress error :("); - return false; - } - return true; -} - -/* Code use in 1.10.2 when client not ignore ban state sended for addons. Saved for reference if client switch to use server ban state information -void AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target, uint32 Packetoffset) -{ - ByteBuffer AddOnPacked; - uLongf AddonRealSize; - uint32 CurrentPosition; - uint32 TempValue; - - *Source >> TempValue; //get real size of the packed structure - - AddonRealSize = TempValue; //temp value becouse ZLIB only excepts uLongf - - CurrentPosition = Source->rpos(); //get the position of the pointer in the structure - - AddOnPacked.resize(AddonRealSize); //resize target for zlib action - - if (!uncompress((uint8*)AddOnPacked.contents(), &AddonRealSize, (uint8*)(*Source).contents() + CurrentPosition, (*Source).size() - CurrentPosition)!= Z_OK) - { - bool* AddonAllowed = new bool; //handle addon check and enable-ing - - uint32 Unknown1; - uint8 Unknown0; - - AddOnPacked >> Unknown0; - AddOnPacked >> Unknown1; - - Target->Initialize(SMSG_ADDON_INFO); - - uint32 i = 5; //offset for addon extraction - while(i != AddOnPacked.size()) - { - std::string AddonNames; - AddOns* Addonstr = new AddOns; - uint8 unk6; - uint64 CRCCHECK; - AddOnPacked >> AddonNames >> CRCCHECK >> unk6; - - //sLog.outDebug("ADDON: Name:%s CRC:%x Unknown:%x",AddonNames.c_str(), CRCCHECK,unk6); - - Addonstr->Name = AddonNames; - Addonstr->CRC = CRCCHECK; - - //if not allowed but unknown added to list - if (GetAddonStatus(Addonstr, AddonAllowed)) // If addon is new - { - Addonstr->Enabled = m_Addon_Default; // by default new addons are set from Config file - *AddonAllowed = m_Addon_Default; // Set addon allowed on default value - _AddAddon(Addonstr); - sLog.outDetail("Found new Addon, Name:%s CRC:%x Unknown:%x",AddonNames.c_str(), CRCCHECK, unk6); - } - - if (CRCCHECK == 0x4C1C776D01LL) //If addon is Standard addon CRC - { - //value's standard Addons - *Target << uint8(0) << uint8(2) << uint8(1) << uint8(0) << uint32(0); - } - else if (*AddonAllowed) //if addon is Custom addons - //value's enable addon - *Target << uint8(0x00) << uint8(0x01) << uint8(0x00) << uint8(0x01); - else - //value's disable addom - *Target << uint8(0x00) << uint8(0x0) << uint8(0x00) << uint8(0x0); - - i += AddonNames.size() + 10; - } - *Target << uint8(0x0); - - //delete mem allocation - delete AddonAllowed; - } - else - { - //handle uncompress error - } -} -*/ - diff --git a/src/server/game/Addons/AddonHandler.h b/src/server/game/Addons/AddonHandler.h deleted file mode 100644 index 999785339bc..00000000000 --- a/src/server/game/Addons/AddonHandler.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __ADDONHANDLER_H -#define __ADDONHANDLER_H - -#include "Common.h" -#include "Config/ConfigEnv.h" -#include "Policies/Singleton.h" - -#include "WorldPacket.h" - -class AddonHandler -{ - public: - /* Construction */ - AddonHandler(); - ~AddonHandler(); - //built addon packet - bool BuildAddonPacket(WorldPacket* Source, WorldPacket* Target); -}; -#define sAddOnHandler Trinity::Singleton::Instance() -#endif - diff --git a/src/server/game/AuctionHouse/AuctionHouseBot/AuctionHouseBot.cpp b/src/server/game/AuctionHouse/AuctionHouseBot/AuctionHouseBot.cpp new file mode 100644 index 00000000000..ebbf48e6476 --- /dev/null +++ b/src/server/game/AuctionHouse/AuctionHouseBot/AuctionHouseBot.cpp @@ -0,0 +1,1860 @@ +#include "ObjectMgr.h" +#include "AuctionHouseMgr.h" +#include "AuctionHouseBot.h" +#include + +#include "Policies/SingletonImp.h" +INSTANTIATE_SINGLETON_1(AuctionHouseBot); + +using namespace std; +vector npcItems; +vector lootItems; +vector greyTradeGoodsBin; +vector whiteTradeGoodsBin; +vector greenTradeGoodsBin; +vector blueTradeGoodsBin; +vector purpleTradeGoodsBin; +vector orangeTradeGoodsBin; +vector yellowTradeGoodsBin; +vector greyItemsBin; +vector whiteItemsBin; +vector greenItemsBin; +vector blueItemsBin; +vector purpleItemsBin; +vector orangeItemsBin; +vector yellowItemsBin; +AuctionHouseBot::AuctionHouseBot() +{ + debug_Out = false; + debug_Out_Filters = false; + AHBSeller = false; + AHBBuyer = false; + + //Begin Filters + + Vendor_Items = false; + Loot_Items = false; + Other_Items = false; + Vendor_TGs = false; + Loot_TGs = false; + Other_TGs = false; + + No_Bind = false; + Bind_When_Picked_Up = false; + Bind_When_Equipped = false; + Bind_When_Use = false; + Bind_Quest_Item = false; + + DisableBeta_PTR_Unused = false; + DisablePermEnchant = false; + DisableConjured = false; + DisableGems = false; + DisableMoney = false; + DisableMoneyLoot = false; + DisableLootable = false; + DisableKeys = false; + DisableDuration = false; + DisableBOP_Or_Quest_NoReqLevel = false; + + DisableWarriorItems = false; + DisablePaladinItems = false; + DisableHunterItems = false; + DisableRogueItems = false; + DisablePriestItems = false; + DisableDKItems = false; + DisableShamanItems = false; + DisableMageItems = false; + DisableWarlockItems = false; + DisableUnusedClassItems = false; + DisableDruidItems = false; + + DisableItemsBelowLevel = 0; + DisableItemsAboveLevel = 0; + DisableTGsBelowLevel = 0; + DisableTGsAboveLevel = 0; + DisableItemsBelowGUID = 0; + DisableItemsAboveGUID = 0; + DisableTGsBelowGUID = 0; + DisableTGsAboveGUID = 0; + DisableItemsBelowReqLevel = 0; + DisableItemsAboveReqLevel = 0; + DisableTGsBelowReqLevel = 0; + DisableTGsAboveReqLevel = 0; + DisableItemsBelowReqSkillRank = 0; + DisableItemsAboveReqSkillRank = 0; + DisableTGsBelowReqSkillRank = 0; + DisableTGsAboveReqSkillRank = 0; + + //End Filters + + _lastrun_a = time(NULL); + _lastrun_h = time(NULL); + _lastrun_n = time(NULL); + + AllianceConfig = AHBConfig(2); + HordeConfig = AHBConfig(6); + NeutralConfig = AHBConfig(7); +} + +AuctionHouseBot::~AuctionHouseBot() +{ +} + +void AuctionHouseBot::addNewAuctions(Player *AHBplayer, AHBConfig *config) +{ + if (!AHBSeller) + { + if (debug_Out) sLog.outError("AHSeller: Disabled"); + return; + } + + uint32 minItems = config->GetMinItems(); + uint32 maxItems = config->GetMaxItems(); + + if (maxItems == 0) + { + //if (debug_Out) sLog.outString("AHSeller: Auctions disabled"); + return; + } + + AuctionHouseEntry const* ahEntry = auctionmgr.GetAuctionHouseEntry(config->GetAHFID()); + if (!ahEntry) + { + return; + } + AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(config->GetAHFID()); + if (!auctionHouse) + { + return; + } + + uint32 auctions = auctionHouse->Getcount(); + + if (auctions >= minItems) + { + //if (debug_Out) sLog.outString("AHSeller: Auctions above minimum"); + return; + } + + if (auctions >= maxItems) + { + //if (debug_Out) sLog.outString("AHSeller: Auctions at or above maximum"); + return; + } + + uint32 items = 0; + if ((maxItems - auctions) >= ItemsPerCycle) + items = ItemsPerCycle; + else + items = (maxItems - auctions); + + if (debug_Out) sLog.outString("AHSeller: Adding %u Auctions", items); + + uint32 AuctioneerGUID = 0; + + switch (config->GetAHID()) + { + case 2: + AuctioneerGUID = 79707; //Human in stormwind. + break; + case 6: + AuctioneerGUID = 4656; //orc in Orgrimmar + break; + case 7: + AuctioneerGUID = 23442; //goblin in GZ + break; + default: + if (debug_Out) sLog.outError("AHSeller: GetAHID() - Default switch reached"); + AuctioneerGUID = 23442; //default to neutral 7 + break; + } + + if (debug_Out) sLog.outString("AHSeller: Current Auctineer GUID is %u", AuctioneerGUID); + + uint32 greyTGcount = config->GetPercents(AHB_GREY_TG); + uint32 whiteTGcount = config->GetPercents(AHB_WHITE_TG); + uint32 greenTGcount = config->GetPercents(AHB_GREEN_TG); + uint32 blueTGcount = config->GetPercents(AHB_BLUE_TG); + uint32 purpleTGcount = config->GetPercents(AHB_PURPLE_TG); + uint32 orangeTGcount = config->GetPercents(AHB_ORANGE_TG); + uint32 yellowTGcount = config->GetPercents(AHB_YELLOW_TG); + uint32 greyIcount = config->GetPercents(AHB_GREY_I); + uint32 whiteIcount = config->GetPercents(AHB_WHITE_I); + uint32 greenIcount = config->GetPercents(AHB_GREEN_I); + uint32 blueIcount = config->GetPercents(AHB_BLUE_I); + uint32 purpleIcount = config->GetPercents(AHB_PURPLE_I); + uint32 orangeIcount = config->GetPercents(AHB_ORANGE_I); + uint32 yellowIcount = config->GetPercents(AHB_YELLOW_I); +/* uint32 total = greyTGcount + whiteTGcount + greenTGcount + blueTGcount + + purpleTGcount + orangeTGcount + yellowTGcount + + whiteIcount + greenIcount + blueIcount + purpleIcount + + orangeIcount + yellowIcount; +*/ + uint32 greyTGoods = config->GetItemCounts(AHB_GREY_TG); + uint32 whiteTGoods = config->GetItemCounts(AHB_WHITE_TG); + uint32 greenTGoods = config->GetItemCounts(AHB_GREEN_TG); + uint32 blueTGoods = config->GetItemCounts(AHB_BLUE_TG); + uint32 purpleTGoods = config->GetItemCounts(AHB_PURPLE_TG); + uint32 orangeTGoods = config->GetItemCounts(AHB_ORANGE_TG); + uint32 yellowTGoods = config->GetItemCounts(AHB_YELLOW_TG); + + uint32 greyItems = config->GetItemCounts(AHB_GREY_I); + uint32 whiteItems = config->GetItemCounts(AHB_WHITE_I); + uint32 greenItems = config->GetItemCounts(AHB_GREEN_I); + uint32 blueItems = config->GetItemCounts(AHB_BLUE_I); + uint32 purpleItems = config->GetItemCounts(AHB_PURPLE_I); + uint32 orangeItems = config->GetItemCounts(AHB_ORANGE_I); + uint32 yellowItems = config->GetItemCounts(AHB_YELLOW_I); + if (debug_Out) sLog.outString("AHSeller: %u items", items); + + // only insert a few at a time, so as not to peg the processor + for (uint32 cnt = 1; cnt <= items; cnt++) + { + if (debug_Out) sLog.outString("AHSeller: %u count", cnt); + uint32 itemID = 0; + uint32 itemColor = 99; + uint32 loopbreaker = 0; + while (itemID == 0 && loopbreaker <= 50) + { + ++loopbreaker; + uint32 choice = urand(0, 13); + itemColor = choice; + switch (choice) + { + case 0: + { + if ((greyItemsBin.size() > 0) && (greyItems < greyIcount)) + itemID = greyItemsBin[urand(0, greyItemsBin.size() - 1)]; + else continue; + break; + } + case 1: + { + if ((whiteItemsBin.size() > 0) && (whiteItems < whiteIcount)) + itemID = whiteItemsBin[urand(0, whiteItemsBin.size() - 1)]; + else continue; + break; + } + case 2: + { + if ((greenItemsBin.size() > 0) && (greenItems < greenIcount)) + itemID = greenItemsBin[urand(0, greenItemsBin.size() - 1)]; + else continue; + break; + } + case 3: + { + if ((blueItemsBin.size() > 0) && (blueItems < blueIcount)) + itemID = blueItemsBin[urand(0, blueItemsBin.size() - 1)]; + else continue; + break; + } + case 4: + { + if ((purpleItemsBin.size() > 0) && (purpleItems < purpleIcount)) + itemID = purpleItemsBin[urand(0, purpleItemsBin.size() - 1)]; + else continue; + break; + } + case 5: + { + if ((orangeItemsBin.size() > 0) && (orangeItems < orangeIcount)) + itemID = orangeItemsBin[urand(0, orangeItemsBin.size() - 1)]; + else continue; + break; + } + case 6: + { + if ((yellowItemsBin.size() > 0) && (yellowItems < yellowIcount)) + itemID = yellowItemsBin[urand(0, yellowItemsBin.size() - 1)]; + else continue; + break; + } + case 7: + { + if ((greyTradeGoodsBin.size() > 0) && (greyTGoods < greyTGcount)) + itemID = greyTradeGoodsBin[urand(0, greyTradeGoodsBin.size() - 1)]; + else continue; + break; + } + case 8: + { + if ((whiteTradeGoodsBin.size() > 0) && (whiteTGoods < whiteTGcount)) + itemID = whiteTradeGoodsBin[urand(0, whiteTradeGoodsBin.size() - 1)]; + else continue; + break; + } + case 9: + { + if ((greenTradeGoodsBin.size() > 0) && (greenTGoods < greenTGcount)) + itemID = greenTradeGoodsBin[urand(0, greenTradeGoodsBin.size() - 1)]; + else continue; + break; + } + case 10: + { + if ((blueTradeGoodsBin.size() > 0) && (blueTGoods < blueTGcount)) + itemID = blueTradeGoodsBin[urand(0, blueTradeGoodsBin.size() - 1)]; + else continue; + break; + } + case 11: + { + if ((purpleTradeGoodsBin.size() > 0) && (purpleTGoods < purpleTGcount)) + itemID = purpleTradeGoodsBin[urand(0, purpleTradeGoodsBin.size() - 1)]; + else continue; + break; + } + case 12: + { + if ((orangeTradeGoodsBin.size() > 0) && (orangeTGoods < orangeTGcount)) + itemID = orangeTradeGoodsBin[urand(0, orangeTradeGoodsBin.size() - 1)]; + else continue; + break; + } + case 13: + { + if ((yellowTradeGoodsBin.size() > 0) && (yellowTGoods < yellowTGcount)) + itemID = yellowTradeGoodsBin[urand(0, yellowTradeGoodsBin.size() - 1)]; + else continue; + break; + } + default: + { + if (debug_Out) sLog.outError("AHSeller: itemID Switch - Default Reached"); + break; + } + } + + if (itemID == 0) + { + if (debug_Out) sLog.outError("AHSeller: Item::CreateItem() - ItemID is 0"); + continue; + } + + ItemPrototype const* prototype = objmgr.GetItemPrototype(itemID); + if (prototype == NULL) + { + if (debug_Out) sLog.outError("AHSeller: Huh?!?! prototype == NULL"); + continue; + } + + Item* item = Item::CreateItem(itemID, 1, AHBplayer); + if (item == NULL) + { + if (debug_Out) sLog.outError("AHSeller: Item::CreateItem() returned NULL"); + break; + } + item->AddToUpdateQueueOf(AHBplayer); + + uint32 randomPropertyId = Item::GenerateItemRandomPropertyId(itemID); + if (randomPropertyId != 0) + item->SetItemRandomProperties(randomPropertyId); + + uint64 buyoutPrice = 0; + uint64 bidPrice = 0; + uint32 stackCount = 1; + + switch (SellMethod) + { + case 0: + buyoutPrice = prototype->SellPrice; + break; + case 1: + buyoutPrice = prototype->BuyPrice; + break; + } + + if ((prototype->Quality >= 0) && (prototype->Quality <= AHB_MAX_QUALITY)) + { + if (config->GetMaxStack(prototype->Quality) > 1 && item->GetMaxStackCount() > 1) + stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(prototype->Quality))); + else if (config->GetMaxStack(prototype->Quality) == 0 && item->GetMaxStackCount() > 1) + stackCount = urand(1, item->GetMaxStackCount()); + else + stackCount = 1; + buyoutPrice *= urand(config->GetMinPrice(prototype->Quality), config->GetMaxPrice(prototype->Quality)); + buyoutPrice /= 100; + bidPrice = buyoutPrice * urand(config->GetMinBidPrice(prototype->Quality), config->GetMaxBidPrice(prototype->Quality)); + bidPrice /= 100; + } + else + { + // quality is something it shouldn't be, let's get out of here + if (debug_Out) sLog.outError("AHBuyer: Quality %u not Supported", prototype->Quality); + item->RemoveFromUpdateQueueOf(AHBplayer); + continue; + } + + uint32 etime = urand(1,3); + switch(etime) + { + case 1: + etime = 43200; + break; + case 2: + etime = 86400; + break; + case 3: + etime = 172800; + break; + default: + etime = 86400; + break; + } + item->SetCount(stackCount); + + uint32 dep = auctionmgr.GetAuctionDeposit(ahEntry, etime, item); + + AuctionEntry* auctionEntry = new AuctionEntry; + auctionEntry->Id = objmgr.GenerateAuctionID(); + auctionEntry->auctioneer = AuctioneerGUID; + auctionEntry->item_guidlow = item->GetGUIDLow(); + auctionEntry->item_template = item->GetEntry(); + auctionEntry->owner = AHBplayer->GetGUIDLow(); + auctionEntry->startbid = bidPrice * stackCount; + auctionEntry->buyout = buyoutPrice * stackCount; + auctionEntry->bidder = 0; + auctionEntry->bid = 0; + auctionEntry->deposit = dep; + auctionEntry->expire_time = (time_t) etime + time(NULL); + auctionEntry->auctionHouseEntry = ahEntry; + item->SaveToDB(); + item->RemoveFromUpdateQueueOf(AHBplayer); + auctionmgr.AddAItem(item); + auctionHouse->AddAuction(auctionEntry); + auctionEntry->SaveToDB(); + + switch(itemColor) + { + case 0: + ++greyItems; + break; + case 1: + ++whiteItems; + break; + case 2: + ++greenItems; + break; + case 3: + ++blueItems; + break; + case 4: + ++purpleItems; + break; + case 5: + ++orangeItems; + break; + case 6: + ++yellowItems; + break; + case 7: + ++greyTGoods; + break; + case 8: + ++whiteTGoods; + break; + case 9: + ++greenTGoods; + break; + case 10: + ++blueTGoods; + break; + case 11: + ++purpleTGoods; + break; + case 12: + ++orangeTGoods; + break; + case 13: + ++yellowTGoods; + break; + default: + break; + } + } + } +} +void AuctionHouseBot::addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, WorldSession *session) +{ + if (!AHBBuyer) + { + if (debug_Out) sLog.outError("AHBuyer: Disabled"); + return; + } + + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT id FROM auctionhouse WHERE itemowner<>%u AND buyguid<>%u", AHBplayerGUID, AHBplayerGUID); + + if (!result) + return; + + if (result->GetRowCount() == 0) + return; + + // Fetches content of selected AH + AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(config->GetAHFID()); + vector possibleBids; + + do + { + uint32 tmpdata = result->Fetch()->GetUInt32(); + possibleBids.push_back(tmpdata); + }while (result->NextRow()); + + for (uint32 count = 1; count <= config->GetBidsPerInterval(); ++count) + { + // Do we have anything to bid? If not, stop here. + if (possibleBids.empty()) + { + //if (debug_Out) sLog.outString("AHBuyer: I have no items to bid on."); + count = config->GetBidsPerInterval(); + continue; + } + + // Choose random auction from possible auctions + uint32 vectorPos = urand(0, possibleBids.size() - 1); + vector::iterator iter = possibleBids.begin(); + advance(iter, vectorPos); + + // from auctionhousehandler.cpp, creates auction pointer & player pointer + AuctionEntry* auction = auctionHouse->GetAuction(*iter); + + // Erase the auction from the vector to prevent bidding on item in next iteration. + possibleBids.erase(iter); + + if (!auction) + continue; + + // get exact item information + Item *pItem = auctionmgr.GetAItem(auction->item_guidlow); + if (!pItem) + { + if (debug_Out) sLog.outError("AHBuyer: Item %u doesn't exist, perhaps bought already?", auction->item_guidlow); + continue; + } + + // get item prototype + ItemPrototype const* prototype = objmgr.GetItemPrototype(auction->item_template); + + // check which price we have to use, startbid or if it is bidded already + uint32 currentprice; + if (auction->bid) + currentprice = auction->bid; + else + currentprice = auction->startbid; + + // Prepare portion from maximum bid + double bidrate = static_cast(urand(1, 100)) / 100; + long double bidMax = 0; + + // check that bid has acceptable value and take bid based on vendorprice, stacksize and quality + switch (BuyMethod) + { + case 0: + { + if ((prototype->Quality >= 0) && (prototype->Quality <= AHB_MAX_QUALITY)) + { + if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(prototype->Quality)) + bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(prototype->Quality); + } + else + { + // quality is something it shouldn't be, let's get out of here + if (debug_Out) sLog.outError("AHBuyer: Quality %u not Supported", prototype->Quality); + continue; + } + break; + } + case 1: + { + if ((prototype->Quality >= 0) && (prototype->Quality <= AHB_MAX_QUALITY)) + { + if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(prototype->Quality)) + bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(prototype->Quality); + } + else + { + // quality is something it shouldn't be, let's get out of here + if (debug_Out) sLog.outError("AHBuyer: Quality %u not Supported", prototype->Quality); + continue; + } + break; + } + } + + // check some special items, and do recalculating to their prices + switch (prototype->Class) + { + // ammo + case 6: + bidMax = 0; + break; + default: + break; + } + + if (bidMax == 0) + { + // quality check failed to get bidmax, let's get out of here + continue; + } + + // Calculate our bid + long double bidvalue = currentprice + ((bidMax - currentprice) * bidrate); + // Convert to uint32 + uint32 bidprice = static_cast(bidvalue); + + // Check our bid is high enough to be valid. If not, correct it to minimum. + if ((currentprice + auction->GetAuctionOutBid()) > bidprice) + bidprice = currentprice + auction->GetAuctionOutBid(); + + if (debug_Out) + { + sLog.outString("-------------------------------------------------"); + sLog.outString("AHBuyer: Info for Auction #%u:", auction->Id); + sLog.outString("AHBuyer: AuctionHouse: %u", auction->GetHouseId()); + sLog.outString("AHBuyer: Auctioneer: %u", auction->auctioneer); + sLog.outString("AHBuyer: Owner: %u", auction->owner); + sLog.outString("AHBuyer: Bidder: %u", auction->bidder); + sLog.outString("AHBuyer: Starting Bid: %u", auction->startbid); + sLog.outString("AHBuyer: Current Bid: %u", currentprice); + sLog.outString("AHBuyer: Buyout: %u", auction->buyout); + sLog.outString("AHBuyer: Deposit: %u", auction->deposit); + sLog.outString("AHBuyer: Expire Time: %u", auction->expire_time); + sLog.outString("AHBuyer: Bid Rate: %f", bidrate); + sLog.outString("AHBuyer: Bid Max: %f", bidMax); + sLog.outString("AHBuyer: Bid Value: %f", bidvalue); + sLog.outString("AHBuyer: Bid Price: %u", bidprice); + sLog.outString("AHBuyer: Item GUID: %u", auction->item_guidlow); + sLog.outString("AHBuyer: Item Template: %u", auction->item_template); + sLog.outString("AHBuyer: Item Info:"); + sLog.outString("AHBuyer: Item ID: %u", prototype->ItemId); + sLog.outString("AHBuyer: Buy Price: %u", prototype->BuyPrice); + sLog.outString("AHBuyer: Sell Price: %u", prototype->SellPrice); + sLog.outString("AHBuyer: Bonding: %u", prototype->Bonding); + sLog.outString("AHBuyer: Quality: %u", prototype->Quality); + sLog.outString("AHBuyer: Item Level: %u", prototype->ItemLevel); + sLog.outString("AHBuyer: Ammo Type: %u", prototype->AmmoType); + sLog.outString("-------------------------------------------------"); + } + + // Check whether we do normal bid, or buyout + if ((bidprice < auction->buyout) || (auction->buyout == 0)) + { + + if (auction->bidder > 0) + { + if (auction->bidder == AHBplayer->GetGUIDLow()) + { + //pl->ModifyMoney(-int32(price - auction->bid)); + } + else + { + // mail to last bidder and return money + session->SendAuctionOutbiddedMail(auction , bidprice); + //pl->ModifyMoney(-int32(price)); + } + } + + auction->bidder = AHBplayer->GetGUIDLow(); + auction->bid = bidprice; + + // Saving auction into database + CharacterDatabase.PExecute("UPDATE auctionhouse SET buyguid = '%u',lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id); + } + else + { + //buyout + if ((auction->bidder) && (AHBplayer->GetGUIDLow() != auction->bidder)) + { + session->SendAuctionOutbiddedMail(auction, auction->buyout); + } + auction->bidder = AHBplayer->GetGUIDLow(); + auction->bid = auction->buyout; + + // Send mails to buyer & seller + auctionmgr.SendAuctionSalePendingMail(auction); + auctionmgr.SendAuctionSuccessfulMail(auction); + auctionmgr.SendAuctionWonMail(auction); + auction->DeleteFromDB(); + uint32 item_template = auction->item_template; + auctionmgr.RemoveAItem(auction->item_guidlow); + auctionHouse->RemoveAuction(auction, item_template); + } + } +} + +void AuctionHouseBot::Update() +{ + time_t _newrun = time(NULL); + if ((!AHBSeller) && (!AHBBuyer)) + return; + + WorldSession _session(AHBplayerAccount, NULL, SEC_PLAYER, true, 0, LOCALE_enUS); + Player _AHBplayer(&_session); + _AHBplayer.Initialize(AHBplayerGUID); + ObjectAccessor::Instance().AddObject(&_AHBplayer); + + // Add New Bids + if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) + { + addNewAuctions(&_AHBplayer, &AllianceConfig); + if (((_newrun - _lastrun_a) >= (AllianceConfig.GetBiddingInterval() * MINUTE)) && (AllianceConfig.GetBidsPerInterval() > 0)) + { + //if (debug_Out) sLog.outString("AHBuyer: %u seconds have passed since last bid", (_newrun - _lastrun_a)); + //if (debug_Out) sLog.outString("AHBuyer: Bidding on Alliance Auctions"); + addNewAuctionBuyerBotBid(&_AHBplayer, &AllianceConfig, &_session); + _lastrun_a = _newrun; + } + + addNewAuctions(&_AHBplayer, &HordeConfig); + if (((_newrun - _lastrun_h) >= (HordeConfig.GetBiddingInterval() * MINUTE)) && (HordeConfig.GetBidsPerInterval() > 0)) + { + //if (debug_Out) sLog.outString("AHBuyer: %u seconds have passed since last bid", (_newrun - _lastrun_h)); + //if (debug_Out) sLog.outString("AHBuyer: Bidding on Horde Auctions"); + addNewAuctionBuyerBotBid(&_AHBplayer, &HordeConfig, &_session); + _lastrun_h = _newrun; + } + } + + addNewAuctions(&_AHBplayer, &NeutralConfig); + if (((_newrun - _lastrun_n) >= (NeutralConfig.GetBiddingInterval() * MINUTE)) && (NeutralConfig.GetBidsPerInterval() > 0)) + { + //if (debug_Out) sLog.outString("AHBuyer: %u seconds have passed since last bid", (_newrun - _lastrun_n)); + //if (debug_Out) sLog.outString("AHBuyer: Bidding on Neutral Auctions"); + addNewAuctionBuyerBotBid(&_AHBplayer, &NeutralConfig, &_session); + _lastrun_n = _newrun; + } + ObjectAccessor::Instance().RemoveObject(&_AHBplayer); +} + +void AuctionHouseBot::Initialize() +{ + debug_Out = sConfig.GetBoolDefault("AuctionHouseBot.DEBUG", false); + debug_Out_Filters = sConfig.GetBoolDefault("AuctionHouseBot.DEBUG_FILTERS", false); + + AHBSeller = sConfig.GetBoolDefault("AuctionHouseBot.EnableSeller", false); + AHBBuyer = sConfig.GetBoolDefault("AuctionHouseBot.EnableBuyer", false); + SellMethod = sConfig.GetBoolDefault("AuctionHouseBot.UseBuyPriceForSeller", false); + BuyMethod = sConfig.GetBoolDefault("AuctionHouseBot.UseBuyPriceForBuyer", false); + + AHBplayerAccount = sConfig.GetIntDefault("AuctionHouseBot.Account", 0); + AHBplayerGUID = sConfig.GetIntDefault("AuctionHouseBot.GUID", 0); + ItemsPerCycle = sConfig.GetIntDefault("AuctionHouseBot.ItemsPerCycle", 200); + + //Begin Filters + + Vendor_Items = sConfig.GetBoolDefault("AuctionHouseBot.VendorItems", false); + Loot_Items = sConfig.GetBoolDefault("AuctionHouseBot.LootItems", true); + Other_Items = sConfig.GetBoolDefault("AuctionHouseBot.OtherItems", false); + Vendor_TGs = sConfig.GetBoolDefault("AuctionHouseBot.VendorTradeGoods", false); + Loot_TGs = sConfig.GetBoolDefault("AuctionHouseBot.LootTradeGoods", true); + Other_TGs = sConfig.GetBoolDefault("AuctionHouseBot.OtherTradeGoods", false); + + No_Bind = sConfig.GetBoolDefault("AuctionHouseBot.No_Bind", true); + Bind_When_Picked_Up = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Picked_Up", false); + Bind_When_Equipped = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Equipped", true); + Bind_When_Use = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Use", true); + Bind_Quest_Item = sConfig.GetBoolDefault("AuctionHouseBot.Bind_Quest_Item", false); + + DisableBeta_PTR_Unused = sConfig.GetBoolDefault("AuctionHouseBot.DisableBeta_PTR_Unused", false); + DisablePermEnchant = sConfig.GetBoolDefault("AuctionHouseBot.DisablePermEnchant", false); + DisableConjured = sConfig.GetBoolDefault("AuctionHouseBot.DisableConjured", false); + DisableGems = sConfig.GetBoolDefault("AuctionHouseBot.DisableGems", false); + DisableMoney = sConfig.GetBoolDefault("AuctionHouseBot.DisableMoney", false); + DisableMoneyLoot = sConfig.GetBoolDefault("AuctionHouseBot.DisableMoneyLoot", false); + DisableLootable = sConfig.GetBoolDefault("AuctionHouseBot.DisableLootable", false); + DisableKeys = sConfig.GetBoolDefault("AuctionHouseBot.DisableKeys", false); + DisableDuration = sConfig.GetBoolDefault("AuctionHouseBot.DisableDuration", false); + DisableBOP_Or_Quest_NoReqLevel = sConfig.GetBoolDefault("AuctionHouseBot.DisableBOP_Or_Quest_NoReqLevel", false); + + DisableWarriorItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableWarriorItems", false); + DisablePaladinItems = sConfig.GetBoolDefault("AuctionHouseBot.DisablePaladinItems", false); + DisableHunterItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableHunterItems", false); + DisableRogueItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableRogueItems", false); + DisablePriestItems = sConfig.GetBoolDefault("AuctionHouseBot.DisablePriestItems", false); + DisableDKItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableDKItems", false); + DisableShamanItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableShamanItems", false); + DisableMageItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableMageItems", false); + DisableWarlockItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableWarlockItems", false); + DisableUnusedClassItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableUnusedClassItems", false); + DisableDruidItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableDruidItems", false); + + DisableItemsBelowLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowLevel", 0); + DisableItemsAboveLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveLevel", 0); + DisableTGsBelowLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowLevel", 0); + DisableTGsAboveLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveLevel", 0); + DisableItemsBelowGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowGUID", 0); + DisableItemsAboveGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveGUID", 0); + DisableTGsBelowGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowGUID", 0); + DisableTGsAboveGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveGUID", 0); + DisableItemsBelowReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowReqLevel", 0); + DisableItemsAboveReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveReqLevel", 0); + DisableTGsBelowReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowReqLevel", 0); + DisableTGsAboveReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveReqLevel", 0); + DisableItemsBelowReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowReqSkillRank", 0); + DisableItemsAboveReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveReqSkillRank", 0); + DisableTGsBelowReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowReqSkillRank", 0); + DisableTGsAboveReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveReqSkillRank", 0); + + //End Filters + if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) + { + LoadValues(&AllianceConfig); + LoadValues(&HordeConfig); + } + LoadValues(&NeutralConfig); + + // + // check if the AHBot account/GUID in the config actually exists + // + + if ((AHBplayerAccount != 0) || (AHBplayerGUID != 0)) + { + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT 1 FROM characters WHERE account = %u AND guid = %u", AHBplayerAccount, AHBplayerGUID); + if (!result) + { + sLog.outError("AuctionHouseBot: The account/GUID-information set for your AHBot is incorrect (account: %u guid: %u)", AHBplayerAccount, AHBplayerGUID); + return; + } + } + + if (AHBSeller) + { + QueryResult_AutoPtr results = QueryResult_AutoPtr(NULL); + char npcQuery[] = "SELECT distinct item FROM npc_vendor"; + results = WorldDatabase.Query(npcQuery); + if (results != NULL) + { + do + { + Field* fields = results->Fetch(); + npcItems.push_back(fields[0].GetUInt32()); + + } while (results->NextRow()); + } + else + { + if (debug_Out) sLog.outString("AuctionHouseBot: \"%s\" failed", npcQuery); + } + + char lootQuery[] = "SELECT item FROM creature_loot_template UNION " + "SELECT item FROM reference_loot_template UNION " + "SELECT item FROM disenchant_loot_template UNION " + "SELECT item FROM fishing_loot_template UNION " + "SELECT item FROM gameobject_loot_template UNION " + "SELECT item FROM item_loot_template UNION " + "SELECT item FROM milling_loot_template UNION " + "SELECT item FROM pickpocketing_loot_template UNION " + "SELECT item FROM prospecting_loot_template UNION " + "SELECT item FROM skinning_loot_template"; + + results = WorldDatabase.Query(lootQuery); + if (results != NULL) + { + do + { + Field* fields = results->Fetch(); + lootItems.push_back(fields[0].GetUInt32()); + + } while (results->NextRow()); + } + else + { + if (debug_Out) sLog.outString("AuctionHouseBot: \"%s\" failed", lootQuery); + } + + for (uint32 itemID = 0; itemID < sItemStorage.MaxEntry; itemID++) + { + ItemPrototype const* prototype = objmgr.GetItemPrototype(itemID); + + if (prototype == NULL) + continue; + + switch (prototype->Bonding) + { + case NO_BIND: + if (!No_Bind) + continue; + break; + case BIND_WHEN_PICKED_UP: + if (!Bind_When_Picked_Up) + continue; + break; + case BIND_WHEN_EQUIPED: + if (!Bind_When_Equipped) + continue; + break; + case BIND_WHEN_USE: + if (!Bind_When_Use) + continue; + break; + case BIND_QUEST_ITEM: + if (!Bind_Quest_Item) + continue; + break; + default: + continue; + break; + } + + switch (SellMethod) + { + case 0: + if (prototype->SellPrice == 0) + continue; + break; + case 1: + if (prototype->BuyPrice == 0) + continue; + break; + } + + if ((prototype->Quality < 0) || (prototype->Quality > 6)) + continue; + + if ((Vendor_Items == 0) && !(prototype->Class == ITEM_CLASS_TRADE_GOODS)) + { + bool isVendorItem = false; + + for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorItem); i++) + { + if (itemID == npcItems[i]) + isVendorItem = true; + } + + if (isVendorItem) + continue; + } + + if ((Vendor_TGs == 0) && (prototype->Class == ITEM_CLASS_TRADE_GOODS)) + { + bool isVendorTG = false; + + for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorTG); i++) + { + if (itemID == npcItems[i]) + isVendorTG = true; + } + + if (isVendorTG) + continue; + } + + if ((Loot_Items == 0) && !(prototype->Class == ITEM_CLASS_TRADE_GOODS)) + { + bool isLootItem = false; + + for (unsigned int i = 0; (i < lootItems.size()) && (!isLootItem); i++) + { + if (itemID == lootItems[i]) + isLootItem = true; + } + + if (isLootItem) + continue; + } + + if ((Loot_TGs == 0) && (prototype->Class == ITEM_CLASS_TRADE_GOODS)) + { + bool isLootTG = false; + + for (unsigned int i = 0; (i < lootItems.size()) && (!isLootTG); i++) + { + if (itemID == lootItems[i]) + isLootTG = true; + } + + if (isLootTG) + continue; + } + + if ((Other_Items == 0) && !(prototype->Class == ITEM_CLASS_TRADE_GOODS)) + { + bool isVendorItem = false; + bool isLootItem = false; + + for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorItem); i++) + { + if (itemID == npcItems[i]) + isVendorItem = true; + } + for (unsigned int i = 0; (i < lootItems.size()) && (!isLootItem); i++) + { + if (itemID == lootItems[i]) + isLootItem = true; + } + if ((!isLootItem) && (!isVendorItem)) + continue; + } + + if ((Other_TGs == 0) && (prototype->Class == ITEM_CLASS_TRADE_GOODS)) + { + bool isVendorTG = false; + bool isLootTG = false; + + for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorTG); i++) + { + if (itemID == npcItems[i]) + isVendorTG = true; + } + for (unsigned int i = 0; (i < lootItems.size()) && (!isLootTG); i++) + { + if (itemID == lootItems[i]) + isLootTG = true; + } + if ((!isLootTG) && (!isVendorTG)) + continue; + } + + //TODO:Make list of items and create a vector + // Disable PTR/Beta/Unused items + if ((DisableBeta_PTR_Unused) && ((prototype->ItemId == 21878) || (prototype->ItemId == 27774) || (prototype->ItemId == 27811) || (prototype->ItemId == 28117) || (prototype->ItemId == 28112))) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (PTR/Beta/Unused Item)", prototype->ItemId); + continue; + } + + // Disable permanent enchants items + if ((DisablePermEnchant) && (prototype->Class == ITEM_CLASS_PERMANENT)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Permanent Enchant Item)", prototype->ItemId); + continue; + } + + // Disable conjured items + if ((DisableConjured) && (prototype->IsConjuredConsumable())) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Conjured Consumable)", prototype->ItemId); + continue; + } + + // Disable gems + if ((DisableGems) && (prototype->Class == ITEM_CLASS_GEM)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Gem)", prototype->ItemId); + continue; + } + + // Disable money + if ((DisableMoney) && (prototype->Class == ITEM_CLASS_MONEY)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Money)", prototype->ItemId); + continue; + } + + // Disable moneyloot + if ((DisableMoneyLoot) && (prototype->MinMoneyLoot > 0)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (MoneyLoot)", prototype->ItemId); + continue; + } + + // Disable lootable items + if ((DisableLootable) && (prototype->Flags & 4)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Lootable Item)", prototype->ItemId); + continue; + } + + // Disable Keys + if ((DisableKeys) && (prototype->Class == ITEM_CLASS_KEY)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Quest Item)", prototype->ItemId); + continue; + } + + // Disable items with duration + if ((DisableDuration) && (prototype->Duration > 0)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Has a Duration)", prototype->ItemId); + continue; + } + + // Disable items which are BOP or Quest Items and have a required level lower than the item level + if ((DisableBOP_Or_Quest_NoReqLevel) && ((prototype->Bonding == BIND_WHEN_PICKED_UP || prototype->Bonding == BIND_QUEST_ITEM) && (prototype->RequiredLevel < prototype->ItemLevel))) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (BOP or BQI and Required Level is less than Item Level)", prototype->ItemId); + continue; + } + + // Disable items specifically for Warrior + if ((DisableWarriorItems) && (prototype->AllowableClass == 1)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Warrior Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Paladin + if ((DisablePaladinItems) && (prototype->AllowableClass == 2)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Paladin Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Hunter + if ((DisableHunterItems) && (prototype->AllowableClass == 4)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Hunter Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Rogue + if ((DisableRogueItems) && (prototype->AllowableClass == 8)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Rogue Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Priest + if ((DisablePriestItems) && (prototype->AllowableClass == 16)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Priest Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for DK + if ((DisableDKItems) && (prototype->AllowableClass == 32)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (DK Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Shaman + if ((DisableShamanItems) && (prototype->AllowableClass == 64)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Shaman Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Mage + if ((DisableMageItems) && (prototype->AllowableClass == 128)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Mage Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Warlock + if ((DisableWarlockItems) && (prototype->AllowableClass == 256)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Warlock Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Unused Class + if ((DisableUnusedClassItems) && (prototype->AllowableClass == 512)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Unused Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Druid + if ((DisableDruidItems) && (prototype->AllowableClass == 1024)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Druid Item)", prototype->ItemId); + continue; + } + + // Disable Items below level X + if ((DisableItemsBelowLevel) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel < DisableItemsBelowLevel)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Items above level X + if ((DisableItemsAboveLevel) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel > DisableItemsAboveLevel)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Trade Goods below level X + if ((DisableTGsBelowLevel) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel < DisableTGsBelowLevel)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Trade Good %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Trade Goods above level X + if ((DisableTGsAboveLevel) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel > DisableTGsAboveLevel)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Trade Good %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Items below GUID X + if ((DisableItemsBelowGUID) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId < DisableItemsBelowGUID)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Items above GUID X + if ((DisableItemsAboveGUID) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId > DisableItemsAboveGUID)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Trade Goods below GUID X + if ((DisableTGsBelowGUID) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId < DisableTGsBelowGUID)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Trade Goods above GUID X + if ((DisableTGsAboveGUID) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId > DisableTGsAboveGUID)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Items for level lower than X + if ((DisableItemsBelowReqLevel) && (prototype->RequiredLevel < DisableItemsBelowReqLevel)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel); + continue; + } + + // Disable Items for level higher than X + if ((DisableItemsAboveReqLevel) && (prototype->RequiredLevel > DisableItemsAboveReqLevel)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel); + continue; + } + + // Disable Trade Goods for level lower than X + if ((DisableTGsBelowReqLevel) && (prototype->RequiredLevel < DisableTGsBelowReqLevel)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Trade Good %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel); + continue; + } + + // Disable Trade Goods for level higher than X + if ((DisableTGsAboveReqLevel) && (prototype->RequiredLevel > DisableTGsAboveReqLevel)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Trade Good %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel); + continue; + } + + // Disable Items that require skill lower than X + if ((DisableItemsBelowReqSkillRank) && (prototype->RequiredSkillRank < DisableItemsBelowReqSkillRank)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank); + continue; + } + + // Disable Items that require skill higher than X + if ((DisableItemsAboveReqSkillRank) && (prototype->RequiredSkillRank > DisableItemsAboveReqSkillRank)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank); + continue; + } + + // Disable Trade Goods that require skill lower than X + if ((DisableTGsBelowReqSkillRank) && (prototype->RequiredSkillRank < DisableTGsBelowReqSkillRank)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank); + continue; + } + + // Disable Trade Goods that require skill higher than X + if ((DisableTGsAboveReqSkillRank) && (prototype->RequiredSkillRank > DisableTGsAboveReqSkillRank)) + { + if (debug_Out_Filters) sLog.outString("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank); + continue; + } + + switch (prototype->Quality) + { + case AHB_GREY: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + greyTradeGoodsBin.push_back(itemID); + else + greyItemsBin.push_back(itemID); + break; + + case AHB_WHITE: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + whiteTradeGoodsBin.push_back(itemID); + else + whiteItemsBin.push_back(itemID); + break; + + case AHB_GREEN: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + greenTradeGoodsBin.push_back(itemID); + else + greenItemsBin.push_back(itemID); + break; + + case AHB_BLUE: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + blueTradeGoodsBin.push_back(itemID); + else + blueItemsBin.push_back(itemID); + break; + + case AHB_PURPLE: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + purpleTradeGoodsBin.push_back(itemID); + else + purpleItemsBin.push_back(itemID); + break; + + case AHB_ORANGE: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + orangeTradeGoodsBin.push_back(itemID); + else + orangeItemsBin.push_back(itemID); + break; + + case AHB_YELLOW: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + yellowTradeGoodsBin.push_back(itemID); + else + yellowItemsBin.push_back(itemID); + break; + } + } + + if ((greyTradeGoodsBin.size() == 0) && + (whiteTradeGoodsBin.size() == 0) && + (greenTradeGoodsBin.size() == 0) && + (blueTradeGoodsBin.size() == 0) && + (purpleTradeGoodsBin.size() == 0) && + (orangeTradeGoodsBin.size() == 0) && + (yellowTradeGoodsBin.size() == 0) && + (greyItemsBin.size() == 0) && + (whiteItemsBin.size() == 0) && + (greenItemsBin.size() == 0) && + (blueItemsBin.size() == 0) && + (purpleItemsBin.size() == 0) && + (orangeItemsBin.size() == 0) && + (yellowItemsBin.size() == 0)) + { + sLog.outError("AuctionHouseBot: No items"); + AHBSeller = 0; + } + + sLog.outString("AuctionHouseBot:"); + sLog.outString("loaded %u grey trade goods", greyTradeGoodsBin.size()); + sLog.outString("loaded %u white trade goods", whiteTradeGoodsBin.size()); + sLog.outString("loaded %u green trade goods", greenTradeGoodsBin.size()); + sLog.outString("loaded %u blue trade goods", blueTradeGoodsBin.size()); + sLog.outString("loaded %u purple trade goods", purpleTradeGoodsBin.size()); + sLog.outString("loaded %u orange trade goods", orangeTradeGoodsBin.size()); + sLog.outString("loaded %u yellow trade goods", yellowTradeGoodsBin.size()); + sLog.outString("loaded %u grey items", greyItemsBin.size()); + sLog.outString("loaded %u white items", whiteItemsBin.size()); + sLog.outString("loaded %u green items", greenItemsBin.size()); + sLog.outString("loaded %u blue items", blueItemsBin.size()); + sLog.outString("loaded %u purple items", purpleItemsBin.size()); + sLog.outString("loaded %u orange items", orangeItemsBin.size()); + sLog.outString("loaded %u yellow items", yellowItemsBin.size()); + } + sLog.outString("AuctionHouseBot and AuctionHouseBuyer have been loaded."); +} + +void AuctionHouseBot::IncrementItemCounts(AuctionEntry* ah) +{ + // from auctionhousehandler.cpp, creates auction pointer & player pointer + + // get exact item information + Item *pItem = auctionmgr.GetAItem(ah->item_guidlow); + if (!pItem) + { + if (debug_Out) sLog.outError("AHBot: Item %u doesn't exist, perhaps bought already?", ah->item_guidlow); + return; + } + + // get item prototype + ItemPrototype const* prototype = objmgr.GetItemPrototype(ah->item_template); + + AHBConfig *config; + + FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(ah->GetHouseFaction()); + if (!u_entry) + { + if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Neutral", ah->GetHouseFaction()); + config = &NeutralConfig; + } + else if (u_entry->ourMask & FACTION_MASK_ALLIANCE) + { + if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Alliance", ah->GetHouseFaction()); + config = &AllianceConfig; + } + else if (u_entry->ourMask & FACTION_MASK_HORDE) + { + if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Horde", ah->GetHouseFaction()); + config = &HordeConfig; + } + else + { + if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Neutral", ah->GetHouseFaction()); + config = &NeutralConfig; + } + + config->IncItemCounts(prototype->Class, prototype->Quality); +} + +void AuctionHouseBot::DecrementItemCounts(AuctionEntry* ah, uint32 item_template) +{ + // get item prototype + ItemPrototype const* prototype = objmgr.GetItemPrototype(item_template); + + AHBConfig *config; + + FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(ah->GetHouseFaction()); + if (!u_entry) + { + if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Neutral", ah->GetHouseFaction()); + config = &NeutralConfig; + } + else if (u_entry->ourMask & FACTION_MASK_ALLIANCE) + { + if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Alliance", ah->GetHouseFaction()); + config = &AllianceConfig; + } + else if (u_entry->ourMask & FACTION_MASK_HORDE) + { + if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Horde", ah->GetHouseFaction()); + config = &HordeConfig; + } + else + { + if (debug_Out) sLog.outError("AHBot: %u returned as House Faction. Neutral", ah->GetHouseFaction()); + config = &NeutralConfig; + } + + config->DecItemCounts(prototype->Class, prototype->Quality); +} + +void AuctionHouseBot::Commands(uint32 command, uint32 ahMapID, uint32 col, char* args) +{ + AHBConfig *config = NULL; + switch (ahMapID) + { + case 2: + config = &AllianceConfig; + break; + case 6: + config = &HordeConfig; + break; + case 7: + config = &NeutralConfig; + break; + } + std::string color; + switch (col) + { + case AHB_GREY: + color = "grey"; + break; + case AHB_WHITE: + color = "white"; + break; + case AHB_GREEN: + color = "green"; + break; + case AHB_BLUE: + color = "blue"; + break; + case AHB_PURPLE: + color = "purple"; + break; + case AHB_ORANGE: + color = "orange"; + break; + case AHB_YELLOW: + color = "yellow"; + break; + default: + break; + } + switch (command) + { + case 0: //ahexpire + { + AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(config->GetAHFID()); + + AuctionHouseObject::AuctionEntryMap::iterator itr; + itr = auctionHouse->GetAuctionsBegin(); + + while (itr != auctionHouse->GetAuctionsEnd()) + { + if (itr->second->owner == AHBplayerGUID) + { + itr->second->expire_time = sWorld.GetGameTime(); + uint32 id = itr->second->Id; + uint32 expire_time = itr->second->expire_time; + CharacterDatabase.PExecute("UPDATE auctionhouse SET time = '%u' WHERE id = '%u'", expire_time, id); + } + ++itr; + } + } + break; + case 1: //min items + { + char * param1 = strtok(args, " "); + uint32 minItems = (uint32) strtoul(param1, NULL, 0); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET minitems = '%u' WHERE auctionhouse = '%u'", minItems, ahMapID); + config->SetMinItems(minItems); + } + break; + case 2: //max items + { + char * param1 = strtok(args, " "); + uint32 maxItems = (uint32) strtoul(param1, NULL, 0); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxitems = '%u' WHERE auctionhouse = '%u'", maxItems, ahMapID); + config->SetMaxItems(maxItems); + } + break; + case 3: //min time Deprecated (Place holder for future commands) + break; + case 4: //max time Deprecated (Place holder for future commands) + break; + case 5: //percentages + { + char * param1 = strtok(args, " "); + char * param2 = strtok(NULL, " "); + char * param3 = strtok(NULL, " "); + char * param4 = strtok(NULL, " "); + char * param5 = strtok(NULL, " "); + char * param6 = strtok(NULL, " "); + char * param7 = strtok(NULL, " "); + char * param8 = strtok(NULL, " "); + char * param9 = strtok(NULL, " "); + char * param10 = strtok(NULL, " "); + char * param11 = strtok(NULL, " "); + char * param12 = strtok(NULL, " "); + char * param13 = strtok(NULL, " "); + char * param14 = strtok(NULL, " "); + uint32 greytg = (uint32) strtoul(param1, NULL, 0); + uint32 whitetg = (uint32) strtoul(param2, NULL, 0); + uint32 greentg = (uint32) strtoul(param3, NULL, 0); + uint32 bluetg = (uint32) strtoul(param4, NULL, 0); + uint32 purpletg = (uint32) strtoul(param5, NULL, 0); + uint32 orangetg = (uint32) strtoul(param6, NULL, 0); + uint32 yellowtg = (uint32) strtoul(param7, NULL, 0); + uint32 greyi = (uint32) strtoul(param8, NULL, 0); + uint32 whitei = (uint32) strtoul(param9, NULL, 0); + uint32 greeni = (uint32) strtoul(param10, NULL, 0); + uint32 bluei = (uint32) strtoul(param11, NULL, 0); + uint32 purplei = (uint32) strtoul(param12, NULL, 0); + uint32 orangei = (uint32) strtoul(param13, NULL, 0); + uint32 yellowi = (uint32) strtoul(param14, NULL, 0); + + CharacterDatabase.BeginTransaction(); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentgreytradegoods = '%u' WHERE auctionhouse = '%u'", greytg, ahMapID); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentwhitetradegoods = '%u' WHERE auctionhouse = '%u'", whitetg, ahMapID); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentgreentradegoods = '%u' WHERE auctionhouse = '%u'", greentg, ahMapID); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentbluetradegoods = '%u' WHERE auctionhouse = '%u'", bluetg, ahMapID); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentpurpletradegoods = '%u' WHERE auctionhouse = '%u'", purpletg, ahMapID); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentorangetradegoods = '%u' WHERE auctionhouse = '%u'", orangetg, ahMapID); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentyellowtradegoods = '%u' WHERE auctionhouse = '%u'", yellowtg, ahMapID); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentgreyitems = '%u' WHERE auctionhouse = '%u'", greyi, ahMapID); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentwhiteitems = '%u' WHERE auctionhouse = '%u'", whitei, ahMapID); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentgreenitems = '%u' WHERE auctionhouse = '%u'", greeni, ahMapID); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentblueitems = '%u' WHERE auctionhouse = '%u'", bluei, ahMapID); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentpurpleitems = '%u' WHERE auctionhouse = '%u'", purplei, ahMapID); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentorangeitems = '%u' WHERE auctionhouse = '%u'", orangei, ahMapID); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentyellowitems = '%u' WHERE auctionhouse = '%u'", yellowi, ahMapID); + CharacterDatabase.CommitTransaction(); + config->SetPercentages(greytg, whitetg, greentg, bluetg, purpletg, orangetg, yellowtg, greyi, whitei, greeni, bluei, purplei, orangei, yellowi); + } + break; + case 6: //min prices + { + char * param1 = strtok(args, " "); + uint32 minPrice = (uint32) strtoul(param1, NULL, 0); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET minprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), minPrice, ahMapID); + config->SetMinPrice(col, minPrice); + } + break; + case 7: //max prices + { + char * param1 = strtok(args, " "); + uint32 maxPrice = (uint32) strtoul(param1, NULL, 0); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), maxPrice, ahMapID); + config->SetMaxPrice(col, maxPrice); + } + break; + case 8: //min bid price + { + char * param1 = strtok(args, " "); + uint32 minBidPrice = (uint32) strtoul(param1, NULL, 0); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET minbidprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), minBidPrice, ahMapID); + config->SetMinBidPrice(col, minBidPrice); + } + break; + case 9: //max bid price + { + char * param1 = strtok(args, " "); + uint32 maxBidPrice = (uint32) strtoul(param1, NULL, 0); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxbidprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), maxBidPrice, ahMapID); + config->SetMaxBidPrice(col, maxBidPrice); + } + break; + case 10: //max stacks + { + char * param1 = strtok(args, " "); + uint32 maxStack = (uint32) strtoul(param1, NULL, 0); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxstack%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), maxStack, ahMapID); + config->SetMaxStack(col, maxStack); + } + break; + case 11: //buyer bid prices + { + char * param1 = strtok(args, " "); + uint32 buyerPrice = (uint32) strtoul(param1, NULL, 0); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET buyerprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), buyerPrice, ahMapID); + config->SetBuyerPrice(col, buyerPrice); + } + break; + case 12: //buyer bidding interval + { + char * param1 = strtok(args, " "); + uint32 bidInterval = (uint32) strtoul(param1, NULL, 0); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET buyerbiddinginterval = '%u' WHERE auctionhouse = '%u'", bidInterval, ahMapID); + config->SetBiddingInterval(bidInterval); + } + break; + case 13: //buyer bids per interval + { + char * param1 = strtok(args, " "); + uint32 bidsPerInterval = (uint32) strtoul(param1, NULL, 0); + CharacterDatabase.PExecute("UPDATE auctionhousebot SET buyerbidsperinterval = '%u' WHERE auctionhouse = '%u'", bidsPerInterval, ahMapID); + config->SetBidsPerInterval(bidsPerInterval); + } + break; + default: + break; + } +} + +void AuctionHouseBot::LoadValues(AHBConfig *config) +{ + if (debug_Out) sLog.outString("Start Settings for %s Auctionhouses:", CharacterDatabase.PQuery("SELECT name FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetString()); + if (AHBSeller) + { + //load min and max items + config->SetMinItems(CharacterDatabase.PQuery("SELECT minitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxItems(CharacterDatabase.PQuery("SELECT maxitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + //load percentages + uint32 greytg = CharacterDatabase.PQuery("SELECT percentgreytradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); + uint32 whitetg = CharacterDatabase.PQuery("SELECT percentwhitetradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); + uint32 greentg = CharacterDatabase.PQuery("SELECT percentgreentradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); + uint32 bluetg = CharacterDatabase.PQuery("SELECT percentbluetradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); + uint32 purpletg = CharacterDatabase.PQuery("SELECT percentpurpletradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); + uint32 orangetg = CharacterDatabase.PQuery("SELECT percentorangetradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); + uint32 yellowtg = CharacterDatabase.PQuery("SELECT percentyellowtradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); + uint32 greyi = CharacterDatabase.PQuery("SELECT percentgreyitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); + uint32 whitei = CharacterDatabase.PQuery("SELECT percentwhiteitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); + uint32 greeni = CharacterDatabase.PQuery("SELECT percentgreenitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); + uint32 bluei = CharacterDatabase.PQuery("SELECT percentblueitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); + uint32 purplei = CharacterDatabase.PQuery("SELECT percentpurpleitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); + uint32 orangei = CharacterDatabase.PQuery("SELECT percentorangeitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); + uint32 yellowi = CharacterDatabase.PQuery("SELECT percentyellowitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); + config->SetPercentages(greytg, whitetg, greentg, bluetg, purpletg, orangetg, yellowtg, greyi, whitei, greeni, bluei, purplei, orangei, yellowi); + //load min and max prices + config->SetMinPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT minpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT maxpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMinPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT minpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT maxpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMinPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT minpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT maxpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMinPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT minpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT maxpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMinPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT minpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT maxpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMinPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT minpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT maxpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMinPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT minpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT maxpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + //load min and max bid prices + config->SetMinBidPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT minbidpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxBidPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT maxbidpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMinBidPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT minbidpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxBidPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT maxbidpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMinBidPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT minbidpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxBidPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT maxbidpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMinBidPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT minbidpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxBidPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT maxbidpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMinBidPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT minbidpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxBidPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT maxbidpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMinBidPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT minbidpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxBidPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT maxbidpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMinBidPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT minbidpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxBidPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT maxbidpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + //load max stacks + config->SetMaxStack(AHB_GREY, CharacterDatabase.PQuery("SELECT maxstackgrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxStack(AHB_WHITE, CharacterDatabase.PQuery("SELECT maxstackwhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxStack(AHB_GREEN, CharacterDatabase.PQuery("SELECT maxstackgreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxStack(AHB_BLUE, CharacterDatabase.PQuery("SELECT maxstackblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxStack(AHB_PURPLE, CharacterDatabase.PQuery("SELECT maxstackpurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxStack(AHB_ORANGE, CharacterDatabase.PQuery("SELECT maxstackorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetMaxStack(AHB_YELLOW, CharacterDatabase.PQuery("SELECT maxstackyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + if (debug_Out) + { + sLog.outString("minItems = %u", config->GetMinItems()); + sLog.outString("maxItems = %u", config->GetMaxItems()); + sLog.outString("percentGreyTradeGoods = %u", config->GetPercentages(AHB_GREY_TG)); + sLog.outString("percentWhiteTradeGoods = %u", config->GetPercentages(AHB_WHITE_TG)); + sLog.outString("percentGreenTradeGoods = %u", config->GetPercentages(AHB_GREEN_TG)); + sLog.outString("percentBlueTradeGoods = %u", config->GetPercentages(AHB_BLUE_TG)); + sLog.outString("percentPurpleTradeGoods = %u", config->GetPercentages(AHB_PURPLE_TG)); + sLog.outString("percentOrangeTradeGoods = %u", config->GetPercentages(AHB_ORANGE_TG)); + sLog.outString("percentYellowTradeGoods = %u", config->GetPercentages(AHB_YELLOW_TG)); + sLog.outString("percentGreyItems = %u", config->GetPercentages(AHB_GREY_I)); + sLog.outString("percentWhiteItems = %u", config->GetPercentages(AHB_WHITE_I)); + sLog.outString("percentGreenItems = %u", config->GetPercentages(AHB_GREEN_I)); + sLog.outString("percentBlueItems = %u", config->GetPercentages(AHB_BLUE_I)); + sLog.outString("percentPurpleItems = %u", config->GetPercentages(AHB_PURPLE_I)); + sLog.outString("percentOrangeItems = %u", config->GetPercentages(AHB_ORANGE_I)); + sLog.outString("percentYellowItems = %u", config->GetPercentages(AHB_YELLOW_I)); + sLog.outString("minPriceGrey = %u", config->GetMinPrice(AHB_GREY)); + sLog.outString("maxPriceGrey = %u", config->GetMaxPrice(AHB_GREY)); + sLog.outString("minPriceWhite = %u", config->GetMinPrice(AHB_WHITE)); + sLog.outString("maxPriceWhite = %u", config->GetMaxPrice(AHB_WHITE)); + sLog.outString("minPriceGreen = %u", config->GetMinPrice(AHB_GREEN)); + sLog.outString("maxPriceGreen = %u", config->GetMaxPrice(AHB_GREEN)); + sLog.outString("minPriceBlue = %u", config->GetMinPrice(AHB_BLUE)); + sLog.outString("maxPriceBlue = %u", config->GetMaxPrice(AHB_BLUE)); + sLog.outString("minPricePurple = %u", config->GetMinPrice(AHB_PURPLE)); + sLog.outString("maxPricePurple = %u", config->GetMaxPrice(AHB_PURPLE)); + sLog.outString("minPriceOrange = %u", config->GetMinPrice(AHB_ORANGE)); + sLog.outString("maxPriceOrange = %u", config->GetMaxPrice(AHB_ORANGE)); + sLog.outString("minPriceYellow = %u", config->GetMinPrice(AHB_YELLOW)); + sLog.outString("maxPriceYellow = %u", config->GetMaxPrice(AHB_YELLOW)); + sLog.outString("minBidPriceGrey = %u", config->GetMinBidPrice(AHB_GREY)); + sLog.outString("maxBidPriceGrey = %u", config->GetMaxBidPrice(AHB_GREY)); + sLog.outString("minBidPriceWhite = %u", config->GetMinBidPrice(AHB_WHITE)); + sLog.outString("maxBidPriceWhite = %u", config->GetMaxBidPrice(AHB_WHITE)); + sLog.outString("minBidPriceGreen = %u", config->GetMinBidPrice(AHB_GREEN)); + sLog.outString("maxBidPriceGreen = %u", config->GetMaxBidPrice(AHB_GREEN)); + sLog.outString("minBidPriceBlue = %u", config->GetMinBidPrice(AHB_BLUE)); + sLog.outString("maxBidPriceBlue = %u", config->GetMinBidPrice(AHB_BLUE)); + sLog.outString("minBidPricePurple = %u", config->GetMinBidPrice(AHB_PURPLE)); + sLog.outString("maxBidPricePurple = %u", config->GetMaxBidPrice(AHB_PURPLE)); + sLog.outString("minBidPriceOrange = %u", config->GetMinBidPrice(AHB_ORANGE)); + sLog.outString("maxBidPriceOrange = %u", config->GetMaxBidPrice(AHB_ORANGE)); + sLog.outString("minBidPriceYellow = %u", config->GetMinBidPrice(AHB_YELLOW)); + sLog.outString("maxBidPriceYellow = %u", config->GetMaxBidPrice(AHB_YELLOW)); + sLog.outString("maxStackGrey = %u", config->GetMaxStack(AHB_GREY)); + sLog.outString("maxStackWhite = %u", config->GetMaxStack(AHB_WHITE)); + sLog.outString("maxStackGreen = %u", config->GetMaxStack(AHB_GREEN)); + sLog.outString("maxStackBlue = %u", config->GetMaxStack(AHB_BLUE)); + sLog.outString("maxStackPurple = %u", config->GetMaxStack(AHB_PURPLE)); + sLog.outString("maxStackOrange = %u", config->GetMaxStack(AHB_ORANGE)); + sLog.outString("maxStackYellow = %u", config->GetMaxStack(AHB_YELLOW)); + } + //AuctionHouseEntry const* ahEntry = auctionmgr.GetAuctionHouseEntry(config->GetAHFID()); + AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(config->GetAHFID()); + + config->ResetItemCounts(); + uint32 auctions = auctionHouse->Getcount(); + + if (auctions) + { + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionHouse->GetAuctionsBegin(); itr != auctionHouse->GetAuctionsEnd(); ++itr) + { + AuctionEntry *Aentry = itr->second; + Item *item = auctionmgr.GetAItem(Aentry->item_guidlow); + if (item) + { + ItemPrototype const *prototype = item->GetProto(); + if (prototype) + { + switch (prototype->Quality) + { + case 0: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + config->IncItemCounts(AHB_GREY_TG); + else + config->IncItemCounts(AHB_GREY_I); + break; + case 1: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + config->IncItemCounts(AHB_WHITE_TG); + else + config->IncItemCounts(AHB_WHITE_I); + break; + case 2: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + config->IncItemCounts(AHB_GREEN_TG); + else + config->IncItemCounts(AHB_GREEN_I); + break; + case 3: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + config->IncItemCounts(AHB_BLUE_TG); + else + config->IncItemCounts(AHB_BLUE_I); + break; + case 4: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + config->IncItemCounts(AHB_PURPLE_TG); + else + config->IncItemCounts(AHB_PURPLE_I); + break; + case 5: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + config->IncItemCounts(AHB_ORANGE_TG); + else + config->IncItemCounts(AHB_ORANGE_I); + break; + case 6: + if (prototype->Class == ITEM_CLASS_TRADE_GOODS) + config->IncItemCounts(AHB_YELLOW_TG); + else + config->IncItemCounts(AHB_YELLOW_I); + break; + } + } + } + } + } + if (debug_Out) + { + sLog.outString("Current Items in %s Auctionhouses:", CharacterDatabase.PQuery("SELECT name FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetString()); + sLog.outString("Grey Trade Goods\t%u\tGrey Items\t%u", config->GetItemCounts(AHB_GREY_TG), config->GetItemCounts(AHB_GREY_I)); + sLog.outString("White Trade Goods\t%u\tWhite Items\t%u", config->GetItemCounts(AHB_WHITE_TG), config->GetItemCounts(AHB_WHITE_I)); + sLog.outString("Green Trade Goods\t%u\tGreen Items\t%u", config->GetItemCounts(AHB_GREEN_TG), config->GetItemCounts(AHB_GREEN_I)); + sLog.outString("Blue Trade Goods\t%u\tBlue Items\t%u", config->GetItemCounts(AHB_BLUE_TG), config->GetItemCounts(AHB_BLUE_I)); + sLog.outString("Purple Trade Goods\t%u\tPurple Items\t%u", config->GetItemCounts(AHB_PURPLE_TG), config->GetItemCounts(AHB_PURPLE_I)); + sLog.outString("Orange Trade Goods\t%u\tOrange Items\t%u", config->GetItemCounts(AHB_ORANGE_TG), config->GetItemCounts(AHB_ORANGE_I)); + sLog.outString("Yellow Trade Goods\t%u\tYellow Items\t%u", config->GetItemCounts(AHB_YELLOW_TG), config->GetItemCounts(AHB_YELLOW_I)); + } + } + if (AHBBuyer) + { + //load buyer bid prices + config->SetBuyerPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT buyerpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetBuyerPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT buyerpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetBuyerPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT buyerpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetBuyerPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT buyerpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetBuyerPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT buyerpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetBuyerPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT buyerpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + config->SetBuyerPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT buyerpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + //load bidding interval + config->SetBiddingInterval(CharacterDatabase.PQuery("SELECT buyerbiddinginterval FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + //load bids per interval + config->SetBidsPerInterval(CharacterDatabase.PQuery("SELECT buyerbidsperinterval FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); + if (debug_Out) + { + sLog.outString("buyerPriceGrey = %u", config->GetBuyerPrice(AHB_GREY)); + sLog.outString("buyerPriceWhite = %u", config->GetBuyerPrice(AHB_WHITE)); + sLog.outString("buyerPriceGreen = %u", config->GetBuyerPrice(AHB_GREEN)); + sLog.outString("buyerPriceBlue = %u", config->GetBuyerPrice(AHB_BLUE)); + sLog.outString("buyerPricePurple = %u", config->GetBuyerPrice(AHB_PURPLE)); + sLog.outString("buyerPriceOrange = %u", config->GetBuyerPrice(AHB_ORANGE)); + sLog.outString("buyerPriceYellow = %u", config->GetBuyerPrice(AHB_YELLOW)); + sLog.outString("buyerBiddingInterval = %u", config->GetBiddingInterval()); + sLog.outString("buyerBidsPerInterval = %u", config->GetBidsPerInterval()); + } + } + if (debug_Out) sLog.outString("End Settings for %s Auctionhouses:", CharacterDatabase.PQuery("SELECT name FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetString()); +} diff --git a/src/server/game/AuctionHouse/AuctionHouseBot/AuctionHouseBot.h b/src/server/game/AuctionHouse/AuctionHouseBot/AuctionHouseBot.h new file mode 100644 index 00000000000..208a09aa0b2 --- /dev/null +++ b/src/server/game/AuctionHouse/AuctionHouseBot/AuctionHouseBot.h @@ -0,0 +1,1225 @@ +#ifndef AUCTION_HOUSE_BOT_H +#define AUCTION_HOUSE_BOT_H + +#include "World.h" +#include "Config/ConfigEnv.h" +#include "ItemPrototype.h" + +#define AHB_GREY 0 +#define AHB_WHITE 1 +#define AHB_GREEN 2 +#define AHB_BLUE 3 +#define AHB_PURPLE 4 +#define AHB_ORANGE 5 +#define AHB_YELLOW 6 +#define AHB_MAX_QUALITY 6 +#define AHB_GREY_TG 0 +#define AHB_WHITE_TG 1 +#define AHB_GREEN_TG 2 +#define AHB_BLUE_TG 3 +#define AHB_PURPLE_TG 4 +#define AHB_ORANGE_TG 5 +#define AHB_YELLOW_TG 6 +#define AHB_GREY_I 7 +#define AHB_WHITE_I 8 +#define AHB_GREEN_I 9 +#define AHB_BLUE_I 10 +#define AHB_PURPLE_I 11 +#define AHB_ORANGE_I 12 +#define AHB_YELLOW_I 13 + +class AHBConfig +{ +private: + uint32 AHID; + uint32 AHFID; + uint32 minItems; + uint32 maxItems; + uint32 percentGreyTradeGoods; + uint32 percentWhiteTradeGoods; + uint32 percentGreenTradeGoods; + uint32 percentBlueTradeGoods; + uint32 percentPurpleTradeGoods; + uint32 percentOrangeTradeGoods; + uint32 percentYellowTradeGoods; + uint32 percentGreyItems; + uint32 percentWhiteItems; + uint32 percentGreenItems; + uint32 percentBlueItems; + uint32 percentPurpleItems; + uint32 percentOrangeItems; + uint32 percentYellowItems; + uint32 minPriceGrey; + uint32 maxPriceGrey; + uint32 minBidPriceGrey; + uint32 maxBidPriceGrey; + uint32 maxStackGrey; + uint32 minPriceWhite; + uint32 maxPriceWhite; + uint32 minBidPriceWhite; + uint32 maxBidPriceWhite; + uint32 maxStackWhite; + uint32 minPriceGreen; + uint32 maxPriceGreen; + uint32 minBidPriceGreen; + uint32 maxBidPriceGreen; + uint32 maxStackGreen; + uint32 minPriceBlue; + uint32 maxPriceBlue; + uint32 minBidPriceBlue; + uint32 maxBidPriceBlue; + uint32 maxStackBlue; + uint32 minPricePurple; + uint32 maxPricePurple; + uint32 minBidPricePurple; + uint32 maxBidPricePurple; + uint32 maxStackPurple; + uint32 minPriceOrange; + uint32 maxPriceOrange; + uint32 minBidPriceOrange; + uint32 maxBidPriceOrange; + uint32 maxStackOrange; + uint32 minPriceYellow; + uint32 maxPriceYellow; + uint32 minBidPriceYellow; + uint32 maxBidPriceYellow; + uint32 maxStackYellow; + + uint32 buyerPriceGrey; + uint32 buyerPriceWhite; + uint32 buyerPriceGreen; + uint32 buyerPriceBlue; + uint32 buyerPricePurple; + uint32 buyerPriceOrange; + uint32 buyerPriceYellow; + uint32 buyerBiddingInterval; + uint32 buyerBidsPerInterval; + + uint32 greytgp; + uint32 whitetgp; + uint32 greentgp; + uint32 bluetgp; + uint32 purpletgp; + uint32 orangetgp; + uint32 yellowtgp; + uint32 greyip; + uint32 whiteip; + uint32 greenip; + uint32 blueip; + uint32 purpleip; + uint32 orangeip; + uint32 yellowip; + + uint32 greyTGoods; + uint32 whiteTGoods; + uint32 greenTGoods; + uint32 blueTGoods; + uint32 purpleTGoods; + uint32 orangeTGoods; + uint32 yellowTGoods; + + uint32 greyItems; + uint32 whiteItems; + uint32 greenItems; + uint32 blueItems; + uint32 purpleItems; + uint32 orangeItems; + uint32 yellowItems; + +public: + AHBConfig(uint32 ahid) + { + AHID = ahid; + switch(ahid) + { + case 2: + AHFID = 55; + break; + case 6: + AHFID = 29; + break; + case 7: + AHFID = 120; + break; + default: + AHFID = 120; + break; + } + } + AHBConfig() + { + } + uint32 GetAHID() + { + return AHID; + } + uint32 GetAHFID() + { + return AHFID; + } + void SetMinItems(uint32 value) + { + minItems = value; + } + uint32 GetMinItems() + { + if ((minItems == 0) && (maxItems)) + return maxItems; + else if ((maxItems) && (minItems > maxItems)) + return maxItems; + else + return minItems; + } + void SetMaxItems(uint32 value) + { + maxItems = value; + CalculatePercents(); + } + uint32 GetMaxItems() + { + return maxItems; + } + void SetPercentages(uint32 greytg, uint32 whitetg, uint32 greentg, uint32 bluetg, uint32 purpletg, uint32 orangetg, uint32 yellowtg, uint32 greyi, uint32 whitei, uint32 greeni, uint32 bluei, uint32 purplei, uint32 orangei, uint32 yellowi) + { + uint32 totalPercent = greytg + whitetg + greentg + bluetg + purpletg + orangetg + yellowtg + greyi + whitei + greeni + bluei + purplei + orangei + yellowi; + + if (totalPercent == 0) + { + maxItems = 0; + } + else if (totalPercent != 100) + { + greytg = 0; + whitetg = 27; + greentg = 12; + bluetg = 10; + purpletg = 1; + orangetg = 0; + yellowtg = 0; + greyi = 0; + whitei = 10; + greeni = 30; + bluei = 8; + purplei = 2; + orangei = 0; + yellowi = 0; + } + percentGreyTradeGoods = greytg; + percentWhiteTradeGoods = whitetg; + percentGreenTradeGoods = greentg; + percentBlueTradeGoods = bluetg; + percentPurpleTradeGoods = purpletg; + percentOrangeTradeGoods = orangetg; + percentYellowTradeGoods = yellowtg; + percentGreyItems = greyi; + percentWhiteItems = whitei; + percentGreenItems = greeni; + percentBlueItems = bluei; + percentPurpleItems = purplei; + percentOrangeItems = orangei; + percentYellowItems = yellowi; + CalculatePercents(); + } + uint32 GetPercentages(uint32 color) + { + switch(color) + { + case AHB_GREY_TG: + return percentGreyTradeGoods; + break; + case AHB_WHITE_TG: + return percentWhiteTradeGoods; + break; + case AHB_GREEN_TG: + return percentGreenTradeGoods; + break; + case AHB_BLUE_TG: + return percentBlueTradeGoods; + break; + case AHB_PURPLE_TG: + return percentPurpleTradeGoods; + break; + case AHB_ORANGE_TG: + return percentOrangeTradeGoods; + break; + case AHB_YELLOW_TG: + return percentYellowTradeGoods; + break; + case AHB_GREY_I: + return percentGreyItems; + break; + case AHB_WHITE_I: + return percentWhiteItems; + break; + case AHB_GREEN_I: + return percentGreenItems; + break; + case AHB_BLUE_I: + return percentBlueItems; + break; + case AHB_PURPLE_I: + return percentPurpleItems; + break; + case AHB_ORANGE_I: + return percentOrangeItems; + break; + case AHB_YELLOW_I: + return percentYellowItems; + break; + default: + return 0; + break; + } + } + void SetMinPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: + minPriceGrey = value; + break; + case AHB_WHITE: + minPriceWhite = value; + break; + case AHB_GREEN: + minPriceGreen = value; + break; + case AHB_BLUE: + minPriceBlue = value; + break; + case AHB_PURPLE: + minPricePurple = value; + break; + case AHB_ORANGE: + minPriceOrange = value; + break; + case AHB_YELLOW: + minPriceYellow = value; + break; + default: + break; + } + } + uint32 GetMinPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: + { + if (minPriceGrey == 0) + return 100; + else if (minPriceGrey > maxPriceGrey) + return maxPriceGrey; + else + return minPriceGrey; + break; + } + case AHB_WHITE: + { + if (minPriceWhite == 0) + return 150; + else if (minPriceWhite > maxPriceWhite) + return maxPriceWhite; + else + return minPriceWhite; + break; + } + case AHB_GREEN: + { + if (minPriceGreen == 0) + return 200; + else if (minPriceGreen > maxPriceGreen) + return maxPriceGreen; + else + return minPriceGreen; + break; + } + case AHB_BLUE: + { + if (minPriceBlue == 0) + return 250; + else if (minPriceBlue > maxPriceBlue) + return maxPriceBlue; + else + return minPriceBlue; + break; + } + case AHB_PURPLE: + { + if (minPricePurple == 0) + return 300; + else if (minPricePurple > maxPricePurple) + return maxPricePurple; + else + return minPricePurple; + break; + } + case AHB_ORANGE: + { + if (minPriceOrange == 0) + return 400; + else if (minPriceOrange > maxPriceOrange) + return maxPriceOrange; + else + return minPriceOrange; + break; + } + case AHB_YELLOW: + { + if (minPriceYellow == 0) + return 500; + else if (minPriceYellow > maxPriceYellow) + return maxPriceYellow; + else + return minPriceYellow; + break; + } + default: + { + return 0; + break; + } + } + } + void SetMaxPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: + maxPriceGrey = value; + break; + case AHB_WHITE: + maxPriceWhite = value; + break; + case AHB_GREEN: + maxPriceGreen = value; + break; + case AHB_BLUE: + maxPriceBlue = value; + break; + case AHB_PURPLE: + maxPricePurple = value; + break; + case AHB_ORANGE: + maxPriceOrange = value; + break; + case AHB_YELLOW: + maxPriceYellow = value; + break; + default: + break; + } + } + uint32 GetMaxPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: + { + if (maxPriceGrey == 0) + return 150; + else + return maxPriceGrey; + break; + } + case AHB_WHITE: + { + if (maxPriceWhite == 0) + return 250; + else + return maxPriceWhite; + break; + } + case AHB_GREEN: + { + if (maxPriceGreen == 0) + return 300; + else + return maxPriceGreen; + break; + } + case AHB_BLUE: + { + if (maxPriceBlue == 0) + return 350; + else + return maxPriceBlue; + break; + } + case AHB_PURPLE: + { + if (maxPricePurple == 0) + return 450; + else + return maxPricePurple; + break; + } + case AHB_ORANGE: + { + if (maxPriceOrange == 0) + return 550; + else + return maxPriceOrange; + break; + } + case AHB_YELLOW: + { + if (maxPriceYellow == 0) + return 650; + else + return maxPriceYellow; + break; + } + default: + { + return 0; + break; + } + } + } + void SetMinBidPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: + minBidPriceGrey = value; + break; + case AHB_WHITE: + minBidPriceWhite = value; + break; + case AHB_GREEN: + minBidPriceGreen = value; + break; + case AHB_BLUE: + minBidPriceBlue = value; + break; + case AHB_PURPLE: + minBidPricePurple = value; + break; + case AHB_ORANGE: + minBidPriceOrange = value; + break; + case AHB_YELLOW: + minBidPriceYellow = value; + break; + default: + break; + } + } + uint32 GetMinBidPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: + { + if (minBidPriceGrey > 100) + return 100; + else + return minBidPriceGrey; + break; + } + case AHB_WHITE: + { + if (minBidPriceWhite > 100) + return 100; + else + return minBidPriceWhite; + break; + } + case AHB_GREEN: + { + if (minBidPriceGreen > 100) + return 100; + else + return minBidPriceGreen; + break; + } + case AHB_BLUE: + { + if (minBidPriceBlue > 100) + return 100; + else + return minBidPriceBlue; + break; + } + case AHB_PURPLE: + { + if (minBidPricePurple > 100) + return 100; + else + return minBidPricePurple; + break; + } + case AHB_ORANGE: + { + if (minBidPriceOrange > 100) + return 100; + else + return minBidPriceOrange; + break; + } + case AHB_YELLOW: + { + if (minBidPriceYellow > 100) + return 100; + else + return minBidPriceYellow; + break; + } + default: + { + return 0; + break; + } + } + } + void SetMaxBidPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: + maxBidPriceGrey = value; + break; + case AHB_WHITE: + maxBidPriceWhite = value; + break; + case AHB_GREEN: + maxBidPriceGreen = value; + break; + case AHB_BLUE: + maxBidPriceBlue = value; + break; + case AHB_PURPLE: + maxBidPricePurple = value; + break; + case AHB_ORANGE: + maxBidPriceOrange = value; + break; + case AHB_YELLOW: + maxBidPriceYellow = value; + break; + default: + break; + } + } + uint32 GetMaxBidPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: + { + if (maxBidPriceGrey > 100) + return 100; + else + return maxBidPriceGrey; + break; + } + case AHB_WHITE: + { + if (maxBidPriceWhite > 100) + return 100; + else + return maxBidPriceWhite; + break; + } + case AHB_GREEN: + { + if (maxBidPriceGreen > 100) + return 100; + else + return maxBidPriceGreen; + break; + } + case AHB_BLUE: + { + if (maxBidPriceBlue > 100) + return 100; + else + return maxBidPriceBlue; + break; + } + case AHB_PURPLE: + { + if (maxBidPricePurple > 100) + return 100; + else + return maxBidPricePurple; + break; + } + case AHB_ORANGE: + { + if (maxBidPriceOrange > 100) + return 100; + else + return maxBidPriceOrange; + break; + } + case AHB_YELLOW: + { + if (maxBidPriceYellow > 100) + return 100; + else + return maxBidPriceYellow; + break; + } + default: + { + return 0; + break; + } + } + } + void SetMaxStack(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: + maxStackGrey = value; + break; + case AHB_WHITE: + maxStackWhite = value; + break; + case AHB_GREEN: + maxStackGreen = value; + break; + case AHB_BLUE: + maxStackBlue = value; + break; + case AHB_PURPLE: + maxStackPurple = value; + break; + case AHB_ORANGE: + maxStackOrange = value; + break; + case AHB_YELLOW: + maxStackYellow = value; + break; + default: + break; + } + } + uint32 GetMaxStack(uint32 color) + { + switch(color) + { + case AHB_GREY: + { + return maxStackGrey; + break; + } + case AHB_WHITE: + { + return maxStackWhite; + break; + } + case AHB_GREEN: + { + return maxStackGreen; + break; + } + case AHB_BLUE: + { + return maxStackBlue; + break; + } + case AHB_PURPLE: + { + return maxStackPurple; + break; + } + case AHB_ORANGE: + { + return maxStackOrange; + break; + } + case AHB_YELLOW: + { + return maxStackYellow; + break; + } + default: + { + return 0; + break; + } + } + } + void SetBuyerPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: + buyerPriceGrey = value; + break; + case AHB_WHITE: + buyerPriceWhite = value; + break; + case AHB_GREEN: + buyerPriceGreen = value; + break; + case AHB_BLUE: + buyerPriceBlue = value; + break; + case AHB_PURPLE: + buyerPricePurple = value; + break; + case AHB_ORANGE: + buyerPriceOrange = value; + break; + case AHB_YELLOW: + buyerPriceYellow = value; + break; + default: + break; + } + } + uint32 GetBuyerPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: + return buyerPriceGrey; + break; + case AHB_WHITE: + return buyerPriceWhite; + break; + case AHB_GREEN: + return buyerPriceGreen; + break; + case AHB_BLUE: + return buyerPriceBlue; + break; + case AHB_PURPLE: + return buyerPricePurple; + break; + case AHB_ORANGE: + return buyerPriceOrange; + break; + case AHB_YELLOW: + return buyerPriceYellow; + break; + default: + return 0; + break; + } + } + void SetBiddingInterval(uint32 value) + { + buyerBiddingInterval = value; + } + uint32 GetBiddingInterval() + { + return buyerBiddingInterval; + } + void CalculatePercents() + { + greytgp = (uint32) (((double)percentGreyTradeGoods / 100.0) * maxItems); + whitetgp = (uint32) (((double)percentWhiteTradeGoods / 100.0) * maxItems); + greentgp = (uint32) (((double)percentGreenTradeGoods / 100.0) * maxItems); + bluetgp = (uint32) (((double)percentBlueTradeGoods / 100.0) * maxItems); + purpletgp = (uint32) (((double)percentPurpleTradeGoods / 100.0) * maxItems); + orangetgp = (uint32) (((double)percentOrangeTradeGoods / 100.0) * maxItems); + yellowtgp = (uint32) (((double)percentYellowTradeGoods / 100.0) * maxItems); + greyip = (uint32) (((double)percentGreyItems / 100.0) * maxItems); + whiteip = (uint32) (((double)percentWhiteItems / 100.0) * maxItems); + greenip = (uint32) (((double)percentGreenItems / 100.0) * maxItems); + blueip = (uint32) (((double)percentBlueItems / 100.0) * maxItems); + purpleip = (uint32) (((double)percentPurpleItems / 100.0) * maxItems); + orangeip = (uint32) (((double)percentOrangeItems / 100.0) * maxItems); + yellowip = (uint32) (((double)percentYellowItems / 100.0) * maxItems); + uint32 total = greytgp + whitetgp + greentgp + bluetgp + purpletgp + orangetgp + yellowtgp + greyip + whiteip + greenip + blueip + purpleip + orangeip + yellowip; + int32 diff = (maxItems - total); + if (diff < 0) + { + if ((whiteip - diff) > 0) + whiteip -= diff; + else if ((greenip - diff) > 0) + greenip -= diff; + } + else if (diff < 0) + { + whiteip += diff; + } + } + uint32 GetPercents(uint32 color) + { + switch(color) + { + case AHB_GREY_TG: + return greytgp; + break; + case AHB_WHITE_TG: + return whitetgp; + break; + case AHB_GREEN_TG: + return greentgp; + break; + case AHB_BLUE_TG: + return bluetgp; + break; + case AHB_PURPLE_TG: + return purpletgp; + break; + case AHB_ORANGE_TG: + return orangetgp; + break; + case AHB_YELLOW_TG: + return yellowtgp; + break; + case AHB_GREY_I: + return greyip; + break; + case AHB_WHITE_I: + return whiteip; + break; + case AHB_GREEN_I: + return greenip; + break; + case AHB_BLUE_I: + return blueip; + break; + case AHB_PURPLE_I: + return purpleip; + break; + case AHB_ORANGE_I: + return orangeip; + break; + case AHB_YELLOW_I: + return yellowip; + break; + default: + return 0; + break; + } + } + + void DecItemCounts(uint32 Class, uint32 Quality) + { + switch(Class) + { + case ITEM_CLASS_TRADE_GOODS: + DecItemCounts(Quality); + break; + default: + DecItemCounts(Quality + 7); + break; + } + } + + void DecItemCounts(uint32 color) + { + switch(color) + { + case AHB_GREY_TG: + --greyTGoods; + break; + case AHB_WHITE_TG: + --whiteTGoods; + break; + case AHB_GREEN_TG: + --greenTGoods; + break; + case AHB_BLUE_TG: + --blueTGoods; + break; + case AHB_PURPLE_TG: + --purpleTGoods; + break; + case AHB_ORANGE_TG: + --orangeTGoods; + break; + case AHB_YELLOW_TG: + --yellowTGoods; + break; + case AHB_GREY_I: + --greyItems; + break; + case AHB_WHITE_I: + --whiteItems; + break; + case AHB_GREEN_I: + --greenItems; + break; + case AHB_BLUE_I: + --blueItems; + break; + case AHB_PURPLE_I: + --purpleItems; + break; + case AHB_ORANGE_I: + --orangeItems; + break; + case AHB_YELLOW_I: + --yellowItems; + break; + default: + break; + } + } + + void IncItemCounts(uint32 Class, uint32 Quality) + { + switch(Class) + { + case ITEM_CLASS_TRADE_GOODS: + IncItemCounts(Quality); + break; + default: + IncItemCounts(Quality + 7); + break; + } + } + + void IncItemCounts(uint32 color) + { + switch(color) + { + case AHB_GREY_TG: + ++greyTGoods; + break; + case AHB_WHITE_TG: + ++whiteTGoods; + break; + case AHB_GREEN_TG: + ++greenTGoods; + break; + case AHB_BLUE_TG: + ++blueTGoods; + break; + case AHB_PURPLE_TG: + ++purpleTGoods; + break; + case AHB_ORANGE_TG: + ++orangeTGoods; + break; + case AHB_YELLOW_TG: + ++yellowTGoods; + break; + case AHB_GREY_I: + ++greyItems; + break; + case AHB_WHITE_I: + ++whiteItems; + break; + case AHB_GREEN_I: + ++greenItems; + break; + case AHB_BLUE_I: + ++blueItems; + break; + case AHB_PURPLE_I: + ++purpleItems; + break; + case AHB_ORANGE_I: + ++orangeItems; + break; + case AHB_YELLOW_I: + ++yellowItems; + break; + default: + break; + } + } + + void ResetItemCounts() + { + greyTGoods = 0; + whiteTGoods = 0; + greenTGoods = 0; + blueTGoods = 0; + purpleTGoods = 0; + orangeTGoods = 0; + yellowTGoods = 0; + + greyItems = 0; + whiteItems = 0; + greenItems = 0; + blueItems = 0; + purpleItems = 0; + orangeItems = 0; + yellowItems = 0; + } + + uint32 TotalItemCounts() + { + return( + greyTGoods + + whiteTGoods + + greenTGoods + + blueTGoods + + purpleTGoods + + orangeTGoods + + yellowTGoods + + + greyItems + + whiteItems + + greenItems + + blueItems + + purpleItems + + orangeItems + + yellowItems); + } + + uint32 GetItemCounts(uint32 color) + { + switch(color) + { + case AHB_GREY_TG: + return greyTGoods; + break; + case AHB_WHITE_TG: + return whiteTGoods; + break; + case AHB_GREEN_TG: + return greenTGoods; + break; + case AHB_BLUE_TG: + return blueTGoods; + break; + case AHB_PURPLE_TG: + return purpleTGoods; + break; + case AHB_ORANGE_TG: + return orangeTGoods; + break; + case AHB_YELLOW_TG: + return yellowTGoods; + break; + case AHB_GREY_I: + return greyItems; + break; + case AHB_WHITE_I: + return whiteItems; + break; + case AHB_GREEN_I: + return greenItems; + break; + case AHB_BLUE_I: + return blueItems; + break; + case AHB_PURPLE_I: + return purpleItems; + break; + case AHB_ORANGE_I: + return orangeItems; + break; + case AHB_YELLOW_I: + return yellowItems; + break; + default: + return 0; + break; + } + } + void SetBidsPerInterval(uint32 value) + { + buyerBidsPerInterval = value; + } + uint32 GetBidsPerInterval() + { + return buyerBidsPerInterval; + } + ~AHBConfig() + { + } +}; +class AuctionHouseBot +{ +private: + + bool debug_Out; + bool debug_Out_Filters; + + bool AHBSeller; + bool AHBBuyer; + bool BuyMethod; + bool SellMethod; + + uint32 AHBplayerAccount; + uint32 AHBplayerGUID; + uint32 ItemsPerCycle; + + //Begin Filters + + bool Vendor_Items; + bool Loot_Items; + bool Other_Items; + bool Vendor_TGs; + bool Loot_TGs; + bool Other_TGs; + + bool No_Bind; + bool Bind_When_Picked_Up; + bool Bind_When_Equipped; + bool Bind_When_Use; + bool Bind_Quest_Item; + + bool DisableBeta_PTR_Unused; + bool DisablePermEnchant; + bool DisableConjured; + bool DisableGems; + bool DisableMoney; + bool DisableMoneyLoot; + bool DisableLootable; + bool DisableKeys; + bool DisableDuration; + bool DisableBOP_Or_Quest_NoReqLevel; + + bool DisableWarriorItems; + bool DisablePaladinItems; + bool DisableHunterItems; + bool DisableRogueItems; + bool DisablePriestItems; + bool DisableDKItems; + bool DisableShamanItems; + bool DisableMageItems; + bool DisableWarlockItems; + bool DisableUnusedClassItems; + bool DisableDruidItems; + + uint32 DisableItemsBelowLevel; + uint32 DisableItemsAboveLevel; + uint32 DisableTGsBelowLevel; + uint32 DisableTGsAboveLevel; + uint32 DisableItemsBelowGUID; + uint32 DisableItemsAboveGUID; + uint32 DisableTGsBelowGUID; + uint32 DisableTGsAboveGUID; + uint32 DisableItemsBelowReqLevel; + uint32 DisableItemsAboveReqLevel; + uint32 DisableTGsBelowReqLevel; + uint32 DisableTGsAboveReqLevel; + uint32 DisableItemsBelowReqSkillRank; + uint32 DisableItemsAboveReqSkillRank; + uint32 DisableTGsBelowReqSkillRank; + uint32 DisableTGsAboveReqSkillRank; + + //End Filters + + AHBConfig AllianceConfig; + AHBConfig HordeConfig; + AHBConfig NeutralConfig; + + time_t _lastrun_a; + time_t _lastrun_h; + time_t _lastrun_n; + + inline uint32 minValue(uint32 a, uint32 b) { return a <= b ? a : b; }; + void addNewAuctions(Player *AHBplayer, AHBConfig *config); + void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, WorldSession *session); + +public: + AuctionHouseBot(); + ~AuctionHouseBot(); + void Update(); + void Initialize(); + void LoadValues(AHBConfig*); + void DecrementItemCounts(AuctionEntry* ah, uint32 item_template); + void IncrementItemCounts(AuctionEntry* ah); + void Commands(uint32, uint32, uint32, char*); + uint32 GetAHBplayerGUID() { return AHBplayerGUID; }; +}; + +#define auctionbot Trinity::Singleton::Instance() + +#endif diff --git a/src/server/game/AuctionHouse/AuctionHouseHandler.cpp b/src/server/game/AuctionHouse/AuctionHouseHandler.cpp deleted file mode 100644 index 8fec3b7df1d..00000000000 --- a/src/server/game/AuctionHouse/AuctionHouseHandler.cpp +++ /dev/null @@ -1,664 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ObjectMgr.h" -#include "Player.h" -#include "World.h" -#include "WorldPacket.h" -#include "WorldSession.h" - -#include "AuctionHouseBot.h" -#include "AuctionHouseMgr.h" -#include "Log.h" -#include "Opcodes.h" -#include "UpdateMask.h" -#include "Util.h" - -//please DO NOT use iterator++, because it is slower than ++iterator!!! -//post-incrementation is always slower than pre-incrementation ! - -//void called when player click on auctioneer npc -void WorldSession::HandleAuctionHelloOpcode(WorldPacket & recv_data) -{ - uint64 guid; //NPC guid - recv_data >> guid; - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_AUCTIONEER); - if (!unit) - { - sLog.outDebug("WORLD: HandleAuctionHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - SendAuctionHello(guid, unit); -} - -//this void causes that auction window is opened -void WorldSession::SendAuctionHello(uint64 guid, Creature* unit) -{ - if (GetPlayer()->getLevel() < sWorld.getConfig(CONFIG_AUCTION_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_AUCTION_REQ), sWorld.getConfig(CONFIG_AUCTION_LEVEL_REQ)); - return; - } - - AuctionHouseEntry const* ahEntry = AuctionHouseMgr::GetAuctionHouseEntry(unit->getFaction()); - if (!ahEntry) - return; - - WorldPacket data(MSG_AUCTION_HELLO, 12); - data << uint64(guid); - data << uint32(ahEntry->houseId); - data << uint8(1); // 3.3.3: 1 - AH enabled, 0 - AH disabled - SendPacket(&data); -} - -//call this method when player bids, creates, or deletes auction -void WorldSession::SendAuctionCommandResult(uint32 auctionId, uint32 Action, uint32 ErrorCode, uint32 bidError) -{ - WorldPacket data(SMSG_AUCTION_COMMAND_RESULT, 16); - data << auctionId; - data << Action; - data << ErrorCode; - if (!ErrorCode && Action) - data << bidError; //when bid, then send 0, once... - SendPacket(&data); -} - -//this function sends notification, if bidder is online -void WorldSession::SendAuctionBidderNotification(uint32 location, uint32 auctionId, uint64 bidder, uint32 bidSum, uint32 diff, uint32 item_template) -{ - WorldPacket data(SMSG_AUCTION_BIDDER_NOTIFICATION, (8*4)); - data << uint32(location); - data << uint32(auctionId); - data << uint64(bidder); - data << uint32(bidSum); - data << uint32(diff); - data << uint32(item_template); - data << uint32(0); - SendPacket(&data); -} - -//this void causes on client to display: "Your auction sold" -void WorldSession::SendAuctionOwnerNotification(AuctionEntry* auction) -{ - WorldPacket data(SMSG_AUCTION_OWNER_NOTIFICATION, (7*4)); - data << auction->Id; - data << auction->bid; - data << (uint32) 0; //unk - data << (uint32) 0; //unk - data << (uint32) 0; //unk - data << auction->item_template; - data << (uint32) 0; //unk - SendPacket(&data); -} - -//this function sends mail to old bidder -void WorldSession::SendAuctionOutbiddedMail(AuctionEntry *auction, uint32 newPrice) -{ - uint64 oldBidder_guid = MAKE_NEW_GUID(auction->bidder,0, HIGHGUID_PLAYER); - Player *oldBidder = objmgr.GetPlayer(oldBidder_guid); - - uint32 oldBidder_accId = 0; - if (!oldBidder) - oldBidder_accId = objmgr.GetPlayerAccountIdByGUID(oldBidder_guid); - - // old bidder exist - if (oldBidder || oldBidder_accId) - { - std::ostringstream msgAuctionOutbiddedSubject; - msgAuctionOutbiddedSubject << auction->item_template << ":0:" << AUCTION_OUTBIDDED << ":0:0"; - - if (oldBidder && !_player) - oldBidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, auctionbot.GetAHBplayerGUID(), newPrice, auction->GetAuctionOutBid(), auction->item_template); - - if (oldBidder && _player) - oldBidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, _player->GetGUID(), newPrice, auction->GetAuctionOutBid(), auction->item_template); - - MailDraft(msgAuctionOutbiddedSubject.str(), "") // TODO: fix body - .AddMoney(auction->bid) - .SendMailTo(MailReceiver(oldBidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED); - } -} - -//this function sends mail, when auction is cancelled to old bidder -void WorldSession::SendAuctionCancelledToBidderMail(AuctionEntry* auction) -{ - uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER); - Player *bidder = objmgr.GetPlayer(bidder_guid); - - uint32 bidder_accId = 0; - if (!bidder) - bidder_accId = objmgr.GetPlayerAccountIdByGUID(bidder_guid); - - // bidder exist - if (bidder || bidder_accId) - { - std::ostringstream msgAuctionCancelledSubject; - msgAuctionCancelledSubject << auction->item_template << ":0:" << AUCTION_CANCELLED_TO_BIDDER << ":0:0"; - - MailDraft(msgAuctionCancelledSubject.str(), "") // TODO: fix body - .AddMoney(auction->bid) - .SendMailTo(MailReceiver(bidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED); - } -} - -//this void creates new auction and adds auction to some auctionhouse -void WorldSession::HandleAuctionSellItem(WorldPacket & recv_data) -{ - uint64 auctioneer, item; - uint32 etime, bid, buyout; - recv_data >> auctioneer; - recv_data.read_skip(); // const 1? - recv_data >> item; - recv_data.read_skip(); // unk 3.2.2, const 1? - recv_data >> bid; - recv_data >> buyout; - recv_data >> etime; - - Player *pl = GetPlayer(); - - if (!item || !bid || !etime) - return; //check for cheaters - - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer,UNIT_NPC_FLAG_AUCTIONEER); - if (!pCreature) - { - sLog.outDebug("WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); - return; - } - - AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(pCreature->getFaction()); - if (!auctionHouseEntry) - { - sLog.outDebug("WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction.", uint32(GUID_LOPART(auctioneer))); - return; - } - - sLog.outDebug("WORLD: HandleAuctionSellItem - ETIME: %u", etime); - - // client send time in minutes, convert to common used sec time - etime *= MINUTE; - - sLog.outDebug("WORLD: HandleAuctionSellItem - ETIME: %u", etime); - - // client understand only 3 auction time - switch(etime) - { - case 1*MIN_AUCTION_TIME: - case 2*MIN_AUCTION_TIME: - case 4*MIN_AUCTION_TIME: - break; - default: - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - Item *it = pl->GetItemByGuid(item); - //do not allow to sell already auctioned items - if (auctionmgr.GetAItem(GUID_LOPART(item))) - { - sLog.outError("AuctionError, player %s is sending item id: %u, but item is already in another auction", pl->GetName(), GUID_LOPART(item)); - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); - return; - } - // prevent sending bag with items (cheat: can be placed in bag after adding equiped empty bag to auction) - if (!it) - { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_ITEM_NOT_FOUND); - return; - } - - if (!it->CanBeTraded()) - { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); - return; - } - - if (it->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || it->GetUInt32Value(ITEM_FIELD_DURATION)) - { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); - return; - } - - AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(pCreature->getFaction()); - - //we have to take deposit : - uint32 deposit = auctionmgr.GetAuctionDeposit(auctionHouseEntry, etime, it); - if (pl->GetMoney() < deposit) - { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_NOT_ENOUGHT_MONEY); - return; - } - - if (GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) - { - sLog.outCommand(GetAccountId(),"GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", - GetPlayerName(),GetAccountId(),it->GetProto()->Name1,it->GetEntry(),it->GetCount()); - } - - pl->ModifyMoney(-int32(deposit)); - - uint32 auction_time = uint32(etime * sWorld.getRate(RATE_AUCTION_TIME)); - - AuctionEntry *AH = new AuctionEntry; - AH->Id = objmgr.GenerateAuctionID(); - if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) - AH->auctioneer = 23442; - else - AH->auctioneer = GUID_LOPART(auctioneer); - AH->item_guidlow = GUID_LOPART(item); - AH->item_template = it->GetEntry(); - AH->owner = pl->GetGUIDLow(); - AH->startbid = bid; - AH->bidder = 0; - AH->bid = 0; - AH->buyout = buyout; - AH->expire_time = time(NULL) + auction_time; - AH->deposit = deposit; - AH->auctionHouseEntry = auctionHouseEntry; - - sLog.outDetail("selling item %u to auctioneer %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", GUID_LOPART(item), AH->auctioneer, bid, buyout, auction_time, AH->GetHouseId()); - auctionmgr.AddAItem(it); - auctionHouse->AddAuction(AH); - - pl->MoveItemFromInventory(it->GetBagSlot(), it->GetSlot(), true); - - CharacterDatabase.BeginTransaction(); - it->DeleteFromInventoryDB(); - it->SaveToDB(); // recursive and not have transaction guard into self, not in inventiory and can be save standalone - AH->SaveToDB(); - pl->SaveInventoryAndGoldToDB(); - CharacterDatabase.CommitTransaction(); - - SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); - - GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); -} - -//this function is called when client bids or buys out auction -void WorldSession::HandleAuctionPlaceBid(WorldPacket & recv_data) -{ - uint64 auctioneer; - uint32 auctionId; - uint32 price; - recv_data >> auctioneer; - recv_data >> auctionId >> price; - - if (!auctionId || !price) - return; //check for cheaters - - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); - if (!pCreature) - { - sLog.outDebug("WORLD: HandleAuctionPlaceBid - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - AuctionHouseObject *auctionHouse = auctionmgr.GetAuctionsMap(pCreature->getFaction()); - - AuctionEntry *auction = auctionHouse->GetAuction(auctionId); - Player *pl = GetPlayer(); - - if (!auction || auction->owner == pl->GetGUIDLow()) - { - //you cannot bid your own auction: - SendAuctionCommandResult(0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR); - return; - } - - // impossible have online own another character (use this for speedup check in case online owner) - Player* auction_owner = objmgr.GetPlayer(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)); - if (!auction_owner && objmgr.GetPlayerAccountIdByGUID(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)) == pl->GetSession()->GetAccountId()) - { - //you cannot bid your another character auction: - SendAuctionCommandResult(0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR); - return; - } - - // cheating - if (price <= auction->bid || price < auction->startbid) - return; - - // price too low for next bid if not buyout - if ((price < auction->buyout || auction->buyout == 0) && - price < auction->bid + auction->GetAuctionOutBid()) - { - //auction has already higher bid, client tests it! - return; - } - - if (price > pl->GetMoney()) - { - //you don't have enought money!, client tests! - //SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???); - return; - } - - if (price < auction->buyout || auction->buyout == 0) - { - if (auction->bidder > 0) - { - if (auction->bidder == pl->GetGUIDLow()) - pl->ModifyMoney(-int32(price - auction->bid)); - else - { - // mail to last bidder and return money - SendAuctionOutbiddedMail(auction, price); - pl->ModifyMoney(-int32(price)); - } - } - else - pl->ModifyMoney(-int32(price)); - - auction->bidder = pl->GetGUIDLow(); - auction->bid = price; - GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, price); - - // after this update we should save player's money ... - CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("UPDATE auctionhouse SET buyguid = '%u',lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id); - - SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK, 0); - } - else - { - //buyout: - if (pl->GetGUIDLow() == auction->bidder) - pl->ModifyMoney(-int32(auction->buyout - auction->bid)); - else - { - pl->ModifyMoney(-int32(auction->buyout)); - if (auction->bidder) //buyout for bidded auction .. - SendAuctionOutbiddedMail(auction, auction->buyout); - } - auction->bidder = pl->GetGUIDLow(); - auction->bid = auction->buyout; - GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout); - - auctionmgr.SendAuctionSalePendingMail(auction); - auctionmgr.SendAuctionSuccessfulMail(auction); - auctionmgr.SendAuctionWonMail(auction); - - SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK); - - CharacterDatabase.BeginTransaction(); - auction->DeleteFromDB(); - uint32 item_template = auction->item_template; - auctionmgr.RemoveAItem(auction->item_guidlow); - auctionHouse->RemoveAuction(auction, item_template); - } - pl->SaveInventoryAndGoldToDB(); - CharacterDatabase.CommitTransaction(); -} - -//this void is called when auction_owner cancels his auction -void WorldSession::HandleAuctionRemoveItem(WorldPacket & recv_data) -{ - uint64 auctioneer; - uint32 auctionId; - recv_data >> auctioneer; - recv_data >> auctionId; - //sLog.outDebug("Cancel AUCTION AuctionID: %u", auctionId); - - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer,UNIT_NPC_FLAG_AUCTIONEER); - if (!pCreature) - { - sLog.outDebug("WORLD: HandleAuctionRemoveItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(pCreature->getFaction()); - - AuctionEntry *auction = auctionHouse->GetAuction(auctionId); - Player *pl = GetPlayer(); - - if (auction && auction->owner == pl->GetGUIDLow()) - { - Item *pItem = auctionmgr.GetAItem(auction->item_guidlow); - if (pItem) - { - if (auction->bidder > 0) // If we have a bidder, we have to send him the money he paid - { - uint32 auctionCut = auction->GetAuctionCut(); - if (pl->GetMoney() < auctionCut) //player doesn't have enough money, maybe message needed - return; - //some auctionBidderNotification would be needed, but don't know that parts.. - SendAuctionCancelledToBidderMail(auction); - pl->ModifyMoney(-int32(auctionCut)); - } - // Return the item by mail - std::ostringstream msgAuctionCanceledOwner; - msgAuctionCanceledOwner << auction->item_template << ":0:" << AUCTION_CANCELED << ":0:0"; - - // item will deleted or added to received mail list - MailDraft(msgAuctionCanceledOwner.str(), "") // TODO: fix body - .AddItem(pItem) - .SendMailTo(pl, auction, MAIL_CHECK_MASK_COPIED); - } - else - { - sLog.outError("Auction id: %u has non-existed item (item guid : %u)!!!", auction->Id, auction->item_guidlow); - SendAuctionCommandResult(0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR); - return; - } - } - else - { - SendAuctionCommandResult(0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR); - //this code isn't possible ... maybe there should be assert - sLog.outError("CHEATER : %u, he tried to cancel auction (id: %u) of another player, or auction is NULL", pl->GetGUIDLow(), auctionId); - return; - } - - //inform player, that auction is removed - SendAuctionCommandResult(auction->Id, AUCTION_CANCEL, AUCTION_OK); - - // Now remove the auction - CharacterDatabase.BeginTransaction(); - pl->SaveInventoryAndGoldToDB(); - auction->DeleteFromDB(); - uint32 item_template = auction->item_template; - auctionmgr.RemoveAItem(auction->item_guidlow); - auctionHouse->RemoveAuction(auction, item_template); - CharacterDatabase.CommitTransaction(); -} - -//called when player lists his bids -void WorldSession::HandleAuctionListBidderItems(WorldPacket & recv_data) -{ - uint64 guid; //NPC guid - uint32 listfrom; //page of auctions - uint32 outbiddedCount; //count of outbidded auctions - - recv_data >> guid; - recv_data >> listfrom; // not used in fact (this list not have page control in client) - recv_data >> outbiddedCount; - if (recv_data.size() != (16 + outbiddedCount * 4)) - { - sLog.outError("Client sent bad opcode!!! with count: %u and size : %lu (must be: %u)", outbiddedCount, (unsigned long)recv_data.size(),(16 + outbiddedCount * 4)); - outbiddedCount = 0; - } - - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_AUCTIONEER); - if (!pCreature) - { - sLog.outDebug("WORLD: HandleAuctionListBidderItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(pCreature->getFaction()); - - WorldPacket data(SMSG_AUCTION_BIDDER_LIST_RESULT, (4+4+4)); - Player *pl = GetPlayer(); - data << (uint32) 0; //add 0 as count - uint32 count = 0; - uint32 totalcount = 0; - while (outbiddedCount > 0) //add all data, which client requires - { - --outbiddedCount; - uint32 outbiddedAuctionId; - recv_data >> outbiddedAuctionId; - AuctionEntry * auction = auctionHouse->GetAuction(outbiddedAuctionId); - if (auction && auction->BuildAuctionInfo(data)) - { - ++totalcount; - ++count; - } - } - - auctionHouse->BuildListBidderItems(data,pl,count,totalcount); - data.put(0, count); // add count to placeholder - data << totalcount; - data << (uint32)300; //unk 2.3.0 - SendPacket(&data); -} - -//this void sends player info about his auctions -void WorldSession::HandleAuctionListOwnerItems(WorldPacket & recv_data) -{ - uint32 listfrom; - uint64 guid; - - recv_data >> guid; - recv_data >> listfrom; // not used in fact (this list not have page control in client) - - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_AUCTIONEER); - if (!pCreature) - { - sLog.outDebug("WORLD: HandleAuctionListOwnerItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(pCreature->getFaction()); - - WorldPacket data(SMSG_AUCTION_OWNER_LIST_RESULT, (4+4+4)); - data << (uint32) 0; // amount place holder - - uint32 count = 0; - uint32 totalcount = 0; - - auctionHouse->BuildListOwnerItems(data,_player,count,totalcount); - data.put(0, count); - data << (uint32) totalcount; - data << (uint32) 0; - SendPacket(&data); -} - -//this void is called when player clicks on search button -void WorldSession::HandleAuctionListItems(WorldPacket & recv_data) -{ - std::string searchedname; - uint8 levelmin, levelmax, usable; - uint32 listfrom, auctionSlotID, auctionMainCategory, auctionSubCategory, quality; - uint64 guid; - - recv_data >> guid; - recv_data >> listfrom; // start, used for page control listing by 50 elements - recv_data >> searchedname; - - recv_data >> levelmin >> levelmax; - recv_data >> auctionSlotID >> auctionMainCategory >> auctionSubCategory; - recv_data >> quality >> usable; - - recv_data.read_skip(16); // unknown 16 bytes: 00 07 01 00 00 01 05 00 06 00 09 01 08 00 03 00 - - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_AUCTIONEER); - if (!pCreature) - { - sLog.outDebug("WORLD: HandleAuctionListItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(pCreature->getFaction()); - - //sLog.outDebug("Auctionhouse search (GUID: %u TypeId: %u)", , list from: %u, searchedname: %s, levelmin: %u, levelmax: %u, auctionSlotID: %u, auctionMainCategory: %u, auctionSubCategory: %u, quality: %u, usable: %u", - // GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(guid)), listfrom, searchedname.c_str(), levelmin, levelmax, auctionSlotID, auctionMainCategory, auctionSubCategory, quality, usable); - - WorldPacket data(SMSG_AUCTION_LIST_RESULT, (4+4+4)); - uint32 count = 0; - uint32 totalcount = 0; - data << (uint32) 0; - - // converting string that we try to find to lower case - std::wstring wsearchedname; - if (!Utf8toWStr(searchedname,wsearchedname)) - return; - - wstrToLower(wsearchedname); - - auctionHouse->BuildListAuctionItems(data,_player, - wsearchedname, listfrom, levelmin, levelmax, usable, - auctionSlotID, auctionMainCategory, auctionSubCategory, quality, - count,totalcount); - - data.put(0, count); - data << (uint32) totalcount; - data << (uint32) 300; // unk 2.3.0 const? - SendPacket(&data); -} - -void WorldSession::HandleAuctionListPendingSales(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_AUCTION_LIST_PENDING_SALES"); - - recv_data.read_skip(); - - uint32 count = 0; - - WorldPacket data(SMSG_AUCTION_LIST_PENDING_SALES, 4); - data << uint32(count); // count - /*for (uint32 i = 0; i < count; ++i) - { - data << ""; // string - data << ""; // string - data << uint32(0); - data << uint32(0); - data << float(0); - }*/ - SendPacket(&data); -} diff --git a/src/server/game/BattleGrounds/ArenaTeamHandler.cpp b/src/server/game/BattleGrounds/ArenaTeamHandler.cpp deleted file mode 100644 index 3a9a14524f9..00000000000 --- a/src/server/game/BattleGrounds/ArenaTeamHandler.cpp +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Player.h" -#include "World.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Database/DatabaseEnv.h" - -#include "ArenaTeam.h" -#include "Log.h" -#include "ObjectMgr.h" -#include "SocialMgr.h" - -void WorldSession::HandleInspectArenaTeamsOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("MSG_INSPECT_ARENA_TEAMS"); - - uint64 guid; - recv_data >> guid; - sLog.outDebug("Inspect Arena stats (GUID: %u TypeId: %u)", GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(guid))); - - if (Player *plr = objmgr.GetPlayer(guid)) - { - for (uint8 i = 0; i < MAX_ARENA_SLOT; ++i) - { - if (uint32 a_id = plr->GetArenaTeamId(i)) - { - if (ArenaTeam *at = objmgr.GetArenaTeamById(a_id)) - at->InspectStats(this, plr->GetGUID()); - } - } - } -} - -void WorldSession::HandleArenaTeamQueryOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_ARENA_TEAM_QUERY"); - - uint32 ArenaTeamId; - recv_data >> ArenaTeamId; - - if (ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId)) - { - arenateam->Query(this); - arenateam->Stats(this); - } -} - -void WorldSession::HandleArenaTeamRosterOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_ARENA_TEAM_ROSTER"); - - uint32 ArenaTeamId; // arena team id - recv_data >> ArenaTeamId; - - if (ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId)) - arenateam->Roster(this); -} - -void WorldSession::HandleArenaTeamInviteOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_ARENA_TEAM_INVITE"); - - uint32 ArenaTeamId; // arena team id - std::string Invitedname; - - Player * player = NULL; - - recv_data >> ArenaTeamId >> Invitedname; - - if (!Invitedname.empty()) - { - if (!normalizePlayerName(Invitedname)) - return; - - player = ObjectAccessor::Instance().FindPlayerByName(Invitedname.c_str()); - } - - if (!player) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", Invitedname, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S); - return; - } - - if (player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", player->GetName(), ERR_ARENA_TEAM_TARGET_TOO_LOW_S); - return; - } - - ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId); - if (!arenateam) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM); - return; - } - - // OK result but not send invite - if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) - return; - - if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeam() != GetPlayer()->GetTeam()) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); - return; - } - - if (player->GetArenaTeamId(arenateam->GetSlot())) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", player->GetName(), ERR_ALREADY_IN_ARENA_TEAM_S); - return; - } - - if (player->GetArenaTeamIdInvited()) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S); - return; - } - - if (arenateam->GetMembersSize() >= arenateam->GetType() * 2) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, arenateam->GetName(), "", ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S); - return; - } - - sLog.outDebug("Player %s Invited %s to Join his ArenaTeam", GetPlayer()->GetName(), Invitedname.c_str()); - - player->SetArenaTeamIdInvited(arenateam->GetId()); - - WorldPacket data(SMSG_ARENA_TEAM_INVITE, (8+10)); - data << GetPlayer()->GetName(); - data << arenateam->GetName(); - player->GetSession()->SendPacket(&data); - - sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_INVITE"); -} - -void WorldSession::HandleArenaTeamAcceptOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("CMSG_ARENA_TEAM_ACCEPT"); // empty opcode - - ArenaTeam *at = objmgr.GetArenaTeamById(_player->GetArenaTeamIdInvited()); - if (!at) - return; - - if (_player->GetArenaTeamId(at->GetSlot())) - { - // already in arena team that size - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ALREADY_IN_ARENA_TEAM); - return; - } - - if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && _player->GetTeam() != objmgr.GetPlayerTeamByGUID(at->GetCaptain())) - { - // not let enemies sign petition - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_NOT_ALLIED); - return; - } - - if (!at->AddMember(_player->GetGUID())) - { - // arena team not found - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S,"","",ERR_ARENA_TEAM_INTERNAL); - return; - } - - // event - at->BroadcastEvent(ERR_ARENA_TEAM_JOIN_SS, _player->GetGUID(), 2, _player->GetName(), at->GetName(), ""); -} - -void WorldSession::HandleArenaTeamDeclineOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("CMSG_ARENA_TEAM_DECLINE"); // empty opcode - - _player->SetArenaTeamIdInvited(0); // no more invited -} - -void WorldSession::HandleArenaTeamLeaveOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_ARENA_TEAM_LEAVE"); - - uint32 ArenaTeamId; // arena team id - recv_data >> ArenaTeamId; - - ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId); - if (!at) - return; - - if (_player->GetGUID() == at->GetCaptain() && at->GetMembersSize() > 1) - { - // check for correctness - SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S); - return; - } - - // arena team has only one member (=captain) - if (_player->GetGUID() == at->GetCaptain()) - { - at->Disband(this); - delete at; - return; - } - - at->DelMember(_player->GetGUID()); - - // event - at->BroadcastEvent(ERR_ARENA_TEAM_LEAVE_SS, _player->GetGUID(), 2, _player->GetName(), at->GetName(), ""); - - // send you are no longer member of team - SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, at->GetName(), "", 0); -} - -void WorldSession::HandleArenaTeamDisbandOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_ARENA_TEAM_DISBAND"); - - uint32 ArenaTeamId; // arena team id - recv_data >> ArenaTeamId; - - if (ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId)) - { - if (at->GetCaptain() != _player->GetGUID()) - return; - - if (at->IsFighting()) - return; - - at->Disband(this); - delete at; - } -} - -void WorldSession::HandleArenaTeamRemoveOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_ARENA_TEAM_REMOVE"); - - uint32 ArenaTeamId; - std::string name; - - recv_data >> ArenaTeamId; - recv_data >> name; - - ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId); - if (!at) // arena team not found - return; - - if (at->GetCaptain() != _player->GetGUID()) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS); - return; - } - - if (!normalizePlayerName(name)) - return; - - ArenaTeamMember* member = at->GetMember(name); - if (!member) // member not found - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", name, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S); - return; - } - - if (at->GetCaptain() == member->guid) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S); - return; - } - - at->DelMember(member->guid); - - // event - at->BroadcastEvent(ERR_ARENA_TEAM_REMOVE_SSS, 0, 3, name, at->GetName(), _player->GetName()); -} - -void WorldSession::HandleArenaTeamLeaderOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_ARENA_TEAM_LEADER"); - - uint32 ArenaTeamId; - std::string name; - - recv_data >> ArenaTeamId; - recv_data >> name; - - ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId); - if (!at) // arena team not found - return; - - if (at->GetCaptain() != _player->GetGUID()) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS); - return; - } - - if (!normalizePlayerName(name)) - return; - - ArenaTeamMember* member = at->GetMember(name); - if (!member) // member not found - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", name, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S); - return; - } - - if (at->GetCaptain() == member->guid) // target player already captain - return; - - at->SetCaptain(member->guid); - - // event - at->BroadcastEvent(ERR_ARENA_TEAM_LEADER_CHANGED_SSS, 0, 3, _player->GetName(), name, at->GetName()); -} - -void WorldSession::SendArenaTeamCommandResult(uint32 team_action, const std::string& team, const std::string& player, uint32 error_id) -{ - WorldPacket data(SMSG_ARENA_TEAM_COMMAND_RESULT, 4+team.length()+1+player.length()+1+4); - data << uint32(team_action); - data << team; - data << player; - data << uint32(error_id); - SendPacket(&data); -} - -void WorldSession::SendNotInArenaTeamPacket(uint8 type) -{ - WorldPacket data(SMSG_ARENA_ERROR, 4+1); // 886 - You are not in a %uv%u arena team - uint32 unk = 0; - data << uint32(unk); // unk(0) - if (!unk) - data << uint8(type); // team type (2=2v2,3=3v3,5=5v5), can be used for custom types... - SendPacket(&data); -} - -/* -+ERR_ARENA_NO_TEAM_II "You are not in a %dv%d arena team" - -+ERR_ARENA_TEAM_CREATE_S "%s created. To disband, use /teamdisband [2v2, 3v3, 5v5]." -+ERR_ARENA_TEAM_INVITE_SS "You have invited %s to join %s" -+ERR_ARENA_TEAM_QUIT_S "You are no longer a member of %s" -ERR_ARENA_TEAM_FOUNDER_S "Congratulations, you are a founding member of %s! To leave, use /teamquit [2v2, 3v3, 5v5]." - -+ERR_ARENA_TEAM_INTERNAL "Internal arena team error" -+ERR_ALREADY_IN_ARENA_TEAM "You are already in an arena team of that size" -+ERR_ALREADY_IN_ARENA_TEAM_S "%s is already in an arena team of that size" -+ERR_INVITED_TO_ARENA_TEAM "You have already been invited into an arena team" -+ERR_ALREADY_INVITED_TO_ARENA_TEAM_S "%s has already been invited to an arena team" -+ERR_ARENA_TEAM_NAME_INVALID "That name contains invalid characters, please enter a new name" -+ERR_ARENA_TEAM_NAME_EXISTS_S "There is already an arena team named \"%s\"" -+ERR_ARENA_TEAM_LEADER_LEAVE_S "You must promote a new team captain using /teamcaptain before leaving the team" -+ERR_ARENA_TEAM_PERMISSIONS "You don't have permission to do that" -+ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM "You are not in an arena team of that size" -+ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM_SS "%s is not in %s" -+ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S "\"%s\" not found" -+ERR_ARENA_TEAM_NOT_ALLIED "You cannot invite players from the opposing alliance" - -+ERR_ARENA_TEAM_JOIN_SS "%s has joined %s" -+ERR_ARENA_TEAM_YOU_JOIN_S "You have joined %s. To leave, use /teamquit [2v2, 3v3, 5v5]." - -+ERR_ARENA_TEAM_LEAVE_SS "%s has left %s" - -+ERR_ARENA_TEAM_LEADER_IS_SS "%s is the captain of %s" -+ERR_ARENA_TEAM_LEADER_CHANGED_SSS "%s has made %s the new captain of %s" - -+ERR_ARENA_TEAM_REMOVE_SSS "%s has been kicked out of %s by %s" - -+ERR_ARENA_TEAM_DISBANDED_S "%s has disbanded %s" - -ERR_ARENA_TEAM_TARGET_TOO_LOW_S "%s is not high enough level to join your team" - -ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S "%s is full" - -ERR_ARENA_TEAM_LEVEL_TOO_LOW_I "You must be level %d to form an arena team" -*/ diff --git a/src/server/game/BattleGrounds/BattleGroundAA.cpp b/src/server/game/BattleGrounds/BattleGroundAA.cpp deleted file mode 100644 index 56cf3ebed15..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundAA.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "BattleGround.h" -#include "BattleGroundAA.h" -#include "Language.h" -#include "Player.h" - -BattleGroundAA::BattleGroundAA() -{ - - m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; - m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; - m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; - m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; - //we must set messageIds - m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; - m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; - m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; -} - -BattleGroundAA::~BattleGroundAA() -{ - -} - -void BattleGroundAA::Update(uint32 diff) -{ - BattleGround::Update(diff); -} - -void BattleGroundAA::StartingEventCloseDoors() -{ -} - -void BattleGroundAA::StartingEventOpenDoors() -{ -} - -void BattleGroundAA::AddPlayer(Player *plr) -{ - BattleGround::AddPlayer(plr); - //create score and add it to map, default values are set in constructor - BattleGroundAAScore* sc = new BattleGroundAAScore; - - m_PlayerScores[plr->GetGUID()] = sc; -} - -void BattleGroundAA::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) -{ -} - -void BattleGroundAA::HandleKillPlayer(Player* player, Player* killer) -{ - BattleGround::HandleKillPlayer(player, killer); -} - -void BattleGroundAA::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/) -{ -} - -bool BattleGroundAA::SetupBattleGround() -{ - return true; -} - diff --git a/src/server/game/BattleGrounds/BattleGroundAA.h b/src/server/game/BattleGrounds/BattleGroundAA.h deleted file mode 100644 index a13833697cf..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundAA.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __BATTLEGROUNDAA_H -#define __BATTLEGROUNDAA_H - -class BattleGround; - -class BattleGroundAAScore : public BattleGroundScore -{ - public: - BattleGroundAAScore() {}; - virtual ~BattleGroundAAScore() {}; - //TODO fix me -}; - -class BattleGroundAA : public BattleGround -{ - friend class BattleGroundMgr; - - public: - BattleGroundAA(); - ~BattleGroundAA(); - void Update(uint32 diff); - - /* inherited from BattlegroundClass */ - virtual void AddPlayer(Player *plr); - virtual void StartingEventCloseDoors(); - virtual void StartingEventOpenDoors(); - - void RemovePlayer(Player *plr, uint64 guid); - void HandleAreaTrigger(Player *Source, uint32 Trigger); - bool SetupBattleGround(); - void HandleKillPlayer(Player* player, Player *killer); -}; -#endif - diff --git a/src/server/game/BattleGrounds/BattleGroundAB.cpp b/src/server/game/BattleGrounds/BattleGroundAB.cpp deleted file mode 100644 index 38671e85597..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundAB.cpp +++ /dev/null @@ -1,715 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "World.h" -#include "WorldPacket.h" -#include "ObjectMgr.h" -#include "BattleGroundMgr.h" -#include "BattleGround.h" -#include "BattleGroundAB.h" -#include "Creature.h" -#include "Language.h" -#include "Object.h" -#include "Player.h" -#include "Util.h" - -// these variables aren't used outside of this file, so declare them only here -uint32 BG_AB_HonorScoreTicks[BG_HONOR_MODE_NUM] = { - 330, // normal honor - 200 // holiday -}; - -uint32 BG_AB_ReputationScoreTicks[BG_HONOR_MODE_NUM] = { - 200, // normal honor - 150 // holiday -}; - -BattleGroundAB::BattleGroundAB() -{ - m_BuffChange = true; - m_BgObjects.resize(BG_AB_OBJECT_MAX); - m_BgCreatures.resize(BG_AB_ALL_NODES_COUNT + 5);//+5 for aura triggers - - m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_AB_START_TWO_MINUTES; - m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AB_START_ONE_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AB_START_HALF_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AB_HAS_BEGUN; -} - -BattleGroundAB::~BattleGroundAB() -{ -} - -void BattleGroundAB::Update(uint32 diff) -{ - BattleGround::Update(diff); - - if (GetStatus() == STATUS_IN_PROGRESS) - { - int team_points[BG_TEAMS_COUNT] = { 0, 0 }; - - for (int node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node) - { - // 3 sec delay to spawn new banner instead previous despawned one - if (m_BannerTimers[node].timer) - { - if (m_BannerTimers[node].timer > diff) - m_BannerTimers[node].timer -= diff; - else - { - m_BannerTimers[node].timer = 0; - _CreateBanner(node, m_BannerTimers[node].type, m_BannerTimers[node].teamIndex, false); - } - } - - // 1-minute to occupy a node from contested state - if (m_NodeTimers[node]) - { - if (m_NodeTimers[node] > diff) - m_NodeTimers[node] -= diff; - else - { - m_NodeTimers[node] = 0; - // Change from contested to occupied ! - uint8 teamIndex = m_Nodes[node]-1; - m_prevNodes[node] = m_Nodes[node]; - m_Nodes[node] += 2; - // burn current contested banner - _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex); - // create new occupied banner - _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true); - _SendNodeUpdate(node); - _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE); - // Message to chatlog - - if (teamIndex == 0) - { - // FIXME: team and node names not localized - SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE,NULL,LANG_BG_AB_ALLY,_GetNodeNameId(node)); - PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE); - } - else - { - // FIXME: team and node names not localized - SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE,NULL,LANG_BG_AB_HORDE,_GetNodeNameId(node)); - PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE); - } - } - } - - for (int team = 0; team < BG_TEAMS_COUNT; ++team) - if (m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED) - ++team_points[team]; - } - - // Accumulate points - for (int team = 0; team < BG_TEAMS_COUNT; ++team) - { - int points = team_points[team]; - if (!points) - continue; - m_lastTick[team] += diff; - if (m_lastTick[team] > BG_AB_TickIntervals[points]) - { - m_lastTick[team] -= BG_AB_TickIntervals[points]; - m_TeamScores[team] += BG_AB_TickPoints[points]; - m_HonorScoreTics[team] += BG_AB_TickPoints[points]; - m_ReputationScoreTics[team] += BG_AB_TickPoints[points]; - if (m_ReputationScoreTics[team] >= m_ReputationTics) - { - (team == BG_TEAM_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE); - m_ReputationScoreTics[team] -= m_ReputationTics; - } - if (m_HonorScoreTics[team] >= m_HonorTics) - { - RewardHonorToTeam(GetBonusHonorFromKill(1), (team == BG_TEAM_ALLIANCE) ? ALLIANCE : HORDE); - m_HonorScoreTics[team] -= m_HonorTics; - } - if (!m_IsInformedNearVictory && m_TeamScores[team] > BG_AB_WARNING_NEAR_VICTORY_SCORE) - { - if (team == BG_TEAM_ALLIANCE) - SendMessageToAll(LANG_BG_AB_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); - else - SendMessageToAll(LANG_BG_AB_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); - PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY); - m_IsInformedNearVictory = true; - } - - if (m_TeamScores[team] > BG_AB_MAX_TEAM_SCORE) - m_TeamScores[team] = BG_AB_MAX_TEAM_SCORE; - if (team == BG_TEAM_ALLIANCE) - UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]); - if (team == BG_TEAM_HORDE) - UpdateWorldState(BG_AB_OP_RESOURCES_HORDE, m_TeamScores[team]); - // update achievement flags - // we increased m_TeamScores[team] so we just need to check if it is 500 more than other teams resources - uint8 otherTeam = (team + 1) % BG_TEAMS_COUNT; - if (m_TeamScores[team] > m_TeamScores[otherTeam] + 500) - m_TeamScores500Disadvantage[otherTeam] = true; - } - } - - // Test win condition - if (m_TeamScores[BG_TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE) - EndBattleGround(ALLIANCE); - if (m_TeamScores[BG_TEAM_HORDE] >= BG_AB_MAX_TEAM_SCORE) - EndBattleGround(HORDE); - } -} - -void BattleGroundAB::StartingEventCloseDoors() -{ - // despawn banners, auras and buffs - for (int obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_DYNAMIC_NODES_COUNT * 8; ++obj) - SpawnBGObject(obj, RESPAWN_ONE_DAY); - for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT * 3; ++i) - SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + i, RESPAWN_ONE_DAY); - - // Starting doors - DoorClose(BG_AB_OBJECT_GATE_A); - DoorClose(BG_AB_OBJECT_GATE_H); - SpawnBGObject(BG_AB_OBJECT_GATE_A, RESPAWN_IMMEDIATELY); - SpawnBGObject(BG_AB_OBJECT_GATE_H, RESPAWN_IMMEDIATELY); - - // Starting base spirit guides - _NodeOccupied(BG_AB_SPIRIT_ALIANCE,ALLIANCE); - _NodeOccupied(BG_AB_SPIRIT_HORDE,HORDE); -} - -void BattleGroundAB::StartingEventOpenDoors() -{ - // spawn neutral banners - for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i) - SpawnBGObject(banner, RESPAWN_IMMEDIATELY); - for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) - { - //randomly select buff to spawn - uint8 buff = urand(0, 2); - SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + buff + i * 3, RESPAWN_IMMEDIATELY); - } - DoorOpen(BG_AB_OBJECT_GATE_A); - DoorOpen(BG_AB_OBJECT_GATE_H); -} - -void BattleGroundAB::AddPlayer(Player *plr) -{ - BattleGround::AddPlayer(plr); - //create score and add it to map, default values are set in the constructor - BattleGroundABScore* sc = new BattleGroundABScore; - - m_PlayerScores[plr->GetGUID()] = sc; -} - -void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) -{ - -} - -void BattleGroundAB::HandleAreaTrigger(Player *Source, uint32 Trigger) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - switch(Trigger) - { - case 3948: // Arathi Basin Alliance Exit. - if (Source->GetTeam() != ALLIANCE) - Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal"); - else - Source->LeaveBattleground(); - break; - case 3949: // Arathi Basin Horde Exit. - if (Source->GetTeam() != HORDE) - Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal"); - else - Source->LeaveBattleground(); - break; - case 3866: // Stables - case 3869: // Gold Mine - case 3867: // Farm - case 3868: // Lumber Mill - case 3870: // Black Smith - case 4020: // Unk1 - case 4021: // Unk2 - //break; - default: - //sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); - //Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); - break; - } -} - -/* type: 0-neutral, 1-contested, 3-occupied - teamIndex: 0-ally, 1-horde */ -void BattleGroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay) -{ - // Just put it into the queue - if (delay) - { - m_BannerTimers[node].timer = 2000; - m_BannerTimers[node].type = type; - m_BannerTimers[node].teamIndex = teamIndex; - return; - } - - uint8 obj = node*8 + type + teamIndex; - - SpawnBGObject(obj, RESPAWN_IMMEDIATELY); - - // handle aura with banner - if (!type) - return; - obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7); - SpawnBGObject(obj, RESPAWN_IMMEDIATELY); -} - -void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex) -{ - uint8 obj = node*8 + type + teamIndex; - SpawnBGObject(obj, RESPAWN_ONE_DAY); - - // handle aura with banner - if (!type) - return; - obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7); - SpawnBGObject(obj, RESPAWN_ONE_DAY); -} - -int32 BattleGroundAB::_GetNodeNameId(uint8 node) -{ - switch (node) - { - case BG_AB_NODE_STABLES: return LANG_BG_AB_NODE_STABLES; - case BG_AB_NODE_BLACKSMITH: return LANG_BG_AB_NODE_BLACKSMITH; - case BG_AB_NODE_FARM: return LANG_BG_AB_NODE_FARM; - case BG_AB_NODE_LUMBER_MILL:return LANG_BG_AB_NODE_LUMBER_MILL; - case BG_AB_NODE_GOLD_MINE: return LANG_BG_AB_NODE_GOLD_MINE; - default: - ASSERT(0); - } - return 0; -} - -void BattleGroundAB::FillInitialWorldStates(WorldPacket& data) -{ - const uint8 plusArray[] = {0, 2, 3, 0, 1}; - - // Node icons - for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node) - data << uint32(BG_AB_OP_NODEICONS[node]) << uint32((m_Nodes[node] == 0)?1:0); - - // Node occupied states - for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node) - for (uint8 i = 1; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) - data << uint32(BG_AB_OP_NODESTATES[node] + plusArray[i]) << uint32((m_Nodes[node] == i)?1:0); - - // How many bases each team owns - uint8 ally = 0, horde = 0; - for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node) - if (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_OCCUPIED) - ++ally; - else if (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED) - ++horde; - - data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY) << uint32(ally); - data << uint32(BG_AB_OP_OCCUPIED_BASES_HORDE) << uint32(horde); - - // Team scores - data << uint32(BG_AB_OP_RESOURCES_MAX) << uint32(BG_AB_MAX_TEAM_SCORE); - data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_NEAR_VICTORY_SCORE); - data << uint32(BG_AB_OP_RESOURCES_ALLY) << uint32(m_TeamScores[BG_TEAM_ALLIANCE]); - data << uint32(BG_AB_OP_RESOURCES_HORDE) << uint32(m_TeamScores[BG_TEAM_HORDE]); - - // other unknown - data << uint32(0x745) << uint32(0x2); // 37 1861 unk -} - -void BattleGroundAB::_SendNodeUpdate(uint8 node) -{ - // Send node owner state update to refresh map icons on client - const uint8 plusArray[] = {0, 2, 3, 0, 1}; - - if (m_prevNodes[node]) - UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_prevNodes[node]], 0); - else - UpdateWorldState(BG_AB_OP_NODEICONS[node], 0); - - UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_Nodes[node]], 1); - - // How many bases each team owns - uint8 ally = 0, horde = 0; - for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) - if (m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED) - ++ally; - else if (m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED) - ++horde; - - UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_ALLY, ally); - UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_HORDE, horde); -} - -void BattleGroundAB::_NodeOccupied(uint8 node,Team team) -{ - if (!AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team)) - sLog.outError("Failed to spawn spirit guide! point: %u, team: %u,", node, team); - - uint8 capturedNodes = 0; - for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) - { - if (m_Nodes[node] == GetTeamIndexByTeamId(team) + BG_AB_NODE_TYPE_OCCUPIED && !m_NodeTimers[i]) - ++capturedNodes; - } - if (capturedNodes >= 5) - CastSpellOnTeam(SPELL_AB_QUEST_REWARD_5_BASES, team); - if (capturedNodes >= 4) - CastSpellOnTeam(SPELL_AB_QUEST_REWARD_4_BASES, team); - - if(node >= BG_AB_DYNAMIC_NODES_COUNT)//only dynamic nodes, no start points - return; - Creature* trigger = GetBGCreature(node+7);//0-6 spirit guides - if (!trigger) - trigger = AddCreature(WORLD_TRIGGER,node+7,team,BG_AB_NodePositions[node][0],BG_AB_NodePositions[node][1],BG_AB_NodePositions[node][2],BG_AB_NodePositions[node][3]); - - //add bonus honor aura trigger creature when node is accupied - //cast bonus aura (+50% honor in 25yards) - //aura should only apply to players who have accupied the node, set correct faction for trigger - if (trigger) - { - trigger->setFaction(team == ALLIANCE ? 84 : 83); - trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false); - } -} - -void BattleGroundAB::_NodeDeOccupied(uint8 node) -{ - if (node >= BG_AB_DYNAMIC_NODES_COUNT) - return; - - //remove bonus honor aura trigger creature when node is lost - if(node < BG_AB_DYNAMIC_NODES_COUNT)//only dynamic nodes, no start points - DelCreature(node+7);//NULL checks are in DelCreature! 0-6 spirit guides - - // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard - std::vector ghost_list = m_ReviveQueue[m_BgCreatures[node]]; - if (!ghost_list.empty()) - { - WorldSafeLocsEntry const *ClosestGrave = NULL; - for (std::vector::const_iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr) - { - Player* plr = objmgr.GetPlayer(*itr); - if (!plr) - continue; - - if (!ClosestGrave) // cache - ClosestGrave = GetClosestGraveYard(plr); - - if (ClosestGrave) - plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation()); - } - } - - if (m_BgCreatures[node]) - DelCreature(node); - - // buff object isn't despawned -} - -/* Invoked if a player used a banner as a gameobject */ -void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*target_obj*/) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - uint8 node = BG_AB_NODE_STABLES; - GameObject* obj=GetBgMap()->GetGameObject(m_BgObjects[node*8+7]); - while ((node < BG_AB_DYNAMIC_NODES_COUNT) && ((!obj) || (!source->IsWithinDistInMap(obj,10)))) - { - ++node; - obj=GetBgMap()->GetGameObject(m_BgObjects[node*8+BG_AB_OBJECT_AURA_CONTESTED]); - } - - if (node == BG_AB_DYNAMIC_NODES_COUNT) - { - // this means our player isn't close to any of banners - maybe cheater ?? - return; - } - - BattleGroundTeamId teamIndex = GetTeamIndexByTeamId(source->GetTeam()); - - // Check if player really could use this banner, not cheated - if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2)) - return; - - source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); - uint32 sound = 0; - // If node is neutral, change to contested - if (m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL) - { - UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1); - m_prevNodes[node] = m_Nodes[node]; - m_Nodes[node] = teamIndex + 1; - // burn current neutral banner - _DelBanner(node, BG_AB_NODE_TYPE_NEUTRAL, 0); - // create new contested banner - _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true); - _SendNodeUpdate(node); - m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; - - // FIXME: team and node names not localized - if (teamIndex == 0) - SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node), LANG_BG_AB_ALLY); - else - SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node), LANG_BG_AB_HORDE); - - sound = BG_AB_SOUND_NODE_CLAIMED; - } - // If node is contested - else if ((m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED)) - { - // If last state is NOT occupied, change node to enemy-contested - if (m_prevNodes[node] < BG_AB_NODE_TYPE_OCCUPIED) - { - UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1); - m_prevNodes[node] = m_Nodes[node]; - m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED; - // burn current contested banner - _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex); - // create new contested banner - _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true); - _SendNodeUpdate(node); - m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; - - // FIXME: node names not localized - if (teamIndex == BG_TEAM_ALLIANCE) - SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); - else - SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); - } - // If contested, change back to occupied - else - { - UpdatePlayerScore(source, SCORE_BASES_DEFENDED, 1); - m_prevNodes[node] = m_Nodes[node]; - m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_OCCUPIED; - // burn current contested banner - _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex); - // create new occupied banner - _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true); - _SendNodeUpdate(node); - m_NodeTimers[node] = 0; - _NodeOccupied(node,(teamIndex == BG_TEAM_ALLIANCE) ? ALLIANCE:HORDE); - - // FIXME: node names not localized - if (teamIndex == BG_TEAM_ALLIANCE) - SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); - else - SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); - } - sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE; - } - // If node is occupied, change to enemy-contested - else - { - UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1); - m_prevNodes[node] = m_Nodes[node]; - m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED; - // burn current occupied banner - _DelBanner(node, BG_AB_NODE_TYPE_OCCUPIED, !teamIndex); - // create new contested banner - _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true); - _SendNodeUpdate(node); - _NodeDeOccupied(node); - m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; - - // FIXME: node names not localized - if (teamIndex == BG_TEAM_ALLIANCE) - SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); - else - SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); - - sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE; - } - - // If node is occupied again, send "X has taken the Y" msg. - if (m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED) - { - // FIXME: team and node names not localized - if (teamIndex == BG_TEAM_ALLIANCE) - SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, LANG_BG_AB_ALLY, _GetNodeNameId(node)); - else - SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE, NULL, LANG_BG_AB_HORDE, _GetNodeNameId(node)); - } - PlaySoundToAll(sound); -} - -bool BattleGroundAB::SetupBattleGround() -{ - for (int i = 0 ; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) - { - if (!AddObject(BG_AB_OBJECT_BANNER_NEUTRAL + 8*i,BG_AB_OBJECTID_NODE_BANNER_0 + i,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AB_OBJECT_BANNER_CONT_A + 8*i,BG_AB_OBJECTID_BANNER_CONT_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AB_OBJECT_BANNER_CONT_H + 8*i,BG_AB_OBJECTID_BANNER_CONT_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AB_OBJECT_BANNER_ALLY + 8*i,BG_AB_OBJECTID_BANNER_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AB_OBJECT_BANNER_HORDE + 8*i,BG_AB_OBJECTID_BANNER_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AB_OBJECT_AURA_ALLY + 8*i,BG_AB_OBJECTID_AURA_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AB_OBJECT_AURA_HORDE + 8*i,BG_AB_OBJECTID_AURA_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AB_OBJECT_AURA_CONTESTED + 8*i,BG_AB_OBJECTID_AURA_C,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) -) - { - sLog.outErrorDb("BatteGroundAB: Failed to spawn some object BattleGround not created!"); - return false; - } - } - if (!AddObject(BG_AB_OBJECT_GATE_A,BG_AB_OBJECTID_GATE_A,BG_AB_DoorPositions[0][0],BG_AB_DoorPositions[0][1],BG_AB_DoorPositions[0][2],BG_AB_DoorPositions[0][3],BG_AB_DoorPositions[0][4],BG_AB_DoorPositions[0][5],BG_AB_DoorPositions[0][6],BG_AB_DoorPositions[0][7],RESPAWN_IMMEDIATELY) - || !AddObject(BG_AB_OBJECT_GATE_H,BG_AB_OBJECTID_GATE_H,BG_AB_DoorPositions[1][0],BG_AB_DoorPositions[1][1],BG_AB_DoorPositions[1][2],BG_AB_DoorPositions[1][3],BG_AB_DoorPositions[1][4],BG_AB_DoorPositions[1][5],BG_AB_DoorPositions[1][6],BG_AB_DoorPositions[1][7],RESPAWN_IMMEDIATELY) -) - { - sLog.outErrorDb("BatteGroundAB: Failed to spawn door object BattleGround not created!"); - return false; - } - //buffs - for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) - { - if (!AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i, Buff_Entries[0], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY) - || !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 1, Buff_Entries[1], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY) - || !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 2, Buff_Entries[2], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY) -) - sLog.outErrorDb("BatteGroundAB: Failed to spawn buff object!"); - } - - return true; -} - -void BattleGroundAB::Reset() -{ - //call parent's class reset - BattleGround::Reset(); - - m_TeamScores[BG_TEAM_ALLIANCE] = 0; - m_TeamScores[BG_TEAM_HORDE] = 0; - m_lastTick[BG_TEAM_ALLIANCE] = 0; - m_lastTick[BG_TEAM_HORDE] = 0; - m_HonorScoreTics[BG_TEAM_ALLIANCE] = 0; - m_HonorScoreTics[BG_TEAM_HORDE] = 0; - m_ReputationScoreTics[BG_TEAM_ALLIANCE] = 0; - m_ReputationScoreTics[BG_TEAM_HORDE] = 0; - m_IsInformedNearVictory = false; - bool isBGWeekend = sBattleGroundMgr.IsBGWeekend(GetTypeID()); - m_HonorTics = (isBGWeekend) ? BG_AB_ABBGWeekendHonorTicks : BG_AB_NotABBGWeekendHonorTicks; - m_ReputationTics = (isBGWeekend) ? BG_AB_ABBGWeekendReputationTicks : BG_AB_NotABBGWeekendReputationTicks; - m_TeamScores500Disadvantage[BG_TEAM_ALLIANCE] = false; - m_TeamScores500Disadvantage[BG_TEAM_HORDE] = false; - - for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) - { - m_Nodes[i] = 0; - m_prevNodes[i] = 0; - m_NodeTimers[i] = 0; - m_BannerTimers[i].timer = 0; - } - - for (uint8 i = 0; i < BG_AB_ALL_NODES_COUNT + 5; ++i)//+5 for aura triggers - if (m_BgCreatures[i]) - DelCreature(i); -} - -void BattleGroundAB::EndBattleGround(uint32 winner) -{ - //win reward - if (winner == ALLIANCE) - RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); - if (winner == HORDE) - RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); - //complete map_end rewards (even if no team wins) - RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); - RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); - - BattleGround::EndBattleGround(winner); -} - -WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player) -{ - BattleGroundTeamId teamIndex = GetTeamIndexByTeamId(player->GetTeam()); - - // Is there any occupied node for this team? - std::vector nodes; - for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) - if (m_Nodes[i] == teamIndex + 3) - nodes.push_back(i); - - WorldSafeLocsEntry const* good_entry = NULL; - // If so, select the closest node to place ghost on - if (!nodes.empty()) - { - float plr_x = player->GetPositionX(); - float plr_y = player->GetPositionY(); - - float mindist = 999999.0f; - for (uint8 i = 0; i < nodes.size(); ++i) - { - WorldSafeLocsEntry const*entry = sWorldSafeLocsStore.LookupEntry(BG_AB_GraveyardIds[nodes[i]]); - if (!entry) - continue; - float dist = (entry->x - plr_x)*(entry->x - plr_x)+(entry->y - plr_y)*(entry->y - plr_y); - if (mindist > dist) - { - mindist = dist; - good_entry = entry; - } - } - nodes.clear(); - } - // If not, place ghost on starting location - if (!good_entry) - good_entry = sWorldSafeLocsStore.LookupEntry(BG_AB_GraveyardIds[teamIndex+5]); - - return good_entry; -} - -void BattleGroundAB::UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor) -{ - BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); - if (itr == m_PlayerScores.end()) // player not found... - return; - - switch(type) - { - case SCORE_BASES_ASSAULTED: - ((BattleGroundABScore*)itr->second)->BasesAssaulted += value; - break; - case SCORE_BASES_DEFENDED: - ((BattleGroundABScore*)itr->second)->BasesDefended += value; - break; - default: - BattleGround::UpdatePlayerScore(Source,type,value, doAddHonor); - break; - } -} - -bool BattleGroundAB::IsAllNodesConrolledByTeam(uint32 team) const -{ - uint32 count = 0; - for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) - if ((team == ALLIANCE && m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED) || - (team == HORDE && m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)) - ++count; - - return count == BG_AB_DYNAMIC_NODES_COUNT; -} diff --git a/src/server/game/BattleGrounds/BattleGroundAB.h b/src/server/game/BattleGrounds/BattleGroundAB.h deleted file mode 100644 index 3072f8beafd..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundAB.h +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __BATTLEGROUNDAB_H -#define __BATTLEGROUNDAB_H - -class BattleGround; - -enum BG_AB_WorldStates -{ - BG_AB_OP_OCCUPIED_BASES_HORDE = 1778, - BG_AB_OP_OCCUPIED_BASES_ALLY = 1779, - BG_AB_OP_RESOURCES_ALLY = 1776, - BG_AB_OP_RESOURCES_HORDE = 1777, - BG_AB_OP_RESOURCES_MAX = 1780, - BG_AB_OP_RESOURCES_WARNING = 1955 -/* - BG_AB_OP_STABLE_ICON = 1842, //Stable map icon (NONE) - BG_AB_OP_STABLE_STATE_ALIENCE = 1767, //Stable map state (ALIENCE) - BG_AB_OP_STABLE_STATE_HORDE = 1768, //Stable map state (HORDE) - BG_AB_OP_STABLE_STATE_CON_ALI = 1769, //Stable map state (CON ALIENCE) - BG_AB_OP_STABLE_STATE_CON_HOR = 1770, //Stable map state (CON HORDE) - BG_AB_OP_FARM_ICON = 1845, //Farm map icon (NONE) - BG_AB_OP_FARM_STATE_ALIENCE = 1772, //Farm state (ALIENCE) - BG_AB_OP_FARM_STATE_HORDE = 1773, //Farm state (HORDE) - BG_AB_OP_FARM_STATE_CON_ALI = 1774, //Farm state (CON ALIENCE) - BG_AB_OP_FARM_STATE_CON_HOR = 1775, //Farm state (CON HORDE) - - BG_AB_OP_BLACKSMITH_ICON = 1846, //Blacksmith map icon (NONE) - BG_AB_OP_BLACKSMITH_STATE_ALIENCE = 1782, //Blacksmith map state (ALIENCE) - BG_AB_OP_BLACKSMITH_STATE_HORDE = 1783, //Blacksmith map state (HORDE) - BG_AB_OP_BLACKSMITH_STATE_CON_ALI = 1784, //Blacksmith map state (CON ALIENCE) - BG_AB_OP_BLACKSMITH_STATE_CON_HOR = 1785, //Blacksmith map state (CON HORDE) - BG_AB_OP_LUMBERMILL_ICON = 1844, //Lumber Mill map icon (NONE) - BG_AB_OP_LUMBERMILL_STATE_ALIENCE = 1792, //Lumber Mill map state (ALIENCE) - BG_AB_OP_LUMBERMILL_STATE_HORDE = 1793, //Lumber Mill map state (HORDE) - BG_AB_OP_LUMBERMILL_STATE_CON_ALI = 1794, //Lumber Mill map state (CON ALIENCE) - BG_AB_OP_LUMBERMILL_STATE_CON_HOR = 1795, //Lumber Mill map state (CON HORDE) - BG_AB_OP_GOLDMINE_ICON = 1843, //Gold Mine map icon (NONE) - BG_AB_OP_GOLDMINE_STATE_ALIENCE = 1787, //Gold Mine map state (ALIENCE) - BG_AB_OP_GOLDMINE_STATE_HORDE = 1788, //Gold Mine map state (HORDE) - BG_AB_OP_GOLDMINE_STATE_CON_ALI = 1789, //Gold Mine map state (CON ALIENCE - BG_AB_OP_GOLDMINE_STATE_CON_HOR = 1790, //Gold Mine map state (CON HORDE) -*/ -}; - -const uint32 BG_AB_OP_NODESTATES[5] = {1767, 1782, 1772, 1792, 1787}; - -const uint32 BG_AB_OP_NODEICONS[5] = {1842, 1846, 1845, 1844, 1843}; - -/* Note: code uses that these IDs follow each other */ -enum BG_AB_NodeObjectId -{ - BG_AB_OBJECTID_NODE_BANNER_0 = 180087, // Stables banner - BG_AB_OBJECTID_NODE_BANNER_1 = 180088, // Blacksmith banner - BG_AB_OBJECTID_NODE_BANNER_2 = 180089, // Farm banner - BG_AB_OBJECTID_NODE_BANNER_3 = 180090, // Lumber mill banner - BG_AB_OBJECTID_NODE_BANNER_4 = 180091 // Gold mine banner -}; - -enum BG_AB_ObjectType -{ - // for all 5 node points 8*5=40 objects - BG_AB_OBJECT_BANNER_NEUTRAL = 0, - BG_AB_OBJECT_BANNER_CONT_A = 1, - BG_AB_OBJECT_BANNER_CONT_H = 2, - BG_AB_OBJECT_BANNER_ALLY = 3, - BG_AB_OBJECT_BANNER_HORDE = 4, - BG_AB_OBJECT_AURA_ALLY = 5, - BG_AB_OBJECT_AURA_HORDE = 6, - BG_AB_OBJECT_AURA_CONTESTED = 7, - //gates - BG_AB_OBJECT_GATE_A = 40, - BG_AB_OBJECT_GATE_H = 41, - //buffs - BG_AB_OBJECT_SPEEDBUFF_STABLES = 42, - BG_AB_OBJECT_REGENBUFF_STABLES = 43, - BG_AB_OBJECT_BERSERKBUFF_STABLES = 44, - BG_AB_OBJECT_SPEEDBUFF_BLACKSMITH = 45, - BG_AB_OBJECT_REGENBUFF_BLACKSMITH = 46, - BG_AB_OBJECT_BERSERKBUFF_BLACKSMITH = 47, - BG_AB_OBJECT_SPEEDBUFF_FARM = 48, - BG_AB_OBJECT_REGENBUFF_FARM = 49, - BG_AB_OBJECT_BERSERKBUFF_FARM = 50, - BG_AB_OBJECT_SPEEDBUFF_LUMBER_MILL = 51, - BG_AB_OBJECT_REGENBUFF_LUMBER_MILL = 52, - BG_AB_OBJECT_BERSERKBUFF_LUMBER_MILL = 53, - BG_AB_OBJECT_SPEEDBUFF_GOLD_MINE = 54, - BG_AB_OBJECT_REGENBUFF_GOLD_MINE = 55, - BG_AB_OBJECT_BERSERKBUFF_GOLD_MINE = 56, - BG_AB_OBJECT_MAX = 57, -}; - -/* Object id templates from DB */ -enum BG_AB_ObjectTypes -{ - BG_AB_OBJECTID_BANNER_A = 180058, - BG_AB_OBJECTID_BANNER_CONT_A = 180059, - BG_AB_OBJECTID_BANNER_H = 180060, - BG_AB_OBJECTID_BANNER_CONT_H = 180061, - - BG_AB_OBJECTID_AURA_A = 180100, - BG_AB_OBJECTID_AURA_H = 180101, - BG_AB_OBJECTID_AURA_C = 180102, - - BG_AB_OBJECTID_GATE_A = 180255, - BG_AB_OBJECTID_GATE_H = 180256 -}; - -enum BG_AB_Timers -{ - BG_AB_FLAG_CAPTURING_TIME = 60000, -}; - -enum BG_AB_Score -{ - BG_AB_WARNING_NEAR_VICTORY_SCORE = 1400, - BG_AB_MAX_TEAM_SCORE = 1600 -}; - -/* do NOT change the order, else wrong behaviour */ -enum BG_AB_BattleGroundNodes -{ - BG_AB_NODE_STABLES = 0, - BG_AB_NODE_BLACKSMITH = 1, - BG_AB_NODE_FARM = 2, - BG_AB_NODE_LUMBER_MILL = 3, - BG_AB_NODE_GOLD_MINE = 4, - - BG_AB_DYNAMIC_NODES_COUNT = 5, // dynamic nodes that can be captured - - BG_AB_SPIRIT_ALIANCE = 5, - BG_AB_SPIRIT_HORDE = 6, - - BG_AB_ALL_NODES_COUNT = 7, // all nodes (dynamic and static) -}; - -enum BG_AB_NodeStatus -{ - BG_AB_NODE_TYPE_NEUTRAL = 0, - BG_AB_NODE_TYPE_CONTESTED = 1, - BG_AB_NODE_STATUS_ALLY_CONTESTED = 1, - BG_AB_NODE_STATUS_HORDE_CONTESTED = 2, - BG_AB_NODE_TYPE_OCCUPIED = 3, - BG_AB_NODE_STATUS_ALLY_OCCUPIED = 3, - BG_AB_NODE_STATUS_HORDE_OCCUPIED = 4 -}; - -enum BG_AB_Sounds -{ - BG_AB_SOUND_NODE_CLAIMED = 8192, - BG_AB_SOUND_NODE_CAPTURED_ALLIANCE = 8173, - BG_AB_SOUND_NODE_CAPTURED_HORDE = 8213, - BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE = 8212, - BG_AB_SOUND_NODE_ASSAULTED_HORDE = 8174, - BG_AB_SOUND_NEAR_VICTORY = 8456 -}; - -#define BG_AB_NotABBGWeekendHonorTicks 330 -#define BG_AB_ABBGWeekendHonorTicks 200 -#define BG_AB_NotABBGWeekendReputationTicks 200 -#define BG_AB_ABBGWeekendReputationTicks 150 - -// x, y, z, o -const float BG_AB_NodePositions[BG_AB_DYNAMIC_NODES_COUNT][4] = { - {1166.785f, 1200.132f, -56.70859f, 0.9075713f}, // stables - {977.0156f, 1046.616f, -44.80923f, -2.600541f}, // blacksmith - {806.1821f, 874.2723f, -55.99371f, -2.303835f}, // farm - {856.1419f, 1148.902f, 11.18469f, -2.303835f}, // lumber mill - {1146.923f, 848.1782f, -110.917f, -0.7330382f} // gold mine -}; - -// x, y, z, o, rot0, rot1, rot2, rot3 -const float BG_AB_DoorPositions[2][8] = { - {1284.597f, 1281.167f, -15.97792f, 0.7068594f, 0.012957f, -0.060288f, 0.344959f, 0.93659f}, - {708.0903f, 708.4479f, -17.8342f, -2.391099f, 0.050291f, 0.015127f, 0.929217f, -0.365784f} -}; - -// Tick intervals and given points: case 0,1,2,3,4,5 captured nodes -const uint32 BG_AB_TickIntervals[6] = {0, 12000, 9000, 6000, 3000, 1000}; -const uint32 BG_AB_TickPoints[6] = {0, 10, 10, 10, 10, 30}; - -// WorldSafeLocs ids for 5 nodes, and for ally, and horde starting location -const uint32 BG_AB_GraveyardIds[BG_AB_ALL_NODES_COUNT] = {895, 894, 893, 897, 896, 898, 899}; - -// x, y, z, o -const float BG_AB_BuffPositions[BG_AB_DYNAMIC_NODES_COUNT][4] = { - {1185.71f, 1185.24f, -56.36f, 2.56f}, // stables - {990.75f, 1008.18f, -42.60f, 2.43f}, // blacksmith - {817.66f, 843.34f, -56.54f, 3.01f}, // farm - {807.46f, 1189.16f, 11.92f, 5.44f}, // lumber mill - {1146.62f, 816.94f, -98.49f, 6.14f} // gold mine -}; - -// x, y, z, o -const float BG_AB_SpiritGuidePos[BG_AB_ALL_NODES_COUNT][4] = { - {1200.03f, 1171.09f, -56.47f, 5.15f}, // stables - {1017.43f, 960.61f, -42.95f, 4.88f}, // blacksmith - {833.00f, 793.00f, -57.25f, 5.27f}, // farm - {775.17f, 1206.40f, 15.79f, 1.90f}, // lumber mill - {1207.48f, 787.00f, -83.36f, 5.51f}, // gold mine - {1354.05f, 1275.48f, -11.30f, 4.77f}, // alliance starting base - {714.61f, 646.15f, -10.87f, 4.34f} // horde starting base -}; - -struct BG_AB_BannerTimer -{ - uint32 timer; - uint8 type; - uint8 teamIndex; -}; - -class BattleGroundABScore : public BattleGroundScore -{ - public: - BattleGroundABScore(): BasesAssaulted(0), BasesDefended(0) {}; - virtual ~BattleGroundABScore() {}; - uint32 BasesAssaulted; - uint32 BasesDefended; -}; - -class BattleGroundAB : public BattleGround -{ - friend class BattleGroundMgr; - - public: - BattleGroundAB(); - ~BattleGroundAB(); - - void Update(uint32 diff); - void AddPlayer(Player *plr); - virtual void StartingEventCloseDoors(); - virtual void StartingEventOpenDoors(); - void RemovePlayer(Player *plr,uint64 guid); - void HandleAreaTrigger(Player *Source, uint32 Trigger); - virtual bool SetupBattleGround(); - virtual void Reset(); - void EndBattleGround(uint32 winner); - virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); - - /* Scorekeeping */ - virtual void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); - - virtual void FillInitialWorldStates(WorldPacket& data); - - /* Nodes occupying */ - virtual void EventPlayerClickedOnFlag(Player *source, GameObject* target_obj); - - /* achievement req. */ - bool IsAllNodesConrolledByTeam(uint32 team) const; // overwrited - bool IsTeamScores500Disadvantage(uint32 team) const { return m_TeamScores500Disadvantage[GetTeamIndexByTeamId(team)]; } - private: - /* Gameobject spawning/despawning */ - void _CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay); - void _DelBanner(uint8 node, uint8 type, uint8 teamIndex); - void _SendNodeUpdate(uint8 node); - - /* Creature spawning/despawning */ - // TODO: working, scripted peons spawning - void _NodeOccupied(uint8 node,Team team); - void _NodeDeOccupied(uint8 node); - - int32 _GetNodeNameId(uint8 node); - - /* Nodes info: - 0: neutral - 1: ally contested - 2: horde contested - 3: ally occupied - 4: horde occupied */ - uint8 m_Nodes[BG_AB_DYNAMIC_NODES_COUNT]; - uint8 m_prevNodes[BG_AB_DYNAMIC_NODES_COUNT]; - BG_AB_BannerTimer m_BannerTimers[BG_AB_DYNAMIC_NODES_COUNT]; - uint32 m_NodeTimers[BG_AB_DYNAMIC_NODES_COUNT]; - uint32 m_lastTick[BG_TEAMS_COUNT]; - uint32 m_HonorScoreTics[BG_TEAMS_COUNT]; - uint32 m_ReputationScoreTics[BG_TEAMS_COUNT]; - bool m_IsInformedNearVictory; - uint32 m_HonorTics; - uint32 m_ReputationTics; - // need for achievements - bool m_TeamScores500Disadvantage[BG_TEAMS_COUNT]; -}; -#endif - diff --git a/src/server/game/BattleGrounds/BattleGroundAV.cpp b/src/server/game/BattleGrounds/BattleGroundAV.cpp deleted file mode 100644 index 7f5482cbf16..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundAV.cpp +++ /dev/null @@ -1,1490 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ObjectMgr.h" -#include "WorldPacket.h" - -#include "BattleGround.h" -#include "BattleGroundAV.h" -#include "Formulas.h" -#include "GameObject.h" -#include "Language.h" -#include "Player.h" -#include "SpellAuras.h" - -BattleGroundAV::BattleGroundAV() -{ - m_BgObjects.resize(BG_AV_OBJECT_MAX); - m_BgCreatures.resize(AV_CPLACE_MAX+AV_STATICCPLACE_MAX); - - m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_AV_START_TWO_MINUTES; - m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AV_START_ONE_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AV_START_HALF_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AV_HAS_BEGUN; -} - -BattleGroundAV::~BattleGroundAV() -{ -} - -const uint16 BattleGroundAV::GetBonusHonor(uint8 kills) //TODO: move this function to Battleground.cpp (needs to find a way to get m_MaxLevel) -{ - return Trinity::Honor::hk_honor_at_level(m_MaxLevel, kills); -} - -void BattleGroundAV::HandleKillPlayer(Player *player, Player *killer) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - BattleGround::HandleKillPlayer(player, killer); - UpdateScore(player->GetTeam(),-1); -} - -void BattleGroundAV::HandleKillUnit(Creature *unit, Player *killer) -{ - sLog.outDebug("bg_av HandleKillUnit %i",unit->GetEntry()); - if (GetStatus() != STATUS_IN_PROGRESS) - return; - uint32 entry = unit->GetEntry(); - /* - uint32 triggerSpawnID = 0; - if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0]) - triggerSpawnID = AV_CPLACE_TRIGGER16; - else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_BOSS][0]) - triggerSpawnID = AV_CPLACE_TRIGGER17; - else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN][0]) - triggerSpawnID = AV_CPLACE_TRIGGER18; - else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_BOSS][0]) - triggerSpawnID = AV_CPLACE_TRIGGER19; - */ - if (entry == BG_AV_CreatureInfo[AV_NPC_A_BOSS][0]) - { - CastSpellOnTeam(23658,HORDE); //this is a spell which finishes a quest where a player has to kill the boss - RewardReputationToTeam(729,BG_AV_REP_BOSS,HORDE); - RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_BOSS),HORDE); - EndBattleGround(HORDE); - DelCreature(AV_CPLACE_TRIGGER17); - } - else if (entry == BG_AV_CreatureInfo[AV_NPC_H_BOSS][0]) - { - CastSpellOnTeam(23658,ALLIANCE); //this is a spell which finishes a quest where a player has to kill the boss - RewardReputationToTeam(730,BG_AV_REP_BOSS,ALLIANCE); - RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_BOSS),ALLIANCE); - EndBattleGround(ALLIANCE); - DelCreature(AV_CPLACE_TRIGGER19); - } - else if (entry == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0]) - { - if (!m_CaptainAlive[0]) - { - sLog.outError("Killed a Captain twice, please report this bug, if you haven't done \".respawn\""); - return; - } - m_CaptainAlive[0]=false; - RewardReputationToTeam(729,BG_AV_REP_CAPTAIN,HORDE); - RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_CAPTAIN),HORDE); - UpdateScore(ALLIANCE,(-1)*BG_AV_RES_CAPTAIN); - //spawn destroyed aura - for (uint8 i=0; i <= 9; i++) - SpawnBGObject(BG_AV_OBJECT_BURN_BUILDING_ALLIANCE+i,RESPAWN_IMMEDIATELY); - Creature* creature = GetBGCreature(AV_CPLACE_HERALD); - if (creature) - YellToAll(creature,GetTrinityString(LANG_BG_AV_A_CAPTAIN_DEAD),LANG_UNIVERSAL); - DelCreature(AV_CPLACE_TRIGGER16); - } - else if (entry == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN][0]) - { - if (!m_CaptainAlive[1]) - { - sLog.outError("Killed a Captain twice, please report this bug, if you haven't done \".respawn\""); - return; - } - m_CaptainAlive[1]=false; - RewardReputationToTeam(730,BG_AV_REP_CAPTAIN,ALLIANCE); - RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_CAPTAIN),ALLIANCE); - UpdateScore(HORDE,(-1)*BG_AV_RES_CAPTAIN); - //spawn destroyed aura - for (uint8 i=0; i <= 9; i++) - SpawnBGObject(BG_AV_OBJECT_BURN_BUILDING_HORDE+i,RESPAWN_IMMEDIATELY); - Creature* creature = GetBGCreature(AV_CPLACE_HERALD); - if (creature) - YellToAll(creature,GetTrinityString(LANG_BG_AV_H_CAPTAIN_DEAD),LANG_UNIVERSAL); - DelCreature(AV_CPLACE_TRIGGER18); - } - else if (entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_N_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_A_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_H_4][0]) - ChangeMineOwner(AV_NORTH_MINE,killer->GetTeam()); - else if (entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_N_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_A_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_H_4][0]) - ChangeMineOwner(AV_SOUTH_MINE,killer->GetTeam()); -} - -void BattleGroundAV::HandleQuestComplete(uint32 questid, Player *player) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return;//maybe we should log this, cause this must be a cheater or a big bug - uint8 team = GetTeamIndexByTeamId(player->GetTeam()); - //TODO add reputation, events (including quest not available anymore, next quest availabe, go/npc de/spawning)and maybe honor - sLog.outDebug("BG_AV Quest %i completed",questid); - switch(questid) - { - case AV_QUEST_A_SCRAPS1: - case AV_QUEST_A_SCRAPS2: - case AV_QUEST_H_SCRAPS1: - case AV_QUEST_H_SCRAPS2: - m_Team_QuestStatus[team][0]+=20; - if (m_Team_QuestStatus[team][0] == 500 || m_Team_QuestStatus[team][0] == 1000 || m_Team_QuestStatus[team][0] == 1500) //25,50,75 turn ins - { - sLog.outDebug("BG_AV Quest %i completed starting with unit upgrading..",questid); - for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i) - if (m_Nodes[i].Owner == player->GetTeam() && m_Nodes[i].State == POINT_CONTROLED) - { - DePopulateNode(i); - PopulateNode(i); - //maybe this is bad, because it will instantly respawn all creatures on every grave.. - } - } - break; - case AV_QUEST_A_COMMANDER1: - case AV_QUEST_H_COMMANDER1: - m_Team_QuestStatus[team][1]++; - RewardReputationToTeam(team,1,player->GetTeam()); - if (m_Team_QuestStatus[team][1] == 30) - sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); - break; - case AV_QUEST_A_COMMANDER2: - case AV_QUEST_H_COMMANDER2: - m_Team_QuestStatus[team][2]++; - RewardReputationToTeam(team,1,player->GetTeam()); - if (m_Team_QuestStatus[team][2] == 60) - sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); - break; - case AV_QUEST_A_COMMANDER3: - case AV_QUEST_H_COMMANDER3: - m_Team_QuestStatus[team][3]++; - RewardReputationToTeam(team,1,player->GetTeam()); - if (m_Team_QuestStatus[team][1] == 120) - sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); - break; - case AV_QUEST_A_BOSS1: - case AV_QUEST_H_BOSS1: - m_Team_QuestStatus[team][4] += 9; //you can turn in 10 or 1 item.. - case AV_QUEST_A_BOSS2: - case AV_QUEST_H_BOSS2: - m_Team_QuestStatus[team][4]++; - if (m_Team_QuestStatus[team][4] >= 200) - sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); - break; - case AV_QUEST_A_NEAR_MINE: - case AV_QUEST_H_NEAR_MINE: - m_Team_QuestStatus[team][5]++; - if (m_Team_QuestStatus[team][5] == 28) - { - sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); - if (m_Team_QuestStatus[team][6] == 7) - sLog.outDebug("BG_AV Quest %i completed (need to implement some events here - ground assault ready",questid); - } - break; - case AV_QUEST_A_OTHER_MINE: - case AV_QUEST_H_OTHER_MINE: - m_Team_QuestStatus[team][6]++; - if (m_Team_QuestStatus[team][6] == 7) - { - sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); - if (m_Team_QuestStatus[team][5] == 20) - sLog.outDebug("BG_AV Quest %i completed (need to implement some events here - ground assault ready",questid); - } - break; - case AV_QUEST_A_RIDER_HIDE: - case AV_QUEST_H_RIDER_HIDE: - m_Team_QuestStatus[team][7]++; - if (m_Team_QuestStatus[team][7] == 25) - { - sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); - if (m_Team_QuestStatus[team][8] == 25) - sLog.outDebug("BG_AV Quest %i completed (need to implement some events here - rider assault ready",questid); - } - break; - case AV_QUEST_A_RIDER_TAME: - case AV_QUEST_H_RIDER_TAME: - m_Team_QuestStatus[team][8]++; - if (m_Team_QuestStatus[team][8] == 25) - { - sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); - if (m_Team_QuestStatus[team][7] == 25) - sLog.outDebug("BG_AV Quest %i completed (need to implement some events here - rider assault ready",questid); - } - break; - default: - sLog.outDebug("BG_AV Quest %i completed but is not interesting at all",questid); - return; //was no interesting quest at all - break; - } -} - -void BattleGroundAV::UpdateScore(uint16 team, int16 points) -{ //note: to remove reinforcementpoints points must be negative, for adding reinforcements points must be positive - assert(team == ALLIANCE || team == HORDE); - uint8 teamindex = GetTeamIndexByTeamId(team); //0=ally 1=horde - m_Team_Scores[teamindex] += points; - - UpdateWorldState(((teamindex == BG_TEAM_HORDE)?AV_Horde_Score:AV_Alliance_Score), m_Team_Scores[teamindex]); - if (points < 0) - { - if (m_Team_Scores[teamindex] < 1) - { - m_Team_Scores[teamindex]=0; - EndBattleGround(((teamindex == BG_TEAM_HORDE)?ALLIANCE:HORDE)); - } - else if (!m_IsInformedNearVictory[teamindex] && m_Team_Scores[teamindex] < SEND_MSG_NEAR_LOSE) - { - SendMessageToAll(teamindex == BG_TEAM_HORDE?LANG_BG_AV_H_NEAR_LOSE:LANG_BG_AV_A_NEAR_LOSE, teamindex == BG_TEAM_HORDE ? CHAT_MSG_BG_SYSTEM_HORDE : CHAT_MSG_BG_SYSTEM_ALLIANCE); - PlaySoundToAll(AV_SOUND_NEAR_VICTORY); - m_IsInformedNearVictory[teamindex] = true; - } - } -} - -Creature* BattleGroundAV::AddAVCreature(uint16 cinfoid, uint16 type) -{ - uint8 level; - bool isStatic = false; - Creature* creature = NULL; - assert(type <= AV_CPLACE_MAX + AV_STATICCPLACE_MAX); - if (type >= AV_CPLACE_MAX) //static - { - type -= AV_CPLACE_MAX; - cinfoid=uint16(BG_AV_StaticCreaturePos[type][4]); - creature = AddCreature(BG_AV_StaticCreatureInfo[cinfoid][0],(type+AV_CPLACE_MAX),BG_AV_StaticCreatureInfo[cinfoid][1],BG_AV_StaticCreaturePos[type][0],BG_AV_StaticCreaturePos[type][1],BG_AV_StaticCreaturePos[type][2],BG_AV_StaticCreaturePos[type][3]); - level = (BG_AV_StaticCreatureInfo[cinfoid][2] == BG_AV_StaticCreatureInfo[cinfoid][3]) ? BG_AV_StaticCreatureInfo[cinfoid][2] : urand(BG_AV_StaticCreatureInfo[cinfoid][2],BG_AV_StaticCreatureInfo[cinfoid][3]); - isStatic = true; - } - else - { - creature = AddCreature(BG_AV_CreatureInfo[cinfoid][0],type,BG_AV_CreatureInfo[cinfoid][1],BG_AV_CreaturePos[type][0],BG_AV_CreaturePos[type][1],BG_AV_CreaturePos[type][2],BG_AV_CreaturePos[type][3]); - level = (BG_AV_CreatureInfo[cinfoid][2] == BG_AV_CreatureInfo[cinfoid][3]) ? BG_AV_CreatureInfo[cinfoid][2] : urand(BG_AV_CreatureInfo[cinfoid][2],BG_AV_CreatureInfo[cinfoid][3]); - } - if (!creature) - return NULL; - if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0] || creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN][0]) - creature->SetRespawnDelay(RESPAWN_ONE_DAY); // TODO: look if this can be done by database + also add this for the wingcommanders - - if ((isStatic && cinfoid >= 10 && cinfoid <= 14) || (!isStatic && ((cinfoid >= AV_NPC_A_GRAVEDEFENSE0 && cinfoid <= AV_NPC_A_GRAVEDEFENSE3) || - (cinfoid >= AV_NPC_H_GRAVEDEFENSE0 && cinfoid <= AV_NPC_H_GRAVEDEFENSE3)))) - { - if (!isStatic && ((cinfoid >= AV_NPC_A_GRAVEDEFENSE0 && cinfoid <= AV_NPC_A_GRAVEDEFENSE3) - || (cinfoid >= AV_NPC_H_GRAVEDEFENSE0 && cinfoid <= AV_NPC_H_GRAVEDEFENSE3))) - { - CreatureData &data = objmgr.NewOrExistCreatureData(creature->GetDBTableGUIDLow()); - data.spawndist = 5; - } - //else spawndist will be 15, so creatures move maximum=10 - //creature->SetDefaultMovementType(RANDOM_MOTION_TYPE); - creature->GetMotionMaster()->Initialize(); - creature->setDeathState(JUST_DIED); - creature->Respawn(); - //TODO: find a way to add a motionmaster without killing the creature (i - //just copied this code from a gm-command - } - - if (level != 0) - level += m_MaxLevel - 60; //maybe we can do this more generic for custom level-range.. actually it's blizzlike - creature->SetLevel(level); - - uint32 triggerSpawnID = 0; - uint32 newFaction = 0; - if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0]) - { - triggerSpawnID = AV_CPLACE_TRIGGER16; - newFaction = 84; - } - else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_BOSS][0]) - { - triggerSpawnID = AV_CPLACE_TRIGGER17; - newFaction = 84; - } - else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN][0]) - { - triggerSpawnID = AV_CPLACE_TRIGGER18; - newFaction = 83; - } - else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_BOSS][0]) - { - triggerSpawnID = AV_CPLACE_TRIGGER19; - newFaction = 83; - } - if (triggerSpawnID && newFaction) - { - if (Creature* trigger = AddCreature(WORLD_TRIGGER,triggerSpawnID,BG_AV_CreatureInfo[creature->GetEntry()][1],BG_AV_CreaturePos[triggerSpawnID][0],BG_AV_CreaturePos[triggerSpawnID][1],BG_AV_CreaturePos[triggerSpawnID][2],BG_AV_CreaturePos[triggerSpawnID][3])) - { - trigger->setFaction(newFaction); - trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false); - } - } - - return creature; -} - -void BattleGroundAV::Update(uint32 diff) -{ - BattleGround::Update(diff); - - if (GetStatus() == STATUS_IN_PROGRESS) - { - for (uint8 i=0; i <= 1; i++)//0=alliance, 1=horde - { - if (!m_CaptainAlive[i]) - continue; - if (m_CaptainBuffTimer[i] > diff) - m_CaptainBuffTimer[i] -= diff; - else - { - if (i == 0) - { - CastSpellOnTeam(AV_BUFF_A_CAPTAIN,ALLIANCE); - Creature* creature = GetBGCreature(AV_CPLACE_MAX + 61); - if (creature) - YellToAll(creature,LANG_BG_AV_A_CAPTAIN_BUFF,LANG_COMMON); - } - else - { - CastSpellOnTeam(AV_BUFF_H_CAPTAIN,HORDE); - Creature* creature = GetBGCreature(AV_CPLACE_MAX + 59); //TODO: make the captains a dynamic creature - if (creature) - YellToAll(creature,LANG_BG_AV_H_CAPTAIN_BUFF,LANG_ORCISH); - } - m_CaptainBuffTimer[i] = 120000 + urand(0,4)* 60000; //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes TODO get the right times - } - } - //add points from mine owning, and look if he neutral team wanrts to reclaim the mine - m_Mine_Timer -=diff; - for (uint8 mine=0; mine <2; mine++) - { - if (m_Mine_Owner[mine] == ALLIANCE || m_Mine_Owner[mine] == HORDE) - { - if (m_Mine_Timer <= 0) - UpdateScore(m_Mine_Owner[mine],1); - - if (m_Mine_Reclaim_Timer[mine] > diff) - m_Mine_Reclaim_Timer[mine] -= diff; - else{ //we don't need to set this timer to 0 cause this codepart wont get called when this thing is 0 - ChangeMineOwner(mine,AV_NEUTRAL_TEAM); - } - } - } - if (m_Mine_Timer <= 0) - m_Mine_Timer=AV_MINE_TICK_TIMER; //this is at the end, cause we need to update both mines - - //looks for all timers of the nodes and destroy the building (for graveyards the building wont get destroyed, it goes just to the other team - for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i) - if (m_Nodes[i].State == POINT_ASSAULTED) //maybe remove this - { - if (m_Nodes[i].Timer > diff) - m_Nodes[i].Timer -= diff; - else - EventPlayerDestroyedPoint(i); - } - } -} - -void BattleGroundAV::StartingEventCloseDoors() -{ - DoorClose(BG_AV_OBJECT_DOOR_A); - DoorClose(BG_AV_OBJECT_DOOR_H); -} - -void BattleGroundAV::StartingEventOpenDoors() -{ - sLog.outDebug("BG_AV: start spawning mine stuff"); - for (uint16 i= BG_AV_OBJECT_MINE_SUPPLY_N_MIN; i <= BG_AV_OBJECT_MINE_SUPPLY_N_MAX; i++) - SpawnBGObject(i,RESPAWN_IMMEDIATELY); - for (uint16 i= BG_AV_OBJECT_MINE_SUPPLY_S_MIN; i <= BG_AV_OBJECT_MINE_SUPPLY_S_MAX; i++) - SpawnBGObject(i,RESPAWN_IMMEDIATELY); - for (uint8 mine = AV_NORTH_MINE; mine <= AV_SOUTH_MINE; mine++) //mine population - ChangeMineOwner(mine, AV_NEUTRAL_TEAM,true); - - UpdateWorldState(AV_SHOW_H_SCORE, 1); - UpdateWorldState(AV_SHOW_A_SCORE, 1); - - DoorOpen(BG_AV_OBJECT_DOOR_H); - DoorOpen(BG_AV_OBJECT_DOOR_A); -} - -void BattleGroundAV::AddPlayer(Player *plr) -{ - BattleGround::AddPlayer(plr); - //create score and add it to map, default values are set in constructor - BattleGroundAVScore* sc = new BattleGroundAVScore; - m_PlayerScores[plr->GetGUID()] = sc; - if (m_MaxLevel == 0) - m_MaxLevel=(plr->getLevel()%10 == 0)? plr->getLevel() : (plr->getLevel()-(plr->getLevel()%10))+10; //TODO: just look at the code \^_^/ --but queue-info should provide this information.. - -} - -void BattleGroundAV::EndBattleGround(uint32 winner) -{ - //calculate bonuskills for both teams: - //first towers: - uint8 kills[2]={0,0}; //0=ally 1=horde - uint8 rep[2]={0,0}; //0=ally 1=horde - for (BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i) - { - if (m_Nodes[i].State == POINT_CONTROLED) - { - if (m_Nodes[i].Owner == ALLIANCE) - { - rep[0] += BG_AV_REP_SURVIVING_TOWER; - kills[0] += BG_AV_KILL_SURVIVING_TOWER; - } - else - { - rep[0] += BG_AV_KILL_SURVIVING_TOWER; - kills[1] += BG_AV_KILL_SURVIVING_TOWER; - } - } - } - - for (int i=0; i <= 1; i++) //0=ally 1=horde - { - if (m_CaptainAlive[i]) - { - kills[i] += BG_AV_KILL_SURVIVING_CAPTAIN; - rep[i] += BG_AV_REP_SURVIVING_CAPTAIN; - } - if (rep[i] != 0) - RewardReputationToTeam((i == 0)?730:729,rep[i],(i == 0)?ALLIANCE:HORDE); - if (kills[i] != 0) - RewardHonorToTeam(GetBonusHonor(kills[i]),(i == 0)?ALLIANCE:HORDE); - } - - //TODO add enterevademode for all attacking creatures - BattleGround::EndBattleGround(winner); -} - -void BattleGroundAV::RemovePlayer(Player* plr,uint64 /*guid*/) -{ - if (!plr) - { - sLog.outError("bg_AV no player at remove"); - return; - } - //TODO search more buffs - plr->RemoveAurasDueToSpell(AV_BUFF_ARMOR); - plr->RemoveAurasDueToSpell(AV_BUFF_A_CAPTAIN); - plr->RemoveAurasDueToSpell(AV_BUFF_H_CAPTAIN); -} - -void BattleGroundAV::HandleAreaTrigger(Player *Source, uint32 Trigger) -{ - // this is wrong way to implement these things. On official it done by gameobject spell cast. - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - uint32 SpellId = 0; - switch(Trigger) - { - case 95: - case 2608: - if (Source->GetTeam() != ALLIANCE) - Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal"); - else - Source->LeaveBattleground(); - break; - case 2606: - if (Source->GetTeam() != HORDE) - Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal"); - else - Source->LeaveBattleground(); - break; - case 3326: - case 3327: - case 3328: - case 3329: - case 3330: - case 3331: - //Source->Unmount(); - break; - default: - sLog.outDebug("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); -// Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); - break; - } - - if (SpellId) - Source->CastSpell(Source, SpellId, true); -} - -void BattleGroundAV::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) -{ - - BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); - if (itr == m_PlayerScores.end()) // player not found... - return; - - switch(type) - { - case SCORE_GRAVEYARDS_ASSAULTED: - ((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted += value; - break; - case SCORE_GRAVEYARDS_DEFENDED: - ((BattleGroundAVScore*)itr->second)->GraveyardsDefended += value; - break; - case SCORE_TOWERS_ASSAULTED: - ((BattleGroundAVScore*)itr->second)->TowersAssaulted += value; - break; - case SCORE_TOWERS_DEFENDED: - ((BattleGroundAVScore*)itr->second)->TowersDefended += value; - break; - case SCORE_MINES_CAPTURED: - ((BattleGroundAVScore*)itr->second)->MinesCaptured += value; - break; - case SCORE_LEADERS_KILLED: - ((BattleGroundAVScore*)itr->second)->LeadersKilled += value; - break; - case SCORE_SECONDARY_OBJECTIVES: - ((BattleGroundAVScore*)itr->second)->SecondaryObjectives += value; - break; - default: - BattleGround::UpdatePlayerScore(Source,type,value, doAddHonor); - break; - } -} - -void BattleGroundAV::EventPlayerDestroyedPoint(BG_AV_Nodes node) -{ - - uint32 object = GetObjectThroughNode(node); - sLog.outDebug("bg_av: player destroyed point node %i object %i",node,object); - - //despawn banner - SpawnBGObject(object, RESPAWN_ONE_DAY); - DestroyNode(node); - UpdateNodeWorldState(node); - - uint32 owner = m_Nodes[node].Owner; - if (IsTower(node)) - { - uint8 tmp = node-BG_AV_NODES_DUNBALDAR_SOUTH; - //despawn marshal - if (m_BgCreatures[AV_CPLACE_A_MARSHAL_SOUTH + tmp]) - DelCreature(AV_CPLACE_A_MARSHAL_SOUTH + tmp); - else - sLog.outError("BG_AV: playerdestroyedpoint: marshal %i doesn't exist",AV_CPLACE_A_MARSHAL_SOUTH + tmp); - //spawn destroyed aura - for (uint8 i=0; i <= 9; i++) - SpawnBGObject(BG_AV_OBJECT_BURN_DUNBALDAR_SOUTH + i + (tmp * 10),RESPAWN_IMMEDIATELY); - - UpdateScore((owner == ALLIANCE) ? HORDE : ALLIANCE, (-1)*BG_AV_RES_TOWER); - RewardReputationToTeam((owner == ALLIANCE)?730:729,BG_AV_REP_TOWER,owner); - RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_TOWER),owner); - - SpawnBGObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+GetTeamIndexByTeamId(owner)+(2*tmp),RESPAWN_ONE_DAY); - SpawnBGObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+GetTeamIndexByTeamId(owner)+(2*tmp),RESPAWN_ONE_DAY); - } - else - { - if (owner == ALLIANCE) - SpawnBGObject(object-11, RESPAWN_IMMEDIATELY); - else - SpawnBGObject(object+11, RESPAWN_IMMEDIATELY); - SpawnBGObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+3*node,RESPAWN_ONE_DAY); - SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+GetTeamIndexByTeamId(owner)+3*node,RESPAWN_IMMEDIATELY); - PopulateNode(node); - if (node == BG_AV_NODES_SNOWFALL_GRAVE) //snowfall eyecandy - { - for (uint8 i = 0; i < 4; i++) - { - SpawnBGObject(((owner == ALLIANCE)?BG_AV_OBJECT_SNOW_EYECANDY_PA : BG_AV_OBJECT_SNOW_EYECANDY_PH)+i,RESPAWN_ONE_DAY); - SpawnBGObject(((owner == ALLIANCE)?BG_AV_OBJECT_SNOW_EYECANDY_A : BG_AV_OBJECT_SNOW_EYECANDY_H)+i,RESPAWN_IMMEDIATELY); - } - } - } - //send a nice message to all :) - char buf[256]; - if (IsTower(node)) - sprintf(buf, GetTrinityString(LANG_BG_AV_TOWER_TAKEN) , GetNodeName(node),(owner == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE)); - else - sprintf(buf, GetTrinityString(LANG_BG_AV_GRAVE_TAKEN) , GetNodeName(node),(owner == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) :GetTrinityString(LANG_BG_AV_HORDE)); - - Creature* creature = GetBGCreature(AV_CPLACE_HERALD); - if (creature) - YellToAll(creature,buf,LANG_UNIVERSAL); -} - -void BattleGroundAV::ChangeMineOwner(uint8 mine, uint32 team, bool initial) -{ //mine=0 northmine mine=1 southmin -//changing the owner results in setting respawntim to infinite for current creatures, spawning new mine owners creatures and changing the chest-objects so that the current owning team can use them - assert(mine == AV_NORTH_MINE || mine == AV_SOUTH_MINE); - if (team != ALLIANCE && team != HORDE) - team = AV_NEUTRAL_TEAM; - else - PlaySoundToAll((team == ALLIANCE)?AV_SOUND_ALLIANCE_GOOD:AV_SOUND_HORDE_GOOD); - - if (m_Mine_Owner[mine] == team && !initial) - return; - m_Mine_PrevOwner[mine] = m_Mine_Owner[mine]; - m_Mine_Owner[mine] = team; - - if (!initial) - { - sLog.outDebug("bg_av depopulating mine %i (0=north,1=south)",mine); - if (mine == AV_SOUTH_MINE) - for (uint16 i=AV_CPLACE_MINE_S_S_MIN; i <= AV_CPLACE_MINE_S_S_MAX; i++) - if (m_BgCreatures[i]) - DelCreature(i); //TODO just set the respawntime to 999999 - for (uint16 i=((mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_1_MIN:AV_CPLACE_MINE_S_1_MIN); i <= ((mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_3:AV_CPLACE_MINE_S_3); i++) - if (m_BgCreatures[i]) - DelCreature(i); //TODO here also - } - SendMineWorldStates(mine); - - sLog.outDebug("bg_av populating mine %i (0=north,1=south)",mine); - uint16 miner; - //also neutral team exists.. after a big time, the neutral team tries to conquer the mine - if (mine == AV_NORTH_MINE) - { - if (team == ALLIANCE) - miner = AV_NPC_N_MINE_A_1; - else if (team == HORDE) - miner = AV_NPC_N_MINE_H_1; - else - miner = AV_NPC_N_MINE_N_1; - } - else - { - uint16 cinfo; - if (team == ALLIANCE) - miner = AV_NPC_S_MINE_A_1; - else if (team == HORDE) - miner = AV_NPC_S_MINE_H_1; - else - miner = AV_NPC_S_MINE_N_1; - //vermin - sLog.outDebug("spawning vermin"); - if (team == ALLIANCE) - cinfo = AV_NPC_S_MINE_A_3; - else if (team == HORDE) - cinfo = AV_NPC_S_MINE_H_3; - else - cinfo = AV_NPC_S_MINE_N_S; - for (uint16 i=AV_CPLACE_MINE_S_S_MIN; i <= AV_CPLACE_MINE_S_S_MAX; i++) - AddAVCreature(cinfo,i); - } - for (uint16 i=((mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_1_MIN:AV_CPLACE_MINE_S_1_MIN); i <= ((mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_1_MAX:AV_CPLACE_MINE_S_1_MAX); i++) - AddAVCreature(miner,i); - //the next chooses randomly between 2 cretures - for (uint16 i=((mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_2_MIN:AV_CPLACE_MINE_S_2_MIN); i <= ((mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_2_MAX:AV_CPLACE_MINE_S_2_MAX); i++) - AddAVCreature(miner+(urand(1,2)),i); - AddAVCreature(miner+3,(mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_3:AV_CPLACE_MINE_S_3); - //because the gameobjects in this mine have changed, update all surrounding players: -// for (uint16 i = ((mine == AV_NORTH_MINE)?BG_AV_OBJECT_MINE_SUPPLY_N_MIN:BG_AV_OBJECT_MINE_SUPPLY_N_MIN); i <= ((mine == AV_NORTH_MINE)?BG_AV_OBJECT_MINE_SUPPLY_N_MAX:BG_AV_OBJECT_MINE_SUPPLY_N_MAX); i++) -// { - //TODO: add gameobject-update code -// } - if (team == ALLIANCE || team == HORDE) - { - m_Mine_Reclaim_Timer[mine]=AV_MINE_RECLAIM_TIMER; - char buf[256]; - sprintf(buf, GetTrinityString(LANG_BG_AV_MINE_TAKEN), GetTrinityString((mine == AV_NORTH_MINE) ? LANG_BG_AV_MINE_NORTH : LANG_BG_AV_MINE_SOUTH), (team == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE)); - Creature* creature = GetBGCreature(AV_CPLACE_HERALD); - if (creature) - YellToAll(creature,buf,LANG_UNIVERSAL); - } - else - { - if (mine == AV_SOUTH_MINE) //i think this gets called all the time - { - Creature* creature = GetBGCreature(AV_CPLACE_MINE_S_3); - YellToAll(creature,LANG_BG_AV_S_MINE_BOSS_CLAIMS,LANG_UNIVERSAL); - } - } - return; -} - -bool BattleGroundAV::PlayerCanDoMineQuest(int32 GOId,uint32 team) -{ - if (GOId == BG_AV_OBJECTID_MINE_N) - return (m_Mine_Owner[AV_NORTH_MINE] == team); - if (GOId == BG_AV_OBJECTID_MINE_S) - return (m_Mine_Owner[AV_SOUTH_MINE] == team); - return true; //cause it's no mine'object it is ok if this is true -} - -void BattleGroundAV::PopulateNode(BG_AV_Nodes node) -{ - uint32 owner = m_Nodes[node].Owner; - assert(owner); - - uint32 c_place = AV_CPLACE_DEFENSE_STORM_AID + (4 * node); - uint32 creatureid; - if (IsTower(node)) - creatureid=(owner == ALLIANCE)?AV_NPC_A_TOWERDEFENSE:AV_NPC_H_TOWERDEFENSE; - else - { - uint8 team2 = GetTeamIndexByTeamId(owner); - if (m_Team_QuestStatus[team2][0] < 500) - creatureid = (owner == ALLIANCE)? AV_NPC_A_GRAVEDEFENSE0 : AV_NPC_H_GRAVEDEFENSE0; - else if (m_Team_QuestStatus[team2][0] < 1000) - creatureid = (owner == ALLIANCE)? AV_NPC_A_GRAVEDEFENSE1 : AV_NPC_H_GRAVEDEFENSE1; - else if (m_Team_QuestStatus[team2][0] < 1500) - creatureid = (owner == ALLIANCE)? AV_NPC_A_GRAVEDEFENSE2 : AV_NPC_H_GRAVEDEFENSE2; - else - creatureid = (owner == ALLIANCE)? AV_NPC_A_GRAVEDEFENSE3 : AV_NPC_H_GRAVEDEFENSE3; - //spiritguide - if (m_BgCreatures[node]) - DelCreature(node); - if (!AddSpiritGuide(node, BG_AV_CreaturePos[node][0], BG_AV_CreaturePos[node][1], BG_AV_CreaturePos[node][2], BG_AV_CreaturePos[node][3], owner)) - sLog.outError("AV: couldn't spawn spiritguide at node %i",node); - - } - for (uint8 i=0; i<4; i++) - AddAVCreature(creatureid,c_place+i); - - if (node >= BG_AV_NODES_MAX)//fail safe - return; - Creature* trigger = GetBGCreature(node + 302);//0-302 other creatures - if (!trigger) - trigger = AddCreature(WORLD_TRIGGER,node + 302,owner,BG_AV_CreaturePos[node + 302][0],BG_AV_CreaturePos[node + 302][1],BG_AV_CreaturePos[node + 302][2],BG_AV_CreaturePos[node + 302][3]); - - //add bonus honor aura trigger creature when node is accupied - //cast bonus aura (+50% honor in 25yards) - //aura should only apply to players who have accupied the node, set correct faction for trigger - if (trigger) - { - if (owner != ALLIANCE && owner != HORDE)//node can be neutral, remove trigger - { - DelCreature(node + 302); - return; - } - trigger->setFaction(owner == ALLIANCE ? 84 : 83); - trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false); - } -} -void BattleGroundAV::DePopulateNode(BG_AV_Nodes node) -{ - uint32 c_place = AV_CPLACE_DEFENSE_STORM_AID + (4 * node); - for (uint8 i=0; i<4; i++) - if (m_BgCreatures[c_place+i]) - DelCreature(c_place+i); - //spiritguide - if (!IsTower(node) && m_BgCreatures[node]) - DelCreature(node); - - //remove bonus honor aura trigger creature when node is lost - if(node < BG_AV_NODES_MAX)//fail safe - DelCreature(node + 302);//NULL checks are in DelCreature! 0-302 spirit guides -} - -const BG_AV_Nodes BattleGroundAV::GetNodeThroughObject(uint32 object) -{ - sLog.outDebug("bg_AV getnodethroughobject %i",object); - if (object <= BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER) - return BG_AV_Nodes(object); - if (object <= BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_HUT) - return BG_AV_Nodes(object - 11); - if (object <= BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_WTOWER) - return BG_AV_Nodes(object - 7); - if (object <= BG_AV_OBJECT_FLAG_C_H_STONEHEART_BUNKER) - return BG_AV_Nodes(object -22); - if (object <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT) - return BG_AV_Nodes(object - 33); - if (object <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER) - return BG_AV_Nodes(object - 29); - if (object == BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE) - return BG_AV_NODES_SNOWFALL_GRAVE; - sLog.outError("BattleGroundAV: ERROR! GetPlace got a wrong object :("); - assert(false); - return BG_AV_Nodes(0); -} - -const uint32 BattleGroundAV::GetObjectThroughNode(BG_AV_Nodes node) -{ //this function is the counterpart to GetNodeThroughObject() - sLog.outDebug("bg_AV GetObjectThroughNode %i",node); - if (m_Nodes[node].Owner == ALLIANCE) - { - if (m_Nodes[node].State == POINT_ASSAULTED) - { - if (node <= BG_AV_NODES_FROSTWOLF_HUT) - return node+11; - if (node >= BG_AV_NODES_ICEBLOOD_TOWER && node <= BG_AV_NODES_FROSTWOLF_WTOWER) - return node+7; - } - else if (m_Nodes[node].State == POINT_CONTROLED) - if (node <= BG_AV_NODES_STONEHEART_BUNKER) - return node; - } - else if (m_Nodes[node].Owner == HORDE) - { - if (m_Nodes[node].State == POINT_ASSAULTED) - if (node <= BG_AV_NODES_STONEHEART_BUNKER) - return node+22; - else if (m_Nodes[node].State == POINT_CONTROLED) - { - if (node <= BG_AV_NODES_FROSTWOLF_HUT) - return node+33; - if (node >= BG_AV_NODES_ICEBLOOD_TOWER && node <= BG_AV_NODES_FROSTWOLF_WTOWER) - return node+29; - } - } - else if (m_Nodes[node].Owner == AV_NEUTRAL_TEAM) - return BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE; - sLog.outError("BattleGroundAV: Error! GetPlaceNode couldn't resolve node %i",node); - assert(false); - return 0; -} - -//called when using banner - -void BattleGroundAV::EventPlayerClickedOnFlag(Player *source, GameObject* target_obj) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - int32 object = GetObjectType(target_obj->GetGUID()); - sLog.outDebug("BG_AV using gameobject %i with type %i",target_obj->GetEntry(),object); - if (object < 0) - return; - switch(target_obj->GetEntry()) - { - case BG_AV_OBJECTID_BANNER_A: - case BG_AV_OBJECTID_BANNER_A_B: - case BG_AV_OBJECTID_BANNER_H: - case BG_AV_OBJECTID_BANNER_H_B: - case BG_AV_OBJECTID_BANNER_SNOWFALL_N: - EventPlayerAssaultsPoint(source, object); - break; - case BG_AV_OBJECTID_BANNER_CONT_A: - case BG_AV_OBJECTID_BANNER_CONT_A_B: - case BG_AV_OBJECTID_BANNER_CONT_H: - case BG_AV_OBJECTID_BANNER_CONT_H_B: - EventPlayerDefendsPoint(source, object); - break; - default: - break; - } -} - -void BattleGroundAV::EventPlayerDefendsPoint(Player* player, uint32 object) -{ - assert(GetStatus() == STATUS_IN_PROGRESS); - BG_AV_Nodes node = GetNodeThroughObject(object); - - uint32 owner = m_Nodes[node].Owner; //maybe should name it prevowner - uint32 team = player->GetTeam(); - - if (owner == player->GetTeam() || m_Nodes[node].State != POINT_ASSAULTED) - return; - if (m_Nodes[node].TotalOwner == AV_NEUTRAL_TEAM) - { //until snowfall doesn't belong to anyone it is better handled in assault-code - assert(node == BG_AV_NODES_SNOWFALL_GRAVE); //currently the only neutral grave - EventPlayerAssaultsPoint(player,object); - return; - } - sLog.outDebug("player defends point object: %i node: %i",object,node); - if (m_Nodes[node].PrevOwner != team) - { - sLog.outError("BG_AV: player defends point which doesn't belong to his team %i",node); - return; - } - - //spawn new go :) - if (m_Nodes[node].Owner == ALLIANCE) - SpawnBGObject(object+22, RESPAWN_IMMEDIATELY); //spawn horde banner - else - SpawnBGObject(object-22, RESPAWN_IMMEDIATELY); //spawn alliance banner - - if (!IsTower(node)) - { - SpawnBGObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+3*node,RESPAWN_ONE_DAY); - SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+GetTeamIndexByTeamId(team)+3*node,RESPAWN_IMMEDIATELY); - } - // despawn old go - SpawnBGObject(object, RESPAWN_ONE_DAY); - - DefendNode(node,team); - PopulateNode(node); - UpdateNodeWorldState(node); - - if (IsTower(node)) - { - //spawn big flag+aura on top of tower - SpawnBGObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == ALLIANCE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); - SpawnBGObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == HORDE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); - SpawnBGObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == ALLIANCE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); - SpawnBGObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == HORDE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); - } - else if (node == BG_AV_NODES_SNOWFALL_GRAVE) //snowfall eyecandy - { - for (uint8 i = 0; i < 4; i++) - { - SpawnBGObject(((owner == ALLIANCE)?BG_AV_OBJECT_SNOW_EYECANDY_PA : BG_AV_OBJECT_SNOW_EYECANDY_PH)+i,RESPAWN_ONE_DAY); - SpawnBGObject(((team == ALLIANCE)?BG_AV_OBJECT_SNOW_EYECANDY_A : BG_AV_OBJECT_SNOW_EYECANDY_H)+i,RESPAWN_IMMEDIATELY); - } - } - //send a nice message to all :) - char buf[256]; - sprintf(buf, GetTrinityString((IsTower(node)) ? LANG_BG_AV_TOWER_DEFENDED : LANG_BG_AV_GRAVE_DEFENDED), GetNodeName(node),(team == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE)); - Creature* creature = GetBGCreature(AV_CPLACE_HERALD); - if (creature) - YellToAll(creature,buf,LANG_UNIVERSAL); - //update the statistic for the defending player - UpdatePlayerScore(player, (IsTower(node)) ? SCORE_TOWERS_DEFENDED : SCORE_GRAVEYARDS_DEFENDED, 1); - if (IsTower(node)) - PlaySoundToAll(AV_SOUND_BOTH_TOWER_DEFEND); - else - PlaySoundToAll((team == ALLIANCE)?AV_SOUND_ALLIANCE_GOOD:AV_SOUND_HORDE_GOOD); -} - -void BattleGroundAV::EventPlayerAssaultsPoint(Player* player, uint32 object) -{ - assert(GetStatus() == STATUS_IN_PROGRESS); - - BG_AV_Nodes node = GetNodeThroughObject(object); - uint32 owner = m_Nodes[node].Owner; //maybe name it prevowner - uint32 team = player->GetTeam(); - sLog.outDebug("bg_av: player assaults point object %i node %i",object,node); - if (owner == team || team == m_Nodes[node].TotalOwner) - return; //surely a gm used this object - - if (node == BG_AV_NODES_SNOWFALL_GRAVE) //snowfall is a bit special in capping + it gets eyecandy stuff - { - if (object == BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE) //initial capping - { - assert(owner == AV_NEUTRAL_TEAM && m_Nodes[node].TotalOwner == AV_NEUTRAL_TEAM); - if (team == ALLIANCE) - SpawnBGObject(BG_AV_OBJECT_FLAG_C_A_SNOWFALL_GRAVE, RESPAWN_IMMEDIATELY); - else - SpawnBGObject(BG_AV_OBJECT_FLAG_C_H_SNOWFALL_GRAVE, RESPAWN_IMMEDIATELY); - SpawnBGObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+3*node,RESPAWN_IMMEDIATELY); //neutral aura spawn - } - else if (m_Nodes[node].TotalOwner == AV_NEUTRAL_TEAM) //recapping, when no team owns this node realy - { - assert(m_Nodes[node].State != POINT_CONTROLED); - if (team == ALLIANCE) - SpawnBGObject(object-11, RESPAWN_IMMEDIATELY); - else - SpawnBGObject(object+11, RESPAWN_IMMEDIATELY); - } - //eyecandy - uint32 spawn,despawn; - if (team == ALLIANCE) - { - despawn = (m_Nodes[node].State == POINT_ASSAULTED)?BG_AV_OBJECT_SNOW_EYECANDY_PH : BG_AV_OBJECT_SNOW_EYECANDY_H; - spawn = BG_AV_OBJECT_SNOW_EYECANDY_PA; - } - else - { - despawn = (m_Nodes[node].State == POINT_ASSAULTED)?BG_AV_OBJECT_SNOW_EYECANDY_PA : BG_AV_OBJECT_SNOW_EYECANDY_A; - spawn = BG_AV_OBJECT_SNOW_EYECANDY_PH; - } - for (uint8 i = 0; i < 4; i++) - { - SpawnBGObject(despawn+i,RESPAWN_ONE_DAY); - SpawnBGObject(spawn+i,RESPAWN_IMMEDIATELY); - } - } - - //if snowfall gots capped it can be handled like all other graveyards - if (m_Nodes[node].TotalOwner != AV_NEUTRAL_TEAM) - { - assert(m_Nodes[node].Owner != AV_NEUTRAL_TEAM); - if (team == ALLIANCE) - SpawnBGObject(object-22, RESPAWN_IMMEDIATELY); - else - SpawnBGObject(object+22, RESPAWN_IMMEDIATELY); - if (IsTower(node)) - { //spawning/despawning of bigflag+aura - SpawnBGObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == ALLIANCE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); - SpawnBGObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == HORDE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); - SpawnBGObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == ALLIANCE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); - SpawnBGObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == HORDE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); - } - else - { - //spawning/despawning of aura - SpawnBGObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+3*node,RESPAWN_IMMEDIATELY); //neutral aura spawn - SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+GetTeamIndexByTeamId(owner)+3*node,RESPAWN_ONE_DAY); //teeamaura despawn - // Those who are waiting to resurrect at this object are taken to the closest own object's graveyard - std::vector ghost_list = m_ReviveQueue[m_BgCreatures[node]]; - if (!ghost_list.empty()) - { - Player *plr; - WorldSafeLocsEntry const *ClosestGrave = NULL; - for (std::vector::iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr) - { - plr = objmgr.GetPlayer(*ghost_list.begin()); - if (!plr) - continue; - if (!ClosestGrave) - ClosestGrave = GetClosestGraveYard(plr); - else - plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation()); - } - m_ReviveQueue[m_BgCreatures[node]].clear(); - } - } - DePopulateNode(node); - } - - SpawnBGObject(object, RESPAWN_ONE_DAY); //delete old banner - AssaultNode(node,team); - UpdateNodeWorldState(node); - - //send a nice message to all :) - char buf[256]; - sprintf(buf, (IsTower(node)) ? GetTrinityString(LANG_BG_AV_TOWER_ASSAULTED) : GetTrinityString(LANG_BG_AV_GRAVE_ASSAULTED), GetNodeName(node), (team == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE)); - Creature* creature = GetBGCreature(AV_CPLACE_HERALD); - if (creature) - YellToAll(creature,buf,LANG_UNIVERSAL); - //update the statistic for the assaulting player - UpdatePlayerScore(player, (IsTower(node)) ? SCORE_TOWERS_ASSAULTED : SCORE_GRAVEYARDS_ASSAULTED, 1); - PlaySoundToAll((team == ALLIANCE)?AV_SOUND_ALLIANCE_ASSAULTS:AV_SOUND_HORDE_ASSAULTS); -} - -void BattleGroundAV::FillInitialWorldStates(WorldPacket& data) -{ - bool stateok; - //graveyards - for (uint8 i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; i++) - { - for (uint8 j =1; j <= 3; j+=2) - {//j=1=assaulted j=3=controled - stateok = (m_Nodes[i].State == j); - data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j,ALLIANCE)]) << uint32((m_Nodes[i].Owner == ALLIANCE && stateok)?1:0); - data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j,HORDE)]) << uint32((m_Nodes[i].Owner == HORDE && stateok)?1:0); - } - } - - //towers - for (uint8 i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_MAX; i++) - for (uint8 j =1; j <= 3; j+=2) - {//j=1=assaulted j=3=controled //i dont have j=2=destroyed cause destroyed is the same like enemy-team controll - stateok = (m_Nodes[i].State == j || (m_Nodes[i].State == POINT_DESTROYED && j == 3)); - data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j,ALLIANCE)]) << uint32((m_Nodes[i].Owner == ALLIANCE && stateok)?1:0); - data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j,HORDE)]) << uint32((m_Nodes[i].Owner == HORDE && stateok)?1:0); - } - if (m_Nodes[BG_AV_NODES_SNOWFALL_GRAVE].Owner == AV_NEUTRAL_TEAM) //cause neutral teams aren't handled generic - data << uint32(AV_SNOWFALL_N) << uint32(1); - data << uint32(AV_Alliance_Score) << uint32(m_Team_Scores[0]); - data << uint32(AV_Horde_Score) << uint32(m_Team_Scores[1]); - if (GetStatus() == STATUS_IN_PROGRESS){ //only if game started the teamscores are displayed - data << uint32(AV_SHOW_A_SCORE) << uint32(1); - data << uint32(AV_SHOW_H_SCORE) << uint32(1); - } - else - { - data << uint32(AV_SHOW_A_SCORE) << uint32(0); - data << uint32(AV_SHOW_H_SCORE) << uint32(0); - } - SendMineWorldStates(AV_NORTH_MINE); - SendMineWorldStates(AV_SOUTH_MINE); -} - -const uint8 BattleGroundAV::GetWorldStateType(uint8 state, uint16 team) //this is used for node worldstates and returns values which fit good into the worldstatesarray -{ - //neutral stuff cant get handled (currently its only snowfall) - assert(team != AV_NEUTRAL_TEAM); - //a_c a_a h_c h_a the positions in worldstate-array - if (team == ALLIANCE) - { - if (state == POINT_CONTROLED || state == POINT_DESTROYED) - return 0; - if (state == POINT_ASSAULTED) - return 1; - } - if (team == HORDE) - { - if (state == POINT_DESTROYED || state == POINT_CONTROLED) - return 2; - if (state == POINT_ASSAULTED) - return 3; - } - sLog.outError("BG_AV: should update a strange worldstate state:%i team:%i",state,team); - return 5; //this will crash the game, but i want to know if something is wrong here -} - -void BattleGroundAV::UpdateNodeWorldState(BG_AV_Nodes node) -{ - UpdateWorldState(BG_AV_NodeWorldStates[node][GetWorldStateType(m_Nodes[node].State,m_Nodes[node].Owner)],1); - if (m_Nodes[node].PrevOwner == AV_NEUTRAL_TEAM) //currently only snowfall is supported as neutral node (i don't want to make an extra row (neutral states) in worldstatesarray just for one node - UpdateWorldState(AV_SNOWFALL_N,0); - else - UpdateWorldState(BG_AV_NodeWorldStates[node][GetWorldStateType(m_Nodes[node].PrevState,m_Nodes[node].PrevOwner)],0); -} - -void BattleGroundAV::SendMineWorldStates(uint32 mine) -{ - assert(mine == AV_NORTH_MINE || mine == AV_SOUTH_MINE); -// currently i'm sure, that this works (: -// assert(m_Mine_PrevOwner[mine] == ALLIANCE || m_Mine_PrevOwner[mine] == HORDE || m_Mine_PrevOwner[mine] == AV_NEUTRAL_TEAM); -// assert(m_Mine_Owner[mine] == ALLIANCE || m_Mine_Owner[mine] == HORDE || m_Mine_Owner[mine] == AV_NEUTRAL_TEAM); - - uint8 owner,prevowner,mine2; //those variables are needed to access the right worldstate in the BG_AV_MineWorldStates array - mine2 = (mine == AV_NORTH_MINE)?0:1; - if (m_Mine_PrevOwner[mine] == ALLIANCE) - prevowner = 0; - else if (m_Mine_PrevOwner[mine] == HORDE) - prevowner = 2; - else - prevowner = 1; - if (m_Mine_Owner[mine] == ALLIANCE) - owner = 0; - else if (m_Mine_Owner[mine] == HORDE) - owner = 2; - else - owner = 1; - - UpdateWorldState(BG_AV_MineWorldStates[mine2][owner],1); - if (prevowner != owner) - UpdateWorldState(BG_AV_MineWorldStates[mine2][prevowner],0); -} - -WorldSafeLocsEntry const* BattleGroundAV::GetClosestGraveYard(Player* player) -{ - WorldSafeLocsEntry const* pGraveyard = NULL; - WorldSafeLocsEntry const* entry = NULL; - float dist = 0; - float minDist = 0; - float x, y; - - player->GetPosition(x, y); - - pGraveyard = sWorldSafeLocsStore.LookupEntry(BG_AV_GraveyardIds[GetTeamIndexByTeamId(player->GetTeam())+7]); - minDist = (pGraveyard->x - x)*(pGraveyard->x - x)+(pGraveyard->y - y)*(pGraveyard->y - y); - - for (uint8 i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i) - if (m_Nodes[i].Owner == player->GetTeam() && m_Nodes[i].State == POINT_CONTROLED) - { - entry = sWorldSafeLocsStore.LookupEntry(BG_AV_GraveyardIds[i]); - if (entry) - { - dist = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y); - if (dist < minDist) - { - minDist = dist; - pGraveyard = entry; - } - } - } - return pGraveyard; -} - -bool BattleGroundAV::SetupBattleGround() -{ - // Create starting objects - if ( - // alliance gates - !AddObject(BG_AV_OBJECT_DOOR_A, BG_AV_OBJECTID_GATE_A, BG_AV_DoorPositons[0][0],BG_AV_DoorPositons[0][1],BG_AV_DoorPositons[0][2],BG_AV_DoorPositons[0][3],0,0,sin(BG_AV_DoorPositons[0][3]/2),cos(BG_AV_DoorPositons[0][3]/2),RESPAWN_IMMEDIATELY) - // horde gates - || !AddObject(BG_AV_OBJECT_DOOR_H, BG_AV_OBJECTID_GATE_H, BG_AV_DoorPositons[1][0],BG_AV_DoorPositons[1][1],BG_AV_DoorPositons[1][2],BG_AV_DoorPositons[1][3],0,0,sin(BG_AV_DoorPositons[1][3]/2),cos(BG_AV_DoorPositons[1][3]/2),RESPAWN_IMMEDIATELY)) - { - sLog.outErrorDb("BatteGroundAV: Failed to spawn some object BattleGround not created!1"); - return false; - } - - //spawn node-objects - for (uint8 i = BG_AV_NODES_FIRSTAID_STATION ; i < BG_AV_NODES_MAX; ++i) - { - if (i <= BG_AV_NODES_FROSTWOLF_HUT) - { - if (!AddObject(i,BG_AV_OBJECTID_BANNER_A_B,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(i+11,BG_AV_OBJECTID_BANNER_CONT_A_B,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(i+33,BG_AV_OBJECTID_BANNER_H_B,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(i+22,BG_AV_OBJECTID_BANNER_CONT_H_B,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) - //aura - || !AddObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+i*3,BG_AV_OBJECTID_AURA_N,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+i*3,BG_AV_OBJECTID_AURA_A,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AV_OBJECT_AURA_H_FIRSTAID_STATION+i*3,BG_AV_OBJECTID_AURA_H,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY)) - { - sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!2"); - return false; - } - } - else //towers - { - if (i <= BG_AV_NODES_STONEHEART_BUNKER) //alliance towers - { - if (!AddObject(i,BG_AV_OBJECTID_BANNER_A,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(i+22,BG_AV_OBJECTID_BANNER_CONT_H,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_AURA_A,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_AURA_N,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_TOWER_BANNER_A,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_TOWER_BANNER_PH,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY)) - { - sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!3"); - return false; - } - } - else //horde towers - { - if (!AddObject(i+7,BG_AV_OBJECTID_BANNER_CONT_A,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(i+29,BG_AV_OBJECTID_BANNER_H,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_AURA_N,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_AURA_H,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_TOWER_BANNER_PA,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY) - || !AddObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_TOWER_BANNER_H,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY)) - { - sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!4"); - return false; - } - } - for (uint8 j=0; j <= 9; j++) //burning aura - { - if (!AddObject(BG_AV_OBJECT_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j,BG_AV_OBJECTID_FIRE,BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][0],BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][1],BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][2],BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3]/2),RESPAWN_ONE_DAY)) - { - sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!5.%i",i); - return false; - } - } - } - } - for (uint8 i=0; i<2; i++) //burning aura for buildings - { - for (uint8 j=0; j <= 9; j++) - { - if (j<5) - { - if (!AddObject(BG_AV_OBJECT_BURN_BUILDING_ALLIANCE+(i*10)+j,BG_AV_OBJECTID_SMOKE,BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][0],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][1],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][2],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2),RESPAWN_ONE_DAY)) - { - sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!6.%i",i); - return false; - } - } - else - { - if (!AddObject(BG_AV_OBJECT_BURN_BUILDING_ALLIANCE+(i*10)+j,BG_AV_OBJECTID_FIRE,BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][0],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][1],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][2],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2),RESPAWN_ONE_DAY)) - { - sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!7.%i",i); - return false; - } - } - } - } - for (uint16 i= 0; i <= (BG_AV_OBJECT_MINE_SUPPLY_N_MAX-BG_AV_OBJECT_MINE_SUPPLY_N_MIN); i++) - { - if (!AddObject(BG_AV_OBJECT_MINE_SUPPLY_N_MIN+i,BG_AV_OBJECTID_MINE_N,BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][0],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][1],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][2],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3]/2),RESPAWN_ONE_DAY)) - { - sLog.outError("BatteGroundAV: Failed to spawn some mine supplies BattleGround not created!7.5.%i",i); - return false; - } - } - for (uint16 i= 0 ; i <= (BG_AV_OBJECT_MINE_SUPPLY_S_MAX-BG_AV_OBJECT_MINE_SUPPLY_S_MIN); i++) - { - if (!AddObject(BG_AV_OBJECT_MINE_SUPPLY_S_MIN+i,BG_AV_OBJECTID_MINE_S,BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][0],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][1],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][2],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3]/2),RESPAWN_ONE_DAY)) - { - sLog.outError("BatteGroundAV: Failed to spawn some mine supplies BattleGround not created!7.6.%i",i); - return false; - } - } - - if (!AddObject(BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE, BG_AV_OBJECTID_BANNER_SNOWFALL_N ,BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][0],BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][1],BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][2],BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3],0,0,sin(BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3]/2), cos(BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3]/2), RESPAWN_ONE_DAY)) - { - sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!8"); - return false; - } - for (uint8 i = 0; i < 4; i++) - { - if (!AddObject(BG_AV_OBJECT_SNOW_EYECANDY_A+i, BG_AV_OBJECTID_SNOWFALL_CANDY_A ,BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],0,0,sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY) - || !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_PA+i, BG_AV_OBJECTID_SNOWFALL_CANDY_PA ,BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],0,0,sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY) - || !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_H+i, BG_AV_OBJECTID_SNOWFALL_CANDY_H ,BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],0,0,sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY) - || !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_PH+i, BG_AV_OBJECTID_SNOWFALL_CANDY_PH ,BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],0,0,sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY)) - { - sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!9.%i",i); - return false; - } - } - - uint16 i; - sLog.outDebug("Alterac Valley: entering state STATUS_WAIT_JOIN ..."); - // Initial Nodes - for (i = 0; i < BG_AV_OBJECT_MAX; i++) - SpawnBGObject(i, RESPAWN_ONE_DAY); - for (i = BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION; i <= BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE ; i++){ - SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+3*i,RESPAWN_IMMEDIATELY); - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - } - for (i = BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH; i <= BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER ; i++) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - for (i = BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE; i <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER ; i++){ - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - if (i <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT) - SpawnBGObject(BG_AV_OBJECT_AURA_H_FIRSTAID_STATION+3*GetNodeThroughObject(i),RESPAWN_IMMEDIATELY); - } - for (i = BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH; i <= BG_AV_OBJECT_TFLAG_A_STONEHEART_BUNKER; i+=2) - { - SpawnBGObject(i, RESPAWN_IMMEDIATELY); //flag - SpawnBGObject(i+16, RESPAWN_IMMEDIATELY); //aura - } - for (i = BG_AV_OBJECT_TFLAG_H_ICEBLOOD_TOWER; i <= BG_AV_OBJECT_TFLAG_H_FROSTWOLF_WTOWER; i+=2) - { - SpawnBGObject(i, RESPAWN_IMMEDIATELY); //flag - SpawnBGObject(i+16, RESPAWN_IMMEDIATELY); //aura - } - //snowfall and the doors - for (i = BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE; i <= BG_AV_OBJECT_DOOR_A; i++) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - SpawnBGObject(BG_AV_OBJECT_AURA_N_SNOWFALL_GRAVE,RESPAWN_IMMEDIATELY); - - //creatures - sLog.outDebug("BG_AV start poputlating nodes"); - for (BG_AV_Nodes i= BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i) - { - if (m_Nodes[i].Owner) - PopulateNode(i); - } - //all creatures which don't get despawned through the script are static - sLog.outDebug("BG_AV: start spawning static creatures"); - for (i=0; i < AV_STATICCPLACE_MAX; i++) - AddAVCreature(0,i+AV_CPLACE_MAX); - //mainspiritguides: - sLog.outDebug("BG_AV: start spawning spiritguides creatures"); - AddSpiritGuide(7, BG_AV_CreaturePos[7][0], BG_AV_CreaturePos[7][1], BG_AV_CreaturePos[7][2], BG_AV_CreaturePos[7][3], ALLIANCE); - AddSpiritGuide(8, BG_AV_CreaturePos[8][0], BG_AV_CreaturePos[8][1], BG_AV_CreaturePos[8][2], BG_AV_CreaturePos[8][3], HORDE); - //spawn the marshals (those who get deleted, if a tower gets destroyed) - sLog.outDebug("BG_AV: start spawning marshal creatures"); - for (i=AV_NPC_A_MARSHAL_SOUTH; i <= AV_NPC_H_MARSHAL_WTOWER; i++) - AddAVCreature(i,AV_CPLACE_A_MARSHAL_SOUTH+(i-AV_NPC_A_MARSHAL_SOUTH)); - AddAVCreature(AV_NPC_HERALD,AV_CPLACE_HERALD); - return true; -} - -const char* BattleGroundAV::GetNodeName(BG_AV_Nodes node) -{ - switch (node) - { - case BG_AV_NODES_FIRSTAID_STATION: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_STORM_AID); - case BG_AV_NODES_DUNBALDAR_SOUTH: return GetTrinityString(LANG_BG_AV_NODE_TOWER_DUN_S); - case BG_AV_NODES_DUNBALDAR_NORTH: return GetTrinityString(LANG_BG_AV_NODE_TOWER_DUN_N); - case BG_AV_NODES_STORMPIKE_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_STORMPIKE); - case BG_AV_NODES_ICEWING_BUNKER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_ICEWING); - case BG_AV_NODES_STONEHEART_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_STONE); - case BG_AV_NODES_STONEHEART_BUNKER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_STONE); - case BG_AV_NODES_SNOWFALL_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_SNOW); - case BG_AV_NODES_ICEBLOOD_TOWER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_ICE); - case BG_AV_NODES_ICEBLOOD_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_ICE); - case BG_AV_NODES_TOWER_POINT: return GetTrinityString(LANG_BG_AV_NODE_TOWER_POINT); - case BG_AV_NODES_FROSTWOLF_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_FROST); - case BG_AV_NODES_FROSTWOLF_ETOWER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_FROST_E); - case BG_AV_NODES_FROSTWOLF_WTOWER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_FROST_W); - case BG_AV_NODES_FROSTWOLF_HUT: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_FROST_HUT); - default: - { - sLog.outError("tried to get name for node %u%",node); - return "Unknown"; - break; - } - } -} - -void BattleGroundAV::AssaultNode(BG_AV_Nodes node, uint16 team) -{ - if (m_Nodes[node].TotalOwner == team) - { - sLog.outCrash("Assaulting team is TotalOwner of node"); - assert (false); - } - if (m_Nodes[node].Owner == team) - { - sLog.outCrash("Assaulting team is owner of node"); - assert (false); - } - if (m_Nodes[node].State == POINT_DESTROYED) - { - sLog.outCrash("Destroyed node is being assaulted"); - assert (false); - } - if (m_Nodes[node].State == POINT_ASSAULTED && m_Nodes[node].TotalOwner) //only assault an assaulted node if no totalowner exists - { - sLog.outCrash("Assault on an not assaulted node with total owner"); - assert (false); - } - //the timer gets another time, if the previous owner was 0 == Neutral - m_Nodes[node].Timer = (m_Nodes[node].PrevOwner)? BG_AV_CAPTIME : BG_AV_SNOWFALL_FIRSTCAP; - m_Nodes[node].PrevOwner = m_Nodes[node].Owner; - m_Nodes[node].Owner = team; - m_Nodes[node].PrevState = m_Nodes[node].State; - m_Nodes[node].State = POINT_ASSAULTED; -} - -void BattleGroundAV::DestroyNode(BG_AV_Nodes node) -{ - assert(m_Nodes[node].State == POINT_ASSAULTED); - - m_Nodes[node].TotalOwner = m_Nodes[node].Owner; - m_Nodes[node].PrevOwner = m_Nodes[node].Owner; - m_Nodes[node].PrevState = m_Nodes[node].State; - m_Nodes[node].State = (m_Nodes[node].Tower)? POINT_DESTROYED : POINT_CONTROLED; - m_Nodes[node].Timer = 0; -} - -void BattleGroundAV::InitNode(BG_AV_Nodes node, uint16 team, bool tower) -{ - m_Nodes[node].TotalOwner = team; - m_Nodes[node].Owner = team; - m_Nodes[node].PrevOwner = 0; - m_Nodes[node].State = POINT_CONTROLED; - m_Nodes[node].PrevState = m_Nodes[node].State; - m_Nodes[node].State = POINT_CONTROLED; - m_Nodes[node].Timer = 0; - m_Nodes[node].Tower = tower; -} - -void BattleGroundAV::DefendNode(BG_AV_Nodes node, uint16 team) -{ - assert(m_Nodes[node].TotalOwner == team); - assert(m_Nodes[node].Owner != team); - assert(m_Nodes[node].State != POINT_CONTROLED && m_Nodes[node].State != POINT_DESTROYED); - m_Nodes[node].PrevOwner = m_Nodes[node].Owner; - m_Nodes[node].Owner = team; - m_Nodes[node].PrevState = m_Nodes[node].State; - m_Nodes[node].State = POINT_CONTROLED; - m_Nodes[node].Timer = 0; -} - -void BattleGroundAV::ResetBGSubclass() -{ - m_MaxLevel=0; - for (uint8 i=0; i<2; i++) //forloop for both teams (it just make 0 == alliance and 1 == horde also for both mines 0=north 1=south - { - for (uint8 j=0; j<9; j++) - m_Team_QuestStatus[i][j]=0; - m_Team_Scores[i]=BG_AV_SCORE_INITIAL_POINTS; - m_IsInformedNearVictory[i]=false; - m_CaptainAlive[i] = true; - m_CaptainBuffTimer[i] = 120000 + urand(0,4)* 60; //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes TODO get the right times - m_Mine_Owner[i] = AV_NEUTRAL_TEAM; - m_Mine_PrevOwner[i] = m_Mine_Owner[i]; - } - for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_STONEHEART_GRAVE; ++i) //alliance graves - InitNode(i,ALLIANCE,false); - for (BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_STONEHEART_BUNKER; ++i) //alliance towers - InitNode(i,ALLIANCE,true); - for (BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_GRAVE; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i) //horde graves - InitNode(i,HORDE,false); - for (BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_TOWER; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i) //horde towers - InitNode(i,HORDE,true); - InitNode(BG_AV_NODES_SNOWFALL_GRAVE,AV_NEUTRAL_TEAM,false); //give snowfall neutral owner - - m_Mine_Timer=AV_MINE_TICK_TIMER; - for (uint16 i = 0; i < AV_CPLACE_MAX+AV_STATICCPLACE_MAX; i++) - if (m_BgCreatures[i]) - DelCreature(i); - -} - - diff --git a/src/server/game/BattleGrounds/BattleGroundAV.h b/src/server/game/BattleGrounds/BattleGroundAV.h deleted file mode 100644 index 6d95c7bbc5d..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundAV.h +++ /dev/null @@ -1,1614 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __BATTLEGROUNDAV_H -#define __BATTLEGROUNDAV_H - -class BattleGround; - -#define LANG_BG_AV_A_CAPTAIN_BUFF "Begone. Uncouth scum! The Alliance shall prevail in Alterac Valley!" -#define LANG_BG_AV_H_CAPTAIN_BUFF "Now is the time to attack! For the Horde!" -#define LANG_BG_AV_S_MINE_BOSS_CLAIMS "Snivvle is here! Snivvle claims the Coldtooth Mine!" - -#define BG_AV_CAPTIME 240000 //4:00 -#define BG_AV_SNOWFALL_FIRSTCAP 300000 //5:00 but i also have seen 4:05 - -#define BG_AV_SCORE_INITIAL_POINTS 600 -#define SEND_MSG_NEAR_LOSE 120 - -#define BG_AV_KILL_BOSS 4 -#define BG_AV_REP_BOSS 350 - -#define BG_AV_KILL_CAPTAIN 3 -#define BG_AV_REP_CAPTAIN 125 -#define BG_AV_RES_CAPTAIN 100 - -#define BG_AV_KILL_TOWER 3 -#define BG_AV_REP_TOWER 12 -#define BG_AV_RES_TOWER 75 - -#define BG_AV_GET_COMMANDER 1 //for a safely returned wingcommander -//bonushonor at the end -#define BG_AV_KILL_SURVIVING_TOWER 2 -#define BG_AV_REP_SURVIVING_TOWER 12 - -#define BG_AV_KILL_SURVIVING_CAPTAIN 2 -#define BG_AV_REP_SURVIVING_CAPTAIN 125 - -enum BG_AV_Sounds -{ //TODO: get out if there comes a sound when neutral team captures mine - -/* -8212: - alliance grave assault - alliance tower assault - drek "mlanzenabschaum! In meiner Burg?! Toetet sie all" - nicht immer der sound -8333: - galv "sterbt fuer euch ist kein platz hier" - -8332: - bal "Verschwinde, dreckiger Abschaum! Die Allianz wird im Alteractal " -8174: - horde tower assault - horde grave assault - van "es Sturmlanzenklans, euer General wird angegriffen! Ich fordere Unterst" -8173: - ally grave capture/defend - tower destroy - mine capture - ally wins -8192: - ally tower destroy(only iceblood - found a bug^^) - ally tower defend - horde tower defend -8213 -horde: - grave defend/capture - tower destroy - mine capture - horde wins - */ - - AV_SOUND_NEAR_VICTORY = 8456, //not confirmed yet - - AV_SOUND_ALLIANCE_ASSAULTS = 8212, //tower,grave + enemy boss if someone tries to attack him - AV_SOUND_HORDE_ASSAULTS = 8174, - AV_SOUND_ALLIANCE_GOOD = 8173, //if something good happens for the team: wins(maybe only through killing the boss), captures mine or grave, destroys tower and defends grave - AV_SOUND_HORDE_GOOD = 8213, - AV_SOUND_BOTH_TOWER_DEFEND = 8192, - - AV_SOUND_ALLIANCE_CAPTAIN = 8232, //gets called when someone attacks them and at the beginning after 3min+rand(x)*10sec (maybe buff) - AV_SOUND_HORDE_CAPTAIN = 8333, - -}; - -enum BG_AV_OTHER_VALUES -{ - AV_STATICCPLACE_MAX = 123, - AV_NORTH_MINE = 0, - AV_SOUTH_MINE = 1, - AV_MINE_TICK_TIMER = 45000, - AV_MINE_RECLAIM_TIMER = 1200000, //TODO: get the right value.. this is currently 20 minutes - AV_NEUTRAL_TEAM = 0 //this is the neutral owner of snowfall -}; -enum BG_AV_ObjectIds -{ - //cause the mangos-system is a bit different, we don't use the right go-ids for every node.. if we want to be 100% like another big server, we must take one object for every node - //snowfall 4flags as eyecandy 179424 (alliance neutral) - //Banners - stolen from battleground_AB.h ;-) - BG_AV_OBJECTID_BANNER_A = 178925, // can only be used by horde - BG_AV_OBJECTID_BANNER_H = 178943, // can only be used by alliance - BG_AV_OBJECTID_BANNER_CONT_A = 178940, // can only be used by horde - BG_AV_OBJECTID_BANNER_CONT_H = 179435, // can only be used by alliance - - BG_AV_OBJECTID_BANNER_A_B = 178365, - BG_AV_OBJECTID_BANNER_H_B = 178364, - BG_AV_OBJECTID_BANNER_CONT_A_B = 179286, - BG_AV_OBJECTID_BANNER_CONT_H_B = 179287, - BG_AV_OBJECTID_BANNER_SNOWFALL_N = 180418, - - //snowfall eyecandy banner: - BG_AV_OBJECTID_SNOWFALL_CANDY_A = 179044, - BG_AV_OBJECTID_SNOWFALL_CANDY_PA = 179424, - BG_AV_OBJECTID_SNOWFALL_CANDY_H = 179064, - BG_AV_OBJECTID_SNOWFALL_CANDY_PH = 179425, - - //banners on top of towers: - BG_AV_OBJECTID_TOWER_BANNER_A = 178927, //[PH] Alliance A1 Tower Banner BIG - BG_AV_OBJECTID_TOWER_BANNER_H = 178955, //[PH] Horde H1 Tower Banner BIG - BG_AV_OBJECTID_TOWER_BANNER_PA = 179446, //[PH] Alliance H1 Tower Pre-Banner BIG - BG_AV_OBJECTID_TOWER_BANNER_PH = 179436, //[PH] Horde A1 Tower Pre-Banner BIG - - //Auras - BG_AV_OBJECTID_AURA_A = 180421, - BG_AV_OBJECTID_AURA_H = 180422, - BG_AV_OBJECTID_AURA_N = 180423, - BG_AV_OBJECTID_AURA_A_S = 180100, - BG_AV_OBJECTID_AURA_H_S = 180101, - BG_AV_OBJECTID_AURA_N_S = 180102, - - BG_AV_OBJECTID_GATE_A = 180424, - BG_AV_OBJECTID_GATE_H = 180424, - - //mine supplies - BG_AV_OBJECTID_MINE_N = 178785, - BG_AV_OBJECTID_MINE_S = 178784, - - BG_AV_OBJECTID_FIRE = 179065, - BG_AV_OBJECTID_SMOKE = 179066 -}; - -enum BG_AV_Nodes -{ - BG_AV_NODES_FIRSTAID_STATION = 0, - BG_AV_NODES_STORMPIKE_GRAVE = 1, - BG_AV_NODES_STONEHEART_GRAVE = 2, - BG_AV_NODES_SNOWFALL_GRAVE = 3, - BG_AV_NODES_ICEBLOOD_GRAVE = 4, - BG_AV_NODES_FROSTWOLF_GRAVE = 5, - BG_AV_NODES_FROSTWOLF_HUT = 6, - BG_AV_NODES_DUNBALDAR_SOUTH = 7, - BG_AV_NODES_DUNBALDAR_NORTH = 8, - BG_AV_NODES_ICEWING_BUNKER = 9, - BG_AV_NODES_STONEHEART_BUNKER = 10, - BG_AV_NODES_ICEBLOOD_TOWER = 11, - BG_AV_NODES_TOWER_POINT = 12, - BG_AV_NODES_FROSTWOLF_ETOWER = 13, - BG_AV_NODES_FROSTWOLF_WTOWER = 14, - - BG_AV_NODES_MAX = 15 -}; - -enum BG_AV_ObjectTypes -{ - BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION = 0, - BG_AV_OBJECT_FLAG_A_STORMPIKE_GRAVE = 1, - BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE = 2, - BG_AV_OBJECT_FLAG_A_SNOWFALL_GRAVE = 3, - BG_AV_OBJECT_FLAG_A_ICEBLOOD_GRAVE = 4, - BG_AV_OBJECT_FLAG_A_FROSTWOLF_GRAVE = 5, - BG_AV_OBJECT_FLAG_A_FROSTWOLF_HUT = 6, - BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH = 7, - BG_AV_OBJECT_FLAG_A_DUNBALDAR_NORTH = 8, - BG_AV_OBJECT_FLAG_A_ICEWING_BUNKER = 9, - BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER = 10, - - BG_AV_OBJECT_FLAG_C_A_FIRSTAID_STATION = 11, - BG_AV_OBJECT_FLAG_C_A_STORMPIKE_GRAVE = 12, - BG_AV_OBJECT_FLAG_C_A_STONEHEART_GRAVE = 13, - BG_AV_OBJECT_FLAG_C_A_SNOWFALL_GRAVE = 14, - BG_AV_OBJECT_FLAG_C_A_ICEBLOOD_GRAVE = 15, - BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_GRAVE = 16, - BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_HUT = 17, - BG_AV_OBJECT_FLAG_C_A_ICEBLOOD_TOWER = 18, - BG_AV_OBJECT_FLAG_C_A_TOWER_POINT = 19, - BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_ETOWER = 20, - BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_WTOWER = 21, - - BG_AV_OBJECT_FLAG_C_H_FIRSTAID_STATION = 22, - BG_AV_OBJECT_FLAG_C_H_STORMPIKE_GRAVE = 23, - BG_AV_OBJECT_FLAG_C_H_STONEHEART_GRAVE = 24, - BG_AV_OBJECT_FLAG_C_H_SNOWFALL_GRAVE = 25, - BG_AV_OBJECT_FLAG_C_H_ICEBLOOD_GRAVE = 26, - BG_AV_OBJECT_FLAG_C_H_FROSTWOLF_GRAVE = 27, - BG_AV_OBJECT_FLAG_C_H_FROSTWOLF_HUT = 28, - BG_AV_OBJECT_FLAG_C_H_DUNBALDAR_SOUTH = 29, - BG_AV_OBJECT_FLAG_C_H_DUNBALDAR_NORTH = 30, - BG_AV_OBJECT_FLAG_C_H_ICEWING_BUNKER = 31, - BG_AV_OBJECT_FLAG_C_H_STONEHEART_BUNKER = 32, - - BG_AV_OBJECT_FLAG_H_FIRSTAID_STATION = 33, - BG_AV_OBJECT_FLAG_H_STORMPIKE_GRAVE = 34, - BG_AV_OBJECT_FLAG_H_STONEHEART_GRAVE = 35, - BG_AV_OBJECT_FLAG_H_SNOWFALL_GRAVE = 36, - BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE = 37, - BG_AV_OBJECT_FLAG_H_FROSTWOLF_GRAVE = 38, - BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT = 39, - BG_AV_OBJECT_FLAG_H_ICEBLOOD_TOWER = 40, - BG_AV_OBJECT_FLAG_H_TOWER_POINT = 41, - BG_AV_OBJECT_FLAG_H_FROSTWOLF_ETOWER = 42, - BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER = 43, - - BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE = 44, - - BG_AV_OBJECT_DOOR_H = 45, - BG_AV_OBJECT_DOOR_A = 46, -//auras for graveyards (3auras per graveyard neutral,alliance,horde) - BG_AV_OBJECT_AURA_N_FIRSTAID_STATION = 47, - BG_AV_OBJECT_AURA_A_FIRSTAID_STATION = 48, - BG_AV_OBJECT_AURA_H_FIRSTAID_STATION = 49, - BG_AV_OBJECT_AURA_N_STORMPIKE_GRAVE = 50, - BG_AV_OBJECT_AURA_A_STORMPIKE_GRAVE = 51, - BG_AV_OBJECT_AURA_H_STORMPIKE_GRAVE = 52, - BG_AV_OBJECT_AURA_N_STONEHEART_GRAVE = 53, - BG_AV_OBJECT_AURA_A_STONEHEART_GRAVE = 54, - BG_AV_OBJECT_AURA_H_STONEHEART_GRAVE = 55, - BG_AV_OBJECT_AURA_N_SNOWFALL_GRAVE = 56, - BG_AV_OBJECT_AURA_A_SNOWFALL_GRAVE = 57, - BG_AV_OBJECT_AURA_H_SNOWFALL_GRAVE = 58, - BG_AV_OBJECT_AURA_N_ICEBLOOD_GRAVE = 59, - BG_AV_OBJECT_AURA_A_ICEBLOOD_GRAVE = 60, - BG_AV_OBJECT_AURA_H_ICEBLOOD_GRAVE = 61, - BG_AV_OBJECT_AURA_N_FROSTWOLF_GRAVE = 62, - BG_AV_OBJECT_AURA_A_FROSTWOLF_GRAVE = 63, - BG_AV_OBJECT_AURA_H_FROSTWOLF_GRAVE = 64, - BG_AV_OBJECT_AURA_N_FROSTWOLF_HUT = 65, - BG_AV_OBJECT_AURA_A_FROSTWOLF_HUT = 66, - BG_AV_OBJECT_AURA_H_FROSTWOLF_HUT = 67, - - //big flags on top of towers 2 flags on each (contested,(alliance | horde)) + 2 auras - BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH = 67, - BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH = 68, - BG_AV_OBJECT_TFLAG_A_DUNBALDAR_NORTH = 69, - BG_AV_OBJECT_TFLAG_H_DUNBALDAR_NORTH = 70, - BG_AV_OBJECT_TFLAG_A_ICEWING_BUNKER = 71, - BG_AV_OBJECT_TFLAG_H_ICEWING_BUNKER = 72, - BG_AV_OBJECT_TFLAG_A_STONEHEART_BUNKER = 73, - BG_AV_OBJECT_TFLAG_H_STONEHEART_BUNKER = 74, - BG_AV_OBJECT_TFLAG_A_ICEBLOOD_TOWER = 75, - BG_AV_OBJECT_TFLAG_H_ICEBLOOD_TOWER = 76, - BG_AV_OBJECT_TFLAG_A_TOWER_POINT = 77, - BG_AV_OBJECT_TFLAG_H_TOWER_POINT = 78, - BG_AV_OBJECT_TFLAG_A_FROSTWOLF_ETOWER = 79, - BG_AV_OBJECT_TFLAG_H_FROSTWOLF_ETOWER = 80, - BG_AV_OBJECT_TFLAG_A_FROSTWOLF_WTOWER = 81, - BG_AV_OBJECT_TFLAG_H_FROSTWOLF_WTOWER = 82, - BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH = 83, - BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH = 84, - BG_AV_OBJECT_TAURA_A_DUNBALDAR_NORTH = 85, - BG_AV_OBJECT_TAURA_H_DUNBALDAR_NORTH = 86, - BG_AV_OBJECT_TAURA_A_ICEWING_BUNKER = 87, - BG_AV_OBJECT_TAURA_H_ICEWING_BUNKER = 88, - BG_AV_OBJECT_TAURA_A_STONEHEART_BUNKER = 89, - BG_AV_OBJECT_TAURA_H_STONEHEART_BUNKER = 90, - BG_AV_OBJECT_TAURA_A_ICEBLOOD_TOWER = 91, - BG_AV_OBJECT_TAURA_H_ICEBLOOD_TOWER = 92, - BG_AV_OBJECT_TAURA_A_TOWER_POINT = 93, - BG_AV_OBJECT_TAURA_H_TOWER_POINT = 94, - BG_AV_OBJECT_TAURA_A_FROSTWOLF_ETOWER = 95, - BG_AV_OBJECT_TAURA_H_FROSTWOLF_ETOWER = 96, - BG_AV_OBJECT_TAURA_A_FROSTWOLF_WTOWER = 97, - BG_AV_OBJECT_TAURA_H_FROSTWOLF_WTOWER = 98, - - BG_AV_OBJECT_BURN_DUNBALDAR_SOUTH = 99, - BG_AV_OBJECT_BURN_DUNBALDAR_NORTH = 109, - BG_AV_OBJECT_BURN_ICEWING_BUNKER = 119, - BG_AV_OBJECT_BURN_STONEHEART_BUNKER = 129, - BG_AV_OBJECT_BURN_ICEBLOOD_TOWER = 139, - BG_AV_OBJECT_BURN_TOWER_POINT = 149, - BG_AV_OBJECT_BURN_FROSTWOLF_ETWOER = 159, - BG_AV_OBJECT_BURN_FROSTWOLF_WTOWER = 169, - BG_AV_OBJECT_BURN_BUILDING_ALLIANCE = 179, - BG_AV_OBJECT_BURN_BUILDING_HORDE = 189, - BG_AV_OBJECT_SNOW_EYECANDY_A = 199, - BG_AV_OBJECT_SNOW_EYECANDY_PA = 203, - BG_AV_OBJECT_SNOW_EYECANDY_H = 207, - BG_AV_OBJECT_SNOW_EYECANDY_PH = 211, - BG_AV_OBJECT_MINE_SUPPLY_N_MIN = 215, - BG_AV_OBJECT_MINE_SUPPLY_N_MAX = 224, - BG_AV_OBJECT_MINE_SUPPLY_S_MIN = 225, - BG_AV_OBJECT_MINE_SUPPLY_S_MAX = 236, - - BG_AV_OBJECT_MAX = 237 -}; - -enum BG_AV_OBJECTS -{ - AV_OPLACE_FIRSTAID_STATION = 0, - AV_OPLACE_STORMPIKE_GRAVE = 1, - AV_OPLACE_STONEHEART_GRAVE = 2, - AV_OPLACE_SNOWFALL_GRAVE = 3, - AV_OPLACE_ICEBLOOD_GRAVE = 4, - AV_OPLACE_FROSTWOLF_GRAVE = 5, - AV_OPLACE_FROSTWOLF_HUT = 6, - AV_OPLACE_DUNBALDAR_SOUTH = 7, - AV_OPLACE_DUNBALDAR_NORTH = 8, - AV_OPLACE_ICEWING_BUNKER = 9, - AV_OPLACE_STONEHEART_BUNKER = 10, - AV_OPLACE_ICEBLOOD_TOWER = 11, - AV_OPLACE_TOWER_POINT = 12, - AV_OPLACE_FROSTWOLF_ETOWER = 13, - AV_OPLACE_FROSTWOLF_WTOWER = 14, - AV_OPLACE_BIGBANNER_DUNBALDAR_SOUTH = 15, - AV_OPLACE_BIGBANNER_DUNBALDAR_NORTH = 16, - AV_OPLACE_BIGBANNER_ICEWING_BUNKER = 17, - AV_OPLACE_BIGBANNER_STONEHEART_BUNKER = 18, - AV_OPLACE_BIGBANNER_ICEBLOOD_TOWER = 19, - AV_OPLACE_BIGBANNER_TOWER_POINT = 20, - AV_OPLACE_BIGBANNER_FROSTWOLF_ETOWER = 21, - AV_OPLACE_BIGBANNER_FROSTWOLF_WTOWER = 22, - - AV_OPLACE_BURN_DUNBALDAR_SOUTH = 23, - AV_OPLACE_BURN_DUNBALDAR_NORTH = 33, - AV_OPLACE_BURN_ICEWING_BUNKER = 43, - AV_OPLACE_BURN_STONEHEART_BUNKER = 53, - AV_OPLACE_BURN_ICEBLOOD_TOWER = 63, - AV_OPLACE_BURN_TOWER_POINT = 73, - AV_OPLACE_BURN_FROSTWOLF_ETOWER = 83, - AV_OPLACE_BURN_FROSTWOLF_WTOWER = 93, - AV_OPLACE_BURN_BUILDING_A = 103, - AV_OPLACE_BURN_BUILDING_H = 113, - AV_OPLACE_SNOW_1 = 123, - AV_OPLACE_SNOW_2 = 124, - AV_OPLACE_SNOW_3 = 125, - AV_OPLACE_SNOW_4 = 126, - AV_OPLACE_MINE_SUPPLY_N_MIN = 127, - AV_OPLACE_MINE_SUPPLY_N_MAX = 136, - AV_OPLACE_MINE_SUPPLY_S_MIN = 137, - AV_OPLACE_MINE_SUPPLY_S_MAX = 148, - - AV_OPLACE_MAX = 149 -}; -const float BG_AV_ObjectPos[AV_OPLACE_MAX][4] = { - {638.592f,-32.422f,46.0608f,-1.62316f },//firstaid station - {669.007f,-294.078f,30.2909f,2.77507f },//stormpike - {77.8013f,-404.7f,46.7549f,-0.872665f },//stone grave - {-202.581f,-112.73f,78.4876f,-0.715585f },//snowfall - {-611.962f,-396.17f,60.8351f,2.53682f}, //iceblood grave - {-1082.45f,-346.823f,54.9219f,-1.53589f },//frostwolf grave - {-1402.21f,-307.431f,89.4424f,0.191986f },//frostwolf hut - {553.779f,-78.6566f,51.9378f,-1.22173f }, //dunnbaldar south - {674.001f,-143.125f,63.6615f,0.994838f }, //dunbaldar north - {203.281f,-360.366f,56.3869f,-0.925024f }, //icew - {-152.437f,-441.758f,40.3982f,-1.95477f }, //stone - {-571.88f,-262.777f,75.0087f,-0.802851f }, //ice tower - {-768.907f,-363.71f,90.8949f,1.07991f}, //tower point - {-1302.9f,-316.981f,113.867f,2.00713f }, //frostwolf etower - {-1297.5f,-266.767f,114.15f,3.31044f}, //frostwolf wtower - //bigbanner: - {555.848f,-84.4151f,64.4397f,3.12414f }, //duns - {679.339f,-136.468f,73.9626f,-2.16421f }, //dunn - {208.973f,-365.971f,66.7409f,-0.244346f }, //icew - {-155.832f,-449.401f,52.7306f,0.610865f }, //stone - {-572.329f,-262.476f,88.6496f,-0.575959f }, //icetower - {-768.199f,-363.105f,104.537f,0.10472f }, //towerp - {-1302.84f,-316.582f,127.516f,0.122173f }, //etower - {-1297.87f,-266.762f,127.796f,0.0698132f }, //wtower - //burning auras towers have 9*179065 captain-buildings have 5*179066+5*179065 - //dunns - {562.632f,-88.1815f,61.993f,0.383972f }, - {562.523f,-74.5028f,37.9474f,-0.0523599f }, - {558.097f,-70.9842f,52.4876f,0.820305f }, - {578.167f,-71.8191f,38.1514f,2.72271f }, - {556.028f,-94.9242f,44.8191f,3.05433f }, - {572.451f,-94.3655f,37.9443f,-1.72788f }, - {549.263f,-79.3645f,44.8191f,0.436332f }, - {543.513f,-94.4006f,52.4819f,0.0349066f }, - {572.149f,-93.7862f,52.5726f,0.541052f }, - {582.162f,-81.2375f,37.9216f,0.0872665f }, - //dunn - {664.797f,-143.65f,64.1784f,-0.453786f}, - {664.505f,-139.452f,49.6696f,-0.0349067f}, - {676.067f,-124.319f,49.6726f,-1.01229f}, - {693.004f,-144.025f,64.1755f,2.44346f}, - {661.175f,-117.691f,49.645f,1.91986f}, - {684.423f,-146.582f,63.6662f,0.994838f}, - {682.791f,-127.769f,62.4155f,1.09956f}, - {674.576f,-147.101f,56.5425f,-1.6057f}, - {655.719f,-126.673f,49.8138f,2.80998f}, - {0,0,0,0}, - //icew - {231.503f,-356.688f,42.3704f,0.296706f}, - {224.989f,-348.175f,42.5607f,1.50098f}, - {205.782f,-351.335f,56.8998f,1.01229f}, - {196.605f,-369.187f,56.3914f,2.46091f}, - {210.619f,-376.938f,49.2677f,2.86234f}, - {209.647f,-352.632f,42.3959f,-0.698132f}, - {220.65f,-368.132f,42.3978f,-0.2618f}, - {224.682f,-374.031f,57.0679f,0.541052f}, - {200.26f,-359.968f,49.2677f,-2.89725f}, - {196.619f,-378.016f,56.9131f,1.01229f}, - //stone - {-155.488f,-437.356f,33.2796f,2.60054f}, - {-163.441f,-454.188f,33.2796f,1.93732f}, - {-143.977f,-445.148f,26.4097f,-1.8675f}, - {-135.764f,-464.708f,26.3823f,2.25147f}, - {-154.076f,-466.929f,41.0636f,-1.8675f}, - {-149.908f,-460.332f,26.4083f,-2.09439f}, - {-151.638f,-439.521f,40.3797f,0.436332f}, - {-131.301f,-454.905f,26.5771f,2.93215f}, - {-171.291f,-444.684f,40.9211f,2.30383f}, - {-143.591f,-439.75f,40.9275f,-1.72788f}, - //iceblood - {-572.667f,-267.923f,56.8542f,2.35619f}, - {-561.021f,-262.689f,68.4589f,1.37881f}, - {-572.538f,-262.649f,88.6197f,1.8326f}, - {-574.77f,-251.45f,74.9422f,-1.18682f}, - {-578.625f,-267.571f,68.4696f,0.506145f}, - {-571.476f,-257.234f,63.3223f,3.10669f}, - {-566.035f,-273.907f,52.9582f,-0.890118f}, - {-580.948f,-259.77f,68.4696f,1.46608f}, - {-568.318f,-267.1f,75.0008f,1.01229f}, - {-559.621f,-268.597f,52.8986f,0.0523599f}, - //towerp - {-776.072f,-368.046f,84.3558f,2.63545f}, - {-777.564f,-368.521f,90.6701f,1.72788f}, - {-765.461f,-357.711f,90.888f,0.314159f}, - {-768.763f,-362.735f,104.612f,1.81514f}, - {-760.356f,-358.896f,84.3558f,2.1293f}, - {-771.967f,-352.838f,84.3484f,1.74533f}, - {-773.333f,-364.653f,79.2351f,-1.64061f}, - {-764.109f,-366.069f,70.0934f,0.383972f}, - {-767.103f,-350.737f,68.7933f,2.80998f}, - {-760.115f,-353.845f,68.8633f,1.79769f}, - //froste - {-1304.87f,-304.525f,91.8366f,-0.680679f}, - {-1301.77f,-310.974f,95.8252f,0.907571f}, - {-1305.58f,-320.625f,102.166f,-0.558505f}, - {-1294.27f,-323.468f,113.893f,-1.67552f}, - {-1302.65f,-317.192f,127.487f,2.30383f}, - {-1293.89f,-313.478f,107.328f,1.6057f}, - {-1312.41f,-312.999f,107.328f,1.5708f}, - {-1311.57f,-308.08f,91.7666f,-1.85005f}, - {-1314.7f,-322.131f,107.36f,0.645772f}, - {-1304.6f,-310.754f,113.859f,-0.401426f}, - //frostw - {-1308.24f,-273.26f,92.0514f,-0.139626f}, - {-1302.26f,-262.858f,95.9269f,0.418879f}, - {-1297.28f,-267.773f,126.756f,2.23402f}, - {-1299.08f,-256.89f,114.108f,-2.44346f}, - {-1303.41f,-268.237f,114.151f,-1.23918f}, - {-1304.43f,-273.682f,107.612f,0.244346f}, - {-1309.53f,-265.951f,92.1418f,-2.49582f}, - {-1295.55f,-263.865f,105.033f,0.925024f}, - {-1294.71f,-281.466f,107.664f,-1.50098f}, - {-1289.69f,-259.521f,107.612f,-2.19912f}, - - //the two buildings of the captains - //alliance - {-64.4987f,-289.33f,33.4616f,-2.82743f}, - {-5.98025f,-326.144f,38.8538f,0}, - {-2.67893f,-306.998f,33.4165f,0}, - {-60.25f,-309.232f,50.2408f,-1.46608f}, - {-48.7941f,-266.533f,47.7916f,2.44346f}, - {-3.40929f,-306.288f,33.34f,0}, - {-48.619f,-266.917f,47.8168f,0}, - {-62.9474f,-286.212f,66.7288f,0}, - {-5.05132f,-325.323f,38.8536f,0}, - {-64.2677f,-289.412f,33.469f,0}, -//horde - {-524.276f,-199.6f,82.8733f,-1.46608f}, - {-518.196f,-173.085f,102.43f,0}, - {-500.732f,-145.358f,88.5337f,2.44346f}, - {-501.084f,-150.784f,80.8506f,0}, - {-518.309f,-163.963f,102.521f,2.96706f}, - {-517.053f,-200.429f,80.759f,0}, - {-514.361f,-163.864f,104.163f,0}, - {-568.04f,-188.707f,81.55f,0}, - {-501.775f,-151.581f,81.2027f,0}, - {-509.975f,-191.652f,83.2978f,0}, - -//snowfall eyecandy - {-191.153f,-129.868f,78.5595f,-1.25664f }, - {-201.282f,-134.319f,78.6753f,-0.942478f }, - {-215.981f,-91.4101f,80.8702f,-1.74533f }, - {-200.465f,-96.418f,79.7587f,1.36136f }, - //mine supplies - //irondeep - {870.899f,-388.434f,61.6406f,-1.22173f}, - {825.214f,-320.174f,63.712f,-2.82743f}, - {837.117f,-452.556f,47.2331f,-3.12414f}, - {869.755f,-448.867f,52.5448f,-0.855212f}, - {949.877f,-458.198f,56.4874f,0.314159f}, - {900.35f,-479.024f,58.3553f,0.122173f}, - {854.449f,-442.255f,50.6589f,0.401426f}, - {886.685f,-442.358f,54.6962f,-1.22173f}, - {817.509f,-457.331f,48.4666f,2.07694f}, - {793.411f,-326.281f,63.1117f,-2.79253f}, - //coldtooth - {-934.212f,-57.3517f,80.277f,-0.0174535f}, - {-916.281f,-36.8579f,77.0227f,0.122173f}, - {-902.73f,-103.868f,75.4378f,-1.58825f}, - {-900.514f,-143.527f,75.9686f,1.8675f}, - {-862.882f,-0.353299f,72.1526f,-2.51327f}, - {-854.932f,-85.9184f,68.6056f,-2.04204f}, - {-851.833f,-118.959f,63.8672f,-0.0698131f}, - {-849.832f,-20.8421f,70.4672f,-1.81514f}, - {-844.25f,-60.0374f,72.1031f,-2.19912f}, - {-820.644f,-136.043f,63.1977f,2.40855f}, - {-947.642f,-208.807f,77.0101f,1.36136f}, - {-951.394f,-193.695f,67.634f,0.802851f} -}; - -const float BG_AV_DoorPositons[2][4] = { - {780.487f, -493.024f, 99.9553f, 3.0976f}, //alliance - {-1375.193f, -538.981f, 55.2824f, 0.72178f} //horde -}; - -//creaturestuff starts here -//is related to BG_AV_CreaturePos -enum BG_AV_CreaturePlace -{ - AV_CPLACE_SPIRIT_STORM_AID = 0, - AV_CPLACE_SPIRIT_STORM_GRAVE = 1, - AV_CPLACE_SPIRIT_STONE_GRAVE = 2, - AV_CPLACE_SPIRIT_SNOWFALL = 3, - AV_CPLACE_SPIRIT_ICE_GRAVE = 4, - AV_CPLACE_SPIRIT_FROSTWOLF = 5, - AV_CPLACE_SPIRIT_FROST_HUT = 6, - AV_CPLACE_SPIRIT_MAIN_ALLIANCE = 7, - AV_CPLACE_SPIRIT_MAIN_HORDE = 8, -//i don't will add for all 4 positions a variable.. i think one is enough to compute the rest - AV_CPLACE_DEFENSE_STORM_AID = 9, - AV_CPLACE_DEFEMSE_STORM_GRAVE = 13, - AV_CPLACE_DEFENSE_STONE_GRAVE = 17, - AV_CPLACE_DEFENSE_SNOWFALL = 21, - AV_CPLACE_DEFENSE_FROSTWOLF = 25, - AV_CPLACE_DEFENSE_ICE_GRAVE = 29, - AV_CPLACE_DEFENSE_FROST_HUT = 33, - - AV_CPLACE_DEFENSE_DUN_S = 37, - AV_CPLACE_DEFENSE_DUN_N = 41, - AV_CPLACE_DEFENSE_ICEWING = 45, - AV_CPLACE_DEFENSE_STONE_TOWER = 49, - AV_CPLACE_DEFENSE_ICE_TOWER = 53, - AV_CPLACE_DEFENSE_TOWERPOINT = 57, - AV_CPLACE_DEFENSE_FROST_E = 61, - AV_CPLACE_DEFENSE_FROST_t = 65, - - AV_CPLACE_A_MARSHAL_SOUTH = 69, - AV_CPLACE_A_MARSHAL_NORTH = 70, - AV_CPLACE_A_MARSHAL_ICE = 71, - AV_CPLACE_A_MARSHAL_STONE = 72, - AV_CPLACE_H_MARSHAL_ICE = 73, - AV_CPLACE_H_MARSHAL_TOWER = 74, - AV_CPLACE_H_MARSHAL_ETOWER = 75, - AV_CPLACE_H_MARSHAL_WTOWER = 76, - //irondeep - //miner: - AV_CPLACE_MINE_N_1_MIN = 77, - AV_CPLACE_MINE_N_1_MAX = 136, - //special types - AV_CPLACE_MINE_N_2_MIN = 137, - AV_CPLACE_MINE_N_2_MAX = 192, - //boss - AV_CPLACE_MINE_N_3 = 193, - //coldtooth - //miner: - AV_CPLACE_MINE_S_1_MIN = 194, - AV_CPLACE_MINE_S_1_MAX = 250, - //special types - AV_CPLACE_MINE_S_2_MIN = 251, - AV_CPLACE_MINE_S_2_MAX = 289, - //vermin - AV_CPLACE_MINE_S_S_MIN = 290, - AV_CPLACE_MINE_S_S_MAX = 299, - //boss - AV_CPLACE_MINE_S_3 = 300, - - //herald - AV_CPLACE_HERALD = 301, - - //node aura triggers - AV_CPLACE_TRIGGER01 = 302, - AV_CPLACE_TRIGGER02 = 303, - AV_CPLACE_TRIGGER03 = 304, - AV_CPLACE_TRIGGER04 = 305, - AV_CPLACE_TRIGGER05 = 306, - AV_CPLACE_TRIGGER06 = 307, - AV_CPLACE_TRIGGER07 = 308, - AV_CPLACE_TRIGGER08 = 309, - AV_CPLACE_TRIGGER09 = 310, - AV_CPLACE_TRIGGER10 = 311, - AV_CPLACE_TRIGGER11 = 312, - AV_CPLACE_TRIGGER12 = 313, - AV_CPLACE_TRIGGER13 = 314, - AV_CPLACE_TRIGGER14 = 315, - AV_CPLACE_TRIGGER15 = 316, - - //boss,captain triggers - AV_CPLACE_TRIGGER16 = 317, - AV_CPLACE_TRIGGER17 = 318, - AV_CPLACE_TRIGGER18 = 319, - AV_CPLACE_TRIGGER19 = 320, - - AV_CPLACE_MAX = 321 -}; - -//x, y, z, o -const float BG_AV_CreaturePos[AV_CPLACE_MAX][4] = { - //spiritguides - {643.000000f,44.000000f,69.740196f,-0.001854f}, - {676.000000f,-374.000000f,30.000000f,-0.001854f}, - {73.417755f,-496.433105f,48.731918f,-0.001854f}, - {-157.409195f,31.206272f,77.050598f,-0.001854f}, - {-531.217834f,-405.231384f,49.551376f,-0.001854f}, - {-1090.476807f,-253.308670f,57.672371f,-0.001854f}, - {-1496.065063f,-333.338409f,101.134804f,-0.001854f}, - {873.001770f,-491.283630f,96.541931f,-0.001854f}, - {-1437.670044f,-610.088989f,51.161900f,-0.001854f}, - //grave - //firstaid - {635.17f,-29.5594f,46.5056f,4.81711f}, - {642.488f,-32.9437f,46.365f,4.67748f}, - {642.326f,-27.9442f,46.9211f,4.59022f}, - {635.945f,-33.6171f,45.7164f,4.97419f}, - //stormpike - {669.272f,-297.304f,30.291f,4.66604f}, - {674.08f,-292.328f,30.4817f,0.0918785f}, - {667.01f,-288.532f,29.8809f,1.81583f}, - {664.153f,-294.042f,30.2851f,3.28531f}, - //stone - {81.7027f,-406.135f,47.7843f,0.598464f}, - {78.1431f,-409.215f,48.0401f,5.05953f}, - {73.4135f,-407.035f,46.7527f,3.34736f}, - {78.2258f,-401.859f,46.4202f,2.05852f}, - //snowfall - {-207.412f,-110.616f,78.7959f,2.43251f}, - {-197.95f,-112.205f,78.5686f,6.22441f}, - {-202.709f,-116.829f,78.4358f,5.13742f}, - {-202.059f,-108.314f,78.5783f,5.91968f}, - //ice - {-615.501f,-393.802f,60.4299f,3.06147f}, - {-608.513f,-392.717f,62.5724f,2.06323f}, - {-609.769f,-400.072f,60.7174f,5.22367f}, - {-616.093f,-398.293f,60.5628f,3.73613f}, - //frost - {-1077.7f,-340.21f,55.4682f,6.25569f}, - {-1082.74f,-333.821f,54.7962f,2.05459f}, - {-1090.66f,-341.267f,54.6768f,3.27746f}, - {-1081.58f,-344.63f,55.256f,4.75636f}, - //frost hut - {-1408.95f,-311.69f,89.2536f,4.49954f}, - {-1407.15f,-305.323f,89.1993f,2.86827f}, - {-1400.64f,-304.3f,89.7008f,1.0595f}, - {-1400.4f,-311.35f,89.3028f,4.99434f}, - //towers - //dun south - OK - {569.395f,-101.064f,52.8296f,2.34974f}, - {574.85f,-92.9842f,52.5869f,3.09325f}, - {575.411f,-83.597f,52.3626f,6.26573f}, - {571.352f,-75.6582f,52.479f,0.523599f}, - //dun north - OK - {668.60f,-122.53f,64.12f,2.34f}, //not 100% ok - {662.253f,-129.105f,64.1794f,2.77507f}, - {661.209f,-138.877f,64.2251f,3.38594f}, - {665.481f,-146.857f,64.1271f,3.75246f}, - //icewing - OK - {225.228f,-368.909f,56.9983f,6.23806f}, - {191.36f,-369.899f,57.1524f,3.24631f}, - {215.518f,-384.019f,56.9889f,5.09636f}, - {199.625f,-382.177f,56.8691f,4.08407f}, - //stone - {-172.851f,-452.366f,40.8725f,3.31829f}, - {-147.147f,-435.053f,40.8022f,0.599238f}, - {-169.456f,-440.325f,40.985f,2.59101f}, - {-163.494f,-434.904f,41.0725f,1.84174f}, - //ice - OK - {-573.522f,-271.854f,75.0078f,3.9619f}, - {-565.616f,-269.051f,74.9952f,5.02655f}, - {-562.825f,-261.087f,74.9898f,5.95157f}, - {-569.176f,-254.446f,74.8771f,0.820305f}, - //towerpoint - {-763.04f,-371.032f,90.7933f,5.25979f}, - {-759.764f,-358.264f,90.8681f,0.289795f}, - {-768.808f,-353.056f,90.8811f,1.52601f}, - {-775.944f,-362.639f,90.8949f,2.59573f}, - //frost etower - {-1294.13f,-313.045f,107.328f,0.270162f}, - {-1306.5f,-308.105f,113.767f,1.78755f}, - {-1294.78f,-319.966f,113.79f,5.94545f}, - {-1294.83f,-312.241f,113.799f,0.295293f}, - //frost wtower - {-1300.96f,-275.111f,114.058f,4.12804f}, - {-1302.41f,-259.256f,114.065f,1.67602f}, - {-1287.97f,-262.087f,114.165f,6.18264f}, - {-1291.59f,-271.166f,114.151f,5.28257f}, - - //alliance marshall - {721.104f,-7.64155f,50.7046f,3.45575f},// south - {723.058f,-14.1548f,50.7046f,3.40339f},// north - {715.691f,-4.72233f,50.2187f,3.47321f},// icewing - {720.046f,-19.9413f,50.2187f,3.36849f},// stone -//horde (coords not 100% ok) - {-1363.99f,-221.99f,98.4053f,4.93012f}, - {-1370.96f,-223.532f,98.4266f,4.93012f}, - {-1378.37f,-228.614f,99.3546f,5.38565f}, - {-1358.02f,-228.998f,98.868f,3.87768f}, - - //irondeep mine - //Irondeep Trogg - {971.671f,-442.657f,57.6951f,3.1765f}, - {969.979f,-457.148f,58.1119f,4.5204f}, - {958.692f,-333.477f,63.2276f,5.77704f}, - {957.113f,-325.92f,61.7589f,1.13446f}, - {948.25f,-448.268f,56.9009f,5.60251f}, - {934.727f,-385.802f,63.0344f,3.75246f}, - {931.751f,-403.458f,59.6737f,5.63741f}, - {931.146f,-359.666f,66.0294f,3.9619f}, - {929.702f,-412.401f,56.8776f,5.89921f}, - {926.849f,-379.074f,63.5286f,2.0944f}, - {921.972f,-358.597f,66.4313f,2.93215f}, - {921.449f,-341.981f,67.1264f,3.4383f}, - {921.1f,-395.812f,60.4615f,2.71695f}, - {919.274f,-394.986f,60.3478f,2.71696f}, - {916.852f,-393.891f,60.1726f,2.71695f}, - {914.568f,-326.21f,66.1733f,2.25147f}, - {913.064f,-395.773f,60.1364f,4.41568f}, - {909.246f,-474.576f,58.2067f,0.226893f}, - {909.246f,-474.576f,58.2901f,0.226893f}, - {907.209f,-428.267f,59.8065f,1.8675f}, - {905.973f,-459.528f,58.7594f,1.37189f}, - {905.067f,-396.074f,60.2085f,5.07891f}, - {901.809f,-457.709f,59.0116f,3.52557f}, - {900.962f,-427.44f,59.0842f,1.50098f}, - {897.929f,-471.742f,59.7729f,2.54818f}, - {893.376f,-343.171f,68.1499f,5.35816f}, - {890.584f,-406.049f,61.1925f,5.67232f}, - {888.208f,-332.564f,68.148f,1.93732f}, - {887.647f,-391.537f,61.8734f,1.37881f}, - {885.109f,-343.338f,67.0867f,3.78979f}, - {881.618f,-419.948f,53.5228f,0.593412f}, - {878.675f,-345.36f,66.1052f,3.45651f}, - {877.127f,-351.8f,66.5296f,5.74213f}, - {876.778f,-345.97f,65.7724f,3.45262f}, - {874.577f,-414.786f,52.7817f,1.67552f}, - {868.247f,-343.136f,64.9894f,1.6057f}, - {859.03f,-367.231f,47.4655f,0.0174533f}, - {857.513f,-351.817f,65.1867f,4.39823f}, - {852.632f,-372.416f,48.1657f,3.66519f}, - {849.86f,-340.944f,66.2447f,0.401426f}, - {847.99f,-386.287f,60.9277f,2.32374f}, - {847.601f,-423.072f,50.0852f,4.57276f}, - {847.135f,-411.307f,50.2106f,1.5708f}, - {835.077f,-379.418f,48.2755f,5.93412f}, - {834.87f,-453.304f,47.9075f,0.226893f}, - {834.634f,-365.981f,62.8801f,1.32645f}, - {834.354f,-355.526f,48.1491f,6.07375f}, - {833.702f,-327.506f,65.0439f,0.331613f}, - {833.151f,-374.228f,63.0938f,3.66519f}, - {831.711f,-346.785f,47.2975f,0.226893f}, - {827.874f,-413.624f,48.5818f,1.49241f}, - {827.728f,-415.483f,48.5593f,1.49238f}, - {827.016f,-424.543f,48.2856f,1.49236f}, - {823.222f,-334.283f,65.6306f,4.88692f}, - {821.892f,-464.723f,48.9451f,4.66003f}, - {821.006f,-387.635f,49.0728f,3.15905f}, - {817.26f,-447.432f,49.4308f,2.18166f}, - {805.399f,-320.146f,52.7712f,0.296706f}, - {801.405f,-328.055f,53.0195f,4.31096f}, - //irondeep skullthumber irondeep shaman - {955.812f,-440.302f,55.3411f,3.19395f}, - {937.378f,-377.816f,65.3919f,3.56047f}, - {925.059f,-331.347f,65.7564f,3.66519f}, - {922.918f,-396.634f,60.3942f,2.71695f}, - {909.99f,-462.154f,59.0811f,3.7001f}, - {907.893f,-388.787f,61.7923f,5.74213f}, - {898.801f,-437.105f,58.5266f,0.959931f}, - {884.237f,-407.597f,61.566f,0.820305f}, - {880.744f,-344.683f,66.4086f,3.4644f}, - {876.047f,-341.857f,65.8743f,4.45059f}, - {874.674f,-402.077f,61.7573f,0.26341f}, - {871.914f,-404.209f,62.1269f,6.06163f}, - {871.606f,-403.665f,62.0795f,0.765774f}, - {871.561f,-404.114f,62.1297f,0.00981727f}, - {871.528f,-404.248f,62.1455f,0.498032f}, - {871.493f,-404.122f,62.1331f,5.65727f}, - {871.282f,-403.843f,62.1108f,0.788382f}, - {868.294f,-392.395f,61.4772f,4.38685f}, - {868.256f,-392.363f,61.4803f,0.732738f}, - {867.804f,-392.51f,61.5089f,2.30167f}, - {867.612f,-392.371f,61.524f,2.86149f}, - {858.593f,-439.614f,50.2184f,0.872665f}, - {851.471f,-362.52f,47.314f,4.06662f}, - {846.939f,-347.279f,66.2876f,0.942478f}, - {842.08f,-421.775f,48.2659f,1.0821f}, - {838.358f,-371.212f,63.3299f,4.04916f}, - {827.57f,-417.483f,48.4538f,1.49237f}, - {827.012f,-457.397f,48.9331f,2.35619f}, - {825.535f,-322.373f,63.9357f,4.76475f}, - {867.635f,-443.605f,51.3347f,1.38626f}, - {957.293f,-455.039f,56.7395f,5.79449f}, - {950.077f,-326.672f,61.6552f,5.48033f}, - {936.692f,-356.78f,65.9835f,2.75762f}, - {926.475f,-419.345f,56.1833f,2.0944f}, - {924.729f,-397.453f,60.213f,2.71695f}, - {902.195f,-475.891f,58.312f,1.39626f}, - {897.464f,-338.758f,68.1715f,2.94961f}, - {884.237f,-407.597f,61.566f,0.820305f}, - {882.517f,-344.111f,66.7887f,3.46962f}, - {881.437f,-400.254f,61.2028f,0.263427f}, - {880.156f,-400.678f,61.3113f,3.41373f}, - {877.989f,-418.051f,52.9753f,4.46804f}, - {871.212f,-404.12f,62.1433f,3.6554f}, - {871.036f,-404.119f,62.2237f,4.50295f}, - {857.396f,-395.766f,61.263f,4.78684f}, - {857.276f,-395.395f,61.2418f,0.0845553f}, - {857.231f,-394.577f,61.2174f,1.96817f}, - {857.108f,-395.682f,61.2317f,4.87022f}, - {856.709f,-395.28f,61.1814f,2.54913f}, - {850.922f,-390.399f,60.8771f,2.85405f}, - {847.556f,-388.228f,60.9438f,2.56872f}, - {842.031f,-384.663f,61.6028f,2.56871f}, - {832.035f,-389.301f,47.5567f,2.11185f}, - {827.415f,-419.468f,48.3322f,1.49232f}, - {826.402f,-349.454f,47.2722f,1.51844f}, - {817.83f,-455.715f,48.4207f,0.925025f}, - {808.953f,-325.964f,52.4043f,3.01942f}, - // Morloch - {865.554f,-438.735f,50.7333f,2.12431f}, - //coldtooth mine - //miner/digger - {-917.648f,-46.8922f,77.0872f,5.27089f}, - {-912.689f,-45.4494f,76.2277f,4.60767f}, - {-905.455f,-84.5179f,75.3642f,3.29867f}, - {-904.332f,-111.509f,75.5925f,2.47837f}, - {-904.27f,-160.419f,61.9876f,3.61192f}, - {-904.023f,-90.4558f,75.3706f,3.40339f}, - {-978.678f,-37.3136f,75.8364f,2.84489f}, - {-973.076f,-36.5013f,77.5047f,1.0821f}, - {-963.951f,-87.734f,81.5555f,0.575959f}, - {-961.941f,-90.7252f,81.6629f,0.820305f}, - {-957.623f,-186.582f,66.6021f,1.95477f}, - {-952.476f,-179.778f,78.6771f,4.5204f}, - {-950.427f,-115.007f,79.6127f,3.68264f}, - {-950.25f,-151.95f,79.4598f,-1.81423f}, - {-950.169f,-188.099f,66.6184f,5.55015f}, - {-949.944f,-142.977f,80.5382f,2.70526f}, - {-947.854f,-170.5f,79.7618f,0.942478f}, - {-946.738f,-139.567f,80.0904f,2.3911f}, - {-945.503f,-65.0654f,79.7907f,5.02655f}, - {-943.678f,-110.986f,80.2557f,0.959931f}, - {-942.993f,-56.9881f,79.8915f,5.65487f}, - {-938.197f,-155.838f,61.3111f,1.65806f}, - {-930.488f,-214.524f,72.1431f,2.1236f}, - {-929.947f,-154.449f,61.5084f,1.67552f}, - {-927.412f,-135.313f,61.1987f,3.29867f}, - {-920.677f,-156.859f,62.8033f,3.15306f}, - {-916.75f,-136.094f,62.2357f,0.0698132f}, - {-915.319f,-132.718f,62.562f,1.16984f}, - {-913.589f,-146.794f,76.9366f,1.8675f}, - {-907.572f,-148.937f,76.6898f,4.76475f}, - {-902.02f,-64.6174f,73.9707f,1.19169f}, - {-899.489f,-61.7252f,73.2498f,5.09636f}, - {-894.792f,-127.141f,75.3834f,6.14356f}, - {-892.408f,-162.525f,64.1212f,2.69884f}, - {-892.326f,-123.158f,76.0318f,5.5676f}, - {-888.468f,-148.462f,61.8012f,1.65806f}, - {-883.268f,-159.738f,63.5311f,5.20108f}, - {-877.76f,-118.07f,65.215f,2.94961f}, - {-876.792f,-128.646f,64.1045f,3.40339f}, - {-874.901f,-36.6579f,69.4246f,2.00713f}, - {-874.856f,-151.351f,62.7537f,3.57875f}, - {-872.135f,-150.08f,62.7513f,3.57201f}, - {-870.288f,-149.217f,62.5413f,3.56624f}, - {-870.03f,-6.27443f,70.3867f,2.3911f}, - {-869.023f,-82.2118f,69.5848f,3.22886f}, - {-866.354f,-40.2455f,70.842f,0.0698132f}, - {-865.305f,-152.302f,63.5044f,4.86947f}, - {-861.926f,-79.0519f,71.4178f,0.20944f}, - {-857.292f,-152.277f,63.2114f,4.18879f}, - {-853.357f,-0.696194f,72.0655f,0.994838f}, - {-850.685f,-14.2596f,70.2298f,0.20944f}, - {-839.987f,-67.7695f,72.7916f,4.93928f}, - {-839.199f,-57.0558f,73.4891f,1.67552f}, - {-836.963f,-153.224f,63.3821f,4.46804f}, - {-832.721f,-67.7555f,72.9062f,4.99164f}, - {-821.496f,-143.095f,63.1292f,0.541052f}, - {-818.829f,-153.004f,62.1757f,6.12611f}, - //special - {-954.622f,-110.958f,80.7911f,6.24828f}, - {-951.477f,-53.9647f,80.0235f,5.32325f}, - {-946.812f,-126.04f,78.8601f,5.15265f}, - {-940.689f,-140.707f,79.9225f,2.79253f}, - {-933.954f,-159.632f,60.778f,2.56563f}, - {-922.537f,-130.291f,61.3756f,4.95674f}, - {-915.862f,-151.74f,76.9427f,0.942478f}, - {-888.321f,-159.831f,62.5303f,1.20428f}, - {-874.361f,-42.4751f,69.4316f,0.785398f}, - {-873.19f,-50.4899f,70.0568f,-2.41288f}, - {-868.511f,-148.386f,62.3547f,3.57875f}, - {-868.44f,-121.649f,64.5056f,3.33358f}, - {-868.324f,-77.7196f,71.4768f,5.41052f}, - {-859.846f,-19.6549f,70.7304f,1.97222f}, - {-828.05f,-150.508f,62.2019f,2.14675f}, - {-826.254f,-58.6911f,72.0041f,3.68264f}, - {-976.086f,-44.1775f,76.029f,1.46608f}, - {-971.864f,-87.4223f,81.4954f,5.8294f}, - {-966.551f,-74.1111f,80.0243f,4.2129f}, - {-958.509f,-173.652f,77.9013f,6.24828f}, - {-951.511f,-181.242f,65.529f,4.39823f}, - {-940.967f,-186.243f,77.698f,1.28164f}, - {-930.004f,-65.0898f,79.077f,0.0581657f}, - {-920.864f,-40.2009f,78.256f,5.16617f}, - {-919.089f,-148.021f,62.0317f,2.59327f}, - {-901.516f,-116.329f,75.6876f,0.471239f}, - {-897.864f,-84.4348f,74.083f,3.00197f}, - {-897.617f,-52.0457f,71.9503f,4.36332f}, - {-894.891f,-153.951f,61.6827f,3.23569f}, - {-893.933f,-111.625f,75.6591f,4.22536f}, - {-883.265f,-152.854f,61.8384f,0.0941087f}, - {-868.293f,-147.243f,62.1097f,3.2056f}, - {-867.501f,-11.8709f,70.018f,6.14356f}, - {-866.699f,-147.54f,62.1646f,3.57878f}, - {-866.566f,-91.1916f,67.4414f,4.56707f}, - {-857.272f,-141.142f,61.7356f,4.17134f}, - {-847.446f,-98.0061f,68.5131f,3.24631f}, - {-837.026f,-140.729f,62.5141f,5.51524f}, - {-824.204f,-65.053f,72.3381f,3.01942f}, - //vermin (s.th special for this mine) - {-951.955f,-197.5f,77.212f,5.63741f}, - {-944.837f,-199.608f,77.0737f,4.97419f}, - {-933.494f,-209.063f,73.7803f,5.88176f}, - {-929.666f,-201.308f,73.7032f,5.02655f}, - {-978.997f,-249.356f,65.4345f,5.05464f}, - {-974.565f,-224.828f,69.5858f,4.88846f}, - {-946.514f,-259.239f,66.0874f,3.78132f}, - {-918.402f,-250.439f,69.5271f,2.21352f}, - {-910.14f,-229.959f,72.9279f,0.27677f}, - {-851.563f,-88.6527f,68.5983f,3.61896f}, - //boss - {-848.902f,-92.931f,68.6325f,3.33350}, - //herald - {-48.459f,-288.802f,55.47f,1.0}, - //triggers - {637.083,-32.6603,45.9715,1.14353}, //firstaid_station - {669.007f,-294.078f,30.2909f,2.77507f}, //stormpike_grave - {77.8013f,-404.7f,46.7549f,-0.872665f}, //stoneheart_grave - {-202.581f,-112.73f,78.4876f,-0.715585f}, //snowfall_grave - {-611.962f,-396.17f,60.8351f,2.53682f}, //iceblood_grave - {-1082.45f,-346.823f,54.9219f,-1.53589f}, //frostwolf_grave - {-1402.21f,-307.431f,89.4424f,0.191986f}, //frostwolf_hut - {553.779f,-78.6566f,51.9378f,-1.22173f}, //dunbaldar_south - {674.001f,-143.125f,63.6615f,0.994838f}, //dunbaldar_north - {203.281f,-360.366f,56.3869f,-0.925024}, //icewing_bunker - {-152.437f,-441.758f,40.3982f,-1.95477f}, //stoneheart_bunker - {-571.88f,-262.777f,75.0087f,-0.802851f}, //iceblood_tower - {-768.907f,-363.71f,90.8949f,1.07991f}, //tower_point - {-1302.9f,-316.981f,113.867f,2.00713f}, //frostwolf_etower - {-1297.5f,-266.767f,114.15f,3.31044f}, //frostwolf_wtower - {-57.7891f,-286.597f,15.6479f,6.02139f}, //AV_NPC_A_CAPTAIN balinda - {722.43f,-10.9982f,50.7046f,3.42085f}, //AV_NPC_A_BOSS vanndar - {-545.23f,-165.35f,57.7886f,3.01145f}, //AV_NPC_H_CAPTAIN galvangar - {-1370.9f,-219.793f,98.4258f,5.04381f} //AV_NPC_H_BOSS drek thar -}; - -enum BG_AV_CreatureIds -{ - - AV_NPC_A_GRAVEDEFENSE0 = 0, // stormpike Defender - AV_NPC_A_GRAVEDEFENSE1 = 1, // seasoned defender - AV_NPC_A_GRAVEDEFENSE2 = 2, // veteran defender - AV_NPC_A_GRAVEDEFENSE3 = 3, // champion defender - AV_NPC_A_TOWERDEFENSE = 4, // stormpike bowman - AV_NPC_A_CAPTAIN = 5, // balinda - AV_NPC_A_BOSS = 6, // vanndar - - AV_NPC_H_GRAVEDEFENSE0 = 7, // frostwolf guardian - AV_NPC_H_GRAVEDEFENSE1 = 8, // seasoned guardian - AV_NPC_H_GRAVEDEFENSE2 = 9, // veteran guardian - AV_NPC_H_GRAVEDEFENSE3 = 10, // champion guardian - AV_NPC_H_TOWERDEFENSE = 11, // frostwolf bowman - AV_NPC_H_CAPTAIN = 12, // galvangar - AV_NPC_H_BOSS = 13, // drek thar - - AV_NPC_A_MARSHAL_SOUTH = 14, - AV_NPC_MARSHAL_NORTH = 15, - AV_NPC_A_MARSHAL_ICE = 16, - AV_NPC_A_MARSHAL_STONE = 17, - AV_NPC_H_MARSHAL_ICE = 18, - AV_NPC_H_MARSHAL_TOWER = 19, - AV_NPC_MARSHAL_ETOWER = 20, - AV_NPC_H_MARSHAL_WTOWER= 21, - AV_NPC_N_MINE_N_1 = 22, - AV_NPC_N_MINE_N_2 = 23, - AV_NPC_N_MINE_N_3 = 24, - AV_NPC_N_MINE_N_4 = 25, - AV_NPC_N_MINE_A_1 = 26, - AV_NPC_N_MINE_A_2 = 27, - AV_NPC_N_MINE_A_3 = 28, - AV_NPC_N_MINE_A_4 = 29, - AV_NPC_N_MINE_H_1 = 30, - AV_NPC_N_MINE_H_2 = 31, - AV_NPC_N_MINE_H_3 = 32, - AV_NPC_N_MINE_H_4 = 33, - AV_NPC_S_MINE_N_1 = 34, - AV_NPC_S_MINE_N_2 = 35, - AV_NPC_S_MINE_N_3 = 36, - AV_NPC_S_MINE_N_4 = 37, - AV_NPC_S_MINE_N_S = 38, - AV_NPC_S_MINE_A_1 = 39, - AV_NPC_S_MINE_A_2 = 40, - AV_NPC_S_MINE_A_3 = 41, - AV_NPC_S_MINE_A_4 = 42, - AV_NPC_S_MINE_H_1 = 43, - AV_NPC_S_MINE_H_2 = 44, - AV_NPC_S_MINE_H_3 = 45, - AV_NPC_S_MINE_H_4 = 46, - AV_NPC_HERALD = 47, - AV_NPC_INFO_MAX = 48 - -}; - -//entry, team, minlevel, maxlevel -//TODO this array should be removed, the only needed things are the entrys (for spawning(?) and handlekillunit) -const uint32 BG_AV_CreatureInfo[AV_NPC_INFO_MAX][4] = { - { 12050, 1216, 58, 58 }, //Stormpike Defender - { 13326, 1216, 59, 59 }, //Seasoned Defender - { 13331, 1216, 60, 60 }, //Veteran Defender - { 13422, 1216, 61, 61 }, //Champion Defender - { 13358, 1216, 59, 60 }, //Stormpike Bowman //i think its 60,61 and 69,70.. but this is until now not possible TODO look if this is ok - { 11949,469,0,0},//not spawned with this data, but used for handlekillunit - { 11948,469,0,0},//not spawned with this data, but used for handlekillunit - { 12053, 1214, 58, 58 }, //Frostwolf Guardian - { 13328, 1214, 59, 59 }, //Seasoned Guardian - { 13332, 1214, 60, 60 }, //Veteran Guardian - { 13421, 1214, 61, 61 }, //Champion Guardian - { 13359, 1214, 59, 60 }, //Frostwolf Bowman - { 11947,67,0,0}, //not spawned with this data, but used for handlekillunit - { 11946,67,0,0}, //not spawned with this data, but used for handlekillunit - { 14763, 1534, 60, 60 }, //Dun Baldar South Marshal - { 14762, 1534, 60, 60 }, //Dun Baldar North Marshal - { 14764, 1534, 60, 60 }, //Icewing Marshal - { 14765, 1534, 60, 60 }, //Stonehearth Marshal - - { 14773, 1214, 60, 60 }, //Iceblood Warmaster - { 14776, 1214, 60, 60 }, //Tower Point Warmaster - { 14772, 1214, 60, 60 }, //East Frostwolf Warmaster - { 14777, 1214, 60, 60 }, //West Frostwolf Warmaster - - { 10987, 59, 52, 53 }, //Irondeep Trogg - { 11600, 59, 53, 54 }, //Irondeep Shaman - { 11602, 59, 54, 55 }, //Irondeep Skullthumper - { 11657, 59, 58, 58 }, //Morloch - - {13396,469,52,53}, //irondeep alliance TODO: get the right ids - {13080,469,53,54}, - {13098,469,54,55}, - {13078,469,58,58}, - - {13397,67,52,53}, //irondeep horde - {13099,67,53,54}, - {13081,67,54,55}, - {13079,67,58,58}, - - { 11603, 59, 52, 53 }, //south mine neutral - { 11604, 59, 53, 54 }, - { 11605, 59, 54, 55 }, - { 11677, 59, 58, 58 }, - { 10982, 59, 52, 53 }, //vermin - - {13317,469,52,53}, //alliance - {13096,469,54,55}, //explorer - {13087,469,54,55}, //invader - {13086,469,58,58}, - - {13316,67,52,53}, //horde - {13097,67,54,55}, //surveypr - {13089,67,54,55}, //guard - {13088,67,58,58}, - {14848,67,58,58} //Herald - -}; - -//x,y,z,o,static_creature_info-id -const float BG_AV_StaticCreaturePos[AV_STATICCPLACE_MAX][5] = { //static creatures - {-1235.31f,-340.777f,60.5088f,3.31613f,0 },//2225 - Zora Guthrek - {-1244.02f,-323.795f,61.0485f,5.21853f,1 },//3343 - Grelkor - {-1235.16f,-332.302f,60.2985f,2.96706f,2 },//3625 - Rarck - {587.303f,-42.8257f,37.5615f,5.23599f,3 },//4255 - Brogus Thunderbrew - {643.635f,-58.3987f,41.7405f,4.72984f,4 },//4257 - Lana Thunderbrew - {591.464f,-44.452f,37.6166f,5.65487f,5 },//5134 - Jonivera Farmountain - {608.515f,-33.3935f,42.0003f,5.41052f,6 },//5135 - Svalbrad Farmountain - {617.656f,-32.0701f,42.7168f,4.06662f,7 },//5139 - Kurdrum Barleybeard - {-1183.76f,-268.295f,72.8233f,3.28122f,8 },//10364 - Yaelika Farclaw - {-1187.86f,-275.31f,73.0481f,3.63028f,9 },//10367 - Shrye Ragefist - {-1008.42f,-368.006f,55.3426f,5.95647f,10 },//10981 - Frostwolf - {-1091.92f,-424.28f,53.0139f,2.93958f,10 },//10981 - Frostwolf - {-558.455f,-198.768f,58.1755f,4.97946f,10 },//10981 - Frostwolf - {-861.247f,-312.51f,55.1427f,3.35382f,10 },//10981 - Frostwolf - {-1003.81f,-395.913f,50.4736f,2.85631f,10 },//10981 - Frostwolf - {-904.5f,-289.815f,65.1222f,5.7847f,10 },//10981 - Frostwolf - {-1064.41f,-438.839f,51.3614f,1.88857f,10 },//10981 - Frostwolf - {258.814f,76.2017f,18.6468f,6.19052f,11 },//10986 - Snowblind Harpy - {265.838f,-315.846f,-16.5429f,3.15917f,11 },//10986 - Snowblind Harpy - {426.485f,-51.1927f,-5.66286f,1.60347f,11 },//10986 - Snowblind Harpy - {452.044f,-33.9594f,-0.044651f,2.72815f,11 },//10986 - Snowblind Harpy - {266.032f,-315.639f,-16.5429f,4.67962f,11 },//10986 - Snowblind Harpy - {532.64f,-54.5863f,20.7024f,2.93215f,11 },//10986 - Snowblind Harpy - {295.183f,-299.908f,-34.6123f,0.135851f,12 },//10990 - Alterac Ram - {421.08f,-225.006f,-23.73f,0.166754f,12 },//10990 - Alterac Ram - {-55.7766f,-192.498f,20.4352f,6.12221f,12 },//10990 - Alterac Ram - {527.887f,-477.223f,62.3559f,0.170935f,12 },//10990 - Alterac Ram - {389.144f,-346.508f,-30.334f,4.14117f,12 },//10990 - Alterac Ram - {108.121f,-322.248f,37.5655f,4.46788f,12 },//10990 - Alterac Ram - {507.479f,-67.9403f,10.3571f,3.26304f,12 },//10990 - Alterac Ram - {329.071f,-185.016f,-29.1542f,0.356943f,12 },//10990 - Alterac Ram - {252.449f,-422.313f,35.1404f,4.53771f,12 },//10990 - Alterac Ram - {358.882f,-118.061f,-24.9119f,2.29257f,12 },//10990 - Alterac Ram - {487.151f,-174.229f,14.7558f,4.73192f,12 },//10990 - Alterac Ram - {449.652f,-123.561f,6.14273f,6.12029f,12 },//10990 - Alterac Ram - {272.419f,-261.802f,-41.8835f,3.66559f,12 },//10990 - Alterac Ram - {359.021f,-210.954f,-29.3483f,4.31339f,12 },//10990 - Alterac Ram - {450.598f,-318.048f,-37.7548f,0.655219f,12 },//10990 - Alterac Ram - {509.333f,-218.2f,3.05439f,3.66292f,12 },//10990 - Alterac Ram - {485.771f,-223.613f,-1.53f,2.04862f,12 },//10990 - Alterac Ram - {486.636f,-452.172f,39.6592f,2.3341f,12 },//10990 - Alterac Ram - {702.783f,-257.494f,25.9777f,1.68329f,12 },//10990 - Alterac Ram - {460.942f,-199.263f,-6.0149f,0.380506f,12 },//10990 - Alterac Ram - {483.108f,-115.307f,10.1056f,3.69701f,12 },//10990 - Alterac Ram - {471.601f,-154.174f,14.0702f,5.5807f,12 },//10990 - Alterac Ram - {213.938f,-420.793f,41.2549f,5.71394f,12 },//10990 - Alterac Ram - {289.387f,-294.685f,-33.9073f,0.555494f,12 },//10990 - Alterac Ram - {155.649f,-402.891f,43.3915f,5.94838f,12 },//10990 - Alterac Ram - {517.184f,-295.105f,-9.78195f,6.05668f,12 },//10990 - Alterac Ram - {102.334f,-332.165f,38.9812f,3.31445f,12 },//10990 - Alterac Ram - {320.244f,-107.793f,-42.6357f,-1.00311f,12 },//10990 - Alterac Ram - {217.976f,110.774f,15.7603f,4.56793f,13 },//11675 - Snowblind Windcaller - {269.872f,6.66684f,20.7592f,0.381212f,13 },//11675 - Snowblind Windcaller - {313.528f,-319.041f,-27.2373f,0.554098f,13 },//11675 - Snowblind Windcaller - {435.441f,-39.9289f,-0.169651f,0.549454f,13 },//11675 - Snowblind Windcaller - {315.115f,-317.62f,-29.1123f,0.90111f,13 },//11675 - Snowblind Windcaller - {428.091f,-122.731f,3.40332f,6.05901f,14 },//11678 - Snowblind Ambusher - {235.05f,85.5705f,18.3079f,-0.914255f,14 },//11678 - Snowblind Ambusher - {-1553.04f,-344.342f,64.4163f,6.09933f,15 },//11839 - Wildpaw Brute - {-545.23f,-165.35f,57.7886f,3.01145f,16 },//11947 - Captain Galvangar - {722.43f,-10.9982f,50.7046f,3.42085f,17 },//11948 - Vanndar Stormpike - {-57.7891f,-286.597f,15.6479f,6.02139f,18 },//11949 - Captain Balinda Stonehearth - {930.498f,-520.755f,93.7334f,1.8326f,19 },//11997 - Stormpike Herald - {-776.092f,-345.161f,67.4092f,1.89257f,20 },//12051 - Frostwolf Legionnaire - {-1224.63f,-308.144f,65.0087f,4.01139f,20 },//12051 - Frostwolf Legionnaire - {-713.039f,-442.515f,82.8638f,0.68724f,20 },//12051 - Frostwolf Legionnaire - {-711.783f,-444.061f,82.7039f,0.683494f,20 },//12051 - Frostwolf Legionnaire - {587.633f,-45.9816f,37.5438f,5.81195f,21 },//12096 - Stormpike Quartermaster - {-1293.79f,-194.407f,72.4398f,5.84685f,22 },//12097 - Frostwolf Quartermaster - {446.163f,-377.119f,-1.12725f,0.209526f,23 },//12127 - Stormpike Guardsman - {549.348f,-399.254f,53.3537f,3.24729f,23 },//12127 - Stormpike Guardsman - {549.801f,-401.217f,53.8305f,3.24729f,23 },//12127 - Stormpike Guardsman - {192.704f,-406.874f,42.9183f,6.10696f,23 },//12127 - Stormpike Guardsman - {441.305f,-435.765f,28.2385f,2.14472f,23 },//12127 - Stormpike Guardsman - {192.982f,-404.891f,43.0132f,6.1061f,23 },//12127 - Stormpike Guardsman - {355.342f,-391.989f,-0.486707f,3.00643f,23 },//12127 - Stormpike Guardsman - {446.035f,-375.104f,-1.12725f,0.21033f,23 },//12127 - Stormpike Guardsman - {697.864f,-433.238f,62.7914f,1.65776f,23 },//12127 - Stormpike Guardsman - {610.74f,-331.585f,30.8021f,5.14253f,23 },//12127 - Stormpike Guardsman - {609.815f,-329.775f,30.9271f,-2.38829f,23 },//12127 - Stormpike Guardsman - {695.874f,-433.434f,62.8543f,1.65776f,23 },//12127 - Stormpike Guardsman - {443.337f,-435.283f,28.6842f,2.13768f,23 },//12127 - Stormpike Guardsman - {-1251.5f,-316.327f,62.6565f,5.02655f,24 },//13176 - Smith Regzar - {-1332.0f,-331.243f,91.2631f,1.50098f,25 },//13179 - Wing Commander Guse - {569.983f,-94.9992f,38.0325f,1.39626f,26 },//13216 - Gaelden Hammersmith - {-1244.92f,-308.916f,63.2525f,1.62316f,27 },//13218 - Grunnda Wolfheart - {-1319.56f,-342.675f,60.3404f,1.20428f,28 },//13236 - Primalist Thurloga - {647.61f,-61.1548f,41.7405f,4.24115f,29 },//13257 - Murgot Deepforge - {-1321.64f,-343.73f,60.4833f,1.01229f,30 },//13284 - Frostwolf Shaman - {-1317.61f,-342.853f,60.3726f,2.47837f,30 },//13284 - Frostwolf Shaman - {-1319.31f,-344.475f,60.3825f,1.72788f,30 },//13284 - Frostwolf Shaman - {569.963f,-42.0218f,37.7581f,4.27606f,31 },//13438 - Wing Commander Slidore - {729.2f,-78.812f,51.6335f,3.97935f,32 },//13442 - Arch Druid Renferal - {729.118f,-82.8713f,51.6335f,2.53073f,33 },//13443 - Druid of the Grove - {725.554f,-79.4973f,51.6335f,5.27089f,33 },//13443 - Druid of the Grove - {724.768f,-84.1642f,51.6335f,0.733038f,33 },//13443 - Druid of the Grove - {596.68f,-83.0633f,39.0051f,6.24828f,34 },//13447 - Corporal Noreg Stormpike - {600.032f,-2.92475f,42.0788f,5.00909f,35 },//13577 - Stormpike Ram Rider Commander - {610.239f,-21.8454f,43.272f,4.90438f,36 },//13617 - Stormpike Stable Master - {613.422f,-150.764f,33.4517f,5.55015f,37 },//13797 - Mountaineer Boombellow - {-1213.91f,-370.619f,56.4455f,0.837758f,38 },//13798 - Jotek - {704.35f,-22.9071f,50.2187f,0.785398f,39 },//13816 - Prospector Stonehewer - {-1271.24f,-335.766f,62.3971f,5.75959f,40 },//14185 - Najak Hexxen - {-1268.64f,-332.688f,62.6171f,5.28835f,41 },//14186 - Ravak Grimtotem - {648.363f,-65.2233f,41.7405f,3.12414f,42 },//14187 - Athramanis - {648.238f,-67.8931f,41.7405f,2.60054f,43 },//14188 - Dirk Swindle - {-1223.44f,-309.833f,64.9331f,4.0131f,44 },//14282 - Frostwolf Bloodhound - {-1226.4f,-307.136f,64.9706f,4.0145f,44 },//14282 - Frostwolf Bloodhound - {356.001f,-389.969f,-0.438796f,3.0334f,45 },//14283 - Stormpike Owl - {355.835f,-394.005f,-0.60149f,3.02498f,45 },//14283 - Stormpike Owl - {882.266f,-496.378f,96.7707f,4.83248f,45 },//14283 - Stormpike Owl - {878.649f,-495.917f,96.6171f,4.67693f,45 },//14283 - Stormpike Owl - {932.851f,-511.017f,93.6748f,3.61004f,45 },//14283 - Stormpike Owl - {935.806f,-513.983f,93.7436f,3.61788f,45 },//14283 - Stormpike Owl - {947.412f,-509.982f,95.1098f,2.82743f,46 },//14284 - Stormpike Battleguard - {934.557f,-512.395f,93.662f,3.61004f,46 },//14284 - Stormpike Battleguard - {939.42f,-502.777f,94.5887f,5.14872f,46 },//14284 - Stormpike Battleguard - {854.276f,-494.241f,96.8017f,5.44543f,46 },//14284 - Stormpike Battleguard - {776.621f,-487.775f,99.4049f,3.50811f,46 },//14284 - Stormpike Battleguard - {880.169f,-495.699f,96.6204f,4.8325f,46 },//14284 - Stormpike Battleguard - {773.651f,-497.482f,99.0408f,2.11185f,46 },//14284 - Stormpike Battleguard - {949.1f,-506.913f,95.4237f,3.31613f,46 },//14284 - Stormpike Battleguard - {-1370.9f,-219.793f,98.4258f,5.04381f,47}, //drek thar - -}; - -const uint32 BG_AV_StaticCreatureInfo[51][4] = { - { 2225, 1215, 55, 55 }, //Zora Guthrek - { 3343, 1215, 55, 55 }, //Grelkor - { 3625, 1215, 55, 55 }, //Rarck - { 4255, 1217, 55, 55 }, //Brogus Thunderbrew - { 4257, 1217, 55, 55 }, //Lana Thunderbrew - { 5134, 1217, 55, 55 }, //Jonivera Farmountain - { 5135, 1217, 55, 55 }, //Svalbrad Farmountain - { 5139, 1217, 55, 55 }, //Kurdrum Barleybeard - { 10364, 1215, 55, 55 }, //Yaelika Farclaw - { 10367, 1215, 55, 55 }, //Shrye Ragefist - { 10981, 38, 50, 51 }, //Frostwolf - { 10986, 514, 52, 53 }, //Snowblind Harpy - { 10990, 1274, 50, 51 }, //Alterac Ram - { 11675, 514, 53, 53 }, //Snowblind Windcaller - { 11678, 14, 52, 53 }, //Snowblind Ambusher - { 11839, 39, 56, 56 }, //Wildpaw Brute - { 11947, 1214, 61, 61 }, //Captain Galvangar --TODO: doubled - { 11948, 1216, 63, 63 }, //Vanndar Stormpike - { 11949, 1216, 61, 61 }, //Captain Balinda Stonehearth - { 11997, 1334, 60, 60 }, //Stormpike Herald - { 12051, 1214, 57, 57 }, //Frostwolf Legionnaire - { 12096, 1217, 55, 55 }, //Stormpike Quartermaster - { 12097, 1215, 55, 55 }, //Frostwolf Quartermaster - { 12127, 1216, 57, 57 }, //Stormpike Guardsman - { 13176, 1215, 60, 60 }, //Smith Regzar - { 13179, 1215, 59, 59 }, //Wing Commander Guse - { 13216, 1217, 58, 58 }, //Gaelden Hammersmith - { 13218, 1215, 58, 58 }, //Grunnda Wolfheart - { 13236, 1214, 60, 60 }, //Primalist Thurloga - { 13257, 1216, 60, 60 }, //Murgot Deepforge - { 13284, 1214, 58, 58 }, //Frostwolf Shaman - { 13438, 1217, 58, 58 }, //Wing Commander Slidore - { 13442, 1216, 60, 60 }, //Arch Druid Renferal - { 13443, 1216, 60, 60 }, //Druid of the Grove - { 13447, 1216, 58, 58 }, //Corporal Noreg Stormpike - { 13577, 1216, 60, 60 }, //Stormpike Ram Rider Commander - { 13617, 1216, 60, 60 }, //Stormpike Stable Master - { 13797, 32, 60, 61 }, //Mountaineer Boombellow - { 13798, 1214, 60, 61 }, //Jotek - { 13816, 1216, 61, 61 }, //Prospector Stonehewer - { 14185, 877, 59, 59 }, //Najak Hexxen - { 14186, 105, 60, 60 }, //Ravak Grimtotem - { 14187, 1594, 60, 60 }, //Athramanis - { 14188, 57, 59, 59 }, //Dirk Swindle - { 14282, 1214, 53, 54 }, //Frostwolf Bloodhound - { 14283, 1216, 53, 54 }, //Stormpike Owl - { 14284, 1216, 61, 61 }, //Stormpike Battleguard - { 11946, 1214, 63, 63 }, //Drek'Thar //TODO: make the levels right (boss=0 maybe) - { 11948, 1216, 63, 63 }, //Vanndar Stormpike - { 11947, 1214, 61, 61 }, //Captain Galvangar - { 11949, 1216, 61, 61 } //Captain Balinda Stonehearth -}; - -enum BG_AV_Graveyards -{ - AV_GRAVE_STORM_AID = 751, - AV_GRAVE_STORM_GRAVE = 689, - AV_GRAVE_STONE_GRAVE = 729, - AV_GRAVE_SNOWFALL = 169, - AV_GRAVE_ICE_GRAVE = 749, - AV_GRAVE_FROSTWOLF = 690, - AV_GRAVE_FROST_HUT = 750, - AV_GRAVE_MAIN_ALLIANCE = 611, - AV_GRAVE_MAIN_HORDE = 610 -}; - -const uint32 BG_AV_GraveyardIds[9]= { - AV_GRAVE_STORM_AID, - AV_GRAVE_STORM_GRAVE, - AV_GRAVE_STONE_GRAVE, - AV_GRAVE_SNOWFALL, - AV_GRAVE_ICE_GRAVE, - AV_GRAVE_FROSTWOLF, - AV_GRAVE_FROST_HUT, - AV_GRAVE_MAIN_ALLIANCE, - AV_GRAVE_MAIN_HORDE -}; - -enum BG_AV_BUFF -{ //TODO add all other buffs here - AV_BUFF_ARMOR = 21163, - AV_BUFF_A_CAPTAIN = 23693, //the buff which the alliance captain does - AV_BUFF_H_CAPTAIN = 22751 //the buff which the horde captain does -}; -enum BG_AV_States -{ - POINT_NEUTRAL = 0, - POINT_ASSAULTED = 1, - POINT_DESTROYED = 2, - POINT_CONTROLED = 3 -}; - -enum BG_AV_WorldStates -{ - AV_Alliance_Score = 3127, - AV_Horde_Score = 3128, - AV_SHOW_H_SCORE = 3133, - AV_SHOW_A_SCORE = 3134, - -/* - //the comments behind the state shows which icon overlaps the other.. but is, until now, unused and maybe not a good solution (but give few performance (:) - -// Graves - - // Alliance - //Stormpike first aid station - AV_AID_A_C = 1325, - AV_AID_A_A = 1326, - AV_AID_H_C = 1327, - AV_AID_H_A = 1328, - //Stormpike Graveyard - AV_PIKEGRAVE_A_C = 1333, - AV_PIKEGRAVE_A_A = 1335, - AV_PIKEGRAVE_H_C = 1334, - AV_PIKEGRAVE_H_A = 1336, - //Stoneheart Grave - AV_STONEHEART_A_C = 1302, - AV_STONEHEART_A_A = 1304, //over hc - AV_STONEHEART_H_C = 1301, //over ac - AV_STONEHEART_H_A = 1303, //over aa - //Neutral - //Snowfall Grave -*/ - AV_SNOWFALL_N = 1966, //over aa -/* - AV_SNOWFALL_A_C = 1341, //over hc - AV_SNOWFALL_A_A = 1343, //over ha - AV_SNOWFALL_H_C = 1342, - AV_SNOWFALL_H_A = 1344, //over ac - //Horde - //Iceblood grave - AV_ICEBLOOD_A_C = 1346, //over hc - AV_ICEBLOOD_A_A = 1348, //over ac - AV_ICEBLOOD_H_C = 1347, - AV_ICEBLOOD_H_A = 1349, //over aa - //Frostwolf Grave - AV_FROSTWOLF_A_C = 1337, //over hc - AV_FROSTWOLF_A_A = 1339, //over ac - AV_FROSTWOLF_H_C = 1338, - AV_FROSTWOLF_H_A = 1340, //over aa - //Frostwolf Hut - AV_FROSTWOLFHUT_A_C = 1329, //over hc - AV_FROSTWOLFHUT_A_A = 1331, //over ha - AV_FROSTWOLFHUT_H_C = 1330, - AV_FROSTWOLFHUT_H_A = 1332, //over ac - -//Towers - //Alliance - //Dunbaldar South Bunker - AV_DUNS_CONTROLLED = 1361, - AV_DUNS_DESTROYED = 1370, - AV_DUNS_ASSAULTED = 1378, - //Dunbaldar North Bunker - AV_DUNN_CONTROLLED = 1362, - AV_DUNN_DESTROYED = 1371, - AV_DUNN_ASSAULTED = 1379, - //Icewing Bunker - AV_ICEWING_CONTROLLED = 1363, - AV_ICEWING_DESTROYED = 1372, - AV_ICEWING_ASSAULTED = 1380, - //Stoneheart Bunker - AV_STONEH_CONTROLLED = 1364, - AV_STONEH_DESTROYED = 1373, - AV_STONEH_ASSAULTED = 1381, - //Horde - //Iceblood Tower - AV_ICEBLOOD_CONTROLLED = 1385, - AV_ICEBLOOD_DESTROYED = 1368, - AV_ICEBLOOD_ASSAULTED = 1390, - //Tower Point - AV_TOWERPOINT_CONTROLLED = 1384, - AV_TOWERPOINT_DESTROYED = 1367, //goes over controlled - AV_TOWERPOINT_ASSAULTED = 1389, //goes over destroyed - //Frostwolf West - AV_FROSTWOLFW_CONTROLLED = 1382, - AV_FROSTWOLFW_DESTROYED = 1365, //over controlled - AV_FROSTWOLFW_ASSAULTED = 1387, //over destroyed - //Frostwolf East - AV_FROSTWOLFE_CONTROLLED = 1383, - AV_FROSTWOLFE_DESTROYED = 1366, - AV_FROSTWOLFE_ASSAULTED = 1388, - -//mines - - AV_N_MINE_N = 1360, - AV_N_MINE_A = 1358, - AV_N_MINE_H = 1359, - - AV_S_MINE_N = 1357, - AV_S_MINE_A = 1355, - AV_S_MINE_H = 1356, - -//towers assaulted by own team (unused) - AV_STONEH_UNUSED = 1377, - AV_ICEWING_UNUSED = 1376, - AV_DUNS_UNUSED = 1375, - AV_DUNN_UNUSED = 1374, - - AV_ICEBLOOD_UNUSED = 1395, - AV_TOWERPOINT_UNUSED = 1394, - AV_FROSTWOLFE_UNUSED = 1393, - AV_FROSTWOLFW_UNUSED = 1392 -*/ - -}; - -//alliance_control neutral_control horde_control -const uint32 BG_AV_MineWorldStates[2][3] = { - {1358, 1360,1359}, - {1355, 1357,1356} -}; - -//alliance_control alliance_assault h_control h_assault -const uint32 BG_AV_NodeWorldStates[16][4] = { - //Stormpike first aid station - {1325, 1326,1327,1328}, - //Stormpike Graveyard - {1333,1335,1334,1336}, - //Stoneheart Grave - {1302,1304,1301,1303}, - //Snowfall Grave - {1341,1343,1342,1344}, - //Iceblood grave - {1346,1348,1347,1349}, - //Frostwolf Grave - {1337,1339,1338,1340}, - //Frostwolf Hut - {1329,1331,1330,1332}, - //Dunbaldar South Bunker - {1361,1375,1370,1378}, - //Dunbaldar North Bunker - {1362,1374,1371,1379}, - //Icewing Bunker - {1363,1376,1372,1380}, - //Stoneheart Bunker - {1364,1377,1373,1381}, - //Iceblood Tower - {1368,1390,1385,1395}, - //Tower Point - {1367,1389,1384,1394}, - //Frostwolf East - {1366,1388,1383,1393}, - //Frostwolf West - {1365,1387,1382,1392}, -}; - -enum BG_AV_QuestIds -{ - AV_QUEST_A_SCRAPS1 = 7223, - AV_QUEST_A_SCRAPS2 = 6781, - AV_QUEST_H_SCRAPS1 = 7224, - AV_QUEST_H_SCRAPS2 = 6741, - AV_QUEST_A_COMMANDER1 = 6942, //soldier - AV_QUEST_H_COMMANDER1 = 6825, - AV_QUEST_A_COMMANDER2 = 6941, //leutnant - AV_QUEST_H_COMMANDER2 = 6826, - AV_QUEST_A_COMMANDER3 = 6943, //commander - AV_QUEST_H_COMMANDER3 = 6827, - AV_QUEST_A_BOSS1 = 7386, // 5 cristal/blood - AV_QUEST_H_BOSS1 = 7385, - AV_QUEST_A_BOSS2 = 6881, // 1 - AV_QUEST_H_BOSS2 = 6801, - AV_QUEST_A_NEAR_MINE = 5892, //the mine near start location of team - AV_QUEST_H_NEAR_MINE = 5893, - AV_QUEST_A_OTHER_MINE = 6982, //the other mine ;) - AV_QUEST_H_OTHER_MINE = 6985, - AV_QUEST_A_RIDER_HIDE = 7026, - AV_QUEST_H_RIDER_HIDE = 7002, - AV_QUEST_A_RIDER_TAME = 7027, - AV_QUEST_H_RIDER_TAME = 7001 -}; - -struct BG_AV_NodeInfo -{ - uint16 TotalOwner; - uint16 Owner; - uint16 PrevOwner; - BG_AV_States State; - BG_AV_States PrevState; - int Timer; - bool Tower; -}; - -inline BG_AV_Nodes &operator++(BG_AV_Nodes &i){ return i = BG_AV_Nodes(i + 1); } - -class BattleGroundAVScore : public BattleGroundScore -{ - public: - BattleGroundAVScore() : GraveyardsAssaulted(0), GraveyardsDefended(0), TowersAssaulted(0), TowersDefended(0), MinesCaptured(0), LeadersKilled(0), SecondaryObjectives(0) {}; - virtual ~BattleGroundAVScore() {}; - uint32 GraveyardsAssaulted; - uint32 GraveyardsDefended; - uint32 TowersAssaulted; - uint32 TowersDefended; - uint32 MinesCaptured; - uint32 LeadersKilled; - uint32 SecondaryObjectives; -}; - -class BattleGroundAV : public BattleGround -{ - friend class BattleGroundMgr; - - public: - BattleGroundAV(); - ~BattleGroundAV(); - void Update(uint32 diff); - - /* inherited from BattlegroundClass */ - virtual void AddPlayer(Player *plr); - virtual void StartingEventCloseDoors(); - virtual void StartingEventOpenDoors(); - - void RemovePlayer(Player *plr,uint64 guid); - void HandleAreaTrigger(Player *Source, uint32 Trigger); - bool SetupBattleGround(); - virtual void ResetBGSubclass(); - - /*general stuff*/ - void UpdateScore(uint16 team, int16 points); - void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); - - /*handlestuff*/ //these are functions which get called from extern - virtual void EventPlayerClickedOnFlag(Player *source, GameObject* target_obj); - void HandleKillPlayer(Player* player, Player *killer); - void HandleKillUnit(Creature *unit, Player *killer); - void HandleQuestComplete(uint32 questid, Player *player); - bool PlayerCanDoMineQuest(int32 GOId,uint32 team); - - void EndBattleGround(uint32 winner); - - virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); - - private: - /* Nodes occupying */ - void EventPlayerAssaultsPoint(Player* player, uint32 object); - void EventPlayerDefendsPoint(Player* player, uint32 object); - void EventPlayerDestroyedPoint(BG_AV_Nodes node); - - void AssaultNode(BG_AV_Nodes node,uint16 team); - void DestroyNode(BG_AV_Nodes node); - void InitNode(BG_AV_Nodes node, uint16 team, bool tower); - void DefendNode(BG_AV_Nodes node, uint16 team); - - void PopulateNode(BG_AV_Nodes node); - void DePopulateNode(BG_AV_Nodes node); - - const BG_AV_Nodes GetNodeThroughObject(uint32 object); - const uint32 GetObjectThroughNode(BG_AV_Nodes node); - const char* GetNodeName(BG_AV_Nodes node); - const bool IsTower(BG_AV_Nodes node) { return m_Nodes[node].Tower; } - - /*mine*/ - void ChangeMineOwner(uint8 mine, uint32 team, bool initial=false); - - /*worldstates*/ - void FillInitialWorldStates(WorldPacket& data); - const uint8 GetWorldStateType(uint8 state, uint16 team); - void SendMineWorldStates(uint32 mine); - void UpdateNodeWorldState(BG_AV_Nodes node); - - /*general */ - Creature* AddAVCreature(uint16 cinfoid, uint16 type); - const uint16 GetBonusHonor(uint8 kills); //TODO remove this when the core handles this right - - /*variables */ - int32 m_Team_Scores[2]; - uint32 m_Team_QuestStatus[2][9]; //[x][y] x=team y=questcounter - - BG_AV_NodeInfo m_Nodes[BG_AV_NODES_MAX]; - - uint32 m_Mine_Owner[2]; - uint32 m_Mine_PrevOwner[2]; //only for worldstates needed - int32 m_Mine_Timer; //ticks for both teams - uint32 m_Mine_Reclaim_Timer[2]; - uint32 m_CaptainBuffTimer[2]; - bool m_CaptainAlive[2]; - - uint8 m_MaxLevel; //TODO remove this when battleground-getmaxlevel() returns something usefull - bool m_IsInformedNearVictory[2]; - -}; - -#endif - diff --git a/src/server/game/BattleGrounds/BattleGroundBE.cpp b/src/server/game/BattleGrounds/BattleGroundBE.cpp deleted file mode 100644 index d6debe45ae3..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundBE.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "BattleGround.h" -#include "BattleGroundBE.h" -#include "Language.h" -#include "Object.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "WorldPacket.h" - -BattleGroundBE::BattleGroundBE() -{ - m_BgObjects.resize(BG_BE_OBJECT_MAX); - - m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; - m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; - m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; - m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; - //we must set messageIds - m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; - m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; - m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; -} - -BattleGroundBE::~BattleGroundBE() -{ - -} - -void BattleGroundBE::Update(uint32 diff) -{ - BattleGround::Update(diff); - - /*if (GetStatus() == STATUS_IN_PROGRESS) - { - // update something - }*/ -} - -void BattleGroundBE::StartingEventCloseDoors() -{ - for (uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_4; ++i) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - - for (uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; ++i) - SpawnBGObject(i, RESPAWN_ONE_DAY); -} - -void BattleGroundBE::StartingEventOpenDoors() -{ - for (uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_2; ++i) - DoorOpen(i); - - for (uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; ++i) - SpawnBGObject(i, 60); -} - -void BattleGroundBE::AddPlayer(Player *plr) -{ - BattleGround::AddPlayer(plr); - //create score and add it to map, default values are set in constructor - BattleGroundBEScore* sc = new BattleGroundBEScore; - - m_PlayerScores[plr->GetGUID()] = sc; - - UpdateArenaWorldState(); -} - -void BattleGroundBE::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) -{ - if (GetStatus() == STATUS_WAIT_LEAVE) - return; - - UpdateArenaWorldState(); - CheckArenaWinConditions(); -} - -void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - if (!killer) - { - sLog.outError("Killer player not found"); - return; - } - - BattleGround::HandleKillPlayer(player,killer); - - UpdateArenaWorldState(); - CheckArenaWinConditions(); -} - -bool BattleGroundBE::HandlePlayerUnderMap(Player *player) -{ - player->TeleportTo(GetMapId(),6238.930176,262.963470,0.889519,player->GetOrientation(),false); - return true; -} - -void BattleGroundBE::HandleAreaTrigger(Player *Source, uint32 Trigger) -{ - // this is wrong way to implement these things. On official it done by gameobject spell cast. - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - //uint32 SpellId = 0; - //uint64 buff_guid = 0; - switch(Trigger) - { - case 4538: // buff trigger? - //buff_guid = m_BgObjects[BG_BE_OBJECT_BUFF_1]; - break; - case 4539: // buff trigger? - //buff_guid = m_BgObjects[BG_BE_OBJECT_BUFF_2]; - break; - default: - sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); - Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); - break; - } - - //if (buff_guid) - // HandleTriggerBuff(buff_guid,Source); -} - -void BattleGroundBE::FillInitialWorldStates(WorldPacket &data) -{ - data << uint32(0x9f3) << uint32(1); // 9 - UpdateArenaWorldState(); -} - -void BattleGroundBE::Reset() -{ - //call parent's class reset - BattleGround::Reset(); -} - -bool BattleGroundBE::SetupBattleGround() -{ - // gates - if (!AddObject(BG_BE_OBJECT_DOOR_1, BG_BE_OBJECT_TYPE_DOOR_1, 6287.277f, 282.1877f, 3.810925f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY) - || !AddObject(BG_BE_OBJECT_DOOR_2, BG_BE_OBJECT_TYPE_DOOR_2, 6189.546f, 241.7099f, 3.101481f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, RESPAWN_IMMEDIATELY) - || !AddObject(BG_BE_OBJECT_DOOR_3, BG_BE_OBJECT_TYPE_DOOR_3, 6299.116f, 296.5494f, 3.308032f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, RESPAWN_IMMEDIATELY) - || !AddObject(BG_BE_OBJECT_DOOR_4, BG_BE_OBJECT_TYPE_DOOR_4, 6177.708f, 227.3481f, 3.604374f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY) - // buffs - || !AddObject(BG_BE_OBJECT_BUFF_1, BG_BE_OBJECT_TYPE_BUFF_1, 6249.042f, 275.3239f, 11.22033f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120) - || !AddObject(BG_BE_OBJECT_BUFF_2, BG_BE_OBJECT_TYPE_BUFF_2, 6228.26f, 249.566f, 11.21812f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120)) - { - sLog.outErrorDb("BatteGroundBE: Failed to spawn some object!"); - return false; - } - - return true; -} - -void BattleGroundBE::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) -{ - - BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); - if (itr == m_PlayerScores.end()) // player not found... - return; - - //there is nothing special in this score - BattleGround::UpdatePlayerScore(Source,type,value, doAddHonor); - -} - -/* -21:45:46 id:231310 [S2C] SMSG_INIT_WORLD_STATES (706 = 0x02C2) len: 86 -0000: 32 02 00 00 76 0e 00 00 00 00 00 00 09 00 f3 09 | 2...v........... -0010: 00 00 01 00 00 00 f1 09 00 00 01 00 00 00 f0 09 | ................ -0020: 00 00 02 00 00 00 d4 08 00 00 00 00 00 00 d8 08 | ................ -0030: 00 00 00 00 00 00 d7 08 00 00 00 00 00 00 d6 08 | ................ -0040: 00 00 00 00 00 00 d5 08 00 00 00 00 00 00 d3 08 | ................ -0050: 00 00 00 00 00 00 | ...... - -spell 32724 - Gold Team -spell 32725 - Green Team -35774 Gold Team -35775 Green Team -*/ diff --git a/src/server/game/BattleGrounds/BattleGroundBE.h b/src/server/game/BattleGrounds/BattleGroundBE.h deleted file mode 100644 index 760d4d278c9..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundBE.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __BATTLEGROUNDBE_H -#define __BATTLEGROUNDBE_H - -class BattleGround; - -enum BattleGroundBEObjectTypes -{ - BG_BE_OBJECT_DOOR_1 = 0, - BG_BE_OBJECT_DOOR_2 = 1, - BG_BE_OBJECT_DOOR_3 = 2, - BG_BE_OBJECT_DOOR_4 = 3, - BG_BE_OBJECT_BUFF_1 = 4, - BG_BE_OBJECT_BUFF_2 = 5, - BG_BE_OBJECT_MAX = 6 -}; - -enum BattleGroundBEObjects -{ - BG_BE_OBJECT_TYPE_DOOR_1 = 183971, - BG_BE_OBJECT_TYPE_DOOR_2 = 183973, - BG_BE_OBJECT_TYPE_DOOR_3 = 183970, - BG_BE_OBJECT_TYPE_DOOR_4 = 183972, - BG_BE_OBJECT_TYPE_BUFF_1 = 184663, - BG_BE_OBJECT_TYPE_BUFF_2 = 184664 -}; - -class BattleGroundBEScore : public BattleGroundScore -{ - public: - BattleGroundBEScore() {}; - virtual ~BattleGroundBEScore() {}; -}; - -class BattleGroundBE : public BattleGround -{ - friend class BattleGroundMgr; - - public: - BattleGroundBE(); - ~BattleGroundBE(); - void Update(uint32 diff); - - /* inherited from BattlegroundClass */ - virtual void AddPlayer(Player *plr); - virtual void StartingEventCloseDoors(); - virtual void StartingEventOpenDoors(); - - void RemovePlayer(Player *plr, uint64 guid); - void HandleAreaTrigger(Player *Source, uint32 Trigger); - bool SetupBattleGround(); - virtual void Reset(); - virtual void FillInitialWorldStates(WorldPacket &d); - void HandleKillPlayer(Player* player, Player *killer); - bool HandlePlayerUnderMap(Player * plr); - - /* Scorekeeping */ - void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); -}; -#endif diff --git a/src/server/game/BattleGrounds/BattleGroundDS.cpp b/src/server/game/BattleGrounds/BattleGroundDS.cpp deleted file mode 100644 index 9036ef83f93..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundDS.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "BattleGround.h" -#include "BattleGroundDS.h" -#include "Language.h" -#include "Player.h" -#include "Object.h" -#include "ObjectMgr.h" -#include "WorldPacket.h" - -BattleGroundDS::BattleGroundDS() -{ - m_BgObjects.resize(BG_DS_OBJECT_MAX); - - m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; - m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; - m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; - m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; - //we must set messageIds - m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; - m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; - m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; -} - -BattleGroundDS::~BattleGroundDS() -{ - -} - -void BattleGroundDS::Update(uint32 diff) -{ - BattleGround::Update(diff); - if (getWaterFallTimer() < diff) - { - if (isWaterFallActive()) - { - setWaterFallTimer(urand(BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX)); - for (uint32 i = BG_DS_OBJECT_WATER_1; i <= BG_DS_OBJECT_WATER_2; ++i) - SpawnBGObject(i, getWaterFallTimer()); - setWaterFallActive(false); - } - else - { - setWaterFallTimer(BG_DS_WATERFALL_DURATION); - for (uint32 i = BG_DS_OBJECT_WATER_1; i <= BG_DS_OBJECT_WATER_2; ++i) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - setWaterFallActive(true); - } - } - else - setWaterFallTimer(getWaterFallTimer() - diff); -} - -void BattleGroundDS::StartingEventCloseDoors() -{ - for (uint32 i = BG_DS_OBJECT_DOOR_1; i <= BG_DS_OBJECT_DOOR_2; ++i) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); -} - -void BattleGroundDS::StartingEventOpenDoors() -{ - for (uint32 i = BG_DS_OBJECT_DOOR_1; i <= BG_DS_OBJECT_DOOR_2; ++i) - DoorOpen(i); - - for (uint32 i = BG_DS_OBJECT_BUFF_1; i <= BG_DS_OBJECT_BUFF_2; ++i) - SpawnBGObject(i, 60); - - setWaterFallTimer(urand(BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX)); - setWaterFallActive(false); - - for (uint32 i = BG_DS_OBJECT_WATER_1; i <= BG_DS_OBJECT_WATER_2; ++i) - SpawnBGObject(i, getWaterFallTimer()); -} - -void BattleGroundDS::AddPlayer(Player *plr) -{ - BattleGround::AddPlayer(plr); - //create score and add it to map, default values are set in constructor - BattleGroundDSScore* sc = new BattleGroundDSScore; - - m_PlayerScores[plr->GetGUID()] = sc; - - UpdateArenaWorldState(); -} - -void BattleGroundDS::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) -{ - if (GetStatus() == STATUS_WAIT_LEAVE) - return; - - UpdateArenaWorldState(); - CheckArenaWinConditions(); -} - -void BattleGroundDS::HandleKillPlayer(Player* player, Player* killer) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - if (!killer) - { - sLog.outError("BattleGroundDS: Killer player not found"); - return; - } - - BattleGround::HandleKillPlayer(player,killer); - - UpdateArenaWorldState(); - CheckArenaWinConditions(); -} - -void BattleGroundDS::HandleAreaTrigger(Player *Source, uint32 Trigger) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - switch(Trigger) - { - case 5347: - case 5348: - break; - default: - sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); - Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); - break; - } -} - -bool BattleGroundDS::HandlePlayerUnderMap(Player *player) -{ - player->TeleportTo(GetMapId(), 1299.046, 784.825, 9.338, 2.422, false); - return true; -} - -void BattleGroundDS::FillInitialWorldStates(WorldPacket &data) -{ - data << uint32(3610) << uint32(1); // 9 show - UpdateArenaWorldState(); -} - -void BattleGroundDS::Reset() -{ - //call parent's class reset - BattleGround::Reset(); -} - - -bool BattleGroundDS::SetupBattleGround() -{ - // gates - if (!AddObject(BG_DS_OBJECT_DOOR_1, BG_DS_OBJECT_TYPE_DOOR_1, 1350.95, 817.2, 20.8096, 3.15, 0, 0, 0.99627, 0.0862864, RESPAWN_IMMEDIATELY) - || !AddObject(BG_DS_OBJECT_DOOR_2, BG_DS_OBJECT_TYPE_DOOR_2, 1232.65, 764.913, 20.0729, 6.3, 0, 0, 0.0310211, -0.999519, RESPAWN_IMMEDIATELY) - // water - || !AddObject(BG_DS_OBJECT_WATER_1, BG_DS_OBJECT_TYPE_WATER_1, 1291.56, 790.837, 7.1, 3.14238, 0, 0, 0.694215, -0.719768, 120) - || !AddObject(BG_DS_OBJECT_WATER_2, BG_DS_OBJECT_TYPE_WATER_2, 1291.56, 790.837, 7.1, 3.14238, 0, 0, 0.694215, -0.719768, 120) - // buffs - || !AddObject(BG_DS_OBJECT_BUFF_1, BG_DS_OBJECT_TYPE_BUFF_1, 1291.7, 813.424, 7.11472, 4.64562, 0, 0, 0.730314, -0.683111, 120) - || !AddObject(BG_DS_OBJECT_BUFF_2, BG_DS_OBJECT_TYPE_BUFF_2, 1291.7, 768.911, 7.11472, 1.55194, 0, 0, 0.700409, 0.713742, 120)) - { - sLog.outErrorDb("BatteGroundDS: Failed to spawn some object!"); - return false; - } - - return true; -} diff --git a/src/server/game/BattleGrounds/BattleGroundDS.h b/src/server/game/BattleGrounds/BattleGroundDS.h deleted file mode 100644 index 2ced5c88fd1..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundDS.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __BATTLEGROUNDDS_H -#define __BATTLEGROUNDDS_H - -class BattleGround; - -enum BattleGroundDSObjectTypes -{ - BG_DS_OBJECT_DOOR_1 = 0, - BG_DS_OBJECT_DOOR_2 = 1, - BG_DS_OBJECT_WATER_1 = 2, - BG_DS_OBJECT_WATER_2 = 3, - BG_DS_OBJECT_BUFF_1 = 4, - BG_DS_OBJECT_BUFF_2 = 5, - BG_DS_OBJECT_MAX = 6 -}; - -enum BattleGroundDSObjects -{ - BG_DS_OBJECT_TYPE_DOOR_1 = 192642, - BG_DS_OBJECT_TYPE_DOOR_2 = 192643, - BG_DS_OBJECT_TYPE_WATER_1 = 194395, - BG_DS_OBJECT_TYPE_WATER_2 = 191877, - BG_DS_OBJECT_TYPE_BUFF_1 = 184663, - BG_DS_OBJECT_TYPE_BUFF_2 = 184664 -}; - -enum BattleGroundDSData -{ // These values are NOT blizzlike... need the correct data! - BG_DS_WATERFALL_TIMER_MIN = 30000, - BG_DS_WATERFALL_TIMER_MAX = 60000, - BG_DS_WATERFALL_DURATION = 10000, -}; - -class BattleGroundDSScore : public BattleGroundScore -{ - public: - BattleGroundDSScore() {}; - virtual ~BattleGroundDSScore() {}; - //TODO fix me -}; - -class BattleGroundDS : public BattleGround -{ - friend class BattleGroundMgr; - - public: - BattleGroundDS(); - ~BattleGroundDS(); - void Update(uint32 diff); - - /* inherited from BattlegroundClass */ - virtual void AddPlayer(Player *plr); - virtual void StartingEventCloseDoors(); - virtual void StartingEventOpenDoors(); - - void RemovePlayer(Player *plr, uint64 guid); - void HandleAreaTrigger(Player *Source, uint32 Trigger); - bool SetupBattleGround(); - virtual void Reset(); - virtual void FillInitialWorldStates(WorldPacket &d); - void HandleKillPlayer(Player* player, Player *killer); - bool HandlePlayerUnderMap(Player * plr); - private: - uint32 m_waterTimer; - bool m_waterfallActive; - protected: - bool isWaterFallActive() { return m_waterfallActive; }; - void setWaterFallActive(bool active) { m_waterfallActive = active; }; - void setWaterFallTimer(uint32 timer) { m_waterTimer = timer; }; - uint32 getWaterFallTimer() { return m_waterTimer; }; -}; -#endif diff --git a/src/server/game/BattleGrounds/BattleGroundEY.cpp b/src/server/game/BattleGrounds/BattleGroundEY.cpp deleted file mode 100644 index 20f023e4c2a..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundEY.cpp +++ /dev/null @@ -1,938 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ObjectMgr.h" -#include "World.h" -#include "WorldPacket.h" -#include "BattleGroundMgr.h" -#include "BattleGround.h" -#include "BattleGroundEY.h" -#include "Creature.h" -#include "Language.h" -#include "Object.h" -#include "Player.h" -#include "Util.h" - -// these variables aren't used outside of this file, so declare them only here -uint32 BG_EY_HonorScoreTicks[BG_HONOR_MODE_NUM] = { - 330, // normal honor - 200 // holiday -}; - -BattleGroundEY::BattleGroundEY() -{ - m_BuffChange = true; - m_BgObjects.resize(BG_EY_OBJECT_MAX); - m_BgCreatures.resize(BG_EY_CREATURES_MAX); - m_Points_Trigger[FEL_REALVER] = TR_FEL_REALVER_BUFF; - m_Points_Trigger[BLOOD_ELF] = TR_BLOOD_ELF_BUFF; - m_Points_Trigger[DRAENEI_RUINS] = TR_DRAENEI_RUINS_BUFF; - m_Points_Trigger[MAGE_TOWER] = TR_MAGE_TOWER_BUFF; - - m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_EY_START_TWO_MINUTES; - m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_EY_START_ONE_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_EY_START_HALF_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_EY_HAS_BEGUN; -} - -BattleGroundEY::~BattleGroundEY() -{ -} - -void BattleGroundEY::Update(uint32 diff) -{ - BattleGround::Update(diff); - - if (GetStatus() == STATUS_IN_PROGRESS) - { - m_PointAddingTimer -= diff; - if (m_PointAddingTimer <= 0) - { - m_PointAddingTimer = BG_EY_FPOINTS_TICK_TIME; - if (m_TeamPointsCount[BG_TEAM_ALLIANCE] > 0) - AddPoints(ALLIANCE, BG_EY_TickPoints[m_TeamPointsCount[BG_TEAM_ALLIANCE] - 1]); - if (m_TeamPointsCount[BG_TEAM_HORDE] > 0) - AddPoints(HORDE, BG_EY_TickPoints[m_TeamPointsCount[BG_TEAM_HORDE] - 1]); - } - - if (m_FlagState == BG_EY_FLAG_STATE_WAIT_RESPAWN || m_FlagState == BG_EY_FLAG_STATE_ON_GROUND) - { - m_FlagsTimer -= diff; - - if (m_FlagsTimer < 0) - { - m_FlagsTimer = 0; - if (m_FlagState == BG_EY_FLAG_STATE_WAIT_RESPAWN) - RespawnFlag(true); - else - RespawnFlagAfterDrop(); - } - } - - m_TowerCapCheckTimer -= diff; - if (m_TowerCapCheckTimer <= 0) - { - //check if player joined point - /*I used this order of calls, because although we will check if one player is in gameobject's distance 2 times - but we can count of players on current point in CheckSomeoneLeftPoint - */ - this->CheckSomeoneJoinedPoint(); - //check if player left point - this->CheckSomeoneLeftPoint(); - this->UpdatePointStatuses(); - m_TowerCapCheckTimer = BG_EY_FPOINTS_TICK_TIME; - } - } -} - -void BattleGroundEY::StartingEventCloseDoors() -{ - SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_IMMEDIATELY); - SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_IMMEDIATELY); - - for (uint32 i = BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER; i < BG_EY_OBJECT_MAX; ++i) - SpawnBGObject(i, RESPAWN_ONE_DAY); -} - -void BattleGroundEY::StartingEventOpenDoors() -{ - SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_ONE_DAY); - SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_ONE_DAY); - - for (uint32 i = BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER; i <= BG_EY_OBJECT_FLAG_NETHERSTORM; ++i) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - for (uint32 i = 0; i < EY_POINTS_MAX; ++i) - { - //randomly spawn buff - uint8 buff = urand(0, 2); - SpawnBGObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + buff + i * 3, RESPAWN_IMMEDIATELY); - } -} - -void BattleGroundEY::AddPoints(uint32 Team, uint32 Points) -{ - BattleGroundTeamId team_index = GetTeamIndexByTeamId(Team); - m_TeamScores[team_index] += Points; - m_HonorScoreTics[team_index] += Points; - if (m_HonorScoreTics[team_index] >= m_HonorTics) - { - RewardHonorToTeam(GetBonusHonorFromKill(1), Team); - m_HonorScoreTics[team_index] -= m_HonorTics; - } - UpdateTeamScore(Team); -} - -void BattleGroundEY::CheckSomeoneJoinedPoint() -{ - GameObject *obj = NULL; - for (uint8 i = 0; i < EY_POINTS_MAX; ++i) - { - obj = HashMapHolder::Find(m_BgObjects[BG_EY_OBJECT_TOWER_CAP_FEL_REALVER + i]); - if (obj) - { - uint8 j = 0; - while (j < m_PlayersNearPoint[EY_POINTS_MAX].size()) - { - Player *plr = objmgr.GetPlayer(m_PlayersNearPoint[EY_POINTS_MAX][j]); - if (!plr) - { - sLog.outError("BattleGroundEY:CheckSomeoneJoinedPoint: Player (GUID: %u) not found!", GUID_LOPART(m_PlayersNearPoint[EY_POINTS_MAX][j])); - ++j; - continue; - } - if (plr->CanCaptureTowerPoint() && plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS)) - { - //player joined point! - //show progress bar - UpdateWorldStateForPlayer(PROGRESS_BAR_PERCENT_GREY, BG_EY_PROGRESS_BAR_PERCENT_GREY, plr); - UpdateWorldStateForPlayer(PROGRESS_BAR_STATUS, m_PointBarStatus[i], plr); - UpdateWorldStateForPlayer(PROGRESS_BAR_SHOW, BG_EY_PROGRESS_BAR_SHOW, plr); - //add player to point - m_PlayersNearPoint[i].push_back(m_PlayersNearPoint[EY_POINTS_MAX][j]); - //remove player from "free space" - m_PlayersNearPoint[EY_POINTS_MAX].erase(m_PlayersNearPoint[EY_POINTS_MAX].begin() + j); - } - else - ++j; - } - } - } -} - -void BattleGroundEY::CheckSomeoneLeftPoint() -{ - //reset current point counts - for (uint8 i = 0; i < 2*EY_POINTS_MAX; ++i) - m_CurrentPointPlayersCount[i] = 0; - GameObject *obj = NULL; - for (uint8 i = 0; i < EY_POINTS_MAX; ++i) - { - obj = HashMapHolder::Find(m_BgObjects[BG_EY_OBJECT_TOWER_CAP_FEL_REALVER + i]); - if (obj) - { - uint8 j = 0; - while (j < m_PlayersNearPoint[i].size()) - { - Player *plr = objmgr.GetPlayer(m_PlayersNearPoint[i][j]); - if (!plr) - { - sLog.outError("BattleGroundEY:CheckSomeoneLeftPoint Player (GUID: %u) not found!", GUID_LOPART(m_PlayersNearPoint[i][j])); - //move not existed player to "free space" - this will cause many error showing in log, but it is a very important bug - m_PlayersNearPoint[EY_POINTS_MAX].push_back(m_PlayersNearPoint[i][j]); - m_PlayersNearPoint[i].erase(m_PlayersNearPoint[i].begin() + j); - ++j; - continue; - } - if (!plr->CanCaptureTowerPoint() || !plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS)) - //move player out of point (add him to players that are out of points - { - m_PlayersNearPoint[EY_POINTS_MAX].push_back(m_PlayersNearPoint[i][j]); - m_PlayersNearPoint[i].erase(m_PlayersNearPoint[i].begin() + j); - this->UpdateWorldStateForPlayer(PROGRESS_BAR_SHOW, BG_EY_PROGRESS_BAR_DONT_SHOW, plr); - } - else - { - //player is neat flag, so update count: - m_CurrentPointPlayersCount[2 * i + GetTeamIndexByTeamId(plr->GetTeam())]++; - ++j; - } - } - } - } -} - -void BattleGroundEY::UpdatePointStatuses() -{ - for (uint8 point = 0; point < EY_POINTS_MAX; ++point) - { - if (m_PlayersNearPoint[point].empty()) - continue; - //count new point bar status: - m_PointBarStatus[point] += (m_CurrentPointPlayersCount[2 * point] - m_CurrentPointPlayersCount[2 * point + 1] < BG_EY_POINT_MAX_CAPTURERS_COUNT) ? m_CurrentPointPlayersCount[2 * point] - m_CurrentPointPlayersCount[2 * point + 1] : BG_EY_POINT_MAX_CAPTURERS_COUNT; - - if (m_PointBarStatus[point] > BG_EY_PROGRESS_BAR_ALI_CONTROLLED) - //point is fully alliance's - m_PointBarStatus[point] = BG_EY_PROGRESS_BAR_ALI_CONTROLLED; - if (m_PointBarStatus[point] < BG_EY_PROGRESS_BAR_HORDE_CONTROLLED) - //point is fully horde's - m_PointBarStatus[point] = BG_EY_PROGRESS_BAR_HORDE_CONTROLLED; - - uint32 pointOwnerTeamId = 0; - //find which team should own this point - if (m_PointBarStatus[point] <= BG_EY_PROGRESS_BAR_NEUTRAL_LOW) - pointOwnerTeamId = HORDE; - else if (m_PointBarStatus[point] >= BG_EY_PROGRESS_BAR_NEUTRAL_HIGH) - pointOwnerTeamId = ALLIANCE; - else - pointOwnerTeamId = EY_POINT_NO_OWNER; - - for (uint8 i = 0; i < m_PlayersNearPoint[point].size(); ++i) - { - Player *plr = objmgr.GetPlayer(m_PlayersNearPoint[point][i]); - if (plr) - { - this->UpdateWorldStateForPlayer(PROGRESS_BAR_STATUS, m_PointBarStatus[point], plr); - //if point owner changed we must evoke event! - if (pointOwnerTeamId != m_PointOwnedByTeam[point]) - { - //point was uncontrolled and player is from team which captured point - if (m_PointState[point] == EY_POINT_STATE_UNCONTROLLED && plr->GetTeam() == pointOwnerTeamId) - this->EventTeamCapturedPoint(plr, point); - - //point was under control and player isn't from team which controlled it - if (m_PointState[point] == EY_POINT_UNDER_CONTROL && plr->GetTeam() != m_PointOwnedByTeam[point]) - this->EventTeamLostPoint(plr, point); - } - } - } - } -} - -void BattleGroundEY::UpdateTeamScore(uint32 Team) -{ - uint32 score = GetTeamScore(Team); - //TODO there should be some sound played when one team is near victory!! - and define variables - /*if (!m_IsInformedNearVictory && score >= BG_EY_WARNING_NEAR_VICTORY_SCORE) - { - if (Team == ALLIANCE) - SendMessageToAll(LANG_BG_EY_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); - else - SendMessageToAll(LANG_BG_EY_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); - PlaySoundToAll(BG_EY_SOUND_NEAR_VICTORY); - m_IsInformedNearVictory = true; - }*/ - - if (score >= BG_EY_MAX_TEAM_SCORE) - { - score = BG_EY_MAX_TEAM_SCORE; - EndBattleGround(Team); - } - - if (Team == ALLIANCE) - UpdateWorldState(EY_ALLIANCE_RESOURCES, score); - else - UpdateWorldState(EY_HORDE_RESOURCES, score); -} - -void BattleGroundEY::EndBattleGround(uint32 winner) -{ - //win reward - if (winner == ALLIANCE) - RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); - if (winner == HORDE) - RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); - //complete map reward - RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); - RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); - - BattleGround::EndBattleGround(winner); -} - -void BattleGroundEY::UpdatePointsCount(uint32 Team) -{ - if (Team == ALLIANCE) - UpdateWorldState(EY_ALLIANCE_BASE, m_TeamPointsCount[BG_TEAM_ALLIANCE]); - else - UpdateWorldState(EY_HORDE_BASE, m_TeamPointsCount[BG_TEAM_HORDE]); -} - -void BattleGroundEY::UpdatePointsIcons(uint32 Team, uint32 Point) -{ - //we MUST firstly send 0, after that we can send 1!!! - if (m_PointState[Point] == EY_POINT_UNDER_CONTROL) - { - UpdateWorldState(m_PointsIconStruct[Point].WorldStateControlIndex, 0); - if (Team == ALLIANCE) - UpdateWorldState(m_PointsIconStruct[Point].WorldStateAllianceControlledIndex, 1); - else - UpdateWorldState(m_PointsIconStruct[Point].WorldStateHordeControlledIndex, 1); - } - else - { - if (Team == ALLIANCE) - UpdateWorldState(m_PointsIconStruct[Point].WorldStateAllianceControlledIndex, 0); - else - UpdateWorldState(m_PointsIconStruct[Point].WorldStateHordeControlledIndex, 0); - UpdateWorldState(m_PointsIconStruct[Point].WorldStateControlIndex, 1); - } -} - -void BattleGroundEY::AddPlayer(Player *plr) -{ - BattleGround::AddPlayer(plr); - //create score and add it to map - BattleGroundEYScore* sc = new BattleGroundEYScore; - - m_PlayersNearPoint[EY_POINTS_MAX].push_back(plr->GetGUID()); - - m_PlayerScores[plr->GetGUID()] = sc; -} - -void BattleGroundEY::RemovePlayer(Player *plr, uint64 guid) -{ - // sometimes flag aura not removed :( - for (int j = EY_POINTS_MAX; j >= 0; --j) - { - for (size_t i = 0; i < m_PlayersNearPoint[j].size(); ++i) - if (m_PlayersNearPoint[j][i] == guid) - m_PlayersNearPoint[j].erase(m_PlayersNearPoint[j].begin() + i); - } - if (IsFlagPickedup()) - { - if (m_FlagKeeper == guid) - { - if (plr) - EventPlayerDroppedFlag(plr); - else - { - SetFlagPicker(0); - RespawnFlag(true); - } - } - } -} - -void BattleGroundEY::HandleAreaTrigger(Player *Source, uint32 Trigger) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - if (!Source->isAlive()) //hack code, must be removed later - return; - - switch(Trigger) - { - case TR_BLOOD_ELF_POINT: - if (m_PointState[BLOOD_ELF] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[BLOOD_ELF] == Source->GetTeam()) - if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) - EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_BLOOD_ELF); - break; - case TR_FEL_REALVER_POINT: - if (m_PointState[FEL_REALVER] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[FEL_REALVER] == Source->GetTeam()) - if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) - EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_FEL_REALVER); - break; - case TR_MAGE_TOWER_POINT: - if (m_PointState[MAGE_TOWER] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[MAGE_TOWER] == Source->GetTeam()) - if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) - EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_MAGE_TOWER); - break; - case TR_DRAENEI_RUINS_POINT: - if (m_PointState[DRAENEI_RUINS] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[DRAENEI_RUINS] == Source->GetTeam()) - if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) - EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_DRAENEI_RUINS); - break; - case 4512: - case 4515: - case 4517: - case 4519: - case 4530: - case 4531: - case 4568: - case 4569: - case 4570: - case 4571: - case 5866: - break; - default: - sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); - Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); - break; - } -} - -bool BattleGroundEY::SetupBattleGround() -{ - // doors - if (!AddObject(BG_EY_OBJECT_DOOR_A, BG_OBJECT_A_DOOR_EY_ENTRY, 2527.6f, 1596.91f, 1262.13f, -3.12414f, -0.173642f, -0.001515f, 0.98477f, -0.008594f, RESPAWN_IMMEDIATELY) - || !AddObject(BG_EY_OBJECT_DOOR_H, BG_OBJECT_H_DOOR_EY_ENTRY, 1803.21f, 1539.49f, 1261.09f, 3.14159f, 0.173648f, 0, 0.984808f, 0, RESPAWN_IMMEDIATELY) - // banners (alliance) - || !AddObject(BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2057.46f, 1735.07f, 1187.91f, -0.925024f, 0, 0, 0.446198f, -0.894934f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_A_BANNER_FEL_REALVER_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2032.25f, 1729.53f, 1190.33f, 1.8675f, 0, 0, 0.803857f, 0.594823f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_A_BANNER_FEL_REALVER_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2092.35f, 1775.46f, 1187.08f, -0.401426f, 0, 0, 0.199368f, -0.979925f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2047.19f, 1349.19f, 1189.0f, -1.62316f, 0, 0, 0.725374f, -0.688354f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_A_BANNER_BLOOD_ELF_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2074.32f, 1385.78f, 1194.72f, 0.488692f, 0, 0, 0.241922f, 0.970296f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_A_BANNER_BLOOD_ELF_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2025.13f, 1386.12f, 1192.74f, 2.3911f, 0, 0, 0.930418f, 0.366501f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2276.8f, 1400.41f, 1196.33f, 2.44346f, 0, 0, 0.939693f, 0.34202f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2305.78f, 1404.56f, 1199.38f, 1.74533f, 0, 0, 0.766044f, 0.642788f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2245.4f, 1366.41f, 1195.28f, 2.21657f, 0, 0, 0.894934f, 0.446198f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2270.84f, 1784.08f, 1186.76f, 2.42601f, 0, 0, 0.936672f, 0.350207f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_A_BANNER_MAGE_TOWER_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2269.13f, 1737.7f, 1186.66f, 0.994838f, 0, 0, 0.477159f, 0.878817f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_A_BANNER_MAGE_TOWER_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2300.86f, 1741.25f, 1187.7f, -0.785398f, 0, 0, 0.382683f, -0.92388f, RESPAWN_ONE_DAY) - // banners (horde) - || !AddObject(BG_EY_OBJECT_H_BANNER_FEL_REALVER_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2057.46f, 1735.07f, 1187.91f, -0.925024f, 0, 0, 0.446198f, -0.894934f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_H_BANNER_FEL_REALVER_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2032.25f, 1729.53f, 1190.33f, 1.8675f, 0, 0, 0.803857f, 0.594823f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_H_BANNER_FEL_REALVER_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2092.35f, 1775.46f, 1187.08f, -0.401426f, 0, 0, 0.199368f, -0.979925f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2047.19f, 1349.19f, 1189.0f, -1.62316f, 0, 0, 0.725374f, -0.688354f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_H_BANNER_BLOOD_ELF_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2074.32f, 1385.78f, 1194.72f, 0.488692f, 0, 0, 0.241922f, 0.970296f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_H_BANNER_BLOOD_ELF_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2025.13f, 1386.12f, 1192.74f, 2.3911f, 0, 0, 0.930418f, 0.366501f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2276.8f, 1400.41f, 1196.33f, 2.44346f, 0, 0, 0.939693f, 0.34202f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2305.78f, 1404.56f, 1199.38f, 1.74533f, 0, 0, 0.766044f, 0.642788f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2245.4f, 1366.41f, 1195.28f, 2.21657f, 0, 0, 0.894934f, 0.446198f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2270.84f, 1784.08f, 1186.76f, 2.42601f, 0, 0, 0.936672f, 0.350207f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_H_BANNER_MAGE_TOWER_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2269.13f, 1737.7f, 1186.66f, 0.994838f, 0, 0, 0.477159f, 0.878817f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_H_BANNER_MAGE_TOWER_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2300.86f, 1741.25f, 1187.7f, -0.785398f, 0, 0, 0.382683f, -0.92388f, RESPAWN_ONE_DAY) - // banners (natural) - || !AddObject(BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2057.46f, 1735.07f, 1187.91f, -0.925024f, 0, 0, 0.446198f, -0.894934f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_N_BANNER_FEL_REALVER_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2032.25f, 1729.53f, 1190.33f, 1.8675f, 0, 0, 0.803857f, 0.594823f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_N_BANNER_FEL_REALVER_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2092.35f, 1775.46f, 1187.08f, -0.401426f, 0, 0, 0.199368f, -0.979925f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2047.19f, 1349.19f, 1189.0f, -1.62316f, 0, 0, 0.725374f, -0.688354f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2074.32f, 1385.78f, 1194.72f, 0.488692f, 0, 0, 0.241922f, 0.970296f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2025.13f, 1386.12f, 1192.74f, 2.3911f, 0, 0, 0.930418f, 0.366501f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2276.8f, 1400.41f, 1196.33f, 2.44346f, 0, 0, 0.939693f, 0.34202f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2305.78f, 1404.56f, 1199.38f, 1.74533f, 0, 0, 0.766044f, 0.642788f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2245.4f, 1366.41f, 1195.28f, 2.21657f, 0, 0, 0.894934f, 0.446198f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2270.84f, 1784.08f, 1186.76f, 2.42601f, 0, 0, 0.936672f, 0.350207f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2269.13f, 1737.7f, 1186.66f, 0.994838f, 0, 0, 0.477159f, 0.878817f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2300.86f, 1741.25f, 1187.7f, -0.785398f, 0, 0, 0.382683f, -0.92388f, RESPAWN_ONE_DAY) - // flags - || !AddObject(BG_EY_OBJECT_FLAG_NETHERSTORM, BG_OBJECT_FLAG2_EY_ENTRY, 2174.782227f, 1569.054688f, 1160.361938f, -1.448624f, 0, 0, 0.662620f, -0.748956f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_FLAG_FEL_REALVER, BG_OBJECT_FLAG1_EY_ENTRY, 2044.28f, 1729.68f, 1189.96f, -0.017453f, 0, 0, 0.008727f, -0.999962f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_FLAG_BLOOD_ELF, BG_OBJECT_FLAG1_EY_ENTRY, 2048.83f, 1393.65f, 1194.49f, 0.20944f, 0, 0, 0.104528f, 0.994522f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_FLAG_DRAENEI_RUINS, BG_OBJECT_FLAG1_EY_ENTRY, 2286.56f, 1402.36f, 1197.11f, 3.72381f, 0, 0, 0.957926f, -0.287016f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_FLAG_MAGE_TOWER, BG_OBJECT_FLAG1_EY_ENTRY, 2284.48f, 1731.23f, 1189.99f, 2.89725f, 0, 0, 0.992546f, 0.121869f, RESPAWN_ONE_DAY) - // tower cap - || !AddObject(BG_EY_OBJECT_TOWER_CAP_FEL_REALVER, BG_OBJECT_FR_TOWER_CAP_EY_ENTRY, 2024.600708f, 1742.819580f, 1195.157715f, 2.443461f, 0, 0, 0.939693f, 0.342020f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_TOWER_CAP_BLOOD_ELF, BG_OBJECT_BE_TOWER_CAP_EY_ENTRY, 2050.493164f, 1372.235962f, 1194.563477f, 1.710423f, 0, 0, 0.754710f, 0.656059f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_TOWER_CAP_DRAENEI_RUINS, BG_OBJECT_DR_TOWER_CAP_EY_ENTRY, 2301.010498f, 1386.931641f, 1197.183472f, 1.570796f, 0, 0, 0.707107f, 0.707107f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_TOWER_CAP_MAGE_TOWER, BG_OBJECT_HU_TOWER_CAP_EY_ENTRY, 2282.121582f, 1760.006958f, 1189.707153f, 1.919862f, 0, 0, 0.819152f, 0.573576f, RESPAWN_ONE_DAY) -) - { - sLog.outErrorDb("BatteGroundEY: Failed to spawn some object BattleGround not created!"); - return false; - } - - //buffs - for (int i = 0; i < EY_POINTS_MAX; ++i) - { - AreaTriggerEntry const* at = sAreaTriggerStore.LookupEntry(m_Points_Trigger[i]); - if (!at) - { - sLog.outError("BattleGroundEY: Unknown trigger: %u", m_Points_Trigger[i]); - continue; - } - if (!AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3, Buff_Entries[0], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3 + 1, Buff_Entries[1], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY) - || !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3 + 2, Buff_Entries[2], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY) -) - sLog.outError("BattleGroundEY: Cannot spawn buff"); - } - - WorldSafeLocsEntry const *sg = NULL; - sg = sWorldSafeLocsStore.LookupEntry(EY_GRAVEYARD_MAIN_ALLIANCE); - if (!sg || !AddSpiritGuide(EY_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, ALLIANCE)) - { - sLog.outErrorDb("BatteGroundEY: Failed to spawn spirit guide! BattleGround not created!"); - return false; - } - - sg = sWorldSafeLocsStore.LookupEntry(EY_GRAVEYARD_MAIN_HORDE); - if (!sg || !AddSpiritGuide(EY_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, HORDE)) - { - sLog.outErrorDb("BatteGroundEY: Failed to spawn spirit guide! BattleGround not created!"); - return false; - } - - return true; -} - -void BattleGroundEY::Reset() -{ - //call parent's class reset - BattleGround::Reset(); - - m_TeamScores[BG_TEAM_ALLIANCE] = 0; - m_TeamScores[BG_TEAM_HORDE] = 0; - m_TeamPointsCount[BG_TEAM_ALLIANCE] = 0; - m_TeamPointsCount[BG_TEAM_HORDE] = 0; - m_HonorScoreTics[BG_TEAM_ALLIANCE] = 0; - m_HonorScoreTics[BG_TEAM_HORDE] = 0; - m_FlagState = BG_EY_FLAG_STATE_ON_BASE; - m_FlagCapturedBgObjectType = 0; - m_FlagKeeper = 0; - m_DroppedFlagGUID = 0; - m_PointAddingTimer = 0; - m_TowerCapCheckTimer = 0; - bool isBGWeekend = sBattleGroundMgr.IsBGWeekend(GetTypeID()); - m_HonorTics = (isBGWeekend) ? BG_EY_EYWeekendHonorTicks : BG_EY_NotEYWeekendHonorTicks; - - for (uint8 i = 0; i < EY_POINTS_MAX; ++i) - { - m_PointOwnedByTeam[i] = EY_POINT_NO_OWNER; - m_PointState[i] = EY_POINT_STATE_UNCONTROLLED; - m_PointBarStatus[i] = BG_EY_PROGRESS_BAR_STATE_MIDDLE; - m_PlayersNearPoint[i].clear(); - m_PlayersNearPoint[i].reserve(15); //tip size - } - m_PlayersNearPoint[EY_PLAYERS_OUT_OF_POINTS].clear(); - m_PlayersNearPoint[EY_PLAYERS_OUT_OF_POINTS].reserve(30); -} - -void BattleGroundEY::RespawnFlag(bool send_message) -{ - if (m_FlagCapturedBgObjectType > 0) - SpawnBGObject(m_FlagCapturedBgObjectType, RESPAWN_ONE_DAY); - - m_FlagCapturedBgObjectType = 0; - m_FlagState = BG_EY_FLAG_STATE_ON_BASE; - SpawnBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM, RESPAWN_IMMEDIATELY); - - if (send_message) - { - SendMessageToAll(LANG_BG_EY_RESETED_FLAG, CHAT_MSG_BG_SYSTEM_NEUTRAL); - PlaySoundToAll(BG_EY_SOUND_FLAG_RESET); // flags respawned sound... - } - - UpdateWorldState(NETHERSTORM_FLAG, 1); -} - -void BattleGroundEY::RespawnFlagAfterDrop() -{ - RespawnFlag(true); - - GameObject *obj = HashMapHolder::Find(GetDroppedFlagGUID()); - if (obj) - obj->Delete(); - else - sLog.outError("BattleGroundEY: Unknown dropped flag guid: %u",GUID_LOPART(GetDroppedFlagGUID())); - - SetDroppedFlagGUID(0); -} - -void BattleGroundEY::HandleKillPlayer(Player *player, Player *killer) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - BattleGround::HandleKillPlayer(player, killer); - EventPlayerDroppedFlag(player); -} - -void BattleGroundEY::EventPlayerDroppedFlag(Player *Source) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - { - // if not running, do not cast things at the dropper player, neither send unnecessary messages - // just take off the aura - if (IsFlagPickedup() && GetFlagPickerGUID() == Source->GetGUID()) - { - SetFlagPicker(0); - Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL); - } - return; - } - - if (!IsFlagPickedup()) - return; - - if (GetFlagPickerGUID() != Source->GetGUID()) - return; - - SetFlagPicker(0); - Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL); - m_FlagState = BG_EY_FLAG_STATE_ON_GROUND; - m_FlagsTimer = BG_EY_FLAG_RESPAWN_TIME; - Source->CastSpell(Source, SPELL_RECENTLY_DROPPED_FLAG, true); - Source->CastSpell(Source, BG_EY_PLAYER_DROPPED_FLAG_SPELL, true); - //this does not work correctly :((it should remove flag carrier name) - UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_WAIT_RESPAWN); - UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_WAIT_RESPAWN); - - if (Source->GetTeam() == ALLIANCE) - SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL); - else - SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, NULL); -} - -void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj) -{ - if (GetStatus() != STATUS_IN_PROGRESS || IsFlagPickedup() || !Source->IsWithinDistInMap(target_obj, 10)) - return; - - if (Source->GetTeam() == ALLIANCE) - { - UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_ON_PLAYER); - PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE); - } - else - { - UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_ON_PLAYER); - PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_HORDE); - } - - if (m_FlagState == BG_EY_FLAG_STATE_ON_BASE) - UpdateWorldState(NETHERSTORM_FLAG, 0); - m_FlagState = BG_EY_FLAG_STATE_ON_PLAYER; - - SpawnBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM, RESPAWN_ONE_DAY); - SetFlagPicker(Source->GetGUID()); - //get flag aura on player - Source->CastSpell(Source, BG_EY_NETHERSTORM_FLAG_SPELL, true); - Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); - - if (Source->GetTeam() == ALLIANCE) - PSendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, Source->GetName()); - else - PSendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, NULL, Source->GetName()); -} - -void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - //Natural point - uint32 Team = m_PointOwnedByTeam[Point]; - - if (!Team) - return; - - if (Team == ALLIANCE) - { - m_TeamPointsCount[BG_TEAM_ALLIANCE]--; - SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance, RESPAWN_ONE_DAY); - SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance + 1, RESPAWN_ONE_DAY); - SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance + 2, RESPAWN_ONE_DAY); - } - else - { - m_TeamPointsCount[BG_TEAM_HORDE]--; - SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde, RESPAWN_ONE_DAY); - SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde + 1, RESPAWN_ONE_DAY); - SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde + 2, RESPAWN_ONE_DAY); - } - - SpawnBGObject(m_LoosingPointTypes[Point].SpawnNeutralObjectType, RESPAWN_IMMEDIATELY); - SpawnBGObject(m_LoosingPointTypes[Point].SpawnNeutralObjectType + 1, RESPAWN_IMMEDIATELY); - SpawnBGObject(m_LoosingPointTypes[Point].SpawnNeutralObjectType + 2, RESPAWN_IMMEDIATELY); - - //buff isn't despawned - - m_PointOwnedByTeam[Point] = EY_POINT_NO_OWNER; - m_PointState[Point] = EY_POINT_NO_OWNER; - - if (Team == ALLIANCE) - SendMessageToAll(m_LoosingPointTypes[Point].MessageIdAlliance,CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); - else - SendMessageToAll(m_LoosingPointTypes[Point].MessageIdHorde,CHAT_MSG_BG_SYSTEM_HORDE, Source); - - UpdatePointsIcons(Team, Point); - UpdatePointsCount(Team); - - //remove bonus honor aura trigger creature when node is lost - if (Point < EY_POINTS_MAX) - DelCreature(Point + 6);//NULL checks are in DelCreature! 0-5 spirit guides -} - -void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - uint32 Team = Source->GetTeam(); - - SpawnBGObject(m_CapturingPointTypes[Point].DespawnNeutralObjectType, RESPAWN_ONE_DAY); - SpawnBGObject(m_CapturingPointTypes[Point].DespawnNeutralObjectType + 1, RESPAWN_ONE_DAY); - SpawnBGObject(m_CapturingPointTypes[Point].DespawnNeutralObjectType + 2, RESPAWN_ONE_DAY); - - if (Team == ALLIANCE) - { - m_TeamPointsCount[BG_TEAM_ALLIANCE]++; - SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance, RESPAWN_IMMEDIATELY); - SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance + 1, RESPAWN_IMMEDIATELY); - SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance + 2, RESPAWN_IMMEDIATELY); - } - else - { - m_TeamPointsCount[BG_TEAM_HORDE]++; - SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde, RESPAWN_IMMEDIATELY); - SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde + 1, RESPAWN_IMMEDIATELY); - SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde + 2, RESPAWN_IMMEDIATELY); - } - - //buff isn't respawned - - m_PointOwnedByTeam[Point] = Team; - m_PointState[Point] = EY_POINT_UNDER_CONTROL; - - if (Team == ALLIANCE) - SendMessageToAll(m_CapturingPointTypes[Point].MessageIdAlliance,CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); - else - SendMessageToAll(m_CapturingPointTypes[Point].MessageIdHorde,CHAT_MSG_BG_SYSTEM_HORDE, Source); - - if (m_BgCreatures[Point]) - DelCreature(Point); - - WorldSafeLocsEntry const *sg = NULL; - sg = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[Point].GraveYardId); - if (!sg || !AddSpiritGuide(Point, sg->x, sg->y, sg->z, 3.124139f, Team)) - sLog.outError("BatteGroundEY: Failed to spawn spirit guide! point: %u, team: %u, graveyard_id: %u", - Point, Team, m_CapturingPointTypes[Point].GraveYardId); - -// SpawnBGCreature(Point,RESPAWN_IMMEDIATELY); - - UpdatePointsIcons(Team, Point); - UpdatePointsCount(Team); - - if (Point >= EY_POINTS_MAX) - return; - - Creature* trigger = GetBGCreature(Point + 6);//0-5 spirit guides - if (!trigger) - trigger = AddCreature(WORLD_TRIGGER,Point+6,Team,BG_EY_TriggerPositions[Point][0],BG_EY_TriggerPositions[Point][1],BG_EY_TriggerPositions[Point][2],BG_EY_TriggerPositions[Point][3]); - - //add bonus honor aura trigger creature when node is accupied - //cast bonus aura (+50% honor in 25yards) - //aura should only apply to players who have accupied the node, set correct faction for trigger - if (trigger) - { - trigger->setFaction(Team == ALLIANCE ? 84 : 83); - trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false); - } -} - -void BattleGroundEY::EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType) -{ - if (GetStatus() != STATUS_IN_PROGRESS || GetFlagPickerGUID() != Source->GetGUID()) - return; - - SetFlagPicker(0); - m_FlagState = BG_EY_FLAG_STATE_WAIT_RESPAWN; - Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL); - - Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); - - if (Source->GetTeam() == ALLIANCE) - PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE); - else - PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_HORDE); - - SpawnBGObject(BgObjectType, RESPAWN_IMMEDIATELY); - - m_FlagsTimer = BG_EY_FLAG_RESPAWN_TIME; - m_FlagCapturedBgObjectType = BgObjectType; - - uint8 team_id = 0; - if (Source->GetTeam() == ALLIANCE) - { - team_id = BG_TEAM_ALLIANCE; - SendMessageToAll(LANG_BG_EY_CAPTURED_FLAG_A, CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); - } - else - { - team_id = BG_TEAM_HORDE; - SendMessageToAll(LANG_BG_EY_CAPTURED_FLAG_H, CHAT_MSG_BG_SYSTEM_HORDE, Source); - } - - if (m_TeamPointsCount[team_id] > 0) - AddPoints(Source->GetTeam(), BG_EY_FlagPoints[m_TeamPointsCount[team_id] - 1]); - - UpdatePlayerScore(Source, SCORE_FLAG_CAPTURES, 1); -} - -void BattleGroundEY::UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor) -{ - BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); - if (itr == m_PlayerScores.end()) // player not found - return; - - switch(type) - { - case SCORE_FLAG_CAPTURES: // flags captured - ((BattleGroundEYScore*)itr->second)->FlagCaptures += value; - break; - default: - BattleGround::UpdatePlayerScore(Source, type, value, doAddHonor); - break; - } -} - -void BattleGroundEY::FillInitialWorldStates(WorldPacket& data) -{ - data << uint32(EY_HORDE_BASE) << uint32(m_TeamPointsCount[BG_TEAM_HORDE]); - data << uint32(EY_ALLIANCE_BASE) << uint32(m_TeamPointsCount[BG_TEAM_ALLIANCE]); - data << uint32(0xab6) << uint32(0x0); - data << uint32(0xab5) << uint32(0x0); - data << uint32(0xab4) << uint32(0x0); - data << uint32(0xab3) << uint32(0x0); - data << uint32(0xab2) << uint32(0x0); - data << uint32(0xab1) << uint32(0x0); - data << uint32(0xab0) << uint32(0x0); - data << uint32(0xaaf) << uint32(0x0); - - data << uint32(DRAENEI_RUINS_HORDE_CONTROL) << uint32(m_PointOwnedByTeam[DRAENEI_RUINS] == HORDE && m_PointState[DRAENEI_RUINS] == EY_POINT_UNDER_CONTROL); - - data << uint32(DRAENEI_RUINS_ALLIANCE_CONTROL) << uint32(m_PointOwnedByTeam[DRAENEI_RUINS] == ALLIANCE && m_PointState[DRAENEI_RUINS] == EY_POINT_UNDER_CONTROL); - - data << uint32(DRAENEI_RUINS_UNCONTROL) << uint32(m_PointState[DRAENEI_RUINS] != EY_POINT_UNDER_CONTROL); - - data << uint32(MAGE_TOWER_ALLIANCE_CONTROL) << uint32(m_PointOwnedByTeam[MAGE_TOWER] == ALLIANCE && m_PointState[MAGE_TOWER] == EY_POINT_UNDER_CONTROL); - - data << uint32(MAGE_TOWER_HORDE_CONTROL) << uint32(m_PointOwnedByTeam[MAGE_TOWER] == HORDE && m_PointState[MAGE_TOWER] == EY_POINT_UNDER_CONTROL); - - data << uint32(MAGE_TOWER_UNCONTROL) << uint32(m_PointState[MAGE_TOWER] != EY_POINT_UNDER_CONTROL); - - data << uint32(FEL_REAVER_HORDE_CONTROL) << uint32(m_PointOwnedByTeam[FEL_REALVER] == HORDE && m_PointState[FEL_REALVER] == EY_POINT_UNDER_CONTROL); - - data << uint32(FEL_REAVER_ALLIANCE_CONTROL) << uint32(m_PointOwnedByTeam[FEL_REALVER] == ALLIANCE && m_PointState[FEL_REALVER] == EY_POINT_UNDER_CONTROL); - - data << uint32(FEL_REAVER_UNCONTROL) << uint32(m_PointState[FEL_REALVER] != EY_POINT_UNDER_CONTROL); - - data << uint32(BLOOD_ELF_HORDE_CONTROL) << uint32(m_PointOwnedByTeam[BLOOD_ELF] == HORDE && m_PointState[BLOOD_ELF] == EY_POINT_UNDER_CONTROL); - - data << uint32(BLOOD_ELF_ALLIANCE_CONTROL) << uint32(m_PointOwnedByTeam[BLOOD_ELF] == ALLIANCE && m_PointState[BLOOD_ELF] == EY_POINT_UNDER_CONTROL); - - data << uint32(BLOOD_ELF_UNCONTROL) << uint32(m_PointState[BLOOD_ELF] != EY_POINT_UNDER_CONTROL); - - data << uint32(NETHERSTORM_FLAG) << uint32(m_FlagState == BG_EY_FLAG_STATE_ON_BASE); - - data << uint32(0xad2) << uint32(0x1); - data << uint32(0xad1) << uint32(0x1); - data << uint32(0xabe) << uint32(GetTeamScore(HORDE)); - data << uint32(0xabd) << uint32(GetTeamScore(ALLIANCE)); - data << uint32(0xa05) << uint32(0x8e); - data << uint32(0xaa0) << uint32(0x0); - data << uint32(0xa9f) << uint32(0x0); - data << uint32(0xa9e) << uint32(0x0); - data << uint32(0xc0d) << uint32(0x17b); -} - -WorldSafeLocsEntry const *BattleGroundEY::GetClosestGraveYard(Player* player) -{ - uint32 g_id = 0; - - switch(player->GetTeam()) - { - case ALLIANCE: g_id = EY_GRAVEYARD_MAIN_ALLIANCE; break; - case HORDE: g_id = EY_GRAVEYARD_MAIN_HORDE; break; - default: return NULL; - } - - float distance, nearestDistance; - - WorldSafeLocsEntry const* entry = NULL; - WorldSafeLocsEntry const* nearestEntry = NULL; - entry = sWorldSafeLocsStore.LookupEntry(g_id); - nearestEntry = entry; - - if (!entry) - { - sLog.outError("BattleGroundEY: Not found the main team graveyard. Graveyard system isn't working!"); - return NULL; - } - - float plr_x = player->GetPositionX(); - float plr_y = player->GetPositionY(); - float plr_z = player->GetPositionZ(); - - distance = (entry->x - plr_x)*(entry->x - plr_x) + (entry->y - plr_y)*(entry->y - plr_y) + (entry->z - plr_z)*(entry->z - plr_z); - nearestDistance = distance; - - for (uint8 i = 0; i < EY_POINTS_MAX; ++i) - { - if (m_PointOwnedByTeam[i] == player->GetTeam() && m_PointState[i] == EY_POINT_UNDER_CONTROL) - { - entry = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[i].GraveYardId); - if (!entry) - sLog.outError("BattleGroundEY: Not found graveyard: %u",m_CapturingPointTypes[i].GraveYardId); - else - { - distance = (entry->x - plr_x)*(entry->x - plr_x) + (entry->y - plr_y)*(entry->y - plr_y) + (entry->z - plr_z)*(entry->z - plr_z); - if (distance < nearestDistance) - { - nearestDistance = distance; - nearestEntry = entry; - } - } - } - } - - return nearestEntry; -} - -bool BattleGroundEY::IsAllNodesConrolledByTeam(uint32 team) const -{ - uint32 count = 0; - for (int i = 0; i < EY_POINTS_MAX; ++i) - if (m_PointOwnedByTeam[i] == team && m_PointState[i] == EY_POINT_UNDER_CONTROL) - ++count; - - return count == EY_POINTS_MAX; -} diff --git a/src/server/game/BattleGrounds/BattleGroundEY.h b/src/server/game/BattleGrounds/BattleGroundEY.h deleted file mode 100644 index 4fe23c4c821..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundEY.h +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __BATTLEGROUNDEY_H -#define __BATTLEGROUNDEY_H - -#include "Language.h" - -class BattleGround; - -#define BG_EY_FLAG_RESPAWN_TIME (8*IN_MILISECONDS) //8 seconds -#define BG_EY_FPOINTS_TICK_TIME (2*IN_MILISECONDS) //2 seconds - -enum BG_EY_WorldStates -{ - EY_ALLIANCE_RESOURCES = 2749, - EY_HORDE_RESOURCES = 2750, - EY_ALLIANCE_BASE = 2752, - EY_HORDE_BASE = 2753, - DRAENEI_RUINS_HORDE_CONTROL = 2733, - DRAENEI_RUINS_ALLIANCE_CONTROL = 2732, - DRAENEI_RUINS_UNCONTROL = 2731, - MAGE_TOWER_ALLIANCE_CONTROL = 2730, - MAGE_TOWER_HORDE_CONTROL = 2729, - MAGE_TOWER_UNCONTROL = 2728, - FEL_REAVER_HORDE_CONTROL = 2727, - FEL_REAVER_ALLIANCE_CONTROL = 2726, - FEL_REAVER_UNCONTROL = 2725, - BLOOD_ELF_HORDE_CONTROL = 2724, - BLOOD_ELF_ALLIANCE_CONTROL = 2723, - BLOOD_ELF_UNCONTROL = 2722, - PROGRESS_BAR_PERCENT_GREY = 2720, //100 = empty (only grey), 0 = blue|red (no grey) - PROGRESS_BAR_STATUS = 2719, //50 init!, 48 ... hordak bere .. 33 .. 0 = full 100% hordacky , 100 = full alliance - PROGRESS_BAR_SHOW = 2718, //1 init, 0 druhy send - bez messagu, 1 = controlled aliance - NETHERSTORM_FLAG = 2757, - //set to 2 when flag is picked up, and to 1 if it is dropped - NETHERSTORM_FLAG_STATE_ALLIANCE = 2769, - NETHERSTORM_FLAG_STATE_HORDE = 2770 -}; - -enum BG_EY_ProgressBarConsts -{ - BG_EY_POINT_MAX_CAPTURERS_COUNT = 5, - BG_EY_POINT_RADIUS = 70, - BG_EY_PROGRESS_BAR_DONT_SHOW = 0, - BG_EY_PROGRESS_BAR_SHOW = 1, - BG_EY_PROGRESS_BAR_PERCENT_GREY = 40, - BG_EY_PROGRESS_BAR_STATE_MIDDLE = 50, - BG_EY_PROGRESS_BAR_HORDE_CONTROLLED = 0, - BG_EY_PROGRESS_BAR_NEUTRAL_LOW = 30, - BG_EY_PROGRESS_BAR_NEUTRAL_HIGH = 70, - BG_EY_PROGRESS_BAR_ALI_CONTROLLED = 100 -}; - -enum BG_EY_Sounds -{ - //strange ids, but sure about them - BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE = 8212, - BG_EY_SOUND_FLAG_CAPTURED_HORDE = 8213, - BG_EY_SOUND_FLAG_PICKED_UP_HORDE = 8174, - BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE = 8173, - BG_EY_SOUND_FLAG_RESET = 8192 -}; - -enum BG_EY_Spells -{ - BG_EY_NETHERSTORM_FLAG_SPELL = 34976, - BG_EY_PLAYER_DROPPED_FLAG_SPELL = 34991 -}; - -enum EYBattleGroundObjectEntry -{ - BG_OBJECT_A_DOOR_EY_ENTRY = 184719, //Alliance door - BG_OBJECT_H_DOOR_EY_ENTRY = 184720, //Horde door - BG_OBJECT_FLAG1_EY_ENTRY = 184493, //Netherstorm flag (generic) - BG_OBJECT_FLAG2_EY_ENTRY = 184141, //Netherstorm flag (flagstand) - BG_OBJECT_FLAG3_EY_ENTRY = 184142, //Netherstorm flag (flagdrop) - BG_OBJECT_A_BANNER_EY_ENTRY = 184381, //Visual Banner (Alliance) - BG_OBJECT_H_BANNER_EY_ENTRY = 184380, //Visual Banner (Horde) - BG_OBJECT_N_BANNER_EY_ENTRY = 184382, //Visual Banner (Neutral) - BG_OBJECT_BE_TOWER_CAP_EY_ENTRY = 184080, //BE Tower Cap Pt - BG_OBJECT_FR_TOWER_CAP_EY_ENTRY = 184081, //Fel Reaver Cap Pt - BG_OBJECT_HU_TOWER_CAP_EY_ENTRY = 184082, //Human Tower Cap Pt - BG_OBJECT_DR_TOWER_CAP_EY_ENTRY = 184083 //Draenei Tower Cap Pt -}; - -enum EYBattleGroundPointsTrigger -{ - TR_BLOOD_ELF_POINT = 4476, - TR_FEL_REALVER_POINT = 4514, - TR_MAGE_TOWER_POINT = 4516, - TR_DRAENEI_RUINS_POINT = 4518, - TR_BLOOD_ELF_BUFF = 4568, - TR_FEL_REALVER_BUFF = 4569, - TR_MAGE_TOWER_BUFF = 4570, - TR_DRAENEI_RUINS_BUFF = 4571 -}; - -enum EYBattleGroundGaveyards -{ - EY_GRAVEYARD_MAIN_ALLIANCE = 1103, - EY_GRAVEYARD_MAIN_HORDE = 1104, - EY_GRAVEYARD_FEL_REALVER = 1105, - EY_GRAVEYARD_BLOOD_ELF = 1106, - EY_GRAVEYARD_DRAENEI_RUINS = 1107, - EY_GRAVEYARD_MAGE_TOWER = 1108 -}; - -enum EYBattleGroundPoints -{ - FEL_REALVER = 0, - BLOOD_ELF = 1, - DRAENEI_RUINS = 2, - MAGE_TOWER = 3, - - EY_PLAYERS_OUT_OF_POINTS = 4, - EY_POINTS_MAX = 4 -}; - -enum EYBattleGroundCreaturesTypes -{ - EY_SPIRIT_FEL_REALVER = 0, - EY_SPIRIT_BLOOD_ELF = 1, - EY_SPIRIT_DRAENEI_RUINS = 2, - EY_SPIRIT_MAGE_TOWER = 3, - EY_SPIRIT_MAIN_ALLIANCE = 4, - EY_SPIRIT_MAIN_HORDE = 5, - - EY_TRIGGER_FEL_REALVER = 6, - EY_TRIGGER_BLOOD_ELF = 7, - EY_TRIGGER_DRAENEI_RUINS = 8, - EY_TRIGGER_MAGE_TOWER = 9, - - BG_EY_CREATURES_MAX = 10 -}; - -enum EYBattleGroundObjectTypes -{ - BG_EY_OBJECT_DOOR_A = 0, - BG_EY_OBJECT_DOOR_H = 1, - BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER = 2, - BG_EY_OBJECT_A_BANNER_FEL_REALVER_LEFT = 3, - BG_EY_OBJECT_A_BANNER_FEL_REALVER_RIGHT = 4, - BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER = 5, - BG_EY_OBJECT_A_BANNER_BLOOD_ELF_LEFT = 6, - BG_EY_OBJECT_A_BANNER_BLOOD_ELF_RIGHT = 7, - BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER = 8, - BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_LEFT = 9, - BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_RIGHT = 10, - BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER = 11, - BG_EY_OBJECT_A_BANNER_MAGE_TOWER_LEFT = 12, - BG_EY_OBJECT_A_BANNER_MAGE_TOWER_RIGHT = 13, - BG_EY_OBJECT_H_BANNER_FEL_REALVER_CENTER = 14, - BG_EY_OBJECT_H_BANNER_FEL_REALVER_LEFT = 15, - BG_EY_OBJECT_H_BANNER_FEL_REALVER_RIGHT = 16, - BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER = 17, - BG_EY_OBJECT_H_BANNER_BLOOD_ELF_LEFT = 18, - BG_EY_OBJECT_H_BANNER_BLOOD_ELF_RIGHT = 19, - BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER = 20, - BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_LEFT = 21, - BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_RIGHT = 22, - BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER = 23, - BG_EY_OBJECT_H_BANNER_MAGE_TOWER_LEFT = 24, - BG_EY_OBJECT_H_BANNER_MAGE_TOWER_RIGHT = 25, - BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER = 26, - BG_EY_OBJECT_N_BANNER_FEL_REALVER_LEFT = 27, - BG_EY_OBJECT_N_BANNER_FEL_REALVER_RIGHT = 28, - BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER = 29, - BG_EY_OBJECT_N_BANNER_BLOOD_ELF_LEFT = 30, - BG_EY_OBJECT_N_BANNER_BLOOD_ELF_RIGHT = 31, - BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER = 32, - BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_LEFT = 33, - BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_RIGHT = 34, - BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER = 35, - BG_EY_OBJECT_N_BANNER_MAGE_TOWER_LEFT = 36, - BG_EY_OBJECT_N_BANNER_MAGE_TOWER_RIGHT = 37, - BG_EY_OBJECT_TOWER_CAP_FEL_REALVER = 38, - BG_EY_OBJECT_TOWER_CAP_BLOOD_ELF = 39, - BG_EY_OBJECT_TOWER_CAP_DRAENEI_RUINS = 40, - BG_EY_OBJECT_TOWER_CAP_MAGE_TOWER = 41, - BG_EY_OBJECT_FLAG_NETHERSTORM = 42, - BG_EY_OBJECT_FLAG_FEL_REALVER = 43, - BG_EY_OBJECT_FLAG_BLOOD_ELF = 44, - BG_EY_OBJECT_FLAG_DRAENEI_RUINS = 45, - BG_EY_OBJECT_FLAG_MAGE_TOWER = 46, - //buffs - BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER = 47, - BG_EY_OBJECT_REGENBUFF_FEL_REALVER = 48, - BG_EY_OBJECT_BERSERKBUFF_FEL_REALVER = 49, - BG_EY_OBJECT_SPEEDBUFF_BLOOD_ELF = 50, - BG_EY_OBJECT_REGENBUFF_BLOOD_ELF = 51, - BG_EY_OBJECT_BERSERKBUFF_BLOOD_ELF = 52, - BG_EY_OBJECT_SPEEDBUFF_DRAENEI_RUINS = 53, - BG_EY_OBJECT_REGENBUFF_DRAENEI_RUINS = 54, - BG_EY_OBJECT_BERSERKBUFF_DRAENEI_RUINS = 55, - BG_EY_OBJECT_SPEEDBUFF_MAGE_TOWER = 56, - BG_EY_OBJECT_REGENBUFF_MAGE_TOWER = 57, - BG_EY_OBJECT_BERSERKBUFF_MAGE_TOWER = 58, - BG_EY_OBJECT_MAX = 59 -}; - -#define BG_EY_NotEYWeekendHonorTicks 330 -#define BG_EY_EYWeekendHonorTicks 200 - -enum BG_EY_Score -{ - BG_EY_WARNING_NEAR_VICTORY_SCORE = 1400, - BG_EY_MAX_TEAM_SCORE = 1600 -}; - -enum BG_EY_FlagState -{ - BG_EY_FLAG_STATE_ON_BASE = 0, - BG_EY_FLAG_STATE_WAIT_RESPAWN = 1, - BG_EY_FLAG_STATE_ON_PLAYER = 2, - BG_EY_FLAG_STATE_ON_GROUND = 3 -}; - -enum EYBattleGroundPointState -{ - EY_POINT_NO_OWNER = 0, - EY_POINT_STATE_UNCONTROLLED = 0, - EY_POINT_UNDER_CONTROL = 3 -}; - -struct BattleGroundEYPointIconsStruct -{ - BattleGroundEYPointIconsStruct(uint32 _WorldStateControlIndex, uint32 _WorldStateAllianceControlledIndex, uint32 _WorldStateHordeControlledIndex) - : WorldStateControlIndex(_WorldStateControlIndex), WorldStateAllianceControlledIndex(_WorldStateAllianceControlledIndex), WorldStateHordeControlledIndex(_WorldStateHordeControlledIndex) {} - uint32 WorldStateControlIndex; - uint32 WorldStateAllianceControlledIndex; - uint32 WorldStateHordeControlledIndex; -}; - -// x, y, z, o -const float BG_EY_TriggerPositions[EY_POINTS_MAX][4] = { - {2044.28f, 1729.68f, 1189.96f, -0.017453f}, // FEL_REALVER center - {2048.83f, 1393.65f, 1194.49f, 0.20944f}, // BLOOD_ELF center - {2286.56f, 1402.36f, 1197.11f, 3.72381f}, // DRAENEI_RUINS center - {2284.48f, 1731.23f, 1189.99f, 2.89725f} // MAGE_TOWER center -}; - -struct BattleGroundEYLoosingPointStruct -{ - BattleGroundEYLoosingPointStruct(uint32 _SpawnNeutralObjectType, uint32 _DespawnObjectTypeAlliance, uint32 _MessageIdAlliance, uint32 _DespawnObjectTypeHorde, uint32 _MessageIdHorde) - : SpawnNeutralObjectType(_SpawnNeutralObjectType), - DespawnObjectTypeAlliance(_DespawnObjectTypeAlliance), MessageIdAlliance(_MessageIdAlliance), - DespawnObjectTypeHorde(_DespawnObjectTypeHorde), MessageIdHorde(_MessageIdHorde) - {} - - uint32 SpawnNeutralObjectType; - uint32 DespawnObjectTypeAlliance; - uint32 MessageIdAlliance; - uint32 DespawnObjectTypeHorde; - uint32 MessageIdHorde; -}; - -struct BattleGroundEYCapturingPointStruct -{ - BattleGroundEYCapturingPointStruct(uint32 _DespawnNeutralObjectType, uint32 _SpawnObjectTypeAlliance, uint32 _MessageIdAlliance, uint32 _SpawnObjectTypeHorde, uint32 _MessageIdHorde, uint32 _GraveYardId) - : DespawnNeutralObjectType(_DespawnNeutralObjectType), - SpawnObjectTypeAlliance(_SpawnObjectTypeAlliance), MessageIdAlliance(_MessageIdAlliance), - SpawnObjectTypeHorde(_SpawnObjectTypeHorde), MessageIdHorde(_MessageIdHorde), - GraveYardId(_GraveYardId) - {} - - uint32 DespawnNeutralObjectType; - uint32 SpawnObjectTypeAlliance; - uint32 MessageIdAlliance; - uint32 SpawnObjectTypeHorde; - uint32 MessageIdHorde; - uint32 GraveYardId; -}; - -const uint8 BG_EY_TickPoints[EY_POINTS_MAX] = {1, 2, 5, 10}; -const uint32 BG_EY_FlagPoints[EY_POINTS_MAX] = {75, 85, 100, 500}; - -//constant arrays: -const BattleGroundEYPointIconsStruct m_PointsIconStruct[EY_POINTS_MAX] = -{ - BattleGroundEYPointIconsStruct(FEL_REAVER_UNCONTROL, FEL_REAVER_ALLIANCE_CONTROL, FEL_REAVER_HORDE_CONTROL), - BattleGroundEYPointIconsStruct(BLOOD_ELF_UNCONTROL, BLOOD_ELF_ALLIANCE_CONTROL, BLOOD_ELF_HORDE_CONTROL), - BattleGroundEYPointIconsStruct(DRAENEI_RUINS_UNCONTROL, DRAENEI_RUINS_ALLIANCE_CONTROL, DRAENEI_RUINS_HORDE_CONTROL), - BattleGroundEYPointIconsStruct(MAGE_TOWER_UNCONTROL, MAGE_TOWER_ALLIANCE_CONTROL, MAGE_TOWER_HORDE_CONTROL) -}; -const BattleGroundEYLoosingPointStruct m_LoosingPointTypes[EY_POINTS_MAX] = -{ - BattleGroundEYLoosingPointStruct(BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER, BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER, LANG_BG_EY_HAS_LOST_A_F_RUINS, BG_EY_OBJECT_H_BANNER_FEL_REALVER_CENTER, LANG_BG_EY_HAS_LOST_H_F_RUINS), - BattleGroundEYLoosingPointStruct(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_LOST_A_B_TOWER, BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_LOST_H_B_TOWER), - BattleGroundEYLoosingPointStruct(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_LOST_A_D_RUINS, BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_LOST_H_D_RUINS), - BattleGroundEYLoosingPointStruct(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_LOST_A_M_TOWER, BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_LOST_H_M_TOWER) -}; -const BattleGroundEYCapturingPointStruct m_CapturingPointTypes[EY_POINTS_MAX] = -{ - BattleGroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER, BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER, LANG_BG_EY_HAS_TAKEN_A_F_RUINS, BG_EY_OBJECT_H_BANNER_FEL_REALVER_CENTER, LANG_BG_EY_HAS_TAKEN_H_F_RUINS, EY_GRAVEYARD_FEL_REALVER), - BattleGroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_TAKEN_A_B_TOWER, BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_TAKEN_H_B_TOWER, EY_GRAVEYARD_BLOOD_ELF), - BattleGroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_TAKEN_A_D_RUINS, BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_TAKEN_H_D_RUINS, EY_GRAVEYARD_DRAENEI_RUINS), - BattleGroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_TAKEN_A_M_TOWER, BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_TAKEN_H_M_TOWER, EY_GRAVEYARD_MAGE_TOWER) -}; - -class BattleGroundEYScore : public BattleGroundScore -{ - public: - BattleGroundEYScore () : FlagCaptures(0) {}; - virtual ~BattleGroundEYScore() {}; - uint32 FlagCaptures; -}; - -class BattleGroundEY : public BattleGround -{ - friend class BattleGroundMgr; - - public: - BattleGroundEY(); - ~BattleGroundEY(); - void Update(uint32 diff); - - /* inherited from BattlegroundClass */ - virtual void AddPlayer(Player *plr); - virtual void StartingEventCloseDoors(); - virtual void StartingEventOpenDoors(); - - /* BG Flags */ - uint64 GetFlagPickerGUID() const { return m_FlagKeeper; } - void SetFlagPicker(uint64 guid) { m_FlagKeeper = guid; } - bool IsFlagPickedup() const { return m_FlagKeeper != 0; } - uint8 GetFlagState() const { return m_FlagState; } - void RespawnFlag(bool send_message); - void RespawnFlagAfterDrop(); - - void RemovePlayer(Player *plr,uint64 guid); - void HandleBuffUse(uint64 const& buff_guid); - void HandleAreaTrigger(Player *Source, uint32 Trigger); - void HandleKillPlayer(Player *player, Player *killer); - virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); - virtual bool SetupBattleGround(); - virtual void Reset(); - void UpdateTeamScore(uint32 Team); - void EndBattleGround(uint32 winner); - void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); - virtual void FillInitialWorldStates(WorldPacket& data); - void SetDroppedFlagGUID(uint64 guid) { m_DroppedFlagGUID = guid;} - uint64 GetDroppedFlagGUID() const { return m_DroppedFlagGUID;} - - /* Battleground Events */ - virtual void EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj); - virtual void EventPlayerDroppedFlag(Player *Source); - - /* achievement req. */ - bool IsAllNodesConrolledByTeam(uint32 team) const; - private: - void EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType); - void EventTeamCapturedPoint(Player *Source, uint32 Point); - void EventTeamLostPoint(Player *Source, uint32 Point); - void UpdatePointsCount(uint32 Team); - void UpdatePointsIcons(uint32 Team, uint32 Point); - - /* Point status updating procedures */ - void CheckSomeoneLeftPoint(); - void CheckSomeoneJoinedPoint(); - void UpdatePointStatuses(); - - /* Scorekeeping */ - uint32 GetTeamScore(uint32 Team) const { return m_TeamScores[GetTeamIndexByTeamId(Team)]; } - void AddPoints(uint32 Team, uint32 Points); - - void RemovePoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] -= Points; } - void SetTeamPoint(uint32 TeamID, uint32 Points = 0) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] = Points; } - - uint32 m_HonorScoreTics[2]; - uint32 m_TeamPointsCount[2]; - - uint32 m_Points_Trigger[EY_POINTS_MAX]; - - uint64 m_FlagKeeper; // keepers guid - uint64 m_DroppedFlagGUID; - uint32 m_FlagCapturedBgObjectType; // type that should be despawned when flag is captured - uint8 m_FlagState; // for checking flag state - int32 m_FlagsTimer; - int32 m_TowerCapCheckTimer; - - uint32 m_PointOwnedByTeam[EY_POINTS_MAX]; - uint8 m_PointState[EY_POINTS_MAX]; - int32 m_PointBarStatus[EY_POINTS_MAX]; - typedef std::vector PlayersNearPointType; - PlayersNearPointType m_PlayersNearPoint[EY_POINTS_MAX + 1]; - uint8 m_CurrentPointPlayersCount[2*EY_POINTS_MAX]; - - int32 m_PointAddingTimer; - uint32 m_HonorTics; -}; -#endif - diff --git a/src/server/game/BattleGrounds/BattleGroundHandler.cpp b/src/server/game/BattleGrounds/BattleGroundHandler.cpp deleted file mode 100644 index e779f2a8ab1..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundHandler.cpp +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "ObjectAccessor.h" -#include "ObjectMgr.h" -#include "WorldPacket.h" -#include "WorldSession.h" - -#include "ArenaTeam.h" -#include "BattleGroundMgr.h" -#include "BattleGroundWS.h" -#include "BattleGround.h" -#include "Chat.h" -#include "Language.h" -#include "Log.h" -#include "Player.h" -#include "Object.h" -#include "Opcodes.h" - -void WorldSession::HandleBattlemasterHelloOpcode(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - sLog.outDebug("WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(guid))); - - Creature *unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - return; - - if (!unit->isBattleMaster()) // it's not battlemaster - return; - - // Stop the npc if moving - unit->StopMoving(); - - BattleGroundTypeId bgTypeId = sBattleGroundMgr.GetBattleMasterBG(unit->GetEntry()); - - if (!_player->GetBGAccessByLevel(bgTypeId)) - { - // temp, must be gossip message... - SendNotification(LANG_YOUR_BG_LEVEL_REQ_ERROR); - return; - } - - SendBattlegGroundList(guid, bgTypeId); -} - -void WorldSession::SendBattlegGroundList(uint64 guid, BattleGroundTypeId bgTypeId) -{ - WorldPacket data; - sBattleGroundMgr.BuildBattleGroundListPacket(&data, guid, _player, bgTypeId, 0); - SendPacket(&data); -} - -void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket & recv_data) -{ - uint64 guid; - uint32 bgTypeId_; - uint32 instanceId; - uint8 joinAsGroup; - bool isPremade = false; - Group * grp = NULL; - - recv_data >> guid; // battlemaster guid - recv_data >> bgTypeId_; // battleground type id (DBC id) - recv_data >> instanceId; // instance id, 0 if First Available selected - recv_data >> joinAsGroup; // join as group - - if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) - { - sLog.outError("Battleground: invalid bgtype (%u) received. possible cheater? player guid %u",bgTypeId_,_player->GetGUIDLow()); - return; - } - - BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_); - - sLog.outDebug("WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid))); - - // can do this, since it's battleground, not arena - BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, 0); - BattleGroundQueueTypeId bgQueueTypeIdRandom = BattleGroundMgr::BGQueueTypeId(BATTLEGROUND_RB, 0); - - // ignore if player is already in BG - if (_player->InBattleGround()) - return; - - // get bg instance or bg template if instance not found - BattleGround *bg = NULL; - if (instanceId) - bg = sBattleGroundMgr.GetBattleGroundThroughClientInstance(instanceId, bgTypeId); - - if (!bg) - bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - if (!bg) - return; - - // expected bracket entry - PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),_player->getLevel()); - if (!bracketEntry) - return; - - GroupJoinBattlegroundResult err; - - // check queue conditions - if (!joinAsGroup) - { - // check Deserter debuff - if (!_player->CanJoinToBattleground()) - { - WorldPacket data; - sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); - _player->GetSession()->SendPacket(&data); - return; - } - - if (_player->GetBattleGroundQueueIndex(bgQueueTypeIdRandom) < PLAYER_MAX_BATTLEGROUND_QUEUES) - { - //player is already in random queue - WorldPacket data; - sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, ERR_IN_RANDOM_BG); - _player->GetSession()->SendPacket(&data); - return; - } - - if (_player->InBattleGroundQueue() && bgTypeId == BATTLEGROUND_RB) - { - //player is already in queue, can't start random queue - WorldPacket data; - sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, ERR_IN_NON_RANDOM_BG); - _player->GetSession()->SendPacket(&data); - return; - } - - // check if already in queue - if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) - //player is already in this queue - return; - - // check if has free queue slots - if (!_player->HasFreeBattleGroundQueueId()) - { - WorldPacket data; - sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_TOO_MANY_QUEUES); - _player->GetSession()->SendPacket(&data); - return; - } - - BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; - - GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, 0, false, isPremade, 0); - uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); - // already checked if queueSlot is valid, now just get it - uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId); - - WorldPacket data; - // send status packet (in queue) - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); - SendPacket(&data); - sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); - } - else - { - grp = _player->GetGroup(); - // no group found, error - if (!grp) - return; - if (grp->GetLeaderGUID() != _player->GetGUID()) - return; - err = grp->CanJoinBattleGroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0); - isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam()); - - BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; - GroupQueueInfo * ginfo = NULL; - uint32 avgTime = 0; - - if (err > 0) - { - sLog.outDebug("Battleground: the following players are joining as group:"); - ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, 0, false, isPremade, 0); - avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); - } - - for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player *member = itr->getSource(); - if (!member) continue; // this should never happen - - WorldPacket data; - - if (err <= 0) - { - sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, err); - member->GetSession()->SendPacket(&data); - continue; - } - - // add to queue - uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); - - // send status packet (in queue) - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); - member->GetSession()->SendPacket(&data); - sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, err); - member->GetSession()->SendPacket(&data); - sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName()); - } - sLog.outDebug("Battleground: group end"); - - } - sBattleGroundMgr.ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); -} - -void WorldSession::HandleBattleGroundPlayerPositionsOpcode(WorldPacket & /*recv_data*/) -{ - // empty opcode - sLog.outDebug("WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message"); - - BattleGround *bg = _player->GetBattleGround(); - if (!bg) // can't be received if player not in battleground - return; - - switch(bg->GetTypeID(true)) - { - case BATTLEGROUND_WS: - { - uint32 count1 = 0; //always constant zero? - uint32 count2 = 0; //count of next fields - - Player *ali_plr = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID()); - if (ali_plr) - ++count2; - - Player *horde_plr = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetHordeFlagPickerGUID()); - if (horde_plr) - ++count2; - - WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4+16*count1+16*count2)); - data << count1; // alliance flag holders count - obsolete, now always 0 - /*for (uint8 i = 0; i < count1; ++i) - { - data << uint64(0); // guid - data << (float)0; // x - data << (float)0; // y - }*/ - data << count2; // horde flag holders count - obsolete, now count of next fields - if (ali_plr) - { - data << (uint64)ali_plr->GetGUID(); - data << (float)ali_plr->GetPositionX(); - data << (float)ali_plr->GetPositionY(); - } - if (horde_plr) - { - data << (uint64)horde_plr->GetGUID(); - data << (float)horde_plr->GetPositionX(); - data << (float)horde_plr->GetPositionY(); - } - - SendPacket(&data); - } - break; - case BATTLEGROUND_EY: - //TODO : fix me! - break; - case BATTLEGROUND_AB: - case BATTLEGROUND_AV: - { - //for other BG types - send default - WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4)); - data << uint32(0); - data << uint32(0); - SendPacket(&data); - } - break; - default: - //maybe it is sent also in arena - do nothing - break; - } -} - -void WorldSession::HandlePVPLogDataOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("WORLD: Recvd MSG_PVP_LOG_DATA Message"); - - BattleGround *bg = _player->GetBattleGround(); - if (!bg) - return; - - WorldPacket data; - sBattleGroundMgr.BuildPvpLogDataPacket(&data, bg); - SendPacket(&data); - - sLog.outDebug("WORLD: Sent MSG_PVP_LOG_DATA Message"); -} - -void WorldSession::HandleBattlefieldListOpcode(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: Recvd CMSG_BATTLEFIELD_LIST Message"); - - uint32 bgTypeId; - recv_data >> bgTypeId; // id from DBC - - uint8 fromWhere; - recv_data >> fromWhere; // 0 - battlemaster (lua: ShowBattlefieldList), 1 - UI (lua: RequestBattlegroundInstanceInfo) - - uint8 unk1; - recv_data >> unk1; // Unknown 3.2.2 - - BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); - if (!bl) - { - sLog.outError("Battleground: invalid bgtype received."); - return; - } - - WorldPacket data; - sBattleGroundMgr.BuildBattleGroundListPacket(&data, 0, _player, BattleGroundTypeId(bgTypeId), fromWhere); - SendPacket(&data); -} - -void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: Recvd CMSG_BATTLEFIELD_PORT Message"); - - uint8 type; // arenatype if arena - uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1 - uint32 bgTypeId_; // type id from dbc - uint16 unk; // 0x1F90 constant? - uint8 action; // enter battle 0x1, leave queue 0x0 - - recv_data >> type >> unk2 >> bgTypeId_ >> unk >> action; - - if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) - { - sLog.outError("BattlegroundHandler: invalid bgtype (%u) received.", bgTypeId_); - return; - } - if (!_player->InBattleGroundQueue()) - { - sLog.outError("BattlegroundHandler: Invalid CMSG_BATTLEFIELD_PORT received from player (%u), he is not in bg_queue.", _player->GetGUIDLow()); - return; - } - - //get GroupQueueInfo from BattleGroundQueue - BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_); - BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type); - BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; - //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function - GroupQueueInfo ginfo; - if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) - { - sLog.outError("BattlegroundHandler: itrplayerstatus not found."); - return; - } - // if action == 1, then instanceId is required - if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) - { - sLog.outError("BattlegroundHandler: instance not found."); - return; - } - - BattleGround *bg = sBattleGroundMgr.GetBattleGround(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); - - // bg template might and must be used in case of leaving queue, when instance is not created yet - if (!bg && action == 0) - bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - if (!bg) - { - sLog.outError("BattlegroundHandler: bg_template not found for type id %u.", bgTypeId); - return; - } - - // expected bracket entry - PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),_player->getLevel()); - if (!bracketEntry) - return; - - //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it - if (action == 1 && ginfo.ArenaType == 0) - { - //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue - if (!_player->CanJoinToBattleground()) - { - //send bg command result to show nice message - WorldPacket data2; - sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data2, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); - _player->GetSession()->SendPacket(&data2); - action = 0; - sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); - } - //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue - if (_player->getLevel() > bg->GetMaxLevel()) - { - sLog.outError("Battleground: Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!", - _player->GetName(), _player->GetGUIDLow(), _player->getLevel(), bg->GetMaxLevel(), bg->GetTypeID()); - action = 0; - } - } - uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId); - WorldPacket data; - switch(action) - { - case 1: // port to battleground - if (!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId)) - return; // cheating? - - if (!_player->InBattleGround()) - _player->SetBattleGroundEntryPoint(); - - // resurrect the player - if (!_player->isAlive()) - { - _player->ResurrectPlayer(1.0f); - _player->SpawnCorpseBones(); - } - // stop taxi flight at port - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType()); - _player->GetSession()->SendPacket(&data); - // remove battleground queue status from BGmgr - bgQueue.RemovePlayer(_player->GetGUID(), false); - // this is still needed here if battleground "jumping" shouldn't add deserter debuff - // also this is required to prevent stuck at old battleground after SetBattleGroundId set to new - if (BattleGround *currentBg = _player->GetBattleGround()) - currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); - - // set the destination instance id - _player->SetBattleGroundId(bg->GetInstanceID(), bgTypeId); - // set the destination team - _player->SetBGTeam(ginfo.Team); - // bg->HandleBeforeTeleportToBattleGround(_player); - sBattleGroundMgr.SendToBattleGround(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); - // add only in HandleMoveWorldPortAck() - // bg->AddPlayer(_player,team); - sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId); - break; - case 0: // leave queue - // if player leaves rated arena match before match start, it is counted as he played but he lost - if (ginfo.IsRated) - { - ArenaTeam * at = objmgr.GetArenaTeamById(ginfo.Team); - if (at) - { - sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), ginfo.OpponentsTeamRating); - at->MemberLost(_player, ginfo.OpponentsTeamRating); - at->SaveToDB(); - } - } - _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); - bgQueue.RemovePlayer(_player->GetGUID(), true); - // player left queue, we should update it - do not update Arena Queue - if (!ginfo.ArenaType) - sBattleGroundMgr.ScheduleQueueUpdate(ginfo.ArenaTeamRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); - SendPacket(&data); - sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); - break; - default: - sLog.outError("Battleground port: unknown action %u", action); - break; - } -} - -void WorldSession::HandleLeaveBattlefieldOpcode(WorldPacket& recv_data) -{ - sLog.outDebug("WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message"); - - recv_data.read_skip(); // unk1 - recv_data.read_skip(); // unk2 - recv_data.read_skip(); // BattleGroundTypeId - recv_data.read_skip(); // unk3 - - // not allow leave battleground in combat - if (_player->isInCombat()) - if (BattleGround* bg = _player->GetBattleGround()) - if (bg->GetStatus() != STATUS_WAIT_LEAVE) - return; - - _player->LeaveBattleground(); -} - -void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recv_data*/) -{ - // empty opcode - sLog.outDebug("WORLD: Battleground status"); - - WorldPacket data; - // we must update all queues here - BattleGround *bg = NULL; - for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) - { - BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i); - if (!bgQueueTypeId) - continue; - BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); - uint8 arenaType = BattleGroundMgr::BGArenaType(bgQueueTypeId); - if (bgTypeId == _player->GetBattleGroundTypeId()) - { - bg = _player->GetBattleGround(); - //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena - //so i must use bg pointer to get that information - if (bg && bg->GetArenaType() == arenaType) - { - // this line is checked, i only don't know if GetStartTime is changing itself after bg end! - // send status in BattleGround - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType); - SendPacket(&data); - continue; - } - } - //we are sending update to player about queue - he can be invited there! - //get GroupQueueInfo for queue status - BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; - GroupQueueInfo ginfo; - if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) - continue; - if (ginfo.IsInvitedToBGInstanceGUID) - { - bg = sBattleGroundMgr.GetBattleGround(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); - if (!bg) - continue; - uint32 remainingTime = getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime); - // send status invited to BattleGround - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType); - SendPacket(&data); - } - else - { - bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - if (!bg) - continue; - - // expected bracket entry - PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),_player->getLevel()); - if (!bracketEntry) - continue; - - uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, bracketEntry->GetBracketId()); - // send status in BattleGround Queue - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, getMSTime()), arenaType); - SendPacket(&data); - } - } -} - -void WorldSession::HandleAreaSpiritHealerQueryOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY"); - - BattleGround *bg = _player->GetBattleGround(); - - uint64 guid; - recv_data >> guid; - - Creature *unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - return; - - if (!unit->isSpiritService()) // it's not spirit service - return; - - if (bg) - sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, guid); -} - - -void WorldSession::HandleAreaSpiritHealerQueueOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE"); - - BattleGround *bg = _player->GetBattleGround(); - - uint64 guid; - recv_data >> guid; - - Creature *unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - return; - - if (!unit->isSpiritService()) // it's not spirit service - return; - - if (bg) - bg->AddPlayerToResurrectQueue(guid, _player->GetGUID()); -} - - -void WorldSession::HandleBattlemasterJoinArena(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_BATTLEMASTER_JOIN_ARENA"); - //recv_data.hexlike(); - - uint64 guid; // arena Battlemaster guid - uint8 arenaslot; // 2v2, 3v3 or 5v5 - uint8 asGroup; // asGroup - uint8 isRated; // isRated - Group * grp = NULL; - - recv_data >> guid >> arenaslot >> asGroup >> isRated; - - // ignore if we already in BG or BG queue - if (_player->InBattleGround()) - return; - - Creature *unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - return; - - if (!unit->isBattleMaster()) // it's not battle master - return; - - uint8 arenatype = 0; - uint32 arenaRating = 0; - - switch(arenaslot) - { - case 0: - arenatype = ARENA_TYPE_2v2; - break; - case 1: - arenatype = ARENA_TYPE_3v3; - break; - case 2: - arenatype = ARENA_TYPE_5v5; - break; - default: - sLog.outError("Unknown arena slot %u at HandleBattlemasterJoinArena()", arenaslot); - return; - } - - //check existance - BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA); - if (!bg) - { - sLog.outError("Battleground: template bg (all arenas) not found"); - return; - } - - BattleGroundTypeId bgTypeId = bg->GetTypeID(); - BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype); - PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),_player->getLevel()); - if (!bracketEntry) - return; - - GroupJoinBattlegroundResult err = ERR_GROUP_JOIN_BATTLEGROUND_FAIL; - - if (!asGroup) - { - // check if already in queue - if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) - //player is already in this queue - return; - // check if has free queue slots - if (!_player->HasFreeBattleGroundQueueId()) - return; - } - else - { - grp = _player->GetGroup(); - // no group found, error - if (!grp) - return; - if (grp->GetLeaderGUID() != _player->GetGUID()) - return; - err = grp->CanJoinBattleGroundQueue(bg, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot); - } - - uint32 ateamId = 0; - - if (isRated) - { - ateamId = _player->GetArenaTeamId(arenaslot); - // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice) - ArenaTeam * at = objmgr.GetArenaTeamById(ateamId); - if (!at) - { - _player->GetSession()->SendNotInArenaTeamPacket(arenatype); - return; - } - // get the team rating for queueing - arenaRating = at->GetRating(); - // the arenateam id must match for everyone in the group - // get the personal ratings for queueing - uint32 avg_pers_rating = 0; - for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player *member = itr->getSource(); - - // calc avg personal rating - avg_pers_rating += member->GetArenaPersonalRating(arenaslot); - } - - if (arenatype) - avg_pers_rating /= arenatype; - - // if avg personal rating is more than 150 points below the teams rating, the team will be queued against an opponent matching or similar to the average personal rating - if (avg_pers_rating + 150 < arenaRating) - arenaRating = avg_pers_rating; - - if (arenaRating <= 0) - arenaRating = 1; - } - - BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; - if (asGroup) - { - uint32 avgTime = 0; - - if (err > 0) - { - sLog.outDebug("Battleground: arena join as group start"); - if (isRated) - { - sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype); - bg->SetRated(true); - } - else - bg->SetRated(false); - - GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, arenatype, isRated, false, arenaRating, ateamId); - avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); - } - - for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player *member = itr->getSource(); - if (!member) - continue; - - WorldPacket data; - - if (err <= 0) - { - sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, err); - member->GetSession()->SendPacket(&data); - continue; - } - - // add to queue - uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); - - // send status packet (in queue) - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); - member->GetSession()->SendPacket(&data); - sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, err); - member->GetSession()->SendPacket(&data); - sLog.outDebug("Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName()); - } - } - else - { - GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, arenatype, isRated, false, arenaRating, ateamId); - uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); - uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId); - - WorldPacket data; - // send status packet (in queue) - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); - SendPacket(&data); - sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); - } - sBattleGroundMgr.ScheduleQueueUpdate(arenaRating, arenatype, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); -} - -void WorldSession::HandleReportPvPAFK(WorldPacket & recv_data) -{ - uint64 playerGuid; - recv_data >> playerGuid; - Player *reportedPlayer = objmgr.GetPlayer(playerGuid); - - if (!reportedPlayer) - { - sLog.outDebug("WorldSession::HandleReportPvPAFK: player not found"); - return; - } - - sLog.outDebug("WorldSession::HandleReportPvPAFK: %s reported %s", _player->GetName(), reportedPlayer->GetName()); - - reportedPlayer->ReportedAfkBy(_player); -} diff --git a/src/server/game/BattleGrounds/BattleGroundIC.cpp b/src/server/game/BattleGrounds/BattleGroundIC.cpp deleted file mode 100644 index 8dbcc81e5c6..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundIC.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Player.h" -#include "BattleGround.h" -#include "BattleGroundIC.h" -#include "Language.h" - -BattleGroundIC::BattleGroundIC() -{ - m_BgCreatures.resize(2); - m_BgObjects.resize(5); - //TODO FIX ME! - m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES; - m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN; -} - -BattleGroundIC::~BattleGroundIC() -{ - -} - -void BattleGroundIC::Update(uint32 diff) -{ - BattleGround::Update(diff); -} - -void BattleGroundIC::StartingEventCloseDoors() -{ -} - -void BattleGroundIC::StartingEventOpenDoors() -{ -} - -void BattleGroundIC::AddPlayer(Player *plr) -{ - BattleGround::AddPlayer(plr); - //create score and add it to map, default values are set in constructor - BattleGroundICScore* sc = new BattleGroundICScore; - - m_PlayerScores[plr->GetGUID()] = sc; -} - -void BattleGroundIC::RemovePlayer(Player* /*plr*/,uint64 /*guid*/) -{ - -} - -void BattleGroundIC::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/) -{ - // this is wrong way to implement these things. On official it done by gameobject spell cast. - if (GetStatus() != STATUS_IN_PROGRESS) - return; -} - -void BattleGroundIC::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) -{ - - std::map::iterator itr = m_PlayerScores.find(Source->GetGUID()); - - if (itr == m_PlayerScores.end()) // player not found... - return; - - BattleGround::UpdatePlayerScore(Source,type,value, doAddHonor); -} - -bool BattleGroundIC::SetupBattleGround() -{ - AddObject(0, 195157, 459.72f, -419.93f, 42.55f, 0, 0, 0, 0.9996573f, 0.02617699f, 10*MINUTE); - AddObject(1, 195158, 797.72f, -1009.48f, 138.52f, 0, 0, 0, 0.9996573f, 0.02617699f, 10*MINUTE); - AddObject(2, 195338, 418.98f, -838.33f, 51.09f, 0, 0, 0, 0.9996573f, 0.02617699f, 10*MINUTE); - AddObject(3, 195343, 1267.45f, -390.88f, 24.23f, 0, 0, 0, 0.9996573f, 0.02617699f, 10*MINUTE); - AddObject(4, 195333, 769.27f, -833.53f, 9.57f, 0, 0, 0, 0.9996573f, 0.02617699f, 10*MINUTE); - SpawnLeader(ALLIANCE); - SpawnLeader(HORDE); - return true; -} - -void BattleGroundIC::SpawnLeader(uint32 teamid) -{ - if (teamid == ALLIANCE) - AddCreature(34924, 0, ALLIANCE, 307.03f, -833.04f, 48.91f, 6.23f, 10*MINUTE); - else - AddCreature(34922, 1, HORDE, 1264.42f, -766.80f, 48.91f, 3.28f, 10*MINUTE); -} - -void BattleGroundIC::HandleKillUnit(Creature *unit, Player * /*killer*/) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - uint32 entry = unit->GetEntry(); - if (entry == 34924) - { - RewardHonorToTeam(500,HORDE); - EndBattleGround(HORDE); - } - else if (entry == 34922) - { - RewardHonorToTeam(500,ALLIANCE); - EndBattleGround(ALLIANCE); - } -} - -void BattleGroundIC::EndBattleGround(uint32 winner) -{ - BattleGround::EndBattleGround(winner); -} - -void BattleGroundIC::EventPlayerClickedOnFlag(Player * /*source*/, GameObject* /*target_obj*/) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; -} diff --git a/src/server/game/BattleGrounds/BattleGroundIC.h b/src/server/game/BattleGrounds/BattleGroundIC.h deleted file mode 100644 index e49ea01e850..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundIC.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __BATTLEGROUNDIC_H -#define __BATTLEGROUNDIC_H - -class BattleGround; - -enum Buffs -{ - OIL_REFINERY = 68719, - QUARRY = 68720 -}; - -class BattleGroundICScore : public BattleGroundScore -{ - public: - BattleGroundICScore() {}; - virtual ~BattleGroundICScore() {}; -}; - -class BattleGroundIC : public BattleGround -{ - friend class BattleGroundMgr; - - public: - BattleGroundIC(); - ~BattleGroundIC(); - void Update(uint32 diff); - - /* inherited from BattlegroundClass */ - virtual void AddPlayer(Player *plr); - virtual void StartingEventCloseDoors(); - virtual void StartingEventOpenDoors(); - - void RemovePlayer(Player *plr,uint64 guid); - void HandleAreaTrigger(Player *Source, uint32 Trigger); - bool SetupBattleGround(); - void SpawnLeader(uint32 teamid); - void HandleKillUnit(Creature *unit, Player *killer); - void EndBattleGround(uint32 winner); - void EventPlayerClickedOnFlag(Player *source, GameObject* /*target_obj*/); - - /* Scorekeeping */ - void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); - - private: -}; -#endif diff --git a/src/server/game/BattleGrounds/BattleGroundNA.cpp b/src/server/game/BattleGrounds/BattleGroundNA.cpp deleted file mode 100644 index 793cf13b3cb..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundNA.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "BattleGround.h" -#include "BattleGroundNA.h" -#include "Language.h" -#include "Object.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "WorldPacket.h" - -BattleGroundNA::BattleGroundNA() -{ - m_BgObjects.resize(BG_NA_OBJECT_MAX); - - m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; - m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; - m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; - m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; - //we must set messageIds - m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; - m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; - m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; -} - -BattleGroundNA::~BattleGroundNA() -{ - -} - -void BattleGroundNA::Update(uint32 diff) -{ - BattleGround::Update(diff); - - /*if (GetStatus() == STATUS_IN_PROGRESS) - { - // update something - }*/ -} - -void BattleGroundNA::StartingEventCloseDoors() -{ - for (uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_4; ++i) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); -} - -void BattleGroundNA::StartingEventOpenDoors() -{ - for (uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_2; ++i) - DoorOpen(i); - - for (uint32 i = BG_NA_OBJECT_BUFF_1; i <= BG_NA_OBJECT_BUFF_2; ++i) - SpawnBGObject(i, 60); -} - -void BattleGroundNA::AddPlayer(Player *plr) -{ - BattleGround::AddPlayer(plr); - //create score and add it to map, default values are set in constructor - BattleGroundNAScore* sc = new BattleGroundNAScore; - - m_PlayerScores[plr->GetGUID()] = sc; - - UpdateArenaWorldState(); -} - -void BattleGroundNA::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) -{ - if (GetStatus() == STATUS_WAIT_LEAVE) - return; - - UpdateArenaWorldState(); - CheckArenaWinConditions(); -} - -void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - if (!killer) - { - sLog.outError("BattleGroundNA: Killer player not found"); - return; - } - - BattleGround::HandleKillPlayer(player,killer); - - UpdateArenaWorldState(); - CheckArenaWinConditions(); -} - -bool BattleGroundNA::HandlePlayerUnderMap(Player *player) -{ - player->TeleportTo(GetMapId(),4055.504395,2919.660645,13.611241,player->GetOrientation(),false); - return true; -} - -void BattleGroundNA::HandleAreaTrigger(Player *Source, uint32 Trigger) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - //uint32 SpellId = 0; - //uint64 buff_guid = 0; - switch(Trigger) - { - case 4536: // buff trigger? - case 4537: // buff trigger? - break; - default: - sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); - Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); - break; - } - - //if (buff_guid) - // HandleTriggerBuff(buff_guid,Source); -} - -void BattleGroundNA::FillInitialWorldStates(WorldPacket &data) -{ - data << uint32(0xa11) << uint32(1); // 9 - UpdateArenaWorldState(); -} - -void BattleGroundNA::Reset() -{ - //call parent's class reset - BattleGround::Reset(); -} - -bool BattleGroundNA::SetupBattleGround() -{ - // gates - if (!AddObject(BG_NA_OBJECT_DOOR_1, BG_NA_OBJECT_TYPE_DOOR_1, 4031.854, 2966.833, 12.6462, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY) - || !AddObject(BG_NA_OBJECT_DOOR_2, BG_NA_OBJECT_TYPE_DOOR_2, 4081.179, 2874.97, 12.39171, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY) - || !AddObject(BG_NA_OBJECT_DOOR_3, BG_NA_OBJECT_TYPE_DOOR_3, 4023.709, 2981.777, 10.70117, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY) - || !AddObject(BG_NA_OBJECT_DOOR_4, BG_NA_OBJECT_TYPE_DOOR_4, 4090.064, 2858.438, 10.23631, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY) - // buffs - || !AddObject(BG_NA_OBJECT_BUFF_1, BG_NA_OBJECT_TYPE_BUFF_1, 4009.189941, 2895.250000, 13.052700, -1.448624, 0, 0, 0.6626201, -0.7489557, 120) - || !AddObject(BG_NA_OBJECT_BUFF_2, BG_NA_OBJECT_TYPE_BUFF_2, 4103.330078, 2946.350098, 13.051300, -0.06981307, 0, 0, 0.03489945, -0.9993908, 120)) - { - sLog.outErrorDb("BatteGroundNA: Failed to spawn some object!"); - return false; - } - - return true; -} - -/* -20:12:14 id:036668 [S2C] SMSG_INIT_WORLD_STATES (706 = 0x02C2) len: 86 -0000: 2f 02 00 00 72 0e 00 00 00 00 00 00 09 00 11 0a | /...r........... -0010: 00 00 01 00 00 00 0f 0a 00 00 00 00 00 00 10 0a | ................ -0020: 00 00 00 00 00 00 d4 08 00 00 00 00 00 00 d8 08 | ................ -0030: 00 00 00 00 00 00 d7 08 00 00 00 00 00 00 d6 08 | ................ -0040: 00 00 00 00 00 00 d5 08 00 00 00 00 00 00 d3 08 | ................ -0050: 00 00 00 00 00 00 | ...... -*/ diff --git a/src/server/game/BattleGrounds/BattleGroundNA.h b/src/server/game/BattleGrounds/BattleGroundNA.h deleted file mode 100644 index a11d311515d..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundNA.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __BATTLEGROUNDNA_H -#define __BATTLEGROUNDNA_H - -class BattleGround; - -enum BattleGroundNAObjectTypes -{ - BG_NA_OBJECT_DOOR_1 = 0, - BG_NA_OBJECT_DOOR_2 = 1, - BG_NA_OBJECT_DOOR_3 = 2, - BG_NA_OBJECT_DOOR_4 = 3, - BG_NA_OBJECT_BUFF_1 = 4, - BG_NA_OBJECT_BUFF_2 = 5, - BG_NA_OBJECT_MAX = 6 -}; - -enum BattleGroundNAObjects -{ - BG_NA_OBJECT_TYPE_DOOR_1 = 183978, - BG_NA_OBJECT_TYPE_DOOR_2 = 183980, - BG_NA_OBJECT_TYPE_DOOR_3 = 183977, - BG_NA_OBJECT_TYPE_DOOR_4 = 183979, - BG_NA_OBJECT_TYPE_BUFF_1 = 184663, - BG_NA_OBJECT_TYPE_BUFF_2 = 184664 -}; - -class BattleGroundNAScore : public BattleGroundScore -{ - public: - BattleGroundNAScore() {}; - virtual ~BattleGroundNAScore() {}; - //TODO fix me -}; - -class BattleGroundNA : public BattleGround -{ - friend class BattleGroundMgr; - - public: - BattleGroundNA(); - ~BattleGroundNA(); - void Update(uint32 diff); - - /* inherited from BattlegroundClass */ - virtual void AddPlayer(Player *plr); - virtual void StartingEventCloseDoors(); - virtual void StartingEventOpenDoors(); - - void RemovePlayer(Player *plr, uint64 guid); - void HandleAreaTrigger(Player *Source, uint32 Trigger); - bool SetupBattleGround(); - virtual void Reset(); - virtual void FillInitialWorldStates(WorldPacket &d); - void HandleKillPlayer(Player* player, Player *killer); - bool HandlePlayerUnderMap(Player * plr); -}; -#endif diff --git a/src/server/game/BattleGrounds/BattleGroundRB.cpp b/src/server/game/BattleGrounds/BattleGroundRB.cpp deleted file mode 100644 index cf22154ed11..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundRB.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Player.h" -#include "BattleGround.h" -#include "BattleGroundRB.h" -#include "Language.h" - -BattleGroundRB::BattleGroundRB() -{ - //TODO FIX ME! - m_StartMessageIds[BG_STARTING_EVENT_FIRST] = 0; - m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN; -} - -BattleGroundRB::~BattleGroundRB() -{ - -} - -void BattleGroundRB::Update(uint32 diff) -{ - BattleGround::Update(diff); -} - -void BattleGroundRB::StartingEventCloseDoors() -{ -} - -void BattleGroundRB::StartingEventOpenDoors() -{ -} - -void BattleGroundRB::AddPlayer(Player *plr) -{ - BattleGround::AddPlayer(plr); - //create score and add it to map, default values are set in constructor - BattleGroundRBScore* sc = new BattleGroundRBScore; - - m_PlayerScores[plr->GetGUID()] = sc; -} - -void BattleGroundRB::RemovePlayer(Player* /*plr*/,uint64 /*guid*/) -{ -} - -void BattleGroundRB::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/) -{ - // this is wrong way to implement these things. On official it done by gameobject spell cast. - if (GetStatus() != STATUS_IN_PROGRESS) - return; -} - -void BattleGroundRB::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) -{ - std::map::iterator itr = m_PlayerScores.find(Source->GetGUID()); - - if (itr == m_PlayerScores.end()) // player not found... - return; - - BattleGround::UpdatePlayerScore(Source,type,value, doAddHonor); -} diff --git a/src/server/game/BattleGrounds/BattleGroundRB.h b/src/server/game/BattleGrounds/BattleGroundRB.h deleted file mode 100644 index a40ade5adfe..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundRB.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __BATTLEGROUNDRB_H -#define __BATTLEGROUNDRB_H - -class BattleGround; - -class BattleGroundRBScore : public BattleGroundScore -{ - public: - BattleGroundRBScore() {}; - virtual ~BattleGroundRBScore() {}; -}; - -class BattleGroundRB : public BattleGround -{ - friend class BattleGroundMgr; - - public: - BattleGroundRB(); - ~BattleGroundRB(); - void Update(uint32 diff); - - virtual void AddPlayer(Player *plr); - virtual void StartingEventCloseDoors(); - virtual void StartingEventOpenDoors(); - - void RemovePlayer(Player *plr,uint64 guid); - void HandleAreaTrigger(Player *Source, uint32 Trigger); - - /* Scorekeeping */ - void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); - - private: -}; -#endif diff --git a/src/server/game/BattleGrounds/BattleGroundRL.cpp b/src/server/game/BattleGrounds/BattleGroundRL.cpp deleted file mode 100644 index ef2ec3cfa94..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundRL.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "BattleGround.h" -#include "BattleGroundRL.h" -#include "Language.h" -#include "Object.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "WorldPacket.h" - -BattleGroundRL::BattleGroundRL() -{ - m_BgObjects.resize(BG_RL_OBJECT_MAX); - - m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; - m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; - m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; - m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; - //we must set messageIds - m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; - m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; - m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; -} - -BattleGroundRL::~BattleGroundRL() -{ - -} - -void BattleGroundRL::Update(uint32 diff) -{ - BattleGround::Update(diff); - - /*if (GetStatus() == STATUS_IN_PROGRESS) - { - // update something - }*/ -} - -void BattleGroundRL::StartingEventCloseDoors() -{ - for (uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; ++i) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); -} - -void BattleGroundRL::StartingEventOpenDoors() -{ - for (uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; ++i) - DoorOpen(i); - - for (uint32 i = BG_RL_OBJECT_BUFF_1; i <= BG_RL_OBJECT_BUFF_2; ++i) - SpawnBGObject(i, 60); -} - -void BattleGroundRL::AddPlayer(Player *plr) -{ - BattleGround::AddPlayer(plr); - //create score and add it to map, default values are set in constructor - BattleGroundRLScore* sc = new BattleGroundRLScore; - - m_PlayerScores[plr->GetGUID()] = sc; - - UpdateArenaWorldState(); -} - -void BattleGroundRL::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) -{ - if (GetStatus() == STATUS_WAIT_LEAVE) - return; - - UpdateArenaWorldState(); - CheckArenaWinConditions(); -} - -void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - if (!killer) - { - sLog.outError("Killer player not found"); - return; - } - - BattleGround::HandleKillPlayer(player,killer); - - UpdateArenaWorldState(); - CheckArenaWinConditions(); -} - -bool BattleGroundRL::HandlePlayerUnderMap(Player *player) -{ - player->TeleportTo(GetMapId(),1285.810547,1667.896851,39.957642,player->GetOrientation(),false); - return true; -} - -void BattleGroundRL::HandleAreaTrigger(Player *Source, uint32 Trigger) -{ - // this is wrong way to implement these things. On official it done by gameobject spell cast. - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - //uint32 SpellId = 0; - //uint64 buff_guid = 0; - switch(Trigger) - { - case 4696: // buff trigger? - case 4697: // buff trigger? - break; - default: - sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); - Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); - break; - } - - //if (buff_guid) - // HandleTriggerBuff(buff_guid,Source); -} - -void BattleGroundRL::FillInitialWorldStates(WorldPacket &data) -{ - data << uint32(0xbba) << uint32(1); // 9 - UpdateArenaWorldState(); -} - -void BattleGroundRL::Reset() -{ - //call parent's reset - BattleGround::Reset(); -} - -bool BattleGroundRL::SetupBattleGround() -{ - // gates - if (!AddObject(BG_RL_OBJECT_DOOR_1, BG_RL_OBJECT_TYPE_DOOR_1, 1293.561, 1601.938, 31.60557, -1.457349, 0, 0, -0.6658813, 0.7460576, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RL_OBJECT_DOOR_2, BG_RL_OBJECT_TYPE_DOOR_2, 1278.648, 1730.557, 31.60557, 1.684245, 0, 0, 0.7460582, 0.6658807, RESPAWN_IMMEDIATELY) - // buffs - || !AddObject(BG_RL_OBJECT_BUFF_1, BG_RL_OBJECT_TYPE_BUFF_1, 1328.719971, 1632.719971, 36.730400, -1.448624, 0, 0, 0.6626201, -0.7489557, 120) - || !AddObject(BG_RL_OBJECT_BUFF_2, BG_RL_OBJECT_TYPE_BUFF_2, 1243.300049, 1699.170044, 34.872601, -0.06981307, 0, 0, 0.03489945, -0.9993908, 120)) - { - sLog.outErrorDb("BatteGroundRL: Failed to spawn some object!"); - return false; - } - - return true; -} - -/* -Packet S->C, id 600, SMSG_INIT_WORLD_STATES (706), len 86 -0000: 3C 02 00 00 80 0F 00 00 00 00 00 00 09 00 BA 0B | <............... -0010: 00 00 01 00 00 00 B9 0B 00 00 02 00 00 00 B8 0B | ................ -0020: 00 00 00 00 00 00 D8 08 00 00 00 00 00 00 D7 08 | ................ -0030: 00 00 00 00 00 00 D6 08 00 00 00 00 00 00 D5 08 | ................ -0040: 00 00 00 00 00 00 D3 08 00 00 00 00 00 00 D4 08 | ................ -0050: 00 00 00 00 00 00 | ...... -*/ diff --git a/src/server/game/BattleGrounds/BattleGroundRL.h b/src/server/game/BattleGrounds/BattleGroundRL.h deleted file mode 100644 index 3b4c10a7c9a..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundRL.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __BATTLEGROUNDRL_H -#define __BATTLEGROUNDRL_H - -class BattleGround; - -enum BattleGroundRLObjectTypes -{ - BG_RL_OBJECT_DOOR_1 = 0, - BG_RL_OBJECT_DOOR_2 = 1, - BG_RL_OBJECT_BUFF_1 = 2, - BG_RL_OBJECT_BUFF_2 = 3, - BG_RL_OBJECT_MAX = 4 -}; - -enum BattleGroundRLObjects -{ - BG_RL_OBJECT_TYPE_DOOR_1 = 185918, - BG_RL_OBJECT_TYPE_DOOR_2 = 185917, - BG_RL_OBJECT_TYPE_BUFF_1 = 184663, - BG_RL_OBJECT_TYPE_BUFF_2 = 184664 -}; - -class BattleGroundRLScore : public BattleGroundScore -{ - public: - BattleGroundRLScore() {}; - virtual ~BattleGroundRLScore() {}; - //TODO fix me -}; - -class BattleGroundRL : public BattleGround -{ - friend class BattleGroundMgr; - - public: - BattleGroundRL(); - ~BattleGroundRL(); - void Update(uint32 diff); - - /* inherited from BattlegroundClass */ - virtual void AddPlayer(Player *plr); - virtual void Reset(); - virtual void FillInitialWorldStates(WorldPacket &d); - virtual void StartingEventCloseDoors(); - virtual void StartingEventOpenDoors(); - - void RemovePlayer(Player *plr, uint64 guid); - void HandleAreaTrigger(Player *Source, uint32 Trigger); - bool SetupBattleGround(); - void HandleKillPlayer(Player* player, Player *killer); - bool HandlePlayerUnderMap(Player * plr); -}; -#endif diff --git a/src/server/game/BattleGrounds/BattleGroundRV.cpp b/src/server/game/BattleGrounds/BattleGroundRV.cpp deleted file mode 100644 index fcc53dbbcf9..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundRV.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "BattleGround.h" -#include "BattleGroundRV.h" -#include "ObjectAccessor.h" -#include "Language.h" -#include "Player.h" -#include "WorldPacket.h" -#include "GameObject.h" - -BattleGroundRV::BattleGroundRV() -{ - m_BgObjects.resize(BG_RV_OBJECT_MAX); - - m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; - m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; - m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; - m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; - //we must set messageIds - m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; - m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; - m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; -} - -BattleGroundRV::~BattleGroundRV() -{ - -} - -void BattleGroundRV::Update(uint32 diff) -{ - BattleGround::Update(diff); - - if (getTimer() < diff) - { - uint32 i; - switch(getState()) - { - case BG_RV_STATE_OPEN_FENCES: - { - setTimer(BG_RV_PILAR_TO_FIRE_TIMER); - setState(BG_RV_STATE_CLOSE_FIRE); - break; - } - case BG_RV_STATE_CLOSE_FIRE: - for (i = BG_RV_OBJECT_FIRE_1; i <= BG_RV_OBJECT_FIREDOOR_2; ++i) - DoorClose(i); - setTimer(BG_RV_FIRE_TO_PILAR_TIMER); - setState(BG_RV_STATE_OPEN_PILARS); - break; - case BG_RV_STATE_OPEN_PILARS: - for (i = BG_RV_OBJECT_PILAR_1; i <= BG_RV_OBJECT_PULLEY_2; ++i) - DoorOpen(i); - setTimer(BG_RV_PILAR_TO_FIRE_TIMER); - setState(BG_RV_STATE_OPEN_FIRE); - break; - case BG_RV_STATE_OPEN_FIRE: - for (i = BG_RV_OBJECT_FIRE_1; i <= BG_RV_OBJECT_FIREDOOR_2; ++i) - DoorOpen(i); - setTimer(BG_RV_FIRE_TO_PILAR_TIMER); - setState(BG_RV_STATE_CLOSE_PILARS); - break; - case BG_RV_STATE_CLOSE_PILARS: - uint32 i; - for (i = BG_RV_OBJECT_PILAR_1; i <= BG_RV_OBJECT_PULLEY_2; ++i) - DoorOpen(i); - setTimer(BG_RV_PILAR_TO_FIRE_TIMER); - setState(BG_RV_STATE_CLOSE_FIRE); - break; - } - } - else - setTimer(getTimer() - diff); -} - -void BattleGroundRV::StartingEventCloseDoors() -{ -} - -void BattleGroundRV::StartingEventOpenDoors() -{ - // Buff respawn - SpawnBGObject(BG_RV_OBJECT_BUFF_1, 90); - SpawnBGObject(BG_RV_OBJECT_BUFF_2, 90); - // Open fences - DoorOpen(BG_RV_OBJECT_FENCE_1); - DoorOpen(BG_RV_OBJECT_FENCE_2); - // Elevators - DoorOpen(BG_RV_OBJECT_ELEVATOR_1); - DoorOpen(BG_RV_OBJECT_ELEVATOR_2); - - setState(BG_RV_STATE_OPEN_FENCES); - setTimer(BG_RV_FIRST_TIMER); -} - -void BattleGroundRV::AddPlayer(Player *plr) -{ - BattleGround::AddPlayer(plr); - //create score and add it to map, default values are set in constructor - BattleGroundRVScore* sc = new BattleGroundRVScore; - - m_PlayerScores[plr->GetGUID()] = sc; - - UpdateWorldState(BG_RV_WORLD_STATE_A, GetAlivePlayersCountByTeam(ALLIANCE)); - UpdateWorldState(BG_RV_WORLD_STATE_H, GetAlivePlayersCountByTeam(HORDE)); -} - -void BattleGroundRV::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) -{ - if (GetStatus() == STATUS_WAIT_LEAVE) - return; - - UpdateWorldState(BG_RV_WORLD_STATE_A, GetAlivePlayersCountByTeam(ALLIANCE)); - UpdateWorldState(BG_RV_WORLD_STATE_H, GetAlivePlayersCountByTeam(HORDE)); - - CheckArenaWinConditions(); -} - -void BattleGroundRV::HandleKillPlayer(Player *player, Player *killer) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - if (!killer) - { - sLog.outError("BattleGroundRV: Killer player not found"); - return; - } - - BattleGround::HandleKillPlayer(player, killer); - - UpdateWorldState(BG_RV_WORLD_STATE_A, GetAlivePlayersCountByTeam(ALLIANCE)); - UpdateWorldState(BG_RV_WORLD_STATE_H, GetAlivePlayersCountByTeam(HORDE)); - - CheckArenaWinConditions(); -} - -bool BattleGroundRV::HandlePlayerUnderMap(Player *player) -{ - player->TeleportTo(GetMapId(), 763.5, -284, 28.276, 2.422, false); - return true; -} - - -void BattleGroundRV::HandleAreaTrigger(Player *Source, uint32 Trigger) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - switch(Trigger) - { - case 5224: - case 5226: - break; - default: - sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); - Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); - break; - } -} - -void BattleGroundRV::FillInitialWorldStates(WorldPacket &data) -{ - data << uint32(BG_RV_WORLD_STATE_A) << uint32(GetAlivePlayersCountByTeam(ALLIANCE)); - data << uint32(BG_RV_WORLD_STATE_H) << uint32(GetAlivePlayersCountByTeam(HORDE)); - data << uint32(BG_RV_WORLD_STATE) << uint32(1); -} - -void BattleGroundRV::Reset() -{ - //call parent's class reset - BattleGround::Reset(); -} - -bool BattleGroundRV::SetupBattleGround() -{ - // Fence - if (!AddObject(BG_RV_OBJECT_FENCE_1, BG_RV_OBJECT_TYPE_FENCE_1, 763.432373, -274.058197, 28.276695, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RV_OBJECT_FENCE_2, BG_RV_OBJECT_TYPE_FENCE_2, 763.432373, -294.419464, 28.276684, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) - // elevators - || !AddObject(BG_RV_OBJECT_ELEVATOR_1, BG_RV_OBJECT_TYPE_ELEVATOR_1, 763.536377, -294.535767, 0.505383, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RV_OBJECT_ELEVATOR_2, BG_RV_OBJECT_TYPE_ELEVATOR_2, 763.506348, -273.873352, 0.505383, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) - // buffs - || !AddObject(BG_RV_OBJECT_BUFF_1, BG_RV_OBJECT_TYPE_BUFF_1, 735.551819, -284.794678, 28.276682, 0.034906, 0, 0, 0, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RV_OBJECT_BUFF_2, BG_RV_OBJECT_TYPE_BUFF_2, 791.224487, -284.794464, 28.276682, 2.600535, 0, 0, 0, RESPAWN_IMMEDIATELY) - // fire - || !AddObject(BG_RV_OBJECT_FIRE_1, BG_RV_OBJECT_TYPE_FIRE_1, 743.543457, -283.799469, 28.286655, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RV_OBJECT_FIRE_2, BG_RV_OBJECT_TYPE_FIRE_2, 782.971802, -283.799469, 28.286655, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RV_OBJECT_FIREDOOR_1, BG_RV_OBJECT_TYPE_FIREDOOR_1, 743.711060, -284.099609, 27.542587, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RV_OBJECT_FIREDOOR_2, BG_RV_OBJECT_TYPE_FIREDOOR_2, 783.221252, -284.133362, 27.535686, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) - // Gear - || !AddObject(BG_RV_OBJECT_GEAR_1, BG_RV_OBJECT_TYPE_GEAR_1, 763.664551, -261.872986, 26.686588, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RV_OBJECT_GEAR_2, BG_RV_OBJECT_TYPE_GEAR_2, 763.578979, -306.146149, 26.665222, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) - // Pulley - || !AddObject(BG_RV_OBJECT_PULLEY_1, BG_RV_OBJECT_TYPE_PULLEY_1, 700.722290, -283.990662, 39.517582, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RV_OBJECT_PULLEY_2, BG_RV_OBJECT_TYPE_PULLEY_2, 826.303833, -283.996429, 39.517582, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) - // Pilars - || !AddObject(BG_RV_OBJECT_PILAR_1, BG_RV_OBJECT_TYPE_PILAR_1, 763.632385, -306.162384, 25.909504, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RV_OBJECT_PILAR_2, BG_RV_OBJECT_TYPE_PILAR_2, 723.644287, -284.493256, 24.648525, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RV_OBJECT_PILAR_3, BG_RV_OBJECT_TYPE_PILAR_3, 763.611145, -261.856750, 25.909504, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RV_OBJECT_PILAR_4, BG_RV_OBJECT_TYPE_PILAR_4, 802.211609, -284.493256, 24.648525, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) -/* - // Pilars Collision - Fixme: Use the collision pilars - should make u break LoS - || !AddObject(BG_RV_OBJECT_PILAR_COLLISION_1, BG_RV_OBJECT_TYPE_PILAR_COLLISION_1, 763.632385, -306.162384, 30.639660, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RV_OBJECT_PILAR_COLLISION_2, BG_RV_OBJECT_TYPE_PILAR_COLLISION_2, 723.644287, -284.493256, 32.382710, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RV_OBJECT_PILAR_COLLISION_3, BG_RV_OBJECT_TYPE_PILAR_COLLISION_3, 763.611145, -261.856750, 30.639660, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) - || !AddObject(BG_RV_OBJECT_PILAR_COLLISION_4, BG_RV_OBJECT_TYPE_PILAR_COLLISION_4, 802.211609, -284.493256, 32.382710, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) -*/ -) - { - sLog.outErrorDb("BatteGroundRV: Failed to spawn some object!"); - return false; - } - return true; -} diff --git a/src/server/game/BattleGrounds/BattleGroundRV.h b/src/server/game/BattleGrounds/BattleGroundRV.h deleted file mode 100644 index bf06478d364..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundRV.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __BATTLEGROUNDRV_H -#define __BATTLEGROUNDRV_H - -class BattleGround; - -enum BattleGroundRVObjectTypes -{ - BG_RV_OBJECT_BUFF_1, - BG_RV_OBJECT_BUFF_2, - BG_RV_OBJECT_FIRE_1, - BG_RV_OBJECT_FIRE_2, - BG_RV_OBJECT_FIREDOOR_1, - BG_RV_OBJECT_FIREDOOR_2, - - BG_RV_OBJECT_PILAR_1, - BG_RV_OBJECT_PILAR_3, - BG_RV_OBJECT_GEAR_1, - BG_RV_OBJECT_GEAR_2, - - BG_RV_OBJECT_PILAR_2, - BG_RV_OBJECT_PILAR_4, - BG_RV_OBJECT_PULLEY_1, - BG_RV_OBJECT_PULLEY_2, -/* - BG_RV_OBJECT_PILAR_COLLISION_1, - BG_RV_OBJECT_PILAR_COLLISION_2, - BG_RV_OBJECT_PILAR_COLLISION_3, - BG_RV_OBJECT_PILAR_COLLISION_4, -*/ - BG_RV_OBJECT_ELEVATOR_1, - BG_RV_OBJECT_ELEVATOR_2, - BG_RV_OBJECT_FENCE_1, - BG_RV_OBJECT_FENCE_2, - BG_RV_OBJECT_MAX, -}; - -enum BattleGroundRVObjects -{ - BG_RV_OBJECT_TYPE_BUFF_1 = 184663, - BG_RV_OBJECT_TYPE_BUFF_2 = 184664, - BG_RV_OBJECT_TYPE_FIRE_1 = 192704, - BG_RV_OBJECT_TYPE_FIRE_2 = 192705, - - BG_RV_OBJECT_TYPE_FIREDOOR_2 = 192387, - BG_RV_OBJECT_TYPE_FIREDOOR_1 = 192388, - BG_RV_OBJECT_TYPE_PULLEY_1 = 192389, - BG_RV_OBJECT_TYPE_PULLEY_2 = 192390, - BG_RV_OBJECT_TYPE_FENCE_1 = 192391, - BG_RV_OBJECT_TYPE_FENCE_2 = 192392, - BG_RV_OBJECT_TYPE_GEAR_1 = 192393, - BG_RV_OBJECT_TYPE_GEAR_2 = 192394, - BG_RV_OBJECT_TYPE_ELEVATOR_1 = 194582, - BG_RV_OBJECT_TYPE_ELEVATOR_2 = 194586, -/* - BG_RV_OBJECT_TYPE_PILAR_COLLISION_1 = 194580, // axe - BG_RV_OBJECT_TYPE_PILAR_COLLISION_2 = 194579, // arena - BG_RV_OBJECT_TYPE_PILAR_COLLISION_3 = 194581, // lightning - BG_RV_OBJECT_TYPE_PILAR_COLLISION_4 = 194578, // ivory -*/ - BG_RV_OBJECT_TYPE_PILAR_1 = 194583, // axe - BG_RV_OBJECT_TYPE_PILAR_2 = 194584, // arena - BG_RV_OBJECT_TYPE_PILAR_3 = 194585, // lightning - BG_RV_OBJECT_TYPE_PILAR_4 = 194587, // ivory -}; - -enum BattleGroundRVData -{ - BG_RV_STATE_OPEN_FENCES, - BG_RV_STATE_OPEN_PILARS, - BG_RV_STATE_CLOSE_PILARS, - BG_RV_STATE_OPEN_FIRE, - BG_RV_STATE_CLOSE_FIRE, - BG_RV_FIRE_TO_PILAR_TIMER = 20000, - BG_RV_PILAR_TO_FIRE_TIMER = 5000, - BG_RV_FIRST_TIMER = 20133, - BG_RV_WORLD_STATE_A = 0xe10, - BG_RV_WORLD_STATE_H = 0xe11, - BG_RV_WORLD_STATE = 0xe1a, -}; - -class BattleGroundRVScore : public BattleGroundScore -{ - public: - BattleGroundRVScore() {}; - virtual ~BattleGroundRVScore() {}; -}; - -class BattleGroundRV : public BattleGround -{ - friend class BattleGroundMgr; - - public: - BattleGroundRV(); - ~BattleGroundRV(); - void Update(uint32 diff); - - /* inherited from BattlegroundClass */ - virtual void AddPlayer(Player *plr); - virtual void StartingEventCloseDoors(); - virtual void StartingEventOpenDoors(); - virtual void Reset(); - virtual void FillInitialWorldStates(WorldPacket &d); - - void RemovePlayer(Player *plr, uint64 guid); - void HandleAreaTrigger(Player *Source, uint32 Trigger); - bool SetupBattleGround(); - void HandleKillPlayer(Player* player, Player *killer); - bool HandlePlayerUnderMap(Player * plr); - - private: - uint32 Timer; - uint32 State; - - protected: - uint32 getTimer() { return Timer; }; - void setTimer(uint32 timer) { Timer = timer; }; - - uint32 getState() { return State; }; - void setState(uint32 state) { State = state; }; -}; -#endif diff --git a/src/server/game/BattleGrounds/BattleGroundSA.cpp b/src/server/game/BattleGrounds/BattleGroundSA.cpp deleted file mode 100644 index ccde43ce948..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundSA.cpp +++ /dev/null @@ -1,822 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "BattleGround.h" -#include "BattleGroundSA.h" -#include "Language.h" -#include "Player.h" -#include "GameObject.h" -#include "ObjectMgr.h" -#include "WorldPacket.h" - - -BattleGroundSA::BattleGroundSA() -{ - m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_SA_START_TWO_MINUTES; - m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_SA_START_ONE_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_SA_START_HALF_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_SA_HAS_BEGUN; - m_BgObjects.resize(BG_SA_MAXOBJ); - m_BgCreatures.resize(BG_SA_MAXNPC + BG_SA_MAX_GY); - TimerEnabled = false; - UpdateWaitTimer = 0; - SignaledRoundTwo = false; - SignaledRoundTwoHalfMin = false; - InitSecondRound = false; -} - -BattleGroundSA::~BattleGroundSA() -{ -} - -void BattleGroundSA::Reset() -{ - TotalTime = 0; - attackers = ((urand(0,1)) ? TEAM_ALLIANCE : TEAM_HORDE); - for (uint8 i = 0; i <= 5; i++) - GateStatus[i] = BG_SA_GATE_OK; - ShipsStarted = false; - status = BG_SA_WARMUP; -} - -bool BattleGroundSA::SetupBattleGround() -{ - return ResetObjs(); -} - -bool BattleGroundSA::ResetObjs() -{ - uint32 atF = BG_SA_Factions[attackers]; - uint32 defF = BG_SA_Factions[attackers ? TEAM_ALLIANCE : TEAM_HORDE]; - - - for (uint8 i = 0; i SetUInt32Value(GAMEOBJECT_FACTION, defF); - } - - GetBGObject(BG_SA_TITAN_RELIC)->SetUInt32Value(GAMEOBJECT_FACTION, atF); - GetBGObject(BG_SA_TITAN_RELIC)->Refresh(); - - for (uint8 i = 0; i <= 5; i++) - GateStatus[i] = BG_SA_GATE_OK; - - // MAD props for Kiper for discovering those values - 4 hours of his work. - GetBGObject(BG_SA_BOAT_ONE)->UpdateRotationFields(1.0f, 0.0002f); - GetBGObject(BG_SA_BOAT_TWO)->UpdateRotationFields(1.0f, 0.00001f); - SpawnBGObject(BG_SA_BOAT_ONE, RESPAWN_IMMEDIATELY); - SpawnBGObject(BG_SA_BOAT_TWO, RESPAWN_IMMEDIATELY); - - TotalTime = 0; - ShipsStarted = false; - - //Graveyards! - for (uint8 i = 0;i < BG_SA_MAX_GY; i++) - { - WorldSafeLocsEntry const *sg = NULL; - sg = sWorldSafeLocsStore.LookupEntry(BG_SA_GYEntries[i]); - - if (!sg) - { - sLog.outError("SOTA: Can't find GY entry %u",BG_SA_GYEntries[i]); - return false; - } - - if (i == BG_SA_BEACH_GY) - { - GraveyardStatus[i] = attackers; - AddSpiritGuide(i + BG_SA_MAXNPC, sg->x, sg->y, sg->z, BG_SA_GYOrientation[i], ((attackers == TEAM_HORDE)? HORDE : ALLIANCE)); - } - else - { - GraveyardStatus[i] = ((attackers == TEAM_HORDE)? TEAM_ALLIANCE : TEAM_HORDE); - if (!AddSpiritGuide(i + BG_SA_MAXNPC, sg->x, sg->y, sg->z, BG_SA_GYOrientation[i], ((attackers == TEAM_HORDE)? ALLIANCE : HORDE))) - sLog.outError("SOTA: couldn't spawn GY: %u",i); - } - } - - //GY capture points - for (uint8 i = BG_SA_CENTRAL_FLAG; i < BG_SA_MAXOBJ; i++) - { - AddObject(i, BG_SA_ObjEntries[(i + (attackers == TEAM_ALLIANCE ? 3:0))], - BG_SA_ObjSpawnlocs[i][0], BG_SA_ObjSpawnlocs[i][1], - BG_SA_ObjSpawnlocs[i][2], BG_SA_ObjSpawnlocs[i][3], - 0,0,0,0,RESPAWN_ONE_DAY); - GetBGObject(i)->SetUInt32Value(GAMEOBJECT_FACTION, atF); - } - - //Player may enter BEFORE we set up bG - lets update his worldstates anyway... - UpdateWorldState(BG_SA_RIGHT_GY_HORDE , GraveyardStatus[BG_SA_RIGHT_CAPTURABLE_GY] == TEAM_HORDE?1:0); - UpdateWorldState(BG_SA_LEFT_GY_HORDE , GraveyardStatus[BG_SA_LEFT_CAPTURABLE_GY] == TEAM_HORDE?1:0); - UpdateWorldState(BG_SA_CENTER_GY_HORDE , GraveyardStatus[BG_SA_CENTRAL_CAPTURABLE_GY] == TEAM_HORDE?1:0); - - UpdateWorldState(BG_SA_RIGHT_GY_ALLIANCE , GraveyardStatus[BG_SA_RIGHT_CAPTURABLE_GY] == TEAM_ALLIANCE?1:0); - UpdateWorldState(BG_SA_LEFT_GY_ALLIANCE , GraveyardStatus[BG_SA_LEFT_CAPTURABLE_GY] == TEAM_ALLIANCE?1:0); - UpdateWorldState(BG_SA_CENTER_GY_ALLIANCE , GraveyardStatus[BG_SA_CENTRAL_CAPTURABLE_GY] == TEAM_ALLIANCE?1:0); - - if (attackers == TEAM_ALLIANCE) - { - UpdateWorldState(BG_SA_ALLY_ATTACKS, 1); - UpdateWorldState(BG_SA_HORDE_ATTACKS, 0); - - UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_ALL, 1); - UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_ALL, 1); - UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_HRD, 0); - UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_HRD, 0); - - UpdateWorldState(BG_SA_HORDE_DEFENCE_TOKEN,1); - UpdateWorldState(BG_SA_ALLIANCE_DEFENCE_TOKEN,0); - } - else - { - UpdateWorldState(BG_SA_HORDE_ATTACKS, 1); - UpdateWorldState(BG_SA_ALLY_ATTACKS, 0); - - UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_ALL, 0); - UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_ALL, 0); - UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_HRD, 1); - UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_HRD, 1); - - UpdateWorldState(BG_SA_HORDE_DEFENCE_TOKEN,0); - UpdateWorldState(BG_SA_ALLIANCE_DEFENCE_TOKEN,1); - } - - UpdateWorldState(BG_SA_PURPLE_GATEWS, 1); - UpdateWorldState(BG_SA_RED_GATEWS, 1); - UpdateWorldState(BG_SA_BLUE_GATEWS, 1); - UpdateWorldState(BG_SA_GREEN_GATEWS, 1); - UpdateWorldState(BG_SA_YELLOW_GATEWS, 1); - UpdateWorldState(BG_SA_ANCIENT_GATEWS, 1); - - TeleportPlayers(); - return true; -} - -void BattleGroundSA::StartShips() -{ - if (ShipsStarted) - return; - - DoorOpen(BG_SA_BOAT_ONE); - DoorOpen(BG_SA_BOAT_TWO); - - for (int i = BG_SA_BOAT_ONE; i <= BG_SA_BOAT_TWO; i++) - { - for (BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end();itr++) - { - if (Player* p = objmgr.GetPlayer(itr->first)) - { - if (p->GetTeamId() != attackers) - continue; - - UpdateData data; - WorldPacket pkt; - GetBGObject(i)->BuildValuesUpdateBlockForPlayer(&data, p); - data.BuildPacket(&pkt); - p->GetSession()->SendPacket(&pkt); - } - } - } - ShipsStarted = true; -} - -void BattleGroundSA::Update(uint32 diff) -{ - if (InitSecondRound) - { - if (UpdateWaitTimer < diff) - { - if (!SignaledRoundTwo) - { - SignaledRoundTwo = true; - InitSecondRound = false; - SendMessageToAll(LANG_BG_SA_ROUND_TWO_ONE_MINUTE, CHAT_MSG_BG_SYSTEM_NEUTRAL); - } - }else - { - UpdateWaitTimer -= diff; - return; - } - } - BattleGround::Update(diff); - TotalTime += diff; - - if (status == BG_SA_WARMUP ) - { - BG_SA_ENDROUNDTIME = BG_SA_ROUNDLENGTH; - if (TotalTime >= BG_SA_WARMUPLENGTH) - { - TotalTime = 0; - ToggleTimer(); - DemolisherStartState(false); - status = BG_SA_ROUND_ONE; - } - if (TotalTime >= BG_SA_BOAT_START) - StartShips(); - return; - } - else if (status == BG_SA_SECOND_WARMUP) - { - if (RoundScores[0].time= 60000) - { - SendWarningToAll(LANG_BG_SA_HAS_BEGUN); - TotalTime = 0; - ToggleTimer(); - DemolisherStartState(false); - status = BG_SA_ROUND_TWO; - } - if (TotalTime >= 30000) - { - if (!SignaledRoundTwoHalfMin) - { - SignaledRoundTwoHalfMin = true; - SendMessageToAll(LANG_BG_SA_ROUND_TWO_START_HALF_MINUTE, CHAT_MSG_BG_SYSTEM_NEUTRAL); - } - } - StartShips(); - return; - } - else if (GetStatus() == STATUS_IN_PROGRESS) - { - if (status == BG_SA_ROUND_ONE) - { - if (TotalTime >= BG_SA_ROUNDLENGTH) - { - RoundScores[0].winner = attackers; - RoundScores[0].time = BG_SA_ROUNDLENGTH; - TotalTime = 0; - status = BG_SA_SECOND_WARMUP; - attackers = (attackers == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE; - status = BG_SA_SECOND_WARMUP; - ToggleTimer(); - ResetObjs(); - return; - } - } - else if (status == BG_SA_ROUND_TWO) - { - if (TotalTime >= BG_SA_ENDROUNDTIME) - { - RoundScores[1].time = BG_SA_ROUNDLENGTH; - RoundScores[1].winner = (attackers == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE; - - if (RoundScores[0].time == RoundScores[1].time) - EndBattleGround(NULL); - else if (RoundScores[0].time < RoundScores[1].time) - EndBattleGround(RoundScores[0].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE); - else - EndBattleGround(RoundScores[1].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE); - return; - } - } - if (status == BG_SA_ROUND_ONE || status == BG_SA_ROUND_TWO) - { - SendTime(); - UpdateDemolisherSpawns(); - } - } -} - -void BattleGroundSA::StartingEventCloseDoors() -{ -} - -void BattleGroundSA::StartingEventOpenDoors() -{ -} - -void BattleGroundSA::FillInitialWorldStates(WorldPacket& data) -{ - uint32 ally_attacks = uint32(attackers == TEAM_ALLIANCE ? 1 : 0); - uint32 horde_attacks = uint32(attackers == TEAM_HORDE ? 1 : 0); - - data << uint32(BG_SA_ANCIENT_GATEWS) << uint32(GateStatus[BG_SA_ANCIENT_GATE]); - data << uint32(BG_SA_YELLOW_GATEWS) << uint32(GateStatus[BG_SA_YELLOW_GATE]); - data << uint32(BG_SA_GREEN_GATEWS) << uint32(GateStatus[BG_SA_GREEN_GATE]); - data << uint32(BG_SA_BLUE_GATEWS) << uint32(GateStatus[BG_SA_BLUE_GATE]); - data << uint32(BG_SA_RED_GATEWS) << uint32(GateStatus[BG_SA_RED_GATE]); - data << uint32(BG_SA_PURPLE_GATEWS) << uint32(GateStatus[BG_SA_PURPLE_GATE]); - - data << uint32(BG_SA_BONUS_TIMER) << uint32(0); - - data << uint32(BG_SA_HORDE_ATTACKS)<< horde_attacks; - data << uint32(BG_SA_ALLY_ATTACKS) << ally_attacks; - - //Time will be sent on first update... - data << uint32(BG_SA_ENABLE_TIMER) << ((TimerEnabled) ? uint32(1) : uint32(0)); - data << uint32(BG_SA_TIMER_MINS) << uint32(0); - data << uint32(BG_SA_TIMER_SEC_TENS) << uint32(0); - data << uint32(BG_SA_TIMER_SEC_DECS) << uint32(0); - - data << uint32(BG_SA_RIGHT_GY_HORDE) << uint32(GraveyardStatus[BG_SA_RIGHT_CAPTURABLE_GY] == TEAM_HORDE?1:0); - data << uint32(BG_SA_LEFT_GY_HORDE) << uint32(GraveyardStatus[BG_SA_LEFT_CAPTURABLE_GY] == TEAM_HORDE?1:0); - data << uint32(BG_SA_CENTER_GY_HORDE) << uint32(GraveyardStatus[BG_SA_CENTRAL_CAPTURABLE_GY] == TEAM_HORDE?1:0); - - data << uint32(BG_SA_RIGHT_GY_ALLIANCE) << uint32(GraveyardStatus[BG_SA_RIGHT_CAPTURABLE_GY] == TEAM_ALLIANCE?1:0); - data << uint32(BG_SA_LEFT_GY_ALLIANCE) << uint32(GraveyardStatus[BG_SA_LEFT_CAPTURABLE_GY] == TEAM_ALLIANCE?1:0); - data << uint32(BG_SA_CENTER_GY_ALLIANCE) << uint32(GraveyardStatus[BG_SA_CENTRAL_CAPTURABLE_GY] == TEAM_ALLIANCE?1:0); - - data << uint32(BG_SA_HORDE_DEFENCE_TOKEN) << ally_attacks; - data << uint32(BG_SA_ALLIANCE_DEFENCE_TOKEN) << horde_attacks; - - data << uint32(BG_SA_LEFT_ATT_TOKEN_HRD) << horde_attacks; - data << uint32(BG_SA_RIGHT_ATT_TOKEN_HRD) << horde_attacks; - data << uint32(BG_SA_RIGHT_ATT_TOKEN_ALL) << ally_attacks; - data << uint32(BG_SA_LEFT_ATT_TOKEN_ALL) << ally_attacks; -} - -void BattleGroundSA::AddPlayer(Player *plr) -{ - BattleGround::AddPlayer(plr); - //create score and add it to map, default values are set in constructor - BattleGroundSAScore* sc = new BattleGroundSAScore; - - if (!ShipsStarted) - { - if (plr->GetTeamId() == attackers) - { - plr->CastSpell(plr,12438,true);//Without this player falls before boat loads... - - if (urand(0,1)) - plr->TeleportTo(607, 2682.936f, -830.368f, 50.0f, 2.895f, 0); - else - plr->TeleportTo(607, 2577.003f, 980.261f, 50.0f, 0.807f, 0); - - } - else - plr->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0); - } - else - { - if (plr->GetTeamId() == attackers) - plr->TeleportTo(607, 1600.381f, -106.263f, 8.8745f, 3.78f, 0); - else - plr->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0); - } - - m_PlayerScores[plr->GetGUID()] = sc; -} - -void BattleGroundSA::RemovePlayer(Player* /*plr*/,uint64 /*guid*/) -{ -} - -void BattleGroundSA::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/) -{ - // this is wrong way to implement these things. On official it done by gameobject spell cast. - if (GetStatus() != STATUS_IN_PROGRESS) - return; -} - -void BattleGroundSA::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) -{ - BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); - if (itr == m_PlayerScores.end()) // player not found... - return; - - if (type == SCORE_DESTROYED_DEMOLISHER) - ((BattleGroundSAScore*)itr->second)->demolishers_destroyed += value; - else if (type == SCORE_DESTROYED_WALL) - ((BattleGroundSAScore*)itr->second)->gates_destroyed += value; - else - BattleGround::UpdatePlayerScore(Source,type,value, doAddHonor); -} - -void BattleGroundSA::TeleportPlayers() -{ - for (BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - { - if (Player *plr = objmgr.GetPlayer(itr->first)) - { - // should remove spirit of redemption - if (plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) - plr->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); - - if (!plr->isAlive()) - { - plr->ResurrectPlayer(1.0f); - plr->SpawnCorpseBones(); - } - - plr->SetHealth(plr->GetMaxHealth()); - plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA)); - plr->CombatStopWithPets(true); - - if (plr->GetTeamId() == attackers) - { - plr->CastSpell(plr,12438,true); //Without this player falls before boat loads... - - if (urand(0,1)) - plr->TeleportTo(607, 2682.936f, -830.368f, 50.0f, 2.895f, 0); - else - plr->TeleportTo(607, 2577.003f, 980.261f, 50.0f, 0.807f, 0); - } - else - plr->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0); - } - } -} - -void BattleGroundSA::EventPlayerDamagedGO(Player* plr, GameObject* go, uint8 hitType, uint32 destroyedEvent) -{ - if (!go || !go->GetGOInfo()) - return; - - switch(hitType) - { - case BG_OBJECT_DMG_HIT_TYPE_JUST_DAMAGED://under attack - SendWarningToAll(LANG_BG_SA_IS_UNDER_ATTACK, go->GetGOInfo()->name); - break; - case BG_OBJECT_DMG_HIT_TYPE_DAMAGED: - break; - case BG_OBJECT_DMG_HIT_TYPE_JUST_HIGH_DAMAGED: - { - uint32 i = GetGateIDFromDestroyEventID(destroyedEvent); - GateStatus[i] = BG_SA_GATE_DAMAGED; - uint32 uws = GetWorldStateFromGateID(i); - if (uws) - UpdateWorldState(uws, GateStatus[i]); - break; - } - case BG_OBJECT_DMG_HIT_TYPE_HIGH_DAMAGED: - break; - case BG_OBJECT_DMG_HIT_TYPE_JUST_DESTROYED://handled at DestroyGate() - if (destroyedEvent == 19837) - SendWarningToAll(LANG_BG_SA_CHAMBER_BREACHED); - else - SendWarningToAll(LANG_BG_SA_WAS_DESTROYED, go->GetGOInfo()->name); - break; - } -} - -void BattleGroundSA::HandleKillUnit(Creature* unit, Player* killer) -{ - if (!unit) - return; - - if (unit->GetEntry() == 28781) //Demolisher - UpdatePlayerScore(killer, SCORE_DESTROYED_DEMOLISHER, 1); -} - -/* - You may ask what the fuck does it do? - Prevents owner overwriting guns faction with own. - */ -void BattleGroundSA::OverrideGunFaction() -{ - if (!m_BgCreatures[0]) - return; - - for (uint8 i = BG_SA_GUN_1; i <= BG_SA_GUN_10;i++) - { - if (Creature* gun = GetBGCreature(i)) - gun->setFaction(BG_SA_Factions[attackers? TEAM_ALLIANCE : TEAM_HORDE]); - } - - for (uint8 i = BG_SA_DEMOLISHER_1; i <= BG_SA_DEMOLISHER_4;i++) - { - if (Creature* dem = GetBGCreature(i)) - dem->setFaction(BG_SA_Factions[attackers]); - } -} - -void BattleGroundSA::DemolisherStartState(bool start) -{ - if (!m_BgCreatures[0]) - return; - - for (uint8 i = BG_SA_DEMOLISHER_1; i <= BG_SA_DEMOLISHER_4; i++) - { - if (Creature* dem = GetBGCreature(i)) - { - if (start) - dem->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - else - dem->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - } - } -} - -void BattleGroundSA::DestroyGate(Player* pl, GameObject* /*go*/, uint32 destroyedEvent) -{ - uint32 i = GetGateIDFromDestroyEventID(destroyedEvent); - if (!GateStatus[i]) - return; - - if (GameObject* g = GetBGObject(i)) - { - if (g->GetGOValue()->building.health == 0) - { - GateStatus[i] = BG_SA_GATE_DESTROYED; - uint32 uws = GetWorldStateFromGateID(i); - if (uws) - UpdateWorldState(uws, GateStatus[i]); - bool rewardHonor = true; - switch(i) - { - case BG_SA_GREEN_GATE: - if (GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED) - rewardHonor = false; - break; - case BG_SA_BLUE_GATE: - if (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED) - rewardHonor = false; - break; - case BG_SA_RED_GATE: - if (GateStatus[BG_SA_PURPLE_GATE] == BG_SA_GATE_DESTROYED) - rewardHonor = false; - break; - case BG_SA_PURPLE_GATE: - if (GateStatus[BG_SA_RED_GATE] == BG_SA_GATE_DESTROYED) - rewardHonor = false; - break; - } - - if (i < 5) - DelObject(i+9); - UpdatePlayerScore(pl,SCORE_DESTROYED_WALL, 1); - if (rewardHonor) - UpdatePlayerScore(pl,SCORE_BONUS_HONOR,(GetBonusHonorFromKill(1))); - } - } -} - -WorldSafeLocsEntry const* BattleGroundSA::GetClosestGraveYard(Player* player) -{ - uint32 safeloc = 0; - WorldSafeLocsEntry const* ret; - WorldSafeLocsEntry const* closest; - float dist, nearest; - float x,y,z; - - player->GetPosition(x,y,z); - - if (player->GetTeamId() == attackers) - safeloc = BG_SA_GYEntries[BG_SA_BEACH_GY]; - else - safeloc = BG_SA_GYEntries[BG_SA_DEFENDER_LAST_GY]; - - closest = sWorldSafeLocsStore.LookupEntry(safeloc); - nearest = sqrt((closest->x - x)*(closest->x - x) + (closest->y - y)*(closest->y - y)+(closest->z - z)*(closest->z - z)); - - for (uint8 i = BG_SA_RIGHT_CAPTURABLE_GY; i < BG_SA_MAX_GY; i++) - { - if (GraveyardStatus[i] != player->GetTeamId()) - continue; - - ret = sWorldSafeLocsStore.LookupEntry(BG_SA_GYEntries[i]); - dist = sqrt((ret->x - x)*(ret->x - x) + (ret->y - y)*(ret->y - y)+(ret->z - z)*(ret->z - z)); - if (dist < nearest) - { - closest = ret; - nearest = dist; - } - } - - return closest; -} - -void BattleGroundSA::SendTime() -{ - uint32 end_of_round = (BG_SA_ENDROUNDTIME - TotalTime); - UpdateWorldState(BG_SA_TIMER_MINS, end_of_round/60000); - UpdateWorldState(BG_SA_TIMER_SEC_TENS, (end_of_round%60000)/10000); - UpdateWorldState(BG_SA_TIMER_SEC_DECS, ((end_of_round%60000)%10000)/1000); -} - -void BattleGroundSA::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj) -{ - switch(target_obj->GetEntry()) - { - case 191307: - case 191308: - if (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED) - CaptureGraveyard(BG_SA_LEFT_CAPTURABLE_GY, Source); - break; - case 191305: - case 191306: - if (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED) - CaptureGraveyard(BG_SA_RIGHT_CAPTURABLE_GY, Source); - break; - case 191310: - case 191309: - if ((GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED) && (GateStatus[BG_SA_RED_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_PURPLE_GATE] == BG_SA_GATE_DESTROYED)) - CaptureGraveyard(BG_SA_CENTRAL_CAPTURABLE_GY, Source); - break; - default: - return; - }; -} - -void BattleGroundSA::CaptureGraveyard(BG_SA_Graveyards i, Player *Source) -{ - DelCreature(BG_SA_MAXNPC + i); - GraveyardStatus[i] = Source->GetTeamId(); - WorldSafeLocsEntry const *sg = NULL; - sg = sWorldSafeLocsStore.LookupEntry(BG_SA_GYEntries[i]); - AddSpiritGuide(i + BG_SA_MAXNPC, sg->x, sg->y, sg->z, BG_SA_GYOrientation[i], (GraveyardStatus[i] == TEAM_ALLIANCE? ALLIANCE : HORDE)); - uint32 npc = 0; - uint32 flag = 0; - - switch(i) - { - case BG_SA_LEFT_CAPTURABLE_GY: - flag = BG_SA_LEFT_FLAG; - DelObject(flag); - AddObject(flag,BG_SA_ObjEntries[(flag + (Source->GetTeamId() == TEAM_ALLIANCE ? 0:3))], - BG_SA_ObjSpawnlocs[flag][0],BG_SA_ObjSpawnlocs[flag][1], - BG_SA_ObjSpawnlocs[flag][2],BG_SA_ObjSpawnlocs[flag][3],0,0,0,0,RESPAWN_ONE_DAY); - - npc = BG_SA_NPC_RIGSPARK; - AddCreature(BG_SA_NpcEntries[npc], npc, attackers, - BG_SA_NpcSpawnlocs[npc][0], BG_SA_NpcSpawnlocs[npc][1], - BG_SA_NpcSpawnlocs[npc][2], BG_SA_NpcSpawnlocs[npc][3]); - - UpdateWorldState(BG_SA_LEFT_GY_ALLIANCE, (GraveyardStatus[i] == TEAM_ALLIANCE? 1:0)); - UpdateWorldState(BG_SA_LEFT_GY_HORDE, (GraveyardStatus[i] == TEAM_ALLIANCE? 0:1)); - if (Source->GetTeamId() == TEAM_ALLIANCE) - SendWarningToAll(LANG_BG_SA_A_GY_WEST); - else - SendWarningToAll(LANG_BG_SA_H_GY_WEST); - break; - case BG_SA_RIGHT_CAPTURABLE_GY: - flag = BG_SA_RIGHT_FLAG; - DelObject(flag); - AddObject(flag,BG_SA_ObjEntries[(flag + (Source->GetTeamId() == TEAM_ALLIANCE ? 0:3))], - BG_SA_ObjSpawnlocs[flag][0],BG_SA_ObjSpawnlocs[flag][1], - BG_SA_ObjSpawnlocs[flag][2],BG_SA_ObjSpawnlocs[flag][3],0,0,0,0,RESPAWN_ONE_DAY); - - npc = BG_SA_NPC_SPARKLIGHT; - AddCreature(BG_SA_NpcEntries[npc], npc, attackers, - BG_SA_NpcSpawnlocs[npc][0], BG_SA_NpcSpawnlocs[npc][1], - BG_SA_NpcSpawnlocs[npc][2], BG_SA_NpcSpawnlocs[npc][3]); - - UpdateWorldState(BG_SA_RIGHT_GY_ALLIANCE, (GraveyardStatus[i] == TEAM_ALLIANCE? 1:0)); - UpdateWorldState(BG_SA_RIGHT_GY_HORDE, (GraveyardStatus[i] == TEAM_ALLIANCE? 0:1)); - if (Source->GetTeamId() == TEAM_ALLIANCE) - SendWarningToAll(LANG_BG_SA_A_GY_EAST); - else - SendWarningToAll(LANG_BG_SA_H_GY_EAST); - break; - case BG_SA_CENTRAL_CAPTURABLE_GY: - flag = BG_SA_CENTRAL_FLAG; - DelObject(flag); - AddObject(flag,BG_SA_ObjEntries[(flag + (Source->GetTeamId() == TEAM_ALLIANCE ? 0:3))], - BG_SA_ObjSpawnlocs[flag][0],BG_SA_ObjSpawnlocs[flag][1], - BG_SA_ObjSpawnlocs[flag][2],BG_SA_ObjSpawnlocs[flag][3],0,0,0,0,RESPAWN_ONE_DAY); - - UpdateWorldState(BG_SA_CENTER_GY_ALLIANCE, (GraveyardStatus[i] == TEAM_ALLIANCE? 1:0)); - UpdateWorldState(BG_SA_CENTER_GY_HORDE, (GraveyardStatus[i] == TEAM_ALLIANCE? 0:1)); - if (Source->GetTeamId() == TEAM_ALLIANCE) - SendWarningToAll(LANG_BG_SA_A_GY_SOUTH); - else - SendWarningToAll(LANG_BG_SA_H_GY_SOUTH); - break; - default: - ASSERT(0); - break; - }; -} - -void BattleGroundSA::EventPlayerUsedGO(Player* Source, GameObject* object) -{ - if (object->GetEntry() == BG_SA_ObjEntries[BG_SA_TITAN_RELIC] && GateStatus[BG_SA_ANCIENT_GATE] == BG_SA_GATE_DESTROYED) - { - if (Source->GetTeamId() == attackers) - { - if (Source->GetTeamId() == ALLIANCE) - SendMessageToAll(LANG_BG_SA_ALLIANCE_CAPTURED_RELIC, CHAT_MSG_BG_SYSTEM_NEUTRAL); - else SendMessageToAll(LANG_BG_SA_HORDE_CAPTURED_RELIC, CHAT_MSG_BG_SYSTEM_NEUTRAL); - - if (status == BG_SA_ROUND_ONE) - { - RoundScores[0].winner = attackers; - RoundScores[0].time = TotalTime; - attackers = (attackers == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE; - status = BG_SA_SECOND_WARMUP; - TotalTime = 0; - ToggleTimer(); - SendWarningToAll(LANG_BG_SA_ROUND_ONE_END); - UpdateWaitTimer = 5000; - SignaledRoundTwo = false; - SignaledRoundTwoHalfMin = false; - InitSecondRound = true; - ResetObjs(); - } - else if (status == BG_SA_ROUND_TWO) - { - RoundScores[1].winner = attackers; - RoundScores[1].time = TotalTime;ToggleTimer(); - if (RoundScores[0].time == RoundScores[1].time) - EndBattleGround(NULL); - else if (RoundScores[0].time < RoundScores[1].time) - EndBattleGround(RoundScores[0].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE); - else - EndBattleGround(RoundScores[1].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE); - } - } - } -} - -void BattleGroundSA::ToggleTimer() -{ - TimerEnabled = !TimerEnabled; - UpdateWorldState(BG_SA_ENABLE_TIMER, (TimerEnabled) ? 1 : 0); -} - -void BattleGroundSA::EndBattleGround(uint32 winner) -{ - //honor reward for winning - if (winner == ALLIANCE) - RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); - else if (winner == HORDE) - RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); - - //complete map_end rewards (even if no team wins) - RewardHonorToTeam(GetBonusHonorFromKill(2), ALLIANCE); - RewardHonorToTeam(GetBonusHonorFromKill(2), HORDE); - - BattleGround::EndBattleGround(winner); -} - -void BattleGroundSA::UpdateDemolisherSpawns() -{ - for (uint8 i = BG_SA_DEMOLISHER_1; i <= BG_SA_DEMOLISHER_4; i++) - { - if (m_BgCreatures[i]) - { - if (Creature *Demolisher = GetBGCreature(i)) - { - if (Demolisher->isDead()) - { - uint8 gy = (i >= BG_SA_DEMOLISHER_3 ? 3 : 2); - if (GraveyardStatus[gy] == attackers) - Demolisher->Relocate(BG_SA_NpcSpawnlocs[i + 6][0], BG_SA_NpcSpawnlocs[i + 6][1], - BG_SA_NpcSpawnlocs[i + 6][2], BG_SA_NpcSpawnlocs[i + 6][3]); - else - Demolisher->Relocate(BG_SA_NpcSpawnlocs[i][0], BG_SA_NpcSpawnlocs[i][1], - BG_SA_NpcSpawnlocs[i][2], BG_SA_NpcSpawnlocs[i][3]); - - Demolisher->Respawn(); - } - } - } - } -} - - diff --git a/src/server/game/BattleGrounds/BattleGroundSA.h b/src/server/game/BattleGrounds/BattleGroundSA.h deleted file mode 100644 index 760be3ca02e..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundSA.h +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __BATTLEGROUNDSA_H -#define __BATTLEGROUNDSA_H - -class BattleGround; - -class BattleGroundSAScore : public BattleGroundScore -{ - public: - BattleGroundSAScore(): demolishers_destroyed(0), gates_destroyed(0) {}; - virtual ~BattleGroundSAScore() {}; - uint8 demolishers_destroyed; - uint8 gates_destroyed; -}; - -#define BG_SA_FLAG_AMOUNT 3 -#define BG_SA_DEMOLISHER_AMOUNT 4 - -enum BG_SA_Status - { - BG_SA_NOTSTARTED = 0, - BG_SA_WARMUP, - BG_SA_ROUND_ONE, - BG_SA_SECOND_WARMUP, - BG_SA_ROUND_TWO, - BG_SA_BONUS_ROUND - }; - -enum BG_SA_GateState - { - BG_SA_GATE_OK = 1, - BG_SA_GATE_DAMAGED = 2, - BG_SA_GATE_DESTROYED = 3 - }; - -enum BG_SA_Timers - { - BG_SA_BOAT_START = 60000, - BG_SA_WARMUPLENGTH = 120000, - BG_SA_ROUNDLENGTH = 600000 - }; - -enum BG_SA_WorldStates - { - BG_SA_TIMER_MINS = 3559, - BG_SA_TIMER_SEC_TENS = 3560, - BG_SA_TIMER_SEC_DECS = 3561, - BG_SA_ALLY_ATTACKS = 4352, - BG_SA_HORDE_ATTACKS = 4353, - - BG_SA_PURPLE_GATEWS = 3614, - BG_SA_RED_GATEWS = 3617, - BG_SA_BLUE_GATEWS = 3620, - BG_SA_GREEN_GATEWS = 3623, - BG_SA_YELLOW_GATEWS = 3638, - BG_SA_ANCIENT_GATEWS = 3849, - - - BG_SA_LEFT_GY_ALLIANCE = 3635, - BG_SA_RIGHT_GY_ALLIANCE = 3636, - BG_SA_CENTER_GY_ALLIANCE = 3637, - - BG_SA_RIGHT_ATT_TOKEN_ALL = 3627, - BG_SA_LEFT_ATT_TOKEN_ALL = 3626, - - BG_SA_LEFT_ATT_TOKEN_HRD = 3629, - BG_SA_RIGHT_ATT_TOKEN_HRD = 3628, - - BG_SA_HORDE_DEFENCE_TOKEN = 3631, - BG_SA_ALLIANCE_DEFENCE_TOKEN = 3630, - - BG_SA_RIGHT_GY_HORDE = 3632, - BG_SA_LEFT_GY_HORDE = 3633, - BG_SA_CENTER_GY_HORDE = 3634, - - BG_SA_BONUS_TIMER = 0xdf3, - BG_SA_ENABLE_TIMER = 3564, - }; - -enum BG_SA_NPCs - { - BG_SA_GUN_1 = 0, - BG_SA_GUN_2, - BG_SA_GUN_3, - BG_SA_GUN_4, - BG_SA_GUN_5, - BG_SA_GUN_6, - BG_SA_GUN_7, - BG_SA_GUN_8, - BG_SA_GUN_9, - BG_SA_GUN_10, - BG_SA_DEMOLISHER_1, - BG_SA_DEMOLISHER_2, - BG_SA_DEMOLISHER_3, - BG_SA_DEMOLISHER_4, - BG_SA_NPC_SPARKLIGHT, - BG_SA_NPC_RIGSPARK, - BG_SA_MAXNPC - }; - -const uint32 BG_SA_NpcEntries[BG_SA_MAXNPC] = - { - 27894, - 27894, - 27894, - 27894, - 27894, - 27894, - 27894, - 27894, - 27894, - 27894, - //4 beach demolishers - 28781, - 28781, - 28781, - 28781, - //Fizzle Sparklight, or whatever his name was - 29260, - 29262, - }; - -const float BG_SA_NpcSpawnlocs[BG_SA_MAXNPC + BG_SA_DEMOLISHER_AMOUNT][4] = - { - //Cannons - { 1436.429f, 110.05f, 41.407f, 5.4f }, - { 1404.9023f, 84.758f, 41.183f, 5.46f }, - { 1068.693f, -86.951f, 93.81f, 0.02f }, - { 1068.83f, -127.56f, 96.45f, 0.0912f }, - { 1422.115f, -196.433f, 42.1825f, 1.0222f }, - { 1454.887f, -220.454f, 41.956f, 0.9627f }, - { 1232.345f, -187.517f, 66.945f, 0.45f }, - { 1249.634f, -224.189f, 66.72f, 0.635f }, - { 1236.213f, 92.287f, 64.965f, 5.751f }, - { 1215.11f, 57.772f, 64.739f, 5.78f } , - //Demolishers - { 1611.597656,-117.270073,8.719355,2.513274}, - { 1575.562500,-158.421875,5.024450,2.129302}, - { 1618.047729,61.424641,7.248210,3.979351}, - { 1575.103149,98.873344,2.830360,3.752458}, - //Npcs - { 1348.644165, -298.786469, 31.080130, 1.710423}, - { 1358.191040, 195.527786, 31.018187, 4.171337}, - //Demolishers2 - { 1371.055786, -317.071136, 35.007359, 1.947460}, - { 1424.034912, -260.195190, 31.084425, 2.820013}, - { 1353.139893, 223.745438, 35.265411, 4.343684}, - { 1404.809570, 197.027237, 32.046032, 3.605401}, - }; - -enum BG_SA_Objects - { - BG_SA_GREEN_GATE = 0, - BG_SA_YELLOW_GATE, - BG_SA_BLUE_GATE, - BG_SA_RED_GATE, - BG_SA_PURPLE_GATE, - BG_SA_ANCIENT_GATE, - BG_SA_TITAN_RELIC, - BG_SA_BOAT_ONE, - BG_SA_BOAT_TWO, - BG_SA_SIGIL_1, - BG_SA_SIGIL_2, - BG_SA_SIGIL_3, - BG_SA_SIGIL_4, - BG_SA_SIGIL_5, - BG_SA_CENTRAL_FLAGPOLE, - BG_SA_RIGHT_FLAGPOLE, - BG_SA_LEFT_FLAGPOLE, - BG_SA_CENTRAL_FLAG, - BG_SA_RIGHT_FLAG, - BG_SA_LEFT_FLAG, - BG_SA_MAXOBJ - }; - -const float BG_SA_ObjSpawnlocs[BG_SA_MAXOBJ][4] = - { - { 1411.57f, 108.163f, 28.692f, 5.441f }, - { 1055.452f, -108.1f, 82.134f, 0.034f }, - { 1431.3413f, -219.437f, 30.893f, 0.9736f }, - { 1227.667f, -212.555f, 55.372f, 0.5023f }, - { 1214.681f, 81.21f, 53.413f, 5.745f }, - { 878.555f, -108.989f, 119.835f, 0.0565f }, - { 836.5f, -108.8f, 120.219f, 0.0f }, - //Ships - { 2679.696777, -826.891235, 3.712860, 5.78367f}, //rot2 1 rot3 0.0002 - { 2574.003662, 981.261475, 2.603424, 0.807696}, - //Sigils - { 1414.054f, 106.72f, 41.442f, 5.441f }, - { 1060.63f, -107.8f, 94.7f, 0.034f }, - { 1433.383f, -216.4f, 43.642f, 0.9736f }, - { 1230.75f, -210.724f, 67.611f, 0.5023f }, - { 1217.8f, 79.532f, 66.58f, 5.745f }, - //Flagpoles - { 1215.114258,-65.711861,70.084267,-3.124123}, - {1338.863892,-153.336533,30.895121,-2.530723}, - {1309.124268,9.410645,30.893402,-1.623156}, - //Flags - { 1215.108032,-65.715767,70.084267,-3.124123}, - { 1338.859253,-153.327316,30.895077,-2.530723}, - { 1309.192017,9.416233,30.893402,1.518436}, - }; - -/* Ships: - * 193182 - ally - * 193183 - horde - * 193184 - horde - * 193185 - ally - * Banners: - * 191308 - left one, - * 191306 - right one, - * 191310 - central, - * Ally ones, substract 1 - * to get horde ones. - */ - -const uint32 BG_SA_ObjEntries[BG_SA_MAXOBJ + BG_SA_FLAG_AMOUNT] = - { - 190722, - 190727, - 190724, - 190726, - 190723, - 192549, - 192834, - 193182, - 193185, - 192687, - 192685, - 192689, - 192690, - 192691, - 191311, - 191311, - 191311, - 191310, - 191306, - 191308, - 191309, - 191305, - 191307, - }; - -const uint32 BG_SA_Factions[2] = - { - 1732, - 1735, - }; - -enum BG_SA_Graveyards - { - BG_SA_BEACH_GY = 0, - BG_SA_DEFENDER_LAST_GY, - BG_SA_RIGHT_CAPTURABLE_GY, - BG_SA_LEFT_CAPTURABLE_GY, - BG_SA_CENTRAL_CAPTURABLE_GY, - BG_SA_MAX_GY - }; - -const uint32 BG_SA_GYEntries[BG_SA_MAX_GY] = - { - 1350, - 1349, - 1347, - 1346, - 1348, - }; - -const float BG_SA_GYOrientation[BG_SA_MAX_GY] = - { - 6.202f, - 1.926f, //right capturable GY - 3.917f, //left capturable GY - 3.104f, //center, capturable - 6.148f, //defender last GY - }; - -struct BG_SA_RoundScore -{ - TeamId winner; - uint32 time; -}; - -class BattleGroundSA : public BattleGround -{ - friend class BattleGroundMgr; - - public: - BattleGroundSA(); - ~BattleGroundSA(); - void Update(uint32 diff); - - /* inherited from BattlegroundClass */ - virtual void AddPlayer(Player *plr); - virtual void StartingEventCloseDoors(); - virtual void StartingEventOpenDoors(); - virtual bool SetupBattleGround(); - virtual void Reset(); - virtual void FillInitialWorldStates(WorldPacket& data); - virtual void EventPlayerDamagedGO(Player* plr, GameObject* go, uint8 hitType, uint32 destroyedEvent); - virtual void HandleKillUnit(Creature* unit, Player* killer); - virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); - virtual void EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj); - virtual void EventPlayerUsedGO(Player* Source, GameObject* object); - uint32 GetGateIDFromDestroyEventID(uint32 id) - { - uint32 i = 0; - switch(id) - { - case 19046: i = BG_SA_GREEN_GATE; break; //Green gate destroyed - case 19045: i = BG_SA_BLUE_GATE; break; //blue gate - case 19047: i = BG_SA_RED_GATE; break; //red gate - case 19048: i = BG_SA_PURPLE_GATE; break; //purple gate - case 19049: i = BG_SA_YELLOW_GATE; break; //yellow gate - case 19837: i = BG_SA_ANCIENT_GATE; break; //ancient gate - } - return i; - } - uint32 GetWorldStateFromGateID(uint32 id) - { - uint32 uws = 0; - switch(id) - { - case BG_SA_GREEN_GATE: uws = BG_SA_GREEN_GATEWS; break; - case BG_SA_YELLOW_GATE: uws = BG_SA_YELLOW_GATEWS; break; - case BG_SA_BLUE_GATE: uws = BG_SA_BLUE_GATEWS; break; - case BG_SA_RED_GATE: uws = BG_SA_RED_GATEWS; break; - case BG_SA_PURPLE_GATE: uws = BG_SA_PURPLE_GATEWS; break; - case BG_SA_ANCIENT_GATE: uws = BG_SA_ANCIENT_GATEWS; break; - } - return uws; - } - void EndBattleGround(uint32 winner); - - void RemovePlayer(Player *plr,uint64 guid); - void HandleAreaTrigger(Player *Source, uint32 Trigger); - - - /* Scorekeeping */ - void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); - - private: - bool ResetObjs(); - void StartShips(); - void TeleportPlayers(); - void OverrideGunFaction(); - void DemolisherStartState(bool start); - void DestroyGate(Player* pl, GameObject* /*go*/, uint32 destroyedEvent); - void SendTime(); - void CaptureGraveyard(BG_SA_Graveyards i, Player *Source); - void ToggleTimer(); - void UpdateDemolisherSpawns(); - TeamId attackers; - uint32 TotalTime; - uint32 BG_SA_ENDROUNDTIME; - bool ShipsStarted; - BG_SA_GateState GateStatus[6]; - BG_SA_Status status; - TeamId GraveyardStatus[BG_SA_MAX_GY]; - BG_SA_RoundScore RoundScores[2]; - bool TimerEnabled; - uint32 UpdateWaitTimer;//5secs before starting the 1min countdown for second round - bool SignaledRoundTwo; - bool SignaledRoundTwoHalfMin; - bool InitSecondRound; -}; -#endif diff --git a/src/server/game/BattleGrounds/BattleGroundWS.cpp b/src/server/game/BattleGrounds/BattleGroundWS.cpp deleted file mode 100644 index 71872511274..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundWS.cpp +++ /dev/null @@ -1,841 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "BattleGround.h" -#include "BattleGroundWS.h" -#include "Creature.h" -#include "GameObject.h" -#include "Language.h" -#include "Object.h" -#include "ObjectMgr.h" -#include "BattleGroundMgr.h" -#include "Player.h" -#include "World.h" -#include "WorldPacket.h" - -// these variables aren't used outside of this file, so declare them only here -enum BG_WSG_Rewards -{ - BG_WSG_WIN = 0, - BG_WSG_FLAG_CAP, - BG_WSG_MAP_COMPLETE, - BG_WSG_REWARD_NUM -}; - -uint32 BG_WSG_Honor[BG_HONOR_MODE_NUM][BG_WSG_REWARD_NUM] = { - {20,40,40}, // normal honor - {60,40,80} // holiday -}; - -uint32 BG_WSG_Reputation[BG_HONOR_MODE_NUM][BG_WSG_REWARD_NUM] = { - {0,35,0}, // normal honor - {0,45,0} // holiday -}; - -BattleGroundWS::BattleGroundWS() -{ - m_BgObjects.resize(BG_WS_OBJECT_MAX); - m_BgCreatures.resize(BG_CREATURES_MAX_WS); - - m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES; - m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN; -} - -BattleGroundWS::~BattleGroundWS() -{ -} - -void BattleGroundWS::Update(uint32 diff) -{ - BattleGround::Update(diff); - - if (GetStatus() == STATUS_IN_PROGRESS) - { - if (GetStartTime() >= 25*MINUTE*IN_MILISECONDS) // Òàéìåð òèêàòü íà÷èíàåò ïîñëå 25 ìèíóò - { - if (GetTeamScore(ALLIANCE) == 0) - { - if (GetTeamScore(HORDE) == 0) // No one scored - result is tie - EndBattleGround(NULL); - else // Horde has more points and thus wins - EndBattleGround(HORDE); - } - - else if (GetTeamScore(HORDE) == 0) - EndBattleGround(ALLIANCE); // Alliance has > 0, Horde has 0, alliance wins - - else if (GetTeamScore(HORDE) == GetTeamScore(ALLIANCE)) // Team score equal, winner is team that scored the first flag - EndBattleGround(m_FirstFlagCaptureTeam); - - else if (GetTeamScore(HORDE) > GetTeamScore(ALLIANCE)) // Last but not least, check who has the higher score - EndBattleGround(HORDE); - else - EndBattleGround(ALLIANCE); - } - else if (GetStartTime() > m_minutesElapsed*MINUTE*IN_MILISECONDS) - { - ++m_minutesElapsed; - UpdateWorldState(BG_WS_STATE_TIMER, 25-m_minutesElapsed); - } - - if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_WAIT_RESPAWN) - { - m_FlagsTimer[BG_TEAM_ALLIANCE] -= diff; - - if (m_FlagsTimer[BG_TEAM_ALLIANCE] < 0) - { - m_FlagsTimer[BG_TEAM_ALLIANCE] = 0; - RespawnFlag(ALLIANCE, true); - } - } - if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND) - { - m_FlagsDropTimer[BG_TEAM_ALLIANCE] -= diff; - - if (m_FlagsDropTimer[BG_TEAM_ALLIANCE] < 0) - { - m_FlagsDropTimer[BG_TEAM_ALLIANCE] = 0; - RespawnFlagAfterDrop(ALLIANCE); - m_BothFlagsKept = false; - } - } - if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_WAIT_RESPAWN) - { - m_FlagsTimer[BG_TEAM_HORDE] -= diff; - - if (m_FlagsTimer[BG_TEAM_HORDE] < 0) - { - m_FlagsTimer[BG_TEAM_HORDE] = 0; - RespawnFlag(HORDE, true); - } - } - if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND) - { - m_FlagsDropTimer[BG_TEAM_HORDE] -= diff; - - if (m_FlagsDropTimer[BG_TEAM_HORDE] < 0) - { - m_FlagsDropTimer[BG_TEAM_HORDE] = 0; - RespawnFlagAfterDrop(HORDE); - m_BothFlagsKept = false; - } - } - if (m_BothFlagsKept) - { - m_FlagSpellForceTimer += diff; - if (m_FlagDebuffState == 0 && m_FlagSpellForceTimer >= 600000) //10 minutes - { - if (Player * plr = objmgr.GetPlayer(m_FlagKeepers[0])) - plr->CastSpell(plr,WS_SPELL_FOCUSED_ASSAULT,true); - if (Player * plr = objmgr.GetPlayer(m_FlagKeepers[1])) - plr->CastSpell(plr,WS_SPELL_FOCUSED_ASSAULT,true); - m_FlagDebuffState = 1; - } - else if (m_FlagDebuffState == 1 && m_FlagSpellForceTimer >= 900000) //15 minutes - { - if (Player * plr = objmgr.GetPlayer(m_FlagKeepers[0])) - { - plr->RemoveAurasDueToSpell(WS_SPELL_FOCUSED_ASSAULT); - plr->CastSpell(plr,WS_SPELL_BRUTAL_ASSAULT,true); - } - if (Player * plr = objmgr.GetPlayer(m_FlagKeepers[1])) - { - plr->RemoveAurasDueToSpell(WS_SPELL_FOCUSED_ASSAULT); - plr->CastSpell(plr,WS_SPELL_BRUTAL_ASSAULT,true); - } - m_FlagDebuffState = 2; - } - } - else - { - m_FlagSpellForceTimer = 0; //reset timer. - m_FlagDebuffState = 0; - } - } -} - -void BattleGroundWS::StartingEventCloseDoors() -{ - for (uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; ++i) - { - DoorClose(i); - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - } - for (uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; ++i) - SpawnBGObject(i, RESPAWN_ONE_DAY); - - UpdateWorldState(BG_WS_STATE_TIMER_ACTIVE, 1); - UpdateWorldState(BG_WS_STATE_TIMER, 25); -} - -void BattleGroundWS::StartingEventOpenDoors() -{ - for (uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_A_4; ++i) - DoorOpen(i); - for (uint32 i = BG_WS_OBJECT_DOOR_H_1; i <= BG_WS_OBJECT_DOOR_H_2; ++i) - DoorOpen(i); - - SpawnBGObject(BG_WS_OBJECT_DOOR_A_5, RESPAWN_ONE_DAY); - SpawnBGObject(BG_WS_OBJECT_DOOR_A_6, RESPAWN_ONE_DAY); - SpawnBGObject(BG_WS_OBJECT_DOOR_H_3, RESPAWN_ONE_DAY); - SpawnBGObject(BG_WS_OBJECT_DOOR_H_4, RESPAWN_ONE_DAY); - - for (uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; ++i) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); -} - -void BattleGroundWS::AddPlayer(Player *plr) -{ - BattleGround::AddPlayer(plr); - //create score and add it to map, default values are set in constructor - BattleGroundWGScore* sc = new BattleGroundWGScore; - - m_PlayerScores[plr->GetGUID()] = sc; -} - -void BattleGroundWS::RespawnFlag(uint32 Team, bool captured) -{ - if (Team == ALLIANCE) - { - sLog.outDebug("Respawn Alliance flag"); - m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_BASE; - } - else - { - sLog.outDebug("Respawn Horde flag"); - m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE; - } - - if (captured) - { - //when map_update will be allowed for battlegrounds this code will be useless - SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY); - SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY); - SendMessageToAll(LANG_BG_WS_F_PLACED, CHAT_MSG_BG_SYSTEM_NEUTRAL); - PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED); // flag respawned sound... - } - m_BothFlagsKept = false; -} - -void BattleGroundWS::RespawnFlagAfterDrop(uint32 team) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - RespawnFlag(team,false); - if (team == ALLIANCE) - { - SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY); - SendMessageToAll(LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED, CHAT_MSG_BG_SYSTEM_NEUTRAL); - } - else - { - SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY); - SendMessageToAll(LANG_BG_WS_HORDE_FLAG_RESPAWNED, CHAT_MSG_BG_SYSTEM_NEUTRAL); - } - - PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED); - - GameObject *obj = GetBgMap()->GetGameObject(GetDroppedFlagGUID(team)); - if (obj) - obj->Delete(); - else - sLog.outError("unknown droped flag bg, guid: %u",GUID_LOPART(GetDroppedFlagGUID(team))); - - SetDroppedFlagGUID(0,team); - m_BothFlagsKept = false; -} - -void BattleGroundWS::EventPlayerCapturedFlag(Player *Source) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - uint32 winner = 0; - - Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); - if (Source->GetTeam() == ALLIANCE) - { - if (!this->IsHordeFlagPickedup()) - return; - SetHordeFlagPicker(0); // must be before aura remove to prevent 2 events (drop+capture) at the same time - // horde flag in base (but not respawned yet) - m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_WAIT_RESPAWN; - // Drop Horde Flag from Player - Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG); - if (m_FlagDebuffState == 1) - Source->RemoveAurasDueToSpell(WS_SPELL_FOCUSED_ASSAULT); - if (m_FlagDebuffState == 2) - Source->RemoveAurasDueToSpell(WS_SPELL_BRUTAL_ASSAULT); - if (GetTeamScore(ALLIANCE) < BG_WS_MAX_TEAM_SCORE) - AddPoint(ALLIANCE, 1); - PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE); - RewardReputationToTeam(890, m_ReputationCapture, ALLIANCE); - } - else - { - if (!this->IsAllianceFlagPickedup()) - return; - SetAllianceFlagPicker(0); // must be before aura remove to prevent 2 events (drop+capture) at the same time - // alliance flag in base (but not respawned yet) - m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_WAIT_RESPAWN; - // Drop Alliance Flag from Player - Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG); - if (m_FlagDebuffState == 1) - Source->RemoveAurasDueToSpell(WS_SPELL_FOCUSED_ASSAULT); - if (m_FlagDebuffState == 2) - Source->RemoveAurasDueToSpell(WS_SPELL_BRUTAL_ASSAULT); - if (GetTeamScore(HORDE) < BG_WS_MAX_TEAM_SCORE) - AddPoint(HORDE, 1); - PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_HORDE); - RewardReputationToTeam(889, m_ReputationCapture, HORDE); - } - //for flag capture is reward 2 honorable kills - RewardHonorToTeam(GetBonusHonorFromKill(2), Source->GetTeam()); - - SpawnBGObject(BG_WS_OBJECT_H_FLAG, BG_WS_FLAG_RESPAWN_TIME); - SpawnBGObject(BG_WS_OBJECT_A_FLAG, BG_WS_FLAG_RESPAWN_TIME); - - if (Source->GetTeam() == ALLIANCE) - SendMessageToAll(LANG_BG_WS_CAPTURED_HF, CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); - else - SendMessageToAll(LANG_BG_WS_CAPTURED_AF, CHAT_MSG_BG_SYSTEM_HORDE, Source); - - UpdateFlagState(Source->GetTeam(), 1); // flag state none - UpdateTeamScore(Source->GetTeam()); - // only flag capture should be updated - UpdatePlayerScore(Source, SCORE_FLAG_CAPTURES, 1); // +1 flag captures - - if (!m_FirstFlagCaptureTeam) - SetFirstFlagCapture(Source->GetTeam()); - - if (GetTeamScore(ALLIANCE) == BG_WS_MAX_TEAM_SCORE) - winner = ALLIANCE; - - if (GetTeamScore(HORDE) == BG_WS_MAX_TEAM_SCORE) - winner = HORDE; - - if (winner) - { - UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 0); - UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 0); - UpdateWorldState(BG_WS_FLAG_STATE_ALLIANCE, 1); - UpdateWorldState(BG_WS_FLAG_STATE_HORDE, 1); - UpdateWorldState(BG_WS_STATE_TIMER_ACTIVE, 0); - - RewardHonorToTeam(BG_WSG_Honor[m_HonorMode][BG_WSG_WIN], winner); - EndBattleGround(winner); - } - else - { - m_FlagsTimer[GetTeamIndexByTeamId(Source->GetTeam()) ? 0 : 1] = BG_WS_FLAG_RESPAWN_TIME; - } -} - -void BattleGroundWS::EventPlayerDroppedFlag(Player *Source) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - { - // if not running, do not cast things at the dropper player (prevent spawning the "dropped" flag), neither send unnecessary messages - // just take off the aura - if (Source->GetTeam() == ALLIANCE) - { - if (!this->IsHordeFlagPickedup()) - return; - if (GetHordeFlagPickerGUID() == Source->GetGUID()) - { - SetHordeFlagPicker(0); - Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG); - } - } - else - { - if (!this->IsAllianceFlagPickedup()) - return; - if (GetAllianceFlagPickerGUID() == Source->GetGUID()) - { - SetAllianceFlagPicker(0); - Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG); - } - } - return; - } - - bool set = false; - - if (Source->GetTeam() == ALLIANCE) - { - if (!IsHordeFlagPickedup()) - return; - if (GetHordeFlagPickerGUID() == Source->GetGUID()) - { - SetHordeFlagPicker(0); - Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG); - if (m_FlagDebuffState == 1) - Source->RemoveAurasDueToSpell(WS_SPELL_FOCUSED_ASSAULT); - if (m_FlagDebuffState == 2) - Source->RemoveAurasDueToSpell(WS_SPELL_BRUTAL_ASSAULT); - m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_GROUND; - Source->CastSpell(Source, BG_WS_SPELL_WARSONG_FLAG_DROPPED, true); - set = true; - } - } - else - { - if (!IsAllianceFlagPickedup()) - return; - if (GetAllianceFlagPickerGUID() == Source->GetGUID()) - { - SetAllianceFlagPicker(0); - Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG); - if (m_FlagDebuffState == 1) - Source->RemoveAurasDueToSpell(WS_SPELL_FOCUSED_ASSAULT); - if (m_FlagDebuffState == 2) - Source->RemoveAurasDueToSpell(WS_SPELL_BRUTAL_ASSAULT); - m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_GROUND; - Source->CastSpell(Source, BG_WS_SPELL_SILVERWING_FLAG_DROPPED, true); - set = true; - } - } - - if (set) - { - Source->CastSpell(Source, SPELL_RECENTLY_DROPPED_FLAG, true); - UpdateFlagState(Source->GetTeam(), 1); - - if (Source->GetTeam() == ALLIANCE) - { - SendMessageToAll(LANG_BG_WS_DROPPED_HF, CHAT_MSG_BG_SYSTEM_HORDE, Source); - UpdateWorldState(BG_WS_FLAG_UNK_HORDE, uint32(-1)); - } - else - { - SendMessageToAll(LANG_BG_WS_DROPPED_AF, CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); - UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, uint32(-1)); - } - - m_FlagsDropTimer[GetTeamIndexByTeamId(Source->GetTeam()) ? 0 : 1] = BG_WS_FLAG_DROP_TIME; - } -} - -void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - int32 message_id = 0; - ChatMsg type = CHAT_MSG_BG_SYSTEM_NEUTRAL; - - //alliance flag picked up from base - if (Source->GetTeam() == HORDE && this->GetFlagState(ALLIANCE) == BG_WS_FLAG_STATE_ON_BASE - && this->m_BgObjects[BG_WS_OBJECT_A_FLAG] == target_obj->GetGUID()) - { - message_id = LANG_BG_WS_PICKEDUP_AF; - type = CHAT_MSG_BG_SYSTEM_HORDE; - PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP); - SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_ONE_DAY); - SetAllianceFlagPicker(Source->GetGUID()); - m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_PLAYER; - //update world state to show correct flag carrier - UpdateFlagState(HORDE, BG_WS_FLAG_STATE_ON_PLAYER); - UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 1); - Source->CastSpell(Source, BG_WS_SPELL_SILVERWING_FLAG, true); - if (m_FlagState[1] == BG_WS_FLAG_STATE_ON_PLAYER) - m_BothFlagsKept = true; - } - - //horde flag picked up from base - if (Source->GetTeam() == ALLIANCE && this->GetFlagState(HORDE) == BG_WS_FLAG_STATE_ON_BASE - && this->m_BgObjects[BG_WS_OBJECT_H_FLAG] == target_obj->GetGUID()) - { - message_id = LANG_BG_WS_PICKEDUP_HF; - type = CHAT_MSG_BG_SYSTEM_ALLIANCE; - PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP); - SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_ONE_DAY); - SetHordeFlagPicker(Source->GetGUID()); - m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_PLAYER; - //update world state to show correct flag carrier - UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_ON_PLAYER); - UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 1); - Source->CastSpell(Source, BG_WS_SPELL_WARSONG_FLAG, true); - if (m_FlagState[0] == BG_WS_FLAG_STATE_ON_PLAYER) - m_BothFlagsKept = true; - } - - //Alliance flag on ground(not in base) (returned or picked up again from ground!) - if (GetFlagState(ALLIANCE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10)) - { - if (Source->GetTeam() == ALLIANCE) - { - message_id = LANG_BG_WS_RETURNED_AF; - type = CHAT_MSG_BG_SYSTEM_ALLIANCE; - UpdateFlagState(HORDE, BG_WS_FLAG_STATE_WAIT_RESPAWN); - RespawnFlag(ALLIANCE, false); - SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY); - PlaySoundToAll(BG_WS_SOUND_FLAG_RETURNED); - UpdatePlayerScore(Source, SCORE_FLAG_RETURNS, 1); - m_BothFlagsKept = false; - } - else - { - message_id = LANG_BG_WS_PICKEDUP_AF; - type = CHAT_MSG_BG_SYSTEM_HORDE; - PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP); - SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_ONE_DAY); - SetAllianceFlagPicker(Source->GetGUID()); - Source->CastSpell(Source, BG_WS_SPELL_SILVERWING_FLAG, true); - m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_PLAYER; - UpdateFlagState(HORDE, BG_WS_FLAG_STATE_ON_PLAYER); - if (m_FlagDebuffState == 1) - Source->CastSpell(Source,WS_SPELL_FOCUSED_ASSAULT,true); - if (m_FlagDebuffState == 2) - Source->CastSpell(Source,WS_SPELL_BRUTAL_ASSAULT,true); - UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 1); - } - //called in HandleGameObjectUseOpcode: - //target_obj->Delete(); - } - - //Horde flag on ground(not in base) (returned or picked up again) - if (GetFlagState(HORDE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10)) - { - if (Source->GetTeam() == HORDE) - { - message_id = LANG_BG_WS_RETURNED_HF; - type = CHAT_MSG_BG_SYSTEM_HORDE; - UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_WAIT_RESPAWN); - RespawnFlag(HORDE, false); - SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY); - PlaySoundToAll(BG_WS_SOUND_FLAG_RETURNED); - UpdatePlayerScore(Source, SCORE_FLAG_RETURNS, 1); - m_BothFlagsKept = false; - } - else - { - message_id = LANG_BG_WS_PICKEDUP_HF; - type = CHAT_MSG_BG_SYSTEM_ALLIANCE; - PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP); - SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_ONE_DAY); - SetHordeFlagPicker(Source->GetGUID()); - Source->CastSpell(Source, BG_WS_SPELL_WARSONG_FLAG, true); - m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_PLAYER; - UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_ON_PLAYER); - if (m_FlagDebuffState == 1) - Source->CastSpell(Source,WS_SPELL_FOCUSED_ASSAULT,true); - if (m_FlagDebuffState == 2) - Source->CastSpell(Source,WS_SPELL_BRUTAL_ASSAULT,true); - UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 1); - } - //called in HandleGameObjectUseOpcode: - //target_obj->Delete(); - } - - if (!message_id) - return; - - SendMessageToAll(message_id, type, Source); - Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); -} - -void BattleGroundWS::RemovePlayer(Player *plr, uint64 guid) -{ - // sometimes flag aura not removed :( - if (IsAllianceFlagPickedup() && m_FlagKeepers[BG_TEAM_ALLIANCE] == guid) - { - if (!plr) - { - sLog.outError("BattleGroundWS: Removing offline player who has the FLAG!!"); - this->SetAllianceFlagPicker(0); - this->RespawnFlag(ALLIANCE, false); - } - else - this->EventPlayerDroppedFlag(plr); - } - if (IsHordeFlagPickedup() && m_FlagKeepers[BG_TEAM_HORDE] == guid) - { - if (!plr) - { - sLog.outError("BattleGroundWS: Removing offline player who has the FLAG!!"); - this->SetHordeFlagPicker(0); - this->RespawnFlag(HORDE, false); - } - else - this->EventPlayerDroppedFlag(plr); - } -} - -void BattleGroundWS::UpdateFlagState(uint32 team, uint32 value) -{ - if (team == ALLIANCE) - UpdateWorldState(BG_WS_FLAG_STATE_ALLIANCE, value); - else - UpdateWorldState(BG_WS_FLAG_STATE_HORDE, value); -} - -void BattleGroundWS::UpdateTeamScore(uint32 team) -{ - if (team == ALLIANCE) - UpdateWorldState(BG_WS_FLAG_CAPTURES_ALLIANCE, GetTeamScore(team)); - else - UpdateWorldState(BG_WS_FLAG_CAPTURES_HORDE, GetTeamScore(team)); -} - -void BattleGroundWS::HandleAreaTrigger(Player *Source, uint32 Trigger) -{ - // this is wrong way to implement these things. On official it done by gameobject spell cast. - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - //uint32 SpellId = 0; - //uint64 buff_guid = 0; - switch(Trigger) - { - case 3686: // Alliance elixir of speed spawn. Trigger not working, because located inside other areatrigger, can be replaced by IsWithinDist(object, dist) in BattleGround::Update(). - //buff_guid = m_BgObjects[BG_WS_OBJECT_SPEEDBUFF_1]; - break; - case 3687: // Horde elixir of speed spawn. Trigger not working, because located inside other areatrigger, can be replaced by IsWithinDist(object, dist) in BattleGround::Update(). - //buff_guid = m_BgObjects[BG_WS_OBJECT_SPEEDBUFF_2]; - break; - case 3706: // Alliance elixir of regeneration spawn - //buff_guid = m_BgObjects[BG_WS_OBJECT_REGENBUFF_1]; - break; - case 3708: // Horde elixir of regeneration spawn - //buff_guid = m_BgObjects[BG_WS_OBJECT_REGENBUFF_2]; - break; - case 3707: // Alliance elixir of berserk spawn - //buff_guid = m_BgObjects[BG_WS_OBJECT_BERSERKBUFF_1]; - break; - case 3709: // Horde elixir of berserk spawn - //buff_guid = m_BgObjects[BG_WS_OBJECT_BERSERKBUFF_2]; - break; - case 3646: // Alliance Flag spawn - if (m_FlagState[BG_TEAM_HORDE] && !m_FlagState[BG_TEAM_ALLIANCE]) - if (GetHordeFlagPickerGUID() == Source->GetGUID()) - EventPlayerCapturedFlag(Source); - break; - case 3647: // Horde Flag spawn - if (m_FlagState[BG_TEAM_ALLIANCE] && !m_FlagState[BG_TEAM_HORDE]) - if (GetAllianceFlagPickerGUID() == Source->GetGUID()) - EventPlayerCapturedFlag(Source); - break; - case 3649: // unk1 - case 3688: // unk2 - case 4628: // unk3 - case 4629: // unk4 - break; - default: - sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); - Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); - break; - } - - //if (buff_guid) - // HandleTriggerBuff(buff_guid,Source); -} - -bool BattleGroundWS::SetupBattleGround() -{ - // flags - if (!AddObject(BG_WS_OBJECT_A_FLAG, BG_OBJECT_A_FLAG_WS_ENTRY, 1540.423f, 1481.325f, 351.8284f, 3.089233f, 0, 0, 0.9996573f, 0.02617699f, BG_WS_FLAG_RESPAWN_TIME/1000) - || !AddObject(BG_WS_OBJECT_H_FLAG, BG_OBJECT_H_FLAG_WS_ENTRY, 916.0226f, 1434.405f, 345.413f, 0.01745329f, 0, 0, 0.008726535f, 0.9999619f, BG_WS_FLAG_RESPAWN_TIME/1000) - // buffs - || !AddObject(BG_WS_OBJECT_SPEEDBUFF_1, BG_OBJECTID_SPEEDBUFF_ENTRY, 1449.93f, 1470.71f, 342.6346f, -1.64061f, 0, 0, 0.7313537f, -0.6819983f, BUFF_RESPAWN_TIME) - || !AddObject(BG_WS_OBJECT_SPEEDBUFF_2, BG_OBJECTID_SPEEDBUFF_ENTRY, 1005.171f, 1447.946f, 335.9032f, 1.64061f, 0, 0, 0.7313537f, 0.6819984f, BUFF_RESPAWN_TIME) - || !AddObject(BG_WS_OBJECT_REGENBUFF_1, BG_OBJECTID_REGENBUFF_ENTRY, 1317.506f, 1550.851f, 313.2344f, -0.2617996f, 0, 0, 0.1305263f, -0.9914448f, BUFF_RESPAWN_TIME) - || !AddObject(BG_WS_OBJECT_REGENBUFF_2, BG_OBJECTID_REGENBUFF_ENTRY, 1110.451f, 1353.656f, 316.5181f, -0.6806787f, 0, 0, 0.333807f, -0.9426414f, BUFF_RESPAWN_TIME) - || !AddObject(BG_WS_OBJECT_BERSERKBUFF_1, BG_OBJECTID_BERSERKERBUFF_ENTRY, 1320.09f, 1378.79f, 314.7532f, 1.186824f, 0, 0, 0.5591929f, 0.8290376f, BUFF_RESPAWN_TIME) - || !AddObject(BG_WS_OBJECT_BERSERKBUFF_2, BG_OBJECTID_BERSERKERBUFF_ENTRY, 1139.688f, 1560.288f, 306.8432f, -2.443461f, 0, 0, 0.9396926f, -0.3420201f, BUFF_RESPAWN_TIME) - // alliance gates - || !AddObject(BG_WS_OBJECT_DOOR_A_1, BG_OBJECT_DOOR_A_1_WS_ENTRY, 1503.335f, 1493.466f, 352.1888f, 3.115414f, 0, 0, 0.9999143f, 0.01308903f, RESPAWN_IMMEDIATELY) - || !AddObject(BG_WS_OBJECT_DOOR_A_2, BG_OBJECT_DOOR_A_2_WS_ENTRY, 1492.478f, 1457.912f, 342.9689f, 3.115414f, 0, 0, 0.9999143f, 0.01308903f, RESPAWN_IMMEDIATELY) - || !AddObject(BG_WS_OBJECT_DOOR_A_3, BG_OBJECT_DOOR_A_3_WS_ENTRY, 1468.503f, 1494.357f, 351.8618f, 3.115414f, 0, 0, 0.9999143f, 0.01308903f, RESPAWN_IMMEDIATELY) - || !AddObject(BG_WS_OBJECT_DOOR_A_4, BG_OBJECT_DOOR_A_4_WS_ENTRY, 1471.555f, 1458.778f, 362.6332f, 3.115414f, 0, 0, 0.9999143f, 0.01308903f, RESPAWN_IMMEDIATELY) - || !AddObject(BG_WS_OBJECT_DOOR_A_5, BG_OBJECT_DOOR_A_5_WS_ENTRY, 1492.347f, 1458.34f, 342.3712f, -0.03490669f, 0, 0, 0.01745246f, -0.9998477f, RESPAWN_IMMEDIATELY) - || !AddObject(BG_WS_OBJECT_DOOR_A_6, BG_OBJECT_DOOR_A_6_WS_ENTRY, 1503.466f, 1493.367f, 351.7352f, -0.03490669f, 0, 0, 0.01745246f, -0.9998477f, RESPAWN_IMMEDIATELY) - // horde gates - || !AddObject(BG_WS_OBJECT_DOOR_H_1, BG_OBJECT_DOOR_H_1_WS_ENTRY, 949.1663f, 1423.772f, 345.6241f, -0.5756807f, -0.01673368f, -0.004956111f, -0.2839723f, 0.9586737f, RESPAWN_IMMEDIATELY) - || !AddObject(BG_WS_OBJECT_DOOR_H_2, BG_OBJECT_DOOR_H_2_WS_ENTRY, 953.0507f, 1459.842f, 340.6526f, -1.99662f, -0.1971825f, 0.1575096f, -0.8239487f, 0.5073641f, RESPAWN_IMMEDIATELY) - || !AddObject(BG_WS_OBJECT_DOOR_H_3, BG_OBJECT_DOOR_H_3_WS_ENTRY, 949.9523f, 1422.751f, 344.9273f, 0.0f, 0, 0, 0, 1, RESPAWN_IMMEDIATELY) - || !AddObject(BG_WS_OBJECT_DOOR_H_4, BG_OBJECT_DOOR_H_4_WS_ENTRY, 950.7952f, 1459.583f, 342.1523f, 0.05235988f, 0, 0, 0.02617695f, 0.9996573f, RESPAWN_IMMEDIATELY) -) - { - sLog.outErrorDb("BatteGroundWS: Failed to spawn some object BattleGround not created!"); - return false; - } - - WorldSafeLocsEntry const *sg = sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_ALLIANCE); - if (!sg || !AddSpiritGuide(WS_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, ALLIANCE)) - { - sLog.outErrorDb("BatteGroundWS: Failed to spawn Alliance spirit guide! BattleGround not created!"); - return false; - } - - sg = sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_HORDE); - if (!sg || !AddSpiritGuide(WS_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, HORDE)) - { - sLog.outErrorDb("BatteGroundWS: Failed to spawn Horde spirit guide! BattleGround not created!"); - return false; - } - - sLog.outDebug("BatteGroundWS: BG objects and spirit guides spawned"); - - return true; -} - -void BattleGroundWS::Reset() -{ - //call parent's class reset - BattleGround::Reset(); - - m_FlagKeepers[BG_TEAM_ALLIANCE] = 0; - m_FlagKeepers[BG_TEAM_HORDE] = 0; - m_DroppedFlagGUID[BG_TEAM_ALLIANCE] = 0; - m_DroppedFlagGUID[BG_TEAM_HORDE] = 0; - m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_BASE; - m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE; - m_TeamScores[BG_TEAM_ALLIANCE] = 0; - m_TeamScores[BG_TEAM_HORDE] = 0; - bool isBGWeekend = sBattleGroundMgr.IsBGWeekend(GetTypeID()); - m_ReputationCapture = (isBGWeekend) ? 45 : 35; - m_HonorWinKills = (isBGWeekend) ? 3 : 1; - m_HonorEndKills = (isBGWeekend) ? 4 : 2; - // For WorldState - m_minutesElapsed = 0; - m_FirstFlagCaptureTeam = 0; - - /* Spirit nodes is static at this BG and then not required deleting at BG reset. - if (m_BgCreatures[WS_SPIRIT_MAIN_ALLIANCE]) - DelCreature(WS_SPIRIT_MAIN_ALLIANCE); - if (m_BgCreatures[WS_SPIRIT_MAIN_HORDE]) - DelCreature(WS_SPIRIT_MAIN_HORDE); - */ -} - -void BattleGroundWS::EndBattleGround(uint32 winner) -{ - //win reward - if (winner == ALLIANCE) - RewardHonorToTeam(GetBonusHonorFromKill(m_HonorWinKills), ALLIANCE); - if (winner == HORDE) - RewardHonorToTeam(GetBonusHonorFromKill(m_HonorWinKills), HORDE); - //complete map_end rewards (even if no team wins) - RewardHonorToTeam(GetBonusHonorFromKill(m_HonorEndKills), ALLIANCE); - RewardHonorToTeam(GetBonusHonorFromKill(m_HonorEndKills), HORDE); - - BattleGround::EndBattleGround(winner); -} - -void BattleGroundWS::HandleKillPlayer(Player *player, Player *killer) -{ - if (GetStatus() != STATUS_IN_PROGRESS) - return; - - EventPlayerDroppedFlag(player); - - BattleGround::HandleKillPlayer(player, killer); -} - -void BattleGroundWS::UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor) -{ - - BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); - if (itr == m_PlayerScores.end()) // player not found - return; - - switch(type) - { - case SCORE_FLAG_CAPTURES: // flags captured - ((BattleGroundWGScore*)itr->second)->FlagCaptures += value; - break; - case SCORE_FLAG_RETURNS: // flags returned - ((BattleGroundWGScore*)itr->second)->FlagReturns += value; - break; - default: - BattleGround::UpdatePlayerScore(Source, type, value, doAddHonor); - break; - } -} - -WorldSafeLocsEntry const* BattleGroundWS::GetClosestGraveYard(Player* player) -{ - //if status in progress, it returns main graveyards with spiritguides - //else it will return the graveyard in the flagroom - this is especially good - //if a player dies in preparation phase - then the player can't cheat - //and teleport to the graveyard outside the flagroom - //and start running around, while the doors are still closed - if (player->GetTeam() == ALLIANCE) - { - if (GetStatus() == STATUS_IN_PROGRESS) - return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_ALLIANCE); - else - return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_FLAGROOM_ALLIANCE); - } - else - { - if (GetStatus() == STATUS_IN_PROGRESS) - return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_HORDE); - else - return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_FLAGROOM_HORDE); - } -} - -void BattleGroundWS::FillInitialWorldStates(WorldPacket& data) -{ - data << uint32(BG_WS_FLAG_CAPTURES_ALLIANCE) << uint32(GetTeamScore(ALLIANCE)); - data << uint32(BG_WS_FLAG_CAPTURES_HORDE) << uint32(GetTeamScore(HORDE)); - - if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND) - data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(-1); - else if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_PLAYER) - data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(1); - else - data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(0); - - if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND) - data << uint32(BG_WS_FLAG_UNK_HORDE) << uint32(-1); - else if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_PLAYER) - data << uint32(BG_WS_FLAG_UNK_HORDE) << uint32(1); - else - data << uint32(BG_WS_FLAG_UNK_HORDE) << uint32(0); - - data << uint32(BG_WS_FLAG_CAPTURES_MAX) << uint32(BG_WS_MAX_TEAM_SCORE); - - if (GetStatus() == STATUS_IN_PROGRESS) - { - data << uint32(BG_WS_STATE_TIMER_ACTIVE) << uint32(1); - data << uint32(BG_WS_STATE_TIMER) << uint32(25-m_minutesElapsed); - } - else - data << uint32(BG_WS_STATE_TIMER_ACTIVE) << uint32(0); - - if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_PLAYER) - data << uint32(BG_WS_FLAG_STATE_ALLIANCE) << uint32(2); - else - data << uint32(BG_WS_FLAG_STATE_ALLIANCE) << uint32(1); - - if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_PLAYER) - data << uint32(BG_WS_FLAG_STATE_HORDE) << uint32(2); - else - data << uint32(BG_WS_FLAG_STATE_HORDE) << uint32(1); - -} - diff --git a/src/server/game/BattleGrounds/BattleGroundWS.h b/src/server/game/BattleGrounds/BattleGroundWS.h deleted file mode 100644 index 1a733c14570..00000000000 --- a/src/server/game/BattleGrounds/BattleGroundWS.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __BATTLEGROUNDWS_H -#define __BATTLEGROUNDWS_H - -#include "BattleGround.h" - -enum BG_WS_TimerOrScore -{ - BG_WS_MAX_TEAM_SCORE = 3, - BG_WS_FLAG_RESPAWN_TIME = 23000, - BG_WS_FLAG_DROP_TIME = 10000, - BG_WS_SPELL_FORCE_TIME = 600000, - BG_WS_SPELL_BRUTAL_TIME = 900000 -}; - -enum BG_WS_Sound -{ - BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE = 8173, - BG_WS_SOUND_FLAG_CAPTURED_HORDE = 8213, - BG_WS_SOUND_FLAG_PLACED = 8232, - BG_WS_SOUND_FLAG_RETURNED = 8192, - BG_WS_SOUND_HORDE_FLAG_PICKED_UP = 8212, - BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP = 8174, - BG_WS_SOUND_FLAGS_RESPAWNED = 8232 -}; - -enum BG_WS_SpellId -{ - BG_WS_SPELL_WARSONG_FLAG = 23333, - BG_WS_SPELL_WARSONG_FLAG_DROPPED = 23334, - BG_WS_SPELL_SILVERWING_FLAG = 23335, - BG_WS_SPELL_SILVERWING_FLAG_DROPPED = 23336, - BG_WS_SPELL_FOCUSED_ASSAULT = 46392, - BG_WS_SPELL_BRUTAL_ASSAULT = 46393 -}; - -enum BG_WS_WorldStates -{ - BG_WS_FLAG_UNK_ALLIANCE = 1545, - BG_WS_FLAG_UNK_HORDE = 1546, -// FLAG_UNK = 1547, - BG_WS_FLAG_CAPTURES_ALLIANCE = 1581, - BG_WS_FLAG_CAPTURES_HORDE = 1582, - BG_WS_FLAG_CAPTURES_MAX = 1601, - BG_WS_FLAG_STATE_HORDE = 2338, - BG_WS_FLAG_STATE_ALLIANCE = 2339, - BG_WS_STATE_TIMER = 4248, - BG_WS_STATE_TIMER_ACTIVE = 4247 -}; - -enum BG_WS_ObjectTypes -{ - BG_WS_OBJECT_DOOR_A_1 = 0, - BG_WS_OBJECT_DOOR_A_2 = 1, - BG_WS_OBJECT_DOOR_A_3 = 2, - BG_WS_OBJECT_DOOR_A_4 = 3, - BG_WS_OBJECT_DOOR_A_5 = 4, - BG_WS_OBJECT_DOOR_A_6 = 5, - BG_WS_OBJECT_DOOR_H_1 = 6, - BG_WS_OBJECT_DOOR_H_2 = 7, - BG_WS_OBJECT_DOOR_H_3 = 8, - BG_WS_OBJECT_DOOR_H_4 = 9, - BG_WS_OBJECT_A_FLAG = 10, - BG_WS_OBJECT_H_FLAG = 11, - BG_WS_OBJECT_SPEEDBUFF_1 = 12, - BG_WS_OBJECT_SPEEDBUFF_2 = 13, - BG_WS_OBJECT_REGENBUFF_1 = 14, - BG_WS_OBJECT_REGENBUFF_2 = 15, - BG_WS_OBJECT_BERSERKBUFF_1 = 16, - BG_WS_OBJECT_BERSERKBUFF_2 = 17, - BG_WS_OBJECT_MAX = 18 -}; - -enum BG_WS_ObjectEntry -{ - BG_OBJECT_DOOR_A_1_WS_ENTRY = 179918, - BG_OBJECT_DOOR_A_2_WS_ENTRY = 179919, - BG_OBJECT_DOOR_A_3_WS_ENTRY = 179920, - BG_OBJECT_DOOR_A_4_WS_ENTRY = 179921, - BG_OBJECT_DOOR_A_5_WS_ENTRY = 180322, - BG_OBJECT_DOOR_A_6_WS_ENTRY = 180322, - BG_OBJECT_DOOR_H_1_WS_ENTRY = 179916, - BG_OBJECT_DOOR_H_2_WS_ENTRY = 179917, - BG_OBJECT_DOOR_H_3_WS_ENTRY = 180322, - BG_OBJECT_DOOR_H_4_WS_ENTRY = 180322, - BG_OBJECT_A_FLAG_WS_ENTRY = 179830, - BG_OBJECT_H_FLAG_WS_ENTRY = 179831, - BG_OBJECT_A_FLAG_GROUND_WS_ENTRY = 179785, - BG_OBJECT_H_FLAG_GROUND_WS_ENTRY = 179786 -}; - -enum BG_WS_FlagState -{ - BG_WS_FLAG_STATE_ON_BASE = 0, - BG_WS_FLAG_STATE_WAIT_RESPAWN = 1, - BG_WS_FLAG_STATE_ON_PLAYER = 2, - BG_WS_FLAG_STATE_ON_GROUND = 3 -}; - -enum BG_WS_Graveyards -{ - WS_GRAVEYARD_FLAGROOM_ALLIANCE = 769, - WS_GRAVEYARD_FLAGROOM_HORDE = 770, - WS_GRAVEYARD_MAIN_ALLIANCE = 771, - WS_GRAVEYARD_MAIN_HORDE = 772 -}; - -enum BG_WS_CreatureTypes -{ - WS_SPIRIT_MAIN_ALLIANCE = 0, - WS_SPIRIT_MAIN_HORDE = 1, - - BG_CREATURES_MAX_WS = 2 -}; - -enum BG_WS_CarrierDebuffs -{ - WS_SPELL_FOCUSED_ASSAULT = 46392, - WS_SPELL_BRUTAL_ASSAULT = 46393 -}; - -class BattleGroundWGScore : public BattleGroundScore -{ - public: - BattleGroundWGScore() : FlagCaptures(0), FlagReturns(0) {}; - virtual ~BattleGroundWGScore() {}; - uint32 FlagCaptures; - uint32 FlagReturns; -}; - -class BattleGroundWS : public BattleGround -{ - friend class BattleGroundMgr; - - public: - /* Construction */ - BattleGroundWS(); - ~BattleGroundWS(); - void Update(uint32 diff); - - /* inherited from BattlegroundClass */ - virtual void AddPlayer(Player *plr); - virtual void StartingEventCloseDoors(); - virtual void StartingEventOpenDoors(); - - /* BG Flags */ - uint64 GetAllianceFlagPickerGUID() const { return m_FlagKeepers[BG_TEAM_ALLIANCE]; } - uint64 GetHordeFlagPickerGUID() const { return m_FlagKeepers[BG_TEAM_HORDE]; } - void SetAllianceFlagPicker(uint64 guid) { m_FlagKeepers[BG_TEAM_ALLIANCE] = guid; } - void SetHordeFlagPicker(uint64 guid) { m_FlagKeepers[BG_TEAM_HORDE] = guid; } - bool IsAllianceFlagPickedup() const { return m_FlagKeepers[BG_TEAM_ALLIANCE] != 0; } - bool IsHordeFlagPickedup() const { return m_FlagKeepers[BG_TEAM_HORDE] != 0; } - void RespawnFlag(uint32 Team, bool captured); - void RespawnFlagAfterDrop(uint32 Team); - uint8 GetFlagState(uint32 team) { return m_FlagState[GetTeamIndexByTeamId(team)]; } - void AddTimedAura(uint32 aura); - void RemoveTimedAura(uint32 aura); - bool IsBrutalTimerDone; - bool IsForceTimerDone; - - /* Battleground Events */ - virtual void EventPlayerDroppedFlag(Player *Source); - virtual void EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj); - virtual void EventPlayerCapturedFlag(Player *Source); - - void RemovePlayer(Player *plr, uint64 guid); - void HandleAreaTrigger(Player *Source, uint32 Trigger); - void HandleKillPlayer(Player *player, Player *killer); - bool SetupBattleGround(); - virtual void Reset(); - void EndBattleGround(uint32 winner); - virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); - - void UpdateFlagState(uint32 team, uint32 value); - void SetFirstFlagCapture(uint32 team) { m_FirstFlagCaptureTeam = team; } - void UpdateTeamScore(uint32 team); - void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); - void SetDroppedFlagGUID(uint64 guid, uint32 TeamID) { m_DroppedFlagGUID[GetTeamIndexByTeamId(TeamID)] = guid;} - uint64 GetDroppedFlagGUID(uint32 TeamID) { return m_DroppedFlagGUID[GetTeamIndexByTeamId(TeamID)];} - virtual void FillInitialWorldStates(WorldPacket& data); - - /* Scorekeeping */ - uint32 GetTeamScore(uint32 TeamID) const { return m_TeamScores[GetTeamIndexByTeamId(TeamID)]; } - void AddPoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] += Points; } - void SetTeamPoint(uint32 TeamID, uint32 Points = 0) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] = Points; } - void RemovePoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] -= Points; } - private: - uint64 m_FlagKeepers[2]; // 0 - alliance, 1 - horde - uint64 m_DroppedFlagGUID[2]; - uint8 m_FlagState[2]; // for checking flag state - int32 m_FlagsTimer[2]; - int32 m_FlagsDropTimer[2]; - uint32 m_FirstFlagCaptureTeam; // Winner is based on this if score is equal - - uint32 m_ReputationCapture; - uint32 m_HonorWinKills; - uint32 m_HonorEndKills; - int32 m_FlagSpellForceTimer; - bool m_BothFlagsKept; - uint8 m_FlagDebuffState; // 0 - no debuffs, 1 - focused assault, 2 - brutal assault - uint8 m_minutesElapsed; -}; -#endif - diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundAA.cpp b/src/server/game/BattleGrounds/Zones/BattleGroundAA.cpp new file mode 100644 index 00000000000..56cf3ebed15 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundAA.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "BattleGround.h" +#include "BattleGroundAA.h" +#include "Language.h" +#include "Player.h" + +BattleGroundAA::BattleGroundAA() +{ + + m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; + m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; + m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; + m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; + //we must set messageIds + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; +} + +BattleGroundAA::~BattleGroundAA() +{ + +} + +void BattleGroundAA::Update(uint32 diff) +{ + BattleGround::Update(diff); +} + +void BattleGroundAA::StartingEventCloseDoors() +{ +} + +void BattleGroundAA::StartingEventOpenDoors() +{ +} + +void BattleGroundAA::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map, default values are set in constructor + BattleGroundAAScore* sc = new BattleGroundAAScore; + + m_PlayerScores[plr->GetGUID()] = sc; +} + +void BattleGroundAA::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) +{ +} + +void BattleGroundAA::HandleKillPlayer(Player* player, Player* killer) +{ + BattleGround::HandleKillPlayer(player, killer); +} + +void BattleGroundAA::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/) +{ +} + +bool BattleGroundAA::SetupBattleGround() +{ + return true; +} + diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundAA.h b/src/server/game/BattleGrounds/Zones/BattleGroundAA.h new file mode 100644 index 00000000000..a13833697cf --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundAA.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __BATTLEGROUNDAA_H +#define __BATTLEGROUNDAA_H + +class BattleGround; + +class BattleGroundAAScore : public BattleGroundScore +{ + public: + BattleGroundAAScore() {}; + virtual ~BattleGroundAAScore() {}; + //TODO fix me +}; + +class BattleGroundAA : public BattleGround +{ + friend class BattleGroundMgr; + + public: + BattleGroundAA(); + ~BattleGroundAA(); + void Update(uint32 diff); + + /* inherited from BattlegroundClass */ + virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + + void RemovePlayer(Player *plr, uint64 guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + bool SetupBattleGround(); + void HandleKillPlayer(Player* player, Player *killer); +}; +#endif + diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundAB.cpp b/src/server/game/BattleGrounds/Zones/BattleGroundAB.cpp new file mode 100644 index 00000000000..38671e85597 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundAB.cpp @@ -0,0 +1,715 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "World.h" +#include "WorldPacket.h" +#include "ObjectMgr.h" +#include "BattleGroundMgr.h" +#include "BattleGround.h" +#include "BattleGroundAB.h" +#include "Creature.h" +#include "Language.h" +#include "Object.h" +#include "Player.h" +#include "Util.h" + +// these variables aren't used outside of this file, so declare them only here +uint32 BG_AB_HonorScoreTicks[BG_HONOR_MODE_NUM] = { + 330, // normal honor + 200 // holiday +}; + +uint32 BG_AB_ReputationScoreTicks[BG_HONOR_MODE_NUM] = { + 200, // normal honor + 150 // holiday +}; + +BattleGroundAB::BattleGroundAB() +{ + m_BuffChange = true; + m_BgObjects.resize(BG_AB_OBJECT_MAX); + m_BgCreatures.resize(BG_AB_ALL_NODES_COUNT + 5);//+5 for aura triggers + + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_AB_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AB_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AB_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AB_HAS_BEGUN; +} + +BattleGroundAB::~BattleGroundAB() +{ +} + +void BattleGroundAB::Update(uint32 diff) +{ + BattleGround::Update(diff); + + if (GetStatus() == STATUS_IN_PROGRESS) + { + int team_points[BG_TEAMS_COUNT] = { 0, 0 }; + + for (int node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node) + { + // 3 sec delay to spawn new banner instead previous despawned one + if (m_BannerTimers[node].timer) + { + if (m_BannerTimers[node].timer > diff) + m_BannerTimers[node].timer -= diff; + else + { + m_BannerTimers[node].timer = 0; + _CreateBanner(node, m_BannerTimers[node].type, m_BannerTimers[node].teamIndex, false); + } + } + + // 1-minute to occupy a node from contested state + if (m_NodeTimers[node]) + { + if (m_NodeTimers[node] > diff) + m_NodeTimers[node] -= diff; + else + { + m_NodeTimers[node] = 0; + // Change from contested to occupied ! + uint8 teamIndex = m_Nodes[node]-1; + m_prevNodes[node] = m_Nodes[node]; + m_Nodes[node] += 2; + // burn current contested banner + _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex); + // create new occupied banner + _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true); + _SendNodeUpdate(node); + _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE); + // Message to chatlog + + if (teamIndex == 0) + { + // FIXME: team and node names not localized + SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE,NULL,LANG_BG_AB_ALLY,_GetNodeNameId(node)); + PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE); + } + else + { + // FIXME: team and node names not localized + SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE,NULL,LANG_BG_AB_HORDE,_GetNodeNameId(node)); + PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE); + } + } + } + + for (int team = 0; team < BG_TEAMS_COUNT; ++team) + if (m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED) + ++team_points[team]; + } + + // Accumulate points + for (int team = 0; team < BG_TEAMS_COUNT; ++team) + { + int points = team_points[team]; + if (!points) + continue; + m_lastTick[team] += diff; + if (m_lastTick[team] > BG_AB_TickIntervals[points]) + { + m_lastTick[team] -= BG_AB_TickIntervals[points]; + m_TeamScores[team] += BG_AB_TickPoints[points]; + m_HonorScoreTics[team] += BG_AB_TickPoints[points]; + m_ReputationScoreTics[team] += BG_AB_TickPoints[points]; + if (m_ReputationScoreTics[team] >= m_ReputationTics) + { + (team == BG_TEAM_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE); + m_ReputationScoreTics[team] -= m_ReputationTics; + } + if (m_HonorScoreTics[team] >= m_HonorTics) + { + RewardHonorToTeam(GetBonusHonorFromKill(1), (team == BG_TEAM_ALLIANCE) ? ALLIANCE : HORDE); + m_HonorScoreTics[team] -= m_HonorTics; + } + if (!m_IsInformedNearVictory && m_TeamScores[team] > BG_AB_WARNING_NEAR_VICTORY_SCORE) + { + if (team == BG_TEAM_ALLIANCE) + SendMessageToAll(LANG_BG_AB_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); + else + SendMessageToAll(LANG_BG_AB_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); + PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY); + m_IsInformedNearVictory = true; + } + + if (m_TeamScores[team] > BG_AB_MAX_TEAM_SCORE) + m_TeamScores[team] = BG_AB_MAX_TEAM_SCORE; + if (team == BG_TEAM_ALLIANCE) + UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]); + if (team == BG_TEAM_HORDE) + UpdateWorldState(BG_AB_OP_RESOURCES_HORDE, m_TeamScores[team]); + // update achievement flags + // we increased m_TeamScores[team] so we just need to check if it is 500 more than other teams resources + uint8 otherTeam = (team + 1) % BG_TEAMS_COUNT; + if (m_TeamScores[team] > m_TeamScores[otherTeam] + 500) + m_TeamScores500Disadvantage[otherTeam] = true; + } + } + + // Test win condition + if (m_TeamScores[BG_TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE) + EndBattleGround(ALLIANCE); + if (m_TeamScores[BG_TEAM_HORDE] >= BG_AB_MAX_TEAM_SCORE) + EndBattleGround(HORDE); + } +} + +void BattleGroundAB::StartingEventCloseDoors() +{ + // despawn banners, auras and buffs + for (int obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_DYNAMIC_NODES_COUNT * 8; ++obj) + SpawnBGObject(obj, RESPAWN_ONE_DAY); + for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT * 3; ++i) + SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + i, RESPAWN_ONE_DAY); + + // Starting doors + DoorClose(BG_AB_OBJECT_GATE_A); + DoorClose(BG_AB_OBJECT_GATE_H); + SpawnBGObject(BG_AB_OBJECT_GATE_A, RESPAWN_IMMEDIATELY); + SpawnBGObject(BG_AB_OBJECT_GATE_H, RESPAWN_IMMEDIATELY); + + // Starting base spirit guides + _NodeOccupied(BG_AB_SPIRIT_ALIANCE,ALLIANCE); + _NodeOccupied(BG_AB_SPIRIT_HORDE,HORDE); +} + +void BattleGroundAB::StartingEventOpenDoors() +{ + // spawn neutral banners + for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i) + SpawnBGObject(banner, RESPAWN_IMMEDIATELY); + for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) + { + //randomly select buff to spawn + uint8 buff = urand(0, 2); + SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + buff + i * 3, RESPAWN_IMMEDIATELY); + } + DoorOpen(BG_AB_OBJECT_GATE_A); + DoorOpen(BG_AB_OBJECT_GATE_H); +} + +void BattleGroundAB::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map, default values are set in the constructor + BattleGroundABScore* sc = new BattleGroundABScore; + + m_PlayerScores[plr->GetGUID()] = sc; +} + +void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) +{ + +} + +void BattleGroundAB::HandleAreaTrigger(Player *Source, uint32 Trigger) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + switch(Trigger) + { + case 3948: // Arathi Basin Alliance Exit. + if (Source->GetTeam() != ALLIANCE) + Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal"); + else + Source->LeaveBattleground(); + break; + case 3949: // Arathi Basin Horde Exit. + if (Source->GetTeam() != HORDE) + Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal"); + else + Source->LeaveBattleground(); + break; + case 3866: // Stables + case 3869: // Gold Mine + case 3867: // Farm + case 3868: // Lumber Mill + case 3870: // Black Smith + case 4020: // Unk1 + case 4021: // Unk2 + //break; + default: + //sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); + //Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); + break; + } +} + +/* type: 0-neutral, 1-contested, 3-occupied + teamIndex: 0-ally, 1-horde */ +void BattleGroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay) +{ + // Just put it into the queue + if (delay) + { + m_BannerTimers[node].timer = 2000; + m_BannerTimers[node].type = type; + m_BannerTimers[node].teamIndex = teamIndex; + return; + } + + uint8 obj = node*8 + type + teamIndex; + + SpawnBGObject(obj, RESPAWN_IMMEDIATELY); + + // handle aura with banner + if (!type) + return; + obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7); + SpawnBGObject(obj, RESPAWN_IMMEDIATELY); +} + +void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex) +{ + uint8 obj = node*8 + type + teamIndex; + SpawnBGObject(obj, RESPAWN_ONE_DAY); + + // handle aura with banner + if (!type) + return; + obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7); + SpawnBGObject(obj, RESPAWN_ONE_DAY); +} + +int32 BattleGroundAB::_GetNodeNameId(uint8 node) +{ + switch (node) + { + case BG_AB_NODE_STABLES: return LANG_BG_AB_NODE_STABLES; + case BG_AB_NODE_BLACKSMITH: return LANG_BG_AB_NODE_BLACKSMITH; + case BG_AB_NODE_FARM: return LANG_BG_AB_NODE_FARM; + case BG_AB_NODE_LUMBER_MILL:return LANG_BG_AB_NODE_LUMBER_MILL; + case BG_AB_NODE_GOLD_MINE: return LANG_BG_AB_NODE_GOLD_MINE; + default: + ASSERT(0); + } + return 0; +} + +void BattleGroundAB::FillInitialWorldStates(WorldPacket& data) +{ + const uint8 plusArray[] = {0, 2, 3, 0, 1}; + + // Node icons + for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node) + data << uint32(BG_AB_OP_NODEICONS[node]) << uint32((m_Nodes[node] == 0)?1:0); + + // Node occupied states + for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node) + for (uint8 i = 1; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) + data << uint32(BG_AB_OP_NODESTATES[node] + plusArray[i]) << uint32((m_Nodes[node] == i)?1:0); + + // How many bases each team owns + uint8 ally = 0, horde = 0; + for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node) + if (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_OCCUPIED) + ++ally; + else if (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED) + ++horde; + + data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY) << uint32(ally); + data << uint32(BG_AB_OP_OCCUPIED_BASES_HORDE) << uint32(horde); + + // Team scores + data << uint32(BG_AB_OP_RESOURCES_MAX) << uint32(BG_AB_MAX_TEAM_SCORE); + data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_NEAR_VICTORY_SCORE); + data << uint32(BG_AB_OP_RESOURCES_ALLY) << uint32(m_TeamScores[BG_TEAM_ALLIANCE]); + data << uint32(BG_AB_OP_RESOURCES_HORDE) << uint32(m_TeamScores[BG_TEAM_HORDE]); + + // other unknown + data << uint32(0x745) << uint32(0x2); // 37 1861 unk +} + +void BattleGroundAB::_SendNodeUpdate(uint8 node) +{ + // Send node owner state update to refresh map icons on client + const uint8 plusArray[] = {0, 2, 3, 0, 1}; + + if (m_prevNodes[node]) + UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_prevNodes[node]], 0); + else + UpdateWorldState(BG_AB_OP_NODEICONS[node], 0); + + UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_Nodes[node]], 1); + + // How many bases each team owns + uint8 ally = 0, horde = 0; + for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) + if (m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED) + ++ally; + else if (m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED) + ++horde; + + UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_ALLY, ally); + UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_HORDE, horde); +} + +void BattleGroundAB::_NodeOccupied(uint8 node,Team team) +{ + if (!AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team)) + sLog.outError("Failed to spawn spirit guide! point: %u, team: %u,", node, team); + + uint8 capturedNodes = 0; + for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) + { + if (m_Nodes[node] == GetTeamIndexByTeamId(team) + BG_AB_NODE_TYPE_OCCUPIED && !m_NodeTimers[i]) + ++capturedNodes; + } + if (capturedNodes >= 5) + CastSpellOnTeam(SPELL_AB_QUEST_REWARD_5_BASES, team); + if (capturedNodes >= 4) + CastSpellOnTeam(SPELL_AB_QUEST_REWARD_4_BASES, team); + + if(node >= BG_AB_DYNAMIC_NODES_COUNT)//only dynamic nodes, no start points + return; + Creature* trigger = GetBGCreature(node+7);//0-6 spirit guides + if (!trigger) + trigger = AddCreature(WORLD_TRIGGER,node+7,team,BG_AB_NodePositions[node][0],BG_AB_NodePositions[node][1],BG_AB_NodePositions[node][2],BG_AB_NodePositions[node][3]); + + //add bonus honor aura trigger creature when node is accupied + //cast bonus aura (+50% honor in 25yards) + //aura should only apply to players who have accupied the node, set correct faction for trigger + if (trigger) + { + trigger->setFaction(team == ALLIANCE ? 84 : 83); + trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false); + } +} + +void BattleGroundAB::_NodeDeOccupied(uint8 node) +{ + if (node >= BG_AB_DYNAMIC_NODES_COUNT) + return; + + //remove bonus honor aura trigger creature when node is lost + if(node < BG_AB_DYNAMIC_NODES_COUNT)//only dynamic nodes, no start points + DelCreature(node+7);//NULL checks are in DelCreature! 0-6 spirit guides + + // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard + std::vector ghost_list = m_ReviveQueue[m_BgCreatures[node]]; + if (!ghost_list.empty()) + { + WorldSafeLocsEntry const *ClosestGrave = NULL; + for (std::vector::const_iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr) + { + Player* plr = objmgr.GetPlayer(*itr); + if (!plr) + continue; + + if (!ClosestGrave) // cache + ClosestGrave = GetClosestGraveYard(plr); + + if (ClosestGrave) + plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation()); + } + } + + if (m_BgCreatures[node]) + DelCreature(node); + + // buff object isn't despawned +} + +/* Invoked if a player used a banner as a gameobject */ +void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*target_obj*/) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + uint8 node = BG_AB_NODE_STABLES; + GameObject* obj=GetBgMap()->GetGameObject(m_BgObjects[node*8+7]); + while ((node < BG_AB_DYNAMIC_NODES_COUNT) && ((!obj) || (!source->IsWithinDistInMap(obj,10)))) + { + ++node; + obj=GetBgMap()->GetGameObject(m_BgObjects[node*8+BG_AB_OBJECT_AURA_CONTESTED]); + } + + if (node == BG_AB_DYNAMIC_NODES_COUNT) + { + // this means our player isn't close to any of banners - maybe cheater ?? + return; + } + + BattleGroundTeamId teamIndex = GetTeamIndexByTeamId(source->GetTeam()); + + // Check if player really could use this banner, not cheated + if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2)) + return; + + source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); + uint32 sound = 0; + // If node is neutral, change to contested + if (m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL) + { + UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1); + m_prevNodes[node] = m_Nodes[node]; + m_Nodes[node] = teamIndex + 1; + // burn current neutral banner + _DelBanner(node, BG_AB_NODE_TYPE_NEUTRAL, 0); + // create new contested banner + _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true); + _SendNodeUpdate(node); + m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; + + // FIXME: team and node names not localized + if (teamIndex == 0) + SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node), LANG_BG_AB_ALLY); + else + SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node), LANG_BG_AB_HORDE); + + sound = BG_AB_SOUND_NODE_CLAIMED; + } + // If node is contested + else if ((m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED)) + { + // If last state is NOT occupied, change node to enemy-contested + if (m_prevNodes[node] < BG_AB_NODE_TYPE_OCCUPIED) + { + UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1); + m_prevNodes[node] = m_Nodes[node]; + m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED; + // burn current contested banner + _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex); + // create new contested banner + _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true); + _SendNodeUpdate(node); + m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; + + // FIXME: node names not localized + if (teamIndex == BG_TEAM_ALLIANCE) + SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); + else + SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); + } + // If contested, change back to occupied + else + { + UpdatePlayerScore(source, SCORE_BASES_DEFENDED, 1); + m_prevNodes[node] = m_Nodes[node]; + m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_OCCUPIED; + // burn current contested banner + _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex); + // create new occupied banner + _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true); + _SendNodeUpdate(node); + m_NodeTimers[node] = 0; + _NodeOccupied(node,(teamIndex == BG_TEAM_ALLIANCE) ? ALLIANCE:HORDE); + + // FIXME: node names not localized + if (teamIndex == BG_TEAM_ALLIANCE) + SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); + else + SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); + } + sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE; + } + // If node is occupied, change to enemy-contested + else + { + UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1); + m_prevNodes[node] = m_Nodes[node]; + m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED; + // burn current occupied banner + _DelBanner(node, BG_AB_NODE_TYPE_OCCUPIED, !teamIndex); + // create new contested banner + _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true); + _SendNodeUpdate(node); + _NodeDeOccupied(node); + m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; + + // FIXME: node names not localized + if (teamIndex == BG_TEAM_ALLIANCE) + SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); + else + SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); + + sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE; + } + + // If node is occupied again, send "X has taken the Y" msg. + if (m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED) + { + // FIXME: team and node names not localized + if (teamIndex == BG_TEAM_ALLIANCE) + SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, LANG_BG_AB_ALLY, _GetNodeNameId(node)); + else + SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE, NULL, LANG_BG_AB_HORDE, _GetNodeNameId(node)); + } + PlaySoundToAll(sound); +} + +bool BattleGroundAB::SetupBattleGround() +{ + for (int i = 0 ; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) + { + if (!AddObject(BG_AB_OBJECT_BANNER_NEUTRAL + 8*i,BG_AB_OBJECTID_NODE_BANNER_0 + i,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AB_OBJECT_BANNER_CONT_A + 8*i,BG_AB_OBJECTID_BANNER_CONT_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AB_OBJECT_BANNER_CONT_H + 8*i,BG_AB_OBJECTID_BANNER_CONT_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AB_OBJECT_BANNER_ALLY + 8*i,BG_AB_OBJECTID_BANNER_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AB_OBJECT_BANNER_HORDE + 8*i,BG_AB_OBJECTID_BANNER_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AB_OBJECT_AURA_ALLY + 8*i,BG_AB_OBJECTID_AURA_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AB_OBJECT_AURA_HORDE + 8*i,BG_AB_OBJECTID_AURA_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AB_OBJECT_AURA_CONTESTED + 8*i,BG_AB_OBJECTID_AURA_C,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY) +) + { + sLog.outErrorDb("BatteGroundAB: Failed to spawn some object BattleGround not created!"); + return false; + } + } + if (!AddObject(BG_AB_OBJECT_GATE_A,BG_AB_OBJECTID_GATE_A,BG_AB_DoorPositions[0][0],BG_AB_DoorPositions[0][1],BG_AB_DoorPositions[0][2],BG_AB_DoorPositions[0][3],BG_AB_DoorPositions[0][4],BG_AB_DoorPositions[0][5],BG_AB_DoorPositions[0][6],BG_AB_DoorPositions[0][7],RESPAWN_IMMEDIATELY) + || !AddObject(BG_AB_OBJECT_GATE_H,BG_AB_OBJECTID_GATE_H,BG_AB_DoorPositions[1][0],BG_AB_DoorPositions[1][1],BG_AB_DoorPositions[1][2],BG_AB_DoorPositions[1][3],BG_AB_DoorPositions[1][4],BG_AB_DoorPositions[1][5],BG_AB_DoorPositions[1][6],BG_AB_DoorPositions[1][7],RESPAWN_IMMEDIATELY) +) + { + sLog.outErrorDb("BatteGroundAB: Failed to spawn door object BattleGround not created!"); + return false; + } + //buffs + for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) + { + if (!AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i, Buff_Entries[0], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY) + || !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 1, Buff_Entries[1], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY) + || !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 2, Buff_Entries[2], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY) +) + sLog.outErrorDb("BatteGroundAB: Failed to spawn buff object!"); + } + + return true; +} + +void BattleGroundAB::Reset() +{ + //call parent's class reset + BattleGround::Reset(); + + m_TeamScores[BG_TEAM_ALLIANCE] = 0; + m_TeamScores[BG_TEAM_HORDE] = 0; + m_lastTick[BG_TEAM_ALLIANCE] = 0; + m_lastTick[BG_TEAM_HORDE] = 0; + m_HonorScoreTics[BG_TEAM_ALLIANCE] = 0; + m_HonorScoreTics[BG_TEAM_HORDE] = 0; + m_ReputationScoreTics[BG_TEAM_ALLIANCE] = 0; + m_ReputationScoreTics[BG_TEAM_HORDE] = 0; + m_IsInformedNearVictory = false; + bool isBGWeekend = sBattleGroundMgr.IsBGWeekend(GetTypeID()); + m_HonorTics = (isBGWeekend) ? BG_AB_ABBGWeekendHonorTicks : BG_AB_NotABBGWeekendHonorTicks; + m_ReputationTics = (isBGWeekend) ? BG_AB_ABBGWeekendReputationTicks : BG_AB_NotABBGWeekendReputationTicks; + m_TeamScores500Disadvantage[BG_TEAM_ALLIANCE] = false; + m_TeamScores500Disadvantage[BG_TEAM_HORDE] = false; + + for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) + { + m_Nodes[i] = 0; + m_prevNodes[i] = 0; + m_NodeTimers[i] = 0; + m_BannerTimers[i].timer = 0; + } + + for (uint8 i = 0; i < BG_AB_ALL_NODES_COUNT + 5; ++i)//+5 for aura triggers + if (m_BgCreatures[i]) + DelCreature(i); +} + +void BattleGroundAB::EndBattleGround(uint32 winner) +{ + //win reward + if (winner == ALLIANCE) + RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); + if (winner == HORDE) + RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); + //complete map_end rewards (even if no team wins) + RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); + RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); + + BattleGround::EndBattleGround(winner); +} + +WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player) +{ + BattleGroundTeamId teamIndex = GetTeamIndexByTeamId(player->GetTeam()); + + // Is there any occupied node for this team? + std::vector nodes; + for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) + if (m_Nodes[i] == teamIndex + 3) + nodes.push_back(i); + + WorldSafeLocsEntry const* good_entry = NULL; + // If so, select the closest node to place ghost on + if (!nodes.empty()) + { + float plr_x = player->GetPositionX(); + float plr_y = player->GetPositionY(); + + float mindist = 999999.0f; + for (uint8 i = 0; i < nodes.size(); ++i) + { + WorldSafeLocsEntry const*entry = sWorldSafeLocsStore.LookupEntry(BG_AB_GraveyardIds[nodes[i]]); + if (!entry) + continue; + float dist = (entry->x - plr_x)*(entry->x - plr_x)+(entry->y - plr_y)*(entry->y - plr_y); + if (mindist > dist) + { + mindist = dist; + good_entry = entry; + } + } + nodes.clear(); + } + // If not, place ghost on starting location + if (!good_entry) + good_entry = sWorldSafeLocsStore.LookupEntry(BG_AB_GraveyardIds[teamIndex+5]); + + return good_entry; +} + +void BattleGroundAB::UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor) +{ + BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); + if (itr == m_PlayerScores.end()) // player not found... + return; + + switch(type) + { + case SCORE_BASES_ASSAULTED: + ((BattleGroundABScore*)itr->second)->BasesAssaulted += value; + break; + case SCORE_BASES_DEFENDED: + ((BattleGroundABScore*)itr->second)->BasesDefended += value; + break; + default: + BattleGround::UpdatePlayerScore(Source,type,value, doAddHonor); + break; + } +} + +bool BattleGroundAB::IsAllNodesConrolledByTeam(uint32 team) const +{ + uint32 count = 0; + for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) + if ((team == ALLIANCE && m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED) || + (team == HORDE && m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)) + ++count; + + return count == BG_AB_DYNAMIC_NODES_COUNT; +} diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundAB.h b/src/server/game/BattleGrounds/Zones/BattleGroundAB.h new file mode 100644 index 00000000000..3072f8beafd --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundAB.h @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __BATTLEGROUNDAB_H +#define __BATTLEGROUNDAB_H + +class BattleGround; + +enum BG_AB_WorldStates +{ + BG_AB_OP_OCCUPIED_BASES_HORDE = 1778, + BG_AB_OP_OCCUPIED_BASES_ALLY = 1779, + BG_AB_OP_RESOURCES_ALLY = 1776, + BG_AB_OP_RESOURCES_HORDE = 1777, + BG_AB_OP_RESOURCES_MAX = 1780, + BG_AB_OP_RESOURCES_WARNING = 1955 +/* + BG_AB_OP_STABLE_ICON = 1842, //Stable map icon (NONE) + BG_AB_OP_STABLE_STATE_ALIENCE = 1767, //Stable map state (ALIENCE) + BG_AB_OP_STABLE_STATE_HORDE = 1768, //Stable map state (HORDE) + BG_AB_OP_STABLE_STATE_CON_ALI = 1769, //Stable map state (CON ALIENCE) + BG_AB_OP_STABLE_STATE_CON_HOR = 1770, //Stable map state (CON HORDE) + BG_AB_OP_FARM_ICON = 1845, //Farm map icon (NONE) + BG_AB_OP_FARM_STATE_ALIENCE = 1772, //Farm state (ALIENCE) + BG_AB_OP_FARM_STATE_HORDE = 1773, //Farm state (HORDE) + BG_AB_OP_FARM_STATE_CON_ALI = 1774, //Farm state (CON ALIENCE) + BG_AB_OP_FARM_STATE_CON_HOR = 1775, //Farm state (CON HORDE) + + BG_AB_OP_BLACKSMITH_ICON = 1846, //Blacksmith map icon (NONE) + BG_AB_OP_BLACKSMITH_STATE_ALIENCE = 1782, //Blacksmith map state (ALIENCE) + BG_AB_OP_BLACKSMITH_STATE_HORDE = 1783, //Blacksmith map state (HORDE) + BG_AB_OP_BLACKSMITH_STATE_CON_ALI = 1784, //Blacksmith map state (CON ALIENCE) + BG_AB_OP_BLACKSMITH_STATE_CON_HOR = 1785, //Blacksmith map state (CON HORDE) + BG_AB_OP_LUMBERMILL_ICON = 1844, //Lumber Mill map icon (NONE) + BG_AB_OP_LUMBERMILL_STATE_ALIENCE = 1792, //Lumber Mill map state (ALIENCE) + BG_AB_OP_LUMBERMILL_STATE_HORDE = 1793, //Lumber Mill map state (HORDE) + BG_AB_OP_LUMBERMILL_STATE_CON_ALI = 1794, //Lumber Mill map state (CON ALIENCE) + BG_AB_OP_LUMBERMILL_STATE_CON_HOR = 1795, //Lumber Mill map state (CON HORDE) + BG_AB_OP_GOLDMINE_ICON = 1843, //Gold Mine map icon (NONE) + BG_AB_OP_GOLDMINE_STATE_ALIENCE = 1787, //Gold Mine map state (ALIENCE) + BG_AB_OP_GOLDMINE_STATE_HORDE = 1788, //Gold Mine map state (HORDE) + BG_AB_OP_GOLDMINE_STATE_CON_ALI = 1789, //Gold Mine map state (CON ALIENCE + BG_AB_OP_GOLDMINE_STATE_CON_HOR = 1790, //Gold Mine map state (CON HORDE) +*/ +}; + +const uint32 BG_AB_OP_NODESTATES[5] = {1767, 1782, 1772, 1792, 1787}; + +const uint32 BG_AB_OP_NODEICONS[5] = {1842, 1846, 1845, 1844, 1843}; + +/* Note: code uses that these IDs follow each other */ +enum BG_AB_NodeObjectId +{ + BG_AB_OBJECTID_NODE_BANNER_0 = 180087, // Stables banner + BG_AB_OBJECTID_NODE_BANNER_1 = 180088, // Blacksmith banner + BG_AB_OBJECTID_NODE_BANNER_2 = 180089, // Farm banner + BG_AB_OBJECTID_NODE_BANNER_3 = 180090, // Lumber mill banner + BG_AB_OBJECTID_NODE_BANNER_4 = 180091 // Gold mine banner +}; + +enum BG_AB_ObjectType +{ + // for all 5 node points 8*5=40 objects + BG_AB_OBJECT_BANNER_NEUTRAL = 0, + BG_AB_OBJECT_BANNER_CONT_A = 1, + BG_AB_OBJECT_BANNER_CONT_H = 2, + BG_AB_OBJECT_BANNER_ALLY = 3, + BG_AB_OBJECT_BANNER_HORDE = 4, + BG_AB_OBJECT_AURA_ALLY = 5, + BG_AB_OBJECT_AURA_HORDE = 6, + BG_AB_OBJECT_AURA_CONTESTED = 7, + //gates + BG_AB_OBJECT_GATE_A = 40, + BG_AB_OBJECT_GATE_H = 41, + //buffs + BG_AB_OBJECT_SPEEDBUFF_STABLES = 42, + BG_AB_OBJECT_REGENBUFF_STABLES = 43, + BG_AB_OBJECT_BERSERKBUFF_STABLES = 44, + BG_AB_OBJECT_SPEEDBUFF_BLACKSMITH = 45, + BG_AB_OBJECT_REGENBUFF_BLACKSMITH = 46, + BG_AB_OBJECT_BERSERKBUFF_BLACKSMITH = 47, + BG_AB_OBJECT_SPEEDBUFF_FARM = 48, + BG_AB_OBJECT_REGENBUFF_FARM = 49, + BG_AB_OBJECT_BERSERKBUFF_FARM = 50, + BG_AB_OBJECT_SPEEDBUFF_LUMBER_MILL = 51, + BG_AB_OBJECT_REGENBUFF_LUMBER_MILL = 52, + BG_AB_OBJECT_BERSERKBUFF_LUMBER_MILL = 53, + BG_AB_OBJECT_SPEEDBUFF_GOLD_MINE = 54, + BG_AB_OBJECT_REGENBUFF_GOLD_MINE = 55, + BG_AB_OBJECT_BERSERKBUFF_GOLD_MINE = 56, + BG_AB_OBJECT_MAX = 57, +}; + +/* Object id templates from DB */ +enum BG_AB_ObjectTypes +{ + BG_AB_OBJECTID_BANNER_A = 180058, + BG_AB_OBJECTID_BANNER_CONT_A = 180059, + BG_AB_OBJECTID_BANNER_H = 180060, + BG_AB_OBJECTID_BANNER_CONT_H = 180061, + + BG_AB_OBJECTID_AURA_A = 180100, + BG_AB_OBJECTID_AURA_H = 180101, + BG_AB_OBJECTID_AURA_C = 180102, + + BG_AB_OBJECTID_GATE_A = 180255, + BG_AB_OBJECTID_GATE_H = 180256 +}; + +enum BG_AB_Timers +{ + BG_AB_FLAG_CAPTURING_TIME = 60000, +}; + +enum BG_AB_Score +{ + BG_AB_WARNING_NEAR_VICTORY_SCORE = 1400, + BG_AB_MAX_TEAM_SCORE = 1600 +}; + +/* do NOT change the order, else wrong behaviour */ +enum BG_AB_BattleGroundNodes +{ + BG_AB_NODE_STABLES = 0, + BG_AB_NODE_BLACKSMITH = 1, + BG_AB_NODE_FARM = 2, + BG_AB_NODE_LUMBER_MILL = 3, + BG_AB_NODE_GOLD_MINE = 4, + + BG_AB_DYNAMIC_NODES_COUNT = 5, // dynamic nodes that can be captured + + BG_AB_SPIRIT_ALIANCE = 5, + BG_AB_SPIRIT_HORDE = 6, + + BG_AB_ALL_NODES_COUNT = 7, // all nodes (dynamic and static) +}; + +enum BG_AB_NodeStatus +{ + BG_AB_NODE_TYPE_NEUTRAL = 0, + BG_AB_NODE_TYPE_CONTESTED = 1, + BG_AB_NODE_STATUS_ALLY_CONTESTED = 1, + BG_AB_NODE_STATUS_HORDE_CONTESTED = 2, + BG_AB_NODE_TYPE_OCCUPIED = 3, + BG_AB_NODE_STATUS_ALLY_OCCUPIED = 3, + BG_AB_NODE_STATUS_HORDE_OCCUPIED = 4 +}; + +enum BG_AB_Sounds +{ + BG_AB_SOUND_NODE_CLAIMED = 8192, + BG_AB_SOUND_NODE_CAPTURED_ALLIANCE = 8173, + BG_AB_SOUND_NODE_CAPTURED_HORDE = 8213, + BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE = 8212, + BG_AB_SOUND_NODE_ASSAULTED_HORDE = 8174, + BG_AB_SOUND_NEAR_VICTORY = 8456 +}; + +#define BG_AB_NotABBGWeekendHonorTicks 330 +#define BG_AB_ABBGWeekendHonorTicks 200 +#define BG_AB_NotABBGWeekendReputationTicks 200 +#define BG_AB_ABBGWeekendReputationTicks 150 + +// x, y, z, o +const float BG_AB_NodePositions[BG_AB_DYNAMIC_NODES_COUNT][4] = { + {1166.785f, 1200.132f, -56.70859f, 0.9075713f}, // stables + {977.0156f, 1046.616f, -44.80923f, -2.600541f}, // blacksmith + {806.1821f, 874.2723f, -55.99371f, -2.303835f}, // farm + {856.1419f, 1148.902f, 11.18469f, -2.303835f}, // lumber mill + {1146.923f, 848.1782f, -110.917f, -0.7330382f} // gold mine +}; + +// x, y, z, o, rot0, rot1, rot2, rot3 +const float BG_AB_DoorPositions[2][8] = { + {1284.597f, 1281.167f, -15.97792f, 0.7068594f, 0.012957f, -0.060288f, 0.344959f, 0.93659f}, + {708.0903f, 708.4479f, -17.8342f, -2.391099f, 0.050291f, 0.015127f, 0.929217f, -0.365784f} +}; + +// Tick intervals and given points: case 0,1,2,3,4,5 captured nodes +const uint32 BG_AB_TickIntervals[6] = {0, 12000, 9000, 6000, 3000, 1000}; +const uint32 BG_AB_TickPoints[6] = {0, 10, 10, 10, 10, 30}; + +// WorldSafeLocs ids for 5 nodes, and for ally, and horde starting location +const uint32 BG_AB_GraveyardIds[BG_AB_ALL_NODES_COUNT] = {895, 894, 893, 897, 896, 898, 899}; + +// x, y, z, o +const float BG_AB_BuffPositions[BG_AB_DYNAMIC_NODES_COUNT][4] = { + {1185.71f, 1185.24f, -56.36f, 2.56f}, // stables + {990.75f, 1008.18f, -42.60f, 2.43f}, // blacksmith + {817.66f, 843.34f, -56.54f, 3.01f}, // farm + {807.46f, 1189.16f, 11.92f, 5.44f}, // lumber mill + {1146.62f, 816.94f, -98.49f, 6.14f} // gold mine +}; + +// x, y, z, o +const float BG_AB_SpiritGuidePos[BG_AB_ALL_NODES_COUNT][4] = { + {1200.03f, 1171.09f, -56.47f, 5.15f}, // stables + {1017.43f, 960.61f, -42.95f, 4.88f}, // blacksmith + {833.00f, 793.00f, -57.25f, 5.27f}, // farm + {775.17f, 1206.40f, 15.79f, 1.90f}, // lumber mill + {1207.48f, 787.00f, -83.36f, 5.51f}, // gold mine + {1354.05f, 1275.48f, -11.30f, 4.77f}, // alliance starting base + {714.61f, 646.15f, -10.87f, 4.34f} // horde starting base +}; + +struct BG_AB_BannerTimer +{ + uint32 timer; + uint8 type; + uint8 teamIndex; +}; + +class BattleGroundABScore : public BattleGroundScore +{ + public: + BattleGroundABScore(): BasesAssaulted(0), BasesDefended(0) {}; + virtual ~BattleGroundABScore() {}; + uint32 BasesAssaulted; + uint32 BasesDefended; +}; + +class BattleGroundAB : public BattleGround +{ + friend class BattleGroundMgr; + + public: + BattleGroundAB(); + ~BattleGroundAB(); + + void Update(uint32 diff); + void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + void RemovePlayer(Player *plr,uint64 guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + virtual bool SetupBattleGround(); + virtual void Reset(); + void EndBattleGround(uint32 winner); + virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); + + /* Scorekeeping */ + virtual void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); + + virtual void FillInitialWorldStates(WorldPacket& data); + + /* Nodes occupying */ + virtual void EventPlayerClickedOnFlag(Player *source, GameObject* target_obj); + + /* achievement req. */ + bool IsAllNodesConrolledByTeam(uint32 team) const; // overwrited + bool IsTeamScores500Disadvantage(uint32 team) const { return m_TeamScores500Disadvantage[GetTeamIndexByTeamId(team)]; } + private: + /* Gameobject spawning/despawning */ + void _CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay); + void _DelBanner(uint8 node, uint8 type, uint8 teamIndex); + void _SendNodeUpdate(uint8 node); + + /* Creature spawning/despawning */ + // TODO: working, scripted peons spawning + void _NodeOccupied(uint8 node,Team team); + void _NodeDeOccupied(uint8 node); + + int32 _GetNodeNameId(uint8 node); + + /* Nodes info: + 0: neutral + 1: ally contested + 2: horde contested + 3: ally occupied + 4: horde occupied */ + uint8 m_Nodes[BG_AB_DYNAMIC_NODES_COUNT]; + uint8 m_prevNodes[BG_AB_DYNAMIC_NODES_COUNT]; + BG_AB_BannerTimer m_BannerTimers[BG_AB_DYNAMIC_NODES_COUNT]; + uint32 m_NodeTimers[BG_AB_DYNAMIC_NODES_COUNT]; + uint32 m_lastTick[BG_TEAMS_COUNT]; + uint32 m_HonorScoreTics[BG_TEAMS_COUNT]; + uint32 m_ReputationScoreTics[BG_TEAMS_COUNT]; + bool m_IsInformedNearVictory; + uint32 m_HonorTics; + uint32 m_ReputationTics; + // need for achievements + bool m_TeamScores500Disadvantage[BG_TEAMS_COUNT]; +}; +#endif + diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundAV.cpp b/src/server/game/BattleGrounds/Zones/BattleGroundAV.cpp new file mode 100644 index 00000000000..7f5482cbf16 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundAV.cpp @@ -0,0 +1,1490 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ObjectMgr.h" +#include "WorldPacket.h" + +#include "BattleGround.h" +#include "BattleGroundAV.h" +#include "Formulas.h" +#include "GameObject.h" +#include "Language.h" +#include "Player.h" +#include "SpellAuras.h" + +BattleGroundAV::BattleGroundAV() +{ + m_BgObjects.resize(BG_AV_OBJECT_MAX); + m_BgCreatures.resize(AV_CPLACE_MAX+AV_STATICCPLACE_MAX); + + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_AV_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AV_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AV_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AV_HAS_BEGUN; +} + +BattleGroundAV::~BattleGroundAV() +{ +} + +const uint16 BattleGroundAV::GetBonusHonor(uint8 kills) //TODO: move this function to Battleground.cpp (needs to find a way to get m_MaxLevel) +{ + return Trinity::Honor::hk_honor_at_level(m_MaxLevel, kills); +} + +void BattleGroundAV::HandleKillPlayer(Player *player, Player *killer) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + BattleGround::HandleKillPlayer(player, killer); + UpdateScore(player->GetTeam(),-1); +} + +void BattleGroundAV::HandleKillUnit(Creature *unit, Player *killer) +{ + sLog.outDebug("bg_av HandleKillUnit %i",unit->GetEntry()); + if (GetStatus() != STATUS_IN_PROGRESS) + return; + uint32 entry = unit->GetEntry(); + /* + uint32 triggerSpawnID = 0; + if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0]) + triggerSpawnID = AV_CPLACE_TRIGGER16; + else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_BOSS][0]) + triggerSpawnID = AV_CPLACE_TRIGGER17; + else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN][0]) + triggerSpawnID = AV_CPLACE_TRIGGER18; + else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_BOSS][0]) + triggerSpawnID = AV_CPLACE_TRIGGER19; + */ + if (entry == BG_AV_CreatureInfo[AV_NPC_A_BOSS][0]) + { + CastSpellOnTeam(23658,HORDE); //this is a spell which finishes a quest where a player has to kill the boss + RewardReputationToTeam(729,BG_AV_REP_BOSS,HORDE); + RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_BOSS),HORDE); + EndBattleGround(HORDE); + DelCreature(AV_CPLACE_TRIGGER17); + } + else if (entry == BG_AV_CreatureInfo[AV_NPC_H_BOSS][0]) + { + CastSpellOnTeam(23658,ALLIANCE); //this is a spell which finishes a quest where a player has to kill the boss + RewardReputationToTeam(730,BG_AV_REP_BOSS,ALLIANCE); + RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_BOSS),ALLIANCE); + EndBattleGround(ALLIANCE); + DelCreature(AV_CPLACE_TRIGGER19); + } + else if (entry == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0]) + { + if (!m_CaptainAlive[0]) + { + sLog.outError("Killed a Captain twice, please report this bug, if you haven't done \".respawn\""); + return; + } + m_CaptainAlive[0]=false; + RewardReputationToTeam(729,BG_AV_REP_CAPTAIN,HORDE); + RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_CAPTAIN),HORDE); + UpdateScore(ALLIANCE,(-1)*BG_AV_RES_CAPTAIN); + //spawn destroyed aura + for (uint8 i=0; i <= 9; i++) + SpawnBGObject(BG_AV_OBJECT_BURN_BUILDING_ALLIANCE+i,RESPAWN_IMMEDIATELY); + Creature* creature = GetBGCreature(AV_CPLACE_HERALD); + if (creature) + YellToAll(creature,GetTrinityString(LANG_BG_AV_A_CAPTAIN_DEAD),LANG_UNIVERSAL); + DelCreature(AV_CPLACE_TRIGGER16); + } + else if (entry == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN][0]) + { + if (!m_CaptainAlive[1]) + { + sLog.outError("Killed a Captain twice, please report this bug, if you haven't done \".respawn\""); + return; + } + m_CaptainAlive[1]=false; + RewardReputationToTeam(730,BG_AV_REP_CAPTAIN,ALLIANCE); + RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_CAPTAIN),ALLIANCE); + UpdateScore(HORDE,(-1)*BG_AV_RES_CAPTAIN); + //spawn destroyed aura + for (uint8 i=0; i <= 9; i++) + SpawnBGObject(BG_AV_OBJECT_BURN_BUILDING_HORDE+i,RESPAWN_IMMEDIATELY); + Creature* creature = GetBGCreature(AV_CPLACE_HERALD); + if (creature) + YellToAll(creature,GetTrinityString(LANG_BG_AV_H_CAPTAIN_DEAD),LANG_UNIVERSAL); + DelCreature(AV_CPLACE_TRIGGER18); + } + else if (entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_N_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_A_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_H_4][0]) + ChangeMineOwner(AV_NORTH_MINE,killer->GetTeam()); + else if (entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_N_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_A_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_H_4][0]) + ChangeMineOwner(AV_SOUTH_MINE,killer->GetTeam()); +} + +void BattleGroundAV::HandleQuestComplete(uint32 questid, Player *player) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return;//maybe we should log this, cause this must be a cheater or a big bug + uint8 team = GetTeamIndexByTeamId(player->GetTeam()); + //TODO add reputation, events (including quest not available anymore, next quest availabe, go/npc de/spawning)and maybe honor + sLog.outDebug("BG_AV Quest %i completed",questid); + switch(questid) + { + case AV_QUEST_A_SCRAPS1: + case AV_QUEST_A_SCRAPS2: + case AV_QUEST_H_SCRAPS1: + case AV_QUEST_H_SCRAPS2: + m_Team_QuestStatus[team][0]+=20; + if (m_Team_QuestStatus[team][0] == 500 || m_Team_QuestStatus[team][0] == 1000 || m_Team_QuestStatus[team][0] == 1500) //25,50,75 turn ins + { + sLog.outDebug("BG_AV Quest %i completed starting with unit upgrading..",questid); + for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i) + if (m_Nodes[i].Owner == player->GetTeam() && m_Nodes[i].State == POINT_CONTROLED) + { + DePopulateNode(i); + PopulateNode(i); + //maybe this is bad, because it will instantly respawn all creatures on every grave.. + } + } + break; + case AV_QUEST_A_COMMANDER1: + case AV_QUEST_H_COMMANDER1: + m_Team_QuestStatus[team][1]++; + RewardReputationToTeam(team,1,player->GetTeam()); + if (m_Team_QuestStatus[team][1] == 30) + sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); + break; + case AV_QUEST_A_COMMANDER2: + case AV_QUEST_H_COMMANDER2: + m_Team_QuestStatus[team][2]++; + RewardReputationToTeam(team,1,player->GetTeam()); + if (m_Team_QuestStatus[team][2] == 60) + sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); + break; + case AV_QUEST_A_COMMANDER3: + case AV_QUEST_H_COMMANDER3: + m_Team_QuestStatus[team][3]++; + RewardReputationToTeam(team,1,player->GetTeam()); + if (m_Team_QuestStatus[team][1] == 120) + sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); + break; + case AV_QUEST_A_BOSS1: + case AV_QUEST_H_BOSS1: + m_Team_QuestStatus[team][4] += 9; //you can turn in 10 or 1 item.. + case AV_QUEST_A_BOSS2: + case AV_QUEST_H_BOSS2: + m_Team_QuestStatus[team][4]++; + if (m_Team_QuestStatus[team][4] >= 200) + sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); + break; + case AV_QUEST_A_NEAR_MINE: + case AV_QUEST_H_NEAR_MINE: + m_Team_QuestStatus[team][5]++; + if (m_Team_QuestStatus[team][5] == 28) + { + sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); + if (m_Team_QuestStatus[team][6] == 7) + sLog.outDebug("BG_AV Quest %i completed (need to implement some events here - ground assault ready",questid); + } + break; + case AV_QUEST_A_OTHER_MINE: + case AV_QUEST_H_OTHER_MINE: + m_Team_QuestStatus[team][6]++; + if (m_Team_QuestStatus[team][6] == 7) + { + sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); + if (m_Team_QuestStatus[team][5] == 20) + sLog.outDebug("BG_AV Quest %i completed (need to implement some events here - ground assault ready",questid); + } + break; + case AV_QUEST_A_RIDER_HIDE: + case AV_QUEST_H_RIDER_HIDE: + m_Team_QuestStatus[team][7]++; + if (m_Team_QuestStatus[team][7] == 25) + { + sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); + if (m_Team_QuestStatus[team][8] == 25) + sLog.outDebug("BG_AV Quest %i completed (need to implement some events here - rider assault ready",questid); + } + break; + case AV_QUEST_A_RIDER_TAME: + case AV_QUEST_H_RIDER_TAME: + m_Team_QuestStatus[team][8]++; + if (m_Team_QuestStatus[team][8] == 25) + { + sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid); + if (m_Team_QuestStatus[team][7] == 25) + sLog.outDebug("BG_AV Quest %i completed (need to implement some events here - rider assault ready",questid); + } + break; + default: + sLog.outDebug("BG_AV Quest %i completed but is not interesting at all",questid); + return; //was no interesting quest at all + break; + } +} + +void BattleGroundAV::UpdateScore(uint16 team, int16 points) +{ //note: to remove reinforcementpoints points must be negative, for adding reinforcements points must be positive + assert(team == ALLIANCE || team == HORDE); + uint8 teamindex = GetTeamIndexByTeamId(team); //0=ally 1=horde + m_Team_Scores[teamindex] += points; + + UpdateWorldState(((teamindex == BG_TEAM_HORDE)?AV_Horde_Score:AV_Alliance_Score), m_Team_Scores[teamindex]); + if (points < 0) + { + if (m_Team_Scores[teamindex] < 1) + { + m_Team_Scores[teamindex]=0; + EndBattleGround(((teamindex == BG_TEAM_HORDE)?ALLIANCE:HORDE)); + } + else if (!m_IsInformedNearVictory[teamindex] && m_Team_Scores[teamindex] < SEND_MSG_NEAR_LOSE) + { + SendMessageToAll(teamindex == BG_TEAM_HORDE?LANG_BG_AV_H_NEAR_LOSE:LANG_BG_AV_A_NEAR_LOSE, teamindex == BG_TEAM_HORDE ? CHAT_MSG_BG_SYSTEM_HORDE : CHAT_MSG_BG_SYSTEM_ALLIANCE); + PlaySoundToAll(AV_SOUND_NEAR_VICTORY); + m_IsInformedNearVictory[teamindex] = true; + } + } +} + +Creature* BattleGroundAV::AddAVCreature(uint16 cinfoid, uint16 type) +{ + uint8 level; + bool isStatic = false; + Creature* creature = NULL; + assert(type <= AV_CPLACE_MAX + AV_STATICCPLACE_MAX); + if (type >= AV_CPLACE_MAX) //static + { + type -= AV_CPLACE_MAX; + cinfoid=uint16(BG_AV_StaticCreaturePos[type][4]); + creature = AddCreature(BG_AV_StaticCreatureInfo[cinfoid][0],(type+AV_CPLACE_MAX),BG_AV_StaticCreatureInfo[cinfoid][1],BG_AV_StaticCreaturePos[type][0],BG_AV_StaticCreaturePos[type][1],BG_AV_StaticCreaturePos[type][2],BG_AV_StaticCreaturePos[type][3]); + level = (BG_AV_StaticCreatureInfo[cinfoid][2] == BG_AV_StaticCreatureInfo[cinfoid][3]) ? BG_AV_StaticCreatureInfo[cinfoid][2] : urand(BG_AV_StaticCreatureInfo[cinfoid][2],BG_AV_StaticCreatureInfo[cinfoid][3]); + isStatic = true; + } + else + { + creature = AddCreature(BG_AV_CreatureInfo[cinfoid][0],type,BG_AV_CreatureInfo[cinfoid][1],BG_AV_CreaturePos[type][0],BG_AV_CreaturePos[type][1],BG_AV_CreaturePos[type][2],BG_AV_CreaturePos[type][3]); + level = (BG_AV_CreatureInfo[cinfoid][2] == BG_AV_CreatureInfo[cinfoid][3]) ? BG_AV_CreatureInfo[cinfoid][2] : urand(BG_AV_CreatureInfo[cinfoid][2],BG_AV_CreatureInfo[cinfoid][3]); + } + if (!creature) + return NULL; + if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0] || creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN][0]) + creature->SetRespawnDelay(RESPAWN_ONE_DAY); // TODO: look if this can be done by database + also add this for the wingcommanders + + if ((isStatic && cinfoid >= 10 && cinfoid <= 14) || (!isStatic && ((cinfoid >= AV_NPC_A_GRAVEDEFENSE0 && cinfoid <= AV_NPC_A_GRAVEDEFENSE3) || + (cinfoid >= AV_NPC_H_GRAVEDEFENSE0 && cinfoid <= AV_NPC_H_GRAVEDEFENSE3)))) + { + if (!isStatic && ((cinfoid >= AV_NPC_A_GRAVEDEFENSE0 && cinfoid <= AV_NPC_A_GRAVEDEFENSE3) + || (cinfoid >= AV_NPC_H_GRAVEDEFENSE0 && cinfoid <= AV_NPC_H_GRAVEDEFENSE3))) + { + CreatureData &data = objmgr.NewOrExistCreatureData(creature->GetDBTableGUIDLow()); + data.spawndist = 5; + } + //else spawndist will be 15, so creatures move maximum=10 + //creature->SetDefaultMovementType(RANDOM_MOTION_TYPE); + creature->GetMotionMaster()->Initialize(); + creature->setDeathState(JUST_DIED); + creature->Respawn(); + //TODO: find a way to add a motionmaster without killing the creature (i + //just copied this code from a gm-command + } + + if (level != 0) + level += m_MaxLevel - 60; //maybe we can do this more generic for custom level-range.. actually it's blizzlike + creature->SetLevel(level); + + uint32 triggerSpawnID = 0; + uint32 newFaction = 0; + if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0]) + { + triggerSpawnID = AV_CPLACE_TRIGGER16; + newFaction = 84; + } + else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_BOSS][0]) + { + triggerSpawnID = AV_CPLACE_TRIGGER17; + newFaction = 84; + } + else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN][0]) + { + triggerSpawnID = AV_CPLACE_TRIGGER18; + newFaction = 83; + } + else if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_BOSS][0]) + { + triggerSpawnID = AV_CPLACE_TRIGGER19; + newFaction = 83; + } + if (triggerSpawnID && newFaction) + { + if (Creature* trigger = AddCreature(WORLD_TRIGGER,triggerSpawnID,BG_AV_CreatureInfo[creature->GetEntry()][1],BG_AV_CreaturePos[triggerSpawnID][0],BG_AV_CreaturePos[triggerSpawnID][1],BG_AV_CreaturePos[triggerSpawnID][2],BG_AV_CreaturePos[triggerSpawnID][3])) + { + trigger->setFaction(newFaction); + trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false); + } + } + + return creature; +} + +void BattleGroundAV::Update(uint32 diff) +{ + BattleGround::Update(diff); + + if (GetStatus() == STATUS_IN_PROGRESS) + { + for (uint8 i=0; i <= 1; i++)//0=alliance, 1=horde + { + if (!m_CaptainAlive[i]) + continue; + if (m_CaptainBuffTimer[i] > diff) + m_CaptainBuffTimer[i] -= diff; + else + { + if (i == 0) + { + CastSpellOnTeam(AV_BUFF_A_CAPTAIN,ALLIANCE); + Creature* creature = GetBGCreature(AV_CPLACE_MAX + 61); + if (creature) + YellToAll(creature,LANG_BG_AV_A_CAPTAIN_BUFF,LANG_COMMON); + } + else + { + CastSpellOnTeam(AV_BUFF_H_CAPTAIN,HORDE); + Creature* creature = GetBGCreature(AV_CPLACE_MAX + 59); //TODO: make the captains a dynamic creature + if (creature) + YellToAll(creature,LANG_BG_AV_H_CAPTAIN_BUFF,LANG_ORCISH); + } + m_CaptainBuffTimer[i] = 120000 + urand(0,4)* 60000; //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes TODO get the right times + } + } + //add points from mine owning, and look if he neutral team wanrts to reclaim the mine + m_Mine_Timer -=diff; + for (uint8 mine=0; mine <2; mine++) + { + if (m_Mine_Owner[mine] == ALLIANCE || m_Mine_Owner[mine] == HORDE) + { + if (m_Mine_Timer <= 0) + UpdateScore(m_Mine_Owner[mine],1); + + if (m_Mine_Reclaim_Timer[mine] > diff) + m_Mine_Reclaim_Timer[mine] -= diff; + else{ //we don't need to set this timer to 0 cause this codepart wont get called when this thing is 0 + ChangeMineOwner(mine,AV_NEUTRAL_TEAM); + } + } + } + if (m_Mine_Timer <= 0) + m_Mine_Timer=AV_MINE_TICK_TIMER; //this is at the end, cause we need to update both mines + + //looks for all timers of the nodes and destroy the building (for graveyards the building wont get destroyed, it goes just to the other team + for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i) + if (m_Nodes[i].State == POINT_ASSAULTED) //maybe remove this + { + if (m_Nodes[i].Timer > diff) + m_Nodes[i].Timer -= diff; + else + EventPlayerDestroyedPoint(i); + } + } +} + +void BattleGroundAV::StartingEventCloseDoors() +{ + DoorClose(BG_AV_OBJECT_DOOR_A); + DoorClose(BG_AV_OBJECT_DOOR_H); +} + +void BattleGroundAV::StartingEventOpenDoors() +{ + sLog.outDebug("BG_AV: start spawning mine stuff"); + for (uint16 i= BG_AV_OBJECT_MINE_SUPPLY_N_MIN; i <= BG_AV_OBJECT_MINE_SUPPLY_N_MAX; i++) + SpawnBGObject(i,RESPAWN_IMMEDIATELY); + for (uint16 i= BG_AV_OBJECT_MINE_SUPPLY_S_MIN; i <= BG_AV_OBJECT_MINE_SUPPLY_S_MAX; i++) + SpawnBGObject(i,RESPAWN_IMMEDIATELY); + for (uint8 mine = AV_NORTH_MINE; mine <= AV_SOUTH_MINE; mine++) //mine population + ChangeMineOwner(mine, AV_NEUTRAL_TEAM,true); + + UpdateWorldState(AV_SHOW_H_SCORE, 1); + UpdateWorldState(AV_SHOW_A_SCORE, 1); + + DoorOpen(BG_AV_OBJECT_DOOR_H); + DoorOpen(BG_AV_OBJECT_DOOR_A); +} + +void BattleGroundAV::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map, default values are set in constructor + BattleGroundAVScore* sc = new BattleGroundAVScore; + m_PlayerScores[plr->GetGUID()] = sc; + if (m_MaxLevel == 0) + m_MaxLevel=(plr->getLevel()%10 == 0)? plr->getLevel() : (plr->getLevel()-(plr->getLevel()%10))+10; //TODO: just look at the code \^_^/ --but queue-info should provide this information.. + +} + +void BattleGroundAV::EndBattleGround(uint32 winner) +{ + //calculate bonuskills for both teams: + //first towers: + uint8 kills[2]={0,0}; //0=ally 1=horde + uint8 rep[2]={0,0}; //0=ally 1=horde + for (BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i) + { + if (m_Nodes[i].State == POINT_CONTROLED) + { + if (m_Nodes[i].Owner == ALLIANCE) + { + rep[0] += BG_AV_REP_SURVIVING_TOWER; + kills[0] += BG_AV_KILL_SURVIVING_TOWER; + } + else + { + rep[0] += BG_AV_KILL_SURVIVING_TOWER; + kills[1] += BG_AV_KILL_SURVIVING_TOWER; + } + } + } + + for (int i=0; i <= 1; i++) //0=ally 1=horde + { + if (m_CaptainAlive[i]) + { + kills[i] += BG_AV_KILL_SURVIVING_CAPTAIN; + rep[i] += BG_AV_REP_SURVIVING_CAPTAIN; + } + if (rep[i] != 0) + RewardReputationToTeam((i == 0)?730:729,rep[i],(i == 0)?ALLIANCE:HORDE); + if (kills[i] != 0) + RewardHonorToTeam(GetBonusHonor(kills[i]),(i == 0)?ALLIANCE:HORDE); + } + + //TODO add enterevademode for all attacking creatures + BattleGround::EndBattleGround(winner); +} + +void BattleGroundAV::RemovePlayer(Player* plr,uint64 /*guid*/) +{ + if (!plr) + { + sLog.outError("bg_AV no player at remove"); + return; + } + //TODO search more buffs + plr->RemoveAurasDueToSpell(AV_BUFF_ARMOR); + plr->RemoveAurasDueToSpell(AV_BUFF_A_CAPTAIN); + plr->RemoveAurasDueToSpell(AV_BUFF_H_CAPTAIN); +} + +void BattleGroundAV::HandleAreaTrigger(Player *Source, uint32 Trigger) +{ + // this is wrong way to implement these things. On official it done by gameobject spell cast. + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + uint32 SpellId = 0; + switch(Trigger) + { + case 95: + case 2608: + if (Source->GetTeam() != ALLIANCE) + Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal"); + else + Source->LeaveBattleground(); + break; + case 2606: + if (Source->GetTeam() != HORDE) + Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal"); + else + Source->LeaveBattleground(); + break; + case 3326: + case 3327: + case 3328: + case 3329: + case 3330: + case 3331: + //Source->Unmount(); + break; + default: + sLog.outDebug("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); +// Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); + break; + } + + if (SpellId) + Source->CastSpell(Source, SpellId, true); +} + +void BattleGroundAV::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) +{ + + BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); + if (itr == m_PlayerScores.end()) // player not found... + return; + + switch(type) + { + case SCORE_GRAVEYARDS_ASSAULTED: + ((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted += value; + break; + case SCORE_GRAVEYARDS_DEFENDED: + ((BattleGroundAVScore*)itr->second)->GraveyardsDefended += value; + break; + case SCORE_TOWERS_ASSAULTED: + ((BattleGroundAVScore*)itr->second)->TowersAssaulted += value; + break; + case SCORE_TOWERS_DEFENDED: + ((BattleGroundAVScore*)itr->second)->TowersDefended += value; + break; + case SCORE_MINES_CAPTURED: + ((BattleGroundAVScore*)itr->second)->MinesCaptured += value; + break; + case SCORE_LEADERS_KILLED: + ((BattleGroundAVScore*)itr->second)->LeadersKilled += value; + break; + case SCORE_SECONDARY_OBJECTIVES: + ((BattleGroundAVScore*)itr->second)->SecondaryObjectives += value; + break; + default: + BattleGround::UpdatePlayerScore(Source,type,value, doAddHonor); + break; + } +} + +void BattleGroundAV::EventPlayerDestroyedPoint(BG_AV_Nodes node) +{ + + uint32 object = GetObjectThroughNode(node); + sLog.outDebug("bg_av: player destroyed point node %i object %i",node,object); + + //despawn banner + SpawnBGObject(object, RESPAWN_ONE_DAY); + DestroyNode(node); + UpdateNodeWorldState(node); + + uint32 owner = m_Nodes[node].Owner; + if (IsTower(node)) + { + uint8 tmp = node-BG_AV_NODES_DUNBALDAR_SOUTH; + //despawn marshal + if (m_BgCreatures[AV_CPLACE_A_MARSHAL_SOUTH + tmp]) + DelCreature(AV_CPLACE_A_MARSHAL_SOUTH + tmp); + else + sLog.outError("BG_AV: playerdestroyedpoint: marshal %i doesn't exist",AV_CPLACE_A_MARSHAL_SOUTH + tmp); + //spawn destroyed aura + for (uint8 i=0; i <= 9; i++) + SpawnBGObject(BG_AV_OBJECT_BURN_DUNBALDAR_SOUTH + i + (tmp * 10),RESPAWN_IMMEDIATELY); + + UpdateScore((owner == ALLIANCE) ? HORDE : ALLIANCE, (-1)*BG_AV_RES_TOWER); + RewardReputationToTeam((owner == ALLIANCE)?730:729,BG_AV_REP_TOWER,owner); + RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_TOWER),owner); + + SpawnBGObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+GetTeamIndexByTeamId(owner)+(2*tmp),RESPAWN_ONE_DAY); + SpawnBGObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+GetTeamIndexByTeamId(owner)+(2*tmp),RESPAWN_ONE_DAY); + } + else + { + if (owner == ALLIANCE) + SpawnBGObject(object-11, RESPAWN_IMMEDIATELY); + else + SpawnBGObject(object+11, RESPAWN_IMMEDIATELY); + SpawnBGObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+3*node,RESPAWN_ONE_DAY); + SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+GetTeamIndexByTeamId(owner)+3*node,RESPAWN_IMMEDIATELY); + PopulateNode(node); + if (node == BG_AV_NODES_SNOWFALL_GRAVE) //snowfall eyecandy + { + for (uint8 i = 0; i < 4; i++) + { + SpawnBGObject(((owner == ALLIANCE)?BG_AV_OBJECT_SNOW_EYECANDY_PA : BG_AV_OBJECT_SNOW_EYECANDY_PH)+i,RESPAWN_ONE_DAY); + SpawnBGObject(((owner == ALLIANCE)?BG_AV_OBJECT_SNOW_EYECANDY_A : BG_AV_OBJECT_SNOW_EYECANDY_H)+i,RESPAWN_IMMEDIATELY); + } + } + } + //send a nice message to all :) + char buf[256]; + if (IsTower(node)) + sprintf(buf, GetTrinityString(LANG_BG_AV_TOWER_TAKEN) , GetNodeName(node),(owner == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE)); + else + sprintf(buf, GetTrinityString(LANG_BG_AV_GRAVE_TAKEN) , GetNodeName(node),(owner == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) :GetTrinityString(LANG_BG_AV_HORDE)); + + Creature* creature = GetBGCreature(AV_CPLACE_HERALD); + if (creature) + YellToAll(creature,buf,LANG_UNIVERSAL); +} + +void BattleGroundAV::ChangeMineOwner(uint8 mine, uint32 team, bool initial) +{ //mine=0 northmine mine=1 southmin +//changing the owner results in setting respawntim to infinite for current creatures, spawning new mine owners creatures and changing the chest-objects so that the current owning team can use them + assert(mine == AV_NORTH_MINE || mine == AV_SOUTH_MINE); + if (team != ALLIANCE && team != HORDE) + team = AV_NEUTRAL_TEAM; + else + PlaySoundToAll((team == ALLIANCE)?AV_SOUND_ALLIANCE_GOOD:AV_SOUND_HORDE_GOOD); + + if (m_Mine_Owner[mine] == team && !initial) + return; + m_Mine_PrevOwner[mine] = m_Mine_Owner[mine]; + m_Mine_Owner[mine] = team; + + if (!initial) + { + sLog.outDebug("bg_av depopulating mine %i (0=north,1=south)",mine); + if (mine == AV_SOUTH_MINE) + for (uint16 i=AV_CPLACE_MINE_S_S_MIN; i <= AV_CPLACE_MINE_S_S_MAX; i++) + if (m_BgCreatures[i]) + DelCreature(i); //TODO just set the respawntime to 999999 + for (uint16 i=((mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_1_MIN:AV_CPLACE_MINE_S_1_MIN); i <= ((mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_3:AV_CPLACE_MINE_S_3); i++) + if (m_BgCreatures[i]) + DelCreature(i); //TODO here also + } + SendMineWorldStates(mine); + + sLog.outDebug("bg_av populating mine %i (0=north,1=south)",mine); + uint16 miner; + //also neutral team exists.. after a big time, the neutral team tries to conquer the mine + if (mine == AV_NORTH_MINE) + { + if (team == ALLIANCE) + miner = AV_NPC_N_MINE_A_1; + else if (team == HORDE) + miner = AV_NPC_N_MINE_H_1; + else + miner = AV_NPC_N_MINE_N_1; + } + else + { + uint16 cinfo; + if (team == ALLIANCE) + miner = AV_NPC_S_MINE_A_1; + else if (team == HORDE) + miner = AV_NPC_S_MINE_H_1; + else + miner = AV_NPC_S_MINE_N_1; + //vermin + sLog.outDebug("spawning vermin"); + if (team == ALLIANCE) + cinfo = AV_NPC_S_MINE_A_3; + else if (team == HORDE) + cinfo = AV_NPC_S_MINE_H_3; + else + cinfo = AV_NPC_S_MINE_N_S; + for (uint16 i=AV_CPLACE_MINE_S_S_MIN; i <= AV_CPLACE_MINE_S_S_MAX; i++) + AddAVCreature(cinfo,i); + } + for (uint16 i=((mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_1_MIN:AV_CPLACE_MINE_S_1_MIN); i <= ((mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_1_MAX:AV_CPLACE_MINE_S_1_MAX); i++) + AddAVCreature(miner,i); + //the next chooses randomly between 2 cretures + for (uint16 i=((mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_2_MIN:AV_CPLACE_MINE_S_2_MIN); i <= ((mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_2_MAX:AV_CPLACE_MINE_S_2_MAX); i++) + AddAVCreature(miner+(urand(1,2)),i); + AddAVCreature(miner+3,(mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_3:AV_CPLACE_MINE_S_3); + //because the gameobjects in this mine have changed, update all surrounding players: +// for (uint16 i = ((mine == AV_NORTH_MINE)?BG_AV_OBJECT_MINE_SUPPLY_N_MIN:BG_AV_OBJECT_MINE_SUPPLY_N_MIN); i <= ((mine == AV_NORTH_MINE)?BG_AV_OBJECT_MINE_SUPPLY_N_MAX:BG_AV_OBJECT_MINE_SUPPLY_N_MAX); i++) +// { + //TODO: add gameobject-update code +// } + if (team == ALLIANCE || team == HORDE) + { + m_Mine_Reclaim_Timer[mine]=AV_MINE_RECLAIM_TIMER; + char buf[256]; + sprintf(buf, GetTrinityString(LANG_BG_AV_MINE_TAKEN), GetTrinityString((mine == AV_NORTH_MINE) ? LANG_BG_AV_MINE_NORTH : LANG_BG_AV_MINE_SOUTH), (team == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE)); + Creature* creature = GetBGCreature(AV_CPLACE_HERALD); + if (creature) + YellToAll(creature,buf,LANG_UNIVERSAL); + } + else + { + if (mine == AV_SOUTH_MINE) //i think this gets called all the time + { + Creature* creature = GetBGCreature(AV_CPLACE_MINE_S_3); + YellToAll(creature,LANG_BG_AV_S_MINE_BOSS_CLAIMS,LANG_UNIVERSAL); + } + } + return; +} + +bool BattleGroundAV::PlayerCanDoMineQuest(int32 GOId,uint32 team) +{ + if (GOId == BG_AV_OBJECTID_MINE_N) + return (m_Mine_Owner[AV_NORTH_MINE] == team); + if (GOId == BG_AV_OBJECTID_MINE_S) + return (m_Mine_Owner[AV_SOUTH_MINE] == team); + return true; //cause it's no mine'object it is ok if this is true +} + +void BattleGroundAV::PopulateNode(BG_AV_Nodes node) +{ + uint32 owner = m_Nodes[node].Owner; + assert(owner); + + uint32 c_place = AV_CPLACE_DEFENSE_STORM_AID + (4 * node); + uint32 creatureid; + if (IsTower(node)) + creatureid=(owner == ALLIANCE)?AV_NPC_A_TOWERDEFENSE:AV_NPC_H_TOWERDEFENSE; + else + { + uint8 team2 = GetTeamIndexByTeamId(owner); + if (m_Team_QuestStatus[team2][0] < 500) + creatureid = (owner == ALLIANCE)? AV_NPC_A_GRAVEDEFENSE0 : AV_NPC_H_GRAVEDEFENSE0; + else if (m_Team_QuestStatus[team2][0] < 1000) + creatureid = (owner == ALLIANCE)? AV_NPC_A_GRAVEDEFENSE1 : AV_NPC_H_GRAVEDEFENSE1; + else if (m_Team_QuestStatus[team2][0] < 1500) + creatureid = (owner == ALLIANCE)? AV_NPC_A_GRAVEDEFENSE2 : AV_NPC_H_GRAVEDEFENSE2; + else + creatureid = (owner == ALLIANCE)? AV_NPC_A_GRAVEDEFENSE3 : AV_NPC_H_GRAVEDEFENSE3; + //spiritguide + if (m_BgCreatures[node]) + DelCreature(node); + if (!AddSpiritGuide(node, BG_AV_CreaturePos[node][0], BG_AV_CreaturePos[node][1], BG_AV_CreaturePos[node][2], BG_AV_CreaturePos[node][3], owner)) + sLog.outError("AV: couldn't spawn spiritguide at node %i",node); + + } + for (uint8 i=0; i<4; i++) + AddAVCreature(creatureid,c_place+i); + + if (node >= BG_AV_NODES_MAX)//fail safe + return; + Creature* trigger = GetBGCreature(node + 302);//0-302 other creatures + if (!trigger) + trigger = AddCreature(WORLD_TRIGGER,node + 302,owner,BG_AV_CreaturePos[node + 302][0],BG_AV_CreaturePos[node + 302][1],BG_AV_CreaturePos[node + 302][2],BG_AV_CreaturePos[node + 302][3]); + + //add bonus honor aura trigger creature when node is accupied + //cast bonus aura (+50% honor in 25yards) + //aura should only apply to players who have accupied the node, set correct faction for trigger + if (trigger) + { + if (owner != ALLIANCE && owner != HORDE)//node can be neutral, remove trigger + { + DelCreature(node + 302); + return; + } + trigger->setFaction(owner == ALLIANCE ? 84 : 83); + trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false); + } +} +void BattleGroundAV::DePopulateNode(BG_AV_Nodes node) +{ + uint32 c_place = AV_CPLACE_DEFENSE_STORM_AID + (4 * node); + for (uint8 i=0; i<4; i++) + if (m_BgCreatures[c_place+i]) + DelCreature(c_place+i); + //spiritguide + if (!IsTower(node) && m_BgCreatures[node]) + DelCreature(node); + + //remove bonus honor aura trigger creature when node is lost + if(node < BG_AV_NODES_MAX)//fail safe + DelCreature(node + 302);//NULL checks are in DelCreature! 0-302 spirit guides +} + +const BG_AV_Nodes BattleGroundAV::GetNodeThroughObject(uint32 object) +{ + sLog.outDebug("bg_AV getnodethroughobject %i",object); + if (object <= BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER) + return BG_AV_Nodes(object); + if (object <= BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_HUT) + return BG_AV_Nodes(object - 11); + if (object <= BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_WTOWER) + return BG_AV_Nodes(object - 7); + if (object <= BG_AV_OBJECT_FLAG_C_H_STONEHEART_BUNKER) + return BG_AV_Nodes(object -22); + if (object <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT) + return BG_AV_Nodes(object - 33); + if (object <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER) + return BG_AV_Nodes(object - 29); + if (object == BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE) + return BG_AV_NODES_SNOWFALL_GRAVE; + sLog.outError("BattleGroundAV: ERROR! GetPlace got a wrong object :("); + assert(false); + return BG_AV_Nodes(0); +} + +const uint32 BattleGroundAV::GetObjectThroughNode(BG_AV_Nodes node) +{ //this function is the counterpart to GetNodeThroughObject() + sLog.outDebug("bg_AV GetObjectThroughNode %i",node); + if (m_Nodes[node].Owner == ALLIANCE) + { + if (m_Nodes[node].State == POINT_ASSAULTED) + { + if (node <= BG_AV_NODES_FROSTWOLF_HUT) + return node+11; + if (node >= BG_AV_NODES_ICEBLOOD_TOWER && node <= BG_AV_NODES_FROSTWOLF_WTOWER) + return node+7; + } + else if (m_Nodes[node].State == POINT_CONTROLED) + if (node <= BG_AV_NODES_STONEHEART_BUNKER) + return node; + } + else if (m_Nodes[node].Owner == HORDE) + { + if (m_Nodes[node].State == POINT_ASSAULTED) + if (node <= BG_AV_NODES_STONEHEART_BUNKER) + return node+22; + else if (m_Nodes[node].State == POINT_CONTROLED) + { + if (node <= BG_AV_NODES_FROSTWOLF_HUT) + return node+33; + if (node >= BG_AV_NODES_ICEBLOOD_TOWER && node <= BG_AV_NODES_FROSTWOLF_WTOWER) + return node+29; + } + } + else if (m_Nodes[node].Owner == AV_NEUTRAL_TEAM) + return BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE; + sLog.outError("BattleGroundAV: Error! GetPlaceNode couldn't resolve node %i",node); + assert(false); + return 0; +} + +//called when using banner + +void BattleGroundAV::EventPlayerClickedOnFlag(Player *source, GameObject* target_obj) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + int32 object = GetObjectType(target_obj->GetGUID()); + sLog.outDebug("BG_AV using gameobject %i with type %i",target_obj->GetEntry(),object); + if (object < 0) + return; + switch(target_obj->GetEntry()) + { + case BG_AV_OBJECTID_BANNER_A: + case BG_AV_OBJECTID_BANNER_A_B: + case BG_AV_OBJECTID_BANNER_H: + case BG_AV_OBJECTID_BANNER_H_B: + case BG_AV_OBJECTID_BANNER_SNOWFALL_N: + EventPlayerAssaultsPoint(source, object); + break; + case BG_AV_OBJECTID_BANNER_CONT_A: + case BG_AV_OBJECTID_BANNER_CONT_A_B: + case BG_AV_OBJECTID_BANNER_CONT_H: + case BG_AV_OBJECTID_BANNER_CONT_H_B: + EventPlayerDefendsPoint(source, object); + break; + default: + break; + } +} + +void BattleGroundAV::EventPlayerDefendsPoint(Player* player, uint32 object) +{ + assert(GetStatus() == STATUS_IN_PROGRESS); + BG_AV_Nodes node = GetNodeThroughObject(object); + + uint32 owner = m_Nodes[node].Owner; //maybe should name it prevowner + uint32 team = player->GetTeam(); + + if (owner == player->GetTeam() || m_Nodes[node].State != POINT_ASSAULTED) + return; + if (m_Nodes[node].TotalOwner == AV_NEUTRAL_TEAM) + { //until snowfall doesn't belong to anyone it is better handled in assault-code + assert(node == BG_AV_NODES_SNOWFALL_GRAVE); //currently the only neutral grave + EventPlayerAssaultsPoint(player,object); + return; + } + sLog.outDebug("player defends point object: %i node: %i",object,node); + if (m_Nodes[node].PrevOwner != team) + { + sLog.outError("BG_AV: player defends point which doesn't belong to his team %i",node); + return; + } + + //spawn new go :) + if (m_Nodes[node].Owner == ALLIANCE) + SpawnBGObject(object+22, RESPAWN_IMMEDIATELY); //spawn horde banner + else + SpawnBGObject(object-22, RESPAWN_IMMEDIATELY); //spawn alliance banner + + if (!IsTower(node)) + { + SpawnBGObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+3*node,RESPAWN_ONE_DAY); + SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+GetTeamIndexByTeamId(team)+3*node,RESPAWN_IMMEDIATELY); + } + // despawn old go + SpawnBGObject(object, RESPAWN_ONE_DAY); + + DefendNode(node,team); + PopulateNode(node); + UpdateNodeWorldState(node); + + if (IsTower(node)) + { + //spawn big flag+aura on top of tower + SpawnBGObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == ALLIANCE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); + SpawnBGObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == HORDE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); + SpawnBGObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == ALLIANCE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); + SpawnBGObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == HORDE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); + } + else if (node == BG_AV_NODES_SNOWFALL_GRAVE) //snowfall eyecandy + { + for (uint8 i = 0; i < 4; i++) + { + SpawnBGObject(((owner == ALLIANCE)?BG_AV_OBJECT_SNOW_EYECANDY_PA : BG_AV_OBJECT_SNOW_EYECANDY_PH)+i,RESPAWN_ONE_DAY); + SpawnBGObject(((team == ALLIANCE)?BG_AV_OBJECT_SNOW_EYECANDY_A : BG_AV_OBJECT_SNOW_EYECANDY_H)+i,RESPAWN_IMMEDIATELY); + } + } + //send a nice message to all :) + char buf[256]; + sprintf(buf, GetTrinityString((IsTower(node)) ? LANG_BG_AV_TOWER_DEFENDED : LANG_BG_AV_GRAVE_DEFENDED), GetNodeName(node),(team == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE)); + Creature* creature = GetBGCreature(AV_CPLACE_HERALD); + if (creature) + YellToAll(creature,buf,LANG_UNIVERSAL); + //update the statistic for the defending player + UpdatePlayerScore(player, (IsTower(node)) ? SCORE_TOWERS_DEFENDED : SCORE_GRAVEYARDS_DEFENDED, 1); + if (IsTower(node)) + PlaySoundToAll(AV_SOUND_BOTH_TOWER_DEFEND); + else + PlaySoundToAll((team == ALLIANCE)?AV_SOUND_ALLIANCE_GOOD:AV_SOUND_HORDE_GOOD); +} + +void BattleGroundAV::EventPlayerAssaultsPoint(Player* player, uint32 object) +{ + assert(GetStatus() == STATUS_IN_PROGRESS); + + BG_AV_Nodes node = GetNodeThroughObject(object); + uint32 owner = m_Nodes[node].Owner; //maybe name it prevowner + uint32 team = player->GetTeam(); + sLog.outDebug("bg_av: player assaults point object %i node %i",object,node); + if (owner == team || team == m_Nodes[node].TotalOwner) + return; //surely a gm used this object + + if (node == BG_AV_NODES_SNOWFALL_GRAVE) //snowfall is a bit special in capping + it gets eyecandy stuff + { + if (object == BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE) //initial capping + { + assert(owner == AV_NEUTRAL_TEAM && m_Nodes[node].TotalOwner == AV_NEUTRAL_TEAM); + if (team == ALLIANCE) + SpawnBGObject(BG_AV_OBJECT_FLAG_C_A_SNOWFALL_GRAVE, RESPAWN_IMMEDIATELY); + else + SpawnBGObject(BG_AV_OBJECT_FLAG_C_H_SNOWFALL_GRAVE, RESPAWN_IMMEDIATELY); + SpawnBGObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+3*node,RESPAWN_IMMEDIATELY); //neutral aura spawn + } + else if (m_Nodes[node].TotalOwner == AV_NEUTRAL_TEAM) //recapping, when no team owns this node realy + { + assert(m_Nodes[node].State != POINT_CONTROLED); + if (team == ALLIANCE) + SpawnBGObject(object-11, RESPAWN_IMMEDIATELY); + else + SpawnBGObject(object+11, RESPAWN_IMMEDIATELY); + } + //eyecandy + uint32 spawn,despawn; + if (team == ALLIANCE) + { + despawn = (m_Nodes[node].State == POINT_ASSAULTED)?BG_AV_OBJECT_SNOW_EYECANDY_PH : BG_AV_OBJECT_SNOW_EYECANDY_H; + spawn = BG_AV_OBJECT_SNOW_EYECANDY_PA; + } + else + { + despawn = (m_Nodes[node].State == POINT_ASSAULTED)?BG_AV_OBJECT_SNOW_EYECANDY_PA : BG_AV_OBJECT_SNOW_EYECANDY_A; + spawn = BG_AV_OBJECT_SNOW_EYECANDY_PH; + } + for (uint8 i = 0; i < 4; i++) + { + SpawnBGObject(despawn+i,RESPAWN_ONE_DAY); + SpawnBGObject(spawn+i,RESPAWN_IMMEDIATELY); + } + } + + //if snowfall gots capped it can be handled like all other graveyards + if (m_Nodes[node].TotalOwner != AV_NEUTRAL_TEAM) + { + assert(m_Nodes[node].Owner != AV_NEUTRAL_TEAM); + if (team == ALLIANCE) + SpawnBGObject(object-22, RESPAWN_IMMEDIATELY); + else + SpawnBGObject(object+22, RESPAWN_IMMEDIATELY); + if (IsTower(node)) + { //spawning/despawning of bigflag+aura + SpawnBGObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == ALLIANCE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); + SpawnBGObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == HORDE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); + SpawnBGObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == ALLIANCE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); + SpawnBGObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == HORDE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); + } + else + { + //spawning/despawning of aura + SpawnBGObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+3*node,RESPAWN_IMMEDIATELY); //neutral aura spawn + SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+GetTeamIndexByTeamId(owner)+3*node,RESPAWN_ONE_DAY); //teeamaura despawn + // Those who are waiting to resurrect at this object are taken to the closest own object's graveyard + std::vector ghost_list = m_ReviveQueue[m_BgCreatures[node]]; + if (!ghost_list.empty()) + { + Player *plr; + WorldSafeLocsEntry const *ClosestGrave = NULL; + for (std::vector::iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr) + { + plr = objmgr.GetPlayer(*ghost_list.begin()); + if (!plr) + continue; + if (!ClosestGrave) + ClosestGrave = GetClosestGraveYard(plr); + else + plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation()); + } + m_ReviveQueue[m_BgCreatures[node]].clear(); + } + } + DePopulateNode(node); + } + + SpawnBGObject(object, RESPAWN_ONE_DAY); //delete old banner + AssaultNode(node,team); + UpdateNodeWorldState(node); + + //send a nice message to all :) + char buf[256]; + sprintf(buf, (IsTower(node)) ? GetTrinityString(LANG_BG_AV_TOWER_ASSAULTED) : GetTrinityString(LANG_BG_AV_GRAVE_ASSAULTED), GetNodeName(node), (team == ALLIANCE) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE)); + Creature* creature = GetBGCreature(AV_CPLACE_HERALD); + if (creature) + YellToAll(creature,buf,LANG_UNIVERSAL); + //update the statistic for the assaulting player + UpdatePlayerScore(player, (IsTower(node)) ? SCORE_TOWERS_ASSAULTED : SCORE_GRAVEYARDS_ASSAULTED, 1); + PlaySoundToAll((team == ALLIANCE)?AV_SOUND_ALLIANCE_ASSAULTS:AV_SOUND_HORDE_ASSAULTS); +} + +void BattleGroundAV::FillInitialWorldStates(WorldPacket& data) +{ + bool stateok; + //graveyards + for (uint8 i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; i++) + { + for (uint8 j =1; j <= 3; j+=2) + {//j=1=assaulted j=3=controled + stateok = (m_Nodes[i].State == j); + data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j,ALLIANCE)]) << uint32((m_Nodes[i].Owner == ALLIANCE && stateok)?1:0); + data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j,HORDE)]) << uint32((m_Nodes[i].Owner == HORDE && stateok)?1:0); + } + } + + //towers + for (uint8 i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_MAX; i++) + for (uint8 j =1; j <= 3; j+=2) + {//j=1=assaulted j=3=controled //i dont have j=2=destroyed cause destroyed is the same like enemy-team controll + stateok = (m_Nodes[i].State == j || (m_Nodes[i].State == POINT_DESTROYED && j == 3)); + data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j,ALLIANCE)]) << uint32((m_Nodes[i].Owner == ALLIANCE && stateok)?1:0); + data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j,HORDE)]) << uint32((m_Nodes[i].Owner == HORDE && stateok)?1:0); + } + if (m_Nodes[BG_AV_NODES_SNOWFALL_GRAVE].Owner == AV_NEUTRAL_TEAM) //cause neutral teams aren't handled generic + data << uint32(AV_SNOWFALL_N) << uint32(1); + data << uint32(AV_Alliance_Score) << uint32(m_Team_Scores[0]); + data << uint32(AV_Horde_Score) << uint32(m_Team_Scores[1]); + if (GetStatus() == STATUS_IN_PROGRESS){ //only if game started the teamscores are displayed + data << uint32(AV_SHOW_A_SCORE) << uint32(1); + data << uint32(AV_SHOW_H_SCORE) << uint32(1); + } + else + { + data << uint32(AV_SHOW_A_SCORE) << uint32(0); + data << uint32(AV_SHOW_H_SCORE) << uint32(0); + } + SendMineWorldStates(AV_NORTH_MINE); + SendMineWorldStates(AV_SOUTH_MINE); +} + +const uint8 BattleGroundAV::GetWorldStateType(uint8 state, uint16 team) //this is used for node worldstates and returns values which fit good into the worldstatesarray +{ + //neutral stuff cant get handled (currently its only snowfall) + assert(team != AV_NEUTRAL_TEAM); + //a_c a_a h_c h_a the positions in worldstate-array + if (team == ALLIANCE) + { + if (state == POINT_CONTROLED || state == POINT_DESTROYED) + return 0; + if (state == POINT_ASSAULTED) + return 1; + } + if (team == HORDE) + { + if (state == POINT_DESTROYED || state == POINT_CONTROLED) + return 2; + if (state == POINT_ASSAULTED) + return 3; + } + sLog.outError("BG_AV: should update a strange worldstate state:%i team:%i",state,team); + return 5; //this will crash the game, but i want to know if something is wrong here +} + +void BattleGroundAV::UpdateNodeWorldState(BG_AV_Nodes node) +{ + UpdateWorldState(BG_AV_NodeWorldStates[node][GetWorldStateType(m_Nodes[node].State,m_Nodes[node].Owner)],1); + if (m_Nodes[node].PrevOwner == AV_NEUTRAL_TEAM) //currently only snowfall is supported as neutral node (i don't want to make an extra row (neutral states) in worldstatesarray just for one node + UpdateWorldState(AV_SNOWFALL_N,0); + else + UpdateWorldState(BG_AV_NodeWorldStates[node][GetWorldStateType(m_Nodes[node].PrevState,m_Nodes[node].PrevOwner)],0); +} + +void BattleGroundAV::SendMineWorldStates(uint32 mine) +{ + assert(mine == AV_NORTH_MINE || mine == AV_SOUTH_MINE); +// currently i'm sure, that this works (: +// assert(m_Mine_PrevOwner[mine] == ALLIANCE || m_Mine_PrevOwner[mine] == HORDE || m_Mine_PrevOwner[mine] == AV_NEUTRAL_TEAM); +// assert(m_Mine_Owner[mine] == ALLIANCE || m_Mine_Owner[mine] == HORDE || m_Mine_Owner[mine] == AV_NEUTRAL_TEAM); + + uint8 owner,prevowner,mine2; //those variables are needed to access the right worldstate in the BG_AV_MineWorldStates array + mine2 = (mine == AV_NORTH_MINE)?0:1; + if (m_Mine_PrevOwner[mine] == ALLIANCE) + prevowner = 0; + else if (m_Mine_PrevOwner[mine] == HORDE) + prevowner = 2; + else + prevowner = 1; + if (m_Mine_Owner[mine] == ALLIANCE) + owner = 0; + else if (m_Mine_Owner[mine] == HORDE) + owner = 2; + else + owner = 1; + + UpdateWorldState(BG_AV_MineWorldStates[mine2][owner],1); + if (prevowner != owner) + UpdateWorldState(BG_AV_MineWorldStates[mine2][prevowner],0); +} + +WorldSafeLocsEntry const* BattleGroundAV::GetClosestGraveYard(Player* player) +{ + WorldSafeLocsEntry const* pGraveyard = NULL; + WorldSafeLocsEntry const* entry = NULL; + float dist = 0; + float minDist = 0; + float x, y; + + player->GetPosition(x, y); + + pGraveyard = sWorldSafeLocsStore.LookupEntry(BG_AV_GraveyardIds[GetTeamIndexByTeamId(player->GetTeam())+7]); + minDist = (pGraveyard->x - x)*(pGraveyard->x - x)+(pGraveyard->y - y)*(pGraveyard->y - y); + + for (uint8 i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i) + if (m_Nodes[i].Owner == player->GetTeam() && m_Nodes[i].State == POINT_CONTROLED) + { + entry = sWorldSafeLocsStore.LookupEntry(BG_AV_GraveyardIds[i]); + if (entry) + { + dist = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y); + if (dist < minDist) + { + minDist = dist; + pGraveyard = entry; + } + } + } + return pGraveyard; +} + +bool BattleGroundAV::SetupBattleGround() +{ + // Create starting objects + if ( + // alliance gates + !AddObject(BG_AV_OBJECT_DOOR_A, BG_AV_OBJECTID_GATE_A, BG_AV_DoorPositons[0][0],BG_AV_DoorPositons[0][1],BG_AV_DoorPositons[0][2],BG_AV_DoorPositons[0][3],0,0,sin(BG_AV_DoorPositons[0][3]/2),cos(BG_AV_DoorPositons[0][3]/2),RESPAWN_IMMEDIATELY) + // horde gates + || !AddObject(BG_AV_OBJECT_DOOR_H, BG_AV_OBJECTID_GATE_H, BG_AV_DoorPositons[1][0],BG_AV_DoorPositons[1][1],BG_AV_DoorPositons[1][2],BG_AV_DoorPositons[1][3],0,0,sin(BG_AV_DoorPositons[1][3]/2),cos(BG_AV_DoorPositons[1][3]/2),RESPAWN_IMMEDIATELY)) + { + sLog.outErrorDb("BatteGroundAV: Failed to spawn some object BattleGround not created!1"); + return false; + } + + //spawn node-objects + for (uint8 i = BG_AV_NODES_FIRSTAID_STATION ; i < BG_AV_NODES_MAX; ++i) + { + if (i <= BG_AV_NODES_FROSTWOLF_HUT) + { + if (!AddObject(i,BG_AV_OBJECTID_BANNER_A_B,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(i+11,BG_AV_OBJECTID_BANNER_CONT_A_B,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(i+33,BG_AV_OBJECTID_BANNER_H_B,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(i+22,BG_AV_OBJECTID_BANNER_CONT_H_B,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) + //aura + || !AddObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+i*3,BG_AV_OBJECTID_AURA_N,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+i*3,BG_AV_OBJECTID_AURA_A,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AV_OBJECT_AURA_H_FIRSTAID_STATION+i*3,BG_AV_OBJECTID_AURA_H,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY)) + { + sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!2"); + return false; + } + } + else //towers + { + if (i <= BG_AV_NODES_STONEHEART_BUNKER) //alliance towers + { + if (!AddObject(i,BG_AV_OBJECTID_BANNER_A,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(i+22,BG_AV_OBJECTID_BANNER_CONT_H,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_AURA_A,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_AURA_N,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_TOWER_BANNER_A,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_TOWER_BANNER_PH,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY)) + { + sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!3"); + return false; + } + } + else //horde towers + { + if (!AddObject(i+7,BG_AV_OBJECTID_BANNER_CONT_A,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(i+29,BG_AV_OBJECTID_BANNER_H,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_AURA_N,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_AURA_H,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_TOWER_BANNER_PA,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY) + || !AddObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_TOWER_BANNER_H,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY)) + { + sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!4"); + return false; + } + } + for (uint8 j=0; j <= 9; j++) //burning aura + { + if (!AddObject(BG_AV_OBJECT_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j,BG_AV_OBJECTID_FIRE,BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][0],BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][1],BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][2],BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3]/2),RESPAWN_ONE_DAY)) + { + sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!5.%i",i); + return false; + } + } + } + } + for (uint8 i=0; i<2; i++) //burning aura for buildings + { + for (uint8 j=0; j <= 9; j++) + { + if (j<5) + { + if (!AddObject(BG_AV_OBJECT_BURN_BUILDING_ALLIANCE+(i*10)+j,BG_AV_OBJECTID_SMOKE,BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][0],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][1],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][2],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2),RESPAWN_ONE_DAY)) + { + sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!6.%i",i); + return false; + } + } + else + { + if (!AddObject(BG_AV_OBJECT_BURN_BUILDING_ALLIANCE+(i*10)+j,BG_AV_OBJECTID_FIRE,BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][0],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][1],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][2],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2),RESPAWN_ONE_DAY)) + { + sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!7.%i",i); + return false; + } + } + } + } + for (uint16 i= 0; i <= (BG_AV_OBJECT_MINE_SUPPLY_N_MAX-BG_AV_OBJECT_MINE_SUPPLY_N_MIN); i++) + { + if (!AddObject(BG_AV_OBJECT_MINE_SUPPLY_N_MIN+i,BG_AV_OBJECTID_MINE_N,BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][0],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][1],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][2],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3]/2),RESPAWN_ONE_DAY)) + { + sLog.outError("BatteGroundAV: Failed to spawn some mine supplies BattleGround not created!7.5.%i",i); + return false; + } + } + for (uint16 i= 0 ; i <= (BG_AV_OBJECT_MINE_SUPPLY_S_MAX-BG_AV_OBJECT_MINE_SUPPLY_S_MIN); i++) + { + if (!AddObject(BG_AV_OBJECT_MINE_SUPPLY_S_MIN+i,BG_AV_OBJECTID_MINE_S,BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][0],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][1],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][2],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3]/2),RESPAWN_ONE_DAY)) + { + sLog.outError("BatteGroundAV: Failed to spawn some mine supplies BattleGround not created!7.6.%i",i); + return false; + } + } + + if (!AddObject(BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE, BG_AV_OBJECTID_BANNER_SNOWFALL_N ,BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][0],BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][1],BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][2],BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3],0,0,sin(BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3]/2), cos(BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3]/2), RESPAWN_ONE_DAY)) + { + sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!8"); + return false; + } + for (uint8 i = 0; i < 4; i++) + { + if (!AddObject(BG_AV_OBJECT_SNOW_EYECANDY_A+i, BG_AV_OBJECTID_SNOWFALL_CANDY_A ,BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],0,0,sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY) + || !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_PA+i, BG_AV_OBJECTID_SNOWFALL_CANDY_PA ,BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],0,0,sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY) + || !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_H+i, BG_AV_OBJECTID_SNOWFALL_CANDY_H ,BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],0,0,sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY) + || !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_PH+i, BG_AV_OBJECTID_SNOWFALL_CANDY_PH ,BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],0,0,sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY)) + { + sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!9.%i",i); + return false; + } + } + + uint16 i; + sLog.outDebug("Alterac Valley: entering state STATUS_WAIT_JOIN ..."); + // Initial Nodes + for (i = 0; i < BG_AV_OBJECT_MAX; i++) + SpawnBGObject(i, RESPAWN_ONE_DAY); + for (i = BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION; i <= BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE ; i++){ + SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+3*i,RESPAWN_IMMEDIATELY); + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + } + for (i = BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH; i <= BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER ; i++) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + for (i = BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE; i <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER ; i++){ + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + if (i <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT) + SpawnBGObject(BG_AV_OBJECT_AURA_H_FIRSTAID_STATION+3*GetNodeThroughObject(i),RESPAWN_IMMEDIATELY); + } + for (i = BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH; i <= BG_AV_OBJECT_TFLAG_A_STONEHEART_BUNKER; i+=2) + { + SpawnBGObject(i, RESPAWN_IMMEDIATELY); //flag + SpawnBGObject(i+16, RESPAWN_IMMEDIATELY); //aura + } + for (i = BG_AV_OBJECT_TFLAG_H_ICEBLOOD_TOWER; i <= BG_AV_OBJECT_TFLAG_H_FROSTWOLF_WTOWER; i+=2) + { + SpawnBGObject(i, RESPAWN_IMMEDIATELY); //flag + SpawnBGObject(i+16, RESPAWN_IMMEDIATELY); //aura + } + //snowfall and the doors + for (i = BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE; i <= BG_AV_OBJECT_DOOR_A; i++) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + SpawnBGObject(BG_AV_OBJECT_AURA_N_SNOWFALL_GRAVE,RESPAWN_IMMEDIATELY); + + //creatures + sLog.outDebug("BG_AV start poputlating nodes"); + for (BG_AV_Nodes i= BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i) + { + if (m_Nodes[i].Owner) + PopulateNode(i); + } + //all creatures which don't get despawned through the script are static + sLog.outDebug("BG_AV: start spawning static creatures"); + for (i=0; i < AV_STATICCPLACE_MAX; i++) + AddAVCreature(0,i+AV_CPLACE_MAX); + //mainspiritguides: + sLog.outDebug("BG_AV: start spawning spiritguides creatures"); + AddSpiritGuide(7, BG_AV_CreaturePos[7][0], BG_AV_CreaturePos[7][1], BG_AV_CreaturePos[7][2], BG_AV_CreaturePos[7][3], ALLIANCE); + AddSpiritGuide(8, BG_AV_CreaturePos[8][0], BG_AV_CreaturePos[8][1], BG_AV_CreaturePos[8][2], BG_AV_CreaturePos[8][3], HORDE); + //spawn the marshals (those who get deleted, if a tower gets destroyed) + sLog.outDebug("BG_AV: start spawning marshal creatures"); + for (i=AV_NPC_A_MARSHAL_SOUTH; i <= AV_NPC_H_MARSHAL_WTOWER; i++) + AddAVCreature(i,AV_CPLACE_A_MARSHAL_SOUTH+(i-AV_NPC_A_MARSHAL_SOUTH)); + AddAVCreature(AV_NPC_HERALD,AV_CPLACE_HERALD); + return true; +} + +const char* BattleGroundAV::GetNodeName(BG_AV_Nodes node) +{ + switch (node) + { + case BG_AV_NODES_FIRSTAID_STATION: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_STORM_AID); + case BG_AV_NODES_DUNBALDAR_SOUTH: return GetTrinityString(LANG_BG_AV_NODE_TOWER_DUN_S); + case BG_AV_NODES_DUNBALDAR_NORTH: return GetTrinityString(LANG_BG_AV_NODE_TOWER_DUN_N); + case BG_AV_NODES_STORMPIKE_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_STORMPIKE); + case BG_AV_NODES_ICEWING_BUNKER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_ICEWING); + case BG_AV_NODES_STONEHEART_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_STONE); + case BG_AV_NODES_STONEHEART_BUNKER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_STONE); + case BG_AV_NODES_SNOWFALL_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_SNOW); + case BG_AV_NODES_ICEBLOOD_TOWER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_ICE); + case BG_AV_NODES_ICEBLOOD_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_ICE); + case BG_AV_NODES_TOWER_POINT: return GetTrinityString(LANG_BG_AV_NODE_TOWER_POINT); + case BG_AV_NODES_FROSTWOLF_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_FROST); + case BG_AV_NODES_FROSTWOLF_ETOWER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_FROST_E); + case BG_AV_NODES_FROSTWOLF_WTOWER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_FROST_W); + case BG_AV_NODES_FROSTWOLF_HUT: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_FROST_HUT); + default: + { + sLog.outError("tried to get name for node %u%",node); + return "Unknown"; + break; + } + } +} + +void BattleGroundAV::AssaultNode(BG_AV_Nodes node, uint16 team) +{ + if (m_Nodes[node].TotalOwner == team) + { + sLog.outCrash("Assaulting team is TotalOwner of node"); + assert (false); + } + if (m_Nodes[node].Owner == team) + { + sLog.outCrash("Assaulting team is owner of node"); + assert (false); + } + if (m_Nodes[node].State == POINT_DESTROYED) + { + sLog.outCrash("Destroyed node is being assaulted"); + assert (false); + } + if (m_Nodes[node].State == POINT_ASSAULTED && m_Nodes[node].TotalOwner) //only assault an assaulted node if no totalowner exists + { + sLog.outCrash("Assault on an not assaulted node with total owner"); + assert (false); + } + //the timer gets another time, if the previous owner was 0 == Neutral + m_Nodes[node].Timer = (m_Nodes[node].PrevOwner)? BG_AV_CAPTIME : BG_AV_SNOWFALL_FIRSTCAP; + m_Nodes[node].PrevOwner = m_Nodes[node].Owner; + m_Nodes[node].Owner = team; + m_Nodes[node].PrevState = m_Nodes[node].State; + m_Nodes[node].State = POINT_ASSAULTED; +} + +void BattleGroundAV::DestroyNode(BG_AV_Nodes node) +{ + assert(m_Nodes[node].State == POINT_ASSAULTED); + + m_Nodes[node].TotalOwner = m_Nodes[node].Owner; + m_Nodes[node].PrevOwner = m_Nodes[node].Owner; + m_Nodes[node].PrevState = m_Nodes[node].State; + m_Nodes[node].State = (m_Nodes[node].Tower)? POINT_DESTROYED : POINT_CONTROLED; + m_Nodes[node].Timer = 0; +} + +void BattleGroundAV::InitNode(BG_AV_Nodes node, uint16 team, bool tower) +{ + m_Nodes[node].TotalOwner = team; + m_Nodes[node].Owner = team; + m_Nodes[node].PrevOwner = 0; + m_Nodes[node].State = POINT_CONTROLED; + m_Nodes[node].PrevState = m_Nodes[node].State; + m_Nodes[node].State = POINT_CONTROLED; + m_Nodes[node].Timer = 0; + m_Nodes[node].Tower = tower; +} + +void BattleGroundAV::DefendNode(BG_AV_Nodes node, uint16 team) +{ + assert(m_Nodes[node].TotalOwner == team); + assert(m_Nodes[node].Owner != team); + assert(m_Nodes[node].State != POINT_CONTROLED && m_Nodes[node].State != POINT_DESTROYED); + m_Nodes[node].PrevOwner = m_Nodes[node].Owner; + m_Nodes[node].Owner = team; + m_Nodes[node].PrevState = m_Nodes[node].State; + m_Nodes[node].State = POINT_CONTROLED; + m_Nodes[node].Timer = 0; +} + +void BattleGroundAV::ResetBGSubclass() +{ + m_MaxLevel=0; + for (uint8 i=0; i<2; i++) //forloop for both teams (it just make 0 == alliance and 1 == horde also for both mines 0=north 1=south + { + for (uint8 j=0; j<9; j++) + m_Team_QuestStatus[i][j]=0; + m_Team_Scores[i]=BG_AV_SCORE_INITIAL_POINTS; + m_IsInformedNearVictory[i]=false; + m_CaptainAlive[i] = true; + m_CaptainBuffTimer[i] = 120000 + urand(0,4)* 60; //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes TODO get the right times + m_Mine_Owner[i] = AV_NEUTRAL_TEAM; + m_Mine_PrevOwner[i] = m_Mine_Owner[i]; + } + for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_STONEHEART_GRAVE; ++i) //alliance graves + InitNode(i,ALLIANCE,false); + for (BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_STONEHEART_BUNKER; ++i) //alliance towers + InitNode(i,ALLIANCE,true); + for (BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_GRAVE; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i) //horde graves + InitNode(i,HORDE,false); + for (BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_TOWER; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i) //horde towers + InitNode(i,HORDE,true); + InitNode(BG_AV_NODES_SNOWFALL_GRAVE,AV_NEUTRAL_TEAM,false); //give snowfall neutral owner + + m_Mine_Timer=AV_MINE_TICK_TIMER; + for (uint16 i = 0; i < AV_CPLACE_MAX+AV_STATICCPLACE_MAX; i++) + if (m_BgCreatures[i]) + DelCreature(i); + +} + + diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundAV.h b/src/server/game/BattleGrounds/Zones/BattleGroundAV.h new file mode 100644 index 00000000000..6d95c7bbc5d --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundAV.h @@ -0,0 +1,1614 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __BATTLEGROUNDAV_H +#define __BATTLEGROUNDAV_H + +class BattleGround; + +#define LANG_BG_AV_A_CAPTAIN_BUFF "Begone. Uncouth scum! The Alliance shall prevail in Alterac Valley!" +#define LANG_BG_AV_H_CAPTAIN_BUFF "Now is the time to attack! For the Horde!" +#define LANG_BG_AV_S_MINE_BOSS_CLAIMS "Snivvle is here! Snivvle claims the Coldtooth Mine!" + +#define BG_AV_CAPTIME 240000 //4:00 +#define BG_AV_SNOWFALL_FIRSTCAP 300000 //5:00 but i also have seen 4:05 + +#define BG_AV_SCORE_INITIAL_POINTS 600 +#define SEND_MSG_NEAR_LOSE 120 + +#define BG_AV_KILL_BOSS 4 +#define BG_AV_REP_BOSS 350 + +#define BG_AV_KILL_CAPTAIN 3 +#define BG_AV_REP_CAPTAIN 125 +#define BG_AV_RES_CAPTAIN 100 + +#define BG_AV_KILL_TOWER 3 +#define BG_AV_REP_TOWER 12 +#define BG_AV_RES_TOWER 75 + +#define BG_AV_GET_COMMANDER 1 //for a safely returned wingcommander +//bonushonor at the end +#define BG_AV_KILL_SURVIVING_TOWER 2 +#define BG_AV_REP_SURVIVING_TOWER 12 + +#define BG_AV_KILL_SURVIVING_CAPTAIN 2 +#define BG_AV_REP_SURVIVING_CAPTAIN 125 + +enum BG_AV_Sounds +{ //TODO: get out if there comes a sound when neutral team captures mine + +/* +8212: + alliance grave assault + alliance tower assault + drek "mlanzenabschaum! In meiner Burg?! Toetet sie all" - nicht immer der sound +8333: + galv "sterbt fuer euch ist kein platz hier" + +8332: + bal "Verschwinde, dreckiger Abschaum! Die Allianz wird im Alteractal " +8174: + horde tower assault + horde grave assault + van "es Sturmlanzenklans, euer General wird angegriffen! Ich fordere Unterst" +8173: + ally grave capture/defend + tower destroy + mine capture + ally wins +8192: + ally tower destroy(only iceblood - found a bug^^) + ally tower defend + horde tower defend +8213 +horde: + grave defend/capture + tower destroy + mine capture + horde wins + */ + + AV_SOUND_NEAR_VICTORY = 8456, //not confirmed yet + + AV_SOUND_ALLIANCE_ASSAULTS = 8212, //tower,grave + enemy boss if someone tries to attack him + AV_SOUND_HORDE_ASSAULTS = 8174, + AV_SOUND_ALLIANCE_GOOD = 8173, //if something good happens for the team: wins(maybe only through killing the boss), captures mine or grave, destroys tower and defends grave + AV_SOUND_HORDE_GOOD = 8213, + AV_SOUND_BOTH_TOWER_DEFEND = 8192, + + AV_SOUND_ALLIANCE_CAPTAIN = 8232, //gets called when someone attacks them and at the beginning after 3min+rand(x)*10sec (maybe buff) + AV_SOUND_HORDE_CAPTAIN = 8333, + +}; + +enum BG_AV_OTHER_VALUES +{ + AV_STATICCPLACE_MAX = 123, + AV_NORTH_MINE = 0, + AV_SOUTH_MINE = 1, + AV_MINE_TICK_TIMER = 45000, + AV_MINE_RECLAIM_TIMER = 1200000, //TODO: get the right value.. this is currently 20 minutes + AV_NEUTRAL_TEAM = 0 //this is the neutral owner of snowfall +}; +enum BG_AV_ObjectIds +{ + //cause the mangos-system is a bit different, we don't use the right go-ids for every node.. if we want to be 100% like another big server, we must take one object for every node + //snowfall 4flags as eyecandy 179424 (alliance neutral) + //Banners - stolen from battleground_AB.h ;-) + BG_AV_OBJECTID_BANNER_A = 178925, // can only be used by horde + BG_AV_OBJECTID_BANNER_H = 178943, // can only be used by alliance + BG_AV_OBJECTID_BANNER_CONT_A = 178940, // can only be used by horde + BG_AV_OBJECTID_BANNER_CONT_H = 179435, // can only be used by alliance + + BG_AV_OBJECTID_BANNER_A_B = 178365, + BG_AV_OBJECTID_BANNER_H_B = 178364, + BG_AV_OBJECTID_BANNER_CONT_A_B = 179286, + BG_AV_OBJECTID_BANNER_CONT_H_B = 179287, + BG_AV_OBJECTID_BANNER_SNOWFALL_N = 180418, + + //snowfall eyecandy banner: + BG_AV_OBJECTID_SNOWFALL_CANDY_A = 179044, + BG_AV_OBJECTID_SNOWFALL_CANDY_PA = 179424, + BG_AV_OBJECTID_SNOWFALL_CANDY_H = 179064, + BG_AV_OBJECTID_SNOWFALL_CANDY_PH = 179425, + + //banners on top of towers: + BG_AV_OBJECTID_TOWER_BANNER_A = 178927, //[PH] Alliance A1 Tower Banner BIG + BG_AV_OBJECTID_TOWER_BANNER_H = 178955, //[PH] Horde H1 Tower Banner BIG + BG_AV_OBJECTID_TOWER_BANNER_PA = 179446, //[PH] Alliance H1 Tower Pre-Banner BIG + BG_AV_OBJECTID_TOWER_BANNER_PH = 179436, //[PH] Horde A1 Tower Pre-Banner BIG + + //Auras + BG_AV_OBJECTID_AURA_A = 180421, + BG_AV_OBJECTID_AURA_H = 180422, + BG_AV_OBJECTID_AURA_N = 180423, + BG_AV_OBJECTID_AURA_A_S = 180100, + BG_AV_OBJECTID_AURA_H_S = 180101, + BG_AV_OBJECTID_AURA_N_S = 180102, + + BG_AV_OBJECTID_GATE_A = 180424, + BG_AV_OBJECTID_GATE_H = 180424, + + //mine supplies + BG_AV_OBJECTID_MINE_N = 178785, + BG_AV_OBJECTID_MINE_S = 178784, + + BG_AV_OBJECTID_FIRE = 179065, + BG_AV_OBJECTID_SMOKE = 179066 +}; + +enum BG_AV_Nodes +{ + BG_AV_NODES_FIRSTAID_STATION = 0, + BG_AV_NODES_STORMPIKE_GRAVE = 1, + BG_AV_NODES_STONEHEART_GRAVE = 2, + BG_AV_NODES_SNOWFALL_GRAVE = 3, + BG_AV_NODES_ICEBLOOD_GRAVE = 4, + BG_AV_NODES_FROSTWOLF_GRAVE = 5, + BG_AV_NODES_FROSTWOLF_HUT = 6, + BG_AV_NODES_DUNBALDAR_SOUTH = 7, + BG_AV_NODES_DUNBALDAR_NORTH = 8, + BG_AV_NODES_ICEWING_BUNKER = 9, + BG_AV_NODES_STONEHEART_BUNKER = 10, + BG_AV_NODES_ICEBLOOD_TOWER = 11, + BG_AV_NODES_TOWER_POINT = 12, + BG_AV_NODES_FROSTWOLF_ETOWER = 13, + BG_AV_NODES_FROSTWOLF_WTOWER = 14, + + BG_AV_NODES_MAX = 15 +}; + +enum BG_AV_ObjectTypes +{ + BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION = 0, + BG_AV_OBJECT_FLAG_A_STORMPIKE_GRAVE = 1, + BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE = 2, + BG_AV_OBJECT_FLAG_A_SNOWFALL_GRAVE = 3, + BG_AV_OBJECT_FLAG_A_ICEBLOOD_GRAVE = 4, + BG_AV_OBJECT_FLAG_A_FROSTWOLF_GRAVE = 5, + BG_AV_OBJECT_FLAG_A_FROSTWOLF_HUT = 6, + BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH = 7, + BG_AV_OBJECT_FLAG_A_DUNBALDAR_NORTH = 8, + BG_AV_OBJECT_FLAG_A_ICEWING_BUNKER = 9, + BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER = 10, + + BG_AV_OBJECT_FLAG_C_A_FIRSTAID_STATION = 11, + BG_AV_OBJECT_FLAG_C_A_STORMPIKE_GRAVE = 12, + BG_AV_OBJECT_FLAG_C_A_STONEHEART_GRAVE = 13, + BG_AV_OBJECT_FLAG_C_A_SNOWFALL_GRAVE = 14, + BG_AV_OBJECT_FLAG_C_A_ICEBLOOD_GRAVE = 15, + BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_GRAVE = 16, + BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_HUT = 17, + BG_AV_OBJECT_FLAG_C_A_ICEBLOOD_TOWER = 18, + BG_AV_OBJECT_FLAG_C_A_TOWER_POINT = 19, + BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_ETOWER = 20, + BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_WTOWER = 21, + + BG_AV_OBJECT_FLAG_C_H_FIRSTAID_STATION = 22, + BG_AV_OBJECT_FLAG_C_H_STORMPIKE_GRAVE = 23, + BG_AV_OBJECT_FLAG_C_H_STONEHEART_GRAVE = 24, + BG_AV_OBJECT_FLAG_C_H_SNOWFALL_GRAVE = 25, + BG_AV_OBJECT_FLAG_C_H_ICEBLOOD_GRAVE = 26, + BG_AV_OBJECT_FLAG_C_H_FROSTWOLF_GRAVE = 27, + BG_AV_OBJECT_FLAG_C_H_FROSTWOLF_HUT = 28, + BG_AV_OBJECT_FLAG_C_H_DUNBALDAR_SOUTH = 29, + BG_AV_OBJECT_FLAG_C_H_DUNBALDAR_NORTH = 30, + BG_AV_OBJECT_FLAG_C_H_ICEWING_BUNKER = 31, + BG_AV_OBJECT_FLAG_C_H_STONEHEART_BUNKER = 32, + + BG_AV_OBJECT_FLAG_H_FIRSTAID_STATION = 33, + BG_AV_OBJECT_FLAG_H_STORMPIKE_GRAVE = 34, + BG_AV_OBJECT_FLAG_H_STONEHEART_GRAVE = 35, + BG_AV_OBJECT_FLAG_H_SNOWFALL_GRAVE = 36, + BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE = 37, + BG_AV_OBJECT_FLAG_H_FROSTWOLF_GRAVE = 38, + BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT = 39, + BG_AV_OBJECT_FLAG_H_ICEBLOOD_TOWER = 40, + BG_AV_OBJECT_FLAG_H_TOWER_POINT = 41, + BG_AV_OBJECT_FLAG_H_FROSTWOLF_ETOWER = 42, + BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER = 43, + + BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE = 44, + + BG_AV_OBJECT_DOOR_H = 45, + BG_AV_OBJECT_DOOR_A = 46, +//auras for graveyards (3auras per graveyard neutral,alliance,horde) + BG_AV_OBJECT_AURA_N_FIRSTAID_STATION = 47, + BG_AV_OBJECT_AURA_A_FIRSTAID_STATION = 48, + BG_AV_OBJECT_AURA_H_FIRSTAID_STATION = 49, + BG_AV_OBJECT_AURA_N_STORMPIKE_GRAVE = 50, + BG_AV_OBJECT_AURA_A_STORMPIKE_GRAVE = 51, + BG_AV_OBJECT_AURA_H_STORMPIKE_GRAVE = 52, + BG_AV_OBJECT_AURA_N_STONEHEART_GRAVE = 53, + BG_AV_OBJECT_AURA_A_STONEHEART_GRAVE = 54, + BG_AV_OBJECT_AURA_H_STONEHEART_GRAVE = 55, + BG_AV_OBJECT_AURA_N_SNOWFALL_GRAVE = 56, + BG_AV_OBJECT_AURA_A_SNOWFALL_GRAVE = 57, + BG_AV_OBJECT_AURA_H_SNOWFALL_GRAVE = 58, + BG_AV_OBJECT_AURA_N_ICEBLOOD_GRAVE = 59, + BG_AV_OBJECT_AURA_A_ICEBLOOD_GRAVE = 60, + BG_AV_OBJECT_AURA_H_ICEBLOOD_GRAVE = 61, + BG_AV_OBJECT_AURA_N_FROSTWOLF_GRAVE = 62, + BG_AV_OBJECT_AURA_A_FROSTWOLF_GRAVE = 63, + BG_AV_OBJECT_AURA_H_FROSTWOLF_GRAVE = 64, + BG_AV_OBJECT_AURA_N_FROSTWOLF_HUT = 65, + BG_AV_OBJECT_AURA_A_FROSTWOLF_HUT = 66, + BG_AV_OBJECT_AURA_H_FROSTWOLF_HUT = 67, + + //big flags on top of towers 2 flags on each (contested,(alliance | horde)) + 2 auras + BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH = 67, + BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH = 68, + BG_AV_OBJECT_TFLAG_A_DUNBALDAR_NORTH = 69, + BG_AV_OBJECT_TFLAG_H_DUNBALDAR_NORTH = 70, + BG_AV_OBJECT_TFLAG_A_ICEWING_BUNKER = 71, + BG_AV_OBJECT_TFLAG_H_ICEWING_BUNKER = 72, + BG_AV_OBJECT_TFLAG_A_STONEHEART_BUNKER = 73, + BG_AV_OBJECT_TFLAG_H_STONEHEART_BUNKER = 74, + BG_AV_OBJECT_TFLAG_A_ICEBLOOD_TOWER = 75, + BG_AV_OBJECT_TFLAG_H_ICEBLOOD_TOWER = 76, + BG_AV_OBJECT_TFLAG_A_TOWER_POINT = 77, + BG_AV_OBJECT_TFLAG_H_TOWER_POINT = 78, + BG_AV_OBJECT_TFLAG_A_FROSTWOLF_ETOWER = 79, + BG_AV_OBJECT_TFLAG_H_FROSTWOLF_ETOWER = 80, + BG_AV_OBJECT_TFLAG_A_FROSTWOLF_WTOWER = 81, + BG_AV_OBJECT_TFLAG_H_FROSTWOLF_WTOWER = 82, + BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH = 83, + BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH = 84, + BG_AV_OBJECT_TAURA_A_DUNBALDAR_NORTH = 85, + BG_AV_OBJECT_TAURA_H_DUNBALDAR_NORTH = 86, + BG_AV_OBJECT_TAURA_A_ICEWING_BUNKER = 87, + BG_AV_OBJECT_TAURA_H_ICEWING_BUNKER = 88, + BG_AV_OBJECT_TAURA_A_STONEHEART_BUNKER = 89, + BG_AV_OBJECT_TAURA_H_STONEHEART_BUNKER = 90, + BG_AV_OBJECT_TAURA_A_ICEBLOOD_TOWER = 91, + BG_AV_OBJECT_TAURA_H_ICEBLOOD_TOWER = 92, + BG_AV_OBJECT_TAURA_A_TOWER_POINT = 93, + BG_AV_OBJECT_TAURA_H_TOWER_POINT = 94, + BG_AV_OBJECT_TAURA_A_FROSTWOLF_ETOWER = 95, + BG_AV_OBJECT_TAURA_H_FROSTWOLF_ETOWER = 96, + BG_AV_OBJECT_TAURA_A_FROSTWOLF_WTOWER = 97, + BG_AV_OBJECT_TAURA_H_FROSTWOLF_WTOWER = 98, + + BG_AV_OBJECT_BURN_DUNBALDAR_SOUTH = 99, + BG_AV_OBJECT_BURN_DUNBALDAR_NORTH = 109, + BG_AV_OBJECT_BURN_ICEWING_BUNKER = 119, + BG_AV_OBJECT_BURN_STONEHEART_BUNKER = 129, + BG_AV_OBJECT_BURN_ICEBLOOD_TOWER = 139, + BG_AV_OBJECT_BURN_TOWER_POINT = 149, + BG_AV_OBJECT_BURN_FROSTWOLF_ETWOER = 159, + BG_AV_OBJECT_BURN_FROSTWOLF_WTOWER = 169, + BG_AV_OBJECT_BURN_BUILDING_ALLIANCE = 179, + BG_AV_OBJECT_BURN_BUILDING_HORDE = 189, + BG_AV_OBJECT_SNOW_EYECANDY_A = 199, + BG_AV_OBJECT_SNOW_EYECANDY_PA = 203, + BG_AV_OBJECT_SNOW_EYECANDY_H = 207, + BG_AV_OBJECT_SNOW_EYECANDY_PH = 211, + BG_AV_OBJECT_MINE_SUPPLY_N_MIN = 215, + BG_AV_OBJECT_MINE_SUPPLY_N_MAX = 224, + BG_AV_OBJECT_MINE_SUPPLY_S_MIN = 225, + BG_AV_OBJECT_MINE_SUPPLY_S_MAX = 236, + + BG_AV_OBJECT_MAX = 237 +}; + +enum BG_AV_OBJECTS +{ + AV_OPLACE_FIRSTAID_STATION = 0, + AV_OPLACE_STORMPIKE_GRAVE = 1, + AV_OPLACE_STONEHEART_GRAVE = 2, + AV_OPLACE_SNOWFALL_GRAVE = 3, + AV_OPLACE_ICEBLOOD_GRAVE = 4, + AV_OPLACE_FROSTWOLF_GRAVE = 5, + AV_OPLACE_FROSTWOLF_HUT = 6, + AV_OPLACE_DUNBALDAR_SOUTH = 7, + AV_OPLACE_DUNBALDAR_NORTH = 8, + AV_OPLACE_ICEWING_BUNKER = 9, + AV_OPLACE_STONEHEART_BUNKER = 10, + AV_OPLACE_ICEBLOOD_TOWER = 11, + AV_OPLACE_TOWER_POINT = 12, + AV_OPLACE_FROSTWOLF_ETOWER = 13, + AV_OPLACE_FROSTWOLF_WTOWER = 14, + AV_OPLACE_BIGBANNER_DUNBALDAR_SOUTH = 15, + AV_OPLACE_BIGBANNER_DUNBALDAR_NORTH = 16, + AV_OPLACE_BIGBANNER_ICEWING_BUNKER = 17, + AV_OPLACE_BIGBANNER_STONEHEART_BUNKER = 18, + AV_OPLACE_BIGBANNER_ICEBLOOD_TOWER = 19, + AV_OPLACE_BIGBANNER_TOWER_POINT = 20, + AV_OPLACE_BIGBANNER_FROSTWOLF_ETOWER = 21, + AV_OPLACE_BIGBANNER_FROSTWOLF_WTOWER = 22, + + AV_OPLACE_BURN_DUNBALDAR_SOUTH = 23, + AV_OPLACE_BURN_DUNBALDAR_NORTH = 33, + AV_OPLACE_BURN_ICEWING_BUNKER = 43, + AV_OPLACE_BURN_STONEHEART_BUNKER = 53, + AV_OPLACE_BURN_ICEBLOOD_TOWER = 63, + AV_OPLACE_BURN_TOWER_POINT = 73, + AV_OPLACE_BURN_FROSTWOLF_ETOWER = 83, + AV_OPLACE_BURN_FROSTWOLF_WTOWER = 93, + AV_OPLACE_BURN_BUILDING_A = 103, + AV_OPLACE_BURN_BUILDING_H = 113, + AV_OPLACE_SNOW_1 = 123, + AV_OPLACE_SNOW_2 = 124, + AV_OPLACE_SNOW_3 = 125, + AV_OPLACE_SNOW_4 = 126, + AV_OPLACE_MINE_SUPPLY_N_MIN = 127, + AV_OPLACE_MINE_SUPPLY_N_MAX = 136, + AV_OPLACE_MINE_SUPPLY_S_MIN = 137, + AV_OPLACE_MINE_SUPPLY_S_MAX = 148, + + AV_OPLACE_MAX = 149 +}; +const float BG_AV_ObjectPos[AV_OPLACE_MAX][4] = { + {638.592f,-32.422f,46.0608f,-1.62316f },//firstaid station + {669.007f,-294.078f,30.2909f,2.77507f },//stormpike + {77.8013f,-404.7f,46.7549f,-0.872665f },//stone grave + {-202.581f,-112.73f,78.4876f,-0.715585f },//snowfall + {-611.962f,-396.17f,60.8351f,2.53682f}, //iceblood grave + {-1082.45f,-346.823f,54.9219f,-1.53589f },//frostwolf grave + {-1402.21f,-307.431f,89.4424f,0.191986f },//frostwolf hut + {553.779f,-78.6566f,51.9378f,-1.22173f }, //dunnbaldar south + {674.001f,-143.125f,63.6615f,0.994838f }, //dunbaldar north + {203.281f,-360.366f,56.3869f,-0.925024f }, //icew + {-152.437f,-441.758f,40.3982f,-1.95477f }, //stone + {-571.88f,-262.777f,75.0087f,-0.802851f }, //ice tower + {-768.907f,-363.71f,90.8949f,1.07991f}, //tower point + {-1302.9f,-316.981f,113.867f,2.00713f }, //frostwolf etower + {-1297.5f,-266.767f,114.15f,3.31044f}, //frostwolf wtower + //bigbanner: + {555.848f,-84.4151f,64.4397f,3.12414f }, //duns + {679.339f,-136.468f,73.9626f,-2.16421f }, //dunn + {208.973f,-365.971f,66.7409f,-0.244346f }, //icew + {-155.832f,-449.401f,52.7306f,0.610865f }, //stone + {-572.329f,-262.476f,88.6496f,-0.575959f }, //icetower + {-768.199f,-363.105f,104.537f,0.10472f }, //towerp + {-1302.84f,-316.582f,127.516f,0.122173f }, //etower + {-1297.87f,-266.762f,127.796f,0.0698132f }, //wtower + //burning auras towers have 9*179065 captain-buildings have 5*179066+5*179065 + //dunns + {562.632f,-88.1815f,61.993f,0.383972f }, + {562.523f,-74.5028f,37.9474f,-0.0523599f }, + {558.097f,-70.9842f,52.4876f,0.820305f }, + {578.167f,-71.8191f,38.1514f,2.72271f }, + {556.028f,-94.9242f,44.8191f,3.05433f }, + {572.451f,-94.3655f,37.9443f,-1.72788f }, + {549.263f,-79.3645f,44.8191f,0.436332f }, + {543.513f,-94.4006f,52.4819f,0.0349066f }, + {572.149f,-93.7862f,52.5726f,0.541052f }, + {582.162f,-81.2375f,37.9216f,0.0872665f }, + //dunn + {664.797f,-143.65f,64.1784f,-0.453786f}, + {664.505f,-139.452f,49.6696f,-0.0349067f}, + {676.067f,-124.319f,49.6726f,-1.01229f}, + {693.004f,-144.025f,64.1755f,2.44346f}, + {661.175f,-117.691f,49.645f,1.91986f}, + {684.423f,-146.582f,63.6662f,0.994838f}, + {682.791f,-127.769f,62.4155f,1.09956f}, + {674.576f,-147.101f,56.5425f,-1.6057f}, + {655.719f,-126.673f,49.8138f,2.80998f}, + {0,0,0,0}, + //icew + {231.503f,-356.688f,42.3704f,0.296706f}, + {224.989f,-348.175f,42.5607f,1.50098f}, + {205.782f,-351.335f,56.8998f,1.01229f}, + {196.605f,-369.187f,56.3914f,2.46091f}, + {210.619f,-376.938f,49.2677f,2.86234f}, + {209.647f,-352.632f,42.3959f,-0.698132f}, + {220.65f,-368.132f,42.3978f,-0.2618f}, + {224.682f,-374.031f,57.0679f,0.541052f}, + {200.26f,-359.968f,49.2677f,-2.89725f}, + {196.619f,-378.016f,56.9131f,1.01229f}, + //stone + {-155.488f,-437.356f,33.2796f,2.60054f}, + {-163.441f,-454.188f,33.2796f,1.93732f}, + {-143.977f,-445.148f,26.4097f,-1.8675f}, + {-135.764f,-464.708f,26.3823f,2.25147f}, + {-154.076f,-466.929f,41.0636f,-1.8675f}, + {-149.908f,-460.332f,26.4083f,-2.09439f}, + {-151.638f,-439.521f,40.3797f,0.436332f}, + {-131.301f,-454.905f,26.5771f,2.93215f}, + {-171.291f,-444.684f,40.9211f,2.30383f}, + {-143.591f,-439.75f,40.9275f,-1.72788f}, + //iceblood + {-572.667f,-267.923f,56.8542f,2.35619f}, + {-561.021f,-262.689f,68.4589f,1.37881f}, + {-572.538f,-262.649f,88.6197f,1.8326f}, + {-574.77f,-251.45f,74.9422f,-1.18682f}, + {-578.625f,-267.571f,68.4696f,0.506145f}, + {-571.476f,-257.234f,63.3223f,3.10669f}, + {-566.035f,-273.907f,52.9582f,-0.890118f}, + {-580.948f,-259.77f,68.4696f,1.46608f}, + {-568.318f,-267.1f,75.0008f,1.01229f}, + {-559.621f,-268.597f,52.8986f,0.0523599f}, + //towerp + {-776.072f,-368.046f,84.3558f,2.63545f}, + {-777.564f,-368.521f,90.6701f,1.72788f}, + {-765.461f,-357.711f,90.888f,0.314159f}, + {-768.763f,-362.735f,104.612f,1.81514f}, + {-760.356f,-358.896f,84.3558f,2.1293f}, + {-771.967f,-352.838f,84.3484f,1.74533f}, + {-773.333f,-364.653f,79.2351f,-1.64061f}, + {-764.109f,-366.069f,70.0934f,0.383972f}, + {-767.103f,-350.737f,68.7933f,2.80998f}, + {-760.115f,-353.845f,68.8633f,1.79769f}, + //froste + {-1304.87f,-304.525f,91.8366f,-0.680679f}, + {-1301.77f,-310.974f,95.8252f,0.907571f}, + {-1305.58f,-320.625f,102.166f,-0.558505f}, + {-1294.27f,-323.468f,113.893f,-1.67552f}, + {-1302.65f,-317.192f,127.487f,2.30383f}, + {-1293.89f,-313.478f,107.328f,1.6057f}, + {-1312.41f,-312.999f,107.328f,1.5708f}, + {-1311.57f,-308.08f,91.7666f,-1.85005f}, + {-1314.7f,-322.131f,107.36f,0.645772f}, + {-1304.6f,-310.754f,113.859f,-0.401426f}, + //frostw + {-1308.24f,-273.26f,92.0514f,-0.139626f}, + {-1302.26f,-262.858f,95.9269f,0.418879f}, + {-1297.28f,-267.773f,126.756f,2.23402f}, + {-1299.08f,-256.89f,114.108f,-2.44346f}, + {-1303.41f,-268.237f,114.151f,-1.23918f}, + {-1304.43f,-273.682f,107.612f,0.244346f}, + {-1309.53f,-265.951f,92.1418f,-2.49582f}, + {-1295.55f,-263.865f,105.033f,0.925024f}, + {-1294.71f,-281.466f,107.664f,-1.50098f}, + {-1289.69f,-259.521f,107.612f,-2.19912f}, + + //the two buildings of the captains + //alliance + {-64.4987f,-289.33f,33.4616f,-2.82743f}, + {-5.98025f,-326.144f,38.8538f,0}, + {-2.67893f,-306.998f,33.4165f,0}, + {-60.25f,-309.232f,50.2408f,-1.46608f}, + {-48.7941f,-266.533f,47.7916f,2.44346f}, + {-3.40929f,-306.288f,33.34f,0}, + {-48.619f,-266.917f,47.8168f,0}, + {-62.9474f,-286.212f,66.7288f,0}, + {-5.05132f,-325.323f,38.8536f,0}, + {-64.2677f,-289.412f,33.469f,0}, +//horde + {-524.276f,-199.6f,82.8733f,-1.46608f}, + {-518.196f,-173.085f,102.43f,0}, + {-500.732f,-145.358f,88.5337f,2.44346f}, + {-501.084f,-150.784f,80.8506f,0}, + {-518.309f,-163.963f,102.521f,2.96706f}, + {-517.053f,-200.429f,80.759f,0}, + {-514.361f,-163.864f,104.163f,0}, + {-568.04f,-188.707f,81.55f,0}, + {-501.775f,-151.581f,81.2027f,0}, + {-509.975f,-191.652f,83.2978f,0}, + +//snowfall eyecandy + {-191.153f,-129.868f,78.5595f,-1.25664f }, + {-201.282f,-134.319f,78.6753f,-0.942478f }, + {-215.981f,-91.4101f,80.8702f,-1.74533f }, + {-200.465f,-96.418f,79.7587f,1.36136f }, + //mine supplies + //irondeep + {870.899f,-388.434f,61.6406f,-1.22173f}, + {825.214f,-320.174f,63.712f,-2.82743f}, + {837.117f,-452.556f,47.2331f,-3.12414f}, + {869.755f,-448.867f,52.5448f,-0.855212f}, + {949.877f,-458.198f,56.4874f,0.314159f}, + {900.35f,-479.024f,58.3553f,0.122173f}, + {854.449f,-442.255f,50.6589f,0.401426f}, + {886.685f,-442.358f,54.6962f,-1.22173f}, + {817.509f,-457.331f,48.4666f,2.07694f}, + {793.411f,-326.281f,63.1117f,-2.79253f}, + //coldtooth + {-934.212f,-57.3517f,80.277f,-0.0174535f}, + {-916.281f,-36.8579f,77.0227f,0.122173f}, + {-902.73f,-103.868f,75.4378f,-1.58825f}, + {-900.514f,-143.527f,75.9686f,1.8675f}, + {-862.882f,-0.353299f,72.1526f,-2.51327f}, + {-854.932f,-85.9184f,68.6056f,-2.04204f}, + {-851.833f,-118.959f,63.8672f,-0.0698131f}, + {-849.832f,-20.8421f,70.4672f,-1.81514f}, + {-844.25f,-60.0374f,72.1031f,-2.19912f}, + {-820.644f,-136.043f,63.1977f,2.40855f}, + {-947.642f,-208.807f,77.0101f,1.36136f}, + {-951.394f,-193.695f,67.634f,0.802851f} +}; + +const float BG_AV_DoorPositons[2][4] = { + {780.487f, -493.024f, 99.9553f, 3.0976f}, //alliance + {-1375.193f, -538.981f, 55.2824f, 0.72178f} //horde +}; + +//creaturestuff starts here +//is related to BG_AV_CreaturePos +enum BG_AV_CreaturePlace +{ + AV_CPLACE_SPIRIT_STORM_AID = 0, + AV_CPLACE_SPIRIT_STORM_GRAVE = 1, + AV_CPLACE_SPIRIT_STONE_GRAVE = 2, + AV_CPLACE_SPIRIT_SNOWFALL = 3, + AV_CPLACE_SPIRIT_ICE_GRAVE = 4, + AV_CPLACE_SPIRIT_FROSTWOLF = 5, + AV_CPLACE_SPIRIT_FROST_HUT = 6, + AV_CPLACE_SPIRIT_MAIN_ALLIANCE = 7, + AV_CPLACE_SPIRIT_MAIN_HORDE = 8, +//i don't will add for all 4 positions a variable.. i think one is enough to compute the rest + AV_CPLACE_DEFENSE_STORM_AID = 9, + AV_CPLACE_DEFEMSE_STORM_GRAVE = 13, + AV_CPLACE_DEFENSE_STONE_GRAVE = 17, + AV_CPLACE_DEFENSE_SNOWFALL = 21, + AV_CPLACE_DEFENSE_FROSTWOLF = 25, + AV_CPLACE_DEFENSE_ICE_GRAVE = 29, + AV_CPLACE_DEFENSE_FROST_HUT = 33, + + AV_CPLACE_DEFENSE_DUN_S = 37, + AV_CPLACE_DEFENSE_DUN_N = 41, + AV_CPLACE_DEFENSE_ICEWING = 45, + AV_CPLACE_DEFENSE_STONE_TOWER = 49, + AV_CPLACE_DEFENSE_ICE_TOWER = 53, + AV_CPLACE_DEFENSE_TOWERPOINT = 57, + AV_CPLACE_DEFENSE_FROST_E = 61, + AV_CPLACE_DEFENSE_FROST_t = 65, + + AV_CPLACE_A_MARSHAL_SOUTH = 69, + AV_CPLACE_A_MARSHAL_NORTH = 70, + AV_CPLACE_A_MARSHAL_ICE = 71, + AV_CPLACE_A_MARSHAL_STONE = 72, + AV_CPLACE_H_MARSHAL_ICE = 73, + AV_CPLACE_H_MARSHAL_TOWER = 74, + AV_CPLACE_H_MARSHAL_ETOWER = 75, + AV_CPLACE_H_MARSHAL_WTOWER = 76, + //irondeep + //miner: + AV_CPLACE_MINE_N_1_MIN = 77, + AV_CPLACE_MINE_N_1_MAX = 136, + //special types + AV_CPLACE_MINE_N_2_MIN = 137, + AV_CPLACE_MINE_N_2_MAX = 192, + //boss + AV_CPLACE_MINE_N_3 = 193, + //coldtooth + //miner: + AV_CPLACE_MINE_S_1_MIN = 194, + AV_CPLACE_MINE_S_1_MAX = 250, + //special types + AV_CPLACE_MINE_S_2_MIN = 251, + AV_CPLACE_MINE_S_2_MAX = 289, + //vermin + AV_CPLACE_MINE_S_S_MIN = 290, + AV_CPLACE_MINE_S_S_MAX = 299, + //boss + AV_CPLACE_MINE_S_3 = 300, + + //herald + AV_CPLACE_HERALD = 301, + + //node aura triggers + AV_CPLACE_TRIGGER01 = 302, + AV_CPLACE_TRIGGER02 = 303, + AV_CPLACE_TRIGGER03 = 304, + AV_CPLACE_TRIGGER04 = 305, + AV_CPLACE_TRIGGER05 = 306, + AV_CPLACE_TRIGGER06 = 307, + AV_CPLACE_TRIGGER07 = 308, + AV_CPLACE_TRIGGER08 = 309, + AV_CPLACE_TRIGGER09 = 310, + AV_CPLACE_TRIGGER10 = 311, + AV_CPLACE_TRIGGER11 = 312, + AV_CPLACE_TRIGGER12 = 313, + AV_CPLACE_TRIGGER13 = 314, + AV_CPLACE_TRIGGER14 = 315, + AV_CPLACE_TRIGGER15 = 316, + + //boss,captain triggers + AV_CPLACE_TRIGGER16 = 317, + AV_CPLACE_TRIGGER17 = 318, + AV_CPLACE_TRIGGER18 = 319, + AV_CPLACE_TRIGGER19 = 320, + + AV_CPLACE_MAX = 321 +}; + +//x, y, z, o +const float BG_AV_CreaturePos[AV_CPLACE_MAX][4] = { + //spiritguides + {643.000000f,44.000000f,69.740196f,-0.001854f}, + {676.000000f,-374.000000f,30.000000f,-0.001854f}, + {73.417755f,-496.433105f,48.731918f,-0.001854f}, + {-157.409195f,31.206272f,77.050598f,-0.001854f}, + {-531.217834f,-405.231384f,49.551376f,-0.001854f}, + {-1090.476807f,-253.308670f,57.672371f,-0.001854f}, + {-1496.065063f,-333.338409f,101.134804f,-0.001854f}, + {873.001770f,-491.283630f,96.541931f,-0.001854f}, + {-1437.670044f,-610.088989f,51.161900f,-0.001854f}, + //grave + //firstaid + {635.17f,-29.5594f,46.5056f,4.81711f}, + {642.488f,-32.9437f,46.365f,4.67748f}, + {642.326f,-27.9442f,46.9211f,4.59022f}, + {635.945f,-33.6171f,45.7164f,4.97419f}, + //stormpike + {669.272f,-297.304f,30.291f,4.66604f}, + {674.08f,-292.328f,30.4817f,0.0918785f}, + {667.01f,-288.532f,29.8809f,1.81583f}, + {664.153f,-294.042f,30.2851f,3.28531f}, + //stone + {81.7027f,-406.135f,47.7843f,0.598464f}, + {78.1431f,-409.215f,48.0401f,5.05953f}, + {73.4135f,-407.035f,46.7527f,3.34736f}, + {78.2258f,-401.859f,46.4202f,2.05852f}, + //snowfall + {-207.412f,-110.616f,78.7959f,2.43251f}, + {-197.95f,-112.205f,78.5686f,6.22441f}, + {-202.709f,-116.829f,78.4358f,5.13742f}, + {-202.059f,-108.314f,78.5783f,5.91968f}, + //ice + {-615.501f,-393.802f,60.4299f,3.06147f}, + {-608.513f,-392.717f,62.5724f,2.06323f}, + {-609.769f,-400.072f,60.7174f,5.22367f}, + {-616.093f,-398.293f,60.5628f,3.73613f}, + //frost + {-1077.7f,-340.21f,55.4682f,6.25569f}, + {-1082.74f,-333.821f,54.7962f,2.05459f}, + {-1090.66f,-341.267f,54.6768f,3.27746f}, + {-1081.58f,-344.63f,55.256f,4.75636f}, + //frost hut + {-1408.95f,-311.69f,89.2536f,4.49954f}, + {-1407.15f,-305.323f,89.1993f,2.86827f}, + {-1400.64f,-304.3f,89.7008f,1.0595f}, + {-1400.4f,-311.35f,89.3028f,4.99434f}, + //towers + //dun south - OK + {569.395f,-101.064f,52.8296f,2.34974f}, + {574.85f,-92.9842f,52.5869f,3.09325f}, + {575.411f,-83.597f,52.3626f,6.26573f}, + {571.352f,-75.6582f,52.479f,0.523599f}, + //dun north - OK + {668.60f,-122.53f,64.12f,2.34f}, //not 100% ok + {662.253f,-129.105f,64.1794f,2.77507f}, + {661.209f,-138.877f,64.2251f,3.38594f}, + {665.481f,-146.857f,64.1271f,3.75246f}, + //icewing - OK + {225.228f,-368.909f,56.9983f,6.23806f}, + {191.36f,-369.899f,57.1524f,3.24631f}, + {215.518f,-384.019f,56.9889f,5.09636f}, + {199.625f,-382.177f,56.8691f,4.08407f}, + //stone + {-172.851f,-452.366f,40.8725f,3.31829f}, + {-147.147f,-435.053f,40.8022f,0.599238f}, + {-169.456f,-440.325f,40.985f,2.59101f}, + {-163.494f,-434.904f,41.0725f,1.84174f}, + //ice - OK + {-573.522f,-271.854f,75.0078f,3.9619f}, + {-565.616f,-269.051f,74.9952f,5.02655f}, + {-562.825f,-261.087f,74.9898f,5.95157f}, + {-569.176f,-254.446f,74.8771f,0.820305f}, + //towerpoint + {-763.04f,-371.032f,90.7933f,5.25979f}, + {-759.764f,-358.264f,90.8681f,0.289795f}, + {-768.808f,-353.056f,90.8811f,1.52601f}, + {-775.944f,-362.639f,90.8949f,2.59573f}, + //frost etower + {-1294.13f,-313.045f,107.328f,0.270162f}, + {-1306.5f,-308.105f,113.767f,1.78755f}, + {-1294.78f,-319.966f,113.79f,5.94545f}, + {-1294.83f,-312.241f,113.799f,0.295293f}, + //frost wtower + {-1300.96f,-275.111f,114.058f,4.12804f}, + {-1302.41f,-259.256f,114.065f,1.67602f}, + {-1287.97f,-262.087f,114.165f,6.18264f}, + {-1291.59f,-271.166f,114.151f,5.28257f}, + + //alliance marshall + {721.104f,-7.64155f,50.7046f,3.45575f},// south + {723.058f,-14.1548f,50.7046f,3.40339f},// north + {715.691f,-4.72233f,50.2187f,3.47321f},// icewing + {720.046f,-19.9413f,50.2187f,3.36849f},// stone +//horde (coords not 100% ok) + {-1363.99f,-221.99f,98.4053f,4.93012f}, + {-1370.96f,-223.532f,98.4266f,4.93012f}, + {-1378.37f,-228.614f,99.3546f,5.38565f}, + {-1358.02f,-228.998f,98.868f,3.87768f}, + + //irondeep mine + //Irondeep Trogg + {971.671f,-442.657f,57.6951f,3.1765f}, + {969.979f,-457.148f,58.1119f,4.5204f}, + {958.692f,-333.477f,63.2276f,5.77704f}, + {957.113f,-325.92f,61.7589f,1.13446f}, + {948.25f,-448.268f,56.9009f,5.60251f}, + {934.727f,-385.802f,63.0344f,3.75246f}, + {931.751f,-403.458f,59.6737f,5.63741f}, + {931.146f,-359.666f,66.0294f,3.9619f}, + {929.702f,-412.401f,56.8776f,5.89921f}, + {926.849f,-379.074f,63.5286f,2.0944f}, + {921.972f,-358.597f,66.4313f,2.93215f}, + {921.449f,-341.981f,67.1264f,3.4383f}, + {921.1f,-395.812f,60.4615f,2.71695f}, + {919.274f,-394.986f,60.3478f,2.71696f}, + {916.852f,-393.891f,60.1726f,2.71695f}, + {914.568f,-326.21f,66.1733f,2.25147f}, + {913.064f,-395.773f,60.1364f,4.41568f}, + {909.246f,-474.576f,58.2067f,0.226893f}, + {909.246f,-474.576f,58.2901f,0.226893f}, + {907.209f,-428.267f,59.8065f,1.8675f}, + {905.973f,-459.528f,58.7594f,1.37189f}, + {905.067f,-396.074f,60.2085f,5.07891f}, + {901.809f,-457.709f,59.0116f,3.52557f}, + {900.962f,-427.44f,59.0842f,1.50098f}, + {897.929f,-471.742f,59.7729f,2.54818f}, + {893.376f,-343.171f,68.1499f,5.35816f}, + {890.584f,-406.049f,61.1925f,5.67232f}, + {888.208f,-332.564f,68.148f,1.93732f}, + {887.647f,-391.537f,61.8734f,1.37881f}, + {885.109f,-343.338f,67.0867f,3.78979f}, + {881.618f,-419.948f,53.5228f,0.593412f}, + {878.675f,-345.36f,66.1052f,3.45651f}, + {877.127f,-351.8f,66.5296f,5.74213f}, + {876.778f,-345.97f,65.7724f,3.45262f}, + {874.577f,-414.786f,52.7817f,1.67552f}, + {868.247f,-343.136f,64.9894f,1.6057f}, + {859.03f,-367.231f,47.4655f,0.0174533f}, + {857.513f,-351.817f,65.1867f,4.39823f}, + {852.632f,-372.416f,48.1657f,3.66519f}, + {849.86f,-340.944f,66.2447f,0.401426f}, + {847.99f,-386.287f,60.9277f,2.32374f}, + {847.601f,-423.072f,50.0852f,4.57276f}, + {847.135f,-411.307f,50.2106f,1.5708f}, + {835.077f,-379.418f,48.2755f,5.93412f}, + {834.87f,-453.304f,47.9075f,0.226893f}, + {834.634f,-365.981f,62.8801f,1.32645f}, + {834.354f,-355.526f,48.1491f,6.07375f}, + {833.702f,-327.506f,65.0439f,0.331613f}, + {833.151f,-374.228f,63.0938f,3.66519f}, + {831.711f,-346.785f,47.2975f,0.226893f}, + {827.874f,-413.624f,48.5818f,1.49241f}, + {827.728f,-415.483f,48.5593f,1.49238f}, + {827.016f,-424.543f,48.2856f,1.49236f}, + {823.222f,-334.283f,65.6306f,4.88692f}, + {821.892f,-464.723f,48.9451f,4.66003f}, + {821.006f,-387.635f,49.0728f,3.15905f}, + {817.26f,-447.432f,49.4308f,2.18166f}, + {805.399f,-320.146f,52.7712f,0.296706f}, + {801.405f,-328.055f,53.0195f,4.31096f}, + //irondeep skullthumber irondeep shaman + {955.812f,-440.302f,55.3411f,3.19395f}, + {937.378f,-377.816f,65.3919f,3.56047f}, + {925.059f,-331.347f,65.7564f,3.66519f}, + {922.918f,-396.634f,60.3942f,2.71695f}, + {909.99f,-462.154f,59.0811f,3.7001f}, + {907.893f,-388.787f,61.7923f,5.74213f}, + {898.801f,-437.105f,58.5266f,0.959931f}, + {884.237f,-407.597f,61.566f,0.820305f}, + {880.744f,-344.683f,66.4086f,3.4644f}, + {876.047f,-341.857f,65.8743f,4.45059f}, + {874.674f,-402.077f,61.7573f,0.26341f}, + {871.914f,-404.209f,62.1269f,6.06163f}, + {871.606f,-403.665f,62.0795f,0.765774f}, + {871.561f,-404.114f,62.1297f,0.00981727f}, + {871.528f,-404.248f,62.1455f,0.498032f}, + {871.493f,-404.122f,62.1331f,5.65727f}, + {871.282f,-403.843f,62.1108f,0.788382f}, + {868.294f,-392.395f,61.4772f,4.38685f}, + {868.256f,-392.363f,61.4803f,0.732738f}, + {867.804f,-392.51f,61.5089f,2.30167f}, + {867.612f,-392.371f,61.524f,2.86149f}, + {858.593f,-439.614f,50.2184f,0.872665f}, + {851.471f,-362.52f,47.314f,4.06662f}, + {846.939f,-347.279f,66.2876f,0.942478f}, + {842.08f,-421.775f,48.2659f,1.0821f}, + {838.358f,-371.212f,63.3299f,4.04916f}, + {827.57f,-417.483f,48.4538f,1.49237f}, + {827.012f,-457.397f,48.9331f,2.35619f}, + {825.535f,-322.373f,63.9357f,4.76475f}, + {867.635f,-443.605f,51.3347f,1.38626f}, + {957.293f,-455.039f,56.7395f,5.79449f}, + {950.077f,-326.672f,61.6552f,5.48033f}, + {936.692f,-356.78f,65.9835f,2.75762f}, + {926.475f,-419.345f,56.1833f,2.0944f}, + {924.729f,-397.453f,60.213f,2.71695f}, + {902.195f,-475.891f,58.312f,1.39626f}, + {897.464f,-338.758f,68.1715f,2.94961f}, + {884.237f,-407.597f,61.566f,0.820305f}, + {882.517f,-344.111f,66.7887f,3.46962f}, + {881.437f,-400.254f,61.2028f,0.263427f}, + {880.156f,-400.678f,61.3113f,3.41373f}, + {877.989f,-418.051f,52.9753f,4.46804f}, + {871.212f,-404.12f,62.1433f,3.6554f}, + {871.036f,-404.119f,62.2237f,4.50295f}, + {857.396f,-395.766f,61.263f,4.78684f}, + {857.276f,-395.395f,61.2418f,0.0845553f}, + {857.231f,-394.577f,61.2174f,1.96817f}, + {857.108f,-395.682f,61.2317f,4.87022f}, + {856.709f,-395.28f,61.1814f,2.54913f}, + {850.922f,-390.399f,60.8771f,2.85405f}, + {847.556f,-388.228f,60.9438f,2.56872f}, + {842.031f,-384.663f,61.6028f,2.56871f}, + {832.035f,-389.301f,47.5567f,2.11185f}, + {827.415f,-419.468f,48.3322f,1.49232f}, + {826.402f,-349.454f,47.2722f,1.51844f}, + {817.83f,-455.715f,48.4207f,0.925025f}, + {808.953f,-325.964f,52.4043f,3.01942f}, + // Morloch + {865.554f,-438.735f,50.7333f,2.12431f}, + //coldtooth mine + //miner/digger + {-917.648f,-46.8922f,77.0872f,5.27089f}, + {-912.689f,-45.4494f,76.2277f,4.60767f}, + {-905.455f,-84.5179f,75.3642f,3.29867f}, + {-904.332f,-111.509f,75.5925f,2.47837f}, + {-904.27f,-160.419f,61.9876f,3.61192f}, + {-904.023f,-90.4558f,75.3706f,3.40339f}, + {-978.678f,-37.3136f,75.8364f,2.84489f}, + {-973.076f,-36.5013f,77.5047f,1.0821f}, + {-963.951f,-87.734f,81.5555f,0.575959f}, + {-961.941f,-90.7252f,81.6629f,0.820305f}, + {-957.623f,-186.582f,66.6021f,1.95477f}, + {-952.476f,-179.778f,78.6771f,4.5204f}, + {-950.427f,-115.007f,79.6127f,3.68264f}, + {-950.25f,-151.95f,79.4598f,-1.81423f}, + {-950.169f,-188.099f,66.6184f,5.55015f}, + {-949.944f,-142.977f,80.5382f,2.70526f}, + {-947.854f,-170.5f,79.7618f,0.942478f}, + {-946.738f,-139.567f,80.0904f,2.3911f}, + {-945.503f,-65.0654f,79.7907f,5.02655f}, + {-943.678f,-110.986f,80.2557f,0.959931f}, + {-942.993f,-56.9881f,79.8915f,5.65487f}, + {-938.197f,-155.838f,61.3111f,1.65806f}, + {-930.488f,-214.524f,72.1431f,2.1236f}, + {-929.947f,-154.449f,61.5084f,1.67552f}, + {-927.412f,-135.313f,61.1987f,3.29867f}, + {-920.677f,-156.859f,62.8033f,3.15306f}, + {-916.75f,-136.094f,62.2357f,0.0698132f}, + {-915.319f,-132.718f,62.562f,1.16984f}, + {-913.589f,-146.794f,76.9366f,1.8675f}, + {-907.572f,-148.937f,76.6898f,4.76475f}, + {-902.02f,-64.6174f,73.9707f,1.19169f}, + {-899.489f,-61.7252f,73.2498f,5.09636f}, + {-894.792f,-127.141f,75.3834f,6.14356f}, + {-892.408f,-162.525f,64.1212f,2.69884f}, + {-892.326f,-123.158f,76.0318f,5.5676f}, + {-888.468f,-148.462f,61.8012f,1.65806f}, + {-883.268f,-159.738f,63.5311f,5.20108f}, + {-877.76f,-118.07f,65.215f,2.94961f}, + {-876.792f,-128.646f,64.1045f,3.40339f}, + {-874.901f,-36.6579f,69.4246f,2.00713f}, + {-874.856f,-151.351f,62.7537f,3.57875f}, + {-872.135f,-150.08f,62.7513f,3.57201f}, + {-870.288f,-149.217f,62.5413f,3.56624f}, + {-870.03f,-6.27443f,70.3867f,2.3911f}, + {-869.023f,-82.2118f,69.5848f,3.22886f}, + {-866.354f,-40.2455f,70.842f,0.0698132f}, + {-865.305f,-152.302f,63.5044f,4.86947f}, + {-861.926f,-79.0519f,71.4178f,0.20944f}, + {-857.292f,-152.277f,63.2114f,4.18879f}, + {-853.357f,-0.696194f,72.0655f,0.994838f}, + {-850.685f,-14.2596f,70.2298f,0.20944f}, + {-839.987f,-67.7695f,72.7916f,4.93928f}, + {-839.199f,-57.0558f,73.4891f,1.67552f}, + {-836.963f,-153.224f,63.3821f,4.46804f}, + {-832.721f,-67.7555f,72.9062f,4.99164f}, + {-821.496f,-143.095f,63.1292f,0.541052f}, + {-818.829f,-153.004f,62.1757f,6.12611f}, + //special + {-954.622f,-110.958f,80.7911f,6.24828f}, + {-951.477f,-53.9647f,80.0235f,5.32325f}, + {-946.812f,-126.04f,78.8601f,5.15265f}, + {-940.689f,-140.707f,79.9225f,2.79253f}, + {-933.954f,-159.632f,60.778f,2.56563f}, + {-922.537f,-130.291f,61.3756f,4.95674f}, + {-915.862f,-151.74f,76.9427f,0.942478f}, + {-888.321f,-159.831f,62.5303f,1.20428f}, + {-874.361f,-42.4751f,69.4316f,0.785398f}, + {-873.19f,-50.4899f,70.0568f,-2.41288f}, + {-868.511f,-148.386f,62.3547f,3.57875f}, + {-868.44f,-121.649f,64.5056f,3.33358f}, + {-868.324f,-77.7196f,71.4768f,5.41052f}, + {-859.846f,-19.6549f,70.7304f,1.97222f}, + {-828.05f,-150.508f,62.2019f,2.14675f}, + {-826.254f,-58.6911f,72.0041f,3.68264f}, + {-976.086f,-44.1775f,76.029f,1.46608f}, + {-971.864f,-87.4223f,81.4954f,5.8294f}, + {-966.551f,-74.1111f,80.0243f,4.2129f}, + {-958.509f,-173.652f,77.9013f,6.24828f}, + {-951.511f,-181.242f,65.529f,4.39823f}, + {-940.967f,-186.243f,77.698f,1.28164f}, + {-930.004f,-65.0898f,79.077f,0.0581657f}, + {-920.864f,-40.2009f,78.256f,5.16617f}, + {-919.089f,-148.021f,62.0317f,2.59327f}, + {-901.516f,-116.329f,75.6876f,0.471239f}, + {-897.864f,-84.4348f,74.083f,3.00197f}, + {-897.617f,-52.0457f,71.9503f,4.36332f}, + {-894.891f,-153.951f,61.6827f,3.23569f}, + {-893.933f,-111.625f,75.6591f,4.22536f}, + {-883.265f,-152.854f,61.8384f,0.0941087f}, + {-868.293f,-147.243f,62.1097f,3.2056f}, + {-867.501f,-11.8709f,70.018f,6.14356f}, + {-866.699f,-147.54f,62.1646f,3.57878f}, + {-866.566f,-91.1916f,67.4414f,4.56707f}, + {-857.272f,-141.142f,61.7356f,4.17134f}, + {-847.446f,-98.0061f,68.5131f,3.24631f}, + {-837.026f,-140.729f,62.5141f,5.51524f}, + {-824.204f,-65.053f,72.3381f,3.01942f}, + //vermin (s.th special for this mine) + {-951.955f,-197.5f,77.212f,5.63741f}, + {-944.837f,-199.608f,77.0737f,4.97419f}, + {-933.494f,-209.063f,73.7803f,5.88176f}, + {-929.666f,-201.308f,73.7032f,5.02655f}, + {-978.997f,-249.356f,65.4345f,5.05464f}, + {-974.565f,-224.828f,69.5858f,4.88846f}, + {-946.514f,-259.239f,66.0874f,3.78132f}, + {-918.402f,-250.439f,69.5271f,2.21352f}, + {-910.14f,-229.959f,72.9279f,0.27677f}, + {-851.563f,-88.6527f,68.5983f,3.61896f}, + //boss + {-848.902f,-92.931f,68.6325f,3.33350}, + //herald + {-48.459f,-288.802f,55.47f,1.0}, + //triggers + {637.083,-32.6603,45.9715,1.14353}, //firstaid_station + {669.007f,-294.078f,30.2909f,2.77507f}, //stormpike_grave + {77.8013f,-404.7f,46.7549f,-0.872665f}, //stoneheart_grave + {-202.581f,-112.73f,78.4876f,-0.715585f}, //snowfall_grave + {-611.962f,-396.17f,60.8351f,2.53682f}, //iceblood_grave + {-1082.45f,-346.823f,54.9219f,-1.53589f}, //frostwolf_grave + {-1402.21f,-307.431f,89.4424f,0.191986f}, //frostwolf_hut + {553.779f,-78.6566f,51.9378f,-1.22173f}, //dunbaldar_south + {674.001f,-143.125f,63.6615f,0.994838f}, //dunbaldar_north + {203.281f,-360.366f,56.3869f,-0.925024}, //icewing_bunker + {-152.437f,-441.758f,40.3982f,-1.95477f}, //stoneheart_bunker + {-571.88f,-262.777f,75.0087f,-0.802851f}, //iceblood_tower + {-768.907f,-363.71f,90.8949f,1.07991f}, //tower_point + {-1302.9f,-316.981f,113.867f,2.00713f}, //frostwolf_etower + {-1297.5f,-266.767f,114.15f,3.31044f}, //frostwolf_wtower + {-57.7891f,-286.597f,15.6479f,6.02139f}, //AV_NPC_A_CAPTAIN balinda + {722.43f,-10.9982f,50.7046f,3.42085f}, //AV_NPC_A_BOSS vanndar + {-545.23f,-165.35f,57.7886f,3.01145f}, //AV_NPC_H_CAPTAIN galvangar + {-1370.9f,-219.793f,98.4258f,5.04381f} //AV_NPC_H_BOSS drek thar +}; + +enum BG_AV_CreatureIds +{ + + AV_NPC_A_GRAVEDEFENSE0 = 0, // stormpike Defender + AV_NPC_A_GRAVEDEFENSE1 = 1, // seasoned defender + AV_NPC_A_GRAVEDEFENSE2 = 2, // veteran defender + AV_NPC_A_GRAVEDEFENSE3 = 3, // champion defender + AV_NPC_A_TOWERDEFENSE = 4, // stormpike bowman + AV_NPC_A_CAPTAIN = 5, // balinda + AV_NPC_A_BOSS = 6, // vanndar + + AV_NPC_H_GRAVEDEFENSE0 = 7, // frostwolf guardian + AV_NPC_H_GRAVEDEFENSE1 = 8, // seasoned guardian + AV_NPC_H_GRAVEDEFENSE2 = 9, // veteran guardian + AV_NPC_H_GRAVEDEFENSE3 = 10, // champion guardian + AV_NPC_H_TOWERDEFENSE = 11, // frostwolf bowman + AV_NPC_H_CAPTAIN = 12, // galvangar + AV_NPC_H_BOSS = 13, // drek thar + + AV_NPC_A_MARSHAL_SOUTH = 14, + AV_NPC_MARSHAL_NORTH = 15, + AV_NPC_A_MARSHAL_ICE = 16, + AV_NPC_A_MARSHAL_STONE = 17, + AV_NPC_H_MARSHAL_ICE = 18, + AV_NPC_H_MARSHAL_TOWER = 19, + AV_NPC_MARSHAL_ETOWER = 20, + AV_NPC_H_MARSHAL_WTOWER= 21, + AV_NPC_N_MINE_N_1 = 22, + AV_NPC_N_MINE_N_2 = 23, + AV_NPC_N_MINE_N_3 = 24, + AV_NPC_N_MINE_N_4 = 25, + AV_NPC_N_MINE_A_1 = 26, + AV_NPC_N_MINE_A_2 = 27, + AV_NPC_N_MINE_A_3 = 28, + AV_NPC_N_MINE_A_4 = 29, + AV_NPC_N_MINE_H_1 = 30, + AV_NPC_N_MINE_H_2 = 31, + AV_NPC_N_MINE_H_3 = 32, + AV_NPC_N_MINE_H_4 = 33, + AV_NPC_S_MINE_N_1 = 34, + AV_NPC_S_MINE_N_2 = 35, + AV_NPC_S_MINE_N_3 = 36, + AV_NPC_S_MINE_N_4 = 37, + AV_NPC_S_MINE_N_S = 38, + AV_NPC_S_MINE_A_1 = 39, + AV_NPC_S_MINE_A_2 = 40, + AV_NPC_S_MINE_A_3 = 41, + AV_NPC_S_MINE_A_4 = 42, + AV_NPC_S_MINE_H_1 = 43, + AV_NPC_S_MINE_H_2 = 44, + AV_NPC_S_MINE_H_3 = 45, + AV_NPC_S_MINE_H_4 = 46, + AV_NPC_HERALD = 47, + AV_NPC_INFO_MAX = 48 + +}; + +//entry, team, minlevel, maxlevel +//TODO this array should be removed, the only needed things are the entrys (for spawning(?) and handlekillunit) +const uint32 BG_AV_CreatureInfo[AV_NPC_INFO_MAX][4] = { + { 12050, 1216, 58, 58 }, //Stormpike Defender + { 13326, 1216, 59, 59 }, //Seasoned Defender + { 13331, 1216, 60, 60 }, //Veteran Defender + { 13422, 1216, 61, 61 }, //Champion Defender + { 13358, 1216, 59, 60 }, //Stormpike Bowman //i think its 60,61 and 69,70.. but this is until now not possible TODO look if this is ok + { 11949,469,0,0},//not spawned with this data, but used for handlekillunit + { 11948,469,0,0},//not spawned with this data, but used for handlekillunit + { 12053, 1214, 58, 58 }, //Frostwolf Guardian + { 13328, 1214, 59, 59 }, //Seasoned Guardian + { 13332, 1214, 60, 60 }, //Veteran Guardian + { 13421, 1214, 61, 61 }, //Champion Guardian + { 13359, 1214, 59, 60 }, //Frostwolf Bowman + { 11947,67,0,0}, //not spawned with this data, but used for handlekillunit + { 11946,67,0,0}, //not spawned with this data, but used for handlekillunit + { 14763, 1534, 60, 60 }, //Dun Baldar South Marshal + { 14762, 1534, 60, 60 }, //Dun Baldar North Marshal + { 14764, 1534, 60, 60 }, //Icewing Marshal + { 14765, 1534, 60, 60 }, //Stonehearth Marshal + + { 14773, 1214, 60, 60 }, //Iceblood Warmaster + { 14776, 1214, 60, 60 }, //Tower Point Warmaster + { 14772, 1214, 60, 60 }, //East Frostwolf Warmaster + { 14777, 1214, 60, 60 }, //West Frostwolf Warmaster + + { 10987, 59, 52, 53 }, //Irondeep Trogg + { 11600, 59, 53, 54 }, //Irondeep Shaman + { 11602, 59, 54, 55 }, //Irondeep Skullthumper + { 11657, 59, 58, 58 }, //Morloch + + {13396,469,52,53}, //irondeep alliance TODO: get the right ids + {13080,469,53,54}, + {13098,469,54,55}, + {13078,469,58,58}, + + {13397,67,52,53}, //irondeep horde + {13099,67,53,54}, + {13081,67,54,55}, + {13079,67,58,58}, + + { 11603, 59, 52, 53 }, //south mine neutral + { 11604, 59, 53, 54 }, + { 11605, 59, 54, 55 }, + { 11677, 59, 58, 58 }, + { 10982, 59, 52, 53 }, //vermin + + {13317,469,52,53}, //alliance + {13096,469,54,55}, //explorer + {13087,469,54,55}, //invader + {13086,469,58,58}, + + {13316,67,52,53}, //horde + {13097,67,54,55}, //surveypr + {13089,67,54,55}, //guard + {13088,67,58,58}, + {14848,67,58,58} //Herald + +}; + +//x,y,z,o,static_creature_info-id +const float BG_AV_StaticCreaturePos[AV_STATICCPLACE_MAX][5] = { //static creatures + {-1235.31f,-340.777f,60.5088f,3.31613f,0 },//2225 - Zora Guthrek + {-1244.02f,-323.795f,61.0485f,5.21853f,1 },//3343 - Grelkor + {-1235.16f,-332.302f,60.2985f,2.96706f,2 },//3625 - Rarck + {587.303f,-42.8257f,37.5615f,5.23599f,3 },//4255 - Brogus Thunderbrew + {643.635f,-58.3987f,41.7405f,4.72984f,4 },//4257 - Lana Thunderbrew + {591.464f,-44.452f,37.6166f,5.65487f,5 },//5134 - Jonivera Farmountain + {608.515f,-33.3935f,42.0003f,5.41052f,6 },//5135 - Svalbrad Farmountain + {617.656f,-32.0701f,42.7168f,4.06662f,7 },//5139 - Kurdrum Barleybeard + {-1183.76f,-268.295f,72.8233f,3.28122f,8 },//10364 - Yaelika Farclaw + {-1187.86f,-275.31f,73.0481f,3.63028f,9 },//10367 - Shrye Ragefist + {-1008.42f,-368.006f,55.3426f,5.95647f,10 },//10981 - Frostwolf + {-1091.92f,-424.28f,53.0139f,2.93958f,10 },//10981 - Frostwolf + {-558.455f,-198.768f,58.1755f,4.97946f,10 },//10981 - Frostwolf + {-861.247f,-312.51f,55.1427f,3.35382f,10 },//10981 - Frostwolf + {-1003.81f,-395.913f,50.4736f,2.85631f,10 },//10981 - Frostwolf + {-904.5f,-289.815f,65.1222f,5.7847f,10 },//10981 - Frostwolf + {-1064.41f,-438.839f,51.3614f,1.88857f,10 },//10981 - Frostwolf + {258.814f,76.2017f,18.6468f,6.19052f,11 },//10986 - Snowblind Harpy + {265.838f,-315.846f,-16.5429f,3.15917f,11 },//10986 - Snowblind Harpy + {426.485f,-51.1927f,-5.66286f,1.60347f,11 },//10986 - Snowblind Harpy + {452.044f,-33.9594f,-0.044651f,2.72815f,11 },//10986 - Snowblind Harpy + {266.032f,-315.639f,-16.5429f,4.67962f,11 },//10986 - Snowblind Harpy + {532.64f,-54.5863f,20.7024f,2.93215f,11 },//10986 - Snowblind Harpy + {295.183f,-299.908f,-34.6123f,0.135851f,12 },//10990 - Alterac Ram + {421.08f,-225.006f,-23.73f,0.166754f,12 },//10990 - Alterac Ram + {-55.7766f,-192.498f,20.4352f,6.12221f,12 },//10990 - Alterac Ram + {527.887f,-477.223f,62.3559f,0.170935f,12 },//10990 - Alterac Ram + {389.144f,-346.508f,-30.334f,4.14117f,12 },//10990 - Alterac Ram + {108.121f,-322.248f,37.5655f,4.46788f,12 },//10990 - Alterac Ram + {507.479f,-67.9403f,10.3571f,3.26304f,12 },//10990 - Alterac Ram + {329.071f,-185.016f,-29.1542f,0.356943f,12 },//10990 - Alterac Ram + {252.449f,-422.313f,35.1404f,4.53771f,12 },//10990 - Alterac Ram + {358.882f,-118.061f,-24.9119f,2.29257f,12 },//10990 - Alterac Ram + {487.151f,-174.229f,14.7558f,4.73192f,12 },//10990 - Alterac Ram + {449.652f,-123.561f,6.14273f,6.12029f,12 },//10990 - Alterac Ram + {272.419f,-261.802f,-41.8835f,3.66559f,12 },//10990 - Alterac Ram + {359.021f,-210.954f,-29.3483f,4.31339f,12 },//10990 - Alterac Ram + {450.598f,-318.048f,-37.7548f,0.655219f,12 },//10990 - Alterac Ram + {509.333f,-218.2f,3.05439f,3.66292f,12 },//10990 - Alterac Ram + {485.771f,-223.613f,-1.53f,2.04862f,12 },//10990 - Alterac Ram + {486.636f,-452.172f,39.6592f,2.3341f,12 },//10990 - Alterac Ram + {702.783f,-257.494f,25.9777f,1.68329f,12 },//10990 - Alterac Ram + {460.942f,-199.263f,-6.0149f,0.380506f,12 },//10990 - Alterac Ram + {483.108f,-115.307f,10.1056f,3.69701f,12 },//10990 - Alterac Ram + {471.601f,-154.174f,14.0702f,5.5807f,12 },//10990 - Alterac Ram + {213.938f,-420.793f,41.2549f,5.71394f,12 },//10990 - Alterac Ram + {289.387f,-294.685f,-33.9073f,0.555494f,12 },//10990 - Alterac Ram + {155.649f,-402.891f,43.3915f,5.94838f,12 },//10990 - Alterac Ram + {517.184f,-295.105f,-9.78195f,6.05668f,12 },//10990 - Alterac Ram + {102.334f,-332.165f,38.9812f,3.31445f,12 },//10990 - Alterac Ram + {320.244f,-107.793f,-42.6357f,-1.00311f,12 },//10990 - Alterac Ram + {217.976f,110.774f,15.7603f,4.56793f,13 },//11675 - Snowblind Windcaller + {269.872f,6.66684f,20.7592f,0.381212f,13 },//11675 - Snowblind Windcaller + {313.528f,-319.041f,-27.2373f,0.554098f,13 },//11675 - Snowblind Windcaller + {435.441f,-39.9289f,-0.169651f,0.549454f,13 },//11675 - Snowblind Windcaller + {315.115f,-317.62f,-29.1123f,0.90111f,13 },//11675 - Snowblind Windcaller + {428.091f,-122.731f,3.40332f,6.05901f,14 },//11678 - Snowblind Ambusher + {235.05f,85.5705f,18.3079f,-0.914255f,14 },//11678 - Snowblind Ambusher + {-1553.04f,-344.342f,64.4163f,6.09933f,15 },//11839 - Wildpaw Brute + {-545.23f,-165.35f,57.7886f,3.01145f,16 },//11947 - Captain Galvangar + {722.43f,-10.9982f,50.7046f,3.42085f,17 },//11948 - Vanndar Stormpike + {-57.7891f,-286.597f,15.6479f,6.02139f,18 },//11949 - Captain Balinda Stonehearth + {930.498f,-520.755f,93.7334f,1.8326f,19 },//11997 - Stormpike Herald + {-776.092f,-345.161f,67.4092f,1.89257f,20 },//12051 - Frostwolf Legionnaire + {-1224.63f,-308.144f,65.0087f,4.01139f,20 },//12051 - Frostwolf Legionnaire + {-713.039f,-442.515f,82.8638f,0.68724f,20 },//12051 - Frostwolf Legionnaire + {-711.783f,-444.061f,82.7039f,0.683494f,20 },//12051 - Frostwolf Legionnaire + {587.633f,-45.9816f,37.5438f,5.81195f,21 },//12096 - Stormpike Quartermaster + {-1293.79f,-194.407f,72.4398f,5.84685f,22 },//12097 - Frostwolf Quartermaster + {446.163f,-377.119f,-1.12725f,0.209526f,23 },//12127 - Stormpike Guardsman + {549.348f,-399.254f,53.3537f,3.24729f,23 },//12127 - Stormpike Guardsman + {549.801f,-401.217f,53.8305f,3.24729f,23 },//12127 - Stormpike Guardsman + {192.704f,-406.874f,42.9183f,6.10696f,23 },//12127 - Stormpike Guardsman + {441.305f,-435.765f,28.2385f,2.14472f,23 },//12127 - Stormpike Guardsman + {192.982f,-404.891f,43.0132f,6.1061f,23 },//12127 - Stormpike Guardsman + {355.342f,-391.989f,-0.486707f,3.00643f,23 },//12127 - Stormpike Guardsman + {446.035f,-375.104f,-1.12725f,0.21033f,23 },//12127 - Stormpike Guardsman + {697.864f,-433.238f,62.7914f,1.65776f,23 },//12127 - Stormpike Guardsman + {610.74f,-331.585f,30.8021f,5.14253f,23 },//12127 - Stormpike Guardsman + {609.815f,-329.775f,30.9271f,-2.38829f,23 },//12127 - Stormpike Guardsman + {695.874f,-433.434f,62.8543f,1.65776f,23 },//12127 - Stormpike Guardsman + {443.337f,-435.283f,28.6842f,2.13768f,23 },//12127 - Stormpike Guardsman + {-1251.5f,-316.327f,62.6565f,5.02655f,24 },//13176 - Smith Regzar + {-1332.0f,-331.243f,91.2631f,1.50098f,25 },//13179 - Wing Commander Guse + {569.983f,-94.9992f,38.0325f,1.39626f,26 },//13216 - Gaelden Hammersmith + {-1244.92f,-308.916f,63.2525f,1.62316f,27 },//13218 - Grunnda Wolfheart + {-1319.56f,-342.675f,60.3404f,1.20428f,28 },//13236 - Primalist Thurloga + {647.61f,-61.1548f,41.7405f,4.24115f,29 },//13257 - Murgot Deepforge + {-1321.64f,-343.73f,60.4833f,1.01229f,30 },//13284 - Frostwolf Shaman + {-1317.61f,-342.853f,60.3726f,2.47837f,30 },//13284 - Frostwolf Shaman + {-1319.31f,-344.475f,60.3825f,1.72788f,30 },//13284 - Frostwolf Shaman + {569.963f,-42.0218f,37.7581f,4.27606f,31 },//13438 - Wing Commander Slidore + {729.2f,-78.812f,51.6335f,3.97935f,32 },//13442 - Arch Druid Renferal + {729.118f,-82.8713f,51.6335f,2.53073f,33 },//13443 - Druid of the Grove + {725.554f,-79.4973f,51.6335f,5.27089f,33 },//13443 - Druid of the Grove + {724.768f,-84.1642f,51.6335f,0.733038f,33 },//13443 - Druid of the Grove + {596.68f,-83.0633f,39.0051f,6.24828f,34 },//13447 - Corporal Noreg Stormpike + {600.032f,-2.92475f,42.0788f,5.00909f,35 },//13577 - Stormpike Ram Rider Commander + {610.239f,-21.8454f,43.272f,4.90438f,36 },//13617 - Stormpike Stable Master + {613.422f,-150.764f,33.4517f,5.55015f,37 },//13797 - Mountaineer Boombellow + {-1213.91f,-370.619f,56.4455f,0.837758f,38 },//13798 - Jotek + {704.35f,-22.9071f,50.2187f,0.785398f,39 },//13816 - Prospector Stonehewer + {-1271.24f,-335.766f,62.3971f,5.75959f,40 },//14185 - Najak Hexxen + {-1268.64f,-332.688f,62.6171f,5.28835f,41 },//14186 - Ravak Grimtotem + {648.363f,-65.2233f,41.7405f,3.12414f,42 },//14187 - Athramanis + {648.238f,-67.8931f,41.7405f,2.60054f,43 },//14188 - Dirk Swindle + {-1223.44f,-309.833f,64.9331f,4.0131f,44 },//14282 - Frostwolf Bloodhound + {-1226.4f,-307.136f,64.9706f,4.0145f,44 },//14282 - Frostwolf Bloodhound + {356.001f,-389.969f,-0.438796f,3.0334f,45 },//14283 - Stormpike Owl + {355.835f,-394.005f,-0.60149f,3.02498f,45 },//14283 - Stormpike Owl + {882.266f,-496.378f,96.7707f,4.83248f,45 },//14283 - Stormpike Owl + {878.649f,-495.917f,96.6171f,4.67693f,45 },//14283 - Stormpike Owl + {932.851f,-511.017f,93.6748f,3.61004f,45 },//14283 - Stormpike Owl + {935.806f,-513.983f,93.7436f,3.61788f,45 },//14283 - Stormpike Owl + {947.412f,-509.982f,95.1098f,2.82743f,46 },//14284 - Stormpike Battleguard + {934.557f,-512.395f,93.662f,3.61004f,46 },//14284 - Stormpike Battleguard + {939.42f,-502.777f,94.5887f,5.14872f,46 },//14284 - Stormpike Battleguard + {854.276f,-494.241f,96.8017f,5.44543f,46 },//14284 - Stormpike Battleguard + {776.621f,-487.775f,99.4049f,3.50811f,46 },//14284 - Stormpike Battleguard + {880.169f,-495.699f,96.6204f,4.8325f,46 },//14284 - Stormpike Battleguard + {773.651f,-497.482f,99.0408f,2.11185f,46 },//14284 - Stormpike Battleguard + {949.1f,-506.913f,95.4237f,3.31613f,46 },//14284 - Stormpike Battleguard + {-1370.9f,-219.793f,98.4258f,5.04381f,47}, //drek thar + +}; + +const uint32 BG_AV_StaticCreatureInfo[51][4] = { + { 2225, 1215, 55, 55 }, //Zora Guthrek + { 3343, 1215, 55, 55 }, //Grelkor + { 3625, 1215, 55, 55 }, //Rarck + { 4255, 1217, 55, 55 }, //Brogus Thunderbrew + { 4257, 1217, 55, 55 }, //Lana Thunderbrew + { 5134, 1217, 55, 55 }, //Jonivera Farmountain + { 5135, 1217, 55, 55 }, //Svalbrad Farmountain + { 5139, 1217, 55, 55 }, //Kurdrum Barleybeard + { 10364, 1215, 55, 55 }, //Yaelika Farclaw + { 10367, 1215, 55, 55 }, //Shrye Ragefist + { 10981, 38, 50, 51 }, //Frostwolf + { 10986, 514, 52, 53 }, //Snowblind Harpy + { 10990, 1274, 50, 51 }, //Alterac Ram + { 11675, 514, 53, 53 }, //Snowblind Windcaller + { 11678, 14, 52, 53 }, //Snowblind Ambusher + { 11839, 39, 56, 56 }, //Wildpaw Brute + { 11947, 1214, 61, 61 }, //Captain Galvangar --TODO: doubled + { 11948, 1216, 63, 63 }, //Vanndar Stormpike + { 11949, 1216, 61, 61 }, //Captain Balinda Stonehearth + { 11997, 1334, 60, 60 }, //Stormpike Herald + { 12051, 1214, 57, 57 }, //Frostwolf Legionnaire + { 12096, 1217, 55, 55 }, //Stormpike Quartermaster + { 12097, 1215, 55, 55 }, //Frostwolf Quartermaster + { 12127, 1216, 57, 57 }, //Stormpike Guardsman + { 13176, 1215, 60, 60 }, //Smith Regzar + { 13179, 1215, 59, 59 }, //Wing Commander Guse + { 13216, 1217, 58, 58 }, //Gaelden Hammersmith + { 13218, 1215, 58, 58 }, //Grunnda Wolfheart + { 13236, 1214, 60, 60 }, //Primalist Thurloga + { 13257, 1216, 60, 60 }, //Murgot Deepforge + { 13284, 1214, 58, 58 }, //Frostwolf Shaman + { 13438, 1217, 58, 58 }, //Wing Commander Slidore + { 13442, 1216, 60, 60 }, //Arch Druid Renferal + { 13443, 1216, 60, 60 }, //Druid of the Grove + { 13447, 1216, 58, 58 }, //Corporal Noreg Stormpike + { 13577, 1216, 60, 60 }, //Stormpike Ram Rider Commander + { 13617, 1216, 60, 60 }, //Stormpike Stable Master + { 13797, 32, 60, 61 }, //Mountaineer Boombellow + { 13798, 1214, 60, 61 }, //Jotek + { 13816, 1216, 61, 61 }, //Prospector Stonehewer + { 14185, 877, 59, 59 }, //Najak Hexxen + { 14186, 105, 60, 60 }, //Ravak Grimtotem + { 14187, 1594, 60, 60 }, //Athramanis + { 14188, 57, 59, 59 }, //Dirk Swindle + { 14282, 1214, 53, 54 }, //Frostwolf Bloodhound + { 14283, 1216, 53, 54 }, //Stormpike Owl + { 14284, 1216, 61, 61 }, //Stormpike Battleguard + { 11946, 1214, 63, 63 }, //Drek'Thar //TODO: make the levels right (boss=0 maybe) + { 11948, 1216, 63, 63 }, //Vanndar Stormpike + { 11947, 1214, 61, 61 }, //Captain Galvangar + { 11949, 1216, 61, 61 } //Captain Balinda Stonehearth +}; + +enum BG_AV_Graveyards +{ + AV_GRAVE_STORM_AID = 751, + AV_GRAVE_STORM_GRAVE = 689, + AV_GRAVE_STONE_GRAVE = 729, + AV_GRAVE_SNOWFALL = 169, + AV_GRAVE_ICE_GRAVE = 749, + AV_GRAVE_FROSTWOLF = 690, + AV_GRAVE_FROST_HUT = 750, + AV_GRAVE_MAIN_ALLIANCE = 611, + AV_GRAVE_MAIN_HORDE = 610 +}; + +const uint32 BG_AV_GraveyardIds[9]= { + AV_GRAVE_STORM_AID, + AV_GRAVE_STORM_GRAVE, + AV_GRAVE_STONE_GRAVE, + AV_GRAVE_SNOWFALL, + AV_GRAVE_ICE_GRAVE, + AV_GRAVE_FROSTWOLF, + AV_GRAVE_FROST_HUT, + AV_GRAVE_MAIN_ALLIANCE, + AV_GRAVE_MAIN_HORDE +}; + +enum BG_AV_BUFF +{ //TODO add all other buffs here + AV_BUFF_ARMOR = 21163, + AV_BUFF_A_CAPTAIN = 23693, //the buff which the alliance captain does + AV_BUFF_H_CAPTAIN = 22751 //the buff which the horde captain does +}; +enum BG_AV_States +{ + POINT_NEUTRAL = 0, + POINT_ASSAULTED = 1, + POINT_DESTROYED = 2, + POINT_CONTROLED = 3 +}; + +enum BG_AV_WorldStates +{ + AV_Alliance_Score = 3127, + AV_Horde_Score = 3128, + AV_SHOW_H_SCORE = 3133, + AV_SHOW_A_SCORE = 3134, + +/* + //the comments behind the state shows which icon overlaps the other.. but is, until now, unused and maybe not a good solution (but give few performance (:) + +// Graves + + // Alliance + //Stormpike first aid station + AV_AID_A_C = 1325, + AV_AID_A_A = 1326, + AV_AID_H_C = 1327, + AV_AID_H_A = 1328, + //Stormpike Graveyard + AV_PIKEGRAVE_A_C = 1333, + AV_PIKEGRAVE_A_A = 1335, + AV_PIKEGRAVE_H_C = 1334, + AV_PIKEGRAVE_H_A = 1336, + //Stoneheart Grave + AV_STONEHEART_A_C = 1302, + AV_STONEHEART_A_A = 1304, //over hc + AV_STONEHEART_H_C = 1301, //over ac + AV_STONEHEART_H_A = 1303, //over aa + //Neutral + //Snowfall Grave +*/ + AV_SNOWFALL_N = 1966, //over aa +/* + AV_SNOWFALL_A_C = 1341, //over hc + AV_SNOWFALL_A_A = 1343, //over ha + AV_SNOWFALL_H_C = 1342, + AV_SNOWFALL_H_A = 1344, //over ac + //Horde + //Iceblood grave + AV_ICEBLOOD_A_C = 1346, //over hc + AV_ICEBLOOD_A_A = 1348, //over ac + AV_ICEBLOOD_H_C = 1347, + AV_ICEBLOOD_H_A = 1349, //over aa + //Frostwolf Grave + AV_FROSTWOLF_A_C = 1337, //over hc + AV_FROSTWOLF_A_A = 1339, //over ac + AV_FROSTWOLF_H_C = 1338, + AV_FROSTWOLF_H_A = 1340, //over aa + //Frostwolf Hut + AV_FROSTWOLFHUT_A_C = 1329, //over hc + AV_FROSTWOLFHUT_A_A = 1331, //over ha + AV_FROSTWOLFHUT_H_C = 1330, + AV_FROSTWOLFHUT_H_A = 1332, //over ac + +//Towers + //Alliance + //Dunbaldar South Bunker + AV_DUNS_CONTROLLED = 1361, + AV_DUNS_DESTROYED = 1370, + AV_DUNS_ASSAULTED = 1378, + //Dunbaldar North Bunker + AV_DUNN_CONTROLLED = 1362, + AV_DUNN_DESTROYED = 1371, + AV_DUNN_ASSAULTED = 1379, + //Icewing Bunker + AV_ICEWING_CONTROLLED = 1363, + AV_ICEWING_DESTROYED = 1372, + AV_ICEWING_ASSAULTED = 1380, + //Stoneheart Bunker + AV_STONEH_CONTROLLED = 1364, + AV_STONEH_DESTROYED = 1373, + AV_STONEH_ASSAULTED = 1381, + //Horde + //Iceblood Tower + AV_ICEBLOOD_CONTROLLED = 1385, + AV_ICEBLOOD_DESTROYED = 1368, + AV_ICEBLOOD_ASSAULTED = 1390, + //Tower Point + AV_TOWERPOINT_CONTROLLED = 1384, + AV_TOWERPOINT_DESTROYED = 1367, //goes over controlled + AV_TOWERPOINT_ASSAULTED = 1389, //goes over destroyed + //Frostwolf West + AV_FROSTWOLFW_CONTROLLED = 1382, + AV_FROSTWOLFW_DESTROYED = 1365, //over controlled + AV_FROSTWOLFW_ASSAULTED = 1387, //over destroyed + //Frostwolf East + AV_FROSTWOLFE_CONTROLLED = 1383, + AV_FROSTWOLFE_DESTROYED = 1366, + AV_FROSTWOLFE_ASSAULTED = 1388, + +//mines + + AV_N_MINE_N = 1360, + AV_N_MINE_A = 1358, + AV_N_MINE_H = 1359, + + AV_S_MINE_N = 1357, + AV_S_MINE_A = 1355, + AV_S_MINE_H = 1356, + +//towers assaulted by own team (unused) + AV_STONEH_UNUSED = 1377, + AV_ICEWING_UNUSED = 1376, + AV_DUNS_UNUSED = 1375, + AV_DUNN_UNUSED = 1374, + + AV_ICEBLOOD_UNUSED = 1395, + AV_TOWERPOINT_UNUSED = 1394, + AV_FROSTWOLFE_UNUSED = 1393, + AV_FROSTWOLFW_UNUSED = 1392 +*/ + +}; + +//alliance_control neutral_control horde_control +const uint32 BG_AV_MineWorldStates[2][3] = { + {1358, 1360,1359}, + {1355, 1357,1356} +}; + +//alliance_control alliance_assault h_control h_assault +const uint32 BG_AV_NodeWorldStates[16][4] = { + //Stormpike first aid station + {1325, 1326,1327,1328}, + //Stormpike Graveyard + {1333,1335,1334,1336}, + //Stoneheart Grave + {1302,1304,1301,1303}, + //Snowfall Grave + {1341,1343,1342,1344}, + //Iceblood grave + {1346,1348,1347,1349}, + //Frostwolf Grave + {1337,1339,1338,1340}, + //Frostwolf Hut + {1329,1331,1330,1332}, + //Dunbaldar South Bunker + {1361,1375,1370,1378}, + //Dunbaldar North Bunker + {1362,1374,1371,1379}, + //Icewing Bunker + {1363,1376,1372,1380}, + //Stoneheart Bunker + {1364,1377,1373,1381}, + //Iceblood Tower + {1368,1390,1385,1395}, + //Tower Point + {1367,1389,1384,1394}, + //Frostwolf East + {1366,1388,1383,1393}, + //Frostwolf West + {1365,1387,1382,1392}, +}; + +enum BG_AV_QuestIds +{ + AV_QUEST_A_SCRAPS1 = 7223, + AV_QUEST_A_SCRAPS2 = 6781, + AV_QUEST_H_SCRAPS1 = 7224, + AV_QUEST_H_SCRAPS2 = 6741, + AV_QUEST_A_COMMANDER1 = 6942, //soldier + AV_QUEST_H_COMMANDER1 = 6825, + AV_QUEST_A_COMMANDER2 = 6941, //leutnant + AV_QUEST_H_COMMANDER2 = 6826, + AV_QUEST_A_COMMANDER3 = 6943, //commander + AV_QUEST_H_COMMANDER3 = 6827, + AV_QUEST_A_BOSS1 = 7386, // 5 cristal/blood + AV_QUEST_H_BOSS1 = 7385, + AV_QUEST_A_BOSS2 = 6881, // 1 + AV_QUEST_H_BOSS2 = 6801, + AV_QUEST_A_NEAR_MINE = 5892, //the mine near start location of team + AV_QUEST_H_NEAR_MINE = 5893, + AV_QUEST_A_OTHER_MINE = 6982, //the other mine ;) + AV_QUEST_H_OTHER_MINE = 6985, + AV_QUEST_A_RIDER_HIDE = 7026, + AV_QUEST_H_RIDER_HIDE = 7002, + AV_QUEST_A_RIDER_TAME = 7027, + AV_QUEST_H_RIDER_TAME = 7001 +}; + +struct BG_AV_NodeInfo +{ + uint16 TotalOwner; + uint16 Owner; + uint16 PrevOwner; + BG_AV_States State; + BG_AV_States PrevState; + int Timer; + bool Tower; +}; + +inline BG_AV_Nodes &operator++(BG_AV_Nodes &i){ return i = BG_AV_Nodes(i + 1); } + +class BattleGroundAVScore : public BattleGroundScore +{ + public: + BattleGroundAVScore() : GraveyardsAssaulted(0), GraveyardsDefended(0), TowersAssaulted(0), TowersDefended(0), MinesCaptured(0), LeadersKilled(0), SecondaryObjectives(0) {}; + virtual ~BattleGroundAVScore() {}; + uint32 GraveyardsAssaulted; + uint32 GraveyardsDefended; + uint32 TowersAssaulted; + uint32 TowersDefended; + uint32 MinesCaptured; + uint32 LeadersKilled; + uint32 SecondaryObjectives; +}; + +class BattleGroundAV : public BattleGround +{ + friend class BattleGroundMgr; + + public: + BattleGroundAV(); + ~BattleGroundAV(); + void Update(uint32 diff); + + /* inherited from BattlegroundClass */ + virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + + void RemovePlayer(Player *plr,uint64 guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + bool SetupBattleGround(); + virtual void ResetBGSubclass(); + + /*general stuff*/ + void UpdateScore(uint16 team, int16 points); + void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); + + /*handlestuff*/ //these are functions which get called from extern + virtual void EventPlayerClickedOnFlag(Player *source, GameObject* target_obj); + void HandleKillPlayer(Player* player, Player *killer); + void HandleKillUnit(Creature *unit, Player *killer); + void HandleQuestComplete(uint32 questid, Player *player); + bool PlayerCanDoMineQuest(int32 GOId,uint32 team); + + void EndBattleGround(uint32 winner); + + virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); + + private: + /* Nodes occupying */ + void EventPlayerAssaultsPoint(Player* player, uint32 object); + void EventPlayerDefendsPoint(Player* player, uint32 object); + void EventPlayerDestroyedPoint(BG_AV_Nodes node); + + void AssaultNode(BG_AV_Nodes node,uint16 team); + void DestroyNode(BG_AV_Nodes node); + void InitNode(BG_AV_Nodes node, uint16 team, bool tower); + void DefendNode(BG_AV_Nodes node, uint16 team); + + void PopulateNode(BG_AV_Nodes node); + void DePopulateNode(BG_AV_Nodes node); + + const BG_AV_Nodes GetNodeThroughObject(uint32 object); + const uint32 GetObjectThroughNode(BG_AV_Nodes node); + const char* GetNodeName(BG_AV_Nodes node); + const bool IsTower(BG_AV_Nodes node) { return m_Nodes[node].Tower; } + + /*mine*/ + void ChangeMineOwner(uint8 mine, uint32 team, bool initial=false); + + /*worldstates*/ + void FillInitialWorldStates(WorldPacket& data); + const uint8 GetWorldStateType(uint8 state, uint16 team); + void SendMineWorldStates(uint32 mine); + void UpdateNodeWorldState(BG_AV_Nodes node); + + /*general */ + Creature* AddAVCreature(uint16 cinfoid, uint16 type); + const uint16 GetBonusHonor(uint8 kills); //TODO remove this when the core handles this right + + /*variables */ + int32 m_Team_Scores[2]; + uint32 m_Team_QuestStatus[2][9]; //[x][y] x=team y=questcounter + + BG_AV_NodeInfo m_Nodes[BG_AV_NODES_MAX]; + + uint32 m_Mine_Owner[2]; + uint32 m_Mine_PrevOwner[2]; //only for worldstates needed + int32 m_Mine_Timer; //ticks for both teams + uint32 m_Mine_Reclaim_Timer[2]; + uint32 m_CaptainBuffTimer[2]; + bool m_CaptainAlive[2]; + + uint8 m_MaxLevel; //TODO remove this when battleground-getmaxlevel() returns something usefull + bool m_IsInformedNearVictory[2]; + +}; + +#endif + diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundBE.cpp b/src/server/game/BattleGrounds/Zones/BattleGroundBE.cpp new file mode 100644 index 00000000000..d6debe45ae3 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundBE.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "BattleGround.h" +#include "BattleGroundBE.h" +#include "Language.h" +#include "Object.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "WorldPacket.h" + +BattleGroundBE::BattleGroundBE() +{ + m_BgObjects.resize(BG_BE_OBJECT_MAX); + + m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; + m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; + m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; + m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; + //we must set messageIds + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; +} + +BattleGroundBE::~BattleGroundBE() +{ + +} + +void BattleGroundBE::Update(uint32 diff) +{ + BattleGround::Update(diff); + + /*if (GetStatus() == STATUS_IN_PROGRESS) + { + // update something + }*/ +} + +void BattleGroundBE::StartingEventCloseDoors() +{ + for (uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_4; ++i) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + + for (uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; ++i) + SpawnBGObject(i, RESPAWN_ONE_DAY); +} + +void BattleGroundBE::StartingEventOpenDoors() +{ + for (uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_2; ++i) + DoorOpen(i); + + for (uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; ++i) + SpawnBGObject(i, 60); +} + +void BattleGroundBE::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map, default values are set in constructor + BattleGroundBEScore* sc = new BattleGroundBEScore; + + m_PlayerScores[plr->GetGUID()] = sc; + + UpdateArenaWorldState(); +} + +void BattleGroundBE::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) +{ + if (GetStatus() == STATUS_WAIT_LEAVE) + return; + + UpdateArenaWorldState(); + CheckArenaWinConditions(); +} + +void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + if (!killer) + { + sLog.outError("Killer player not found"); + return; + } + + BattleGround::HandleKillPlayer(player,killer); + + UpdateArenaWorldState(); + CheckArenaWinConditions(); +} + +bool BattleGroundBE::HandlePlayerUnderMap(Player *player) +{ + player->TeleportTo(GetMapId(),6238.930176,262.963470,0.889519,player->GetOrientation(),false); + return true; +} + +void BattleGroundBE::HandleAreaTrigger(Player *Source, uint32 Trigger) +{ + // this is wrong way to implement these things. On official it done by gameobject spell cast. + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + //uint32 SpellId = 0; + //uint64 buff_guid = 0; + switch(Trigger) + { + case 4538: // buff trigger? + //buff_guid = m_BgObjects[BG_BE_OBJECT_BUFF_1]; + break; + case 4539: // buff trigger? + //buff_guid = m_BgObjects[BG_BE_OBJECT_BUFF_2]; + break; + default: + sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); + Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); + break; + } + + //if (buff_guid) + // HandleTriggerBuff(buff_guid,Source); +} + +void BattleGroundBE::FillInitialWorldStates(WorldPacket &data) +{ + data << uint32(0x9f3) << uint32(1); // 9 + UpdateArenaWorldState(); +} + +void BattleGroundBE::Reset() +{ + //call parent's class reset + BattleGround::Reset(); +} + +bool BattleGroundBE::SetupBattleGround() +{ + // gates + if (!AddObject(BG_BE_OBJECT_DOOR_1, BG_BE_OBJECT_TYPE_DOOR_1, 6287.277f, 282.1877f, 3.810925f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY) + || !AddObject(BG_BE_OBJECT_DOOR_2, BG_BE_OBJECT_TYPE_DOOR_2, 6189.546f, 241.7099f, 3.101481f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, RESPAWN_IMMEDIATELY) + || !AddObject(BG_BE_OBJECT_DOOR_3, BG_BE_OBJECT_TYPE_DOOR_3, 6299.116f, 296.5494f, 3.308032f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, RESPAWN_IMMEDIATELY) + || !AddObject(BG_BE_OBJECT_DOOR_4, BG_BE_OBJECT_TYPE_DOOR_4, 6177.708f, 227.3481f, 3.604374f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY) + // buffs + || !AddObject(BG_BE_OBJECT_BUFF_1, BG_BE_OBJECT_TYPE_BUFF_1, 6249.042f, 275.3239f, 11.22033f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120) + || !AddObject(BG_BE_OBJECT_BUFF_2, BG_BE_OBJECT_TYPE_BUFF_2, 6228.26f, 249.566f, 11.21812f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120)) + { + sLog.outErrorDb("BatteGroundBE: Failed to spawn some object!"); + return false; + } + + return true; +} + +void BattleGroundBE::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) +{ + + BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); + if (itr == m_PlayerScores.end()) // player not found... + return; + + //there is nothing special in this score + BattleGround::UpdatePlayerScore(Source,type,value, doAddHonor); + +} + +/* +21:45:46 id:231310 [S2C] SMSG_INIT_WORLD_STATES (706 = 0x02C2) len: 86 +0000: 32 02 00 00 76 0e 00 00 00 00 00 00 09 00 f3 09 | 2...v........... +0010: 00 00 01 00 00 00 f1 09 00 00 01 00 00 00 f0 09 | ................ +0020: 00 00 02 00 00 00 d4 08 00 00 00 00 00 00 d8 08 | ................ +0030: 00 00 00 00 00 00 d7 08 00 00 00 00 00 00 d6 08 | ................ +0040: 00 00 00 00 00 00 d5 08 00 00 00 00 00 00 d3 08 | ................ +0050: 00 00 00 00 00 00 | ...... + +spell 32724 - Gold Team +spell 32725 - Green Team +35774 Gold Team +35775 Green Team +*/ diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundBE.h b/src/server/game/BattleGrounds/Zones/BattleGroundBE.h new file mode 100644 index 00000000000..760d4d278c9 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundBE.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __BATTLEGROUNDBE_H +#define __BATTLEGROUNDBE_H + +class BattleGround; + +enum BattleGroundBEObjectTypes +{ + BG_BE_OBJECT_DOOR_1 = 0, + BG_BE_OBJECT_DOOR_2 = 1, + BG_BE_OBJECT_DOOR_3 = 2, + BG_BE_OBJECT_DOOR_4 = 3, + BG_BE_OBJECT_BUFF_1 = 4, + BG_BE_OBJECT_BUFF_2 = 5, + BG_BE_OBJECT_MAX = 6 +}; + +enum BattleGroundBEObjects +{ + BG_BE_OBJECT_TYPE_DOOR_1 = 183971, + BG_BE_OBJECT_TYPE_DOOR_2 = 183973, + BG_BE_OBJECT_TYPE_DOOR_3 = 183970, + BG_BE_OBJECT_TYPE_DOOR_4 = 183972, + BG_BE_OBJECT_TYPE_BUFF_1 = 184663, + BG_BE_OBJECT_TYPE_BUFF_2 = 184664 +}; + +class BattleGroundBEScore : public BattleGroundScore +{ + public: + BattleGroundBEScore() {}; + virtual ~BattleGroundBEScore() {}; +}; + +class BattleGroundBE : public BattleGround +{ + friend class BattleGroundMgr; + + public: + BattleGroundBE(); + ~BattleGroundBE(); + void Update(uint32 diff); + + /* inherited from BattlegroundClass */ + virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + + void RemovePlayer(Player *plr, uint64 guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + bool SetupBattleGround(); + virtual void Reset(); + virtual void FillInitialWorldStates(WorldPacket &d); + void HandleKillPlayer(Player* player, Player *killer); + bool HandlePlayerUnderMap(Player * plr); + + /* Scorekeeping */ + void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); +}; +#endif diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundDS.cpp b/src/server/game/BattleGrounds/Zones/BattleGroundDS.cpp new file mode 100644 index 00000000000..9036ef83f93 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundDS.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "BattleGround.h" +#include "BattleGroundDS.h" +#include "Language.h" +#include "Player.h" +#include "Object.h" +#include "ObjectMgr.h" +#include "WorldPacket.h" + +BattleGroundDS::BattleGroundDS() +{ + m_BgObjects.resize(BG_DS_OBJECT_MAX); + + m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; + m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; + m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; + m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; + //we must set messageIds + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; +} + +BattleGroundDS::~BattleGroundDS() +{ + +} + +void BattleGroundDS::Update(uint32 diff) +{ + BattleGround::Update(diff); + if (getWaterFallTimer() < diff) + { + if (isWaterFallActive()) + { + setWaterFallTimer(urand(BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX)); + for (uint32 i = BG_DS_OBJECT_WATER_1; i <= BG_DS_OBJECT_WATER_2; ++i) + SpawnBGObject(i, getWaterFallTimer()); + setWaterFallActive(false); + } + else + { + setWaterFallTimer(BG_DS_WATERFALL_DURATION); + for (uint32 i = BG_DS_OBJECT_WATER_1; i <= BG_DS_OBJECT_WATER_2; ++i) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + setWaterFallActive(true); + } + } + else + setWaterFallTimer(getWaterFallTimer() - diff); +} + +void BattleGroundDS::StartingEventCloseDoors() +{ + for (uint32 i = BG_DS_OBJECT_DOOR_1; i <= BG_DS_OBJECT_DOOR_2; ++i) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); +} + +void BattleGroundDS::StartingEventOpenDoors() +{ + for (uint32 i = BG_DS_OBJECT_DOOR_1; i <= BG_DS_OBJECT_DOOR_2; ++i) + DoorOpen(i); + + for (uint32 i = BG_DS_OBJECT_BUFF_1; i <= BG_DS_OBJECT_BUFF_2; ++i) + SpawnBGObject(i, 60); + + setWaterFallTimer(urand(BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX)); + setWaterFallActive(false); + + for (uint32 i = BG_DS_OBJECT_WATER_1; i <= BG_DS_OBJECT_WATER_2; ++i) + SpawnBGObject(i, getWaterFallTimer()); +} + +void BattleGroundDS::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map, default values are set in constructor + BattleGroundDSScore* sc = new BattleGroundDSScore; + + m_PlayerScores[plr->GetGUID()] = sc; + + UpdateArenaWorldState(); +} + +void BattleGroundDS::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) +{ + if (GetStatus() == STATUS_WAIT_LEAVE) + return; + + UpdateArenaWorldState(); + CheckArenaWinConditions(); +} + +void BattleGroundDS::HandleKillPlayer(Player* player, Player* killer) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + if (!killer) + { + sLog.outError("BattleGroundDS: Killer player not found"); + return; + } + + BattleGround::HandleKillPlayer(player,killer); + + UpdateArenaWorldState(); + CheckArenaWinConditions(); +} + +void BattleGroundDS::HandleAreaTrigger(Player *Source, uint32 Trigger) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + switch(Trigger) + { + case 5347: + case 5348: + break; + default: + sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); + Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); + break; + } +} + +bool BattleGroundDS::HandlePlayerUnderMap(Player *player) +{ + player->TeleportTo(GetMapId(), 1299.046, 784.825, 9.338, 2.422, false); + return true; +} + +void BattleGroundDS::FillInitialWorldStates(WorldPacket &data) +{ + data << uint32(3610) << uint32(1); // 9 show + UpdateArenaWorldState(); +} + +void BattleGroundDS::Reset() +{ + //call parent's class reset + BattleGround::Reset(); +} + + +bool BattleGroundDS::SetupBattleGround() +{ + // gates + if (!AddObject(BG_DS_OBJECT_DOOR_1, BG_DS_OBJECT_TYPE_DOOR_1, 1350.95, 817.2, 20.8096, 3.15, 0, 0, 0.99627, 0.0862864, RESPAWN_IMMEDIATELY) + || !AddObject(BG_DS_OBJECT_DOOR_2, BG_DS_OBJECT_TYPE_DOOR_2, 1232.65, 764.913, 20.0729, 6.3, 0, 0, 0.0310211, -0.999519, RESPAWN_IMMEDIATELY) + // water + || !AddObject(BG_DS_OBJECT_WATER_1, BG_DS_OBJECT_TYPE_WATER_1, 1291.56, 790.837, 7.1, 3.14238, 0, 0, 0.694215, -0.719768, 120) + || !AddObject(BG_DS_OBJECT_WATER_2, BG_DS_OBJECT_TYPE_WATER_2, 1291.56, 790.837, 7.1, 3.14238, 0, 0, 0.694215, -0.719768, 120) + // buffs + || !AddObject(BG_DS_OBJECT_BUFF_1, BG_DS_OBJECT_TYPE_BUFF_1, 1291.7, 813.424, 7.11472, 4.64562, 0, 0, 0.730314, -0.683111, 120) + || !AddObject(BG_DS_OBJECT_BUFF_2, BG_DS_OBJECT_TYPE_BUFF_2, 1291.7, 768.911, 7.11472, 1.55194, 0, 0, 0.700409, 0.713742, 120)) + { + sLog.outErrorDb("BatteGroundDS: Failed to spawn some object!"); + return false; + } + + return true; +} diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundDS.h b/src/server/game/BattleGrounds/Zones/BattleGroundDS.h new file mode 100644 index 00000000000..2ced5c88fd1 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundDS.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __BATTLEGROUNDDS_H +#define __BATTLEGROUNDDS_H + +class BattleGround; + +enum BattleGroundDSObjectTypes +{ + BG_DS_OBJECT_DOOR_1 = 0, + BG_DS_OBJECT_DOOR_2 = 1, + BG_DS_OBJECT_WATER_1 = 2, + BG_DS_OBJECT_WATER_2 = 3, + BG_DS_OBJECT_BUFF_1 = 4, + BG_DS_OBJECT_BUFF_2 = 5, + BG_DS_OBJECT_MAX = 6 +}; + +enum BattleGroundDSObjects +{ + BG_DS_OBJECT_TYPE_DOOR_1 = 192642, + BG_DS_OBJECT_TYPE_DOOR_2 = 192643, + BG_DS_OBJECT_TYPE_WATER_1 = 194395, + BG_DS_OBJECT_TYPE_WATER_2 = 191877, + BG_DS_OBJECT_TYPE_BUFF_1 = 184663, + BG_DS_OBJECT_TYPE_BUFF_2 = 184664 +}; + +enum BattleGroundDSData +{ // These values are NOT blizzlike... need the correct data! + BG_DS_WATERFALL_TIMER_MIN = 30000, + BG_DS_WATERFALL_TIMER_MAX = 60000, + BG_DS_WATERFALL_DURATION = 10000, +}; + +class BattleGroundDSScore : public BattleGroundScore +{ + public: + BattleGroundDSScore() {}; + virtual ~BattleGroundDSScore() {}; + //TODO fix me +}; + +class BattleGroundDS : public BattleGround +{ + friend class BattleGroundMgr; + + public: + BattleGroundDS(); + ~BattleGroundDS(); + void Update(uint32 diff); + + /* inherited from BattlegroundClass */ + virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + + void RemovePlayer(Player *plr, uint64 guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + bool SetupBattleGround(); + virtual void Reset(); + virtual void FillInitialWorldStates(WorldPacket &d); + void HandleKillPlayer(Player* player, Player *killer); + bool HandlePlayerUnderMap(Player * plr); + private: + uint32 m_waterTimer; + bool m_waterfallActive; + protected: + bool isWaterFallActive() { return m_waterfallActive; }; + void setWaterFallActive(bool active) { m_waterfallActive = active; }; + void setWaterFallTimer(uint32 timer) { m_waterTimer = timer; }; + uint32 getWaterFallTimer() { return m_waterTimer; }; +}; +#endif diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundEY.cpp b/src/server/game/BattleGrounds/Zones/BattleGroundEY.cpp new file mode 100644 index 00000000000..20f023e4c2a --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundEY.cpp @@ -0,0 +1,938 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ObjectMgr.h" +#include "World.h" +#include "WorldPacket.h" +#include "BattleGroundMgr.h" +#include "BattleGround.h" +#include "BattleGroundEY.h" +#include "Creature.h" +#include "Language.h" +#include "Object.h" +#include "Player.h" +#include "Util.h" + +// these variables aren't used outside of this file, so declare them only here +uint32 BG_EY_HonorScoreTicks[BG_HONOR_MODE_NUM] = { + 330, // normal honor + 200 // holiday +}; + +BattleGroundEY::BattleGroundEY() +{ + m_BuffChange = true; + m_BgObjects.resize(BG_EY_OBJECT_MAX); + m_BgCreatures.resize(BG_EY_CREATURES_MAX); + m_Points_Trigger[FEL_REALVER] = TR_FEL_REALVER_BUFF; + m_Points_Trigger[BLOOD_ELF] = TR_BLOOD_ELF_BUFF; + m_Points_Trigger[DRAENEI_RUINS] = TR_DRAENEI_RUINS_BUFF; + m_Points_Trigger[MAGE_TOWER] = TR_MAGE_TOWER_BUFF; + + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_EY_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_EY_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_EY_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_EY_HAS_BEGUN; +} + +BattleGroundEY::~BattleGroundEY() +{ +} + +void BattleGroundEY::Update(uint32 diff) +{ + BattleGround::Update(diff); + + if (GetStatus() == STATUS_IN_PROGRESS) + { + m_PointAddingTimer -= diff; + if (m_PointAddingTimer <= 0) + { + m_PointAddingTimer = BG_EY_FPOINTS_TICK_TIME; + if (m_TeamPointsCount[BG_TEAM_ALLIANCE] > 0) + AddPoints(ALLIANCE, BG_EY_TickPoints[m_TeamPointsCount[BG_TEAM_ALLIANCE] - 1]); + if (m_TeamPointsCount[BG_TEAM_HORDE] > 0) + AddPoints(HORDE, BG_EY_TickPoints[m_TeamPointsCount[BG_TEAM_HORDE] - 1]); + } + + if (m_FlagState == BG_EY_FLAG_STATE_WAIT_RESPAWN || m_FlagState == BG_EY_FLAG_STATE_ON_GROUND) + { + m_FlagsTimer -= diff; + + if (m_FlagsTimer < 0) + { + m_FlagsTimer = 0; + if (m_FlagState == BG_EY_FLAG_STATE_WAIT_RESPAWN) + RespawnFlag(true); + else + RespawnFlagAfterDrop(); + } + } + + m_TowerCapCheckTimer -= diff; + if (m_TowerCapCheckTimer <= 0) + { + //check if player joined point + /*I used this order of calls, because although we will check if one player is in gameobject's distance 2 times + but we can count of players on current point in CheckSomeoneLeftPoint + */ + this->CheckSomeoneJoinedPoint(); + //check if player left point + this->CheckSomeoneLeftPoint(); + this->UpdatePointStatuses(); + m_TowerCapCheckTimer = BG_EY_FPOINTS_TICK_TIME; + } + } +} + +void BattleGroundEY::StartingEventCloseDoors() +{ + SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_IMMEDIATELY); + SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_IMMEDIATELY); + + for (uint32 i = BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER; i < BG_EY_OBJECT_MAX; ++i) + SpawnBGObject(i, RESPAWN_ONE_DAY); +} + +void BattleGroundEY::StartingEventOpenDoors() +{ + SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_ONE_DAY); + SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_ONE_DAY); + + for (uint32 i = BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER; i <= BG_EY_OBJECT_FLAG_NETHERSTORM; ++i) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + for (uint32 i = 0; i < EY_POINTS_MAX; ++i) + { + //randomly spawn buff + uint8 buff = urand(0, 2); + SpawnBGObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + buff + i * 3, RESPAWN_IMMEDIATELY); + } +} + +void BattleGroundEY::AddPoints(uint32 Team, uint32 Points) +{ + BattleGroundTeamId team_index = GetTeamIndexByTeamId(Team); + m_TeamScores[team_index] += Points; + m_HonorScoreTics[team_index] += Points; + if (m_HonorScoreTics[team_index] >= m_HonorTics) + { + RewardHonorToTeam(GetBonusHonorFromKill(1), Team); + m_HonorScoreTics[team_index] -= m_HonorTics; + } + UpdateTeamScore(Team); +} + +void BattleGroundEY::CheckSomeoneJoinedPoint() +{ + GameObject *obj = NULL; + for (uint8 i = 0; i < EY_POINTS_MAX; ++i) + { + obj = HashMapHolder::Find(m_BgObjects[BG_EY_OBJECT_TOWER_CAP_FEL_REALVER + i]); + if (obj) + { + uint8 j = 0; + while (j < m_PlayersNearPoint[EY_POINTS_MAX].size()) + { + Player *plr = objmgr.GetPlayer(m_PlayersNearPoint[EY_POINTS_MAX][j]); + if (!plr) + { + sLog.outError("BattleGroundEY:CheckSomeoneJoinedPoint: Player (GUID: %u) not found!", GUID_LOPART(m_PlayersNearPoint[EY_POINTS_MAX][j])); + ++j; + continue; + } + if (plr->CanCaptureTowerPoint() && plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS)) + { + //player joined point! + //show progress bar + UpdateWorldStateForPlayer(PROGRESS_BAR_PERCENT_GREY, BG_EY_PROGRESS_BAR_PERCENT_GREY, plr); + UpdateWorldStateForPlayer(PROGRESS_BAR_STATUS, m_PointBarStatus[i], plr); + UpdateWorldStateForPlayer(PROGRESS_BAR_SHOW, BG_EY_PROGRESS_BAR_SHOW, plr); + //add player to point + m_PlayersNearPoint[i].push_back(m_PlayersNearPoint[EY_POINTS_MAX][j]); + //remove player from "free space" + m_PlayersNearPoint[EY_POINTS_MAX].erase(m_PlayersNearPoint[EY_POINTS_MAX].begin() + j); + } + else + ++j; + } + } + } +} + +void BattleGroundEY::CheckSomeoneLeftPoint() +{ + //reset current point counts + for (uint8 i = 0; i < 2*EY_POINTS_MAX; ++i) + m_CurrentPointPlayersCount[i] = 0; + GameObject *obj = NULL; + for (uint8 i = 0; i < EY_POINTS_MAX; ++i) + { + obj = HashMapHolder::Find(m_BgObjects[BG_EY_OBJECT_TOWER_CAP_FEL_REALVER + i]); + if (obj) + { + uint8 j = 0; + while (j < m_PlayersNearPoint[i].size()) + { + Player *plr = objmgr.GetPlayer(m_PlayersNearPoint[i][j]); + if (!plr) + { + sLog.outError("BattleGroundEY:CheckSomeoneLeftPoint Player (GUID: %u) not found!", GUID_LOPART(m_PlayersNearPoint[i][j])); + //move not existed player to "free space" - this will cause many error showing in log, but it is a very important bug + m_PlayersNearPoint[EY_POINTS_MAX].push_back(m_PlayersNearPoint[i][j]); + m_PlayersNearPoint[i].erase(m_PlayersNearPoint[i].begin() + j); + ++j; + continue; + } + if (!plr->CanCaptureTowerPoint() || !plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS)) + //move player out of point (add him to players that are out of points + { + m_PlayersNearPoint[EY_POINTS_MAX].push_back(m_PlayersNearPoint[i][j]); + m_PlayersNearPoint[i].erase(m_PlayersNearPoint[i].begin() + j); + this->UpdateWorldStateForPlayer(PROGRESS_BAR_SHOW, BG_EY_PROGRESS_BAR_DONT_SHOW, plr); + } + else + { + //player is neat flag, so update count: + m_CurrentPointPlayersCount[2 * i + GetTeamIndexByTeamId(plr->GetTeam())]++; + ++j; + } + } + } + } +} + +void BattleGroundEY::UpdatePointStatuses() +{ + for (uint8 point = 0; point < EY_POINTS_MAX; ++point) + { + if (m_PlayersNearPoint[point].empty()) + continue; + //count new point bar status: + m_PointBarStatus[point] += (m_CurrentPointPlayersCount[2 * point] - m_CurrentPointPlayersCount[2 * point + 1] < BG_EY_POINT_MAX_CAPTURERS_COUNT) ? m_CurrentPointPlayersCount[2 * point] - m_CurrentPointPlayersCount[2 * point + 1] : BG_EY_POINT_MAX_CAPTURERS_COUNT; + + if (m_PointBarStatus[point] > BG_EY_PROGRESS_BAR_ALI_CONTROLLED) + //point is fully alliance's + m_PointBarStatus[point] = BG_EY_PROGRESS_BAR_ALI_CONTROLLED; + if (m_PointBarStatus[point] < BG_EY_PROGRESS_BAR_HORDE_CONTROLLED) + //point is fully horde's + m_PointBarStatus[point] = BG_EY_PROGRESS_BAR_HORDE_CONTROLLED; + + uint32 pointOwnerTeamId = 0; + //find which team should own this point + if (m_PointBarStatus[point] <= BG_EY_PROGRESS_BAR_NEUTRAL_LOW) + pointOwnerTeamId = HORDE; + else if (m_PointBarStatus[point] >= BG_EY_PROGRESS_BAR_NEUTRAL_HIGH) + pointOwnerTeamId = ALLIANCE; + else + pointOwnerTeamId = EY_POINT_NO_OWNER; + + for (uint8 i = 0; i < m_PlayersNearPoint[point].size(); ++i) + { + Player *plr = objmgr.GetPlayer(m_PlayersNearPoint[point][i]); + if (plr) + { + this->UpdateWorldStateForPlayer(PROGRESS_BAR_STATUS, m_PointBarStatus[point], plr); + //if point owner changed we must evoke event! + if (pointOwnerTeamId != m_PointOwnedByTeam[point]) + { + //point was uncontrolled and player is from team which captured point + if (m_PointState[point] == EY_POINT_STATE_UNCONTROLLED && plr->GetTeam() == pointOwnerTeamId) + this->EventTeamCapturedPoint(plr, point); + + //point was under control and player isn't from team which controlled it + if (m_PointState[point] == EY_POINT_UNDER_CONTROL && plr->GetTeam() != m_PointOwnedByTeam[point]) + this->EventTeamLostPoint(plr, point); + } + } + } + } +} + +void BattleGroundEY::UpdateTeamScore(uint32 Team) +{ + uint32 score = GetTeamScore(Team); + //TODO there should be some sound played when one team is near victory!! - and define variables + /*if (!m_IsInformedNearVictory && score >= BG_EY_WARNING_NEAR_VICTORY_SCORE) + { + if (Team == ALLIANCE) + SendMessageToAll(LANG_BG_EY_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); + else + SendMessageToAll(LANG_BG_EY_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); + PlaySoundToAll(BG_EY_SOUND_NEAR_VICTORY); + m_IsInformedNearVictory = true; + }*/ + + if (score >= BG_EY_MAX_TEAM_SCORE) + { + score = BG_EY_MAX_TEAM_SCORE; + EndBattleGround(Team); + } + + if (Team == ALLIANCE) + UpdateWorldState(EY_ALLIANCE_RESOURCES, score); + else + UpdateWorldState(EY_HORDE_RESOURCES, score); +} + +void BattleGroundEY::EndBattleGround(uint32 winner) +{ + //win reward + if (winner == ALLIANCE) + RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); + if (winner == HORDE) + RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); + //complete map reward + RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); + RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); + + BattleGround::EndBattleGround(winner); +} + +void BattleGroundEY::UpdatePointsCount(uint32 Team) +{ + if (Team == ALLIANCE) + UpdateWorldState(EY_ALLIANCE_BASE, m_TeamPointsCount[BG_TEAM_ALLIANCE]); + else + UpdateWorldState(EY_HORDE_BASE, m_TeamPointsCount[BG_TEAM_HORDE]); +} + +void BattleGroundEY::UpdatePointsIcons(uint32 Team, uint32 Point) +{ + //we MUST firstly send 0, after that we can send 1!!! + if (m_PointState[Point] == EY_POINT_UNDER_CONTROL) + { + UpdateWorldState(m_PointsIconStruct[Point].WorldStateControlIndex, 0); + if (Team == ALLIANCE) + UpdateWorldState(m_PointsIconStruct[Point].WorldStateAllianceControlledIndex, 1); + else + UpdateWorldState(m_PointsIconStruct[Point].WorldStateHordeControlledIndex, 1); + } + else + { + if (Team == ALLIANCE) + UpdateWorldState(m_PointsIconStruct[Point].WorldStateAllianceControlledIndex, 0); + else + UpdateWorldState(m_PointsIconStruct[Point].WorldStateHordeControlledIndex, 0); + UpdateWorldState(m_PointsIconStruct[Point].WorldStateControlIndex, 1); + } +} + +void BattleGroundEY::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map + BattleGroundEYScore* sc = new BattleGroundEYScore; + + m_PlayersNearPoint[EY_POINTS_MAX].push_back(plr->GetGUID()); + + m_PlayerScores[plr->GetGUID()] = sc; +} + +void BattleGroundEY::RemovePlayer(Player *plr, uint64 guid) +{ + // sometimes flag aura not removed :( + for (int j = EY_POINTS_MAX; j >= 0; --j) + { + for (size_t i = 0; i < m_PlayersNearPoint[j].size(); ++i) + if (m_PlayersNearPoint[j][i] == guid) + m_PlayersNearPoint[j].erase(m_PlayersNearPoint[j].begin() + i); + } + if (IsFlagPickedup()) + { + if (m_FlagKeeper == guid) + { + if (plr) + EventPlayerDroppedFlag(plr); + else + { + SetFlagPicker(0); + RespawnFlag(true); + } + } + } +} + +void BattleGroundEY::HandleAreaTrigger(Player *Source, uint32 Trigger) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + if (!Source->isAlive()) //hack code, must be removed later + return; + + switch(Trigger) + { + case TR_BLOOD_ELF_POINT: + if (m_PointState[BLOOD_ELF] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[BLOOD_ELF] == Source->GetTeam()) + if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) + EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_BLOOD_ELF); + break; + case TR_FEL_REALVER_POINT: + if (m_PointState[FEL_REALVER] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[FEL_REALVER] == Source->GetTeam()) + if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) + EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_FEL_REALVER); + break; + case TR_MAGE_TOWER_POINT: + if (m_PointState[MAGE_TOWER] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[MAGE_TOWER] == Source->GetTeam()) + if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) + EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_MAGE_TOWER); + break; + case TR_DRAENEI_RUINS_POINT: + if (m_PointState[DRAENEI_RUINS] == EY_POINT_UNDER_CONTROL && m_PointOwnedByTeam[DRAENEI_RUINS] == Source->GetTeam()) + if (m_FlagState && GetFlagPickerGUID() == Source->GetGUID()) + EventPlayerCapturedFlag(Source, BG_EY_OBJECT_FLAG_DRAENEI_RUINS); + break; + case 4512: + case 4515: + case 4517: + case 4519: + case 4530: + case 4531: + case 4568: + case 4569: + case 4570: + case 4571: + case 5866: + break; + default: + sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); + Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); + break; + } +} + +bool BattleGroundEY::SetupBattleGround() +{ + // doors + if (!AddObject(BG_EY_OBJECT_DOOR_A, BG_OBJECT_A_DOOR_EY_ENTRY, 2527.6f, 1596.91f, 1262.13f, -3.12414f, -0.173642f, -0.001515f, 0.98477f, -0.008594f, RESPAWN_IMMEDIATELY) + || !AddObject(BG_EY_OBJECT_DOOR_H, BG_OBJECT_H_DOOR_EY_ENTRY, 1803.21f, 1539.49f, 1261.09f, 3.14159f, 0.173648f, 0, 0.984808f, 0, RESPAWN_IMMEDIATELY) + // banners (alliance) + || !AddObject(BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2057.46f, 1735.07f, 1187.91f, -0.925024f, 0, 0, 0.446198f, -0.894934f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_A_BANNER_FEL_REALVER_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2032.25f, 1729.53f, 1190.33f, 1.8675f, 0, 0, 0.803857f, 0.594823f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_A_BANNER_FEL_REALVER_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2092.35f, 1775.46f, 1187.08f, -0.401426f, 0, 0, 0.199368f, -0.979925f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2047.19f, 1349.19f, 1189.0f, -1.62316f, 0, 0, 0.725374f, -0.688354f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_A_BANNER_BLOOD_ELF_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2074.32f, 1385.78f, 1194.72f, 0.488692f, 0, 0, 0.241922f, 0.970296f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_A_BANNER_BLOOD_ELF_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2025.13f, 1386.12f, 1192.74f, 2.3911f, 0, 0, 0.930418f, 0.366501f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2276.8f, 1400.41f, 1196.33f, 2.44346f, 0, 0, 0.939693f, 0.34202f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2305.78f, 1404.56f, 1199.38f, 1.74533f, 0, 0, 0.766044f, 0.642788f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2245.4f, 1366.41f, 1195.28f, 2.21657f, 0, 0, 0.894934f, 0.446198f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2270.84f, 1784.08f, 1186.76f, 2.42601f, 0, 0, 0.936672f, 0.350207f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_A_BANNER_MAGE_TOWER_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2269.13f, 1737.7f, 1186.66f, 0.994838f, 0, 0, 0.477159f, 0.878817f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_A_BANNER_MAGE_TOWER_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2300.86f, 1741.25f, 1187.7f, -0.785398f, 0, 0, 0.382683f, -0.92388f, RESPAWN_ONE_DAY) + // banners (horde) + || !AddObject(BG_EY_OBJECT_H_BANNER_FEL_REALVER_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2057.46f, 1735.07f, 1187.91f, -0.925024f, 0, 0, 0.446198f, -0.894934f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_H_BANNER_FEL_REALVER_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2032.25f, 1729.53f, 1190.33f, 1.8675f, 0, 0, 0.803857f, 0.594823f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_H_BANNER_FEL_REALVER_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2092.35f, 1775.46f, 1187.08f, -0.401426f, 0, 0, 0.199368f, -0.979925f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2047.19f, 1349.19f, 1189.0f, -1.62316f, 0, 0, 0.725374f, -0.688354f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_H_BANNER_BLOOD_ELF_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2074.32f, 1385.78f, 1194.72f, 0.488692f, 0, 0, 0.241922f, 0.970296f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_H_BANNER_BLOOD_ELF_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2025.13f, 1386.12f, 1192.74f, 2.3911f, 0, 0, 0.930418f, 0.366501f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2276.8f, 1400.41f, 1196.33f, 2.44346f, 0, 0, 0.939693f, 0.34202f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2305.78f, 1404.56f, 1199.38f, 1.74533f, 0, 0, 0.766044f, 0.642788f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2245.4f, 1366.41f, 1195.28f, 2.21657f, 0, 0, 0.894934f, 0.446198f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2270.84f, 1784.08f, 1186.76f, 2.42601f, 0, 0, 0.936672f, 0.350207f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_H_BANNER_MAGE_TOWER_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2269.13f, 1737.7f, 1186.66f, 0.994838f, 0, 0, 0.477159f, 0.878817f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_H_BANNER_MAGE_TOWER_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2300.86f, 1741.25f, 1187.7f, -0.785398f, 0, 0, 0.382683f, -0.92388f, RESPAWN_ONE_DAY) + // banners (natural) + || !AddObject(BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2057.46f, 1735.07f, 1187.91f, -0.925024f, 0, 0, 0.446198f, -0.894934f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_N_BANNER_FEL_REALVER_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2032.25f, 1729.53f, 1190.33f, 1.8675f, 0, 0, 0.803857f, 0.594823f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_N_BANNER_FEL_REALVER_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2092.35f, 1775.46f, 1187.08f, -0.401426f, 0, 0, 0.199368f, -0.979925f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2047.19f, 1349.19f, 1189.0f, -1.62316f, 0, 0, 0.725374f, -0.688354f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2074.32f, 1385.78f, 1194.72f, 0.488692f, 0, 0, 0.241922f, 0.970296f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2025.13f, 1386.12f, 1192.74f, 2.3911f, 0, 0, 0.930418f, 0.366501f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2276.8f, 1400.41f, 1196.33f, 2.44346f, 0, 0, 0.939693f, 0.34202f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2305.78f, 1404.56f, 1199.38f, 1.74533f, 0, 0, 0.766044f, 0.642788f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2245.4f, 1366.41f, 1195.28f, 2.21657f, 0, 0, 0.894934f, 0.446198f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2270.84f, 1784.08f, 1186.76f, 2.42601f, 0, 0, 0.936672f, 0.350207f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2269.13f, 1737.7f, 1186.66f, 0.994838f, 0, 0, 0.477159f, 0.878817f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2300.86f, 1741.25f, 1187.7f, -0.785398f, 0, 0, 0.382683f, -0.92388f, RESPAWN_ONE_DAY) + // flags + || !AddObject(BG_EY_OBJECT_FLAG_NETHERSTORM, BG_OBJECT_FLAG2_EY_ENTRY, 2174.782227f, 1569.054688f, 1160.361938f, -1.448624f, 0, 0, 0.662620f, -0.748956f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_FLAG_FEL_REALVER, BG_OBJECT_FLAG1_EY_ENTRY, 2044.28f, 1729.68f, 1189.96f, -0.017453f, 0, 0, 0.008727f, -0.999962f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_FLAG_BLOOD_ELF, BG_OBJECT_FLAG1_EY_ENTRY, 2048.83f, 1393.65f, 1194.49f, 0.20944f, 0, 0, 0.104528f, 0.994522f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_FLAG_DRAENEI_RUINS, BG_OBJECT_FLAG1_EY_ENTRY, 2286.56f, 1402.36f, 1197.11f, 3.72381f, 0, 0, 0.957926f, -0.287016f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_FLAG_MAGE_TOWER, BG_OBJECT_FLAG1_EY_ENTRY, 2284.48f, 1731.23f, 1189.99f, 2.89725f, 0, 0, 0.992546f, 0.121869f, RESPAWN_ONE_DAY) + // tower cap + || !AddObject(BG_EY_OBJECT_TOWER_CAP_FEL_REALVER, BG_OBJECT_FR_TOWER_CAP_EY_ENTRY, 2024.600708f, 1742.819580f, 1195.157715f, 2.443461f, 0, 0, 0.939693f, 0.342020f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_TOWER_CAP_BLOOD_ELF, BG_OBJECT_BE_TOWER_CAP_EY_ENTRY, 2050.493164f, 1372.235962f, 1194.563477f, 1.710423f, 0, 0, 0.754710f, 0.656059f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_TOWER_CAP_DRAENEI_RUINS, BG_OBJECT_DR_TOWER_CAP_EY_ENTRY, 2301.010498f, 1386.931641f, 1197.183472f, 1.570796f, 0, 0, 0.707107f, 0.707107f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_TOWER_CAP_MAGE_TOWER, BG_OBJECT_HU_TOWER_CAP_EY_ENTRY, 2282.121582f, 1760.006958f, 1189.707153f, 1.919862f, 0, 0, 0.819152f, 0.573576f, RESPAWN_ONE_DAY) +) + { + sLog.outErrorDb("BatteGroundEY: Failed to spawn some object BattleGround not created!"); + return false; + } + + //buffs + for (int i = 0; i < EY_POINTS_MAX; ++i) + { + AreaTriggerEntry const* at = sAreaTriggerStore.LookupEntry(m_Points_Trigger[i]); + if (!at) + { + sLog.outError("BattleGroundEY: Unknown trigger: %u", m_Points_Trigger[i]); + continue; + } + if (!AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3, Buff_Entries[0], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3 + 1, Buff_Entries[1], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY) + || !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + i * 3 + 2, Buff_Entries[2], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY) +) + sLog.outError("BattleGroundEY: Cannot spawn buff"); + } + + WorldSafeLocsEntry const *sg = NULL; + sg = sWorldSafeLocsStore.LookupEntry(EY_GRAVEYARD_MAIN_ALLIANCE); + if (!sg || !AddSpiritGuide(EY_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, ALLIANCE)) + { + sLog.outErrorDb("BatteGroundEY: Failed to spawn spirit guide! BattleGround not created!"); + return false; + } + + sg = sWorldSafeLocsStore.LookupEntry(EY_GRAVEYARD_MAIN_HORDE); + if (!sg || !AddSpiritGuide(EY_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, HORDE)) + { + sLog.outErrorDb("BatteGroundEY: Failed to spawn spirit guide! BattleGround not created!"); + return false; + } + + return true; +} + +void BattleGroundEY::Reset() +{ + //call parent's class reset + BattleGround::Reset(); + + m_TeamScores[BG_TEAM_ALLIANCE] = 0; + m_TeamScores[BG_TEAM_HORDE] = 0; + m_TeamPointsCount[BG_TEAM_ALLIANCE] = 0; + m_TeamPointsCount[BG_TEAM_HORDE] = 0; + m_HonorScoreTics[BG_TEAM_ALLIANCE] = 0; + m_HonorScoreTics[BG_TEAM_HORDE] = 0; + m_FlagState = BG_EY_FLAG_STATE_ON_BASE; + m_FlagCapturedBgObjectType = 0; + m_FlagKeeper = 0; + m_DroppedFlagGUID = 0; + m_PointAddingTimer = 0; + m_TowerCapCheckTimer = 0; + bool isBGWeekend = sBattleGroundMgr.IsBGWeekend(GetTypeID()); + m_HonorTics = (isBGWeekend) ? BG_EY_EYWeekendHonorTicks : BG_EY_NotEYWeekendHonorTicks; + + for (uint8 i = 0; i < EY_POINTS_MAX; ++i) + { + m_PointOwnedByTeam[i] = EY_POINT_NO_OWNER; + m_PointState[i] = EY_POINT_STATE_UNCONTROLLED; + m_PointBarStatus[i] = BG_EY_PROGRESS_BAR_STATE_MIDDLE; + m_PlayersNearPoint[i].clear(); + m_PlayersNearPoint[i].reserve(15); //tip size + } + m_PlayersNearPoint[EY_PLAYERS_OUT_OF_POINTS].clear(); + m_PlayersNearPoint[EY_PLAYERS_OUT_OF_POINTS].reserve(30); +} + +void BattleGroundEY::RespawnFlag(bool send_message) +{ + if (m_FlagCapturedBgObjectType > 0) + SpawnBGObject(m_FlagCapturedBgObjectType, RESPAWN_ONE_DAY); + + m_FlagCapturedBgObjectType = 0; + m_FlagState = BG_EY_FLAG_STATE_ON_BASE; + SpawnBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM, RESPAWN_IMMEDIATELY); + + if (send_message) + { + SendMessageToAll(LANG_BG_EY_RESETED_FLAG, CHAT_MSG_BG_SYSTEM_NEUTRAL); + PlaySoundToAll(BG_EY_SOUND_FLAG_RESET); // flags respawned sound... + } + + UpdateWorldState(NETHERSTORM_FLAG, 1); +} + +void BattleGroundEY::RespawnFlagAfterDrop() +{ + RespawnFlag(true); + + GameObject *obj = HashMapHolder::Find(GetDroppedFlagGUID()); + if (obj) + obj->Delete(); + else + sLog.outError("BattleGroundEY: Unknown dropped flag guid: %u",GUID_LOPART(GetDroppedFlagGUID())); + + SetDroppedFlagGUID(0); +} + +void BattleGroundEY::HandleKillPlayer(Player *player, Player *killer) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + BattleGround::HandleKillPlayer(player, killer); + EventPlayerDroppedFlag(player); +} + +void BattleGroundEY::EventPlayerDroppedFlag(Player *Source) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + { + // if not running, do not cast things at the dropper player, neither send unnecessary messages + // just take off the aura + if (IsFlagPickedup() && GetFlagPickerGUID() == Source->GetGUID()) + { + SetFlagPicker(0); + Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL); + } + return; + } + + if (!IsFlagPickedup()) + return; + + if (GetFlagPickerGUID() != Source->GetGUID()) + return; + + SetFlagPicker(0); + Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL); + m_FlagState = BG_EY_FLAG_STATE_ON_GROUND; + m_FlagsTimer = BG_EY_FLAG_RESPAWN_TIME; + Source->CastSpell(Source, SPELL_RECENTLY_DROPPED_FLAG, true); + Source->CastSpell(Source, BG_EY_PLAYER_DROPPED_FLAG_SPELL, true); + //this does not work correctly :((it should remove flag carrier name) + UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_WAIT_RESPAWN); + UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_WAIT_RESPAWN); + + if (Source->GetTeam() == ALLIANCE) + SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL); + else + SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, NULL); +} + +void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj) +{ + if (GetStatus() != STATUS_IN_PROGRESS || IsFlagPickedup() || !Source->IsWithinDistInMap(target_obj, 10)) + return; + + if (Source->GetTeam() == ALLIANCE) + { + UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_ON_PLAYER); + PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE); + } + else + { + UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_ON_PLAYER); + PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_HORDE); + } + + if (m_FlagState == BG_EY_FLAG_STATE_ON_BASE) + UpdateWorldState(NETHERSTORM_FLAG, 0); + m_FlagState = BG_EY_FLAG_STATE_ON_PLAYER; + + SpawnBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM, RESPAWN_ONE_DAY); + SetFlagPicker(Source->GetGUID()); + //get flag aura on player + Source->CastSpell(Source, BG_EY_NETHERSTORM_FLAG_SPELL, true); + Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); + + if (Source->GetTeam() == ALLIANCE) + PSendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, Source->GetName()); + else + PSendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, NULL, Source->GetName()); +} + +void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + //Natural point + uint32 Team = m_PointOwnedByTeam[Point]; + + if (!Team) + return; + + if (Team == ALLIANCE) + { + m_TeamPointsCount[BG_TEAM_ALLIANCE]--; + SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance, RESPAWN_ONE_DAY); + SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance + 1, RESPAWN_ONE_DAY); + SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance + 2, RESPAWN_ONE_DAY); + } + else + { + m_TeamPointsCount[BG_TEAM_HORDE]--; + SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde, RESPAWN_ONE_DAY); + SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde + 1, RESPAWN_ONE_DAY); + SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde + 2, RESPAWN_ONE_DAY); + } + + SpawnBGObject(m_LoosingPointTypes[Point].SpawnNeutralObjectType, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_LoosingPointTypes[Point].SpawnNeutralObjectType + 1, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_LoosingPointTypes[Point].SpawnNeutralObjectType + 2, RESPAWN_IMMEDIATELY); + + //buff isn't despawned + + m_PointOwnedByTeam[Point] = EY_POINT_NO_OWNER; + m_PointState[Point] = EY_POINT_NO_OWNER; + + if (Team == ALLIANCE) + SendMessageToAll(m_LoosingPointTypes[Point].MessageIdAlliance,CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); + else + SendMessageToAll(m_LoosingPointTypes[Point].MessageIdHorde,CHAT_MSG_BG_SYSTEM_HORDE, Source); + + UpdatePointsIcons(Team, Point); + UpdatePointsCount(Team); + + //remove bonus honor aura trigger creature when node is lost + if (Point < EY_POINTS_MAX) + DelCreature(Point + 6);//NULL checks are in DelCreature! 0-5 spirit guides +} + +void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + uint32 Team = Source->GetTeam(); + + SpawnBGObject(m_CapturingPointTypes[Point].DespawnNeutralObjectType, RESPAWN_ONE_DAY); + SpawnBGObject(m_CapturingPointTypes[Point].DespawnNeutralObjectType + 1, RESPAWN_ONE_DAY); + SpawnBGObject(m_CapturingPointTypes[Point].DespawnNeutralObjectType + 2, RESPAWN_ONE_DAY); + + if (Team == ALLIANCE) + { + m_TeamPointsCount[BG_TEAM_ALLIANCE]++; + SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance + 1, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance + 2, RESPAWN_IMMEDIATELY); + } + else + { + m_TeamPointsCount[BG_TEAM_HORDE]++; + SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde + 1, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde + 2, RESPAWN_IMMEDIATELY); + } + + //buff isn't respawned + + m_PointOwnedByTeam[Point] = Team; + m_PointState[Point] = EY_POINT_UNDER_CONTROL; + + if (Team == ALLIANCE) + SendMessageToAll(m_CapturingPointTypes[Point].MessageIdAlliance,CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); + else + SendMessageToAll(m_CapturingPointTypes[Point].MessageIdHorde,CHAT_MSG_BG_SYSTEM_HORDE, Source); + + if (m_BgCreatures[Point]) + DelCreature(Point); + + WorldSafeLocsEntry const *sg = NULL; + sg = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[Point].GraveYardId); + if (!sg || !AddSpiritGuide(Point, sg->x, sg->y, sg->z, 3.124139f, Team)) + sLog.outError("BatteGroundEY: Failed to spawn spirit guide! point: %u, team: %u, graveyard_id: %u", + Point, Team, m_CapturingPointTypes[Point].GraveYardId); + +// SpawnBGCreature(Point,RESPAWN_IMMEDIATELY); + + UpdatePointsIcons(Team, Point); + UpdatePointsCount(Team); + + if (Point >= EY_POINTS_MAX) + return; + + Creature* trigger = GetBGCreature(Point + 6);//0-5 spirit guides + if (!trigger) + trigger = AddCreature(WORLD_TRIGGER,Point+6,Team,BG_EY_TriggerPositions[Point][0],BG_EY_TriggerPositions[Point][1],BG_EY_TriggerPositions[Point][2],BG_EY_TriggerPositions[Point][3]); + + //add bonus honor aura trigger creature when node is accupied + //cast bonus aura (+50% honor in 25yards) + //aura should only apply to players who have accupied the node, set correct faction for trigger + if (trigger) + { + trigger->setFaction(Team == ALLIANCE ? 84 : 83); + trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false); + } +} + +void BattleGroundEY::EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType) +{ + if (GetStatus() != STATUS_IN_PROGRESS || GetFlagPickerGUID() != Source->GetGUID()) + return; + + SetFlagPicker(0); + m_FlagState = BG_EY_FLAG_STATE_WAIT_RESPAWN; + Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL); + + Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); + + if (Source->GetTeam() == ALLIANCE) + PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE); + else + PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_HORDE); + + SpawnBGObject(BgObjectType, RESPAWN_IMMEDIATELY); + + m_FlagsTimer = BG_EY_FLAG_RESPAWN_TIME; + m_FlagCapturedBgObjectType = BgObjectType; + + uint8 team_id = 0; + if (Source->GetTeam() == ALLIANCE) + { + team_id = BG_TEAM_ALLIANCE; + SendMessageToAll(LANG_BG_EY_CAPTURED_FLAG_A, CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); + } + else + { + team_id = BG_TEAM_HORDE; + SendMessageToAll(LANG_BG_EY_CAPTURED_FLAG_H, CHAT_MSG_BG_SYSTEM_HORDE, Source); + } + + if (m_TeamPointsCount[team_id] > 0) + AddPoints(Source->GetTeam(), BG_EY_FlagPoints[m_TeamPointsCount[team_id] - 1]); + + UpdatePlayerScore(Source, SCORE_FLAG_CAPTURES, 1); +} + +void BattleGroundEY::UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor) +{ + BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); + if (itr == m_PlayerScores.end()) // player not found + return; + + switch(type) + { + case SCORE_FLAG_CAPTURES: // flags captured + ((BattleGroundEYScore*)itr->second)->FlagCaptures += value; + break; + default: + BattleGround::UpdatePlayerScore(Source, type, value, doAddHonor); + break; + } +} + +void BattleGroundEY::FillInitialWorldStates(WorldPacket& data) +{ + data << uint32(EY_HORDE_BASE) << uint32(m_TeamPointsCount[BG_TEAM_HORDE]); + data << uint32(EY_ALLIANCE_BASE) << uint32(m_TeamPointsCount[BG_TEAM_ALLIANCE]); + data << uint32(0xab6) << uint32(0x0); + data << uint32(0xab5) << uint32(0x0); + data << uint32(0xab4) << uint32(0x0); + data << uint32(0xab3) << uint32(0x0); + data << uint32(0xab2) << uint32(0x0); + data << uint32(0xab1) << uint32(0x0); + data << uint32(0xab0) << uint32(0x0); + data << uint32(0xaaf) << uint32(0x0); + + data << uint32(DRAENEI_RUINS_HORDE_CONTROL) << uint32(m_PointOwnedByTeam[DRAENEI_RUINS] == HORDE && m_PointState[DRAENEI_RUINS] == EY_POINT_UNDER_CONTROL); + + data << uint32(DRAENEI_RUINS_ALLIANCE_CONTROL) << uint32(m_PointOwnedByTeam[DRAENEI_RUINS] == ALLIANCE && m_PointState[DRAENEI_RUINS] == EY_POINT_UNDER_CONTROL); + + data << uint32(DRAENEI_RUINS_UNCONTROL) << uint32(m_PointState[DRAENEI_RUINS] != EY_POINT_UNDER_CONTROL); + + data << uint32(MAGE_TOWER_ALLIANCE_CONTROL) << uint32(m_PointOwnedByTeam[MAGE_TOWER] == ALLIANCE && m_PointState[MAGE_TOWER] == EY_POINT_UNDER_CONTROL); + + data << uint32(MAGE_TOWER_HORDE_CONTROL) << uint32(m_PointOwnedByTeam[MAGE_TOWER] == HORDE && m_PointState[MAGE_TOWER] == EY_POINT_UNDER_CONTROL); + + data << uint32(MAGE_TOWER_UNCONTROL) << uint32(m_PointState[MAGE_TOWER] != EY_POINT_UNDER_CONTROL); + + data << uint32(FEL_REAVER_HORDE_CONTROL) << uint32(m_PointOwnedByTeam[FEL_REALVER] == HORDE && m_PointState[FEL_REALVER] == EY_POINT_UNDER_CONTROL); + + data << uint32(FEL_REAVER_ALLIANCE_CONTROL) << uint32(m_PointOwnedByTeam[FEL_REALVER] == ALLIANCE && m_PointState[FEL_REALVER] == EY_POINT_UNDER_CONTROL); + + data << uint32(FEL_REAVER_UNCONTROL) << uint32(m_PointState[FEL_REALVER] != EY_POINT_UNDER_CONTROL); + + data << uint32(BLOOD_ELF_HORDE_CONTROL) << uint32(m_PointOwnedByTeam[BLOOD_ELF] == HORDE && m_PointState[BLOOD_ELF] == EY_POINT_UNDER_CONTROL); + + data << uint32(BLOOD_ELF_ALLIANCE_CONTROL) << uint32(m_PointOwnedByTeam[BLOOD_ELF] == ALLIANCE && m_PointState[BLOOD_ELF] == EY_POINT_UNDER_CONTROL); + + data << uint32(BLOOD_ELF_UNCONTROL) << uint32(m_PointState[BLOOD_ELF] != EY_POINT_UNDER_CONTROL); + + data << uint32(NETHERSTORM_FLAG) << uint32(m_FlagState == BG_EY_FLAG_STATE_ON_BASE); + + data << uint32(0xad2) << uint32(0x1); + data << uint32(0xad1) << uint32(0x1); + data << uint32(0xabe) << uint32(GetTeamScore(HORDE)); + data << uint32(0xabd) << uint32(GetTeamScore(ALLIANCE)); + data << uint32(0xa05) << uint32(0x8e); + data << uint32(0xaa0) << uint32(0x0); + data << uint32(0xa9f) << uint32(0x0); + data << uint32(0xa9e) << uint32(0x0); + data << uint32(0xc0d) << uint32(0x17b); +} + +WorldSafeLocsEntry const *BattleGroundEY::GetClosestGraveYard(Player* player) +{ + uint32 g_id = 0; + + switch(player->GetTeam()) + { + case ALLIANCE: g_id = EY_GRAVEYARD_MAIN_ALLIANCE; break; + case HORDE: g_id = EY_GRAVEYARD_MAIN_HORDE; break; + default: return NULL; + } + + float distance, nearestDistance; + + WorldSafeLocsEntry const* entry = NULL; + WorldSafeLocsEntry const* nearestEntry = NULL; + entry = sWorldSafeLocsStore.LookupEntry(g_id); + nearestEntry = entry; + + if (!entry) + { + sLog.outError("BattleGroundEY: Not found the main team graveyard. Graveyard system isn't working!"); + return NULL; + } + + float plr_x = player->GetPositionX(); + float plr_y = player->GetPositionY(); + float plr_z = player->GetPositionZ(); + + distance = (entry->x - plr_x)*(entry->x - plr_x) + (entry->y - plr_y)*(entry->y - plr_y) + (entry->z - plr_z)*(entry->z - plr_z); + nearestDistance = distance; + + for (uint8 i = 0; i < EY_POINTS_MAX; ++i) + { + if (m_PointOwnedByTeam[i] == player->GetTeam() && m_PointState[i] == EY_POINT_UNDER_CONTROL) + { + entry = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[i].GraveYardId); + if (!entry) + sLog.outError("BattleGroundEY: Not found graveyard: %u",m_CapturingPointTypes[i].GraveYardId); + else + { + distance = (entry->x - plr_x)*(entry->x - plr_x) + (entry->y - plr_y)*(entry->y - plr_y) + (entry->z - plr_z)*(entry->z - plr_z); + if (distance < nearestDistance) + { + nearestDistance = distance; + nearestEntry = entry; + } + } + } + } + + return nearestEntry; +} + +bool BattleGroundEY::IsAllNodesConrolledByTeam(uint32 team) const +{ + uint32 count = 0; + for (int i = 0; i < EY_POINTS_MAX; ++i) + if (m_PointOwnedByTeam[i] == team && m_PointState[i] == EY_POINT_UNDER_CONTROL) + ++count; + + return count == EY_POINTS_MAX; +} diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundEY.h b/src/server/game/BattleGrounds/Zones/BattleGroundEY.h new file mode 100644 index 00000000000..4fe23c4c821 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundEY.h @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __BATTLEGROUNDEY_H +#define __BATTLEGROUNDEY_H + +#include "Language.h" + +class BattleGround; + +#define BG_EY_FLAG_RESPAWN_TIME (8*IN_MILISECONDS) //8 seconds +#define BG_EY_FPOINTS_TICK_TIME (2*IN_MILISECONDS) //2 seconds + +enum BG_EY_WorldStates +{ + EY_ALLIANCE_RESOURCES = 2749, + EY_HORDE_RESOURCES = 2750, + EY_ALLIANCE_BASE = 2752, + EY_HORDE_BASE = 2753, + DRAENEI_RUINS_HORDE_CONTROL = 2733, + DRAENEI_RUINS_ALLIANCE_CONTROL = 2732, + DRAENEI_RUINS_UNCONTROL = 2731, + MAGE_TOWER_ALLIANCE_CONTROL = 2730, + MAGE_TOWER_HORDE_CONTROL = 2729, + MAGE_TOWER_UNCONTROL = 2728, + FEL_REAVER_HORDE_CONTROL = 2727, + FEL_REAVER_ALLIANCE_CONTROL = 2726, + FEL_REAVER_UNCONTROL = 2725, + BLOOD_ELF_HORDE_CONTROL = 2724, + BLOOD_ELF_ALLIANCE_CONTROL = 2723, + BLOOD_ELF_UNCONTROL = 2722, + PROGRESS_BAR_PERCENT_GREY = 2720, //100 = empty (only grey), 0 = blue|red (no grey) + PROGRESS_BAR_STATUS = 2719, //50 init!, 48 ... hordak bere .. 33 .. 0 = full 100% hordacky , 100 = full alliance + PROGRESS_BAR_SHOW = 2718, //1 init, 0 druhy send - bez messagu, 1 = controlled aliance + NETHERSTORM_FLAG = 2757, + //set to 2 when flag is picked up, and to 1 if it is dropped + NETHERSTORM_FLAG_STATE_ALLIANCE = 2769, + NETHERSTORM_FLAG_STATE_HORDE = 2770 +}; + +enum BG_EY_ProgressBarConsts +{ + BG_EY_POINT_MAX_CAPTURERS_COUNT = 5, + BG_EY_POINT_RADIUS = 70, + BG_EY_PROGRESS_BAR_DONT_SHOW = 0, + BG_EY_PROGRESS_BAR_SHOW = 1, + BG_EY_PROGRESS_BAR_PERCENT_GREY = 40, + BG_EY_PROGRESS_BAR_STATE_MIDDLE = 50, + BG_EY_PROGRESS_BAR_HORDE_CONTROLLED = 0, + BG_EY_PROGRESS_BAR_NEUTRAL_LOW = 30, + BG_EY_PROGRESS_BAR_NEUTRAL_HIGH = 70, + BG_EY_PROGRESS_BAR_ALI_CONTROLLED = 100 +}; + +enum BG_EY_Sounds +{ + //strange ids, but sure about them + BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE = 8212, + BG_EY_SOUND_FLAG_CAPTURED_HORDE = 8213, + BG_EY_SOUND_FLAG_PICKED_UP_HORDE = 8174, + BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE = 8173, + BG_EY_SOUND_FLAG_RESET = 8192 +}; + +enum BG_EY_Spells +{ + BG_EY_NETHERSTORM_FLAG_SPELL = 34976, + BG_EY_PLAYER_DROPPED_FLAG_SPELL = 34991 +}; + +enum EYBattleGroundObjectEntry +{ + BG_OBJECT_A_DOOR_EY_ENTRY = 184719, //Alliance door + BG_OBJECT_H_DOOR_EY_ENTRY = 184720, //Horde door + BG_OBJECT_FLAG1_EY_ENTRY = 184493, //Netherstorm flag (generic) + BG_OBJECT_FLAG2_EY_ENTRY = 184141, //Netherstorm flag (flagstand) + BG_OBJECT_FLAG3_EY_ENTRY = 184142, //Netherstorm flag (flagdrop) + BG_OBJECT_A_BANNER_EY_ENTRY = 184381, //Visual Banner (Alliance) + BG_OBJECT_H_BANNER_EY_ENTRY = 184380, //Visual Banner (Horde) + BG_OBJECT_N_BANNER_EY_ENTRY = 184382, //Visual Banner (Neutral) + BG_OBJECT_BE_TOWER_CAP_EY_ENTRY = 184080, //BE Tower Cap Pt + BG_OBJECT_FR_TOWER_CAP_EY_ENTRY = 184081, //Fel Reaver Cap Pt + BG_OBJECT_HU_TOWER_CAP_EY_ENTRY = 184082, //Human Tower Cap Pt + BG_OBJECT_DR_TOWER_CAP_EY_ENTRY = 184083 //Draenei Tower Cap Pt +}; + +enum EYBattleGroundPointsTrigger +{ + TR_BLOOD_ELF_POINT = 4476, + TR_FEL_REALVER_POINT = 4514, + TR_MAGE_TOWER_POINT = 4516, + TR_DRAENEI_RUINS_POINT = 4518, + TR_BLOOD_ELF_BUFF = 4568, + TR_FEL_REALVER_BUFF = 4569, + TR_MAGE_TOWER_BUFF = 4570, + TR_DRAENEI_RUINS_BUFF = 4571 +}; + +enum EYBattleGroundGaveyards +{ + EY_GRAVEYARD_MAIN_ALLIANCE = 1103, + EY_GRAVEYARD_MAIN_HORDE = 1104, + EY_GRAVEYARD_FEL_REALVER = 1105, + EY_GRAVEYARD_BLOOD_ELF = 1106, + EY_GRAVEYARD_DRAENEI_RUINS = 1107, + EY_GRAVEYARD_MAGE_TOWER = 1108 +}; + +enum EYBattleGroundPoints +{ + FEL_REALVER = 0, + BLOOD_ELF = 1, + DRAENEI_RUINS = 2, + MAGE_TOWER = 3, + + EY_PLAYERS_OUT_OF_POINTS = 4, + EY_POINTS_MAX = 4 +}; + +enum EYBattleGroundCreaturesTypes +{ + EY_SPIRIT_FEL_REALVER = 0, + EY_SPIRIT_BLOOD_ELF = 1, + EY_SPIRIT_DRAENEI_RUINS = 2, + EY_SPIRIT_MAGE_TOWER = 3, + EY_SPIRIT_MAIN_ALLIANCE = 4, + EY_SPIRIT_MAIN_HORDE = 5, + + EY_TRIGGER_FEL_REALVER = 6, + EY_TRIGGER_BLOOD_ELF = 7, + EY_TRIGGER_DRAENEI_RUINS = 8, + EY_TRIGGER_MAGE_TOWER = 9, + + BG_EY_CREATURES_MAX = 10 +}; + +enum EYBattleGroundObjectTypes +{ + BG_EY_OBJECT_DOOR_A = 0, + BG_EY_OBJECT_DOOR_H = 1, + BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER = 2, + BG_EY_OBJECT_A_BANNER_FEL_REALVER_LEFT = 3, + BG_EY_OBJECT_A_BANNER_FEL_REALVER_RIGHT = 4, + BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER = 5, + BG_EY_OBJECT_A_BANNER_BLOOD_ELF_LEFT = 6, + BG_EY_OBJECT_A_BANNER_BLOOD_ELF_RIGHT = 7, + BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER = 8, + BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_LEFT = 9, + BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_RIGHT = 10, + BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER = 11, + BG_EY_OBJECT_A_BANNER_MAGE_TOWER_LEFT = 12, + BG_EY_OBJECT_A_BANNER_MAGE_TOWER_RIGHT = 13, + BG_EY_OBJECT_H_BANNER_FEL_REALVER_CENTER = 14, + BG_EY_OBJECT_H_BANNER_FEL_REALVER_LEFT = 15, + BG_EY_OBJECT_H_BANNER_FEL_REALVER_RIGHT = 16, + BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER = 17, + BG_EY_OBJECT_H_BANNER_BLOOD_ELF_LEFT = 18, + BG_EY_OBJECT_H_BANNER_BLOOD_ELF_RIGHT = 19, + BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER = 20, + BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_LEFT = 21, + BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_RIGHT = 22, + BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER = 23, + BG_EY_OBJECT_H_BANNER_MAGE_TOWER_LEFT = 24, + BG_EY_OBJECT_H_BANNER_MAGE_TOWER_RIGHT = 25, + BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER = 26, + BG_EY_OBJECT_N_BANNER_FEL_REALVER_LEFT = 27, + BG_EY_OBJECT_N_BANNER_FEL_REALVER_RIGHT = 28, + BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER = 29, + BG_EY_OBJECT_N_BANNER_BLOOD_ELF_LEFT = 30, + BG_EY_OBJECT_N_BANNER_BLOOD_ELF_RIGHT = 31, + BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER = 32, + BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_LEFT = 33, + BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_RIGHT = 34, + BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER = 35, + BG_EY_OBJECT_N_BANNER_MAGE_TOWER_LEFT = 36, + BG_EY_OBJECT_N_BANNER_MAGE_TOWER_RIGHT = 37, + BG_EY_OBJECT_TOWER_CAP_FEL_REALVER = 38, + BG_EY_OBJECT_TOWER_CAP_BLOOD_ELF = 39, + BG_EY_OBJECT_TOWER_CAP_DRAENEI_RUINS = 40, + BG_EY_OBJECT_TOWER_CAP_MAGE_TOWER = 41, + BG_EY_OBJECT_FLAG_NETHERSTORM = 42, + BG_EY_OBJECT_FLAG_FEL_REALVER = 43, + BG_EY_OBJECT_FLAG_BLOOD_ELF = 44, + BG_EY_OBJECT_FLAG_DRAENEI_RUINS = 45, + BG_EY_OBJECT_FLAG_MAGE_TOWER = 46, + //buffs + BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER = 47, + BG_EY_OBJECT_REGENBUFF_FEL_REALVER = 48, + BG_EY_OBJECT_BERSERKBUFF_FEL_REALVER = 49, + BG_EY_OBJECT_SPEEDBUFF_BLOOD_ELF = 50, + BG_EY_OBJECT_REGENBUFF_BLOOD_ELF = 51, + BG_EY_OBJECT_BERSERKBUFF_BLOOD_ELF = 52, + BG_EY_OBJECT_SPEEDBUFF_DRAENEI_RUINS = 53, + BG_EY_OBJECT_REGENBUFF_DRAENEI_RUINS = 54, + BG_EY_OBJECT_BERSERKBUFF_DRAENEI_RUINS = 55, + BG_EY_OBJECT_SPEEDBUFF_MAGE_TOWER = 56, + BG_EY_OBJECT_REGENBUFF_MAGE_TOWER = 57, + BG_EY_OBJECT_BERSERKBUFF_MAGE_TOWER = 58, + BG_EY_OBJECT_MAX = 59 +}; + +#define BG_EY_NotEYWeekendHonorTicks 330 +#define BG_EY_EYWeekendHonorTicks 200 + +enum BG_EY_Score +{ + BG_EY_WARNING_NEAR_VICTORY_SCORE = 1400, + BG_EY_MAX_TEAM_SCORE = 1600 +}; + +enum BG_EY_FlagState +{ + BG_EY_FLAG_STATE_ON_BASE = 0, + BG_EY_FLAG_STATE_WAIT_RESPAWN = 1, + BG_EY_FLAG_STATE_ON_PLAYER = 2, + BG_EY_FLAG_STATE_ON_GROUND = 3 +}; + +enum EYBattleGroundPointState +{ + EY_POINT_NO_OWNER = 0, + EY_POINT_STATE_UNCONTROLLED = 0, + EY_POINT_UNDER_CONTROL = 3 +}; + +struct BattleGroundEYPointIconsStruct +{ + BattleGroundEYPointIconsStruct(uint32 _WorldStateControlIndex, uint32 _WorldStateAllianceControlledIndex, uint32 _WorldStateHordeControlledIndex) + : WorldStateControlIndex(_WorldStateControlIndex), WorldStateAllianceControlledIndex(_WorldStateAllianceControlledIndex), WorldStateHordeControlledIndex(_WorldStateHordeControlledIndex) {} + uint32 WorldStateControlIndex; + uint32 WorldStateAllianceControlledIndex; + uint32 WorldStateHordeControlledIndex; +}; + +// x, y, z, o +const float BG_EY_TriggerPositions[EY_POINTS_MAX][4] = { + {2044.28f, 1729.68f, 1189.96f, -0.017453f}, // FEL_REALVER center + {2048.83f, 1393.65f, 1194.49f, 0.20944f}, // BLOOD_ELF center + {2286.56f, 1402.36f, 1197.11f, 3.72381f}, // DRAENEI_RUINS center + {2284.48f, 1731.23f, 1189.99f, 2.89725f} // MAGE_TOWER center +}; + +struct BattleGroundEYLoosingPointStruct +{ + BattleGroundEYLoosingPointStruct(uint32 _SpawnNeutralObjectType, uint32 _DespawnObjectTypeAlliance, uint32 _MessageIdAlliance, uint32 _DespawnObjectTypeHorde, uint32 _MessageIdHorde) + : SpawnNeutralObjectType(_SpawnNeutralObjectType), + DespawnObjectTypeAlliance(_DespawnObjectTypeAlliance), MessageIdAlliance(_MessageIdAlliance), + DespawnObjectTypeHorde(_DespawnObjectTypeHorde), MessageIdHorde(_MessageIdHorde) + {} + + uint32 SpawnNeutralObjectType; + uint32 DespawnObjectTypeAlliance; + uint32 MessageIdAlliance; + uint32 DespawnObjectTypeHorde; + uint32 MessageIdHorde; +}; + +struct BattleGroundEYCapturingPointStruct +{ + BattleGroundEYCapturingPointStruct(uint32 _DespawnNeutralObjectType, uint32 _SpawnObjectTypeAlliance, uint32 _MessageIdAlliance, uint32 _SpawnObjectTypeHorde, uint32 _MessageIdHorde, uint32 _GraveYardId) + : DespawnNeutralObjectType(_DespawnNeutralObjectType), + SpawnObjectTypeAlliance(_SpawnObjectTypeAlliance), MessageIdAlliance(_MessageIdAlliance), + SpawnObjectTypeHorde(_SpawnObjectTypeHorde), MessageIdHorde(_MessageIdHorde), + GraveYardId(_GraveYardId) + {} + + uint32 DespawnNeutralObjectType; + uint32 SpawnObjectTypeAlliance; + uint32 MessageIdAlliance; + uint32 SpawnObjectTypeHorde; + uint32 MessageIdHorde; + uint32 GraveYardId; +}; + +const uint8 BG_EY_TickPoints[EY_POINTS_MAX] = {1, 2, 5, 10}; +const uint32 BG_EY_FlagPoints[EY_POINTS_MAX] = {75, 85, 100, 500}; + +//constant arrays: +const BattleGroundEYPointIconsStruct m_PointsIconStruct[EY_POINTS_MAX] = +{ + BattleGroundEYPointIconsStruct(FEL_REAVER_UNCONTROL, FEL_REAVER_ALLIANCE_CONTROL, FEL_REAVER_HORDE_CONTROL), + BattleGroundEYPointIconsStruct(BLOOD_ELF_UNCONTROL, BLOOD_ELF_ALLIANCE_CONTROL, BLOOD_ELF_HORDE_CONTROL), + BattleGroundEYPointIconsStruct(DRAENEI_RUINS_UNCONTROL, DRAENEI_RUINS_ALLIANCE_CONTROL, DRAENEI_RUINS_HORDE_CONTROL), + BattleGroundEYPointIconsStruct(MAGE_TOWER_UNCONTROL, MAGE_TOWER_ALLIANCE_CONTROL, MAGE_TOWER_HORDE_CONTROL) +}; +const BattleGroundEYLoosingPointStruct m_LoosingPointTypes[EY_POINTS_MAX] = +{ + BattleGroundEYLoosingPointStruct(BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER, BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER, LANG_BG_EY_HAS_LOST_A_F_RUINS, BG_EY_OBJECT_H_BANNER_FEL_REALVER_CENTER, LANG_BG_EY_HAS_LOST_H_F_RUINS), + BattleGroundEYLoosingPointStruct(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_LOST_A_B_TOWER, BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_LOST_H_B_TOWER), + BattleGroundEYLoosingPointStruct(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_LOST_A_D_RUINS, BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_LOST_H_D_RUINS), + BattleGroundEYLoosingPointStruct(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_LOST_A_M_TOWER, BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_LOST_H_M_TOWER) +}; +const BattleGroundEYCapturingPointStruct m_CapturingPointTypes[EY_POINTS_MAX] = +{ + BattleGroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER, BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER, LANG_BG_EY_HAS_TAKEN_A_F_RUINS, BG_EY_OBJECT_H_BANNER_FEL_REALVER_CENTER, LANG_BG_EY_HAS_TAKEN_H_F_RUINS, EY_GRAVEYARD_FEL_REALVER), + BattleGroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_TAKEN_A_B_TOWER, BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_TAKEN_H_B_TOWER, EY_GRAVEYARD_BLOOD_ELF), + BattleGroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_TAKEN_A_D_RUINS, BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_TAKEN_H_D_RUINS, EY_GRAVEYARD_DRAENEI_RUINS), + BattleGroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_TAKEN_A_M_TOWER, BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_TAKEN_H_M_TOWER, EY_GRAVEYARD_MAGE_TOWER) +}; + +class BattleGroundEYScore : public BattleGroundScore +{ + public: + BattleGroundEYScore () : FlagCaptures(0) {}; + virtual ~BattleGroundEYScore() {}; + uint32 FlagCaptures; +}; + +class BattleGroundEY : public BattleGround +{ + friend class BattleGroundMgr; + + public: + BattleGroundEY(); + ~BattleGroundEY(); + void Update(uint32 diff); + + /* inherited from BattlegroundClass */ + virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + + /* BG Flags */ + uint64 GetFlagPickerGUID() const { return m_FlagKeeper; } + void SetFlagPicker(uint64 guid) { m_FlagKeeper = guid; } + bool IsFlagPickedup() const { return m_FlagKeeper != 0; } + uint8 GetFlagState() const { return m_FlagState; } + void RespawnFlag(bool send_message); + void RespawnFlagAfterDrop(); + + void RemovePlayer(Player *plr,uint64 guid); + void HandleBuffUse(uint64 const& buff_guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + void HandleKillPlayer(Player *player, Player *killer); + virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); + virtual bool SetupBattleGround(); + virtual void Reset(); + void UpdateTeamScore(uint32 Team); + void EndBattleGround(uint32 winner); + void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); + virtual void FillInitialWorldStates(WorldPacket& data); + void SetDroppedFlagGUID(uint64 guid) { m_DroppedFlagGUID = guid;} + uint64 GetDroppedFlagGUID() const { return m_DroppedFlagGUID;} + + /* Battleground Events */ + virtual void EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj); + virtual void EventPlayerDroppedFlag(Player *Source); + + /* achievement req. */ + bool IsAllNodesConrolledByTeam(uint32 team) const; + private: + void EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType); + void EventTeamCapturedPoint(Player *Source, uint32 Point); + void EventTeamLostPoint(Player *Source, uint32 Point); + void UpdatePointsCount(uint32 Team); + void UpdatePointsIcons(uint32 Team, uint32 Point); + + /* Point status updating procedures */ + void CheckSomeoneLeftPoint(); + void CheckSomeoneJoinedPoint(); + void UpdatePointStatuses(); + + /* Scorekeeping */ + uint32 GetTeamScore(uint32 Team) const { return m_TeamScores[GetTeamIndexByTeamId(Team)]; } + void AddPoints(uint32 Team, uint32 Points); + + void RemovePoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] -= Points; } + void SetTeamPoint(uint32 TeamID, uint32 Points = 0) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] = Points; } + + uint32 m_HonorScoreTics[2]; + uint32 m_TeamPointsCount[2]; + + uint32 m_Points_Trigger[EY_POINTS_MAX]; + + uint64 m_FlagKeeper; // keepers guid + uint64 m_DroppedFlagGUID; + uint32 m_FlagCapturedBgObjectType; // type that should be despawned when flag is captured + uint8 m_FlagState; // for checking flag state + int32 m_FlagsTimer; + int32 m_TowerCapCheckTimer; + + uint32 m_PointOwnedByTeam[EY_POINTS_MAX]; + uint8 m_PointState[EY_POINTS_MAX]; + int32 m_PointBarStatus[EY_POINTS_MAX]; + typedef std::vector PlayersNearPointType; + PlayersNearPointType m_PlayersNearPoint[EY_POINTS_MAX + 1]; + uint8 m_CurrentPointPlayersCount[2*EY_POINTS_MAX]; + + int32 m_PointAddingTimer; + uint32 m_HonorTics; +}; +#endif + diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundIC.cpp b/src/server/game/BattleGrounds/Zones/BattleGroundIC.cpp new file mode 100644 index 00000000000..8dbcc81e5c6 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundIC.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Player.h" +#include "BattleGround.h" +#include "BattleGroundIC.h" +#include "Language.h" + +BattleGroundIC::BattleGroundIC() +{ + m_BgCreatures.resize(2); + m_BgObjects.resize(5); + //TODO FIX ME! + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN; +} + +BattleGroundIC::~BattleGroundIC() +{ + +} + +void BattleGroundIC::Update(uint32 diff) +{ + BattleGround::Update(diff); +} + +void BattleGroundIC::StartingEventCloseDoors() +{ +} + +void BattleGroundIC::StartingEventOpenDoors() +{ +} + +void BattleGroundIC::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map, default values are set in constructor + BattleGroundICScore* sc = new BattleGroundICScore; + + m_PlayerScores[plr->GetGUID()] = sc; +} + +void BattleGroundIC::RemovePlayer(Player* /*plr*/,uint64 /*guid*/) +{ + +} + +void BattleGroundIC::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/) +{ + // this is wrong way to implement these things. On official it done by gameobject spell cast. + if (GetStatus() != STATUS_IN_PROGRESS) + return; +} + +void BattleGroundIC::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) +{ + + std::map::iterator itr = m_PlayerScores.find(Source->GetGUID()); + + if (itr == m_PlayerScores.end()) // player not found... + return; + + BattleGround::UpdatePlayerScore(Source,type,value, doAddHonor); +} + +bool BattleGroundIC::SetupBattleGround() +{ + AddObject(0, 195157, 459.72f, -419.93f, 42.55f, 0, 0, 0, 0.9996573f, 0.02617699f, 10*MINUTE); + AddObject(1, 195158, 797.72f, -1009.48f, 138.52f, 0, 0, 0, 0.9996573f, 0.02617699f, 10*MINUTE); + AddObject(2, 195338, 418.98f, -838.33f, 51.09f, 0, 0, 0, 0.9996573f, 0.02617699f, 10*MINUTE); + AddObject(3, 195343, 1267.45f, -390.88f, 24.23f, 0, 0, 0, 0.9996573f, 0.02617699f, 10*MINUTE); + AddObject(4, 195333, 769.27f, -833.53f, 9.57f, 0, 0, 0, 0.9996573f, 0.02617699f, 10*MINUTE); + SpawnLeader(ALLIANCE); + SpawnLeader(HORDE); + return true; +} + +void BattleGroundIC::SpawnLeader(uint32 teamid) +{ + if (teamid == ALLIANCE) + AddCreature(34924, 0, ALLIANCE, 307.03f, -833.04f, 48.91f, 6.23f, 10*MINUTE); + else + AddCreature(34922, 1, HORDE, 1264.42f, -766.80f, 48.91f, 3.28f, 10*MINUTE); +} + +void BattleGroundIC::HandleKillUnit(Creature *unit, Player * /*killer*/) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + uint32 entry = unit->GetEntry(); + if (entry == 34924) + { + RewardHonorToTeam(500,HORDE); + EndBattleGround(HORDE); + } + else if (entry == 34922) + { + RewardHonorToTeam(500,ALLIANCE); + EndBattleGround(ALLIANCE); + } +} + +void BattleGroundIC::EndBattleGround(uint32 winner) +{ + BattleGround::EndBattleGround(winner); +} + +void BattleGroundIC::EventPlayerClickedOnFlag(Player * /*source*/, GameObject* /*target_obj*/) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; +} diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundIC.h b/src/server/game/BattleGrounds/Zones/BattleGroundIC.h new file mode 100644 index 00000000000..e49ea01e850 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundIC.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __BATTLEGROUNDIC_H +#define __BATTLEGROUNDIC_H + +class BattleGround; + +enum Buffs +{ + OIL_REFINERY = 68719, + QUARRY = 68720 +}; + +class BattleGroundICScore : public BattleGroundScore +{ + public: + BattleGroundICScore() {}; + virtual ~BattleGroundICScore() {}; +}; + +class BattleGroundIC : public BattleGround +{ + friend class BattleGroundMgr; + + public: + BattleGroundIC(); + ~BattleGroundIC(); + void Update(uint32 diff); + + /* inherited from BattlegroundClass */ + virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + + void RemovePlayer(Player *plr,uint64 guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + bool SetupBattleGround(); + void SpawnLeader(uint32 teamid); + void HandleKillUnit(Creature *unit, Player *killer); + void EndBattleGround(uint32 winner); + void EventPlayerClickedOnFlag(Player *source, GameObject* /*target_obj*/); + + /* Scorekeeping */ + void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); + + private: +}; +#endif diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundNA.cpp b/src/server/game/BattleGrounds/Zones/BattleGroundNA.cpp new file mode 100644 index 00000000000..793cf13b3cb --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundNA.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "BattleGround.h" +#include "BattleGroundNA.h" +#include "Language.h" +#include "Object.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "WorldPacket.h" + +BattleGroundNA::BattleGroundNA() +{ + m_BgObjects.resize(BG_NA_OBJECT_MAX); + + m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; + m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; + m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; + m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; + //we must set messageIds + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; +} + +BattleGroundNA::~BattleGroundNA() +{ + +} + +void BattleGroundNA::Update(uint32 diff) +{ + BattleGround::Update(diff); + + /*if (GetStatus() == STATUS_IN_PROGRESS) + { + // update something + }*/ +} + +void BattleGroundNA::StartingEventCloseDoors() +{ + for (uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_4; ++i) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); +} + +void BattleGroundNA::StartingEventOpenDoors() +{ + for (uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_2; ++i) + DoorOpen(i); + + for (uint32 i = BG_NA_OBJECT_BUFF_1; i <= BG_NA_OBJECT_BUFF_2; ++i) + SpawnBGObject(i, 60); +} + +void BattleGroundNA::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map, default values are set in constructor + BattleGroundNAScore* sc = new BattleGroundNAScore; + + m_PlayerScores[plr->GetGUID()] = sc; + + UpdateArenaWorldState(); +} + +void BattleGroundNA::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) +{ + if (GetStatus() == STATUS_WAIT_LEAVE) + return; + + UpdateArenaWorldState(); + CheckArenaWinConditions(); +} + +void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + if (!killer) + { + sLog.outError("BattleGroundNA: Killer player not found"); + return; + } + + BattleGround::HandleKillPlayer(player,killer); + + UpdateArenaWorldState(); + CheckArenaWinConditions(); +} + +bool BattleGroundNA::HandlePlayerUnderMap(Player *player) +{ + player->TeleportTo(GetMapId(),4055.504395,2919.660645,13.611241,player->GetOrientation(),false); + return true; +} + +void BattleGroundNA::HandleAreaTrigger(Player *Source, uint32 Trigger) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + //uint32 SpellId = 0; + //uint64 buff_guid = 0; + switch(Trigger) + { + case 4536: // buff trigger? + case 4537: // buff trigger? + break; + default: + sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); + Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); + break; + } + + //if (buff_guid) + // HandleTriggerBuff(buff_guid,Source); +} + +void BattleGroundNA::FillInitialWorldStates(WorldPacket &data) +{ + data << uint32(0xa11) << uint32(1); // 9 + UpdateArenaWorldState(); +} + +void BattleGroundNA::Reset() +{ + //call parent's class reset + BattleGround::Reset(); +} + +bool BattleGroundNA::SetupBattleGround() +{ + // gates + if (!AddObject(BG_NA_OBJECT_DOOR_1, BG_NA_OBJECT_TYPE_DOOR_1, 4031.854, 2966.833, 12.6462, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY) + || !AddObject(BG_NA_OBJECT_DOOR_2, BG_NA_OBJECT_TYPE_DOOR_2, 4081.179, 2874.97, 12.39171, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY) + || !AddObject(BG_NA_OBJECT_DOOR_3, BG_NA_OBJECT_TYPE_DOOR_3, 4023.709, 2981.777, 10.70117, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY) + || !AddObject(BG_NA_OBJECT_DOOR_4, BG_NA_OBJECT_TYPE_DOOR_4, 4090.064, 2858.438, 10.23631, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY) + // buffs + || !AddObject(BG_NA_OBJECT_BUFF_1, BG_NA_OBJECT_TYPE_BUFF_1, 4009.189941, 2895.250000, 13.052700, -1.448624, 0, 0, 0.6626201, -0.7489557, 120) + || !AddObject(BG_NA_OBJECT_BUFF_2, BG_NA_OBJECT_TYPE_BUFF_2, 4103.330078, 2946.350098, 13.051300, -0.06981307, 0, 0, 0.03489945, -0.9993908, 120)) + { + sLog.outErrorDb("BatteGroundNA: Failed to spawn some object!"); + return false; + } + + return true; +} + +/* +20:12:14 id:036668 [S2C] SMSG_INIT_WORLD_STATES (706 = 0x02C2) len: 86 +0000: 2f 02 00 00 72 0e 00 00 00 00 00 00 09 00 11 0a | /...r........... +0010: 00 00 01 00 00 00 0f 0a 00 00 00 00 00 00 10 0a | ................ +0020: 00 00 00 00 00 00 d4 08 00 00 00 00 00 00 d8 08 | ................ +0030: 00 00 00 00 00 00 d7 08 00 00 00 00 00 00 d6 08 | ................ +0040: 00 00 00 00 00 00 d5 08 00 00 00 00 00 00 d3 08 | ................ +0050: 00 00 00 00 00 00 | ...... +*/ diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundNA.h b/src/server/game/BattleGrounds/Zones/BattleGroundNA.h new file mode 100644 index 00000000000..a11d311515d --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundNA.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __BATTLEGROUNDNA_H +#define __BATTLEGROUNDNA_H + +class BattleGround; + +enum BattleGroundNAObjectTypes +{ + BG_NA_OBJECT_DOOR_1 = 0, + BG_NA_OBJECT_DOOR_2 = 1, + BG_NA_OBJECT_DOOR_3 = 2, + BG_NA_OBJECT_DOOR_4 = 3, + BG_NA_OBJECT_BUFF_1 = 4, + BG_NA_OBJECT_BUFF_2 = 5, + BG_NA_OBJECT_MAX = 6 +}; + +enum BattleGroundNAObjects +{ + BG_NA_OBJECT_TYPE_DOOR_1 = 183978, + BG_NA_OBJECT_TYPE_DOOR_2 = 183980, + BG_NA_OBJECT_TYPE_DOOR_3 = 183977, + BG_NA_OBJECT_TYPE_DOOR_4 = 183979, + BG_NA_OBJECT_TYPE_BUFF_1 = 184663, + BG_NA_OBJECT_TYPE_BUFF_2 = 184664 +}; + +class BattleGroundNAScore : public BattleGroundScore +{ + public: + BattleGroundNAScore() {}; + virtual ~BattleGroundNAScore() {}; + //TODO fix me +}; + +class BattleGroundNA : public BattleGround +{ + friend class BattleGroundMgr; + + public: + BattleGroundNA(); + ~BattleGroundNA(); + void Update(uint32 diff); + + /* inherited from BattlegroundClass */ + virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + + void RemovePlayer(Player *plr, uint64 guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + bool SetupBattleGround(); + virtual void Reset(); + virtual void FillInitialWorldStates(WorldPacket &d); + void HandleKillPlayer(Player* player, Player *killer); + bool HandlePlayerUnderMap(Player * plr); +}; +#endif diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundRB.cpp b/src/server/game/BattleGrounds/Zones/BattleGroundRB.cpp new file mode 100644 index 00000000000..cf22154ed11 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundRB.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Player.h" +#include "BattleGround.h" +#include "BattleGroundRB.h" +#include "Language.h" + +BattleGroundRB::BattleGroundRB() +{ + //TODO FIX ME! + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = 0; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN; +} + +BattleGroundRB::~BattleGroundRB() +{ + +} + +void BattleGroundRB::Update(uint32 diff) +{ + BattleGround::Update(diff); +} + +void BattleGroundRB::StartingEventCloseDoors() +{ +} + +void BattleGroundRB::StartingEventOpenDoors() +{ +} + +void BattleGroundRB::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map, default values are set in constructor + BattleGroundRBScore* sc = new BattleGroundRBScore; + + m_PlayerScores[plr->GetGUID()] = sc; +} + +void BattleGroundRB::RemovePlayer(Player* /*plr*/,uint64 /*guid*/) +{ +} + +void BattleGroundRB::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/) +{ + // this is wrong way to implement these things. On official it done by gameobject spell cast. + if (GetStatus() != STATUS_IN_PROGRESS) + return; +} + +void BattleGroundRB::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) +{ + std::map::iterator itr = m_PlayerScores.find(Source->GetGUID()); + + if (itr == m_PlayerScores.end()) // player not found... + return; + + BattleGround::UpdatePlayerScore(Source,type,value, doAddHonor); +} diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundRB.h b/src/server/game/BattleGrounds/Zones/BattleGroundRB.h new file mode 100644 index 00000000000..a40ade5adfe --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundRB.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __BATTLEGROUNDRB_H +#define __BATTLEGROUNDRB_H + +class BattleGround; + +class BattleGroundRBScore : public BattleGroundScore +{ + public: + BattleGroundRBScore() {}; + virtual ~BattleGroundRBScore() {}; +}; + +class BattleGroundRB : public BattleGround +{ + friend class BattleGroundMgr; + + public: + BattleGroundRB(); + ~BattleGroundRB(); + void Update(uint32 diff); + + virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + + void RemovePlayer(Player *plr,uint64 guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + + /* Scorekeeping */ + void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); + + private: +}; +#endif diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundRL.cpp b/src/server/game/BattleGrounds/Zones/BattleGroundRL.cpp new file mode 100644 index 00000000000..ef2ec3cfa94 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundRL.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "BattleGround.h" +#include "BattleGroundRL.h" +#include "Language.h" +#include "Object.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "WorldPacket.h" + +BattleGroundRL::BattleGroundRL() +{ + m_BgObjects.resize(BG_RL_OBJECT_MAX); + + m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; + m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; + m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; + m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; + //we must set messageIds + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; +} + +BattleGroundRL::~BattleGroundRL() +{ + +} + +void BattleGroundRL::Update(uint32 diff) +{ + BattleGround::Update(diff); + + /*if (GetStatus() == STATUS_IN_PROGRESS) + { + // update something + }*/ +} + +void BattleGroundRL::StartingEventCloseDoors() +{ + for (uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; ++i) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); +} + +void BattleGroundRL::StartingEventOpenDoors() +{ + for (uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; ++i) + DoorOpen(i); + + for (uint32 i = BG_RL_OBJECT_BUFF_1; i <= BG_RL_OBJECT_BUFF_2; ++i) + SpawnBGObject(i, 60); +} + +void BattleGroundRL::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map, default values are set in constructor + BattleGroundRLScore* sc = new BattleGroundRLScore; + + m_PlayerScores[plr->GetGUID()] = sc; + + UpdateArenaWorldState(); +} + +void BattleGroundRL::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) +{ + if (GetStatus() == STATUS_WAIT_LEAVE) + return; + + UpdateArenaWorldState(); + CheckArenaWinConditions(); +} + +void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + if (!killer) + { + sLog.outError("Killer player not found"); + return; + } + + BattleGround::HandleKillPlayer(player,killer); + + UpdateArenaWorldState(); + CheckArenaWinConditions(); +} + +bool BattleGroundRL::HandlePlayerUnderMap(Player *player) +{ + player->TeleportTo(GetMapId(),1285.810547,1667.896851,39.957642,player->GetOrientation(),false); + return true; +} + +void BattleGroundRL::HandleAreaTrigger(Player *Source, uint32 Trigger) +{ + // this is wrong way to implement these things. On official it done by gameobject spell cast. + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + //uint32 SpellId = 0; + //uint64 buff_guid = 0; + switch(Trigger) + { + case 4696: // buff trigger? + case 4697: // buff trigger? + break; + default: + sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); + Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); + break; + } + + //if (buff_guid) + // HandleTriggerBuff(buff_guid,Source); +} + +void BattleGroundRL::FillInitialWorldStates(WorldPacket &data) +{ + data << uint32(0xbba) << uint32(1); // 9 + UpdateArenaWorldState(); +} + +void BattleGroundRL::Reset() +{ + //call parent's reset + BattleGround::Reset(); +} + +bool BattleGroundRL::SetupBattleGround() +{ + // gates + if (!AddObject(BG_RL_OBJECT_DOOR_1, BG_RL_OBJECT_TYPE_DOOR_1, 1293.561, 1601.938, 31.60557, -1.457349, 0, 0, -0.6658813, 0.7460576, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RL_OBJECT_DOOR_2, BG_RL_OBJECT_TYPE_DOOR_2, 1278.648, 1730.557, 31.60557, 1.684245, 0, 0, 0.7460582, 0.6658807, RESPAWN_IMMEDIATELY) + // buffs + || !AddObject(BG_RL_OBJECT_BUFF_1, BG_RL_OBJECT_TYPE_BUFF_1, 1328.719971, 1632.719971, 36.730400, -1.448624, 0, 0, 0.6626201, -0.7489557, 120) + || !AddObject(BG_RL_OBJECT_BUFF_2, BG_RL_OBJECT_TYPE_BUFF_2, 1243.300049, 1699.170044, 34.872601, -0.06981307, 0, 0, 0.03489945, -0.9993908, 120)) + { + sLog.outErrorDb("BatteGroundRL: Failed to spawn some object!"); + return false; + } + + return true; +} + +/* +Packet S->C, id 600, SMSG_INIT_WORLD_STATES (706), len 86 +0000: 3C 02 00 00 80 0F 00 00 00 00 00 00 09 00 BA 0B | <............... +0010: 00 00 01 00 00 00 B9 0B 00 00 02 00 00 00 B8 0B | ................ +0020: 00 00 00 00 00 00 D8 08 00 00 00 00 00 00 D7 08 | ................ +0030: 00 00 00 00 00 00 D6 08 00 00 00 00 00 00 D5 08 | ................ +0040: 00 00 00 00 00 00 D3 08 00 00 00 00 00 00 D4 08 | ................ +0050: 00 00 00 00 00 00 | ...... +*/ diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundRL.h b/src/server/game/BattleGrounds/Zones/BattleGroundRL.h new file mode 100644 index 00000000000..3b4c10a7c9a --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundRL.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __BATTLEGROUNDRL_H +#define __BATTLEGROUNDRL_H + +class BattleGround; + +enum BattleGroundRLObjectTypes +{ + BG_RL_OBJECT_DOOR_1 = 0, + BG_RL_OBJECT_DOOR_2 = 1, + BG_RL_OBJECT_BUFF_1 = 2, + BG_RL_OBJECT_BUFF_2 = 3, + BG_RL_OBJECT_MAX = 4 +}; + +enum BattleGroundRLObjects +{ + BG_RL_OBJECT_TYPE_DOOR_1 = 185918, + BG_RL_OBJECT_TYPE_DOOR_2 = 185917, + BG_RL_OBJECT_TYPE_BUFF_1 = 184663, + BG_RL_OBJECT_TYPE_BUFF_2 = 184664 +}; + +class BattleGroundRLScore : public BattleGroundScore +{ + public: + BattleGroundRLScore() {}; + virtual ~BattleGroundRLScore() {}; + //TODO fix me +}; + +class BattleGroundRL : public BattleGround +{ + friend class BattleGroundMgr; + + public: + BattleGroundRL(); + ~BattleGroundRL(); + void Update(uint32 diff); + + /* inherited from BattlegroundClass */ + virtual void AddPlayer(Player *plr); + virtual void Reset(); + virtual void FillInitialWorldStates(WorldPacket &d); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + + void RemovePlayer(Player *plr, uint64 guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + bool SetupBattleGround(); + void HandleKillPlayer(Player* player, Player *killer); + bool HandlePlayerUnderMap(Player * plr); +}; +#endif diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundRV.cpp b/src/server/game/BattleGrounds/Zones/BattleGroundRV.cpp new file mode 100644 index 00000000000..fcc53dbbcf9 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundRV.cpp @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "BattleGround.h" +#include "BattleGroundRV.h" +#include "ObjectAccessor.h" +#include "Language.h" +#include "Player.h" +#include "WorldPacket.h" +#include "GameObject.h" + +BattleGroundRV::BattleGroundRV() +{ + m_BgObjects.resize(BG_RV_OBJECT_MAX); + + m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; + m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; + m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; + m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; + //we must set messageIds + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; +} + +BattleGroundRV::~BattleGroundRV() +{ + +} + +void BattleGroundRV::Update(uint32 diff) +{ + BattleGround::Update(diff); + + if (getTimer() < diff) + { + uint32 i; + switch(getState()) + { + case BG_RV_STATE_OPEN_FENCES: + { + setTimer(BG_RV_PILAR_TO_FIRE_TIMER); + setState(BG_RV_STATE_CLOSE_FIRE); + break; + } + case BG_RV_STATE_CLOSE_FIRE: + for (i = BG_RV_OBJECT_FIRE_1; i <= BG_RV_OBJECT_FIREDOOR_2; ++i) + DoorClose(i); + setTimer(BG_RV_FIRE_TO_PILAR_TIMER); + setState(BG_RV_STATE_OPEN_PILARS); + break; + case BG_RV_STATE_OPEN_PILARS: + for (i = BG_RV_OBJECT_PILAR_1; i <= BG_RV_OBJECT_PULLEY_2; ++i) + DoorOpen(i); + setTimer(BG_RV_PILAR_TO_FIRE_TIMER); + setState(BG_RV_STATE_OPEN_FIRE); + break; + case BG_RV_STATE_OPEN_FIRE: + for (i = BG_RV_OBJECT_FIRE_1; i <= BG_RV_OBJECT_FIREDOOR_2; ++i) + DoorOpen(i); + setTimer(BG_RV_FIRE_TO_PILAR_TIMER); + setState(BG_RV_STATE_CLOSE_PILARS); + break; + case BG_RV_STATE_CLOSE_PILARS: + uint32 i; + for (i = BG_RV_OBJECT_PILAR_1; i <= BG_RV_OBJECT_PULLEY_2; ++i) + DoorOpen(i); + setTimer(BG_RV_PILAR_TO_FIRE_TIMER); + setState(BG_RV_STATE_CLOSE_FIRE); + break; + } + } + else + setTimer(getTimer() - diff); +} + +void BattleGroundRV::StartingEventCloseDoors() +{ +} + +void BattleGroundRV::StartingEventOpenDoors() +{ + // Buff respawn + SpawnBGObject(BG_RV_OBJECT_BUFF_1, 90); + SpawnBGObject(BG_RV_OBJECT_BUFF_2, 90); + // Open fences + DoorOpen(BG_RV_OBJECT_FENCE_1); + DoorOpen(BG_RV_OBJECT_FENCE_2); + // Elevators + DoorOpen(BG_RV_OBJECT_ELEVATOR_1); + DoorOpen(BG_RV_OBJECT_ELEVATOR_2); + + setState(BG_RV_STATE_OPEN_FENCES); + setTimer(BG_RV_FIRST_TIMER); +} + +void BattleGroundRV::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map, default values are set in constructor + BattleGroundRVScore* sc = new BattleGroundRVScore; + + m_PlayerScores[plr->GetGUID()] = sc; + + UpdateWorldState(BG_RV_WORLD_STATE_A, GetAlivePlayersCountByTeam(ALLIANCE)); + UpdateWorldState(BG_RV_WORLD_STATE_H, GetAlivePlayersCountByTeam(HORDE)); +} + +void BattleGroundRV::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) +{ + if (GetStatus() == STATUS_WAIT_LEAVE) + return; + + UpdateWorldState(BG_RV_WORLD_STATE_A, GetAlivePlayersCountByTeam(ALLIANCE)); + UpdateWorldState(BG_RV_WORLD_STATE_H, GetAlivePlayersCountByTeam(HORDE)); + + CheckArenaWinConditions(); +} + +void BattleGroundRV::HandleKillPlayer(Player *player, Player *killer) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + if (!killer) + { + sLog.outError("BattleGroundRV: Killer player not found"); + return; + } + + BattleGround::HandleKillPlayer(player, killer); + + UpdateWorldState(BG_RV_WORLD_STATE_A, GetAlivePlayersCountByTeam(ALLIANCE)); + UpdateWorldState(BG_RV_WORLD_STATE_H, GetAlivePlayersCountByTeam(HORDE)); + + CheckArenaWinConditions(); +} + +bool BattleGroundRV::HandlePlayerUnderMap(Player *player) +{ + player->TeleportTo(GetMapId(), 763.5, -284, 28.276, 2.422, false); + return true; +} + + +void BattleGroundRV::HandleAreaTrigger(Player *Source, uint32 Trigger) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + switch(Trigger) + { + case 5224: + case 5226: + break; + default: + sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); + Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); + break; + } +} + +void BattleGroundRV::FillInitialWorldStates(WorldPacket &data) +{ + data << uint32(BG_RV_WORLD_STATE_A) << uint32(GetAlivePlayersCountByTeam(ALLIANCE)); + data << uint32(BG_RV_WORLD_STATE_H) << uint32(GetAlivePlayersCountByTeam(HORDE)); + data << uint32(BG_RV_WORLD_STATE) << uint32(1); +} + +void BattleGroundRV::Reset() +{ + //call parent's class reset + BattleGround::Reset(); +} + +bool BattleGroundRV::SetupBattleGround() +{ + // Fence + if (!AddObject(BG_RV_OBJECT_FENCE_1, BG_RV_OBJECT_TYPE_FENCE_1, 763.432373, -274.058197, 28.276695, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RV_OBJECT_FENCE_2, BG_RV_OBJECT_TYPE_FENCE_2, 763.432373, -294.419464, 28.276684, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) + // elevators + || !AddObject(BG_RV_OBJECT_ELEVATOR_1, BG_RV_OBJECT_TYPE_ELEVATOR_1, 763.536377, -294.535767, 0.505383, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RV_OBJECT_ELEVATOR_2, BG_RV_OBJECT_TYPE_ELEVATOR_2, 763.506348, -273.873352, 0.505383, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) + // buffs + || !AddObject(BG_RV_OBJECT_BUFF_1, BG_RV_OBJECT_TYPE_BUFF_1, 735.551819, -284.794678, 28.276682, 0.034906, 0, 0, 0, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RV_OBJECT_BUFF_2, BG_RV_OBJECT_TYPE_BUFF_2, 791.224487, -284.794464, 28.276682, 2.600535, 0, 0, 0, RESPAWN_IMMEDIATELY) + // fire + || !AddObject(BG_RV_OBJECT_FIRE_1, BG_RV_OBJECT_TYPE_FIRE_1, 743.543457, -283.799469, 28.286655, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RV_OBJECT_FIRE_2, BG_RV_OBJECT_TYPE_FIRE_2, 782.971802, -283.799469, 28.286655, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RV_OBJECT_FIREDOOR_1, BG_RV_OBJECT_TYPE_FIREDOOR_1, 743.711060, -284.099609, 27.542587, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RV_OBJECT_FIREDOOR_2, BG_RV_OBJECT_TYPE_FIREDOOR_2, 783.221252, -284.133362, 27.535686, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) + // Gear + || !AddObject(BG_RV_OBJECT_GEAR_1, BG_RV_OBJECT_TYPE_GEAR_1, 763.664551, -261.872986, 26.686588, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RV_OBJECT_GEAR_2, BG_RV_OBJECT_TYPE_GEAR_2, 763.578979, -306.146149, 26.665222, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) + // Pulley + || !AddObject(BG_RV_OBJECT_PULLEY_1, BG_RV_OBJECT_TYPE_PULLEY_1, 700.722290, -283.990662, 39.517582, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RV_OBJECT_PULLEY_2, BG_RV_OBJECT_TYPE_PULLEY_2, 826.303833, -283.996429, 39.517582, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) + // Pilars + || !AddObject(BG_RV_OBJECT_PILAR_1, BG_RV_OBJECT_TYPE_PILAR_1, 763.632385, -306.162384, 25.909504, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RV_OBJECT_PILAR_2, BG_RV_OBJECT_TYPE_PILAR_2, 723.644287, -284.493256, 24.648525, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RV_OBJECT_PILAR_3, BG_RV_OBJECT_TYPE_PILAR_3, 763.611145, -261.856750, 25.909504, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RV_OBJECT_PILAR_4, BG_RV_OBJECT_TYPE_PILAR_4, 802.211609, -284.493256, 24.648525, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) +/* + // Pilars Collision - Fixme: Use the collision pilars - should make u break LoS + || !AddObject(BG_RV_OBJECT_PILAR_COLLISION_1, BG_RV_OBJECT_TYPE_PILAR_COLLISION_1, 763.632385, -306.162384, 30.639660, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RV_OBJECT_PILAR_COLLISION_2, BG_RV_OBJECT_TYPE_PILAR_COLLISION_2, 723.644287, -284.493256, 32.382710, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RV_OBJECT_PILAR_COLLISION_3, BG_RV_OBJECT_TYPE_PILAR_COLLISION_3, 763.611145, -261.856750, 30.639660, 0.000000, 0, 0, 0, RESPAWN_IMMEDIATELY) + || !AddObject(BG_RV_OBJECT_PILAR_COLLISION_4, BG_RV_OBJECT_TYPE_PILAR_COLLISION_4, 802.211609, -284.493256, 32.382710, 3.141593, 0, 0, 0, RESPAWN_IMMEDIATELY) +*/ +) + { + sLog.outErrorDb("BatteGroundRV: Failed to spawn some object!"); + return false; + } + return true; +} diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundRV.h b/src/server/game/BattleGrounds/Zones/BattleGroundRV.h new file mode 100644 index 00000000000..bf06478d364 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundRV.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __BATTLEGROUNDRV_H +#define __BATTLEGROUNDRV_H + +class BattleGround; + +enum BattleGroundRVObjectTypes +{ + BG_RV_OBJECT_BUFF_1, + BG_RV_OBJECT_BUFF_2, + BG_RV_OBJECT_FIRE_1, + BG_RV_OBJECT_FIRE_2, + BG_RV_OBJECT_FIREDOOR_1, + BG_RV_OBJECT_FIREDOOR_2, + + BG_RV_OBJECT_PILAR_1, + BG_RV_OBJECT_PILAR_3, + BG_RV_OBJECT_GEAR_1, + BG_RV_OBJECT_GEAR_2, + + BG_RV_OBJECT_PILAR_2, + BG_RV_OBJECT_PILAR_4, + BG_RV_OBJECT_PULLEY_1, + BG_RV_OBJECT_PULLEY_2, +/* + BG_RV_OBJECT_PILAR_COLLISION_1, + BG_RV_OBJECT_PILAR_COLLISION_2, + BG_RV_OBJECT_PILAR_COLLISION_3, + BG_RV_OBJECT_PILAR_COLLISION_4, +*/ + BG_RV_OBJECT_ELEVATOR_1, + BG_RV_OBJECT_ELEVATOR_2, + BG_RV_OBJECT_FENCE_1, + BG_RV_OBJECT_FENCE_2, + BG_RV_OBJECT_MAX, +}; + +enum BattleGroundRVObjects +{ + BG_RV_OBJECT_TYPE_BUFF_1 = 184663, + BG_RV_OBJECT_TYPE_BUFF_2 = 184664, + BG_RV_OBJECT_TYPE_FIRE_1 = 192704, + BG_RV_OBJECT_TYPE_FIRE_2 = 192705, + + BG_RV_OBJECT_TYPE_FIREDOOR_2 = 192387, + BG_RV_OBJECT_TYPE_FIREDOOR_1 = 192388, + BG_RV_OBJECT_TYPE_PULLEY_1 = 192389, + BG_RV_OBJECT_TYPE_PULLEY_2 = 192390, + BG_RV_OBJECT_TYPE_FENCE_1 = 192391, + BG_RV_OBJECT_TYPE_FENCE_2 = 192392, + BG_RV_OBJECT_TYPE_GEAR_1 = 192393, + BG_RV_OBJECT_TYPE_GEAR_2 = 192394, + BG_RV_OBJECT_TYPE_ELEVATOR_1 = 194582, + BG_RV_OBJECT_TYPE_ELEVATOR_2 = 194586, +/* + BG_RV_OBJECT_TYPE_PILAR_COLLISION_1 = 194580, // axe + BG_RV_OBJECT_TYPE_PILAR_COLLISION_2 = 194579, // arena + BG_RV_OBJECT_TYPE_PILAR_COLLISION_3 = 194581, // lightning + BG_RV_OBJECT_TYPE_PILAR_COLLISION_4 = 194578, // ivory +*/ + BG_RV_OBJECT_TYPE_PILAR_1 = 194583, // axe + BG_RV_OBJECT_TYPE_PILAR_2 = 194584, // arena + BG_RV_OBJECT_TYPE_PILAR_3 = 194585, // lightning + BG_RV_OBJECT_TYPE_PILAR_4 = 194587, // ivory +}; + +enum BattleGroundRVData +{ + BG_RV_STATE_OPEN_FENCES, + BG_RV_STATE_OPEN_PILARS, + BG_RV_STATE_CLOSE_PILARS, + BG_RV_STATE_OPEN_FIRE, + BG_RV_STATE_CLOSE_FIRE, + BG_RV_FIRE_TO_PILAR_TIMER = 20000, + BG_RV_PILAR_TO_FIRE_TIMER = 5000, + BG_RV_FIRST_TIMER = 20133, + BG_RV_WORLD_STATE_A = 0xe10, + BG_RV_WORLD_STATE_H = 0xe11, + BG_RV_WORLD_STATE = 0xe1a, +}; + +class BattleGroundRVScore : public BattleGroundScore +{ + public: + BattleGroundRVScore() {}; + virtual ~BattleGroundRVScore() {}; +}; + +class BattleGroundRV : public BattleGround +{ + friend class BattleGroundMgr; + + public: + BattleGroundRV(); + ~BattleGroundRV(); + void Update(uint32 diff); + + /* inherited from BattlegroundClass */ + virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + virtual void Reset(); + virtual void FillInitialWorldStates(WorldPacket &d); + + void RemovePlayer(Player *plr, uint64 guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + bool SetupBattleGround(); + void HandleKillPlayer(Player* player, Player *killer); + bool HandlePlayerUnderMap(Player * plr); + + private: + uint32 Timer; + uint32 State; + + protected: + uint32 getTimer() { return Timer; }; + void setTimer(uint32 timer) { Timer = timer; }; + + uint32 getState() { return State; }; + void setState(uint32 state) { State = state; }; +}; +#endif diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundSA.cpp b/src/server/game/BattleGrounds/Zones/BattleGroundSA.cpp new file mode 100644 index 00000000000..ccde43ce948 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundSA.cpp @@ -0,0 +1,822 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "BattleGround.h" +#include "BattleGroundSA.h" +#include "Language.h" +#include "Player.h" +#include "GameObject.h" +#include "ObjectMgr.h" +#include "WorldPacket.h" + + +BattleGroundSA::BattleGroundSA() +{ + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_SA_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_SA_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_SA_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_SA_HAS_BEGUN; + m_BgObjects.resize(BG_SA_MAXOBJ); + m_BgCreatures.resize(BG_SA_MAXNPC + BG_SA_MAX_GY); + TimerEnabled = false; + UpdateWaitTimer = 0; + SignaledRoundTwo = false; + SignaledRoundTwoHalfMin = false; + InitSecondRound = false; +} + +BattleGroundSA::~BattleGroundSA() +{ +} + +void BattleGroundSA::Reset() +{ + TotalTime = 0; + attackers = ((urand(0,1)) ? TEAM_ALLIANCE : TEAM_HORDE); + for (uint8 i = 0; i <= 5; i++) + GateStatus[i] = BG_SA_GATE_OK; + ShipsStarted = false; + status = BG_SA_WARMUP; +} + +bool BattleGroundSA::SetupBattleGround() +{ + return ResetObjs(); +} + +bool BattleGroundSA::ResetObjs() +{ + uint32 atF = BG_SA_Factions[attackers]; + uint32 defF = BG_SA_Factions[attackers ? TEAM_ALLIANCE : TEAM_HORDE]; + + + for (uint8 i = 0; i SetUInt32Value(GAMEOBJECT_FACTION, defF); + } + + GetBGObject(BG_SA_TITAN_RELIC)->SetUInt32Value(GAMEOBJECT_FACTION, atF); + GetBGObject(BG_SA_TITAN_RELIC)->Refresh(); + + for (uint8 i = 0; i <= 5; i++) + GateStatus[i] = BG_SA_GATE_OK; + + // MAD props for Kiper for discovering those values - 4 hours of his work. + GetBGObject(BG_SA_BOAT_ONE)->UpdateRotationFields(1.0f, 0.0002f); + GetBGObject(BG_SA_BOAT_TWO)->UpdateRotationFields(1.0f, 0.00001f); + SpawnBGObject(BG_SA_BOAT_ONE, RESPAWN_IMMEDIATELY); + SpawnBGObject(BG_SA_BOAT_TWO, RESPAWN_IMMEDIATELY); + + TotalTime = 0; + ShipsStarted = false; + + //Graveyards! + for (uint8 i = 0;i < BG_SA_MAX_GY; i++) + { + WorldSafeLocsEntry const *sg = NULL; + sg = sWorldSafeLocsStore.LookupEntry(BG_SA_GYEntries[i]); + + if (!sg) + { + sLog.outError("SOTA: Can't find GY entry %u",BG_SA_GYEntries[i]); + return false; + } + + if (i == BG_SA_BEACH_GY) + { + GraveyardStatus[i] = attackers; + AddSpiritGuide(i + BG_SA_MAXNPC, sg->x, sg->y, sg->z, BG_SA_GYOrientation[i], ((attackers == TEAM_HORDE)? HORDE : ALLIANCE)); + } + else + { + GraveyardStatus[i] = ((attackers == TEAM_HORDE)? TEAM_ALLIANCE : TEAM_HORDE); + if (!AddSpiritGuide(i + BG_SA_MAXNPC, sg->x, sg->y, sg->z, BG_SA_GYOrientation[i], ((attackers == TEAM_HORDE)? ALLIANCE : HORDE))) + sLog.outError("SOTA: couldn't spawn GY: %u",i); + } + } + + //GY capture points + for (uint8 i = BG_SA_CENTRAL_FLAG; i < BG_SA_MAXOBJ; i++) + { + AddObject(i, BG_SA_ObjEntries[(i + (attackers == TEAM_ALLIANCE ? 3:0))], + BG_SA_ObjSpawnlocs[i][0], BG_SA_ObjSpawnlocs[i][1], + BG_SA_ObjSpawnlocs[i][2], BG_SA_ObjSpawnlocs[i][3], + 0,0,0,0,RESPAWN_ONE_DAY); + GetBGObject(i)->SetUInt32Value(GAMEOBJECT_FACTION, atF); + } + + //Player may enter BEFORE we set up bG - lets update his worldstates anyway... + UpdateWorldState(BG_SA_RIGHT_GY_HORDE , GraveyardStatus[BG_SA_RIGHT_CAPTURABLE_GY] == TEAM_HORDE?1:0); + UpdateWorldState(BG_SA_LEFT_GY_HORDE , GraveyardStatus[BG_SA_LEFT_CAPTURABLE_GY] == TEAM_HORDE?1:0); + UpdateWorldState(BG_SA_CENTER_GY_HORDE , GraveyardStatus[BG_SA_CENTRAL_CAPTURABLE_GY] == TEAM_HORDE?1:0); + + UpdateWorldState(BG_SA_RIGHT_GY_ALLIANCE , GraveyardStatus[BG_SA_RIGHT_CAPTURABLE_GY] == TEAM_ALLIANCE?1:0); + UpdateWorldState(BG_SA_LEFT_GY_ALLIANCE , GraveyardStatus[BG_SA_LEFT_CAPTURABLE_GY] == TEAM_ALLIANCE?1:0); + UpdateWorldState(BG_SA_CENTER_GY_ALLIANCE , GraveyardStatus[BG_SA_CENTRAL_CAPTURABLE_GY] == TEAM_ALLIANCE?1:0); + + if (attackers == TEAM_ALLIANCE) + { + UpdateWorldState(BG_SA_ALLY_ATTACKS, 1); + UpdateWorldState(BG_SA_HORDE_ATTACKS, 0); + + UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_ALL, 1); + UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_ALL, 1); + UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_HRD, 0); + UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_HRD, 0); + + UpdateWorldState(BG_SA_HORDE_DEFENCE_TOKEN,1); + UpdateWorldState(BG_SA_ALLIANCE_DEFENCE_TOKEN,0); + } + else + { + UpdateWorldState(BG_SA_HORDE_ATTACKS, 1); + UpdateWorldState(BG_SA_ALLY_ATTACKS, 0); + + UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_ALL, 0); + UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_ALL, 0); + UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_HRD, 1); + UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_HRD, 1); + + UpdateWorldState(BG_SA_HORDE_DEFENCE_TOKEN,0); + UpdateWorldState(BG_SA_ALLIANCE_DEFENCE_TOKEN,1); + } + + UpdateWorldState(BG_SA_PURPLE_GATEWS, 1); + UpdateWorldState(BG_SA_RED_GATEWS, 1); + UpdateWorldState(BG_SA_BLUE_GATEWS, 1); + UpdateWorldState(BG_SA_GREEN_GATEWS, 1); + UpdateWorldState(BG_SA_YELLOW_GATEWS, 1); + UpdateWorldState(BG_SA_ANCIENT_GATEWS, 1); + + TeleportPlayers(); + return true; +} + +void BattleGroundSA::StartShips() +{ + if (ShipsStarted) + return; + + DoorOpen(BG_SA_BOAT_ONE); + DoorOpen(BG_SA_BOAT_TWO); + + for (int i = BG_SA_BOAT_ONE; i <= BG_SA_BOAT_TWO; i++) + { + for (BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end();itr++) + { + if (Player* p = objmgr.GetPlayer(itr->first)) + { + if (p->GetTeamId() != attackers) + continue; + + UpdateData data; + WorldPacket pkt; + GetBGObject(i)->BuildValuesUpdateBlockForPlayer(&data, p); + data.BuildPacket(&pkt); + p->GetSession()->SendPacket(&pkt); + } + } + } + ShipsStarted = true; +} + +void BattleGroundSA::Update(uint32 diff) +{ + if (InitSecondRound) + { + if (UpdateWaitTimer < diff) + { + if (!SignaledRoundTwo) + { + SignaledRoundTwo = true; + InitSecondRound = false; + SendMessageToAll(LANG_BG_SA_ROUND_TWO_ONE_MINUTE, CHAT_MSG_BG_SYSTEM_NEUTRAL); + } + }else + { + UpdateWaitTimer -= diff; + return; + } + } + BattleGround::Update(diff); + TotalTime += diff; + + if (status == BG_SA_WARMUP ) + { + BG_SA_ENDROUNDTIME = BG_SA_ROUNDLENGTH; + if (TotalTime >= BG_SA_WARMUPLENGTH) + { + TotalTime = 0; + ToggleTimer(); + DemolisherStartState(false); + status = BG_SA_ROUND_ONE; + } + if (TotalTime >= BG_SA_BOAT_START) + StartShips(); + return; + } + else if (status == BG_SA_SECOND_WARMUP) + { + if (RoundScores[0].time= 60000) + { + SendWarningToAll(LANG_BG_SA_HAS_BEGUN); + TotalTime = 0; + ToggleTimer(); + DemolisherStartState(false); + status = BG_SA_ROUND_TWO; + } + if (TotalTime >= 30000) + { + if (!SignaledRoundTwoHalfMin) + { + SignaledRoundTwoHalfMin = true; + SendMessageToAll(LANG_BG_SA_ROUND_TWO_START_HALF_MINUTE, CHAT_MSG_BG_SYSTEM_NEUTRAL); + } + } + StartShips(); + return; + } + else if (GetStatus() == STATUS_IN_PROGRESS) + { + if (status == BG_SA_ROUND_ONE) + { + if (TotalTime >= BG_SA_ROUNDLENGTH) + { + RoundScores[0].winner = attackers; + RoundScores[0].time = BG_SA_ROUNDLENGTH; + TotalTime = 0; + status = BG_SA_SECOND_WARMUP; + attackers = (attackers == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE; + status = BG_SA_SECOND_WARMUP; + ToggleTimer(); + ResetObjs(); + return; + } + } + else if (status == BG_SA_ROUND_TWO) + { + if (TotalTime >= BG_SA_ENDROUNDTIME) + { + RoundScores[1].time = BG_SA_ROUNDLENGTH; + RoundScores[1].winner = (attackers == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE; + + if (RoundScores[0].time == RoundScores[1].time) + EndBattleGround(NULL); + else if (RoundScores[0].time < RoundScores[1].time) + EndBattleGround(RoundScores[0].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE); + else + EndBattleGround(RoundScores[1].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE); + return; + } + } + if (status == BG_SA_ROUND_ONE || status == BG_SA_ROUND_TWO) + { + SendTime(); + UpdateDemolisherSpawns(); + } + } +} + +void BattleGroundSA::StartingEventCloseDoors() +{ +} + +void BattleGroundSA::StartingEventOpenDoors() +{ +} + +void BattleGroundSA::FillInitialWorldStates(WorldPacket& data) +{ + uint32 ally_attacks = uint32(attackers == TEAM_ALLIANCE ? 1 : 0); + uint32 horde_attacks = uint32(attackers == TEAM_HORDE ? 1 : 0); + + data << uint32(BG_SA_ANCIENT_GATEWS) << uint32(GateStatus[BG_SA_ANCIENT_GATE]); + data << uint32(BG_SA_YELLOW_GATEWS) << uint32(GateStatus[BG_SA_YELLOW_GATE]); + data << uint32(BG_SA_GREEN_GATEWS) << uint32(GateStatus[BG_SA_GREEN_GATE]); + data << uint32(BG_SA_BLUE_GATEWS) << uint32(GateStatus[BG_SA_BLUE_GATE]); + data << uint32(BG_SA_RED_GATEWS) << uint32(GateStatus[BG_SA_RED_GATE]); + data << uint32(BG_SA_PURPLE_GATEWS) << uint32(GateStatus[BG_SA_PURPLE_GATE]); + + data << uint32(BG_SA_BONUS_TIMER) << uint32(0); + + data << uint32(BG_SA_HORDE_ATTACKS)<< horde_attacks; + data << uint32(BG_SA_ALLY_ATTACKS) << ally_attacks; + + //Time will be sent on first update... + data << uint32(BG_SA_ENABLE_TIMER) << ((TimerEnabled) ? uint32(1) : uint32(0)); + data << uint32(BG_SA_TIMER_MINS) << uint32(0); + data << uint32(BG_SA_TIMER_SEC_TENS) << uint32(0); + data << uint32(BG_SA_TIMER_SEC_DECS) << uint32(0); + + data << uint32(BG_SA_RIGHT_GY_HORDE) << uint32(GraveyardStatus[BG_SA_RIGHT_CAPTURABLE_GY] == TEAM_HORDE?1:0); + data << uint32(BG_SA_LEFT_GY_HORDE) << uint32(GraveyardStatus[BG_SA_LEFT_CAPTURABLE_GY] == TEAM_HORDE?1:0); + data << uint32(BG_SA_CENTER_GY_HORDE) << uint32(GraveyardStatus[BG_SA_CENTRAL_CAPTURABLE_GY] == TEAM_HORDE?1:0); + + data << uint32(BG_SA_RIGHT_GY_ALLIANCE) << uint32(GraveyardStatus[BG_SA_RIGHT_CAPTURABLE_GY] == TEAM_ALLIANCE?1:0); + data << uint32(BG_SA_LEFT_GY_ALLIANCE) << uint32(GraveyardStatus[BG_SA_LEFT_CAPTURABLE_GY] == TEAM_ALLIANCE?1:0); + data << uint32(BG_SA_CENTER_GY_ALLIANCE) << uint32(GraveyardStatus[BG_SA_CENTRAL_CAPTURABLE_GY] == TEAM_ALLIANCE?1:0); + + data << uint32(BG_SA_HORDE_DEFENCE_TOKEN) << ally_attacks; + data << uint32(BG_SA_ALLIANCE_DEFENCE_TOKEN) << horde_attacks; + + data << uint32(BG_SA_LEFT_ATT_TOKEN_HRD) << horde_attacks; + data << uint32(BG_SA_RIGHT_ATT_TOKEN_HRD) << horde_attacks; + data << uint32(BG_SA_RIGHT_ATT_TOKEN_ALL) << ally_attacks; + data << uint32(BG_SA_LEFT_ATT_TOKEN_ALL) << ally_attacks; +} + +void BattleGroundSA::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map, default values are set in constructor + BattleGroundSAScore* sc = new BattleGroundSAScore; + + if (!ShipsStarted) + { + if (plr->GetTeamId() == attackers) + { + plr->CastSpell(plr,12438,true);//Without this player falls before boat loads... + + if (urand(0,1)) + plr->TeleportTo(607, 2682.936f, -830.368f, 50.0f, 2.895f, 0); + else + plr->TeleportTo(607, 2577.003f, 980.261f, 50.0f, 0.807f, 0); + + } + else + plr->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0); + } + else + { + if (plr->GetTeamId() == attackers) + plr->TeleportTo(607, 1600.381f, -106.263f, 8.8745f, 3.78f, 0); + else + plr->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0); + } + + m_PlayerScores[plr->GetGUID()] = sc; +} + +void BattleGroundSA::RemovePlayer(Player* /*plr*/,uint64 /*guid*/) +{ +} + +void BattleGroundSA::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/) +{ + // this is wrong way to implement these things. On official it done by gameobject spell cast. + if (GetStatus() != STATUS_IN_PROGRESS) + return; +} + +void BattleGroundSA::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor) +{ + BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); + if (itr == m_PlayerScores.end()) // player not found... + return; + + if (type == SCORE_DESTROYED_DEMOLISHER) + ((BattleGroundSAScore*)itr->second)->demolishers_destroyed += value; + else if (type == SCORE_DESTROYED_WALL) + ((BattleGroundSAScore*)itr->second)->gates_destroyed += value; + else + BattleGround::UpdatePlayerScore(Source,type,value, doAddHonor); +} + +void BattleGroundSA::TeleportPlayers() +{ + for (BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) + { + if (Player *plr = objmgr.GetPlayer(itr->first)) + { + // should remove spirit of redemption + if (plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) + plr->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); + + if (!plr->isAlive()) + { + plr->ResurrectPlayer(1.0f); + plr->SpawnCorpseBones(); + } + + plr->SetHealth(plr->GetMaxHealth()); + plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA)); + plr->CombatStopWithPets(true); + + if (plr->GetTeamId() == attackers) + { + plr->CastSpell(plr,12438,true); //Without this player falls before boat loads... + + if (urand(0,1)) + plr->TeleportTo(607, 2682.936f, -830.368f, 50.0f, 2.895f, 0); + else + plr->TeleportTo(607, 2577.003f, 980.261f, 50.0f, 0.807f, 0); + } + else + plr->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0); + } + } +} + +void BattleGroundSA::EventPlayerDamagedGO(Player* plr, GameObject* go, uint8 hitType, uint32 destroyedEvent) +{ + if (!go || !go->GetGOInfo()) + return; + + switch(hitType) + { + case BG_OBJECT_DMG_HIT_TYPE_JUST_DAMAGED://under attack + SendWarningToAll(LANG_BG_SA_IS_UNDER_ATTACK, go->GetGOInfo()->name); + break; + case BG_OBJECT_DMG_HIT_TYPE_DAMAGED: + break; + case BG_OBJECT_DMG_HIT_TYPE_JUST_HIGH_DAMAGED: + { + uint32 i = GetGateIDFromDestroyEventID(destroyedEvent); + GateStatus[i] = BG_SA_GATE_DAMAGED; + uint32 uws = GetWorldStateFromGateID(i); + if (uws) + UpdateWorldState(uws, GateStatus[i]); + break; + } + case BG_OBJECT_DMG_HIT_TYPE_HIGH_DAMAGED: + break; + case BG_OBJECT_DMG_HIT_TYPE_JUST_DESTROYED://handled at DestroyGate() + if (destroyedEvent == 19837) + SendWarningToAll(LANG_BG_SA_CHAMBER_BREACHED); + else + SendWarningToAll(LANG_BG_SA_WAS_DESTROYED, go->GetGOInfo()->name); + break; + } +} + +void BattleGroundSA::HandleKillUnit(Creature* unit, Player* killer) +{ + if (!unit) + return; + + if (unit->GetEntry() == 28781) //Demolisher + UpdatePlayerScore(killer, SCORE_DESTROYED_DEMOLISHER, 1); +} + +/* + You may ask what the fuck does it do? + Prevents owner overwriting guns faction with own. + */ +void BattleGroundSA::OverrideGunFaction() +{ + if (!m_BgCreatures[0]) + return; + + for (uint8 i = BG_SA_GUN_1; i <= BG_SA_GUN_10;i++) + { + if (Creature* gun = GetBGCreature(i)) + gun->setFaction(BG_SA_Factions[attackers? TEAM_ALLIANCE : TEAM_HORDE]); + } + + for (uint8 i = BG_SA_DEMOLISHER_1; i <= BG_SA_DEMOLISHER_4;i++) + { + if (Creature* dem = GetBGCreature(i)) + dem->setFaction(BG_SA_Factions[attackers]); + } +} + +void BattleGroundSA::DemolisherStartState(bool start) +{ + if (!m_BgCreatures[0]) + return; + + for (uint8 i = BG_SA_DEMOLISHER_1; i <= BG_SA_DEMOLISHER_4; i++) + { + if (Creature* dem = GetBGCreature(i)) + { + if (start) + dem->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + else + dem->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + } + } +} + +void BattleGroundSA::DestroyGate(Player* pl, GameObject* /*go*/, uint32 destroyedEvent) +{ + uint32 i = GetGateIDFromDestroyEventID(destroyedEvent); + if (!GateStatus[i]) + return; + + if (GameObject* g = GetBGObject(i)) + { + if (g->GetGOValue()->building.health == 0) + { + GateStatus[i] = BG_SA_GATE_DESTROYED; + uint32 uws = GetWorldStateFromGateID(i); + if (uws) + UpdateWorldState(uws, GateStatus[i]); + bool rewardHonor = true; + switch(i) + { + case BG_SA_GREEN_GATE: + if (GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED) + rewardHonor = false; + break; + case BG_SA_BLUE_GATE: + if (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED) + rewardHonor = false; + break; + case BG_SA_RED_GATE: + if (GateStatus[BG_SA_PURPLE_GATE] == BG_SA_GATE_DESTROYED) + rewardHonor = false; + break; + case BG_SA_PURPLE_GATE: + if (GateStatus[BG_SA_RED_GATE] == BG_SA_GATE_DESTROYED) + rewardHonor = false; + break; + } + + if (i < 5) + DelObject(i+9); + UpdatePlayerScore(pl,SCORE_DESTROYED_WALL, 1); + if (rewardHonor) + UpdatePlayerScore(pl,SCORE_BONUS_HONOR,(GetBonusHonorFromKill(1))); + } + } +} + +WorldSafeLocsEntry const* BattleGroundSA::GetClosestGraveYard(Player* player) +{ + uint32 safeloc = 0; + WorldSafeLocsEntry const* ret; + WorldSafeLocsEntry const* closest; + float dist, nearest; + float x,y,z; + + player->GetPosition(x,y,z); + + if (player->GetTeamId() == attackers) + safeloc = BG_SA_GYEntries[BG_SA_BEACH_GY]; + else + safeloc = BG_SA_GYEntries[BG_SA_DEFENDER_LAST_GY]; + + closest = sWorldSafeLocsStore.LookupEntry(safeloc); + nearest = sqrt((closest->x - x)*(closest->x - x) + (closest->y - y)*(closest->y - y)+(closest->z - z)*(closest->z - z)); + + for (uint8 i = BG_SA_RIGHT_CAPTURABLE_GY; i < BG_SA_MAX_GY; i++) + { + if (GraveyardStatus[i] != player->GetTeamId()) + continue; + + ret = sWorldSafeLocsStore.LookupEntry(BG_SA_GYEntries[i]); + dist = sqrt((ret->x - x)*(ret->x - x) + (ret->y - y)*(ret->y - y)+(ret->z - z)*(ret->z - z)); + if (dist < nearest) + { + closest = ret; + nearest = dist; + } + } + + return closest; +} + +void BattleGroundSA::SendTime() +{ + uint32 end_of_round = (BG_SA_ENDROUNDTIME - TotalTime); + UpdateWorldState(BG_SA_TIMER_MINS, end_of_round/60000); + UpdateWorldState(BG_SA_TIMER_SEC_TENS, (end_of_round%60000)/10000); + UpdateWorldState(BG_SA_TIMER_SEC_DECS, ((end_of_round%60000)%10000)/1000); +} + +void BattleGroundSA::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj) +{ + switch(target_obj->GetEntry()) + { + case 191307: + case 191308: + if (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED) + CaptureGraveyard(BG_SA_LEFT_CAPTURABLE_GY, Source); + break; + case 191305: + case 191306: + if (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED) + CaptureGraveyard(BG_SA_RIGHT_CAPTURABLE_GY, Source); + break; + case 191310: + case 191309: + if ((GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED) && (GateStatus[BG_SA_RED_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_PURPLE_GATE] == BG_SA_GATE_DESTROYED)) + CaptureGraveyard(BG_SA_CENTRAL_CAPTURABLE_GY, Source); + break; + default: + return; + }; +} + +void BattleGroundSA::CaptureGraveyard(BG_SA_Graveyards i, Player *Source) +{ + DelCreature(BG_SA_MAXNPC + i); + GraveyardStatus[i] = Source->GetTeamId(); + WorldSafeLocsEntry const *sg = NULL; + sg = sWorldSafeLocsStore.LookupEntry(BG_SA_GYEntries[i]); + AddSpiritGuide(i + BG_SA_MAXNPC, sg->x, sg->y, sg->z, BG_SA_GYOrientation[i], (GraveyardStatus[i] == TEAM_ALLIANCE? ALLIANCE : HORDE)); + uint32 npc = 0; + uint32 flag = 0; + + switch(i) + { + case BG_SA_LEFT_CAPTURABLE_GY: + flag = BG_SA_LEFT_FLAG; + DelObject(flag); + AddObject(flag,BG_SA_ObjEntries[(flag + (Source->GetTeamId() == TEAM_ALLIANCE ? 0:3))], + BG_SA_ObjSpawnlocs[flag][0],BG_SA_ObjSpawnlocs[flag][1], + BG_SA_ObjSpawnlocs[flag][2],BG_SA_ObjSpawnlocs[flag][3],0,0,0,0,RESPAWN_ONE_DAY); + + npc = BG_SA_NPC_RIGSPARK; + AddCreature(BG_SA_NpcEntries[npc], npc, attackers, + BG_SA_NpcSpawnlocs[npc][0], BG_SA_NpcSpawnlocs[npc][1], + BG_SA_NpcSpawnlocs[npc][2], BG_SA_NpcSpawnlocs[npc][3]); + + UpdateWorldState(BG_SA_LEFT_GY_ALLIANCE, (GraveyardStatus[i] == TEAM_ALLIANCE? 1:0)); + UpdateWorldState(BG_SA_LEFT_GY_HORDE, (GraveyardStatus[i] == TEAM_ALLIANCE? 0:1)); + if (Source->GetTeamId() == TEAM_ALLIANCE) + SendWarningToAll(LANG_BG_SA_A_GY_WEST); + else + SendWarningToAll(LANG_BG_SA_H_GY_WEST); + break; + case BG_SA_RIGHT_CAPTURABLE_GY: + flag = BG_SA_RIGHT_FLAG; + DelObject(flag); + AddObject(flag,BG_SA_ObjEntries[(flag + (Source->GetTeamId() == TEAM_ALLIANCE ? 0:3))], + BG_SA_ObjSpawnlocs[flag][0],BG_SA_ObjSpawnlocs[flag][1], + BG_SA_ObjSpawnlocs[flag][2],BG_SA_ObjSpawnlocs[flag][3],0,0,0,0,RESPAWN_ONE_DAY); + + npc = BG_SA_NPC_SPARKLIGHT; + AddCreature(BG_SA_NpcEntries[npc], npc, attackers, + BG_SA_NpcSpawnlocs[npc][0], BG_SA_NpcSpawnlocs[npc][1], + BG_SA_NpcSpawnlocs[npc][2], BG_SA_NpcSpawnlocs[npc][3]); + + UpdateWorldState(BG_SA_RIGHT_GY_ALLIANCE, (GraveyardStatus[i] == TEAM_ALLIANCE? 1:0)); + UpdateWorldState(BG_SA_RIGHT_GY_HORDE, (GraveyardStatus[i] == TEAM_ALLIANCE? 0:1)); + if (Source->GetTeamId() == TEAM_ALLIANCE) + SendWarningToAll(LANG_BG_SA_A_GY_EAST); + else + SendWarningToAll(LANG_BG_SA_H_GY_EAST); + break; + case BG_SA_CENTRAL_CAPTURABLE_GY: + flag = BG_SA_CENTRAL_FLAG; + DelObject(flag); + AddObject(flag,BG_SA_ObjEntries[(flag + (Source->GetTeamId() == TEAM_ALLIANCE ? 0:3))], + BG_SA_ObjSpawnlocs[flag][0],BG_SA_ObjSpawnlocs[flag][1], + BG_SA_ObjSpawnlocs[flag][2],BG_SA_ObjSpawnlocs[flag][3],0,0,0,0,RESPAWN_ONE_DAY); + + UpdateWorldState(BG_SA_CENTER_GY_ALLIANCE, (GraveyardStatus[i] == TEAM_ALLIANCE? 1:0)); + UpdateWorldState(BG_SA_CENTER_GY_HORDE, (GraveyardStatus[i] == TEAM_ALLIANCE? 0:1)); + if (Source->GetTeamId() == TEAM_ALLIANCE) + SendWarningToAll(LANG_BG_SA_A_GY_SOUTH); + else + SendWarningToAll(LANG_BG_SA_H_GY_SOUTH); + break; + default: + ASSERT(0); + break; + }; +} + +void BattleGroundSA::EventPlayerUsedGO(Player* Source, GameObject* object) +{ + if (object->GetEntry() == BG_SA_ObjEntries[BG_SA_TITAN_RELIC] && GateStatus[BG_SA_ANCIENT_GATE] == BG_SA_GATE_DESTROYED) + { + if (Source->GetTeamId() == attackers) + { + if (Source->GetTeamId() == ALLIANCE) + SendMessageToAll(LANG_BG_SA_ALLIANCE_CAPTURED_RELIC, CHAT_MSG_BG_SYSTEM_NEUTRAL); + else SendMessageToAll(LANG_BG_SA_HORDE_CAPTURED_RELIC, CHAT_MSG_BG_SYSTEM_NEUTRAL); + + if (status == BG_SA_ROUND_ONE) + { + RoundScores[0].winner = attackers; + RoundScores[0].time = TotalTime; + attackers = (attackers == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE; + status = BG_SA_SECOND_WARMUP; + TotalTime = 0; + ToggleTimer(); + SendWarningToAll(LANG_BG_SA_ROUND_ONE_END); + UpdateWaitTimer = 5000; + SignaledRoundTwo = false; + SignaledRoundTwoHalfMin = false; + InitSecondRound = true; + ResetObjs(); + } + else if (status == BG_SA_ROUND_TWO) + { + RoundScores[1].winner = attackers; + RoundScores[1].time = TotalTime;ToggleTimer(); + if (RoundScores[0].time == RoundScores[1].time) + EndBattleGround(NULL); + else if (RoundScores[0].time < RoundScores[1].time) + EndBattleGround(RoundScores[0].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE); + else + EndBattleGround(RoundScores[1].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE); + } + } + } +} + +void BattleGroundSA::ToggleTimer() +{ + TimerEnabled = !TimerEnabled; + UpdateWorldState(BG_SA_ENABLE_TIMER, (TimerEnabled) ? 1 : 0); +} + +void BattleGroundSA::EndBattleGround(uint32 winner) +{ + //honor reward for winning + if (winner == ALLIANCE) + RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); + else if (winner == HORDE) + RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); + + //complete map_end rewards (even if no team wins) + RewardHonorToTeam(GetBonusHonorFromKill(2), ALLIANCE); + RewardHonorToTeam(GetBonusHonorFromKill(2), HORDE); + + BattleGround::EndBattleGround(winner); +} + +void BattleGroundSA::UpdateDemolisherSpawns() +{ + for (uint8 i = BG_SA_DEMOLISHER_1; i <= BG_SA_DEMOLISHER_4; i++) + { + if (m_BgCreatures[i]) + { + if (Creature *Demolisher = GetBGCreature(i)) + { + if (Demolisher->isDead()) + { + uint8 gy = (i >= BG_SA_DEMOLISHER_3 ? 3 : 2); + if (GraveyardStatus[gy] == attackers) + Demolisher->Relocate(BG_SA_NpcSpawnlocs[i + 6][0], BG_SA_NpcSpawnlocs[i + 6][1], + BG_SA_NpcSpawnlocs[i + 6][2], BG_SA_NpcSpawnlocs[i + 6][3]); + else + Demolisher->Relocate(BG_SA_NpcSpawnlocs[i][0], BG_SA_NpcSpawnlocs[i][1], + BG_SA_NpcSpawnlocs[i][2], BG_SA_NpcSpawnlocs[i][3]); + + Demolisher->Respawn(); + } + } + } + } +} + + diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundSA.h b/src/server/game/BattleGrounds/Zones/BattleGroundSA.h new file mode 100644 index 00000000000..760be3ca02e --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundSA.h @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __BATTLEGROUNDSA_H +#define __BATTLEGROUNDSA_H + +class BattleGround; + +class BattleGroundSAScore : public BattleGroundScore +{ + public: + BattleGroundSAScore(): demolishers_destroyed(0), gates_destroyed(0) {}; + virtual ~BattleGroundSAScore() {}; + uint8 demolishers_destroyed; + uint8 gates_destroyed; +}; + +#define BG_SA_FLAG_AMOUNT 3 +#define BG_SA_DEMOLISHER_AMOUNT 4 + +enum BG_SA_Status + { + BG_SA_NOTSTARTED = 0, + BG_SA_WARMUP, + BG_SA_ROUND_ONE, + BG_SA_SECOND_WARMUP, + BG_SA_ROUND_TWO, + BG_SA_BONUS_ROUND + }; + +enum BG_SA_GateState + { + BG_SA_GATE_OK = 1, + BG_SA_GATE_DAMAGED = 2, + BG_SA_GATE_DESTROYED = 3 + }; + +enum BG_SA_Timers + { + BG_SA_BOAT_START = 60000, + BG_SA_WARMUPLENGTH = 120000, + BG_SA_ROUNDLENGTH = 600000 + }; + +enum BG_SA_WorldStates + { + BG_SA_TIMER_MINS = 3559, + BG_SA_TIMER_SEC_TENS = 3560, + BG_SA_TIMER_SEC_DECS = 3561, + BG_SA_ALLY_ATTACKS = 4352, + BG_SA_HORDE_ATTACKS = 4353, + + BG_SA_PURPLE_GATEWS = 3614, + BG_SA_RED_GATEWS = 3617, + BG_SA_BLUE_GATEWS = 3620, + BG_SA_GREEN_GATEWS = 3623, + BG_SA_YELLOW_GATEWS = 3638, + BG_SA_ANCIENT_GATEWS = 3849, + + + BG_SA_LEFT_GY_ALLIANCE = 3635, + BG_SA_RIGHT_GY_ALLIANCE = 3636, + BG_SA_CENTER_GY_ALLIANCE = 3637, + + BG_SA_RIGHT_ATT_TOKEN_ALL = 3627, + BG_SA_LEFT_ATT_TOKEN_ALL = 3626, + + BG_SA_LEFT_ATT_TOKEN_HRD = 3629, + BG_SA_RIGHT_ATT_TOKEN_HRD = 3628, + + BG_SA_HORDE_DEFENCE_TOKEN = 3631, + BG_SA_ALLIANCE_DEFENCE_TOKEN = 3630, + + BG_SA_RIGHT_GY_HORDE = 3632, + BG_SA_LEFT_GY_HORDE = 3633, + BG_SA_CENTER_GY_HORDE = 3634, + + BG_SA_BONUS_TIMER = 0xdf3, + BG_SA_ENABLE_TIMER = 3564, + }; + +enum BG_SA_NPCs + { + BG_SA_GUN_1 = 0, + BG_SA_GUN_2, + BG_SA_GUN_3, + BG_SA_GUN_4, + BG_SA_GUN_5, + BG_SA_GUN_6, + BG_SA_GUN_7, + BG_SA_GUN_8, + BG_SA_GUN_9, + BG_SA_GUN_10, + BG_SA_DEMOLISHER_1, + BG_SA_DEMOLISHER_2, + BG_SA_DEMOLISHER_3, + BG_SA_DEMOLISHER_4, + BG_SA_NPC_SPARKLIGHT, + BG_SA_NPC_RIGSPARK, + BG_SA_MAXNPC + }; + +const uint32 BG_SA_NpcEntries[BG_SA_MAXNPC] = + { + 27894, + 27894, + 27894, + 27894, + 27894, + 27894, + 27894, + 27894, + 27894, + 27894, + //4 beach demolishers + 28781, + 28781, + 28781, + 28781, + //Fizzle Sparklight, or whatever his name was + 29260, + 29262, + }; + +const float BG_SA_NpcSpawnlocs[BG_SA_MAXNPC + BG_SA_DEMOLISHER_AMOUNT][4] = + { + //Cannons + { 1436.429f, 110.05f, 41.407f, 5.4f }, + { 1404.9023f, 84.758f, 41.183f, 5.46f }, + { 1068.693f, -86.951f, 93.81f, 0.02f }, + { 1068.83f, -127.56f, 96.45f, 0.0912f }, + { 1422.115f, -196.433f, 42.1825f, 1.0222f }, + { 1454.887f, -220.454f, 41.956f, 0.9627f }, + { 1232.345f, -187.517f, 66.945f, 0.45f }, + { 1249.634f, -224.189f, 66.72f, 0.635f }, + { 1236.213f, 92.287f, 64.965f, 5.751f }, + { 1215.11f, 57.772f, 64.739f, 5.78f } , + //Demolishers + { 1611.597656,-117.270073,8.719355,2.513274}, + { 1575.562500,-158.421875,5.024450,2.129302}, + { 1618.047729,61.424641,7.248210,3.979351}, + { 1575.103149,98.873344,2.830360,3.752458}, + //Npcs + { 1348.644165, -298.786469, 31.080130, 1.710423}, + { 1358.191040, 195.527786, 31.018187, 4.171337}, + //Demolishers2 + { 1371.055786, -317.071136, 35.007359, 1.947460}, + { 1424.034912, -260.195190, 31.084425, 2.820013}, + { 1353.139893, 223.745438, 35.265411, 4.343684}, + { 1404.809570, 197.027237, 32.046032, 3.605401}, + }; + +enum BG_SA_Objects + { + BG_SA_GREEN_GATE = 0, + BG_SA_YELLOW_GATE, + BG_SA_BLUE_GATE, + BG_SA_RED_GATE, + BG_SA_PURPLE_GATE, + BG_SA_ANCIENT_GATE, + BG_SA_TITAN_RELIC, + BG_SA_BOAT_ONE, + BG_SA_BOAT_TWO, + BG_SA_SIGIL_1, + BG_SA_SIGIL_2, + BG_SA_SIGIL_3, + BG_SA_SIGIL_4, + BG_SA_SIGIL_5, + BG_SA_CENTRAL_FLAGPOLE, + BG_SA_RIGHT_FLAGPOLE, + BG_SA_LEFT_FLAGPOLE, + BG_SA_CENTRAL_FLAG, + BG_SA_RIGHT_FLAG, + BG_SA_LEFT_FLAG, + BG_SA_MAXOBJ + }; + +const float BG_SA_ObjSpawnlocs[BG_SA_MAXOBJ][4] = + { + { 1411.57f, 108.163f, 28.692f, 5.441f }, + { 1055.452f, -108.1f, 82.134f, 0.034f }, + { 1431.3413f, -219.437f, 30.893f, 0.9736f }, + { 1227.667f, -212.555f, 55.372f, 0.5023f }, + { 1214.681f, 81.21f, 53.413f, 5.745f }, + { 878.555f, -108.989f, 119.835f, 0.0565f }, + { 836.5f, -108.8f, 120.219f, 0.0f }, + //Ships + { 2679.696777, -826.891235, 3.712860, 5.78367f}, //rot2 1 rot3 0.0002 + { 2574.003662, 981.261475, 2.603424, 0.807696}, + //Sigils + { 1414.054f, 106.72f, 41.442f, 5.441f }, + { 1060.63f, -107.8f, 94.7f, 0.034f }, + { 1433.383f, -216.4f, 43.642f, 0.9736f }, + { 1230.75f, -210.724f, 67.611f, 0.5023f }, + { 1217.8f, 79.532f, 66.58f, 5.745f }, + //Flagpoles + { 1215.114258,-65.711861,70.084267,-3.124123}, + {1338.863892,-153.336533,30.895121,-2.530723}, + {1309.124268,9.410645,30.893402,-1.623156}, + //Flags + { 1215.108032,-65.715767,70.084267,-3.124123}, + { 1338.859253,-153.327316,30.895077,-2.530723}, + { 1309.192017,9.416233,30.893402,1.518436}, + }; + +/* Ships: + * 193182 - ally + * 193183 - horde + * 193184 - horde + * 193185 - ally + * Banners: + * 191308 - left one, + * 191306 - right one, + * 191310 - central, + * Ally ones, substract 1 + * to get horde ones. + */ + +const uint32 BG_SA_ObjEntries[BG_SA_MAXOBJ + BG_SA_FLAG_AMOUNT] = + { + 190722, + 190727, + 190724, + 190726, + 190723, + 192549, + 192834, + 193182, + 193185, + 192687, + 192685, + 192689, + 192690, + 192691, + 191311, + 191311, + 191311, + 191310, + 191306, + 191308, + 191309, + 191305, + 191307, + }; + +const uint32 BG_SA_Factions[2] = + { + 1732, + 1735, + }; + +enum BG_SA_Graveyards + { + BG_SA_BEACH_GY = 0, + BG_SA_DEFENDER_LAST_GY, + BG_SA_RIGHT_CAPTURABLE_GY, + BG_SA_LEFT_CAPTURABLE_GY, + BG_SA_CENTRAL_CAPTURABLE_GY, + BG_SA_MAX_GY + }; + +const uint32 BG_SA_GYEntries[BG_SA_MAX_GY] = + { + 1350, + 1349, + 1347, + 1346, + 1348, + }; + +const float BG_SA_GYOrientation[BG_SA_MAX_GY] = + { + 6.202f, + 1.926f, //right capturable GY + 3.917f, //left capturable GY + 3.104f, //center, capturable + 6.148f, //defender last GY + }; + +struct BG_SA_RoundScore +{ + TeamId winner; + uint32 time; +}; + +class BattleGroundSA : public BattleGround +{ + friend class BattleGroundMgr; + + public: + BattleGroundSA(); + ~BattleGroundSA(); + void Update(uint32 diff); + + /* inherited from BattlegroundClass */ + virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + virtual bool SetupBattleGround(); + virtual void Reset(); + virtual void FillInitialWorldStates(WorldPacket& data); + virtual void EventPlayerDamagedGO(Player* plr, GameObject* go, uint8 hitType, uint32 destroyedEvent); + virtual void HandleKillUnit(Creature* unit, Player* killer); + virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); + virtual void EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj); + virtual void EventPlayerUsedGO(Player* Source, GameObject* object); + uint32 GetGateIDFromDestroyEventID(uint32 id) + { + uint32 i = 0; + switch(id) + { + case 19046: i = BG_SA_GREEN_GATE; break; //Green gate destroyed + case 19045: i = BG_SA_BLUE_GATE; break; //blue gate + case 19047: i = BG_SA_RED_GATE; break; //red gate + case 19048: i = BG_SA_PURPLE_GATE; break; //purple gate + case 19049: i = BG_SA_YELLOW_GATE; break; //yellow gate + case 19837: i = BG_SA_ANCIENT_GATE; break; //ancient gate + } + return i; + } + uint32 GetWorldStateFromGateID(uint32 id) + { + uint32 uws = 0; + switch(id) + { + case BG_SA_GREEN_GATE: uws = BG_SA_GREEN_GATEWS; break; + case BG_SA_YELLOW_GATE: uws = BG_SA_YELLOW_GATEWS; break; + case BG_SA_BLUE_GATE: uws = BG_SA_BLUE_GATEWS; break; + case BG_SA_RED_GATE: uws = BG_SA_RED_GATEWS; break; + case BG_SA_PURPLE_GATE: uws = BG_SA_PURPLE_GATEWS; break; + case BG_SA_ANCIENT_GATE: uws = BG_SA_ANCIENT_GATEWS; break; + } + return uws; + } + void EndBattleGround(uint32 winner); + + void RemovePlayer(Player *plr,uint64 guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + + + /* Scorekeeping */ + void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); + + private: + bool ResetObjs(); + void StartShips(); + void TeleportPlayers(); + void OverrideGunFaction(); + void DemolisherStartState(bool start); + void DestroyGate(Player* pl, GameObject* /*go*/, uint32 destroyedEvent); + void SendTime(); + void CaptureGraveyard(BG_SA_Graveyards i, Player *Source); + void ToggleTimer(); + void UpdateDemolisherSpawns(); + TeamId attackers; + uint32 TotalTime; + uint32 BG_SA_ENDROUNDTIME; + bool ShipsStarted; + BG_SA_GateState GateStatus[6]; + BG_SA_Status status; + TeamId GraveyardStatus[BG_SA_MAX_GY]; + BG_SA_RoundScore RoundScores[2]; + bool TimerEnabled; + uint32 UpdateWaitTimer;//5secs before starting the 1min countdown for second round + bool SignaledRoundTwo; + bool SignaledRoundTwoHalfMin; + bool InitSecondRound; +}; +#endif diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundWS.cpp b/src/server/game/BattleGrounds/Zones/BattleGroundWS.cpp new file mode 100644 index 00000000000..71872511274 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundWS.cpp @@ -0,0 +1,841 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "BattleGround.h" +#include "BattleGroundWS.h" +#include "Creature.h" +#include "GameObject.h" +#include "Language.h" +#include "Object.h" +#include "ObjectMgr.h" +#include "BattleGroundMgr.h" +#include "Player.h" +#include "World.h" +#include "WorldPacket.h" + +// these variables aren't used outside of this file, so declare them only here +enum BG_WSG_Rewards +{ + BG_WSG_WIN = 0, + BG_WSG_FLAG_CAP, + BG_WSG_MAP_COMPLETE, + BG_WSG_REWARD_NUM +}; + +uint32 BG_WSG_Honor[BG_HONOR_MODE_NUM][BG_WSG_REWARD_NUM] = { + {20,40,40}, // normal honor + {60,40,80} // holiday +}; + +uint32 BG_WSG_Reputation[BG_HONOR_MODE_NUM][BG_WSG_REWARD_NUM] = { + {0,35,0}, // normal honor + {0,45,0} // holiday +}; + +BattleGroundWS::BattleGroundWS() +{ + m_BgObjects.resize(BG_WS_OBJECT_MAX); + m_BgCreatures.resize(BG_CREATURES_MAX_WS); + + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN; +} + +BattleGroundWS::~BattleGroundWS() +{ +} + +void BattleGroundWS::Update(uint32 diff) +{ + BattleGround::Update(diff); + + if (GetStatus() == STATUS_IN_PROGRESS) + { + if (GetStartTime() >= 25*MINUTE*IN_MILISECONDS) // Òàéìåð òèêàòü íà÷èíàåò ïîñëå 25 ìèíóò + { + if (GetTeamScore(ALLIANCE) == 0) + { + if (GetTeamScore(HORDE) == 0) // No one scored - result is tie + EndBattleGround(NULL); + else // Horde has more points and thus wins + EndBattleGround(HORDE); + } + + else if (GetTeamScore(HORDE) == 0) + EndBattleGround(ALLIANCE); // Alliance has > 0, Horde has 0, alliance wins + + else if (GetTeamScore(HORDE) == GetTeamScore(ALLIANCE)) // Team score equal, winner is team that scored the first flag + EndBattleGround(m_FirstFlagCaptureTeam); + + else if (GetTeamScore(HORDE) > GetTeamScore(ALLIANCE)) // Last but not least, check who has the higher score + EndBattleGround(HORDE); + else + EndBattleGround(ALLIANCE); + } + else if (GetStartTime() > m_minutesElapsed*MINUTE*IN_MILISECONDS) + { + ++m_minutesElapsed; + UpdateWorldState(BG_WS_STATE_TIMER, 25-m_minutesElapsed); + } + + if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_WAIT_RESPAWN) + { + m_FlagsTimer[BG_TEAM_ALLIANCE] -= diff; + + if (m_FlagsTimer[BG_TEAM_ALLIANCE] < 0) + { + m_FlagsTimer[BG_TEAM_ALLIANCE] = 0; + RespawnFlag(ALLIANCE, true); + } + } + if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND) + { + m_FlagsDropTimer[BG_TEAM_ALLIANCE] -= diff; + + if (m_FlagsDropTimer[BG_TEAM_ALLIANCE] < 0) + { + m_FlagsDropTimer[BG_TEAM_ALLIANCE] = 0; + RespawnFlagAfterDrop(ALLIANCE); + m_BothFlagsKept = false; + } + } + if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_WAIT_RESPAWN) + { + m_FlagsTimer[BG_TEAM_HORDE] -= diff; + + if (m_FlagsTimer[BG_TEAM_HORDE] < 0) + { + m_FlagsTimer[BG_TEAM_HORDE] = 0; + RespawnFlag(HORDE, true); + } + } + if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND) + { + m_FlagsDropTimer[BG_TEAM_HORDE] -= diff; + + if (m_FlagsDropTimer[BG_TEAM_HORDE] < 0) + { + m_FlagsDropTimer[BG_TEAM_HORDE] = 0; + RespawnFlagAfterDrop(HORDE); + m_BothFlagsKept = false; + } + } + if (m_BothFlagsKept) + { + m_FlagSpellForceTimer += diff; + if (m_FlagDebuffState == 0 && m_FlagSpellForceTimer >= 600000) //10 minutes + { + if (Player * plr = objmgr.GetPlayer(m_FlagKeepers[0])) + plr->CastSpell(plr,WS_SPELL_FOCUSED_ASSAULT,true); + if (Player * plr = objmgr.GetPlayer(m_FlagKeepers[1])) + plr->CastSpell(plr,WS_SPELL_FOCUSED_ASSAULT,true); + m_FlagDebuffState = 1; + } + else if (m_FlagDebuffState == 1 && m_FlagSpellForceTimer >= 900000) //15 minutes + { + if (Player * plr = objmgr.GetPlayer(m_FlagKeepers[0])) + { + plr->RemoveAurasDueToSpell(WS_SPELL_FOCUSED_ASSAULT); + plr->CastSpell(plr,WS_SPELL_BRUTAL_ASSAULT,true); + } + if (Player * plr = objmgr.GetPlayer(m_FlagKeepers[1])) + { + plr->RemoveAurasDueToSpell(WS_SPELL_FOCUSED_ASSAULT); + plr->CastSpell(plr,WS_SPELL_BRUTAL_ASSAULT,true); + } + m_FlagDebuffState = 2; + } + } + else + { + m_FlagSpellForceTimer = 0; //reset timer. + m_FlagDebuffState = 0; + } + } +} + +void BattleGroundWS::StartingEventCloseDoors() +{ + for (uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; ++i) + { + DoorClose(i); + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + } + for (uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; ++i) + SpawnBGObject(i, RESPAWN_ONE_DAY); + + UpdateWorldState(BG_WS_STATE_TIMER_ACTIVE, 1); + UpdateWorldState(BG_WS_STATE_TIMER, 25); +} + +void BattleGroundWS::StartingEventOpenDoors() +{ + for (uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_A_4; ++i) + DoorOpen(i); + for (uint32 i = BG_WS_OBJECT_DOOR_H_1; i <= BG_WS_OBJECT_DOOR_H_2; ++i) + DoorOpen(i); + + SpawnBGObject(BG_WS_OBJECT_DOOR_A_5, RESPAWN_ONE_DAY); + SpawnBGObject(BG_WS_OBJECT_DOOR_A_6, RESPAWN_ONE_DAY); + SpawnBGObject(BG_WS_OBJECT_DOOR_H_3, RESPAWN_ONE_DAY); + SpawnBGObject(BG_WS_OBJECT_DOOR_H_4, RESPAWN_ONE_DAY); + + for (uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; ++i) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); +} + +void BattleGroundWS::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map, default values are set in constructor + BattleGroundWGScore* sc = new BattleGroundWGScore; + + m_PlayerScores[plr->GetGUID()] = sc; +} + +void BattleGroundWS::RespawnFlag(uint32 Team, bool captured) +{ + if (Team == ALLIANCE) + { + sLog.outDebug("Respawn Alliance flag"); + m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_BASE; + } + else + { + sLog.outDebug("Respawn Horde flag"); + m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE; + } + + if (captured) + { + //when map_update will be allowed for battlegrounds this code will be useless + SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY); + SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY); + SendMessageToAll(LANG_BG_WS_F_PLACED, CHAT_MSG_BG_SYSTEM_NEUTRAL); + PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED); // flag respawned sound... + } + m_BothFlagsKept = false; +} + +void BattleGroundWS::RespawnFlagAfterDrop(uint32 team) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + RespawnFlag(team,false); + if (team == ALLIANCE) + { + SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY); + SendMessageToAll(LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED, CHAT_MSG_BG_SYSTEM_NEUTRAL); + } + else + { + SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY); + SendMessageToAll(LANG_BG_WS_HORDE_FLAG_RESPAWNED, CHAT_MSG_BG_SYSTEM_NEUTRAL); + } + + PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED); + + GameObject *obj = GetBgMap()->GetGameObject(GetDroppedFlagGUID(team)); + if (obj) + obj->Delete(); + else + sLog.outError("unknown droped flag bg, guid: %u",GUID_LOPART(GetDroppedFlagGUID(team))); + + SetDroppedFlagGUID(0,team); + m_BothFlagsKept = false; +} + +void BattleGroundWS::EventPlayerCapturedFlag(Player *Source) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + uint32 winner = 0; + + Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); + if (Source->GetTeam() == ALLIANCE) + { + if (!this->IsHordeFlagPickedup()) + return; + SetHordeFlagPicker(0); // must be before aura remove to prevent 2 events (drop+capture) at the same time + // horde flag in base (but not respawned yet) + m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_WAIT_RESPAWN; + // Drop Horde Flag from Player + Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG); + if (m_FlagDebuffState == 1) + Source->RemoveAurasDueToSpell(WS_SPELL_FOCUSED_ASSAULT); + if (m_FlagDebuffState == 2) + Source->RemoveAurasDueToSpell(WS_SPELL_BRUTAL_ASSAULT); + if (GetTeamScore(ALLIANCE) < BG_WS_MAX_TEAM_SCORE) + AddPoint(ALLIANCE, 1); + PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE); + RewardReputationToTeam(890, m_ReputationCapture, ALLIANCE); + } + else + { + if (!this->IsAllianceFlagPickedup()) + return; + SetAllianceFlagPicker(0); // must be before aura remove to prevent 2 events (drop+capture) at the same time + // alliance flag in base (but not respawned yet) + m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_WAIT_RESPAWN; + // Drop Alliance Flag from Player + Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG); + if (m_FlagDebuffState == 1) + Source->RemoveAurasDueToSpell(WS_SPELL_FOCUSED_ASSAULT); + if (m_FlagDebuffState == 2) + Source->RemoveAurasDueToSpell(WS_SPELL_BRUTAL_ASSAULT); + if (GetTeamScore(HORDE) < BG_WS_MAX_TEAM_SCORE) + AddPoint(HORDE, 1); + PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_HORDE); + RewardReputationToTeam(889, m_ReputationCapture, HORDE); + } + //for flag capture is reward 2 honorable kills + RewardHonorToTeam(GetBonusHonorFromKill(2), Source->GetTeam()); + + SpawnBGObject(BG_WS_OBJECT_H_FLAG, BG_WS_FLAG_RESPAWN_TIME); + SpawnBGObject(BG_WS_OBJECT_A_FLAG, BG_WS_FLAG_RESPAWN_TIME); + + if (Source->GetTeam() == ALLIANCE) + SendMessageToAll(LANG_BG_WS_CAPTURED_HF, CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); + else + SendMessageToAll(LANG_BG_WS_CAPTURED_AF, CHAT_MSG_BG_SYSTEM_HORDE, Source); + + UpdateFlagState(Source->GetTeam(), 1); // flag state none + UpdateTeamScore(Source->GetTeam()); + // only flag capture should be updated + UpdatePlayerScore(Source, SCORE_FLAG_CAPTURES, 1); // +1 flag captures + + if (!m_FirstFlagCaptureTeam) + SetFirstFlagCapture(Source->GetTeam()); + + if (GetTeamScore(ALLIANCE) == BG_WS_MAX_TEAM_SCORE) + winner = ALLIANCE; + + if (GetTeamScore(HORDE) == BG_WS_MAX_TEAM_SCORE) + winner = HORDE; + + if (winner) + { + UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 0); + UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 0); + UpdateWorldState(BG_WS_FLAG_STATE_ALLIANCE, 1); + UpdateWorldState(BG_WS_FLAG_STATE_HORDE, 1); + UpdateWorldState(BG_WS_STATE_TIMER_ACTIVE, 0); + + RewardHonorToTeam(BG_WSG_Honor[m_HonorMode][BG_WSG_WIN], winner); + EndBattleGround(winner); + } + else + { + m_FlagsTimer[GetTeamIndexByTeamId(Source->GetTeam()) ? 0 : 1] = BG_WS_FLAG_RESPAWN_TIME; + } +} + +void BattleGroundWS::EventPlayerDroppedFlag(Player *Source) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + { + // if not running, do not cast things at the dropper player (prevent spawning the "dropped" flag), neither send unnecessary messages + // just take off the aura + if (Source->GetTeam() == ALLIANCE) + { + if (!this->IsHordeFlagPickedup()) + return; + if (GetHordeFlagPickerGUID() == Source->GetGUID()) + { + SetHordeFlagPicker(0); + Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG); + } + } + else + { + if (!this->IsAllianceFlagPickedup()) + return; + if (GetAllianceFlagPickerGUID() == Source->GetGUID()) + { + SetAllianceFlagPicker(0); + Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG); + } + } + return; + } + + bool set = false; + + if (Source->GetTeam() == ALLIANCE) + { + if (!IsHordeFlagPickedup()) + return; + if (GetHordeFlagPickerGUID() == Source->GetGUID()) + { + SetHordeFlagPicker(0); + Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG); + if (m_FlagDebuffState == 1) + Source->RemoveAurasDueToSpell(WS_SPELL_FOCUSED_ASSAULT); + if (m_FlagDebuffState == 2) + Source->RemoveAurasDueToSpell(WS_SPELL_BRUTAL_ASSAULT); + m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_GROUND; + Source->CastSpell(Source, BG_WS_SPELL_WARSONG_FLAG_DROPPED, true); + set = true; + } + } + else + { + if (!IsAllianceFlagPickedup()) + return; + if (GetAllianceFlagPickerGUID() == Source->GetGUID()) + { + SetAllianceFlagPicker(0); + Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG); + if (m_FlagDebuffState == 1) + Source->RemoveAurasDueToSpell(WS_SPELL_FOCUSED_ASSAULT); + if (m_FlagDebuffState == 2) + Source->RemoveAurasDueToSpell(WS_SPELL_BRUTAL_ASSAULT); + m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_GROUND; + Source->CastSpell(Source, BG_WS_SPELL_SILVERWING_FLAG_DROPPED, true); + set = true; + } + } + + if (set) + { + Source->CastSpell(Source, SPELL_RECENTLY_DROPPED_FLAG, true); + UpdateFlagState(Source->GetTeam(), 1); + + if (Source->GetTeam() == ALLIANCE) + { + SendMessageToAll(LANG_BG_WS_DROPPED_HF, CHAT_MSG_BG_SYSTEM_HORDE, Source); + UpdateWorldState(BG_WS_FLAG_UNK_HORDE, uint32(-1)); + } + else + { + SendMessageToAll(LANG_BG_WS_DROPPED_AF, CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); + UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, uint32(-1)); + } + + m_FlagsDropTimer[GetTeamIndexByTeamId(Source->GetTeam()) ? 0 : 1] = BG_WS_FLAG_DROP_TIME; + } +} + +void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + int32 message_id = 0; + ChatMsg type = CHAT_MSG_BG_SYSTEM_NEUTRAL; + + //alliance flag picked up from base + if (Source->GetTeam() == HORDE && this->GetFlagState(ALLIANCE) == BG_WS_FLAG_STATE_ON_BASE + && this->m_BgObjects[BG_WS_OBJECT_A_FLAG] == target_obj->GetGUID()) + { + message_id = LANG_BG_WS_PICKEDUP_AF; + type = CHAT_MSG_BG_SYSTEM_HORDE; + PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP); + SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_ONE_DAY); + SetAllianceFlagPicker(Source->GetGUID()); + m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_PLAYER; + //update world state to show correct flag carrier + UpdateFlagState(HORDE, BG_WS_FLAG_STATE_ON_PLAYER); + UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 1); + Source->CastSpell(Source, BG_WS_SPELL_SILVERWING_FLAG, true); + if (m_FlagState[1] == BG_WS_FLAG_STATE_ON_PLAYER) + m_BothFlagsKept = true; + } + + //horde flag picked up from base + if (Source->GetTeam() == ALLIANCE && this->GetFlagState(HORDE) == BG_WS_FLAG_STATE_ON_BASE + && this->m_BgObjects[BG_WS_OBJECT_H_FLAG] == target_obj->GetGUID()) + { + message_id = LANG_BG_WS_PICKEDUP_HF; + type = CHAT_MSG_BG_SYSTEM_ALLIANCE; + PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP); + SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_ONE_DAY); + SetHordeFlagPicker(Source->GetGUID()); + m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_PLAYER; + //update world state to show correct flag carrier + UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_ON_PLAYER); + UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 1); + Source->CastSpell(Source, BG_WS_SPELL_WARSONG_FLAG, true); + if (m_FlagState[0] == BG_WS_FLAG_STATE_ON_PLAYER) + m_BothFlagsKept = true; + } + + //Alliance flag on ground(not in base) (returned or picked up again from ground!) + if (GetFlagState(ALLIANCE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10)) + { + if (Source->GetTeam() == ALLIANCE) + { + message_id = LANG_BG_WS_RETURNED_AF; + type = CHAT_MSG_BG_SYSTEM_ALLIANCE; + UpdateFlagState(HORDE, BG_WS_FLAG_STATE_WAIT_RESPAWN); + RespawnFlag(ALLIANCE, false); + SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY); + PlaySoundToAll(BG_WS_SOUND_FLAG_RETURNED); + UpdatePlayerScore(Source, SCORE_FLAG_RETURNS, 1); + m_BothFlagsKept = false; + } + else + { + message_id = LANG_BG_WS_PICKEDUP_AF; + type = CHAT_MSG_BG_SYSTEM_HORDE; + PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP); + SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_ONE_DAY); + SetAllianceFlagPicker(Source->GetGUID()); + Source->CastSpell(Source, BG_WS_SPELL_SILVERWING_FLAG, true); + m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_PLAYER; + UpdateFlagState(HORDE, BG_WS_FLAG_STATE_ON_PLAYER); + if (m_FlagDebuffState == 1) + Source->CastSpell(Source,WS_SPELL_FOCUSED_ASSAULT,true); + if (m_FlagDebuffState == 2) + Source->CastSpell(Source,WS_SPELL_BRUTAL_ASSAULT,true); + UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, 1); + } + //called in HandleGameObjectUseOpcode: + //target_obj->Delete(); + } + + //Horde flag on ground(not in base) (returned or picked up again) + if (GetFlagState(HORDE) == BG_WS_FLAG_STATE_ON_GROUND && Source->IsWithinDistInMap(target_obj, 10)) + { + if (Source->GetTeam() == HORDE) + { + message_id = LANG_BG_WS_RETURNED_HF; + type = CHAT_MSG_BG_SYSTEM_HORDE; + UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_WAIT_RESPAWN); + RespawnFlag(HORDE, false); + SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY); + PlaySoundToAll(BG_WS_SOUND_FLAG_RETURNED); + UpdatePlayerScore(Source, SCORE_FLAG_RETURNS, 1); + m_BothFlagsKept = false; + } + else + { + message_id = LANG_BG_WS_PICKEDUP_HF; + type = CHAT_MSG_BG_SYSTEM_ALLIANCE; + PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP); + SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_ONE_DAY); + SetHordeFlagPicker(Source->GetGUID()); + Source->CastSpell(Source, BG_WS_SPELL_WARSONG_FLAG, true); + m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_PLAYER; + UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_ON_PLAYER); + if (m_FlagDebuffState == 1) + Source->CastSpell(Source,WS_SPELL_FOCUSED_ASSAULT,true); + if (m_FlagDebuffState == 2) + Source->CastSpell(Source,WS_SPELL_BRUTAL_ASSAULT,true); + UpdateWorldState(BG_WS_FLAG_UNK_HORDE, 1); + } + //called in HandleGameObjectUseOpcode: + //target_obj->Delete(); + } + + if (!message_id) + return; + + SendMessageToAll(message_id, type, Source); + Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); +} + +void BattleGroundWS::RemovePlayer(Player *plr, uint64 guid) +{ + // sometimes flag aura not removed :( + if (IsAllianceFlagPickedup() && m_FlagKeepers[BG_TEAM_ALLIANCE] == guid) + { + if (!plr) + { + sLog.outError("BattleGroundWS: Removing offline player who has the FLAG!!"); + this->SetAllianceFlagPicker(0); + this->RespawnFlag(ALLIANCE, false); + } + else + this->EventPlayerDroppedFlag(plr); + } + if (IsHordeFlagPickedup() && m_FlagKeepers[BG_TEAM_HORDE] == guid) + { + if (!plr) + { + sLog.outError("BattleGroundWS: Removing offline player who has the FLAG!!"); + this->SetHordeFlagPicker(0); + this->RespawnFlag(HORDE, false); + } + else + this->EventPlayerDroppedFlag(plr); + } +} + +void BattleGroundWS::UpdateFlagState(uint32 team, uint32 value) +{ + if (team == ALLIANCE) + UpdateWorldState(BG_WS_FLAG_STATE_ALLIANCE, value); + else + UpdateWorldState(BG_WS_FLAG_STATE_HORDE, value); +} + +void BattleGroundWS::UpdateTeamScore(uint32 team) +{ + if (team == ALLIANCE) + UpdateWorldState(BG_WS_FLAG_CAPTURES_ALLIANCE, GetTeamScore(team)); + else + UpdateWorldState(BG_WS_FLAG_CAPTURES_HORDE, GetTeamScore(team)); +} + +void BattleGroundWS::HandleAreaTrigger(Player *Source, uint32 Trigger) +{ + // this is wrong way to implement these things. On official it done by gameobject spell cast. + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + //uint32 SpellId = 0; + //uint64 buff_guid = 0; + switch(Trigger) + { + case 3686: // Alliance elixir of speed spawn. Trigger not working, because located inside other areatrigger, can be replaced by IsWithinDist(object, dist) in BattleGround::Update(). + //buff_guid = m_BgObjects[BG_WS_OBJECT_SPEEDBUFF_1]; + break; + case 3687: // Horde elixir of speed spawn. Trigger not working, because located inside other areatrigger, can be replaced by IsWithinDist(object, dist) in BattleGround::Update(). + //buff_guid = m_BgObjects[BG_WS_OBJECT_SPEEDBUFF_2]; + break; + case 3706: // Alliance elixir of regeneration spawn + //buff_guid = m_BgObjects[BG_WS_OBJECT_REGENBUFF_1]; + break; + case 3708: // Horde elixir of regeneration spawn + //buff_guid = m_BgObjects[BG_WS_OBJECT_REGENBUFF_2]; + break; + case 3707: // Alliance elixir of berserk spawn + //buff_guid = m_BgObjects[BG_WS_OBJECT_BERSERKBUFF_1]; + break; + case 3709: // Horde elixir of berserk spawn + //buff_guid = m_BgObjects[BG_WS_OBJECT_BERSERKBUFF_2]; + break; + case 3646: // Alliance Flag spawn + if (m_FlagState[BG_TEAM_HORDE] && !m_FlagState[BG_TEAM_ALLIANCE]) + if (GetHordeFlagPickerGUID() == Source->GetGUID()) + EventPlayerCapturedFlag(Source); + break; + case 3647: // Horde Flag spawn + if (m_FlagState[BG_TEAM_ALLIANCE] && !m_FlagState[BG_TEAM_HORDE]) + if (GetAllianceFlagPickerGUID() == Source->GetGUID()) + EventPlayerCapturedFlag(Source); + break; + case 3649: // unk1 + case 3688: // unk2 + case 4628: // unk3 + case 4629: // unk4 + break; + default: + sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); + Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); + break; + } + + //if (buff_guid) + // HandleTriggerBuff(buff_guid,Source); +} + +bool BattleGroundWS::SetupBattleGround() +{ + // flags + if (!AddObject(BG_WS_OBJECT_A_FLAG, BG_OBJECT_A_FLAG_WS_ENTRY, 1540.423f, 1481.325f, 351.8284f, 3.089233f, 0, 0, 0.9996573f, 0.02617699f, BG_WS_FLAG_RESPAWN_TIME/1000) + || !AddObject(BG_WS_OBJECT_H_FLAG, BG_OBJECT_H_FLAG_WS_ENTRY, 916.0226f, 1434.405f, 345.413f, 0.01745329f, 0, 0, 0.008726535f, 0.9999619f, BG_WS_FLAG_RESPAWN_TIME/1000) + // buffs + || !AddObject(BG_WS_OBJECT_SPEEDBUFF_1, BG_OBJECTID_SPEEDBUFF_ENTRY, 1449.93f, 1470.71f, 342.6346f, -1.64061f, 0, 0, 0.7313537f, -0.6819983f, BUFF_RESPAWN_TIME) + || !AddObject(BG_WS_OBJECT_SPEEDBUFF_2, BG_OBJECTID_SPEEDBUFF_ENTRY, 1005.171f, 1447.946f, 335.9032f, 1.64061f, 0, 0, 0.7313537f, 0.6819984f, BUFF_RESPAWN_TIME) + || !AddObject(BG_WS_OBJECT_REGENBUFF_1, BG_OBJECTID_REGENBUFF_ENTRY, 1317.506f, 1550.851f, 313.2344f, -0.2617996f, 0, 0, 0.1305263f, -0.9914448f, BUFF_RESPAWN_TIME) + || !AddObject(BG_WS_OBJECT_REGENBUFF_2, BG_OBJECTID_REGENBUFF_ENTRY, 1110.451f, 1353.656f, 316.5181f, -0.6806787f, 0, 0, 0.333807f, -0.9426414f, BUFF_RESPAWN_TIME) + || !AddObject(BG_WS_OBJECT_BERSERKBUFF_1, BG_OBJECTID_BERSERKERBUFF_ENTRY, 1320.09f, 1378.79f, 314.7532f, 1.186824f, 0, 0, 0.5591929f, 0.8290376f, BUFF_RESPAWN_TIME) + || !AddObject(BG_WS_OBJECT_BERSERKBUFF_2, BG_OBJECTID_BERSERKERBUFF_ENTRY, 1139.688f, 1560.288f, 306.8432f, -2.443461f, 0, 0, 0.9396926f, -0.3420201f, BUFF_RESPAWN_TIME) + // alliance gates + || !AddObject(BG_WS_OBJECT_DOOR_A_1, BG_OBJECT_DOOR_A_1_WS_ENTRY, 1503.335f, 1493.466f, 352.1888f, 3.115414f, 0, 0, 0.9999143f, 0.01308903f, RESPAWN_IMMEDIATELY) + || !AddObject(BG_WS_OBJECT_DOOR_A_2, BG_OBJECT_DOOR_A_2_WS_ENTRY, 1492.478f, 1457.912f, 342.9689f, 3.115414f, 0, 0, 0.9999143f, 0.01308903f, RESPAWN_IMMEDIATELY) + || !AddObject(BG_WS_OBJECT_DOOR_A_3, BG_OBJECT_DOOR_A_3_WS_ENTRY, 1468.503f, 1494.357f, 351.8618f, 3.115414f, 0, 0, 0.9999143f, 0.01308903f, RESPAWN_IMMEDIATELY) + || !AddObject(BG_WS_OBJECT_DOOR_A_4, BG_OBJECT_DOOR_A_4_WS_ENTRY, 1471.555f, 1458.778f, 362.6332f, 3.115414f, 0, 0, 0.9999143f, 0.01308903f, RESPAWN_IMMEDIATELY) + || !AddObject(BG_WS_OBJECT_DOOR_A_5, BG_OBJECT_DOOR_A_5_WS_ENTRY, 1492.347f, 1458.34f, 342.3712f, -0.03490669f, 0, 0, 0.01745246f, -0.9998477f, RESPAWN_IMMEDIATELY) + || !AddObject(BG_WS_OBJECT_DOOR_A_6, BG_OBJECT_DOOR_A_6_WS_ENTRY, 1503.466f, 1493.367f, 351.7352f, -0.03490669f, 0, 0, 0.01745246f, -0.9998477f, RESPAWN_IMMEDIATELY) + // horde gates + || !AddObject(BG_WS_OBJECT_DOOR_H_1, BG_OBJECT_DOOR_H_1_WS_ENTRY, 949.1663f, 1423.772f, 345.6241f, -0.5756807f, -0.01673368f, -0.004956111f, -0.2839723f, 0.9586737f, RESPAWN_IMMEDIATELY) + || !AddObject(BG_WS_OBJECT_DOOR_H_2, BG_OBJECT_DOOR_H_2_WS_ENTRY, 953.0507f, 1459.842f, 340.6526f, -1.99662f, -0.1971825f, 0.1575096f, -0.8239487f, 0.5073641f, RESPAWN_IMMEDIATELY) + || !AddObject(BG_WS_OBJECT_DOOR_H_3, BG_OBJECT_DOOR_H_3_WS_ENTRY, 949.9523f, 1422.751f, 344.9273f, 0.0f, 0, 0, 0, 1, RESPAWN_IMMEDIATELY) + || !AddObject(BG_WS_OBJECT_DOOR_H_4, BG_OBJECT_DOOR_H_4_WS_ENTRY, 950.7952f, 1459.583f, 342.1523f, 0.05235988f, 0, 0, 0.02617695f, 0.9996573f, RESPAWN_IMMEDIATELY) +) + { + sLog.outErrorDb("BatteGroundWS: Failed to spawn some object BattleGround not created!"); + return false; + } + + WorldSafeLocsEntry const *sg = sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_ALLIANCE); + if (!sg || !AddSpiritGuide(WS_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, ALLIANCE)) + { + sLog.outErrorDb("BatteGroundWS: Failed to spawn Alliance spirit guide! BattleGround not created!"); + return false; + } + + sg = sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_HORDE); + if (!sg || !AddSpiritGuide(WS_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, HORDE)) + { + sLog.outErrorDb("BatteGroundWS: Failed to spawn Horde spirit guide! BattleGround not created!"); + return false; + } + + sLog.outDebug("BatteGroundWS: BG objects and spirit guides spawned"); + + return true; +} + +void BattleGroundWS::Reset() +{ + //call parent's class reset + BattleGround::Reset(); + + m_FlagKeepers[BG_TEAM_ALLIANCE] = 0; + m_FlagKeepers[BG_TEAM_HORDE] = 0; + m_DroppedFlagGUID[BG_TEAM_ALLIANCE] = 0; + m_DroppedFlagGUID[BG_TEAM_HORDE] = 0; + m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_BASE; + m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE; + m_TeamScores[BG_TEAM_ALLIANCE] = 0; + m_TeamScores[BG_TEAM_HORDE] = 0; + bool isBGWeekend = sBattleGroundMgr.IsBGWeekend(GetTypeID()); + m_ReputationCapture = (isBGWeekend) ? 45 : 35; + m_HonorWinKills = (isBGWeekend) ? 3 : 1; + m_HonorEndKills = (isBGWeekend) ? 4 : 2; + // For WorldState + m_minutesElapsed = 0; + m_FirstFlagCaptureTeam = 0; + + /* Spirit nodes is static at this BG and then not required deleting at BG reset. + if (m_BgCreatures[WS_SPIRIT_MAIN_ALLIANCE]) + DelCreature(WS_SPIRIT_MAIN_ALLIANCE); + if (m_BgCreatures[WS_SPIRIT_MAIN_HORDE]) + DelCreature(WS_SPIRIT_MAIN_HORDE); + */ +} + +void BattleGroundWS::EndBattleGround(uint32 winner) +{ + //win reward + if (winner == ALLIANCE) + RewardHonorToTeam(GetBonusHonorFromKill(m_HonorWinKills), ALLIANCE); + if (winner == HORDE) + RewardHonorToTeam(GetBonusHonorFromKill(m_HonorWinKills), HORDE); + //complete map_end rewards (even if no team wins) + RewardHonorToTeam(GetBonusHonorFromKill(m_HonorEndKills), ALLIANCE); + RewardHonorToTeam(GetBonusHonorFromKill(m_HonorEndKills), HORDE); + + BattleGround::EndBattleGround(winner); +} + +void BattleGroundWS::HandleKillPlayer(Player *player, Player *killer) +{ + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + EventPlayerDroppedFlag(player); + + BattleGround::HandleKillPlayer(player, killer); +} + +void BattleGroundWS::UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor) +{ + + BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); + if (itr == m_PlayerScores.end()) // player not found + return; + + switch(type) + { + case SCORE_FLAG_CAPTURES: // flags captured + ((BattleGroundWGScore*)itr->second)->FlagCaptures += value; + break; + case SCORE_FLAG_RETURNS: // flags returned + ((BattleGroundWGScore*)itr->second)->FlagReturns += value; + break; + default: + BattleGround::UpdatePlayerScore(Source, type, value, doAddHonor); + break; + } +} + +WorldSafeLocsEntry const* BattleGroundWS::GetClosestGraveYard(Player* player) +{ + //if status in progress, it returns main graveyards with spiritguides + //else it will return the graveyard in the flagroom - this is especially good + //if a player dies in preparation phase - then the player can't cheat + //and teleport to the graveyard outside the flagroom + //and start running around, while the doors are still closed + if (player->GetTeam() == ALLIANCE) + { + if (GetStatus() == STATUS_IN_PROGRESS) + return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_ALLIANCE); + else + return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_FLAGROOM_ALLIANCE); + } + else + { + if (GetStatus() == STATUS_IN_PROGRESS) + return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_HORDE); + else + return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_FLAGROOM_HORDE); + } +} + +void BattleGroundWS::FillInitialWorldStates(WorldPacket& data) +{ + data << uint32(BG_WS_FLAG_CAPTURES_ALLIANCE) << uint32(GetTeamScore(ALLIANCE)); + data << uint32(BG_WS_FLAG_CAPTURES_HORDE) << uint32(GetTeamScore(HORDE)); + + if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_GROUND) + data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(-1); + else if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_PLAYER) + data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(1); + else + data << uint32(BG_WS_FLAG_UNK_ALLIANCE) << uint32(0); + + if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_GROUND) + data << uint32(BG_WS_FLAG_UNK_HORDE) << uint32(-1); + else if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_PLAYER) + data << uint32(BG_WS_FLAG_UNK_HORDE) << uint32(1); + else + data << uint32(BG_WS_FLAG_UNK_HORDE) << uint32(0); + + data << uint32(BG_WS_FLAG_CAPTURES_MAX) << uint32(BG_WS_MAX_TEAM_SCORE); + + if (GetStatus() == STATUS_IN_PROGRESS) + { + data << uint32(BG_WS_STATE_TIMER_ACTIVE) << uint32(1); + data << uint32(BG_WS_STATE_TIMER) << uint32(25-m_minutesElapsed); + } + else + data << uint32(BG_WS_STATE_TIMER_ACTIVE) << uint32(0); + + if (m_FlagState[BG_TEAM_HORDE] == BG_WS_FLAG_STATE_ON_PLAYER) + data << uint32(BG_WS_FLAG_STATE_ALLIANCE) << uint32(2); + else + data << uint32(BG_WS_FLAG_STATE_ALLIANCE) << uint32(1); + + if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_ON_PLAYER) + data << uint32(BG_WS_FLAG_STATE_HORDE) << uint32(2); + else + data << uint32(BG_WS_FLAG_STATE_HORDE) << uint32(1); + +} + diff --git a/src/server/game/BattleGrounds/Zones/BattleGroundWS.h b/src/server/game/BattleGrounds/Zones/BattleGroundWS.h new file mode 100644 index 00000000000..1a733c14570 --- /dev/null +++ b/src/server/game/BattleGrounds/Zones/BattleGroundWS.h @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __BATTLEGROUNDWS_H +#define __BATTLEGROUNDWS_H + +#include "BattleGround.h" + +enum BG_WS_TimerOrScore +{ + BG_WS_MAX_TEAM_SCORE = 3, + BG_WS_FLAG_RESPAWN_TIME = 23000, + BG_WS_FLAG_DROP_TIME = 10000, + BG_WS_SPELL_FORCE_TIME = 600000, + BG_WS_SPELL_BRUTAL_TIME = 900000 +}; + +enum BG_WS_Sound +{ + BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE = 8173, + BG_WS_SOUND_FLAG_CAPTURED_HORDE = 8213, + BG_WS_SOUND_FLAG_PLACED = 8232, + BG_WS_SOUND_FLAG_RETURNED = 8192, + BG_WS_SOUND_HORDE_FLAG_PICKED_UP = 8212, + BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP = 8174, + BG_WS_SOUND_FLAGS_RESPAWNED = 8232 +}; + +enum BG_WS_SpellId +{ + BG_WS_SPELL_WARSONG_FLAG = 23333, + BG_WS_SPELL_WARSONG_FLAG_DROPPED = 23334, + BG_WS_SPELL_SILVERWING_FLAG = 23335, + BG_WS_SPELL_SILVERWING_FLAG_DROPPED = 23336, + BG_WS_SPELL_FOCUSED_ASSAULT = 46392, + BG_WS_SPELL_BRUTAL_ASSAULT = 46393 +}; + +enum BG_WS_WorldStates +{ + BG_WS_FLAG_UNK_ALLIANCE = 1545, + BG_WS_FLAG_UNK_HORDE = 1546, +// FLAG_UNK = 1547, + BG_WS_FLAG_CAPTURES_ALLIANCE = 1581, + BG_WS_FLAG_CAPTURES_HORDE = 1582, + BG_WS_FLAG_CAPTURES_MAX = 1601, + BG_WS_FLAG_STATE_HORDE = 2338, + BG_WS_FLAG_STATE_ALLIANCE = 2339, + BG_WS_STATE_TIMER = 4248, + BG_WS_STATE_TIMER_ACTIVE = 4247 +}; + +enum BG_WS_ObjectTypes +{ + BG_WS_OBJECT_DOOR_A_1 = 0, + BG_WS_OBJECT_DOOR_A_2 = 1, + BG_WS_OBJECT_DOOR_A_3 = 2, + BG_WS_OBJECT_DOOR_A_4 = 3, + BG_WS_OBJECT_DOOR_A_5 = 4, + BG_WS_OBJECT_DOOR_A_6 = 5, + BG_WS_OBJECT_DOOR_H_1 = 6, + BG_WS_OBJECT_DOOR_H_2 = 7, + BG_WS_OBJECT_DOOR_H_3 = 8, + BG_WS_OBJECT_DOOR_H_4 = 9, + BG_WS_OBJECT_A_FLAG = 10, + BG_WS_OBJECT_H_FLAG = 11, + BG_WS_OBJECT_SPEEDBUFF_1 = 12, + BG_WS_OBJECT_SPEEDBUFF_2 = 13, + BG_WS_OBJECT_REGENBUFF_1 = 14, + BG_WS_OBJECT_REGENBUFF_2 = 15, + BG_WS_OBJECT_BERSERKBUFF_1 = 16, + BG_WS_OBJECT_BERSERKBUFF_2 = 17, + BG_WS_OBJECT_MAX = 18 +}; + +enum BG_WS_ObjectEntry +{ + BG_OBJECT_DOOR_A_1_WS_ENTRY = 179918, + BG_OBJECT_DOOR_A_2_WS_ENTRY = 179919, + BG_OBJECT_DOOR_A_3_WS_ENTRY = 179920, + BG_OBJECT_DOOR_A_4_WS_ENTRY = 179921, + BG_OBJECT_DOOR_A_5_WS_ENTRY = 180322, + BG_OBJECT_DOOR_A_6_WS_ENTRY = 180322, + BG_OBJECT_DOOR_H_1_WS_ENTRY = 179916, + BG_OBJECT_DOOR_H_2_WS_ENTRY = 179917, + BG_OBJECT_DOOR_H_3_WS_ENTRY = 180322, + BG_OBJECT_DOOR_H_4_WS_ENTRY = 180322, + BG_OBJECT_A_FLAG_WS_ENTRY = 179830, + BG_OBJECT_H_FLAG_WS_ENTRY = 179831, + BG_OBJECT_A_FLAG_GROUND_WS_ENTRY = 179785, + BG_OBJECT_H_FLAG_GROUND_WS_ENTRY = 179786 +}; + +enum BG_WS_FlagState +{ + BG_WS_FLAG_STATE_ON_BASE = 0, + BG_WS_FLAG_STATE_WAIT_RESPAWN = 1, + BG_WS_FLAG_STATE_ON_PLAYER = 2, + BG_WS_FLAG_STATE_ON_GROUND = 3 +}; + +enum BG_WS_Graveyards +{ + WS_GRAVEYARD_FLAGROOM_ALLIANCE = 769, + WS_GRAVEYARD_FLAGROOM_HORDE = 770, + WS_GRAVEYARD_MAIN_ALLIANCE = 771, + WS_GRAVEYARD_MAIN_HORDE = 772 +}; + +enum BG_WS_CreatureTypes +{ + WS_SPIRIT_MAIN_ALLIANCE = 0, + WS_SPIRIT_MAIN_HORDE = 1, + + BG_CREATURES_MAX_WS = 2 +}; + +enum BG_WS_CarrierDebuffs +{ + WS_SPELL_FOCUSED_ASSAULT = 46392, + WS_SPELL_BRUTAL_ASSAULT = 46393 +}; + +class BattleGroundWGScore : public BattleGroundScore +{ + public: + BattleGroundWGScore() : FlagCaptures(0), FlagReturns(0) {}; + virtual ~BattleGroundWGScore() {}; + uint32 FlagCaptures; + uint32 FlagReturns; +}; + +class BattleGroundWS : public BattleGround +{ + friend class BattleGroundMgr; + + public: + /* Construction */ + BattleGroundWS(); + ~BattleGroundWS(); + void Update(uint32 diff); + + /* inherited from BattlegroundClass */ + virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + + /* BG Flags */ + uint64 GetAllianceFlagPickerGUID() const { return m_FlagKeepers[BG_TEAM_ALLIANCE]; } + uint64 GetHordeFlagPickerGUID() const { return m_FlagKeepers[BG_TEAM_HORDE]; } + void SetAllianceFlagPicker(uint64 guid) { m_FlagKeepers[BG_TEAM_ALLIANCE] = guid; } + void SetHordeFlagPicker(uint64 guid) { m_FlagKeepers[BG_TEAM_HORDE] = guid; } + bool IsAllianceFlagPickedup() const { return m_FlagKeepers[BG_TEAM_ALLIANCE] != 0; } + bool IsHordeFlagPickedup() const { return m_FlagKeepers[BG_TEAM_HORDE] != 0; } + void RespawnFlag(uint32 Team, bool captured); + void RespawnFlagAfterDrop(uint32 Team); + uint8 GetFlagState(uint32 team) { return m_FlagState[GetTeamIndexByTeamId(team)]; } + void AddTimedAura(uint32 aura); + void RemoveTimedAura(uint32 aura); + bool IsBrutalTimerDone; + bool IsForceTimerDone; + + /* Battleground Events */ + virtual void EventPlayerDroppedFlag(Player *Source); + virtual void EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj); + virtual void EventPlayerCapturedFlag(Player *Source); + + void RemovePlayer(Player *plr, uint64 guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + void HandleKillPlayer(Player *player, Player *killer); + bool SetupBattleGround(); + virtual void Reset(); + void EndBattleGround(uint32 winner); + virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); + + void UpdateFlagState(uint32 team, uint32 value); + void SetFirstFlagCapture(uint32 team) { m_FirstFlagCaptureTeam = team; } + void UpdateTeamScore(uint32 team); + void UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor = true); + void SetDroppedFlagGUID(uint64 guid, uint32 TeamID) { m_DroppedFlagGUID[GetTeamIndexByTeamId(TeamID)] = guid;} + uint64 GetDroppedFlagGUID(uint32 TeamID) { return m_DroppedFlagGUID[GetTeamIndexByTeamId(TeamID)];} + virtual void FillInitialWorldStates(WorldPacket& data); + + /* Scorekeeping */ + uint32 GetTeamScore(uint32 TeamID) const { return m_TeamScores[GetTeamIndexByTeamId(TeamID)]; } + void AddPoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] += Points; } + void SetTeamPoint(uint32 TeamID, uint32 Points = 0) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] = Points; } + void RemovePoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] -= Points; } + private: + uint64 m_FlagKeepers[2]; // 0 - alliance, 1 - horde + uint64 m_DroppedFlagGUID[2]; + uint8 m_FlagState[2]; // for checking flag state + int32 m_FlagsTimer[2]; + int32 m_FlagsDropTimer[2]; + uint32 m_FirstFlagCaptureTeam; // Winner is based on this if score is equal + + uint32 m_ReputationCapture; + uint32 m_HonorWinKills; + uint32 m_HonorEndKills; + int32 m_FlagSpellForceTimer; + bool m_BothFlagsKept; + uint8 m_FlagDebuffState; // 0 - no debuffs, 1 - focused assault, 2 - brutal assault + uint8 m_minutesElapsed; +}; +#endif + diff --git a/src/server/game/Calendar/CalendarHandler.cpp b/src/server/game/Calendar/CalendarHandler.cpp deleted file mode 100644 index f6679c5d5ac..00000000000 --- a/src/server/game/Calendar/CalendarHandler.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" - -#include "InstanceSaveMgr.h" -#include "Log.h" -#include "Opcodes.h" -#include "Player.h" - -void WorldSession::HandleCalendarGetCalendar(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_GET_CALENDAR"); // empty - - time_t cur_time = time(NULL); - - WorldPacket data(SMSG_CALENDAR_SEND_CALENDAR,4+4*0+4+4*0+4+4); - - data << uint32(0); // invite count - /* - for (;;) - { - uint64 inviteId; - uint64 unkGuid0; - uint8 unk1, unk2, unk3; - uint64 creatorGuid; - } - */ - - data << uint32(0); // event count - /* - for (;;) - { - uint64 eventId; - std::string title; // 128 chars - uint32 type; - uint32 occurrenceTime; - uint32 flags; - uint32 unk4; -- possibly mapid for dungeon/raid - uint64 creatorGuid; - } - */ - - data << uint32(0); // unk - data << uint32(secsToTimeBitFields(cur_time)); // current time - - uint32 counter = 0; - size_t p_counter = data.wpos(); - data << uint32(counter); // instance save count - - for (int i = 0; i < MAX_DIFFICULTY; ++i) - { - for (Player::BoundInstancesMap::const_iterator itr = _player->m_boundInstances[i].begin(); itr != _player->m_boundInstances[i].end(); ++itr) - { - if (itr->second.perm) - { - InstanceSave *save = itr->second.save; - data << uint32(save->GetMapId()); - data << uint32(save->GetDifficulty()); - data << uint32(save->GetResetTime() - cur_time); - data << uint64(save->GetInstanceId()); // instance save id as unique instance copy id - ++counter; - } - } - } - - data.put(p_counter, counter); - - data << uint32(1135753200); // unk (28.12.2005 12:00) - - counter = 0; - p_counter = data.wpos(); - data << uint32(counter); // raid reset count - - ResetTimeByMapDifficultyMap const& resets = sInstanceSaveManager.GetResetTimeMap(); - for (ResetTimeByMapDifficultyMap::const_iterator itr = resets.begin(); itr != resets.end(); ++itr) - { - uint32 mapid = PAIR32_LOPART(itr->first); - MapEntry const* mapEnt = sMapStore.LookupEntry(mapid); - if (!mapEnt || !mapEnt->IsRaid()) - continue; - - data << uint32(mapid); - data << uint32(itr->second - cur_time); - data << uint32(mapEnt->unk_time); - ++counter; - } - - data.put(p_counter, counter); - - data << uint32(0); // holiday count? - /* - for (;;) - { - uint32 unk5, unk6, unk7, unk8, unk9; - for (uint32 j = 0; j < 26; ++j) - { - uint32 unk10; - } - for (uint32 j = 0; j < 10; ++j) - { - uint32 unk11; - } - for (uint32 j = 0; j < 10; ++j) - { - uint32 unk12; - } - std::string holidayName; // 64 chars - } - */ - - sLog.outDebug("Sending calendar"); - data.hexlike(); - SendPacket(&data); -} - -void WorldSession::HandleCalendarGetEvent(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_GET_EVENT"); - recv_data.hexlike(); - recv_data.read_skip(); // unk -} - -void WorldSession::HandleCalendarGuildFilter(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_GUILD_FILTER"); - recv_data.hexlike(); - recv_data.read_skip(); // unk1 - recv_data.read_skip(); // unk2 - recv_data.read_skip(); // unk3 -} - -void WorldSession::HandleCalendarArenaTeam(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_ARENA_TEAM"); - recv_data.hexlike(); - recv_data.read_skip(); // unk -} - -void WorldSession::HandleCalendarAddEvent(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_ADD_EVENT"); - recv_data.hexlike(); - recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam - - //std::string unk1, unk2; - //recv_data >> (std::string)unk1; - //recv_data >> (std::string)unk2; - - //uint8 unk3, unk4; - //uint32 unk5, unk6, unk7, unk8, unk9, count = 0; - //recv_data >> (uint8)unk3; - //recv_data >> (uint8)unk4; - //recv_data >> (uint32)unk5; - //recv_data >> (uint32)unk6; - //recv_data >> (uint32)unk7; - //recv_data >> (uint32)unk8; - //recv_data >> (uint32)unk9; - //if (!((unk9 >> 6) & 1)) - //{ - // recv_data >> (uint32)count; - // if (count) - // { - // uint8 unk12,unk13; - // uint64 guid; - // for (int i=0; i> (uint8)unk12; - // recv_data >> (uint8)unk13; - // } - // } - //} -} - -void WorldSession::HandleCalendarUpdateEvent(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_UPDATE_EVENT"); - recv_data.hexlike(); - recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam - - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> std::string - //recv_data >> std::string - //recv_data >> uint8 - //recv_data >> uint8 - //recv_data >> uint32 - //recv_data >> uint32 - //recv_data >> uint32 - //recv_data >> uint32 - //recv_data >> uint32 -} - -void WorldSession::HandleCalendarRemoveEvent(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_REMOVE_EVENT"); - recv_data.hexlike(); - recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam - - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint32 - -} - -void WorldSession::HandleCalendarCopyEvent(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_COPY_EVENT"); - recv_data.hexlike(); - recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam - - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint32 - -} - -void WorldSession::HandleCalendarEventInvite(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_INVITE"); - recv_data.hexlike(); - recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam - - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> std::string - //recv_data >> uint8 - //recv_data >> uint8 - -} - -void WorldSession::HandleCalendarEventRsvp(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_RSVP"); - recv_data.hexlike(); - recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam - - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint32 - -} - -void WorldSession::HandleCalendarEventRemoveInvite(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_REMOVE_INVITE"); - recv_data.hexlike(); - recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam - - //recv_data.readPackGUID(guid) - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint64 -} - -void WorldSession::HandleCalendarEventStatus(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_STATUS"); - recv_data.hexlike(); - recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam - - //recv_data.readPackGUID(guid) - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint32 -} - -void WorldSession::HandleCalendarEventModeratorStatus(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_MODERATOR_STATUS"); - recv_data.hexlike(); - recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam - - //recv_data.readPackGUID(guid) - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint32 -} - -void WorldSession::HandleCalendarComplain(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_COMPLAIN"); - recv_data.hexlike(); - recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam - - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint64 -} - -void WorldSession::HandleCalendarGetNumPending(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("WORLD: CMSG_CALENDAR_GET_NUM_PENDING"); // empty - - WorldPacket data(SMSG_CALENDAR_SEND_NUM_PENDING, 4); - data << uint32(0); // 0 - no pending invites, 1 - some pending invites - SendPacket(&data); -} diff --git a/src/server/game/Chat/Channel.cpp b/src/server/game/Chat/Channel.cpp deleted file mode 100644 index 0047892972b..00000000000 --- a/src/server/game/Chat/Channel.cpp +++ /dev/null @@ -1,1102 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Channel.h" -#include "Chat.h" -#include "ObjectMgr.h" -#include "SocialMgr.h" -#include "World.h" - -Channel::Channel(const std::string& name, uint32 channel_id, uint32 Team) - : m_name(name), m_announce(true), m_moderate(false), m_channelId(channel_id), m_ownerGUID(0), m_password(""), m_flags(0), m_Team(Team) -{ - // set special flags if built-in channel - ChatChannelsEntry const* ch = GetChannelEntryFor(channel_id); - if (ch) // it's built-in channel - { - channel_id = ch->ChannelID; // built-in channel - m_announce = false; // no join/leave announces - - m_flags |= CHANNEL_FLAG_GENERAL; // for all built-in channels - - if (ch->flags & CHANNEL_DBC_FLAG_TRADE) // for trade channel - m_flags |= CHANNEL_FLAG_TRADE; - - if (ch->flags & CHANNEL_DBC_FLAG_CITY_ONLY2) // for city only channels - m_flags |= CHANNEL_FLAG_CITY; - - if (ch->flags & CHANNEL_DBC_FLAG_LFG) // for LFG channel - m_flags |= CHANNEL_FLAG_LFG; - else // for all other channels - m_flags |= CHANNEL_FLAG_NOT_LFG; - m_IsSaved = false; - } - else // it's custom channel - { - m_flags |= CHANNEL_FLAG_CUSTOM; - //load not built in channel if saved - std::string _name(name); - CharacterDatabase.escape_string(_name); - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT m_announce, m_moderate, m_public, m_password, BannedList FROM channels WHERE m_name = '%s' AND m_team = '%u'", _name.c_str(), m_Team); - if (result)//load - { - Field *fields = result->Fetch(); - m_announce = fields[0].GetBool(); - m_moderate = fields[1].GetBool(); - m_public = fields[2].GetBool(); - m_password = fields[3].GetString(); - const char* db_BannedList = fields[4].GetString(); - - m_IsSaved = true; - - if (db_BannedList) - { - Tokens tokens = StrSplit(db_BannedList, " "); - Tokens::iterator iter; - for (iter = tokens.begin(); iter != tokens.end(); ++iter) - { - uint64 banned_guid = atol((*iter).c_str()); - if (banned_guid) - { - sLog.outDebug("Channel(%s) loaded banned guid: %u",name.c_str(), banned_guid); - banned.insert(banned_guid); - } - } - } - } - else // save - { - // _name is already escaped at this point. - if (CharacterDatabase.PExecute("INSERT INTO channels (m_name, m_team, m_announce, m_moderate, m_public, m_password) " - "VALUES ('%s', '%u', '1', '0', '1', '')", _name.c_str(), m_Team)) - { - sLog.outDebug("New Channel(%s) saved", name.c_str()); - m_IsSaved = true; - } - } - } -} - -bool Channel::_UpdateStringInDB(const std::string& colName, const std::string& colValue) const -{ - // Prevent SQL-injection - std::string _name(m_name); - std::string _colValue(colValue); - CharacterDatabase.escape_string(_colValue); - CharacterDatabase.escape_string(_name); - return CharacterDatabase.PExecute("UPDATE channels SET %s = '%s' WHERE m_name = '%s' AND m_team = '%u'", - colName.c_str(), _colValue.c_str(), _name.c_str(), m_Team); -} - -bool Channel::_UpdateIntInDB(const std::string& colName, int colValue) const -{ - // Prevent SQL-injection - std::string _name(m_name); - CharacterDatabase.escape_string(_name); - return CharacterDatabase.PExecute("UPDATE channels SET %s = '%u' WHERE m_name = '%s' AND m_team = '%u'", - colName.c_str(), colValue, _name.c_str(), m_Team); -} - -void Channel::_UpdateBanListInDB() const -{ - // save banlist - if (m_IsSaved) - { - std::ostringstream banlist; - BannedList::const_iterator iter; - for (iter = banned.begin(); iter != banned.end(); ++iter) - banlist << (*iter) << " "; - std::string banListStr = banlist.str(); - if (_UpdateStringInDB("BannedList", banListStr)) - sLog.outDebug("Channel(%s) BannedList saved", m_name.c_str()); - } -} - -void Channel::Join(uint64 p, const char *pass) -{ - WorldPacket data; - if (IsOn(p)) - { - if (!IsConstant()) // non send error message for built-in channels - { - MakePlayerAlreadyMember(&data, p); - SendToOne(&data, p); - } - return; - } - - if (IsBanned(p)) - { - MakeBanned(&data); - SendToOne(&data, p); - return; - } - - if (m_password.length() > 0 && strcmp(pass, m_password.c_str())) - { - MakeWrongPassword(&data); - SendToOne(&data, p); - return; - } - - Player *plr = objmgr.GetPlayer(p); - - if (plr) - { - if (HasFlag(CHANNEL_FLAG_LFG) && - sWorld.getConfig(CONFIG_RESTRICTED_LFG_CHANNEL) && plr->GetSession()->GetSecurity() == SEC_PLAYER && plr->GetGroup()) - { - MakeNotInLfg(&data); - SendToOne(&data, p); - return; - } - - if (plr->GetGuildId() && (GetFlags() == 0x38)) - return; - - plr->JoinedChannel(this); - } - - if (m_announce && (!plr || plr->GetSession()->GetSecurity() < SEC_GAMEMASTER || !sWorld.getConfig(CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL))) - { - MakeJoined(&data, p); - SendToAll(&data); - } - - data.clear(); - - PlayerInfo pinfo; - pinfo.player = p; - pinfo.flags = MEMBER_FLAG_NONE; - players[p] = pinfo; - - MakeYouJoined(&data); - SendToOne(&data, p); - - JoinNotify(p); - - // if no owner first logged will become - if (!IsConstant() && !m_ownerGUID) - { - SetOwner(p, (players.size() > 1 ? true : false)); - players[p].SetModerator(true); - } - /* - else if (!IsConstant() && m_ownerGUID && plr && m_ownerGUID == plr->GetGUID())) - { - SetOwner(p, (players.size() > 1 ? true : false)); - players[p].SetModerator(true); - }*/ -} - -void Channel::Leave(uint64 p, bool send) -{ - if (!IsOn(p)) - { - if (send) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - } - else - { - Player *plr = objmgr.GetPlayer(p); - - if (send) - { - WorldPacket data; - MakeYouLeft(&data); - SendToOne(&data, p); - if (plr) - plr->LeftChannel(this); - data.clear(); - } - - bool changeowner = players[p].IsOwner(); - - players.erase(p); - if (m_announce && (!plr || plr->GetSession()->GetSecurity() < SEC_GAMEMASTER || !sWorld.getConfig(CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL))) - { - WorldPacket data; - MakeLeft(&data, p); - SendToAll(&data); - } - - LeaveNotify(p); - - if (changeowner) - { - uint64 newowner = !players.empty() ? players.begin()->second.player : 0; - players[newowner].SetModerator(true); - SetOwner(newowner); - } - } -} - -void Channel::KickOrBan(uint64 good, const char *badname, bool ban) -{ - AccountTypes sec = SEC_PLAYER; - Player *gplr = objmgr.GetPlayer(good); - if (gplr) - sec = gplr->GetSession()->GetSecurity(); - - if (!IsOn(good)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, good); - } - else if (!players[good].IsModerator() && sec < SEC_GAMEMASTER) - { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, good); - } - else - { - Player *bad = objmgr.GetPlayer(badname); - if (bad == NULL || !IsOn(bad->GetGUID())) - { - WorldPacket data; - MakePlayerNotFound(&data, badname); - SendToOne(&data, good); - } - else if (sec < SEC_GAMEMASTER && bad->GetGUID() == m_ownerGUID && good != m_ownerGUID) - { - WorldPacket data; - MakeNotOwner(&data); - SendToOne(&data, good); - } - else - { - bool changeowner = (m_ownerGUID == bad->GetGUID()); - - WorldPacket data; - - if (ban && !IsBanned(bad->GetGUID())) - { - banned.insert(bad->GetGUID()); - MakePlayerBanned(&data, bad->GetGUID(), good); - _UpdateBanListInDB(); - - } - else - MakePlayerKicked(&data, bad->GetGUID(), good); - - SendToAll(&data); - players.erase(bad->GetGUID()); - bad->LeftChannel(this); - - if (changeowner) - { - uint64 newowner = !players.empty() ? good : false; - players[newowner].SetModerator(true); - SetOwner(newowner); - } - } - } -} - -void Channel::UnBan(uint64 good, const char *badname) -{ - uint32 sec = 0; - Player *gplr = objmgr.GetPlayer(good); - if (gplr) - sec = gplr->GetSession()->GetSecurity(); - - if (!IsOn(good)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, good); - } - else if (!players[good].IsModerator() && sec < SEC_GAMEMASTER) - { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, good); - } - else - { - Player *bad = objmgr.GetPlayer(badname); - if (bad == NULL || !IsBanned(bad->GetGUID())) - { - WorldPacket data; - MakePlayerNotFound(&data, badname); - SendToOne(&data, good); - } - else - { - banned.erase(bad->GetGUID()); - - WorldPacket data; - MakePlayerUnbanned(&data, bad->GetGUID(), good); - SendToAll(&data); - //save banlist - _UpdateBanListInDB(); - } - } -} - -void Channel::Password(uint64 p, const char *pass) -{ - std::string plName; - uint32 sec = 0; - Player *plr = objmgr.GetPlayer(p); - if (plr) - sec = plr->GetSession()->GetSecurity(); - - ChatHandler chat(plr); - - if (!m_public && sec <= SEC_MODERATOR) - { - chat.PSendSysMessage(LANG_CHANNEL_NOT_PUBLIC); - return; - } - - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - else if (!players[p].IsModerator() && sec < SEC_GAMEMASTER) - { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, p); - } - else - { - m_password = pass; - - WorldPacket data; - MakePasswordChanged(&data, p); - SendToAll(&data); - if (m_IsSaved && _UpdateStringInDB("m_password", m_password)) - sLog.outDebug("Channel(%s) password saved", m_name.c_str()); - } -} - -void Channel::SetMode(uint64 p, const char *p2n, bool mod, bool set) -{ - Player *plr = objmgr.GetPlayer(p); - if (!plr) - return; - - uint32 sec = plr->GetSession()->GetSecurity(); - - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - else if (!players[p].IsModerator() && sec < SEC_GAMEMASTER) - { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, p); - } - else - { - Player *newp = objmgr.GetPlayer(p2n); - if (!newp) - { - WorldPacket data; - MakePlayerNotFound(&data, p2n); - SendToOne(&data, p); - return; - } - - if (p == m_ownerGUID && newp->GetGUID() == m_ownerGUID && mod) - return; - - if (!IsOn(newp->GetGUID())) - { - WorldPacket data; - MakePlayerNotFound(&data, p2n); - SendToOne(&data, p); - return; - } - - // allow make moderator from another team only if both is GMs - // at this moment this only way to show channel post for GM from another team - if ((plr->GetSession()->GetSecurity() < SEC_GAMEMASTER || newp->GetSession()->GetSecurity() < SEC_GAMEMASTER) && - plr->GetTeam() != newp->GetTeam() && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) - { - WorldPacket data; - MakePlayerNotFound(&data, p2n); - SendToOne(&data, p); - return; - } - - if (m_ownerGUID == newp->GetGUID() && m_ownerGUID != p) - { - WorldPacket data; - MakeNotOwner(&data); - SendToOne(&data, p); - return; - } - - if (mod) - SetModerator(newp->GetGUID(), set); - else - SetMute(newp->GetGUID(), set); - } -} - -void Channel::SetOwner(uint64 p, const char *newname) -{ - Player *plr = objmgr.GetPlayer(p); - if (!plr) - return; - - uint32 sec = plr->GetSession()->GetSecurity(); - - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - return; - } - - if (sec < SEC_GAMEMASTER && p != m_ownerGUID) - { - WorldPacket data; - MakeNotOwner(&data); - SendToOne(&data, p); - return; - } - - Player *newp = objmgr.GetPlayer(newname); - if (newp == NULL || !IsOn(newp->GetGUID())) - { - WorldPacket data; - MakePlayerNotFound(&data, newname); - SendToOne(&data, p); - return; - } - - if (newp->GetTeam() != plr->GetTeam() && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) - { - WorldPacket data; - MakePlayerNotFound(&data, newname); - SendToOne(&data, p); - return; - } - - players[newp->GetGUID()].SetModerator(true); - SetOwner(newp->GetGUID()); -} - -void Channel::SendWhoOwner(uint64 p) -{ - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - else - { - WorldPacket data; - MakeChannelOwner(&data); - SendToOne(&data, p); - } -} - -void Channel::List(Player* player) -{ - uint64 p = player->GetGUID(); - - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - else - { - WorldPacket data(SMSG_CHANNEL_LIST, 1+(GetName().size()+1)+1+4+players.size()*(8+1)); - data << uint8(1); // channel type? - data << GetName(); // channel name - data << uint8(GetFlags()); // channel flags? - - size_t pos = data.wpos(); - data << uint32(0); // size of list, placeholder - - uint32 gmLevelInWhoList = sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST); - - uint32 count = 0; - for (PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) - { - Player *plr = objmgr.GetPlayer(i->first); - - // PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters - // MODERATOR, GAME MASTER, ADMINISTRATOR can see all - if (plr && (player->GetSession()->GetSecurity() > SEC_PLAYER || plr->GetSession()->GetSecurity() <= gmLevelInWhoList) && - plr->IsVisibleGloballyFor(player)) - { - data << uint64(i->first); - data << uint8(i->second.flags); // flags seems to be changed... - ++count; - } - } - - data.put(pos,count); - - SendToOne(&data, p); - } -} - -void Channel::Announce(uint64 p) -{ - uint32 sec = 0; - Player *plr = objmgr.GetPlayer(p); - if (plr) - sec = plr->GetSession()->GetSecurity(); - - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - else if (!players[p].IsModerator() && sec < SEC_GAMEMASTER) - { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, p); - } - else - { - m_announce = !m_announce; - - WorldPacket data; - if (m_announce) - MakeAnnouncementsOn(&data, p); - else - MakeAnnouncementsOff(&data, p); - SendToAll(&data); - if (m_IsSaved && _UpdateIntInDB("m_announce", m_announce ? 1 : 0)) - sLog.outDebug("Channel(%s) announce saved", m_name.c_str()); - - } -} - -void Channel::Moderate(uint64 p) -{ - uint32 sec = 0; - Player *plr = objmgr.GetPlayer(p); - if (plr) - sec = plr->GetSession()->GetSecurity(); - - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - else if (!players[p].IsModerator() && sec < SEC_GAMEMASTER) - { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, p); - } - else - { - m_moderate = !m_moderate; - - WorldPacket data; - if (m_moderate) - MakeModerationOn(&data, p); - else - MakeModerationOff(&data, p); - SendToAll(&data); - if (m_IsSaved && _UpdateIntInDB("m_announce", m_announce ? 1 : 0)) - sLog.outDebug("Channel(%s) announce saved", m_name.c_str()); - } -} - -void Channel::Say(uint64 p, const char *what, uint32 lang) -{ - if (!what) - return; - if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) - lang = LANG_UNIVERSAL; - - uint32 sec = 0; - Player *plr = objmgr.GetPlayer(p); - if (plr) - sec = plr->GetSession()->GetSecurity(); - - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - else if (players[p].IsMuted()) - { - WorldPacket data; - MakeMuted(&data); - SendToOne(&data, p); - } - else if (m_moderate && !players[p].IsModerator() && sec < SEC_GAMEMASTER) - { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, p); - } - else - { - uint32 messageLength = strlen(what) + 1; - - WorldPacket data(SMSG_MESSAGECHAT, 1+4+8+4+m_name.size()+1+8+4+messageLength+1); - data << (uint8)CHAT_MSG_CHANNEL; - data << (uint32)lang; - data << p; // 2.1.0 - data << uint32(0); // 2.1.0 - data << m_name; - data << p; - data << messageLength; - data << what; - data << uint8(plr ? plr->chatTag() : 0); - - SendToAll(&data, !players[p].IsModerator() ? p : false); - } -} - -void Channel::Invite(uint64 p, const char *newname) -{ - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - return; - } - - Player *newp = objmgr.GetPlayer(newname); - if (!newp) - { - WorldPacket data; - MakePlayerNotFound(&data, newname); - SendToOne(&data, p); - return; - } - - Player *plr = objmgr.GetPlayer(p); - if (!plr) - return; - - if (newp->GetTeam() != plr->GetTeam() && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) - { - WorldPacket data; - MakeInviteWrongFaction(&data); - SendToOne(&data, p); - return; - } - - if (IsOn(newp->GetGUID())) - { - WorldPacket data; - MakePlayerAlreadyMember(&data, newp->GetGUID()); - SendToOne(&data, p); - return; - } - - WorldPacket data; - if (!newp->GetSocial()->HasIgnore(GUID_LOPART(p))) - { - MakeInvite(&data, p); - SendToOne(&data, newp->GetGUID()); - data.clear(); - } - MakePlayerInvited(&data, newp->GetName()); - SendToOne(&data, p); -} - -void Channel::SetOwner(uint64 guid, bool exclaim) -{ - if (m_ownerGUID) - { - // [] will re-add player after it possible removed - PlayerList::iterator p_itr = players.find(m_ownerGUID); - if (p_itr != players.end()) - p_itr->second.SetOwner(false); - } - - m_ownerGUID = guid; - if (m_ownerGUID) - { - uint8 oldFlag = GetPlayerFlags(m_ownerGUID); - players[m_ownerGUID].SetModerator(true); - players[m_ownerGUID].SetOwner(true); - - WorldPacket data; - MakeModeChange(&data, m_ownerGUID, oldFlag); - SendToAll(&data); - - if (exclaim) - { - MakeOwnerChanged(&data, m_ownerGUID); - SendToAll(&data); - } - if (m_IsSaved && _UpdateIntInDB("m_moderate", m_moderate ? 1 : 0)) - sLog.outDebug("Channel(%s) moderate saved", m_name.c_str()); - - } -} - -void Channel::SendToAll(WorldPacket *data, uint64 p) -{ - for (PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) - { - Player *plr = objmgr.GetPlayer(i->first); - if (plr) - { - if (!p || !plr->GetSocial()->HasIgnore(GUID_LOPART(p))) - plr->GetSession()->SendPacket(data); - } - } -} - -void Channel::SendToAllButOne(WorldPacket *data, uint64 who) -{ - for (PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) - { - if (i->first != who) - { - Player *plr = objmgr.GetPlayer(i->first); - if (plr) - plr->GetSession()->SendPacket(data); - } - } -} - -void Channel::SendToOne(WorldPacket *data, uint64 who) -{ - Player *plr = objmgr.GetPlayer(who); - if (plr) - plr->GetSession()->SendPacket(data); -} - -void Channel::Voice(uint64 /*guid1*/, uint64 /*guid2*/) -{ - -} - -void Channel::DeVoice(uint64 /*guid1*/, uint64 /*guid2*/) -{ - -} - -// done -void Channel::MakeNotifyPacket(WorldPacket *data, uint8 notify_type) -{ - data->Initialize(SMSG_CHANNEL_NOTIFY, 1+m_name.size()+1); - *data << uint8(notify_type); - *data << m_name; -} - -// done 0x00 -void Channel::MakeJoined(WorldPacket *data, uint64 guid) -{ - MakeNotifyPacket(data, CHAT_JOINED_NOTICE); - *data << uint64(guid); -} - -// done 0x01 -void Channel::MakeLeft(WorldPacket *data, uint64 guid) -{ - MakeNotifyPacket(data, CHAT_LEFT_NOTICE); - *data << uint64(guid); -} - -// done 0x02 -void Channel::MakeYouJoined(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_YOU_JOINED_NOTICE); - *data << uint8(GetFlags()); - *data << uint32(GetChannelId()); - *data << uint32(0); -} - -// done 0x03 -void Channel::MakeYouLeft(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_YOU_LEFT_NOTICE); - *data << uint32(GetChannelId()); - *data << uint8(0); // can be 0x00 and 0x01 -} - -// done 0x04 -void Channel::MakeWrongPassword(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_WRONG_PASSWORD_NOTICE); -} - -// done 0x05 -void Channel::MakeNotMember(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_NOT_MEMBER_NOTICE); -} - -// done 0x06 -void Channel::MakeNotModerator(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_NOT_MODERATOR_NOTICE); -} - -// done 0x07 -void Channel::MakePasswordChanged(WorldPacket *data, uint64 guid) -{ - MakeNotifyPacket(data, CHAT_PASSWORD_CHANGED_NOTICE); - *data << uint64(guid); -} - -// done 0x08 -void Channel::MakeOwnerChanged(WorldPacket *data, uint64 guid) -{ - MakeNotifyPacket(data, CHAT_OWNER_CHANGED_NOTICE); - *data << uint64(guid); -} - -// done 0x09 -void Channel::MakePlayerNotFound(WorldPacket *data, const std::string& name) -{ - MakeNotifyPacket(data, CHAT_PLAYER_NOT_FOUND_NOTICE); - *data << name; -} - -// done 0x0A -void Channel::MakeNotOwner(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_NOT_OWNER_NOTICE); -} - -// done 0x0B -void Channel::MakeChannelOwner(WorldPacket *data) -{ - std::string name = ""; - - if (!objmgr.GetPlayerNameByGUID(m_ownerGUID, name) || name.empty()) - name = "PLAYER_NOT_FOUND"; - - MakeNotifyPacket(data, CHAT_CHANNEL_OWNER_NOTICE); - *data << ((IsConstant() || !m_ownerGUID) ? "Nobody" : name); -} - -// done 0x0C -void Channel::MakeModeChange(WorldPacket *data, uint64 guid, uint8 oldflags) -{ - MakeNotifyPacket(data, CHAT_MODE_CHANGE_NOTICE); - *data << uint64(guid); - *data << uint8(oldflags); - *data << uint8(GetPlayerFlags(guid)); -} - -// done 0x0D -void Channel::MakeAnnouncementsOn(WorldPacket *data, uint64 guid) -{ - MakeNotifyPacket(data, CHAT_ANNOUNCEMENTS_ON_NOTICE); - *data << uint64(guid); -} - -// done 0x0E -void Channel::MakeAnnouncementsOff(WorldPacket *data, uint64 guid) -{ - MakeNotifyPacket(data, CHAT_ANNOUNCEMENTS_OFF_NOTICE); - *data << uint64(guid); -} - -// done 0x0F -void Channel::MakeModerationOn(WorldPacket *data, uint64 guid) -{ - MakeNotifyPacket(data, CHAT_MODERATION_ON_NOTICE); - *data << uint64(guid); -} - -// done 0x10 -void Channel::MakeModerationOff(WorldPacket *data, uint64 guid) -{ - MakeNotifyPacket(data, CHAT_MODERATION_OFF_NOTICE); - *data << uint64(guid); -} - -// done 0x11 -void Channel::MakeMuted(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_MUTED_NOTICE); -} - -// done 0x12 -void Channel::MakePlayerKicked(WorldPacket *data, uint64 bad, uint64 good) -{ - MakeNotifyPacket(data, CHAT_PLAYER_KICKED_NOTICE); - *data << uint64(bad); - *data << uint64(good); -} - -// done 0x13 -void Channel::MakeBanned(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_BANNED_NOTICE); -} - -// done 0x14 -void Channel::MakePlayerBanned(WorldPacket *data, uint64 bad, uint64 good) -{ - MakeNotifyPacket(data, CHAT_PLAYER_BANNED_NOTICE); - *data << uint64(bad); - *data << uint64(good); -} - -// done 0x15 -void Channel::MakePlayerUnbanned(WorldPacket *data, uint64 bad, uint64 good) -{ - MakeNotifyPacket(data, CHAT_PLAYER_UNBANNED_NOTICE); - *data << uint64(bad); - *data << uint64(good); -} - -// done 0x16 -void Channel::MakePlayerNotBanned(WorldPacket *data, uint64 guid) -{ - MakeNotifyPacket(data, CHAT_PLAYER_NOT_BANNED_NOTICE); - *data << uint64(guid); -} - -// done 0x17 -void Channel::MakePlayerAlreadyMember(WorldPacket *data, uint64 guid) -{ - MakeNotifyPacket(data, CHAT_PLAYER_ALREADY_MEMBER_NOTICE); - *data << uint64(guid); -} - -// done 0x18 -void Channel::MakeInvite(WorldPacket *data, uint64 guid) -{ - MakeNotifyPacket(data, CHAT_INVITE_NOTICE); - *data << uint64(guid); -} - -// done 0x19 -void Channel::MakeInviteWrongFaction(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_INVITE_WRONG_FACTION_NOTICE); -} - -// done 0x1A -void Channel::MakeWrongFaction(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_WRONG_FACTION_NOTICE); -} - -// done 0x1B -void Channel::MakeInvalidName(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_INVALID_NAME_NOTICE); -} - -// done 0x1C -void Channel::MakeNotModerated(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_NOT_MODERATED_NOTICE); -} - -// done 0x1D -void Channel::MakePlayerInvited(WorldPacket *data, const std::string& name) -{ - MakeNotifyPacket(data, CHAT_PLAYER_INVITED_NOTICE); - *data << name; -} - -// done 0x1E -void Channel::MakePlayerInviteBanned(WorldPacket *data, uint64 guid) -{ - MakeNotifyPacket(data, CHAT_PLAYER_INVITE_BANNED_NOTICE); - *data << uint64(guid); -} - -// done 0x1F -void Channel::MakeThrottled(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_THROTTLED_NOTICE); -} - -// done 0x20 -void Channel::MakeNotInArea(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_NOT_IN_AREA_NOTICE); -} - -// done 0x21 -void Channel::MakeNotInLfg(WorldPacket *data) -{ - MakeNotifyPacket(data, CHAT_NOT_IN_LFG_NOTICE); -} - -// done 0x22 -void Channel::MakeVoiceOn(WorldPacket *data, uint64 guid) -{ - MakeNotifyPacket(data, CHAT_VOICE_ON_NOTICE); - *data << uint64(guid); -} - -// done 0x23 -void Channel::MakeVoiceOff(WorldPacket *data, uint64 guid) -{ - MakeNotifyPacket(data, CHAT_VOICE_OFF_NOTICE); - *data << uint64(guid); -} - -void Channel::JoinNotify(uint64 guid) -{ - WorldPacket data; - - if (IsConstant()) - data.Initialize(SMSG_USERLIST_ADD, 8+1+1+4+GetName().size()+1); - else - data.Initialize(SMSG_USERLIST_UPDATE, 8+1+1+4+GetName().size()+1); - - data << uint64(guid); - data << uint8(GetPlayerFlags(guid)); - data << uint8(GetFlags()); - data << uint32(GetNumPlayers()); - data << GetName(); - SendToAll(&data); -} - -void Channel::LeaveNotify(uint64 guid) -{ - WorldPacket data(SMSG_USERLIST_REMOVE, 8+1+4+GetName().size()+1); - data << uint64(guid); - data << uint8(GetFlags()); - data << uint32(GetNumPlayers()); - data << GetName(); - SendToAll(&data); -} - diff --git a/src/server/game/Chat/Channel.h b/src/server/game/Chat/Channel.h deleted file mode 100644 index d0b5923e30e..00000000000 --- a/src/server/game/Chat/Channel.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _CHANNEL_H -#define _CHANNEL_H - -#include -#include -#include - -#include "Common.h" - -#include "Opcodes.h" -#include "Player.h" -#include "WorldPacket.h" - -enum ChatNotify -{ - CHAT_JOINED_NOTICE = 0x00, //+ "%s joined channel."; - CHAT_LEFT_NOTICE = 0x01, //+ "%s left channel."; - //CHAT_SUSPENDED_NOTICE = 0x01, // "%s left channel."; - CHAT_YOU_JOINED_NOTICE = 0x02, //+ "Joined Channel: [%s]"; -- You joined - //CHAT_YOU_CHANGED_NOTICE = 0x02, // "Changed Channel: [%s]"; - CHAT_YOU_LEFT_NOTICE = 0x03, //+ "Left Channel: [%s]"; -- You left - CHAT_WRONG_PASSWORD_NOTICE = 0x04, //+ "Wrong password for %s."; - CHAT_NOT_MEMBER_NOTICE = 0x05, //+ "Not on channel %s."; - CHAT_NOT_MODERATOR_NOTICE = 0x06, //+ "Not a moderator of %s."; - CHAT_PASSWORD_CHANGED_NOTICE = 0x07, //+ "[%s] Password changed by %s."; - CHAT_OWNER_CHANGED_NOTICE = 0x08, //+ "[%s] Owner changed to %s."; - CHAT_PLAYER_NOT_FOUND_NOTICE = 0x09, //+ "[%s] Player %s was not found."; - CHAT_NOT_OWNER_NOTICE = 0x0A, //+ "[%s] You are not the channel owner."; - CHAT_CHANNEL_OWNER_NOTICE = 0x0B, //+ "[%s] Channel owner is %s."; - CHAT_MODE_CHANGE_NOTICE = 0x0C, //? - CHAT_ANNOUNCEMENTS_ON_NOTICE = 0x0D, //+ "[%s] Channel announcements enabled by %s."; - CHAT_ANNOUNCEMENTS_OFF_NOTICE = 0x0E, //+ "[%s] Channel announcements disabled by %s."; - CHAT_MODERATION_ON_NOTICE = 0x0F, //+ "[%s] Channel moderation enabled by %s."; - CHAT_MODERATION_OFF_NOTICE = 0x10, //+ "[%s] Channel moderation disabled by %s."; - CHAT_MUTED_NOTICE = 0x11, //+ "[%s] You do not have permission to speak."; - CHAT_PLAYER_KICKED_NOTICE = 0x12, //? "[%s] Player %s kicked by %s."; - CHAT_BANNED_NOTICE = 0x13, //+ "[%s] You are banned from that channel."; - CHAT_PLAYER_BANNED_NOTICE = 0x14, //? "[%s] Player %s banned by %s."; - CHAT_PLAYER_UNBANNED_NOTICE = 0x15, //? "[%s] Player %s unbanned by %s."; - CHAT_PLAYER_NOT_BANNED_NOTICE = 0x16, //+ "[%s] Player %s is not banned."; - CHAT_PLAYER_ALREADY_MEMBER_NOTICE = 0x17, //+ "[%s] Player %s is already on the channel."; - CHAT_INVITE_NOTICE = 0x18, //+ "%2$s has invited you to join the channel '%1$s'."; - CHAT_INVITE_WRONG_FACTION_NOTICE = 0x19, //+ "Target is in the wrong alliance for %s."; - CHAT_WRONG_FACTION_NOTICE = 0x1A, //+ "Wrong alliance for %s."; - CHAT_INVALID_NAME_NOTICE = 0x1B, //+ "Invalid channel name"; - CHAT_NOT_MODERATED_NOTICE = 0x1C, //+ "%s is not moderated"; - CHAT_PLAYER_INVITED_NOTICE = 0x1D, //+ "[%s] You invited %s to join the channel"; - CHAT_PLAYER_INVITE_BANNED_NOTICE = 0x1E, //+ "[%s] %s has been banned."; - CHAT_THROTTLED_NOTICE = 0x1F, //+ "[%s] The number of messages that can be sent to this channel is limited, please wait to send another message."; - CHAT_NOT_IN_AREA_NOTICE = 0x20, //+ "[%s] You are not in the correct area for this channel."; -- The user is trying to send a chat to a zone specific channel, and they're not physically in that zone. - CHAT_NOT_IN_LFG_NOTICE = 0x21, //+ "[%s] You must be queued in looking for group before joining this channel."; -- The user must be in the looking for group system to join LFG chat channels. - CHAT_VOICE_ON_NOTICE = 0x22, //+ "[%s] Channel voice enabled by %s."; - CHAT_VOICE_OFF_NOTICE = 0x23, //+ "[%s] Channel voice disabled by %s."; -}; - -enum ChannelFlags -{ - CHANNEL_FLAG_NONE = 0x00, - CHANNEL_FLAG_CUSTOM = 0x01, - // 0x02 - CHANNEL_FLAG_TRADE = 0x04, - CHANNEL_FLAG_NOT_LFG = 0x08, - CHANNEL_FLAG_GENERAL = 0x10, - CHANNEL_FLAG_CITY = 0x20, - CHANNEL_FLAG_LFG = 0x40, - CHANNEL_FLAG_VOICE = 0x80 - // General 0x18 = 0x10 | 0x08 - // Trade 0x3C = 0x20 | 0x10 | 0x08 | 0x04 - // LocalDefence 0x18 = 0x10 | 0x08 - // GuildRecruitment 0x38 = 0x20 | 0x10 | 0x08 - // LookingForGroup 0x50 = 0x40 | 0x10 -}; - -enum ChannelDBCFlags -{ - CHANNEL_DBC_FLAG_NONE = 0x00000, - CHANNEL_DBC_FLAG_INITIAL = 0x00001, // General, Trade, LocalDefense, LFG - CHANNEL_DBC_FLAG_ZONE_DEP = 0x00002, // General, Trade, LocalDefense, GuildRecruitment - CHANNEL_DBC_FLAG_GLOBAL = 0x00004, // WorldDefense - CHANNEL_DBC_FLAG_TRADE = 0x00008, // Trade - CHANNEL_DBC_FLAG_CITY_ONLY = 0x00010, // Trade, GuildRecruitment - CHANNEL_DBC_FLAG_CITY_ONLY2 = 0x00020, // Trade, GuildRecruitment - CHANNEL_DBC_FLAG_DEFENSE = 0x10000, // LocalDefense, WorldDefense - CHANNEL_DBC_FLAG_GUILD_REQ = 0x20000, // GuildRecruitment - CHANNEL_DBC_FLAG_LFG = 0x40000 // LookingForGroup -}; - -enum ChannelMemberFlags -{ - MEMBER_FLAG_NONE = 0x00, - MEMBER_FLAG_OWNER = 0x01, - MEMBER_FLAG_MODERATOR = 0x02, - MEMBER_FLAG_VOICED = 0x04, - MEMBER_FLAG_MUTED = 0x08, - MEMBER_FLAG_CUSTOM = 0x10, - MEMBER_FLAG_MIC_MUTED = 0x20, - // 0x40 - // 0x80 -}; - -class Channel -{ - struct PlayerInfo - { - uint64 player; - uint8 flags; - - bool HasFlag(uint8 flag) { return flags & flag; } - void SetFlag(uint8 flag) { if (!HasFlag(flag)) flags |= flag; } - bool IsOwner() { return flags & MEMBER_FLAG_OWNER; } - void SetOwner(bool state) - { - if (state) flags |= MEMBER_FLAG_OWNER; - else flags &= ~MEMBER_FLAG_OWNER; - } - bool IsModerator() { return flags & MEMBER_FLAG_MODERATOR; } - void SetModerator(bool state) - { - if (state) flags |= MEMBER_FLAG_MODERATOR; - else flags &= ~MEMBER_FLAG_MODERATOR; - } - bool IsMuted() { return flags & MEMBER_FLAG_MUTED; } - void SetMuted(bool state) - { - if (state) flags |= MEMBER_FLAG_MUTED; - else flags &= ~MEMBER_FLAG_MUTED; - } - }; - - typedef std::map PlayerList; - PlayerList players; - typedef std::set BannedList; - BannedList banned; - bool m_announce; - bool m_moderate; - bool m_public; - std::string m_name; - std::string m_password; - uint8 m_flags; - uint32 m_channelId; - uint64 m_ownerGUID; - bool m_IsSaved; - - private: - // initial packet data (notify type and channel name) - void MakeNotifyPacket(WorldPacket *data, uint8 notify_type); - // type specific packet data - void MakeJoined(WorldPacket *data, uint64 guid); //+ 0x00 - void MakeLeft(WorldPacket *data, uint64 guid); //+ 0x01 - void MakeYouJoined(WorldPacket *data); //+ 0x02 - void MakeYouLeft(WorldPacket *data); //+ 0x03 - void MakeWrongPassword(WorldPacket *data); //? 0x04 - void MakeNotMember(WorldPacket *data); //? 0x05 - void MakeNotModerator(WorldPacket *data); //? 0x06 - void MakePasswordChanged(WorldPacket *data, uint64 guid); //+ 0x07 - void MakeOwnerChanged(WorldPacket *data, uint64 guid); //? 0x08 - void MakePlayerNotFound(WorldPacket *data, const std::string& name); //+ 0x09 - void MakeNotOwner(WorldPacket *data); //? 0x0A - void MakeChannelOwner(WorldPacket *data); //? 0x0B - void MakeModeChange(WorldPacket *data, uint64 guid, uint8 oldflags); //+ 0x0C - void MakeAnnouncementsOn(WorldPacket *data, uint64 guid); //+ 0x0D - void MakeAnnouncementsOff(WorldPacket *data, uint64 guid); //+ 0x0E - void MakeModerationOn(WorldPacket *data, uint64 guid); //+ 0x0F - void MakeModerationOff(WorldPacket *data, uint64 guid); //+ 0x10 - void MakeMuted(WorldPacket *data); //? 0x11 - void MakePlayerKicked(WorldPacket *data, uint64 bad, uint64 good); //? 0x12 - void MakeBanned(WorldPacket *data); //? 0x13 - void MakePlayerBanned(WorldPacket *data, uint64 bad, uint64 good); //? 0x14 - void MakePlayerUnbanned(WorldPacket *data, uint64 bad, uint64 good); //? 0x15 - void MakePlayerNotBanned(WorldPacket *data, uint64 guid); //? 0x16 - void MakePlayerAlreadyMember(WorldPacket *data, uint64 guid); //+ 0x17 - void MakeInvite(WorldPacket *data, uint64 guid); //? 0x18 - void MakeInviteWrongFaction(WorldPacket *data); //? 0x19 - void MakeWrongFaction(WorldPacket *data); //? 0x1A - void MakeInvalidName(WorldPacket *data); //? 0x1B - void MakeNotModerated(WorldPacket *data); //? 0x1C - void MakePlayerInvited(WorldPacket *data, const std::string& name); //+ 0x1D - void MakePlayerInviteBanned(WorldPacket *data, uint64 guid); //? 0x1E - void MakeThrottled(WorldPacket *data); //? 0x1F - void MakeNotInArea(WorldPacket *data); //? 0x20 - void MakeNotInLfg(WorldPacket *data); //? 0x21 - void MakeVoiceOn(WorldPacket *data, uint64 guid); //+ 0x22 - void MakeVoiceOff(WorldPacket *data, uint64 guid); //+ 0x23 - - void SendToAll(WorldPacket *data, uint64 p = 0); - void SendToAllButOne(WorldPacket *data, uint64 who); - void SendToOne(WorldPacket *data, uint64 who); - - bool IsOn(uint64 who) const { return players.find(who) != players.end(); } - bool IsBanned(uint64 guid) const { return banned.find(guid) != banned.end(); } - - bool _UpdateStringInDB(const std::string& colName, const std::string& colValue) const; - bool _UpdateIntInDB(const std::string& colName, int colValue) const; - void _UpdateBanListInDB() const; - - uint8 GetPlayerFlags(uint64 p) const - { - PlayerList::const_iterator p_itr = players.find(p); - if (p_itr == players.end()) - return 0; - - return p_itr->second.flags; - } - - void SetModerator(uint64 p, bool set) - { - if (players[p].IsModerator() != set) - { - uint8 oldFlag = GetPlayerFlags(p); - players[p].SetModerator(set); - - WorldPacket data; - MakeModeChange(&data, p, oldFlag); - SendToAll(&data); - } - } - - void SetMute(uint64 p, bool set) - { - if (players[p].IsMuted() != set) - { - uint8 oldFlag = GetPlayerFlags(p); - players[p].SetMuted(set); - - WorldPacket data; - MakeModeChange(&data, p, oldFlag); - SendToAll(&data); - } - } - - public: - uint32 m_Team; - Channel(const std::string& name, uint32 channel_id, uint32 Team = 0); - std::string GetName() const { return m_name; } - uint32 GetChannelId() const { return m_channelId; } - bool IsConstant() const { return m_channelId != 0; } - bool IsAnnounce() const { return m_announce; } - bool IsLFG() const { return GetFlags() & CHANNEL_FLAG_LFG; } - std::string GetPassword() const { return m_password; } - void SetPassword(const std::string& npassword) { m_password = npassword; } - void SetAnnounce(bool nannounce) { m_announce = nannounce; } - uint32 GetNumPlayers() const { return players.size(); } - uint8 GetFlags() const { return m_flags; } - bool HasFlag(uint8 flag) { return m_flags & flag; } - - void Join(uint64 p, const char *pass); - void Leave(uint64 p, bool send = true); - void KickOrBan(uint64 good, const char *badname, bool ban); - void Kick(uint64 good, const char *badname) { KickOrBan(good, badname, false); } - void Ban(uint64 good, const char *badname) { KickOrBan(good, badname, true); } - void UnBan(uint64 good, const char *badname); - void Password(uint64 p, const char *pass); - void SetMode(uint64 p, const char *p2n, bool mod, bool set); - void SetOwner(uint64 p, bool exclaim = true); - void SetOwner(uint64 p, const char *newname); - void SendWhoOwner(uint64 p); - void SetModerator(uint64 p, const char *newname) { SetMode(p, newname, true, true); } - void UnsetModerator(uint64 p, const char *newname) { SetMode(p, newname, true, false); } - void SetMute(uint64 p, const char *newname) { SetMode(p, newname, false, true); } - void UnsetMute(uint64 p, const char *newname) { SetMode(p, newname, false, false); } - void List(Player* p); - void Announce(uint64 p); - void Moderate(uint64 p); - void Say(uint64 p, const char *what, uint32 lang); - void Invite(uint64 p, const char *newp); - void Voice(uint64 guid1, uint64 guid2); - void DeVoice(uint64 guid1, uint64 guid2); - void JoinNotify(uint64 guid); // invisible notify - void LeaveNotify(uint64 guid); // invisible notify -}; -#endif - diff --git a/src/server/game/Chat/ChannelHandler.cpp b/src/server/game/Chat/ChannelHandler.cpp deleted file mode 100644 index 0f615579cb6..00000000000 --- a/src/server/game/Chat/ChannelHandler.cpp +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Policies/SingletonImp.h" - -#include "ObjectMgr.h" // for normalizePlayerName -#include "ChannelMgr.h" - -void WorldSession::HandleJoinChannel(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - - uint32 channel_id; - uint8 unknown1, unknown2; - std::string channelname, pass; - - recvPacket >> channel_id >> unknown1 >> unknown2; - recvPacket >> channelname; - - if (channelname.empty()) - return; - - recvPacket >> pass; - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - { - cMgr->team = _player->GetTeam(); - if (Channel *chn = cMgr->GetJoinChannel(channelname, channel_id)) - chn->Join(_player->GetGUID(), pass.c_str()); - } -} - -void WorldSession::HandleLeaveChannel(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - - uint32 unk; - std::string channelname; - recvPacket >> unk; // channel id? - recvPacket >> channelname; - - if (channelname.empty()) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - { - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->Leave(_player->GetGUID(), true); - cMgr->LeftChannel(channelname); - } -} - -void WorldSession::HandleChannelList(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname; - recvPacket >> channelname; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->List(_player); -} - -void WorldSession::HandleChannelPassword(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname, pass; - recvPacket >> channelname; - - recvPacket >> pass; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->Password(_player->GetGUID(), pass.c_str()); -} - -void WorldSession::HandleChannelSetOwner(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname, newp; - recvPacket >> channelname; - - recvPacket >> newp; - - if (!normalizePlayerName(newp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->SetOwner(_player->GetGUID(), newp.c_str()); -} - -void WorldSession::HandleChannelOwner(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname; - recvPacket >> channelname; - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->SendWhoOwner(_player->GetGUID()); -} - -void WorldSession::HandleChannelModerator(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->SetModerator(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelUnmoderator(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->UnsetModerator(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelMute(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->SetMute(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelUnmute(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->UnsetMute(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelInvite(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->Invite(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelKick(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->Kick(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelBan(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->Ban(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelUnban(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->UnBan(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelAnnouncements(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname; - recvPacket >> channelname; - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->Announce(_player->GetGUID()); -} - -void WorldSession::HandleChannelModerate(WorldPacket& recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname; - recvPacket >> channelname; - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->Moderate(_player->GetGUID()); -} - -void WorldSession::HandleChannelDisplayListQuery(WorldPacket &recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname; - recvPacket >> channelname; - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->List(_player); -} - -void WorldSession::HandleGetChannelMemberCount(WorldPacket &recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname; - recvPacket >> channelname; - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - { - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - { - WorldPacket data(SMSG_CHANNEL_MEMBER_COUNT, chn->GetName().size()+1+1+4); - data << chn->GetName(); - data << uint8(chn->GetFlags()); - data << uint32(chn->GetNumPlayers()); - SendPacket(&data); - } - } -} - -void WorldSession::HandleSetChannelWatch(WorldPacket &recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); - //recvPacket.hexlike(); - std::string channelname; - recvPacket >> channelname; - /*if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel *chn = cMgr->GetChannel(channelname, _player)) - chn->JoinNotify(_player->GetGUID());*/ -} - diff --git a/src/server/game/Chat/ChannelMgr.cpp b/src/server/game/Chat/ChannelMgr.cpp deleted file mode 100644 index f31d3ffde50..00000000000 --- a/src/server/game/Chat/ChannelMgr.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ChannelMgr.h" -#include "Policies/SingletonImp.h" -#include "World.h" - -INSTANTIATE_SINGLETON_1(AllianceChannelMgr); -INSTANTIATE_SINGLETON_1(HordeChannelMgr); - -ChannelMgr* channelMgr(uint32 team) -{ - if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) - return &Trinity::Singleton::Instance(); // cross-faction - - if (team == ALLIANCE) - return &Trinity::Singleton::Instance(); - if (team == HORDE) - return &Trinity::Singleton::Instance(); - - return NULL; -} - -ChannelMgr::~ChannelMgr() -{ - for (ChannelMap::iterator itr = channels.begin(); itr != channels.end(); ++itr) - delete itr->second; - - channels.clear(); -} - -Channel *ChannelMgr::GetJoinChannel(std::string name, uint32 channel_id) -{ - std::wstring wname; - Utf8toWStr(name,wname); - wstrToLower(wname); - - if (channels.find(wname) == channels.end()) - { - Channel *nchan = new Channel(name,channel_id, team); - channels[wname] = nchan; - return nchan; - } - - return channels[wname]; -} - -Channel *ChannelMgr::GetChannel(std::string name, Player *p, bool pkt) -{ - std::wstring wname; - Utf8toWStr(name,wname); - wstrToLower(wname); - - ChannelMap::const_iterator i = channels.find(wname); - - if (i == channels.end()) - { - if (pkt) - { - WorldPacket data; - MakeNotOnPacket(&data,name); - p->GetSession()->SendPacket(&data); - } - - return NULL; - } - else - return i->second; -} - -void ChannelMgr::LeftChannel(std::string name) -{ - std::wstring wname; - Utf8toWStr(name,wname); - wstrToLower(wname); - - ChannelMap::const_iterator i = channels.find(wname); - - if (i == channels.end()) - return; - - Channel* channel = i->second; - - if (channel->GetNumPlayers() == 0 && !channel->IsConstant()) - { - channels.erase(wname); - delete channel; - } -} - -void ChannelMgr::MakeNotOnPacket(WorldPacket *data, std::string name) -{ - data->Initialize(SMSG_CHANNEL_NOTIFY, (1+10)); // we guess size - (*data) << (uint8)0x05 << name; -} diff --git a/src/server/game/Chat/ChannelMgr.h b/src/server/game/Chat/ChannelMgr.h deleted file mode 100644 index 6f3b7c415ae..00000000000 --- a/src/server/game/Chat/ChannelMgr.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __TRINITY_CHANNELMGR_H -#define __TRINITY_CHANNELMGR_H - -#include "Common.h" -#include "Channel.h" -#include "Policies/Singleton.h" - -#include -#include - -#include "Policies/Singleton.h" - -#include "Channel.h" -#include "World.h" - -class ChannelMgr -{ - public: - uint32 team; - typedef std::map ChannelMap; - ChannelMgr() {team = 0;} - ~ChannelMgr(); - - Channel *GetJoinChannel(std::string name, uint32 channel_id); - Channel *GetChannel(std::string name, Player *p, bool pkt = true); - void LeftChannel(std::string name); - private: - ChannelMap channels; - void MakeNotOnPacket(WorldPacket *data, std::string name); -}; - -class AllianceChannelMgr : public ChannelMgr {}; -class HordeChannelMgr : public ChannelMgr {}; - -ChannelMgr* channelMgr(uint32 team); - -#endif - diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp new file mode 100644 index 00000000000..0047892972b --- /dev/null +++ b/src/server/game/Chat/Channels/Channel.cpp @@ -0,0 +1,1102 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Channel.h" +#include "Chat.h" +#include "ObjectMgr.h" +#include "SocialMgr.h" +#include "World.h" + +Channel::Channel(const std::string& name, uint32 channel_id, uint32 Team) + : m_name(name), m_announce(true), m_moderate(false), m_channelId(channel_id), m_ownerGUID(0), m_password(""), m_flags(0), m_Team(Team) +{ + // set special flags if built-in channel + ChatChannelsEntry const* ch = GetChannelEntryFor(channel_id); + if (ch) // it's built-in channel + { + channel_id = ch->ChannelID; // built-in channel + m_announce = false; // no join/leave announces + + m_flags |= CHANNEL_FLAG_GENERAL; // for all built-in channels + + if (ch->flags & CHANNEL_DBC_FLAG_TRADE) // for trade channel + m_flags |= CHANNEL_FLAG_TRADE; + + if (ch->flags & CHANNEL_DBC_FLAG_CITY_ONLY2) // for city only channels + m_flags |= CHANNEL_FLAG_CITY; + + if (ch->flags & CHANNEL_DBC_FLAG_LFG) // for LFG channel + m_flags |= CHANNEL_FLAG_LFG; + else // for all other channels + m_flags |= CHANNEL_FLAG_NOT_LFG; + m_IsSaved = false; + } + else // it's custom channel + { + m_flags |= CHANNEL_FLAG_CUSTOM; + //load not built in channel if saved + std::string _name(name); + CharacterDatabase.escape_string(_name); + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT m_announce, m_moderate, m_public, m_password, BannedList FROM channels WHERE m_name = '%s' AND m_team = '%u'", _name.c_str(), m_Team); + if (result)//load + { + Field *fields = result->Fetch(); + m_announce = fields[0].GetBool(); + m_moderate = fields[1].GetBool(); + m_public = fields[2].GetBool(); + m_password = fields[3].GetString(); + const char* db_BannedList = fields[4].GetString(); + + m_IsSaved = true; + + if (db_BannedList) + { + Tokens tokens = StrSplit(db_BannedList, " "); + Tokens::iterator iter; + for (iter = tokens.begin(); iter != tokens.end(); ++iter) + { + uint64 banned_guid = atol((*iter).c_str()); + if (banned_guid) + { + sLog.outDebug("Channel(%s) loaded banned guid: %u",name.c_str(), banned_guid); + banned.insert(banned_guid); + } + } + } + } + else // save + { + // _name is already escaped at this point. + if (CharacterDatabase.PExecute("INSERT INTO channels (m_name, m_team, m_announce, m_moderate, m_public, m_password) " + "VALUES ('%s', '%u', '1', '0', '1', '')", _name.c_str(), m_Team)) + { + sLog.outDebug("New Channel(%s) saved", name.c_str()); + m_IsSaved = true; + } + } + } +} + +bool Channel::_UpdateStringInDB(const std::string& colName, const std::string& colValue) const +{ + // Prevent SQL-injection + std::string _name(m_name); + std::string _colValue(colValue); + CharacterDatabase.escape_string(_colValue); + CharacterDatabase.escape_string(_name); + return CharacterDatabase.PExecute("UPDATE channels SET %s = '%s' WHERE m_name = '%s' AND m_team = '%u'", + colName.c_str(), _colValue.c_str(), _name.c_str(), m_Team); +} + +bool Channel::_UpdateIntInDB(const std::string& colName, int colValue) const +{ + // Prevent SQL-injection + std::string _name(m_name); + CharacterDatabase.escape_string(_name); + return CharacterDatabase.PExecute("UPDATE channels SET %s = '%u' WHERE m_name = '%s' AND m_team = '%u'", + colName.c_str(), colValue, _name.c_str(), m_Team); +} + +void Channel::_UpdateBanListInDB() const +{ + // save banlist + if (m_IsSaved) + { + std::ostringstream banlist; + BannedList::const_iterator iter; + for (iter = banned.begin(); iter != banned.end(); ++iter) + banlist << (*iter) << " "; + std::string banListStr = banlist.str(); + if (_UpdateStringInDB("BannedList", banListStr)) + sLog.outDebug("Channel(%s) BannedList saved", m_name.c_str()); + } +} + +void Channel::Join(uint64 p, const char *pass) +{ + WorldPacket data; + if (IsOn(p)) + { + if (!IsConstant()) // non send error message for built-in channels + { + MakePlayerAlreadyMember(&data, p); + SendToOne(&data, p); + } + return; + } + + if (IsBanned(p)) + { + MakeBanned(&data); + SendToOne(&data, p); + return; + } + + if (m_password.length() > 0 && strcmp(pass, m_password.c_str())) + { + MakeWrongPassword(&data); + SendToOne(&data, p); + return; + } + + Player *plr = objmgr.GetPlayer(p); + + if (plr) + { + if (HasFlag(CHANNEL_FLAG_LFG) && + sWorld.getConfig(CONFIG_RESTRICTED_LFG_CHANNEL) && plr->GetSession()->GetSecurity() == SEC_PLAYER && plr->GetGroup()) + { + MakeNotInLfg(&data); + SendToOne(&data, p); + return; + } + + if (plr->GetGuildId() && (GetFlags() == 0x38)) + return; + + plr->JoinedChannel(this); + } + + if (m_announce && (!plr || plr->GetSession()->GetSecurity() < SEC_GAMEMASTER || !sWorld.getConfig(CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL))) + { + MakeJoined(&data, p); + SendToAll(&data); + } + + data.clear(); + + PlayerInfo pinfo; + pinfo.player = p; + pinfo.flags = MEMBER_FLAG_NONE; + players[p] = pinfo; + + MakeYouJoined(&data); + SendToOne(&data, p); + + JoinNotify(p); + + // if no owner first logged will become + if (!IsConstant() && !m_ownerGUID) + { + SetOwner(p, (players.size() > 1 ? true : false)); + players[p].SetModerator(true); + } + /* + else if (!IsConstant() && m_ownerGUID && plr && m_ownerGUID == plr->GetGUID())) + { + SetOwner(p, (players.size() > 1 ? true : false)); + players[p].SetModerator(true); + }*/ +} + +void Channel::Leave(uint64 p, bool send) +{ + if (!IsOn(p)) + { + if (send) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, p); + } + } + else + { + Player *plr = objmgr.GetPlayer(p); + + if (send) + { + WorldPacket data; + MakeYouLeft(&data); + SendToOne(&data, p); + if (plr) + plr->LeftChannel(this); + data.clear(); + } + + bool changeowner = players[p].IsOwner(); + + players.erase(p); + if (m_announce && (!plr || plr->GetSession()->GetSecurity() < SEC_GAMEMASTER || !sWorld.getConfig(CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL))) + { + WorldPacket data; + MakeLeft(&data, p); + SendToAll(&data); + } + + LeaveNotify(p); + + if (changeowner) + { + uint64 newowner = !players.empty() ? players.begin()->second.player : 0; + players[newowner].SetModerator(true); + SetOwner(newowner); + } + } +} + +void Channel::KickOrBan(uint64 good, const char *badname, bool ban) +{ + AccountTypes sec = SEC_PLAYER; + Player *gplr = objmgr.GetPlayer(good); + if (gplr) + sec = gplr->GetSession()->GetSecurity(); + + if (!IsOn(good)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, good); + } + else if (!players[good].IsModerator() && sec < SEC_GAMEMASTER) + { + WorldPacket data; + MakeNotModerator(&data); + SendToOne(&data, good); + } + else + { + Player *bad = objmgr.GetPlayer(badname); + if (bad == NULL || !IsOn(bad->GetGUID())) + { + WorldPacket data; + MakePlayerNotFound(&data, badname); + SendToOne(&data, good); + } + else if (sec < SEC_GAMEMASTER && bad->GetGUID() == m_ownerGUID && good != m_ownerGUID) + { + WorldPacket data; + MakeNotOwner(&data); + SendToOne(&data, good); + } + else + { + bool changeowner = (m_ownerGUID == bad->GetGUID()); + + WorldPacket data; + + if (ban && !IsBanned(bad->GetGUID())) + { + banned.insert(bad->GetGUID()); + MakePlayerBanned(&data, bad->GetGUID(), good); + _UpdateBanListInDB(); + + } + else + MakePlayerKicked(&data, bad->GetGUID(), good); + + SendToAll(&data); + players.erase(bad->GetGUID()); + bad->LeftChannel(this); + + if (changeowner) + { + uint64 newowner = !players.empty() ? good : false; + players[newowner].SetModerator(true); + SetOwner(newowner); + } + } + } +} + +void Channel::UnBan(uint64 good, const char *badname) +{ + uint32 sec = 0; + Player *gplr = objmgr.GetPlayer(good); + if (gplr) + sec = gplr->GetSession()->GetSecurity(); + + if (!IsOn(good)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, good); + } + else if (!players[good].IsModerator() && sec < SEC_GAMEMASTER) + { + WorldPacket data; + MakeNotModerator(&data); + SendToOne(&data, good); + } + else + { + Player *bad = objmgr.GetPlayer(badname); + if (bad == NULL || !IsBanned(bad->GetGUID())) + { + WorldPacket data; + MakePlayerNotFound(&data, badname); + SendToOne(&data, good); + } + else + { + banned.erase(bad->GetGUID()); + + WorldPacket data; + MakePlayerUnbanned(&data, bad->GetGUID(), good); + SendToAll(&data); + //save banlist + _UpdateBanListInDB(); + } + } +} + +void Channel::Password(uint64 p, const char *pass) +{ + std::string plName; + uint32 sec = 0; + Player *plr = objmgr.GetPlayer(p); + if (plr) + sec = plr->GetSession()->GetSecurity(); + + ChatHandler chat(plr); + + if (!m_public && sec <= SEC_MODERATOR) + { + chat.PSendSysMessage(LANG_CHANNEL_NOT_PUBLIC); + return; + } + + if (!IsOn(p)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, p); + } + else if (!players[p].IsModerator() && sec < SEC_GAMEMASTER) + { + WorldPacket data; + MakeNotModerator(&data); + SendToOne(&data, p); + } + else + { + m_password = pass; + + WorldPacket data; + MakePasswordChanged(&data, p); + SendToAll(&data); + if (m_IsSaved && _UpdateStringInDB("m_password", m_password)) + sLog.outDebug("Channel(%s) password saved", m_name.c_str()); + } +} + +void Channel::SetMode(uint64 p, const char *p2n, bool mod, bool set) +{ + Player *plr = objmgr.GetPlayer(p); + if (!plr) + return; + + uint32 sec = plr->GetSession()->GetSecurity(); + + if (!IsOn(p)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, p); + } + else if (!players[p].IsModerator() && sec < SEC_GAMEMASTER) + { + WorldPacket data; + MakeNotModerator(&data); + SendToOne(&data, p); + } + else + { + Player *newp = objmgr.GetPlayer(p2n); + if (!newp) + { + WorldPacket data; + MakePlayerNotFound(&data, p2n); + SendToOne(&data, p); + return; + } + + if (p == m_ownerGUID && newp->GetGUID() == m_ownerGUID && mod) + return; + + if (!IsOn(newp->GetGUID())) + { + WorldPacket data; + MakePlayerNotFound(&data, p2n); + SendToOne(&data, p); + return; + } + + // allow make moderator from another team only if both is GMs + // at this moment this only way to show channel post for GM from another team + if ((plr->GetSession()->GetSecurity() < SEC_GAMEMASTER || newp->GetSession()->GetSecurity() < SEC_GAMEMASTER) && + plr->GetTeam() != newp->GetTeam() && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) + { + WorldPacket data; + MakePlayerNotFound(&data, p2n); + SendToOne(&data, p); + return; + } + + if (m_ownerGUID == newp->GetGUID() && m_ownerGUID != p) + { + WorldPacket data; + MakeNotOwner(&data); + SendToOne(&data, p); + return; + } + + if (mod) + SetModerator(newp->GetGUID(), set); + else + SetMute(newp->GetGUID(), set); + } +} + +void Channel::SetOwner(uint64 p, const char *newname) +{ + Player *plr = objmgr.GetPlayer(p); + if (!plr) + return; + + uint32 sec = plr->GetSession()->GetSecurity(); + + if (!IsOn(p)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, p); + return; + } + + if (sec < SEC_GAMEMASTER && p != m_ownerGUID) + { + WorldPacket data; + MakeNotOwner(&data); + SendToOne(&data, p); + return; + } + + Player *newp = objmgr.GetPlayer(newname); + if (newp == NULL || !IsOn(newp->GetGUID())) + { + WorldPacket data; + MakePlayerNotFound(&data, newname); + SendToOne(&data, p); + return; + } + + if (newp->GetTeam() != plr->GetTeam() && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) + { + WorldPacket data; + MakePlayerNotFound(&data, newname); + SendToOne(&data, p); + return; + } + + players[newp->GetGUID()].SetModerator(true); + SetOwner(newp->GetGUID()); +} + +void Channel::SendWhoOwner(uint64 p) +{ + if (!IsOn(p)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, p); + } + else + { + WorldPacket data; + MakeChannelOwner(&data); + SendToOne(&data, p); + } +} + +void Channel::List(Player* player) +{ + uint64 p = player->GetGUID(); + + if (!IsOn(p)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, p); + } + else + { + WorldPacket data(SMSG_CHANNEL_LIST, 1+(GetName().size()+1)+1+4+players.size()*(8+1)); + data << uint8(1); // channel type? + data << GetName(); // channel name + data << uint8(GetFlags()); // channel flags? + + size_t pos = data.wpos(); + data << uint32(0); // size of list, placeholder + + uint32 gmLevelInWhoList = sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST); + + uint32 count = 0; + for (PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + { + Player *plr = objmgr.GetPlayer(i->first); + + // PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters + // MODERATOR, GAME MASTER, ADMINISTRATOR can see all + if (plr && (player->GetSession()->GetSecurity() > SEC_PLAYER || plr->GetSession()->GetSecurity() <= gmLevelInWhoList) && + plr->IsVisibleGloballyFor(player)) + { + data << uint64(i->first); + data << uint8(i->second.flags); // flags seems to be changed... + ++count; + } + } + + data.put(pos,count); + + SendToOne(&data, p); + } +} + +void Channel::Announce(uint64 p) +{ + uint32 sec = 0; + Player *plr = objmgr.GetPlayer(p); + if (plr) + sec = plr->GetSession()->GetSecurity(); + + if (!IsOn(p)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, p); + } + else if (!players[p].IsModerator() && sec < SEC_GAMEMASTER) + { + WorldPacket data; + MakeNotModerator(&data); + SendToOne(&data, p); + } + else + { + m_announce = !m_announce; + + WorldPacket data; + if (m_announce) + MakeAnnouncementsOn(&data, p); + else + MakeAnnouncementsOff(&data, p); + SendToAll(&data); + if (m_IsSaved && _UpdateIntInDB("m_announce", m_announce ? 1 : 0)) + sLog.outDebug("Channel(%s) announce saved", m_name.c_str()); + + } +} + +void Channel::Moderate(uint64 p) +{ + uint32 sec = 0; + Player *plr = objmgr.GetPlayer(p); + if (plr) + sec = plr->GetSession()->GetSecurity(); + + if (!IsOn(p)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, p); + } + else if (!players[p].IsModerator() && sec < SEC_GAMEMASTER) + { + WorldPacket data; + MakeNotModerator(&data); + SendToOne(&data, p); + } + else + { + m_moderate = !m_moderate; + + WorldPacket data; + if (m_moderate) + MakeModerationOn(&data, p); + else + MakeModerationOff(&data, p); + SendToAll(&data); + if (m_IsSaved && _UpdateIntInDB("m_announce", m_announce ? 1 : 0)) + sLog.outDebug("Channel(%s) announce saved", m_name.c_str()); + } +} + +void Channel::Say(uint64 p, const char *what, uint32 lang) +{ + if (!what) + return; + if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) + lang = LANG_UNIVERSAL; + + uint32 sec = 0; + Player *plr = objmgr.GetPlayer(p); + if (plr) + sec = plr->GetSession()->GetSecurity(); + + if (!IsOn(p)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, p); + } + else if (players[p].IsMuted()) + { + WorldPacket data; + MakeMuted(&data); + SendToOne(&data, p); + } + else if (m_moderate && !players[p].IsModerator() && sec < SEC_GAMEMASTER) + { + WorldPacket data; + MakeNotModerator(&data); + SendToOne(&data, p); + } + else + { + uint32 messageLength = strlen(what) + 1; + + WorldPacket data(SMSG_MESSAGECHAT, 1+4+8+4+m_name.size()+1+8+4+messageLength+1); + data << (uint8)CHAT_MSG_CHANNEL; + data << (uint32)lang; + data << p; // 2.1.0 + data << uint32(0); // 2.1.0 + data << m_name; + data << p; + data << messageLength; + data << what; + data << uint8(plr ? plr->chatTag() : 0); + + SendToAll(&data, !players[p].IsModerator() ? p : false); + } +} + +void Channel::Invite(uint64 p, const char *newname) +{ + if (!IsOn(p)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, p); + return; + } + + Player *newp = objmgr.GetPlayer(newname); + if (!newp) + { + WorldPacket data; + MakePlayerNotFound(&data, newname); + SendToOne(&data, p); + return; + } + + Player *plr = objmgr.GetPlayer(p); + if (!plr) + return; + + if (newp->GetTeam() != plr->GetTeam() && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) + { + WorldPacket data; + MakeInviteWrongFaction(&data); + SendToOne(&data, p); + return; + } + + if (IsOn(newp->GetGUID())) + { + WorldPacket data; + MakePlayerAlreadyMember(&data, newp->GetGUID()); + SendToOne(&data, p); + return; + } + + WorldPacket data; + if (!newp->GetSocial()->HasIgnore(GUID_LOPART(p))) + { + MakeInvite(&data, p); + SendToOne(&data, newp->GetGUID()); + data.clear(); + } + MakePlayerInvited(&data, newp->GetName()); + SendToOne(&data, p); +} + +void Channel::SetOwner(uint64 guid, bool exclaim) +{ + if (m_ownerGUID) + { + // [] will re-add player after it possible removed + PlayerList::iterator p_itr = players.find(m_ownerGUID); + if (p_itr != players.end()) + p_itr->second.SetOwner(false); + } + + m_ownerGUID = guid; + if (m_ownerGUID) + { + uint8 oldFlag = GetPlayerFlags(m_ownerGUID); + players[m_ownerGUID].SetModerator(true); + players[m_ownerGUID].SetOwner(true); + + WorldPacket data; + MakeModeChange(&data, m_ownerGUID, oldFlag); + SendToAll(&data); + + if (exclaim) + { + MakeOwnerChanged(&data, m_ownerGUID); + SendToAll(&data); + } + if (m_IsSaved && _UpdateIntInDB("m_moderate", m_moderate ? 1 : 0)) + sLog.outDebug("Channel(%s) moderate saved", m_name.c_str()); + + } +} + +void Channel::SendToAll(WorldPacket *data, uint64 p) +{ + for (PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + { + Player *plr = objmgr.GetPlayer(i->first); + if (plr) + { + if (!p || !plr->GetSocial()->HasIgnore(GUID_LOPART(p))) + plr->GetSession()->SendPacket(data); + } + } +} + +void Channel::SendToAllButOne(WorldPacket *data, uint64 who) +{ + for (PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + { + if (i->first != who) + { + Player *plr = objmgr.GetPlayer(i->first); + if (plr) + plr->GetSession()->SendPacket(data); + } + } +} + +void Channel::SendToOne(WorldPacket *data, uint64 who) +{ + Player *plr = objmgr.GetPlayer(who); + if (plr) + plr->GetSession()->SendPacket(data); +} + +void Channel::Voice(uint64 /*guid1*/, uint64 /*guid2*/) +{ + +} + +void Channel::DeVoice(uint64 /*guid1*/, uint64 /*guid2*/) +{ + +} + +// done +void Channel::MakeNotifyPacket(WorldPacket *data, uint8 notify_type) +{ + data->Initialize(SMSG_CHANNEL_NOTIFY, 1+m_name.size()+1); + *data << uint8(notify_type); + *data << m_name; +} + +// done 0x00 +void Channel::MakeJoined(WorldPacket *data, uint64 guid) +{ + MakeNotifyPacket(data, CHAT_JOINED_NOTICE); + *data << uint64(guid); +} + +// done 0x01 +void Channel::MakeLeft(WorldPacket *data, uint64 guid) +{ + MakeNotifyPacket(data, CHAT_LEFT_NOTICE); + *data << uint64(guid); +} + +// done 0x02 +void Channel::MakeYouJoined(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_YOU_JOINED_NOTICE); + *data << uint8(GetFlags()); + *data << uint32(GetChannelId()); + *data << uint32(0); +} + +// done 0x03 +void Channel::MakeYouLeft(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_YOU_LEFT_NOTICE); + *data << uint32(GetChannelId()); + *data << uint8(0); // can be 0x00 and 0x01 +} + +// done 0x04 +void Channel::MakeWrongPassword(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_WRONG_PASSWORD_NOTICE); +} + +// done 0x05 +void Channel::MakeNotMember(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_NOT_MEMBER_NOTICE); +} + +// done 0x06 +void Channel::MakeNotModerator(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_NOT_MODERATOR_NOTICE); +} + +// done 0x07 +void Channel::MakePasswordChanged(WorldPacket *data, uint64 guid) +{ + MakeNotifyPacket(data, CHAT_PASSWORD_CHANGED_NOTICE); + *data << uint64(guid); +} + +// done 0x08 +void Channel::MakeOwnerChanged(WorldPacket *data, uint64 guid) +{ + MakeNotifyPacket(data, CHAT_OWNER_CHANGED_NOTICE); + *data << uint64(guid); +} + +// done 0x09 +void Channel::MakePlayerNotFound(WorldPacket *data, const std::string& name) +{ + MakeNotifyPacket(data, CHAT_PLAYER_NOT_FOUND_NOTICE); + *data << name; +} + +// done 0x0A +void Channel::MakeNotOwner(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_NOT_OWNER_NOTICE); +} + +// done 0x0B +void Channel::MakeChannelOwner(WorldPacket *data) +{ + std::string name = ""; + + if (!objmgr.GetPlayerNameByGUID(m_ownerGUID, name) || name.empty()) + name = "PLAYER_NOT_FOUND"; + + MakeNotifyPacket(data, CHAT_CHANNEL_OWNER_NOTICE); + *data << ((IsConstant() || !m_ownerGUID) ? "Nobody" : name); +} + +// done 0x0C +void Channel::MakeModeChange(WorldPacket *data, uint64 guid, uint8 oldflags) +{ + MakeNotifyPacket(data, CHAT_MODE_CHANGE_NOTICE); + *data << uint64(guid); + *data << uint8(oldflags); + *data << uint8(GetPlayerFlags(guid)); +} + +// done 0x0D +void Channel::MakeAnnouncementsOn(WorldPacket *data, uint64 guid) +{ + MakeNotifyPacket(data, CHAT_ANNOUNCEMENTS_ON_NOTICE); + *data << uint64(guid); +} + +// done 0x0E +void Channel::MakeAnnouncementsOff(WorldPacket *data, uint64 guid) +{ + MakeNotifyPacket(data, CHAT_ANNOUNCEMENTS_OFF_NOTICE); + *data << uint64(guid); +} + +// done 0x0F +void Channel::MakeModerationOn(WorldPacket *data, uint64 guid) +{ + MakeNotifyPacket(data, CHAT_MODERATION_ON_NOTICE); + *data << uint64(guid); +} + +// done 0x10 +void Channel::MakeModerationOff(WorldPacket *data, uint64 guid) +{ + MakeNotifyPacket(data, CHAT_MODERATION_OFF_NOTICE); + *data << uint64(guid); +} + +// done 0x11 +void Channel::MakeMuted(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_MUTED_NOTICE); +} + +// done 0x12 +void Channel::MakePlayerKicked(WorldPacket *data, uint64 bad, uint64 good) +{ + MakeNotifyPacket(data, CHAT_PLAYER_KICKED_NOTICE); + *data << uint64(bad); + *data << uint64(good); +} + +// done 0x13 +void Channel::MakeBanned(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_BANNED_NOTICE); +} + +// done 0x14 +void Channel::MakePlayerBanned(WorldPacket *data, uint64 bad, uint64 good) +{ + MakeNotifyPacket(data, CHAT_PLAYER_BANNED_NOTICE); + *data << uint64(bad); + *data << uint64(good); +} + +// done 0x15 +void Channel::MakePlayerUnbanned(WorldPacket *data, uint64 bad, uint64 good) +{ + MakeNotifyPacket(data, CHAT_PLAYER_UNBANNED_NOTICE); + *data << uint64(bad); + *data << uint64(good); +} + +// done 0x16 +void Channel::MakePlayerNotBanned(WorldPacket *data, uint64 guid) +{ + MakeNotifyPacket(data, CHAT_PLAYER_NOT_BANNED_NOTICE); + *data << uint64(guid); +} + +// done 0x17 +void Channel::MakePlayerAlreadyMember(WorldPacket *data, uint64 guid) +{ + MakeNotifyPacket(data, CHAT_PLAYER_ALREADY_MEMBER_NOTICE); + *data << uint64(guid); +} + +// done 0x18 +void Channel::MakeInvite(WorldPacket *data, uint64 guid) +{ + MakeNotifyPacket(data, CHAT_INVITE_NOTICE); + *data << uint64(guid); +} + +// done 0x19 +void Channel::MakeInviteWrongFaction(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_INVITE_WRONG_FACTION_NOTICE); +} + +// done 0x1A +void Channel::MakeWrongFaction(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_WRONG_FACTION_NOTICE); +} + +// done 0x1B +void Channel::MakeInvalidName(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_INVALID_NAME_NOTICE); +} + +// done 0x1C +void Channel::MakeNotModerated(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_NOT_MODERATED_NOTICE); +} + +// done 0x1D +void Channel::MakePlayerInvited(WorldPacket *data, const std::string& name) +{ + MakeNotifyPacket(data, CHAT_PLAYER_INVITED_NOTICE); + *data << name; +} + +// done 0x1E +void Channel::MakePlayerInviteBanned(WorldPacket *data, uint64 guid) +{ + MakeNotifyPacket(data, CHAT_PLAYER_INVITE_BANNED_NOTICE); + *data << uint64(guid); +} + +// done 0x1F +void Channel::MakeThrottled(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_THROTTLED_NOTICE); +} + +// done 0x20 +void Channel::MakeNotInArea(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_NOT_IN_AREA_NOTICE); +} + +// done 0x21 +void Channel::MakeNotInLfg(WorldPacket *data) +{ + MakeNotifyPacket(data, CHAT_NOT_IN_LFG_NOTICE); +} + +// done 0x22 +void Channel::MakeVoiceOn(WorldPacket *data, uint64 guid) +{ + MakeNotifyPacket(data, CHAT_VOICE_ON_NOTICE); + *data << uint64(guid); +} + +// done 0x23 +void Channel::MakeVoiceOff(WorldPacket *data, uint64 guid) +{ + MakeNotifyPacket(data, CHAT_VOICE_OFF_NOTICE); + *data << uint64(guid); +} + +void Channel::JoinNotify(uint64 guid) +{ + WorldPacket data; + + if (IsConstant()) + data.Initialize(SMSG_USERLIST_ADD, 8+1+1+4+GetName().size()+1); + else + data.Initialize(SMSG_USERLIST_UPDATE, 8+1+1+4+GetName().size()+1); + + data << uint64(guid); + data << uint8(GetPlayerFlags(guid)); + data << uint8(GetFlags()); + data << uint32(GetNumPlayers()); + data << GetName(); + SendToAll(&data); +} + +void Channel::LeaveNotify(uint64 guid) +{ + WorldPacket data(SMSG_USERLIST_REMOVE, 8+1+4+GetName().size()+1); + data << uint64(guid); + data << uint8(GetFlags()); + data << uint32(GetNumPlayers()); + data << GetName(); + SendToAll(&data); +} + diff --git a/src/server/game/Chat/Channels/Channel.h b/src/server/game/Chat/Channels/Channel.h new file mode 100644 index 00000000000..d0b5923e30e --- /dev/null +++ b/src/server/game/Chat/Channels/Channel.h @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _CHANNEL_H +#define _CHANNEL_H + +#include +#include +#include + +#include "Common.h" + +#include "Opcodes.h" +#include "Player.h" +#include "WorldPacket.h" + +enum ChatNotify +{ + CHAT_JOINED_NOTICE = 0x00, //+ "%s joined channel."; + CHAT_LEFT_NOTICE = 0x01, //+ "%s left channel."; + //CHAT_SUSPENDED_NOTICE = 0x01, // "%s left channel."; + CHAT_YOU_JOINED_NOTICE = 0x02, //+ "Joined Channel: [%s]"; -- You joined + //CHAT_YOU_CHANGED_NOTICE = 0x02, // "Changed Channel: [%s]"; + CHAT_YOU_LEFT_NOTICE = 0x03, //+ "Left Channel: [%s]"; -- You left + CHAT_WRONG_PASSWORD_NOTICE = 0x04, //+ "Wrong password for %s."; + CHAT_NOT_MEMBER_NOTICE = 0x05, //+ "Not on channel %s."; + CHAT_NOT_MODERATOR_NOTICE = 0x06, //+ "Not a moderator of %s."; + CHAT_PASSWORD_CHANGED_NOTICE = 0x07, //+ "[%s] Password changed by %s."; + CHAT_OWNER_CHANGED_NOTICE = 0x08, //+ "[%s] Owner changed to %s."; + CHAT_PLAYER_NOT_FOUND_NOTICE = 0x09, //+ "[%s] Player %s was not found."; + CHAT_NOT_OWNER_NOTICE = 0x0A, //+ "[%s] You are not the channel owner."; + CHAT_CHANNEL_OWNER_NOTICE = 0x0B, //+ "[%s] Channel owner is %s."; + CHAT_MODE_CHANGE_NOTICE = 0x0C, //? + CHAT_ANNOUNCEMENTS_ON_NOTICE = 0x0D, //+ "[%s] Channel announcements enabled by %s."; + CHAT_ANNOUNCEMENTS_OFF_NOTICE = 0x0E, //+ "[%s] Channel announcements disabled by %s."; + CHAT_MODERATION_ON_NOTICE = 0x0F, //+ "[%s] Channel moderation enabled by %s."; + CHAT_MODERATION_OFF_NOTICE = 0x10, //+ "[%s] Channel moderation disabled by %s."; + CHAT_MUTED_NOTICE = 0x11, //+ "[%s] You do not have permission to speak."; + CHAT_PLAYER_KICKED_NOTICE = 0x12, //? "[%s] Player %s kicked by %s."; + CHAT_BANNED_NOTICE = 0x13, //+ "[%s] You are banned from that channel."; + CHAT_PLAYER_BANNED_NOTICE = 0x14, //? "[%s] Player %s banned by %s."; + CHAT_PLAYER_UNBANNED_NOTICE = 0x15, //? "[%s] Player %s unbanned by %s."; + CHAT_PLAYER_NOT_BANNED_NOTICE = 0x16, //+ "[%s] Player %s is not banned."; + CHAT_PLAYER_ALREADY_MEMBER_NOTICE = 0x17, //+ "[%s] Player %s is already on the channel."; + CHAT_INVITE_NOTICE = 0x18, //+ "%2$s has invited you to join the channel '%1$s'."; + CHAT_INVITE_WRONG_FACTION_NOTICE = 0x19, //+ "Target is in the wrong alliance for %s."; + CHAT_WRONG_FACTION_NOTICE = 0x1A, //+ "Wrong alliance for %s."; + CHAT_INVALID_NAME_NOTICE = 0x1B, //+ "Invalid channel name"; + CHAT_NOT_MODERATED_NOTICE = 0x1C, //+ "%s is not moderated"; + CHAT_PLAYER_INVITED_NOTICE = 0x1D, //+ "[%s] You invited %s to join the channel"; + CHAT_PLAYER_INVITE_BANNED_NOTICE = 0x1E, //+ "[%s] %s has been banned."; + CHAT_THROTTLED_NOTICE = 0x1F, //+ "[%s] The number of messages that can be sent to this channel is limited, please wait to send another message."; + CHAT_NOT_IN_AREA_NOTICE = 0x20, //+ "[%s] You are not in the correct area for this channel."; -- The user is trying to send a chat to a zone specific channel, and they're not physically in that zone. + CHAT_NOT_IN_LFG_NOTICE = 0x21, //+ "[%s] You must be queued in looking for group before joining this channel."; -- The user must be in the looking for group system to join LFG chat channels. + CHAT_VOICE_ON_NOTICE = 0x22, //+ "[%s] Channel voice enabled by %s."; + CHAT_VOICE_OFF_NOTICE = 0x23, //+ "[%s] Channel voice disabled by %s."; +}; + +enum ChannelFlags +{ + CHANNEL_FLAG_NONE = 0x00, + CHANNEL_FLAG_CUSTOM = 0x01, + // 0x02 + CHANNEL_FLAG_TRADE = 0x04, + CHANNEL_FLAG_NOT_LFG = 0x08, + CHANNEL_FLAG_GENERAL = 0x10, + CHANNEL_FLAG_CITY = 0x20, + CHANNEL_FLAG_LFG = 0x40, + CHANNEL_FLAG_VOICE = 0x80 + // General 0x18 = 0x10 | 0x08 + // Trade 0x3C = 0x20 | 0x10 | 0x08 | 0x04 + // LocalDefence 0x18 = 0x10 | 0x08 + // GuildRecruitment 0x38 = 0x20 | 0x10 | 0x08 + // LookingForGroup 0x50 = 0x40 | 0x10 +}; + +enum ChannelDBCFlags +{ + CHANNEL_DBC_FLAG_NONE = 0x00000, + CHANNEL_DBC_FLAG_INITIAL = 0x00001, // General, Trade, LocalDefense, LFG + CHANNEL_DBC_FLAG_ZONE_DEP = 0x00002, // General, Trade, LocalDefense, GuildRecruitment + CHANNEL_DBC_FLAG_GLOBAL = 0x00004, // WorldDefense + CHANNEL_DBC_FLAG_TRADE = 0x00008, // Trade + CHANNEL_DBC_FLAG_CITY_ONLY = 0x00010, // Trade, GuildRecruitment + CHANNEL_DBC_FLAG_CITY_ONLY2 = 0x00020, // Trade, GuildRecruitment + CHANNEL_DBC_FLAG_DEFENSE = 0x10000, // LocalDefense, WorldDefense + CHANNEL_DBC_FLAG_GUILD_REQ = 0x20000, // GuildRecruitment + CHANNEL_DBC_FLAG_LFG = 0x40000 // LookingForGroup +}; + +enum ChannelMemberFlags +{ + MEMBER_FLAG_NONE = 0x00, + MEMBER_FLAG_OWNER = 0x01, + MEMBER_FLAG_MODERATOR = 0x02, + MEMBER_FLAG_VOICED = 0x04, + MEMBER_FLAG_MUTED = 0x08, + MEMBER_FLAG_CUSTOM = 0x10, + MEMBER_FLAG_MIC_MUTED = 0x20, + // 0x40 + // 0x80 +}; + +class Channel +{ + struct PlayerInfo + { + uint64 player; + uint8 flags; + + bool HasFlag(uint8 flag) { return flags & flag; } + void SetFlag(uint8 flag) { if (!HasFlag(flag)) flags |= flag; } + bool IsOwner() { return flags & MEMBER_FLAG_OWNER; } + void SetOwner(bool state) + { + if (state) flags |= MEMBER_FLAG_OWNER; + else flags &= ~MEMBER_FLAG_OWNER; + } + bool IsModerator() { return flags & MEMBER_FLAG_MODERATOR; } + void SetModerator(bool state) + { + if (state) flags |= MEMBER_FLAG_MODERATOR; + else flags &= ~MEMBER_FLAG_MODERATOR; + } + bool IsMuted() { return flags & MEMBER_FLAG_MUTED; } + void SetMuted(bool state) + { + if (state) flags |= MEMBER_FLAG_MUTED; + else flags &= ~MEMBER_FLAG_MUTED; + } + }; + + typedef std::map PlayerList; + PlayerList players; + typedef std::set BannedList; + BannedList banned; + bool m_announce; + bool m_moderate; + bool m_public; + std::string m_name; + std::string m_password; + uint8 m_flags; + uint32 m_channelId; + uint64 m_ownerGUID; + bool m_IsSaved; + + private: + // initial packet data (notify type and channel name) + void MakeNotifyPacket(WorldPacket *data, uint8 notify_type); + // type specific packet data + void MakeJoined(WorldPacket *data, uint64 guid); //+ 0x00 + void MakeLeft(WorldPacket *data, uint64 guid); //+ 0x01 + void MakeYouJoined(WorldPacket *data); //+ 0x02 + void MakeYouLeft(WorldPacket *data); //+ 0x03 + void MakeWrongPassword(WorldPacket *data); //? 0x04 + void MakeNotMember(WorldPacket *data); //? 0x05 + void MakeNotModerator(WorldPacket *data); //? 0x06 + void MakePasswordChanged(WorldPacket *data, uint64 guid); //+ 0x07 + void MakeOwnerChanged(WorldPacket *data, uint64 guid); //? 0x08 + void MakePlayerNotFound(WorldPacket *data, const std::string& name); //+ 0x09 + void MakeNotOwner(WorldPacket *data); //? 0x0A + void MakeChannelOwner(WorldPacket *data); //? 0x0B + void MakeModeChange(WorldPacket *data, uint64 guid, uint8 oldflags); //+ 0x0C + void MakeAnnouncementsOn(WorldPacket *data, uint64 guid); //+ 0x0D + void MakeAnnouncementsOff(WorldPacket *data, uint64 guid); //+ 0x0E + void MakeModerationOn(WorldPacket *data, uint64 guid); //+ 0x0F + void MakeModerationOff(WorldPacket *data, uint64 guid); //+ 0x10 + void MakeMuted(WorldPacket *data); //? 0x11 + void MakePlayerKicked(WorldPacket *data, uint64 bad, uint64 good); //? 0x12 + void MakeBanned(WorldPacket *data); //? 0x13 + void MakePlayerBanned(WorldPacket *data, uint64 bad, uint64 good); //? 0x14 + void MakePlayerUnbanned(WorldPacket *data, uint64 bad, uint64 good); //? 0x15 + void MakePlayerNotBanned(WorldPacket *data, uint64 guid); //? 0x16 + void MakePlayerAlreadyMember(WorldPacket *data, uint64 guid); //+ 0x17 + void MakeInvite(WorldPacket *data, uint64 guid); //? 0x18 + void MakeInviteWrongFaction(WorldPacket *data); //? 0x19 + void MakeWrongFaction(WorldPacket *data); //? 0x1A + void MakeInvalidName(WorldPacket *data); //? 0x1B + void MakeNotModerated(WorldPacket *data); //? 0x1C + void MakePlayerInvited(WorldPacket *data, const std::string& name); //+ 0x1D + void MakePlayerInviteBanned(WorldPacket *data, uint64 guid); //? 0x1E + void MakeThrottled(WorldPacket *data); //? 0x1F + void MakeNotInArea(WorldPacket *data); //? 0x20 + void MakeNotInLfg(WorldPacket *data); //? 0x21 + void MakeVoiceOn(WorldPacket *data, uint64 guid); //+ 0x22 + void MakeVoiceOff(WorldPacket *data, uint64 guid); //+ 0x23 + + void SendToAll(WorldPacket *data, uint64 p = 0); + void SendToAllButOne(WorldPacket *data, uint64 who); + void SendToOne(WorldPacket *data, uint64 who); + + bool IsOn(uint64 who) const { return players.find(who) != players.end(); } + bool IsBanned(uint64 guid) const { return banned.find(guid) != banned.end(); } + + bool _UpdateStringInDB(const std::string& colName, const std::string& colValue) const; + bool _UpdateIntInDB(const std::string& colName, int colValue) const; + void _UpdateBanListInDB() const; + + uint8 GetPlayerFlags(uint64 p) const + { + PlayerList::const_iterator p_itr = players.find(p); + if (p_itr == players.end()) + return 0; + + return p_itr->second.flags; + } + + void SetModerator(uint64 p, bool set) + { + if (players[p].IsModerator() != set) + { + uint8 oldFlag = GetPlayerFlags(p); + players[p].SetModerator(set); + + WorldPacket data; + MakeModeChange(&data, p, oldFlag); + SendToAll(&data); + } + } + + void SetMute(uint64 p, bool set) + { + if (players[p].IsMuted() != set) + { + uint8 oldFlag = GetPlayerFlags(p); + players[p].SetMuted(set); + + WorldPacket data; + MakeModeChange(&data, p, oldFlag); + SendToAll(&data); + } + } + + public: + uint32 m_Team; + Channel(const std::string& name, uint32 channel_id, uint32 Team = 0); + std::string GetName() const { return m_name; } + uint32 GetChannelId() const { return m_channelId; } + bool IsConstant() const { return m_channelId != 0; } + bool IsAnnounce() const { return m_announce; } + bool IsLFG() const { return GetFlags() & CHANNEL_FLAG_LFG; } + std::string GetPassword() const { return m_password; } + void SetPassword(const std::string& npassword) { m_password = npassword; } + void SetAnnounce(bool nannounce) { m_announce = nannounce; } + uint32 GetNumPlayers() const { return players.size(); } + uint8 GetFlags() const { return m_flags; } + bool HasFlag(uint8 flag) { return m_flags & flag; } + + void Join(uint64 p, const char *pass); + void Leave(uint64 p, bool send = true); + void KickOrBan(uint64 good, const char *badname, bool ban); + void Kick(uint64 good, const char *badname) { KickOrBan(good, badname, false); } + void Ban(uint64 good, const char *badname) { KickOrBan(good, badname, true); } + void UnBan(uint64 good, const char *badname); + void Password(uint64 p, const char *pass); + void SetMode(uint64 p, const char *p2n, bool mod, bool set); + void SetOwner(uint64 p, bool exclaim = true); + void SetOwner(uint64 p, const char *newname); + void SendWhoOwner(uint64 p); + void SetModerator(uint64 p, const char *newname) { SetMode(p, newname, true, true); } + void UnsetModerator(uint64 p, const char *newname) { SetMode(p, newname, true, false); } + void SetMute(uint64 p, const char *newname) { SetMode(p, newname, false, true); } + void UnsetMute(uint64 p, const char *newname) { SetMode(p, newname, false, false); } + void List(Player* p); + void Announce(uint64 p); + void Moderate(uint64 p); + void Say(uint64 p, const char *what, uint32 lang); + void Invite(uint64 p, const char *newp); + void Voice(uint64 guid1, uint64 guid2); + void DeVoice(uint64 guid1, uint64 guid2); + void JoinNotify(uint64 guid); // invisible notify + void LeaveNotify(uint64 guid); // invisible notify +}; +#endif + diff --git a/src/server/game/Chat/Channels/ChannelMgr.cpp b/src/server/game/Chat/Channels/ChannelMgr.cpp new file mode 100644 index 00000000000..f31d3ffde50 --- /dev/null +++ b/src/server/game/Chat/Channels/ChannelMgr.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ChannelMgr.h" +#include "Policies/SingletonImp.h" +#include "World.h" + +INSTANTIATE_SINGLETON_1(AllianceChannelMgr); +INSTANTIATE_SINGLETON_1(HordeChannelMgr); + +ChannelMgr* channelMgr(uint32 team) +{ + if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) + return &Trinity::Singleton::Instance(); // cross-faction + + if (team == ALLIANCE) + return &Trinity::Singleton::Instance(); + if (team == HORDE) + return &Trinity::Singleton::Instance(); + + return NULL; +} + +ChannelMgr::~ChannelMgr() +{ + for (ChannelMap::iterator itr = channels.begin(); itr != channels.end(); ++itr) + delete itr->second; + + channels.clear(); +} + +Channel *ChannelMgr::GetJoinChannel(std::string name, uint32 channel_id) +{ + std::wstring wname; + Utf8toWStr(name,wname); + wstrToLower(wname); + + if (channels.find(wname) == channels.end()) + { + Channel *nchan = new Channel(name,channel_id, team); + channels[wname] = nchan; + return nchan; + } + + return channels[wname]; +} + +Channel *ChannelMgr::GetChannel(std::string name, Player *p, bool pkt) +{ + std::wstring wname; + Utf8toWStr(name,wname); + wstrToLower(wname); + + ChannelMap::const_iterator i = channels.find(wname); + + if (i == channels.end()) + { + if (pkt) + { + WorldPacket data; + MakeNotOnPacket(&data,name); + p->GetSession()->SendPacket(&data); + } + + return NULL; + } + else + return i->second; +} + +void ChannelMgr::LeftChannel(std::string name) +{ + std::wstring wname; + Utf8toWStr(name,wname); + wstrToLower(wname); + + ChannelMap::const_iterator i = channels.find(wname); + + if (i == channels.end()) + return; + + Channel* channel = i->second; + + if (channel->GetNumPlayers() == 0 && !channel->IsConstant()) + { + channels.erase(wname); + delete channel; + } +} + +void ChannelMgr::MakeNotOnPacket(WorldPacket *data, std::string name) +{ + data->Initialize(SMSG_CHANNEL_NOTIFY, (1+10)); // we guess size + (*data) << (uint8)0x05 << name; +} diff --git a/src/server/game/Chat/Channels/ChannelMgr.h b/src/server/game/Chat/Channels/ChannelMgr.h new file mode 100644 index 00000000000..6f3b7c415ae --- /dev/null +++ b/src/server/game/Chat/Channels/ChannelMgr.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __TRINITY_CHANNELMGR_H +#define __TRINITY_CHANNELMGR_H + +#include "Common.h" +#include "Channel.h" +#include "Policies/Singleton.h" + +#include +#include + +#include "Policies/Singleton.h" + +#include "Channel.h" +#include "World.h" + +class ChannelMgr +{ + public: + uint32 team; + typedef std::map ChannelMap; + ChannelMgr() {team = 0;} + ~ChannelMgr(); + + Channel *GetJoinChannel(std::string name, uint32 channel_id); + Channel *GetChannel(std::string name, Player *p, bool pkt = true); + void LeftChannel(std::string name); + private: + ChannelMap channels; + void MakeNotOnPacket(WorldPacket *data, std::string name); +}; + +class AllianceChannelMgr : public ChannelMgr {}; +class HordeChannelMgr : public ChannelMgr {}; + +ChannelMgr* channelMgr(uint32 team); + +#endif + diff --git a/src/server/game/Chat/ChatHandler.cpp b/src/server/game/Chat/ChatHandler.cpp deleted file mode 100644 index 88e2b5473a5..00000000000 --- a/src/server/game/Chat/ChatHandler.cpp +++ /dev/null @@ -1,756 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "ObjectAccessor.h" -#include "ObjectMgr.h" -#include "World.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Database/DatabaseEnv.h" - -#include "CellImpl.h" -#include "Chat.h" -#include "ChannelMgr.h" -#include "GridNotifiersImpl.h" -#include "Group.h" -#include "Guild.h" -#include "Language.h" -#include "Log.h" -#include "Opcodes.h" -#include "Player.h" -#include "SpellAuras.h" -#include "SpellAuraEffects.h" -#include "Util.h" - -bool WorldSession::processChatmessageFurtherAfterSecurityChecks(std::string& msg, uint32 lang) -{ - if (lang != LANG_ADDON) - { - // strip invisible characters for non-addon messages - if (sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) - stripLineInvisibleChars(msg); - - if (sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) && GetSecurity() < SEC_MODERATOR - && !ChatHandler(this).isValidChatMessage(msg.c_str())) - { - sLog.outError("Player %s (GUID: %u) sent a chatmessage with an invalid link: %s", GetPlayer()->GetName(), - GetPlayer()->GetGUIDLow(), msg.c_str()); - if (sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK)) - KickPlayer(); - return false; - } - } - - return true; -} - -void WorldSession::HandleMessagechatOpcode(WorldPacket & recv_data) -{ - uint32 type; - uint32 lang; - - recv_data >> type; - recv_data >> lang; - - if (type >= MAX_CHAT_MSG_TYPE) - { - sLog.outError("CHAT: Wrong message type received: %u", type); - return; - } - - //sLog.outDebug("CHAT: packet received. type %u, lang %u", type, lang); - - // prevent talking at unknown language (cheating) - LanguageDesc const* langDesc = GetLanguageDescByID(lang); - if (!langDesc) - { - SendNotification(LANG_UNKNOWN_LANGUAGE); - return; - } - if (langDesc->skill_id != 0 && !_player->HasSkill(langDesc->skill_id)) - { - // also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language) - Unit::AuraEffectList const& langAuras = _player->GetAuraEffectsByType(SPELL_AURA_COMPREHEND_LANGUAGE); - bool foundAura = false; - for (Unit::AuraEffectList::const_iterator i = langAuras.begin(); i != langAuras.end(); ++i) - { - if ((*i)->GetMiscValue() == int32(lang)) - { - foundAura = true; - break; - } - } - if (!foundAura) - { - SendNotification(LANG_NOT_LEARNED_LANGUAGE); - return; - } - } - - if (lang == LANG_ADDON) - { - if (sWorld.getConfig(CONFIG_CHATLOG_ADDON)) - { - std::string msg = ""; - recv_data >> msg; - - if (msg.empty()) - { - sLog.outDebug("Player %s send empty addon msg", GetPlayer()->GetName()); - return; - } - - sLog.outChat("[ADDON] Player %s sends: %s", - GetPlayer()->GetName(), msg.c_str()); - } - - // Disabled addon channel? - if (!sWorld.getConfig(CONFIG_ADDON_CHANNEL)) - return; - } - // LANG_ADDON should not be changed nor be affected by flood control - else - { - // send in universal language if player in .gmon mode (ignore spell effects) - if (_player->isGameMaster()) - lang = LANG_UNIVERSAL; - else - { - // send in universal language in two side iteration allowed mode - if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT)) - lang = LANG_UNIVERSAL; - else - { - switch(type) - { - case CHAT_MSG_PARTY: - case CHAT_MSG_RAID: - case CHAT_MSG_RAID_LEADER: - case CHAT_MSG_RAID_WARNING: - // allow two side chat at group channel if two side group allowed - if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP)) - lang = LANG_UNIVERSAL; - break; - case CHAT_MSG_GUILD: - case CHAT_MSG_OFFICER: - // allow two side chat at guild channel if two side guild allowed - if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) - lang = LANG_UNIVERSAL; - break; - } - } - - // but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used) - Unit::AuraEffectList const& ModLangAuras = _player->GetAuraEffectsByType(SPELL_AURA_MOD_LANGUAGE); - if (!ModLangAuras.empty()) - lang = ModLangAuras.front()->GetMiscValue(); - } - - if (!_player->CanSpeak()) - { - std::string timeStr = secsToTimeString(m_muteTime - time(NULL)); - SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING),timeStr.c_str()); - return; - } - - if (type != CHAT_MSG_AFK && type != CHAT_MSG_DND) - GetPlayer()->UpdateSpeakTime(); - } - - if (GetPlayer()->HasAura(1852) && type != CHAT_MSG_WHISPER) - { - std::string msg=""; - recv_data >> msg; - - SendNotification(GetTrinityString(LANG_GM_SILENCE), GetPlayer()->GetName()); - return; - } - - switch(type) - { - case CHAT_MSG_SAY: - case CHAT_MSG_EMOTE: - case CHAT_MSG_YELL: - { - std::string msg; - recv_data >> msg; - - if (msg.empty()) - break; - - if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) - break; - - if (_player->getLevel() < sWorld.getConfig(CONFIG_CHAT_SAY_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_SAY_REQ), sWorld.getConfig(CONFIG_CHAT_SAY_LEVEL_REQ)); - return; - } - - if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) - return; - - if (msg.empty()) - break; - - if (type == CHAT_MSG_SAY) - GetPlayer()->Say(msg, lang); - else if (type == CHAT_MSG_EMOTE) - GetPlayer()->TextEmote(msg); - else if (type == CHAT_MSG_YELL) - GetPlayer()->Yell(msg, lang); - } break; - - case CHAT_MSG_WHISPER: - { - std::string to, msg; - recv_data >> to; - recv_data >> msg; - - if (_player->getLevel() < sWorld.getConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_WHISPER_REQ), sWorld.getConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ)); - return; - } - - if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) - return; - - if (msg.empty()) - break; - - if (!normalizePlayerName(to)) - { - SendPlayerNotFoundNotice(to); - break; - } - - Player *player = objmgr.GetPlayer(to.c_str()); - uint32 tSecurity = GetSecurity(); - uint32 pSecurity = player ? player->GetSession()->GetSecurity() : SEC_PLAYER; - if (!player || (tSecurity == SEC_PLAYER && pSecurity > SEC_PLAYER && !player->isAcceptWhispers())) - { - SendPlayerNotFoundNotice(to); - return; - } - - if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT) && tSecurity == SEC_PLAYER && pSecurity == SEC_PLAYER) - { - uint32 sidea = GetPlayer()->GetTeam(); - uint32 sideb = player->GetTeam(); - if (sidea != sideb) - { - SendWrongFactionNotice(); - return; - } - } - - if (GetPlayer()->HasAura(1852) && !player->isGameMaster()) - { - SendNotification(GetTrinityString(LANG_GM_SILENCE), GetPlayer()->GetName()); - return; - } - - GetPlayer()->Whisper(msg, lang, player->GetGUID()); - } break; - - case CHAT_MSG_PARTY: - case CHAT_MSG_PARTY_LEADER: - { - std::string msg; - recv_data >> msg; - - if (msg.empty()) - break; - - if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) - break; - - if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) - return; - - if (msg.empty()) - break; - - // if player is in battleground, he cannot say to battleground members by /p - Group *group = GetPlayer()->GetOriginalGroup(); - if (!group) - { - group = _player->GetGroup(); - if (!group || group->isBGGroup()) - return; - } - - if ((type == CHAT_MSG_PARTY_LEADER) && !group->IsLeader(_player->GetGUID())) - return; - - WorldPacket data; - ChatHandler::FillMessageData(&data, this, type, lang, NULL, 0, msg.c_str(), NULL); - group->BroadcastPacket(&data, false, group->GetMemberGroup(GetPlayer()->GetGUID())); - - if (sWorld.getConfig(CONFIG_CHATLOG_PARTY)) - sLog.outChat("[PARTY] Player %s tells group with leader %s: %s", - GetPlayer()->GetName(), group->GetLeaderName(), msg.c_str()); - } break; - - case CHAT_MSG_GUILD: - { - std::string msg; - recv_data >> msg; - - if (msg.empty()) - break; - - if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) - break; - - if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) - return; - - if (msg.empty()) - break; - - if (GetPlayer()->GetGuildId()) - { - Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - - if (guild) - guild->BroadcastToGuild(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); - - if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHATLOG_GUILD)) - { - sLog.outChat("[GUILD] Player %s tells guild %s: %s", - GetPlayer()->GetName(), guild->GetName().c_str(), msg.c_str()); - } - else if (lang == LANG_ADDON && sWorld.getConfig(CONFIG_CHATLOG_ADDON)) - { - sLog.outChat("[ADDON] Player %s sends to guild %s: %s", - GetPlayer()->GetName(), guild->GetName().c_str(), msg.c_str()); - } - } - - break; - } - case CHAT_MSG_OFFICER: - { - std::string msg; - recv_data >> msg; - - if (msg.empty()) - break; - - if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) - break; - - if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) - return; - - if (msg.empty()) - break; - - if (GetPlayer()->GetGuildId()) - { - Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - - if (guild) - guild->BroadcastToOfficers(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); - - if (sWorld.getConfig(CONFIG_CHATLOG_GUILD)) - sLog.outChat("[OFFICER] Player %s tells guild %s officers: %s", - GetPlayer()->GetName(), guild->GetName().c_str(), msg.c_str()); - } - break; - } - case CHAT_MSG_RAID: - { - std::string msg; - recv_data >> msg; - - if (msg.empty()) - break; - - if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) - break; - - if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) - return; - - if (msg.empty()) - break; - - // if player is in battleground, he cannot say to battleground members by /ra - Group *group = GetPlayer()->GetOriginalGroup(); - if (!group) - { - group = GetPlayer()->GetGroup(); - if (!group || group->isBGGroup() || !group->isRaidGroup()) - return; - } - - WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, "", 0, msg.c_str(), NULL); - group->BroadcastPacket(&data, false); - - if (sWorld.getConfig(CONFIG_CHATLOG_RAID)) - sLog.outChat("[RAID] Player %s tells raid with leader %s: %s", - GetPlayer()->GetName(), group->GetLeaderName(), msg.c_str()); - } break; - case CHAT_MSG_RAID_LEADER: - { - std::string msg; - recv_data >> msg; - - if (msg.empty()) - break; - - if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) - break; - - if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) - return; - - if (msg.empty()) - break; - - // if player is in battleground, he cannot say to battleground members by /ra - Group *group = GetPlayer()->GetOriginalGroup(); - if (!group) - { - group = GetPlayer()->GetGroup(); - if (!group || group->isBGGroup() || !group->isRaidGroup() || !group->IsLeader(_player->GetGUID())) - return; - } - - WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, "", 0, msg.c_str(), NULL); - group->BroadcastPacket(&data, false); - - if (sWorld.getConfig(CONFIG_CHATLOG_RAID)) - sLog.outChat("[RAID] Leader player %s tells raid: %s", - GetPlayer()->GetName(), msg.c_str()); - } break; - case CHAT_MSG_RAID_WARNING: - { - std::string msg; - recv_data >> msg; - - if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) - return; - - if (msg.empty()) - break; - - Group *group = GetPlayer()->GetGroup(); - if (!group || !group->isRaidGroup() || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())) || group->isBGGroup()) - return; - - WorldPacket data; - //in battleground, raid warning is sent only to players in battleground - code is ok - ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, "", 0, msg.c_str(), NULL); - group->BroadcastPacket(&data, false); - - if (sWorld.getConfig(CONFIG_CHATLOG_RAID)) - sLog.outChat("[RAID] Leader player %s warns raid with: %s", - GetPlayer()->GetName(), msg.c_str()); - } break; - - case CHAT_MSG_BATTLEGROUND: - { - std::string msg; - recv_data >> msg; - - if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) - return; - - if (msg.empty()) - break; - - //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() - Group *group = GetPlayer()->GetGroup(); - if (!group || !group->isBGGroup()) - return; - - WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, "", 0, msg.c_str(), NULL); - group->BroadcastPacket(&data, false); - - if (sWorld.getConfig(CONFIG_CHATLOG_BGROUND)) - sLog.outChat("[BATTLEGROUND] Player %s tells battleground with leader %s: %s", - GetPlayer()->GetName(), group->GetLeaderName(), msg.c_str()); - } break; - - case CHAT_MSG_BATTLEGROUND_LEADER: - { - std::string msg; - recv_data >> msg; - - if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) - return; - - if (msg.empty()) - break; - - // battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() - Group *group = GetPlayer()->GetGroup(); - if (!group || !group->isBGGroup() || !group->IsLeader(GetPlayer()->GetGUID())) - return; - - WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, "", 0, msg.c_str(), NULL); - group->BroadcastPacket(&data, false); - - if (sWorld.getConfig(CONFIG_CHATLOG_BGROUND)) - sLog.outChat("[RAID] Leader player %s tells battleground: %s", - GetPlayer()->GetName(), msg.c_str()); - } break; - - case CHAT_MSG_CHANNEL: - { - std::string channel, msg; - recv_data >> channel; - recv_data >> msg; - - if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) - return; - - if (_player->getLevel() < sWorld.getConfig(CONFIG_CHAT_CHANNEL_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_CHANNEL_REQ), sWorld.getConfig(CONFIG_CHAT_CHANNEL_LEVEL_REQ)); - return; - } - - if (msg.empty()) - break; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - { - - if (Channel *chn = cMgr->GetChannel(channel, _player)) - { - chn->Say(_player->GetGUID(), msg.c_str(), lang); - - if ((chn->HasFlag(CHANNEL_FLAG_TRADE) || - chn->HasFlag(CHANNEL_FLAG_GENERAL) || - chn->HasFlag(CHANNEL_FLAG_CITY) || - chn->HasFlag(CHANNEL_FLAG_LFG)) && - sWorld.getConfig(CONFIG_CHATLOG_SYSCHAN)) - sLog.outChat("[SYSCHAN] Player %s tells channel %s: %s", - GetPlayer()->GetName(), chn->GetName().c_str(), msg.c_str()); - else if (sWorld.getConfig(CONFIG_CHATLOG_CHANNEL)) - sLog.outChat("[CHANNEL] Player %s tells channel %s: %s", - GetPlayer()->GetName(), chn->GetName().c_str(), msg.c_str()); - } - } - } break; - - case CHAT_MSG_AFK: - { - std::string msg; - recv_data >> msg; - - if ((msg.empty() || !_player->isAFK()) && !_player->isInCombat()) - { - if (!_player->isAFK()) - { - if (msg.empty()) - msg = GetTrinityString(LANG_PLAYER_AFK_DEFAULT); - _player->afkMsg = msg; - } - _player->ToggleAFK(); - if (_player->isAFK() && _player->isDND()) - _player->ToggleDND(); - } - } break; - - case CHAT_MSG_DND: - { - std::string msg; - recv_data >> msg; - - if (msg.empty() || !_player->isDND()) - { - if (!_player->isDND()) - { - if (msg.empty()) - msg = GetTrinityString(LANG_PLAYER_DND_DEFAULT); - _player->dndMsg = msg; - } - _player->ToggleDND(); - if (_player->isDND() && _player->isAFK()) - _player->ToggleAFK(); - } - } break; - - default: - sLog.outError("CHAT: unknown message type %u, lang: %u", type, lang); - break; - } -} - -void WorldSession::HandleEmoteOpcode(WorldPacket & recv_data) -{ - if (!GetPlayer()->isAlive()) - return; - - uint32 emote; - recv_data >> emote; - GetPlayer()->HandleEmoteCommand(emote); -} - -namespace Trinity -{ - class EmoteChatBuilder - { - public: - EmoteChatBuilder(Player const& pl, uint32 text_emote, uint32 emote_num, Unit const* target) - : i_player(pl), i_text_emote(text_emote), i_emote_num(emote_num), i_target(target) {} - - void operator()(WorldPacket& data, int32 loc_idx) - { - char const* nam = i_target ? i_target->GetNameForLocaleIdx(loc_idx) : NULL; - uint32 namlen = (nam ? strlen(nam) : 0) + 1; - - data.Initialize(SMSG_TEXT_EMOTE, (20+namlen)); - data << i_player.GetGUID(); - data << (uint32)i_text_emote; - data << i_emote_num; - data << (uint32)namlen; - if (namlen > 1) - data.append(nam, namlen); - else - data << (uint8)0x00; - } - - private: - Player const& i_player; - uint32 i_text_emote; - uint32 i_emote_num; - Unit const* i_target; - }; -} // namespace Trinity - -void WorldSession::HandleTextEmoteOpcode(WorldPacket & recv_data) -{ - if (!GetPlayer()->isAlive()) - return; - - if (!GetPlayer()->CanSpeak()) - { - std::string timeStr = secsToTimeString(m_muteTime - time(NULL)); - SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING),timeStr.c_str()); - return; - } - - uint32 text_emote, emoteNum; - uint64 guid; - - recv_data >> text_emote; - recv_data >> emoteNum; - recv_data >> guid; - - EmotesTextEntry const *em = sEmotesTextStore.LookupEntry(text_emote); - if (!em) - return; - - uint32 emote_anim = em->textid; - - switch(emote_anim) - { - case EMOTE_STATE_SLEEP: - case EMOTE_STATE_SIT: - case EMOTE_STATE_KNEEL: - case EMOTE_ONESHOT_NONE: - break; - default: - GetPlayer()->HandleEmoteCommand(emote_anim); - break; - } - - Unit* unit = ObjectAccessor::GetUnit(*_player, guid); - - CellPair p = Trinity::ComputeCellPair(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY()); - - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - Trinity::EmoteChatBuilder emote_builder(*GetPlayer(), text_emote, emoteNum, unit); - Trinity::LocalizedPacketDo emote_do(emote_builder); - Trinity::PlayerDistWorker > emote_worker(GetPlayer(), sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), emote_do); - TypeContainerVisitor >, WorldTypeMapContainer> message(emote_worker); - cell.Visit(p, message, *GetPlayer()->GetMap(), *GetPlayer(), sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE)); - - GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit); - - //Send scripted event call - if (unit && unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->AI()) - ((Creature*)unit)->AI()->ReceiveEmote(GetPlayer(), text_emote); -} - -void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data) -{ - uint64 iguid; - uint8 unk; - //sLog.outDebug("WORLD: Received CMSG_CHAT_IGNORED"); - - recv_data >> iguid; - recv_data >> unk; // probably related to spam reporting - - Player *player = objmgr.GetPlayer(iguid); - if (!player || !player->GetSession()) - return; - - WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_IGNORED, LANG_UNIVERSAL, NULL, GetPlayer()->GetGUID(), GetPlayer()->GetName(), NULL); - player->GetSession()->SendPacket(&data); -} - -void WorldSession::HandleChannelDeclineInvite(WorldPacket &recvPacket) -{ - sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); -} - -void WorldSession::SendPlayerNotFoundNotice(std::string name) -{ - WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, name.size()+1); - data << name; - SendPacket(&data); -} - -void WorldSession::SendPlayerAmbiguousNotice(std::string name) -{ - WorldPacket data(SMSG_CHAT_PLAYER_AMBIGUOUS, name.size()+1); - data << name; - SendPacket(&data); -} - -void WorldSession::SendWrongFactionNotice() -{ - WorldPacket data(SMSG_CHAT_WRONG_FACTION, 0); - SendPacket(&data); -} - -void WorldSession::SendChatRestrictedNotice(ChatRestrictionType restriction) -{ - WorldPacket data(SMSG_CHAT_RESTRICTED, 1); - data << uint8(restriction); - SendPacket(&data); -} diff --git a/src/server/game/Chat/Commands/Debugcmds.cpp b/src/server/game/Chat/Commands/Debugcmds.cpp new file mode 100644 index 00000000000..ee8c623c3d0 --- /dev/null +++ b/src/server/game/Chat/Commands/Debugcmds.cpp @@ -0,0 +1,1127 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "WorldPacket.h" +#include "Vehicle.h" +#include "Player.h" +#include "Opcodes.h" +#include "Chat.h" +#include "Log.h" +#include "Unit.h" +#include "GossipDef.h" +#include "Language.h" +#include "BattleGroundMgr.h" +#include +#include "ObjectMgr.h" +#include "Cell.h" +#include "CellImpl.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "SpellMgr.h" +#include "ScriptMgr.h" + +bool ChatHandler::HandleDebugSendSpellFailCommand(const char* args) +{ + if (!*args) + return false; + + char* px = strtok((char*)args, " "); + if (!px) + return false; + + uint8 failnum = (uint8)atoi(px); + if (failnum == 0 && *px != '0') + return false; + + char* p1 = strtok(NULL, " "); + uint8 failarg1 = p1 ? (uint8)atoi(p1) : 0; + + char* p2 = strtok(NULL, " "); + uint8 failarg2 = p2 ? (uint8)atoi(p2) : 0; + + WorldPacket data(SMSG_CAST_FAILED, 5); + data << uint8(0); + data << uint32(133); + data << uint8(failnum); + if (p1 || p2) + data << uint32(failarg1); + if (p2) + data << uint32(failarg2); + + m_session->SendPacket(&data); + + return true; +} + +bool ChatHandler::HandleDebugSendPoiCommand(const char* args) +{ + if (!*args) + return false; + + Player *pPlayer = m_session->GetPlayer(); + Unit* target = getSelectedUnit(); + if (!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + return true; + } + + char* icon_text = strtok((char*)args, " "); + char* flags_text = strtok(NULL, " "); + if (!icon_text || !flags_text) + return false; + + uint32 icon = atol(icon_text); + uint32 flags = atol(flags_text); + + sLog.outDetail("Command : POI, NPC = %u, icon = %u flags = %u", target->GetGUIDLow(), icon,flags); + pPlayer->PlayerTalkClass->SendPointOfInterest(target->GetPositionX(), target->GetPositionY(), Poi_Icon(icon), flags, 30, "Test POI"); + return true; +} + +bool ChatHandler::HandleDebugSendEquipErrorCommand(const char* args) +{ + if (!*args) + return false; + + uint8 msg = atoi(args); + m_session->GetPlayer()->SendEquipError(msg, 0, 0); + return true; +} + +bool ChatHandler::HandleDebugSendSellErrorCommand(const char* args) +{ + if (!*args) + return false; + + uint8 msg = atoi(args); + m_session->GetPlayer()->SendSellError(msg, 0, 0, 0); + return true; +} + +bool ChatHandler::HandleDebugSendBuyErrorCommand(const char* args) +{ + if (!*args) + return false; + + uint8 msg = atoi(args); + m_session->GetPlayer()->SendBuyError(msg, 0, 0, 0); + return true; +} + +bool ChatHandler::HandleDebugSendOpcodeCommand(const char* /*args*/) +{ + Unit *unit = getSelectedUnit(); + Player *player = NULL; + if (!unit || (unit->GetTypeId() != TYPEID_PLAYER)) + player = m_session->GetPlayer(); + else + player = (Player*)unit; + if (!unit) unit = player; + + std::ifstream ifs("opcode.txt"); + if (ifs.bad()) + return false; + + uint32 opcode; + ifs >> opcode; + + WorldPacket data(opcode, 0); + + while (!ifs.eof()) + { + std::string type; + ifs >> type; + + if (type == "") + break; + + if (type == "uint8") + { + uint16 val1; + ifs >> val1; + data << uint8(val1); + } + else if (type == "uint16") + { + uint16 val2; + ifs >> val2; + data << val2; + } + else if (type == "uint32") + { + uint32 val3; + ifs >> val3; + data << val3; + } + else if (type == "uint64") + { + uint64 val4; + ifs >> val4; + data << val4; + } + else if (type == "float") + { + float val5; + ifs >> val5; + data << val5; + } + else if (type == "string") + { + std::string val6; + ifs >> val6; + data << val6; + } + else if (type == "appitsguid") + { + data.append(unit->GetPackGUID()); + } + else if (type == "appmyguid") + { + data.append(player->GetPackGUID()); + } + else if (type == "appgoguid") + { + GameObject *obj = GetNearbyGameObject(); + if (!obj) + { + PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, 0); + SetSentErrorMessage(true); + ifs.close(); + return false; + } + data.append(obj->GetPackGUID()); + } + else if (type == "goguid") + { + GameObject *obj = GetNearbyGameObject(); + if (!obj) + { + PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, 0); + SetSentErrorMessage(true); + ifs.close(); + return false; + } + data << uint64(obj->GetGUID()); + } + else if (type == "myguid") + { + data << uint64(player->GetGUID()); + } + else if (type == "itsguid") + { + data << uint64(unit->GetGUID()); + } + else if (type == "pos") + { + data << unit->GetPositionX(); + data << unit->GetPositionY(); + data << unit->GetPositionZ(); + } + else if (type == "mypos") + { + data << player->GetPositionX(); + data << player->GetPositionY(); + data << player->GetPositionZ(); + } + else + { + sLog.outDebug("Sending opcode: unknown type '%s'", type.c_str()); + break; + } + } + ifs.close(); + sLog.outDebug("Sending opcode %u", data.GetOpcode()); + data.hexlike(); + player->GetSession()->SendPacket(&data); + PSendSysMessage(LANG_COMMAND_OPCODESENT, data.GetOpcode(), unit->GetName()); + return true; +} + +bool ChatHandler::HandleDebugUpdateWorldStateCommand(const char* args) +{ + char* w = strtok((char*)args, " "); + char* s = strtok(NULL, " "); + + if (!w || !s) + return false; + + uint32 world = (uint32)atoi(w); + uint32 state = (uint32)atoi(s); + m_session->GetPlayer()->SendUpdateWorldState(world, state); + return true; +} + +bool ChatHandler::HandleDebugPlayCinematicCommand(const char* args) +{ + // USAGE: .debug play cinematic #cinematicid + // #cinematicid - ID decimal number from CinemaicSequences.dbc (1st column) + if (!*args) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + uint32 dwId = atoi((char*)args); + + if (!sCinematicSequencesStore.LookupEntry(dwId)) + { + PSendSysMessage(LANG_CINEMATIC_NOT_EXIST, dwId); + SetSentErrorMessage(true); + return false; + } + + m_session->GetPlayer()->SendCinematicStart(dwId); + return true; +} + +bool ChatHandler::HandleDebugPlayMovieCommand(const char* args) +{ + // USAGE: .debug play movie #movieid + // #movieid - ID decimal number from Movie.dbc (1st column) + if (!*args) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + uint32 dwId = atoi((char*)args); + + if (!sMovieStore.LookupEntry(dwId)) + { + PSendSysMessage(LANG_MOVIE_NOT_EXIST, dwId); + SetSentErrorMessage(true); + return false; + } + + m_session->GetPlayer()->SendMovieStart(dwId); + return true; +} + +//Play sound +bool ChatHandler::HandleDebugPlaySoundCommand(const char* args) +{ + // USAGE: .debug playsound #soundid + // #soundid - ID decimal number from SoundEntries.dbc (1st column) + if (!*args) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + uint32 dwSoundId = atoi((char*)args); + + if (!sSoundEntriesStore.LookupEntry(dwSoundId)) + { + PSendSysMessage(LANG_SOUND_NOT_EXIST, dwSoundId); + SetSentErrorMessage(true); + return false; + } + + Unit* unit = getSelectedUnit(); + if (!unit) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if (m_session->GetPlayer()->GetSelection()) + unit->PlayDistanceSound(dwSoundId,m_session->GetPlayer()); + else + unit->PlayDirectSound(dwSoundId,m_session->GetPlayer()); + + PSendSysMessage(LANG_YOU_HEAR_SOUND, dwSoundId); + return true; +} + +//Send notification in channel +bool ChatHandler::HandleDebugSendChannelNotifyCommand(const char* args) +{ + if (!*args) + return false; + + const char *name = "test"; + uint8 code = atoi(args); + + WorldPacket data(SMSG_CHANNEL_NOTIFY, (1+10)); + data << code; // notify type + data << name; // channel name + data << uint32(0); + data << uint32(0); + m_session->SendPacket(&data); + return true; +} + +//Send notification in chat +bool ChatHandler::HandleDebugSendChatMsgCommand(const char* args) +{ + if (!*args) + return false; + + const char *msg = "testtest"; + uint8 type = atoi(args); + WorldPacket data; + ChatHandler::FillMessageData(&data, m_session, type, 0, "chan", m_session->GetPlayer()->GetGUID(), msg, m_session->GetPlayer()); + m_session->SendPacket(&data); + return true; +} + +bool ChatHandler::HandleDebugSendQuestPartyMsgCommand(const char* args) +{ + uint32 msg = atol((char*)args); + m_session->GetPlayer()->SendPushToPartyResponse(m_session->GetPlayer(), msg); + return true; +} + +bool ChatHandler::HandleDebugGetLootRecipientCommand(const char* /*args*/) +{ + Creature* target = getSelectedCreature(); + if (!target) + return false; + + PSendSysMessage("loot recipient: %s", target->hasLootRecipient()?(target->GetLootRecipient()?target->GetLootRecipient()->GetName():"offline"):"no loot recipient"); + return true; +} + +bool ChatHandler::HandleDebugSendQuestInvalidMsgCommand(const char* args) +{ + uint32 msg = atol((char*)args); + m_session->GetPlayer()->SendCanTakeQuestResponse(msg); + return true; +} + +bool ChatHandler::HandleDebugGetItemStateCommand(const char* args) +{ + if (!*args) + return false; + + std::string state_str = args; + + ItemUpdateState state = ITEM_UNCHANGED; + bool list_queue = false, check_all = false; + if (state_str == "unchanged") state = ITEM_UNCHANGED; + else if (state_str == "changed") state = ITEM_CHANGED; + else if (state_str == "new") state = ITEM_NEW; + else if (state_str == "removed") state = ITEM_REMOVED; + else if (state_str == "queue") list_queue = true; + else if (state_str == "check_all") check_all = true; + else return false; + + Player* player = getSelectedPlayer(); + if (!player) player = m_session->GetPlayer(); + + if (!list_queue && !check_all) + { + state_str = "The player has the following " + state_str + " items: "; + SendSysMessage(state_str.c_str()); + for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i) + { + if (i >= BUYBACK_SLOT_START && i < BUYBACK_SLOT_END) + continue; + + Item *item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + if (!item) continue; + if (!item->IsBag()) + { + if (item->GetState() == state) + PSendSysMessage("bag: 255 slot: %d guid: %d owner: %d", item->GetSlot(), item->GetGUIDLow(), GUID_LOPART(item->GetOwnerGUID())); + } + else + { + Bag *bag = (Bag*)item; + for (uint8 j = 0; j < bag->GetBagSize(); ++j) + { + Item* item2 = bag->GetItemByPos(j); + if (item2 && item2->GetState() == state) + PSendSysMessage("bag: 255 slot: %d guid: %d owner: %d", item2->GetSlot(), item2->GetGUIDLow(), GUID_LOPART(item2->GetOwnerGUID())); + } + } + } + } + + if (list_queue) + { + std::vector &updateQueue = player->GetItemUpdateQueue(); + for (size_t i = 0; i < updateQueue.size(); ++i) + { + Item *item = updateQueue[i]; + if (!item) continue; + + Bag *container = item->GetContainer(); + uint8 bag_slot = container ? container->GetSlot() : uint8(INVENTORY_SLOT_BAG_0); + + std::string st; + switch(item->GetState()) + { + case ITEM_UNCHANGED: st = "unchanged"; break; + case ITEM_CHANGED: st = "changed"; break; + case ITEM_NEW: st = "new"; break; + case ITEM_REMOVED: st = "removed"; break; + } + + PSendSysMessage("bag: %d slot: %d guid: %d - state: %s", bag_slot, item->GetSlot(), item->GetGUIDLow(), st.c_str()); + } + if (updateQueue.empty()) + PSendSysMessage("updatequeue empty"); + } + + if (check_all) + { + bool error = false; + std::vector &updateQueue = player->GetItemUpdateQueue(); + for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i) + { + if (i >= BUYBACK_SLOT_START && i < BUYBACK_SLOT_END) + continue; + + Item *item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + if (!item) continue; + + if (item->GetSlot() != i) + { + PSendSysMessage("item at slot %d, guid %d has an incorrect slot value: %d", i, item->GetGUIDLow(), item->GetSlot()); + error = true; continue; + } + + if (item->GetOwnerGUID() != player->GetGUID()) + { + PSendSysMessage("for the item at slot %d and itemguid %d, owner's guid (%d) and player's guid (%d) don't match!", item->GetSlot(), item->GetGUIDLow(), GUID_LOPART(item->GetOwnerGUID()), player->GetGUIDLow()); + error = true; continue; + } + + if (Bag *container = item->GetContainer()) + { + PSendSysMessage("item at slot: %d guid: %d has a container (slot: %d, guid: %d) but shouldnt!", item->GetSlot(), item->GetGUIDLow(), container->GetSlot(), container->GetGUIDLow()); + error = true; continue; + } + + if (item->IsInUpdateQueue()) + { + uint16 qp = item->GetQueuePos(); + if (qp > updateQueue.size()) + { + PSendSysMessage("item at slot: %d guid: %d has a queuepos (%d) larger than the update queue size! ", item->GetSlot(), item->GetGUIDLow(), qp); + error = true; continue; + } + + if (updateQueue[qp] == NULL) + { + PSendSysMessage("item at slot: %d guid: %d has a queuepos (%d) that points to NULL in the queue!", item->GetSlot(), item->GetGUIDLow(), qp); + error = true; continue; + } + + if (updateQueue[qp] != item) + { + PSendSysMessage("item at slot: %d guid: %d has has a queuepos (%d) that points to another item in the queue (bag: %d, slot: %d, guid: %d)", item->GetSlot(), item->GetGUIDLow(), qp, updateQueue[qp]->GetBagSlot(), updateQueue[qp]->GetSlot(), updateQueue[qp]->GetGUIDLow()); + error = true; continue; + } + } + else if (item->GetState() != ITEM_UNCHANGED) + { + PSendSysMessage("item at slot: %d guid: %d is not in queue but should be (state: %d)!", item->GetSlot(), item->GetGUIDLow(), item->GetState()); + error = true; continue; + } + + if (item->IsBag()) + { + Bag *bag = (Bag*)item; + for (uint8 j = 0; j < bag->GetBagSize(); ++j) + { + Item* item2 = bag->GetItemByPos(j); + if (!item2) continue; + + if (item2->GetSlot() != j) + { + PSendSysMessage("the item in bag %d slot %d, guid %d has an incorrect slot value: %d", bag->GetSlot(), j, item2->GetGUIDLow(), item2->GetSlot()); + error = true; continue; + } + + if (item2->GetOwnerGUID() != player->GetGUID()) + { + PSendSysMessage("for the item in bag %d at slot %d and itemguid %d, owner's guid (%d) and player's guid (%d) don't match!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), GUID_LOPART(item2->GetOwnerGUID()), player->GetGUIDLow()); + error = true; continue; + } + + Bag *container = item2->GetContainer(); + if (!container) + { + PSendSysMessage("the item in bag %d at slot %d with guid %d has no container!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow()); + error = true; continue; + } + + if (container != bag) + { + PSendSysMessage("the item in bag %d at slot %d with guid %d has a different container(slot %d guid %d)!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), container->GetSlot(), container->GetGUIDLow()); + error = true; continue; + } + + if (item2->IsInUpdateQueue()) + { + uint16 qp = item2->GetQueuePos(); + if (qp > updateQueue.size()) + { + PSendSysMessage("item in bag: %d at slot: %d guid: %d has a queuepos (%d) larger than the update queue size! ", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), qp); + error = true; continue; + } + + if (updateQueue[qp] == NULL) + { + PSendSysMessage("item in bag: %d at slot: %d guid: %d has a queuepos (%d) that points to NULL in the queue!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), qp); + error = true; continue; + } + + if (updateQueue[qp] != item2) + { + PSendSysMessage("item in bag: %d at slot: %d guid: %d has has a queuepos (%d) that points to another item in the queue (bag: %d, slot: %d, guid: %d)", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), qp, updateQueue[qp]->GetBagSlot(), updateQueue[qp]->GetSlot(), updateQueue[qp]->GetGUIDLow()); + error = true; continue; + } + } + else if (item2->GetState() != ITEM_UNCHANGED) + { + PSendSysMessage("item in bag: %d at slot: %d guid: %d is not in queue but should be (state: %d)!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), item2->GetState()); + error = true; continue; + } + } + } + } + + for (size_t i = 0; i < updateQueue.size(); ++i) + { + Item *item = updateQueue[i]; + if (!item) continue; + + if (item->GetOwnerGUID() != player->GetGUID()) + { + PSendSysMessage("queue(" SIZEFMTD "): for the an item (guid %d), the owner's guid (%d) and player's guid (%d) don't match!", i, item->GetGUIDLow(), GUID_LOPART(item->GetOwnerGUID()), player->GetGUIDLow()); + error = true; continue; + } + + if (item->GetQueuePos() != i) + { + PSendSysMessage("queue(" SIZEFMTD "): for the an item (guid %d), the queuepos doesn't match it's position in the queue!", i, item->GetGUIDLow()); + error = true; continue; + } + + if (item->GetState() == ITEM_REMOVED) continue; + Item *test = player->GetItemByPos(item->GetBagSlot(), item->GetSlot()); + + if (test == NULL) + { + PSendSysMessage("queue(" SIZEFMTD "): the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the player doesn't have an item at that position!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow()); + error = true; continue; + } + + if (test != item) + { + PSendSysMessage("queue(" SIZEFMTD "): the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the item with guid %d is there instead!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), test->GetGUIDLow()); + error = true; continue; + } + } + if (!error) + SendSysMessage("All OK!"); + } + + return true; +} + +bool ChatHandler::HandleDebugBattlegroundCommand(const char * /*args*/) +{ + sBattleGroundMgr.ToggleTesting(); + return true; +} + +bool ChatHandler::HandleDebugArenaCommand(const char * /*args*/) +{ + sBattleGroundMgr.ToggleArenaTesting(); + return true; +} + +bool ChatHandler::HandleDebugThreatList(const char * /*args*/) +{ + Creature* target = getSelectedCreature(); + if (!target || target->isTotem() || target->isPet()) + return false; + + std::list& tlist = target->getThreatManager().getThreatList(); + std::list::iterator itr; + uint32 cnt = 0; + PSendSysMessage("Threat list of %s (guid %u)",target->GetName(), target->GetGUIDLow()); + for (itr = tlist.begin(); itr != tlist.end(); ++itr) + { + Unit* unit = (*itr)->getTarget(); + if (!unit) + continue; + ++cnt; + PSendSysMessage(" %u. %s (guid %u) - threat %f",cnt,unit->GetName(), unit->GetGUIDLow(), (*itr)->getThreat()); + } + SendSysMessage("End of threat list."); + return true; +} + +bool ChatHandler::HandleDebugHostileRefList(const char * /*args*/) +{ + Unit* target = getSelectedUnit(); + if (!target) + target = m_session->GetPlayer(); + HostileReference* ref = target->getHostileRefManager().getFirst(); + uint32 cnt = 0; + PSendSysMessage("Hostil reference list of %s (guid %u)",target->GetName(), target->GetGUIDLow()); + while (ref) + { + if (Unit * unit = ref->getSource()->getOwner()) + { + ++cnt; + PSendSysMessage(" %u. %s (guid %u) - threat %f",cnt,unit->GetName(), unit->GetGUIDLow(), ref->getThreat()); + } + ref = ref->next(); + } + SendSysMessage("End of hostil reference list."); + return true; +} + +bool ChatHandler::HandleDebugSetVehicleId(const char *args) +{ + Unit* target = getSelectedUnit(); + if (!target || target->IsVehicle()) + return false; + + if (!args) + return false; + + char* i = strtok((char*)args, " "); + if (!i) + return false; + + uint32 id = (uint32)atoi(i); + //target->SetVehicleId(id); + PSendSysMessage("Vehicle id set to %u", id); + return true; +} + +bool ChatHandler::HandleDebugEnterVehicle(const char * args) +{ + Unit* target = getSelectedUnit(); + if (!target || !target->IsVehicle()) + return false; + + if (!args) + return false; + + char* i = strtok((char*)args, " "); + if (!i) + return false; + + char* j = strtok(NULL, " "); + + uint32 entry = (uint32)atoi(i); + int8 seatId = j ? (int8)atoi(j) : -1; + + if (!entry) + m_session->GetPlayer()->EnterVehicle(target, seatId); + else + { + Creature *passenger = NULL; + Trinity::AllCreaturesOfEntryInRange check(m_session->GetPlayer(), entry, 20.0f); + Trinity::CreatureSearcher searcher(m_session->GetPlayer(), passenger, check); + m_session->GetPlayer()->VisitNearbyObject(30.0f, searcher); + if (!passenger || passenger == target) + return false; + passenger->EnterVehicle(target, seatId); + } + + PSendSysMessage("Unit %u entered vehicle %d", entry, (int32)seatId); + return true; +} + +bool ChatHandler::HandleDebugSpawnVehicle(const char* args) +{ + if (!*args) + return false; + + char* e = strtok((char*)args, " "); + char* i = strtok(NULL, " "); + + if (!e) + return false; + + uint32 entry = (uint32)atoi(e); + + float x, y, z, o = m_session->GetPlayer()->GetOrientation(); + m_session->GetPlayer()->GetClosePoint(x, y, z, m_session->GetPlayer()->GetObjectSize()); + + if (!i) + return m_session->GetPlayer()->SummonCreature(entry, x, y, z, o); + + uint32 id = (uint32)atoi(i); + + CreatureInfo const *ci = objmgr.GetCreatureTemplate(entry); + + if (!ci) + return false; + + VehicleEntry const *ve = sVehicleStore.LookupEntry(id); + + if (!ve) + return false; + + Creature *v = new Creature; + + Map *map = m_session->GetPlayer()->GetMap(); + + if (!v->Create(objmgr.GenerateLowGuid(HIGHGUID_VEHICLE), map, m_session->GetPlayer()->GetPhaseMask(), entry, id, m_session->GetPlayer()->GetTeam(), x, y, z, o)) + { + delete v; + return false; + } + + map->Add(v->ToCreature()); + + return true; +} + +bool ChatHandler::HandleDebugSendLargePacketCommand(const char* /*args*/) +{ + const char* stuffingString = "This is a dummy string to push the packet's size beyond 128000 bytes. "; + std::ostringstream ss; + while (ss.str().size() < 128000) + ss << stuffingString; + SendSysMessage(ss.str().c_str()); + return true; +} + +bool ChatHandler::HandleDebugSendSetPhaseShiftCommand(const char* args) +{ + if (!*args) + return false; + + uint32 PhaseShift = atoi(args); + m_session->SendSetPhaseShift(PhaseShift); + return true; +} + +bool ChatHandler::HandleDebugGetItemValueCommand(const char* args) +{ + if (!*args) + return false; + + char* e = strtok((char*)args, " "); + char* f = strtok(NULL, " "); + + if (!e || !f) + return false; + + uint32 guid = (uint32)atoi(e); + uint32 index = (uint32)atoi(f); + + Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM)); + + if (!i) + return false; + + if (index >= i->GetValuesCount()) + return false; + + uint32 value = i->GetUInt32Value(index); + + PSendSysMessage("Item %u: value at %u is %u", guid, index, value); + + return true; +} + +bool ChatHandler::HandleDebugSetItemValueCommand(const char* args) +{ + if (!*args) + return false; + + char* e = strtok((char*)args, " "); + char* f = strtok(NULL, " "); + char* g = strtok(NULL, " "); + + if (!e || !f || !g) + return false; + + uint32 guid = (uint32)atoi(e); + uint32 index = (uint32)atoi(f); + uint32 value = (uint32)atoi(g); + + Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM)); + + if (!i) + return false; + + if (index >= i->GetValuesCount()) + return false; + + i->SetUInt32Value(index, value); + + return true; +} + +bool ChatHandler::HandleDebugItemExpireCommand(const char* args) +{ + if (!*args) + return false; + + char* e = strtok((char*)args, " "); + if (!e) + return false; + + uint32 guid = (uint32)atoi(e); + + Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM)); + + if (!i) + return false; + + m_session->GetPlayer()->DestroyItem(i->GetBagSlot(),i->GetSlot(), true); + sScriptMgr.ItemExpire(m_session->GetPlayer(),i->GetProto()); + + return true; +} + +//show animation +bool ChatHandler::HandleDebugAnimCommand(const char* args) +{ + if (!*args) + return false; + + uint32 anim_id = atoi((char*)args); + m_session->GetPlayer()->HandleEmoteCommand(anim_id); + return true; +} + +bool ChatHandler::HandleDebugSetAuraStateCommand(const char* args) +{ + if (!*args) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Unit* unit = getSelectedUnit(); + if (!unit) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + int32 state = atoi((char*)args); + if (!state) + { + // reset all states + for (int i = 1; i <= 32; ++i) + unit->ModifyAuraState(AuraState(i),false); + return true; + } + + unit->ModifyAuraState(AuraState(abs(state)),state > 0); + return true; +} + +bool ChatHandler::HandleDebugSetValueCommand(const char* args) +{ + if (!*args) + return false; + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + char* pz = strtok(NULL, " "); + + if (!px || !py) + return false; + + WorldObject* target = getSelectedObject(); + if (!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + uint64 guid = target->GetGUID(); + + uint32 Opcode = (uint32)atoi(px); + if (Opcode >= target->GetValuesCount()) + { + PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount()); + return false; + } + uint32 iValue; + float fValue; + bool isint32 = true; + if (pz) + isint32 = (bool)atoi(pz); + if (isint32) + { + iValue = (uint32)atoi(py); + sLog.outDebug(GetTrinityString(LANG_SET_UINT), GUID_LOPART(guid), Opcode, iValue); + target->SetUInt32Value(Opcode , iValue); + PSendSysMessage(LANG_SET_UINT_FIELD, GUID_LOPART(guid), Opcode,iValue); + } + else + { + fValue = (float)atof(py); + sLog.outDebug(GetTrinityString(LANG_SET_FLOAT), GUID_LOPART(guid), Opcode, fValue); + target->SetFloatValue(Opcode , fValue); + PSendSysMessage(LANG_SET_FLOAT_FIELD, GUID_LOPART(guid), Opcode,fValue); + } + + return true; +} + +bool ChatHandler::HandleDebugGetValueCommand(const char* args) +{ + if (!*args) + return false; + + char* px = strtok((char*)args, " "); + char* pz = strtok(NULL, " "); + + if (!px) + return false; + + Unit* target = getSelectedUnit(); + if (!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + uint64 guid = target->GetGUID(); + + uint32 Opcode = (uint32)atoi(px); + if (Opcode >= target->GetValuesCount()) + { + PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount()); + return false; + } + uint32 iValue; + float fValue; + bool isint32 = true; + if (pz) + isint32 = (bool)atoi(pz); + + if (isint32) + { + iValue = target->GetUInt32Value(Opcode); + sLog.outDebug(GetTrinityString(LANG_GET_UINT), GUID_LOPART(guid), Opcode, iValue); + PSendSysMessage(LANG_GET_UINT_FIELD, GUID_LOPART(guid), Opcode, iValue); + } + else + { + fValue = target->GetFloatValue(Opcode); + sLog.outDebug(GetTrinityString(LANG_GET_FLOAT), GUID_LOPART(guid), Opcode, fValue); + PSendSysMessage(LANG_GET_FLOAT_FIELD, GUID_LOPART(guid), Opcode, fValue); + } + + return true; +} + +bool ChatHandler::HandleDebugMod32ValueCommand(const char* args) +{ + if (!*args) + return false; + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + + if (!px || !py) + return false; + + uint32 Opcode = (uint32)atoi(px); + int Value = atoi(py); + + if (Opcode >= m_session->GetPlayer()->GetValuesCount()) + { + PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, m_session->GetPlayer()->GetGUIDLow(), m_session->GetPlayer()->GetValuesCount()); + return false; + } + + sLog.outDebug(GetTrinityString(LANG_CHANGE_32BIT), Opcode, Value); + + int CurrentValue = (int)m_session->GetPlayer()->GetUInt32Value(Opcode); + + CurrentValue += Value; + m_session->GetPlayer()->SetUInt32Value(Opcode , (uint32)CurrentValue); + + PSendSysMessage(LANG_CHANGE_32BIT_FIELD, Opcode,CurrentValue); + + return true; +} + +bool ChatHandler::HandleDebugUpdateCommand(const char* args) +{ + if (!*args) + return false; + + uint32 updateIndex; + uint32 value; + + char* pUpdateIndex = strtok((char*)args, " "); + + Unit* chr = getSelectedUnit(); + if (chr == NULL) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if (!pUpdateIndex) + { + return true; + } + updateIndex = atoi(pUpdateIndex); + //check updateIndex + if (chr->GetTypeId() == TYPEID_PLAYER) + { + if (updateIndex >= PLAYER_END) return true; + } + else + { + if (updateIndex >= UNIT_END) return true; + } + + char* pvalue = strtok(NULL, " "); + if (!pvalue) + { + value=chr->GetUInt32Value(updateIndex); + + PSendSysMessage(LANG_UPDATE, chr->GetGUIDLow(),updateIndex,value); + return true; + } + + value=atoi(pvalue); + + PSendSysMessage(LANG_UPDATE_CHANGE, chr->GetGUIDLow(),updateIndex,value); + + chr->SetUInt32Value(updateIndex,value); + + return true; +} diff --git a/src/server/game/Chat/Commands/Level0.cpp b/src/server/game/Chat/Commands/Level0.cpp new file mode 100644 index 00000000000..ed021ac00d4 --- /dev/null +++ b/src/server/game/Chat/Commands/Level0.cpp @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "World.h" +#include "Player.h" +#include "Opcodes.h" +#include "Chat.h" +#include "ObjectAccessor.h" +#include "Language.h" +#include "AccountMgr.h" +#include "SystemConfig.h" +#include "revision.h" +#include "Util.h" + +bool ChatHandler::HandleHelpCommand(const char* args) +{ + char* cmd = strtok((char*)args, " "); + if (!cmd) + { + ShowHelpForCommand(getCommandTable(), "help"); + ShowHelpForCommand(getCommandTable(), ""); + } + else + { + if (!ShowHelpForCommand(getCommandTable(), cmd)) + SendSysMessage(LANG_NO_HELP_CMD); + } + + return true; +} + +bool ChatHandler::HandleCommandsCommand(const char* /*args*/) +{ + ShowHelpForCommand(getCommandTable(), ""); + return true; +} + +bool ChatHandler::HandleAccountCommand(const char* /*args*/) +{ + AccountTypes gmlevel = m_session->GetSecurity(); + PSendSysMessage(LANG_ACCOUNT_LEVEL, uint32(gmlevel)); + return true; +} + +bool ChatHandler::HandleStartCommand(const char* /*args*/) +{ + Player *chr = m_session->GetPlayer(); + + if (chr->isInFlight()) + { + SendSysMessage(LANG_YOU_IN_FLIGHT); + SetSentErrorMessage(true); + return false; + } + + if (chr->isInCombat()) + { + SendSysMessage(LANG_YOU_IN_COMBAT); + SetSentErrorMessage(true); + return false; + } + + if ((chr->isDead()) || (chr->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))) + { + // if player is dead and stuck, send ghost to graveyard + chr->RepopAtGraveyard(); + return true; + } + + // cast spell Stuck + chr->CastSpell(chr,7355,false); + return true; +} + +bool ChatHandler::HandleServerInfoCommand(const char* /*args*/) +{ + uint32 PlayersNum = sWorld.GetPlayerCount(); + uint32 MaxPlayersNum = sWorld.GetMaxPlayerCount(); + uint32 activeClientsNum = sWorld.GetActiveSessionCount(); + uint32 queuedClientsNum = sWorld.GetQueuedSessionCount(); + uint32 maxActiveClientsNum = sWorld.GetMaxActiveSessionCount(); + uint32 maxQueuedClientsNum = sWorld.GetMaxQueuedSessionCount(); + std::string uptime = secsToTimeString(sWorld.GetUptime()); + uint32 updateTime = sWorld.GetUpdateTime(); + + PSendSysMessage(_FULLVERSION); + //if (m_session) + // full = _FULLVERSION(REVISION_DATE,REVISION_TIME,"|cffffffff|Hurl:" REVISION_ID "|h" REVISION_ID "|h|r"); + //else + // full = _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_ID); + + //SendSysMessage(full); + //PSendSysMessage(LANG_USING_WORLD_DB,sWorld.GetDBVersion()); + //PSendSysMessage(LANG_USING_EVENT_AI,sWorld.GetCreatureEventAIVersion()); + PSendSysMessage(LANG_CONNECTED_PLAYERS, PlayersNum, MaxPlayersNum); + PSendSysMessage(LANG_CONNECTED_USERS, activeClientsNum, maxActiveClientsNum, queuedClientsNum, maxQueuedClientsNum); + PSendSysMessage(LANG_UPTIME, uptime.c_str()); + PSendSysMessage("Update time diff: %u.", updateTime); + + return true; +} + +bool ChatHandler::HandleDismountCommand(const char* /*args*/) +{ + //If player is not mounted, so go out :) + if (!m_session->GetPlayer()->IsMounted()) + { + SendSysMessage(LANG_CHAR_NON_MOUNTED); + SetSentErrorMessage(true); + return false; + } + + if (m_session->GetPlayer()->isInFlight()) + { + SendSysMessage(LANG_YOU_IN_FLIGHT); + SetSentErrorMessage(true); + return false; + } + + m_session->GetPlayer()->Unmount(); + m_session->GetPlayer()->RemoveAurasByType(SPELL_AURA_MOUNTED); + return true; +} + +bool ChatHandler::HandleSaveCommand(const char* /*args*/) +{ + Player *player=m_session->GetPlayer(); + + // save GM account without delay and output message (testing, etc) + if (m_session->GetSecurity() > SEC_PLAYER) + { + player->SaveToDB(); + SendSysMessage(LANG_PLAYER_SAVED); + return true; + } + + // save or plan save after 20 sec (logout delay) if current next save time more this value and _not_ output any messages to prevent cheat planning + uint32 save_interval = sWorld.getConfig(CONFIG_INTERVAL_SAVE); + if ((save_interval == 0 || save_interval > 20*IN_MILISECONDS && player->GetSaveTimer() <= save_interval - 20*IN_MILISECONDS)) + player->SaveToDB(); + + return true; +} + +bool ChatHandler::HandleGMListIngameCommand(const char* /*args*/) +{ + bool first = true; + + ObjectAccessor::Guard guard(*HashMapHolder::GetLock()); + HashMapHolder::MapType &m = ObjectAccessor::Instance().GetPlayers(); + for (HashMapHolder::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) + { + AccountTypes itr_sec = itr->second->GetSession()->GetSecurity(); + if ((itr->second->isGameMaster() || (itr_sec > SEC_PLAYER && itr_sec <= sWorld.getConfig(CONFIG_GM_LEVEL_IN_GM_LIST))) && + (!m_session || itr->second->IsVisibleGloballyFor(m_session->GetPlayer()))) + { + if (first) + { + SendSysMessage(LANG_GMS_ON_SRV); + first = false; + } + + SendSysMessage(GetNameLink(itr->second).c_str()); + } + } + + if (first) + SendSysMessage(LANG_GMS_NOT_LOGGED); + + return true; +} + +bool ChatHandler::HandleAccountPasswordCommand(const char* args) +{ + if (!*args) + return false; + + char *old_pass = strtok ((char*)args, " "); + char *new_pass = strtok (NULL, " "); + char *new_pass_c = strtok (NULL, " "); + + if (!old_pass || !new_pass || !new_pass_c) + return false; + + std::string password_old = old_pass; + std::string password_new = new_pass; + std::string password_new_c = new_pass_c; + + if (strcmp(new_pass, new_pass_c) != 0) + { + SendSysMessage (LANG_NEW_PASSWORDS_NOT_MATCH); + SetSentErrorMessage (true); + return false; + } + + if (!accmgr.CheckPassword (m_session->GetAccountId(), password_old)) + { + SendSysMessage (LANG_COMMAND_WRONGOLDPASSWORD); + SetSentErrorMessage (true); + return false; + } + + AccountOpResult result = accmgr.ChangePassword(m_session->GetAccountId(), password_new); + + switch(result) + { + case AOR_OK: + SendSysMessage(LANG_COMMAND_PASSWORD); + break; + case AOR_PASS_TOO_LONG: + SendSysMessage(LANG_PASSWORD_TOO_LONG); + SetSentErrorMessage(true); + return false; + case AOR_NAME_NOT_EXIST: // not possible case, don't want get account name for output + default: + SendSysMessage(LANG_COMMAND_NOTCHANGEPASSWORD); + SetSentErrorMessage(true); + return false; + } + + return true; +} + +bool ChatHandler::HandleAccountAddonCommand(const char* args) +{ + if (!*args) + return false; + + char *szExp = strtok((char*)args," "); + + uint32 account_id = m_session->GetAccountId(); + + int expansion=atoi(szExp); //get int anyway (0 if error) + if (expansion < 0 || expansion > sWorld.getConfig(CONFIG_EXPANSION)) + return false; + + // No SQL injection + LoginDatabase.PExecute("UPDATE account SET expansion = '%d' WHERE id = '%u'", expansion, account_id); + PSendSysMessage(LANG_ACCOUNT_ADDON, expansion); + return true; +} + +bool ChatHandler::HandleAccountLockCommand(const char* args) +{ + if (!*args) + { + SendSysMessage(LANG_USE_BOL); + return true; + } + + std::string argstr = (char*)args; + if (argstr == "on") + { + LoginDatabase.PExecute("UPDATE account SET locked = '1' WHERE id = '%d'",m_session->GetAccountId()); + PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED); + return true; + } + + if (argstr == "off") + { + LoginDatabase.PExecute("UPDATE account SET locked = '0' WHERE id = '%d'",m_session->GetAccountId()); + PSendSysMessage(LANG_COMMAND_ACCLOCKUNLOCKED); + return true; + } + + SendSysMessage(LANG_USE_BOL); + return true; +} + +/// Display the 'Message of the day' for the realm +bool ChatHandler::HandleServerMotdCommand(const char* /*args*/) +{ + PSendSysMessage(LANG_MOTD_CURRENT, sWorld.GetMotd()); + return true; +} + diff --git a/src/server/game/Chat/Commands/Level1.cpp b/src/server/game/Chat/Commands/Level1.cpp new file mode 100644 index 00000000000..11189d519a0 --- /dev/null +++ b/src/server/game/Chat/Commands/Level1.cpp @@ -0,0 +1,2960 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "AccountMgr.h" +#include "Opcodes.h" +#include "Chat.h" +#include "Log.h" +#include "MapManager.h" +#include "ObjectAccessor.h" +#include "Language.h" +#include "CellImpl.h" +#include "InstanceSaveMgr.h" +#include "Util.h" + +#ifdef _DEBUG_VMAPS +#include "VMapFactory.h" +#endif + +//-----------------------Npc Commands----------------------- +bool ChatHandler::HandleNpcSayCommand(const char* args) +{ + if (!*args) + return false; + + Creature* pCreature = getSelectedCreature(); + if (!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->MonsterSay(args, LANG_UNIVERSAL, 0); + + // make some emotes + char lastchar = args[strlen(args) - 1]; + switch(lastchar) + { + case '?': pCreature->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION); break; + case '!': pCreature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); break; + default: pCreature->HandleEmoteCommand(EMOTE_ONESHOT_TALK); break; + } + + return true; +} + +bool ChatHandler::HandleNpcYellCommand(const char* args) +{ + if (!*args) + return false; + + Creature* pCreature = getSelectedCreature(); + if (!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->MonsterYell(args, LANG_UNIVERSAL, 0); + + // make an emote + pCreature->HandleEmoteCommand(EMOTE_ONESHOT_SHOUT); + + return true; +} + +//show text emote by creature in chat +bool ChatHandler::HandleNpcTextEmoteCommand(const char* args) +{ + if (!*args) + return false; + + Creature* pCreature = getSelectedCreature(); + + if (!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->MonsterTextEmote(args, 0); + + return true; +} + +// make npc whisper to player +bool ChatHandler::HandleNpcWhisperCommand(const char* args) +{ + if (!*args) + return false; + + char* receiver_str = strtok((char*)args, " "); + char* text = strtok(NULL, ""); + + uint64 guid = m_session->GetPlayer()->GetSelection(); + Creature* pCreature = m_session->GetPlayer()->GetMap()->GetCreature(guid); + + if (!pCreature || !receiver_str || !text) + { + return false; + } + + uint64 receiver_guid= atol(receiver_str); + + // check online security + if (HasLowerSecurity(objmgr.GetPlayer(receiver_guid), 0)) + return false; + + pCreature->MonsterWhisper(text,receiver_guid); + + return true; +} +//---------------------------------------------------------- + +bool ChatHandler::HandleNameAnnounceCommand(const char* args) +{ + WorldPacket data; + if (!*args) + return false; + + sWorld.SendWorldText(LANG_ANNOUNCE_COLOR, m_session->GetPlayer()->GetName(), args); + return true; +} + +bool ChatHandler::HandleGMNameAnnounceCommand(const char* args) +{ + WorldPacket data; + if (!*args) + return false; + + sWorld.SendGMText(LANG_GM_ANNOUNCE_COLOR, m_session->GetPlayer()->GetName(), args); + return true; +} + +// global announce +bool ChatHandler::HandleAnnounceCommand(const char* args) +{ + if (!*args) + return false; + + sWorld.SendWorldText(LANG_SYSTEMMESSAGE,args); + return true; +} + +// announce to logged in GMs +bool ChatHandler::HandleGMAnnounceCommand(const char* args) +{ + if (!*args) + return false; + + sWorld.SendGMText(LANG_GM_BROADCAST,args); + return true; +} + +//notification player at the screen +bool ChatHandler::HandleNotifyCommand(const char* args) +{ + if (!*args) + return false; + + std::string str = GetTrinityString(LANG_GLOBAL_NOTIFY); + str += args; + + WorldPacket data(SMSG_NOTIFICATION, (str.size()+1)); + data << str; + sWorld.SendGlobalMessage(&data); + + return true; +} + +//notification GM at the screen +bool ChatHandler::HandleGMNotifyCommand(const char* args) +{ + if (!*args) + return false; + + std::string str = GetTrinityString(LANG_GM_NOTIFY); + str += args; + + WorldPacket data(SMSG_NOTIFICATION, (str.size()+1)); + data << str; + sWorld.SendGlobalGMMessage(&data); + + return true; +} + +//Enable\Dissable GM Mode +bool ChatHandler::HandleGMCommand(const char* args) +{ + if (!*args) + { + if (m_session->GetPlayer()->isGameMaster()) + m_session->SendNotification(LANG_GM_ON); + else + m_session->SendNotification(LANG_GM_OFF); + return true; + } + + std::string argstr = (char*)args; + + if (argstr == "on") + { + m_session->GetPlayer()->SetGameMaster(true); + m_session->SendNotification(LANG_GM_ON); + m_session->GetPlayer()->UpdateTriggerVisibility(); + #ifdef _DEBUG_VMAPS + VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager(); + vMapManager->processCommand("stoplog"); + #endif + return true; + } + + if (argstr == "off") + { + m_session->GetPlayer()->SetGameMaster(false); + m_session->SendNotification(LANG_GM_OFF); + m_session->GetPlayer()->UpdateTriggerVisibility(); + #ifdef _DEBUG_VMAPS + VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager(); + vMapManager->processCommand("startlog"); + #endif + return true; + } + + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; +} + +// Enables or disables hiding of the staff badge +bool ChatHandler::HandleGMChatCommand(const char* args) +{ + if (!*args) + { + if (m_session->GetPlayer()->isGMChat()) + m_session->SendNotification(LANG_GM_CHAT_ON); + else + m_session->SendNotification(LANG_GM_CHAT_OFF); + return true; + } + + std::string argstr = (char*)args; + + if (argstr == "on") + { + m_session->GetPlayer()->SetGMChat(true); + m_session->SendNotification(LANG_GM_CHAT_ON); + return true; + } + + if (argstr == "off") + { + m_session->GetPlayer()->SetGMChat(false); + m_session->SendNotification(LANG_GM_CHAT_OFF); + return true; + } + + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; +} + +std::string ChatHandler::PGetParseString(int32 entry, ...) +{ + const char *format = GetTrinityString(entry); + va_list ap; + char str [1024]; + va_start(ap, entry); + vsnprintf(str,1024,format, ap); + va_end(ap); + return (std::string)str; +} + +bool ChatHandler::HandleGMTicketListCommand(const char* /*args*/) +{ + SendSysMessage(LANG_COMMAND_TICKETSHOWLIST); + for (GmTicketList::iterator itr = objmgr.m_GMTicketList.begin(); itr != objmgr.m_GMTicketList.end(); ++itr) + { + if ((*itr)->closed != 0) + continue; + std::string gmname; + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, (*itr)->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, (*itr)->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - (*itr)->createtime, true, false)).c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - (*itr)->timestamp, true, false)).c_str()); + if (objmgr.GetPlayerNameByGUID((*itr)->assignedToGM, gmname)) + { + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + } + SendSysMessage(ss.str().c_str()); + } + return true; +} + +bool ChatHandler::HandleGMTicketListOnlineCommand(const char* /*args*/) +{ + SendSysMessage(LANG_COMMAND_TICKETSHOWONLINELIST); + for (GmTicketList::iterator itr = objmgr.m_GMTicketList.begin(); itr != objmgr.m_GMTicketList.end(); ++itr) + { + if ((*itr)->closed != 0 || !objmgr.GetPlayer((*itr)->playerGuid)) + continue; + + std::string gmname; + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, (*itr)->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, (*itr)->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - (*itr)->createtime, true, false)).c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - (*itr)->timestamp, true, false)).c_str()); + if (objmgr.GetPlayerNameByGUID((*itr)->assignedToGM, gmname)) + { + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + } + SendSysMessage(ss.str().c_str()); + } + return true; +} + +bool ChatHandler::HandleGMTicketListClosedCommand(const char* /*args*/) +{ + SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST); + for (GmTicketList::iterator itr = objmgr.m_GMTicketList.begin(); itr != objmgr.m_GMTicketList.end(); ++itr) + { + if ((*itr)->closed == 0) + continue; + + std::string gmname; + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, (*itr)->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, (*itr)->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - (*itr)->createtime, true, false)).c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - (*itr)->timestamp, true, false)).c_str()); + if (objmgr.GetPlayerNameByGUID((*itr)->assignedToGM, gmname)) + { + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + } + SendSysMessage(ss.str().c_str()); + } + return true; +} + +bool ChatHandler::HandleGMTicketGetByIdCommand(const char* args) +{ + if (!*args) + return false; + + uint64 tguid = atoi(args); + GM_Ticket *ticket = objmgr.GetGMTicket(tguid); + if (!ticket || ticket->closed != 0) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + std::string gmname; + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - ticket->createtime, true, false)).c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - ticket->timestamp, true, false)).c_str()); + if (objmgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname)) + { + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + } + ss << PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, ticket->message.c_str()); + if (ticket->comment != "") + { + ss << PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, ticket->comment.c_str()); + } + SendSysMessage(ss.str().c_str()); + return true; +} + +bool ChatHandler::HandleGMTicketGetByNameCommand(const char* args) +{ + if (!*args) + return false; + + std::string name = (char*)args; + normalizePlayerName(name); + + Player *plr = objmgr.GetPlayer(name.c_str()); + if (!plr) + { + SendSysMessage(LANG_NO_PLAYERS_FOUND); + return true; + } + + GM_Ticket *ticket = objmgr.GetGMTicketByPlayer(plr->GetGUID()); + if (!ticket) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + std::string gmname; + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - ticket->createtime, true, false)).c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - ticket->timestamp, true, false)).c_str()); + if (objmgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname)) + { + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + } + ss << PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, ticket->message.c_str()); + if (ticket->comment != "") + { + ss << PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, ticket->comment.c_str()); + } + SendSysMessage(ss.str().c_str()); + return true; +} + +bool ChatHandler::HandleGMTicketCloseByIdCommand(const char* args) +{ + if (!*args) + return false; + + uint64 tguid = atoi(args); + GM_Ticket *ticket = objmgr.GetGMTicket(tguid); + if (!ticket || ticket->closed != 0) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + if (ticket && ticket->assignedToGM != 0 && ticket->assignedToGM != m_session->GetPlayer()->GetGUID()) + { + PSendSysMessage(LANG_COMMAND_TICKETCANNOTCLOSE, ticket->guid); + return true; + } + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETCLOSED, m_session->GetPlayer()->GetName()); + SendGlobalGMSysMessage(ss.str().c_str()); + Player *plr = objmgr.GetPlayer(ticket->playerGuid); + objmgr.RemoveGMTicket(ticket, m_session->GetPlayer()->GetGUID()); + + if (!plr || !plr->IsInWorld()) + return true; + + // send abandon ticket + WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4); + data << uint32(9); + plr->GetSession()->SendPacket(&data); + return true; +} + +bool ChatHandler::HandleGMTicketAssignToCommand(const char* args) +{ + if (!*args) + return false; + + char* tguid = strtok((char*)args, " "); + uint64 ticketGuid = atoi(tguid); + char* targetgm = strtok(NULL, " "); + + if (!targetgm) + return false; + + std::string targm = targetgm; + if (!normalizePlayerName(targm)) + return false; + + Player *cplr = m_session->GetPlayer(); + GM_Ticket *ticket = objmgr.GetGMTicket(ticketGuid); + + if (!ticket || ticket->closed != 0) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + uint64 tarGUID = objmgr.GetPlayerGUIDByName(targm.c_str()); + uint64 accid = objmgr.GetPlayerAccountIdByGUID(tarGUID); + uint32 gmlevel = accmgr.GetSecurity(accid, realmID); + + if (!tarGUID || gmlevel == SEC_PLAYER) + { + SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A); + return true; + } + + if (ticket->assignedToGM == tarGUID) + { + PSendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_B, ticket->guid); + return true; + } + + std::string gmname; + objmgr.GetPlayerNameByGUID(tarGUID, gmname); + if (ticket->assignedToGM != 0 && ticket->assignedToGM != cplr->GetGUID()) + { + PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->guid, gmname.c_str()); + return true; + } + + ticket->assignedToGM = tarGUID; + objmgr.AddOrUpdateGMTicket(*ticket); + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + SendGlobalGMSysMessage(ss.str().c_str()); + return true; +} + +bool ChatHandler::HandleGMTicketUnAssignCommand(const char* args) +{ + if (!*args) + return false; + + uint64 ticketGuid = atoi(args); + Player *cplr = m_session->GetPlayer(); + GM_Ticket *ticket = objmgr.GetGMTicket(ticketGuid); + + if (!ticket|| ticket->closed != 0) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + if (ticket->assignedToGM == 0) + { + PSendSysMessage(LANG_COMMAND_TICKETNOTASSIGNED, ticket->guid); + return true; + } + + std::string gmname; + objmgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname); + Player *plr = objmgr.GetPlayer(ticket->assignedToGM); + if (plr && plr->IsInWorld() && plr->GetSession()->GetSecurity() > cplr->GetSession()->GetSecurity()) + { + SendSysMessage(LANG_COMMAND_TICKETUNASSIGNSECURITY); + return true; + } + + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTUNASSIGNED, cplr->GetName()); + SendGlobalGMSysMessage(ss.str().c_str()); + ticket->assignedToGM = 0; + objmgr.AddOrUpdateGMTicket(*ticket); + return true; +} + +bool ChatHandler::HandleGMTicketCommentCommand(const char* args) +{ + if (!*args) + return false; + + char* tguid = strtok((char*)args, " "); + uint64 ticketGuid = atoi(tguid); + char* comment = strtok(NULL, "\n"); + + if (!comment) + return false; + + Player *cplr = m_session->GetPlayer(); + GM_Ticket *ticket = objmgr.GetGMTicket(ticketGuid); + + if (!ticket || ticket->closed != 0) + { + PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + if (ticket->assignedToGM != 0 && ticket->assignedToGM != cplr->GetGUID()) + { + PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->guid); + return true; + } + + std::string gmname; + objmgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname); + ticket->comment = comment; + objmgr.AddOrUpdateGMTicket(*ticket); + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); + if (objmgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname)) + { + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + } + ss << PGetParseString(LANG_COMMAND_TICKETLISTADDCOMMENT, cplr->GetName(), ticket->comment.c_str()); + SendGlobalGMSysMessage(ss.str().c_str()); + return true; +} + +bool ChatHandler::HandleGMTicketDeleteByIdCommand(const char* args) +{ + if (!*args) + return false; + uint64 ticketGuid = atoi(args); + GM_Ticket *ticket = objmgr.GetGMTicket(ticketGuid); + + if (!ticket) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + if (ticket->closed == 0) + { + SendSysMessage(LANG_COMMAND_TICKETCLOSEFIRST); + return true; + } + + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETDELETED, m_session->GetPlayer()->GetName()); + SendGlobalGMSysMessage(ss.str().c_str()); + Player *plr = objmgr.GetPlayer(ticket->playerGuid); + objmgr.RemoveGMTicket(ticket, -1, true); + if (plr && plr->IsInWorld()) + { + // Force abandon ticket + WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4); + data << uint32(9); + plr->GetSession()->SendPacket(&data); + } + + ticket = NULL; + return true; +} + +bool ChatHandler::HandleGMTicketReloadCommand(const char*) +{ + objmgr.LoadGMTickets(); + return true; +} + +//Enable\Dissable Invisible mode +bool ChatHandler::HandleGMVisibleCommand(const char* args) +{ + if (!*args) + { + PSendSysMessage(LANG_YOU_ARE, m_session->GetPlayer()->isGMVisible() ? GetTrinityString(LANG_VISIBLE) : GetTrinityString(LANG_INVISIBLE)); + return true; + } + + std::string argstr = (char*)args; + + if (argstr == "on") + { + m_session->GetPlayer()->SetGMVisible(true); + m_session->SendNotification(LANG_INVISIBLE_VISIBLE); + return true; + } + + if (argstr == "off") + { + m_session->SendNotification(LANG_INVISIBLE_INVISIBLE); + m_session->GetPlayer()->SetGMVisible(false); + return true; + } + + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; +} + +bool ChatHandler::HandleGPSCommand(const char* args) +{ + WorldObject *obj = NULL; + if (*args) + { + uint64 guid = extractGuidFromLink((char*)args); + if (guid) + obj = (WorldObject*)ObjectAccessor::GetObjectByTypeMask(*m_session->GetPlayer(),guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); + + if (!obj) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + } + else + { + obj = getSelectedUnit(); + + if (!obj) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + } + CellPair cell_val = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); + Cell cell(cell_val); + + uint32 zone_id, area_id; + obj->GetZoneAndAreaId(zone_id,area_id); + + MapEntry const* mapEntry = sMapStore.LookupEntry(obj->GetMapId()); + AreaTableEntry const* zoneEntry = GetAreaEntryByAreaID(zone_id); + AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(area_id); + + float zone_x = obj->GetPositionX(); + float zone_y = obj->GetPositionY(); + + Map2ZoneCoordinates(zone_x,zone_y,zone_id); + + Map const *map = obj->GetMap(); + float ground_z = map->GetHeight(obj->GetPositionX(), obj->GetPositionY(), MAX_HEIGHT); + float floor_z = map->GetHeight(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ()); + + GridPair p = Trinity::ComputeGridPair(obj->GetPositionX(), obj->GetPositionY()); + + int gx=63-p.x_coord; + int gy=63-p.y_coord; + + uint32 have_map = Map::ExistMap(obj->GetMapId(),gx,gy) ? 1 : 0; + uint32 have_vmap = Map::ExistVMap(obj->GetMapId(),gx,gy) ? 1 : 0; + + if(have_vmap) + { + if(map->IsOutdoors(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ())) + PSendSysMessage("You are outdoors"); + else + PSendSysMessage("You are indoor"); + } + else PSendSysMessage("no VMAP available for area info"); + + PSendSysMessage(LANG_MAP_POSITION, + obj->GetMapId(), (mapEntry ? mapEntry->name[GetSessionDbcLocale()] : ""), + zone_id, (zoneEntry ? zoneEntry->area_name[GetSessionDbcLocale()] : ""), + area_id, (areaEntry ? areaEntry->area_name[GetSessionDbcLocale()] : ""), + obj->GetPhaseMask(), + obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(), + cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), obj->GetInstanceId(), + zone_x, zone_y, ground_z, floor_z, have_map, have_vmap); + + sLog.outDebug("Player %s GPS call for %s '%s' (%s: %u):", + m_session ? GetNameLink().c_str() : GetTrinityString(LANG_CONSOLE_COMMAND), + (obj->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), obj->GetName(), + (obj->GetTypeId() == TYPEID_PLAYER ? "GUID" : "Entry"), (obj->GetTypeId() == TYPEID_PLAYER ? obj->GetGUIDLow(): obj->GetEntry())); + sLog.outDebug(GetTrinityString(LANG_MAP_POSITION), + obj->GetMapId(), (mapEntry ? mapEntry->name[sWorld.GetDefaultDbcLocale()] : ""), + zone_id, (zoneEntry ? zoneEntry->area_name[sWorld.GetDefaultDbcLocale()] : ""), + area_id, (areaEntry ? areaEntry->area_name[sWorld.GetDefaultDbcLocale()] : ""), + obj->GetPhaseMask(), + obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(), + cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), obj->GetInstanceId(), + zone_x, zone_y, ground_z, floor_z, have_map, have_vmap); + + LiquidData liquid_status; + ZLiquidStatus res = map->getLiquidStatus(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), MAP_ALL_LIQUIDS, &liquid_status); + if (res) + { + PSendSysMessage(LANG_LIQUID_STATUS, liquid_status.level, liquid_status.depth_level, liquid_status.type, res); + } + return true; +} + +//Summon Player +bool ChatHandler::HandleNamegoCommand(const char* args) +{ + Player* target; + uint64 target_guid; + std::string target_name; + if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) + return false; + + Player* _player = m_session->GetPlayer(); + if (target == _player || target_guid == _player->GetGUID()) + { + PSendSysMessage(LANG_CANT_TELEPORT_SELF); + SetSentErrorMessage(true); + return false; + } + + if (target) + { + std::string nameLink = playerLink(target_name); + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + if (target->IsBeingTeleported()) + { + PSendSysMessage(LANG_IS_TELEPORTED, nameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + + Map* pMap = m_session->GetPlayer()->GetMap(); + + if (pMap->IsBattleGroundOrArena()) + { + // only allow if gm mode is on + if (!target->isGameMaster()) + { + PSendSysMessage(LANG_CANNOT_GO_TO_BG_GM,nameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + // if both players are in different bgs + else if (target->GetBattleGroundId() && m_session->GetPlayer()->GetBattleGroundId() != target->GetBattleGroundId()) + { + target->LeaveBattleground(false); // Note: should be changed so target gets no Deserter debuff + //PSendSysMessage(LANG_CANNOT_GO_TO_BG_FROM_BG,nameLink.c_str()); + //SetSentErrorMessage(true); + //return false; + } + // all's well, set bg id + // when porting out from the bg, it will be reset to 0 + target->SetBattleGroundId(m_session->GetPlayer()->GetBattleGroundId(), m_session->GetPlayer()->GetBattleGroundTypeId()); + // remember current position as entry point for return at bg end teleportation + if (!target->GetMap()->IsBattleGroundOrArena()) + target->SetBattleGroundEntryPoint(); + } + else if (pMap->IsDungeon()) + { + Map* cMap = target->GetMap(); + if (cMap->Instanceable() && cMap->GetInstanceId() != pMap->GetInstanceId()) + { + target->UnbindInstance(pMap->GetInstanceId(), target->GetDungeonDifficulty(), true); + // cannot summon from instance to instance + //PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,nameLink.c_str()); + //SetSentErrorMessage(true); + //return false; + } + + // we are in instance, and can summon only player in our group with us as lead + if (!m_session->GetPlayer()->GetGroup() || !target->GetGroup() || + (target->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) || + (m_session->GetPlayer()->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID())) + // the last check is a bit excessive, but let it be, just in case + { + PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,nameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + } + + PSendSysMessage(LANG_SUMMONING, nameLink.c_str(),""); + if (needReportToTarget(target)) + ChatHandler(target).PSendSysMessage(LANG_SUMMONED_BY, playerLink(_player->GetName()).c_str()); + + // stop flight if need + if (target->isInFlight()) + { + target->GetMotionMaster()->MovementExpired(); + target->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + target->SaveRecallPosition(); + + // before GM + float x,y,z; + m_session->GetPlayer()->GetClosePoint(x,y,z,target->GetObjectSize()); + target->TeleportTo(m_session->GetPlayer()->GetMapId(),x,y,z,target->GetOrientation()); + target->SetPhaseMask(m_session->GetPlayer()->GetPhaseMask(), true); + } + else + { + // check offline security + if (HasLowerSecurity(NULL, target_guid)) + return false; + + std::string nameLink = playerLink(target_name); + + PSendSysMessage(LANG_SUMMONING, nameLink.c_str(),GetTrinityString(LANG_OFFLINE)); + + // in point where GM stay + Player::SavePositionInDB(m_session->GetPlayer()->GetMapId(), + m_session->GetPlayer()->GetPositionX(), + m_session->GetPlayer()->GetPositionY(), + m_session->GetPlayer()->GetPositionZ(), + m_session->GetPlayer()->GetOrientation(), + m_session->GetPlayer()->GetZoneId(), + target_guid); + } + + return true; +} + +//Teleport to Player +bool ChatHandler::HandleGonameCommand(const char* args) +{ + Player* target; + uint64 target_guid; + std::string target_name; + if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) + return false; + + Player* _player = m_session->GetPlayer(); + if (target == _player || target_guid == _player->GetGUID()) + { + SendSysMessage(LANG_CANT_TELEPORT_SELF); + SetSentErrorMessage(true); + return false; + } + + if (target) + { + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + std::string chrNameLink = playerLink(target_name); + + Map* cMap = target->GetMap(); + if (cMap->IsBattleGroundOrArena()) + { + // only allow if gm mode is on + if (!_player->isGameMaster()) + { + PSendSysMessage(LANG_CANNOT_GO_TO_BG_GM,chrNameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + // if both players are in different bgs + else if (_player->GetBattleGroundId() && _player->GetBattleGroundId() != target->GetBattleGroundId()) + { + _player->LeaveBattleground(false); // Note: should be changed so _player gets no Deserter debuff + //PSendSysMessage(LANG_CANNOT_GO_TO_BG_FROM_BG,chrNameLink.c_str()); + //SetSentErrorMessage(true); + //return false; + } + // all's well, set bg id + // when porting out from the bg, it will be reset to 0 + _player->SetBattleGroundId(target->GetBattleGroundId(), target->GetBattleGroundTypeId()); + // remember current position as entry point for return at bg end teleportation + if (!_player->GetMap()->IsBattleGroundOrArena()) + _player->SetBattleGroundEntryPoint(); + } + else if (cMap->IsDungeon()) + { + //Map* pMap = _player->GetMap(); + + // we have to go to instance, and can go to player only if: + // 1) we are in his group (either as leader or as member) + // 2) we are not bound to any group and have GM mode on + if (_player->GetGroup()) + { + // we are in group, we can go only if we are in the player group + if (_player->GetGroup() != target->GetGroup()) + { + PSendSysMessage(LANG_CANNOT_GO_TO_INST_PARTY,chrNameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + } + else + { + // we are not in group, let's verify our GM mode + if (!_player->isGameMaster()) + { + PSendSysMessage(LANG_CANNOT_GO_TO_INST_GM,chrNameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + } + + // if the player or the player's group is bound to another instance + // the player will not be bound to another one + InstancePlayerBind *pBind = _player->GetBoundInstance(target->GetMapId(), target->GetDifficulty(cMap->IsRaid())); + if (!pBind) + { + Group *group = _player->GetGroup(); + // if no bind exists, create a solo bind + InstanceGroupBind *gBind = group ? group->GetBoundInstance(target) : NULL; // if no bind exists, create a solo bind + if (!gBind) + if (InstanceSave *save = sInstanceSaveManager.GetInstanceSave(target->GetInstanceId())) + _player->BindToInstance(save, !save->CanReset()); + } + + if (cMap->IsRaid()) + _player->SetRaidDifficulty(target->GetRaidDifficulty()); + else + _player->SetDungeonDifficulty(target->GetDungeonDifficulty()); + } + + PSendSysMessage(LANG_APPEARING_AT, chrNameLink.c_str()); + //if (needReportToTarget(target)) + // ChatHandler(target).PSendSysMessage(LANG_APPEARING_TO, GetNameLink().c_str()); + + // stop flight if need + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + // to point to see at target with same orientation + float x,y,z; + target->GetContactPoint(_player,x,y,z); + + _player->TeleportTo(target->GetMapId(), x, y, z, _player->GetAngle(target), TELE_TO_GM_MODE); + _player->SetPhaseMask(target->GetPhaseMask(), true); + } + else + { + // check offline security + if (HasLowerSecurity(NULL, target_guid)) + return false; + + std::string nameLink = playerLink(target_name); + + PSendSysMessage(LANG_APPEARING_AT, nameLink.c_str()); + + // to point where player stay (if loaded) + float x,y,z,o; + uint32 map; + bool in_flight; + if (!Player::LoadPositionFromDB(map,x,y,z,o,in_flight,target_guid)) + return false; + + // stop flight if need + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(map, x, y, z,_player->GetOrientation()); + } + + return true; +} + +// Teleport player to last position +bool ChatHandler::HandleRecallCommand(const char* args) +{ + Player* target; + if (!extractPlayerTarget((char*)args,&target)) + return false; + + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + if (target->IsBeingTeleported()) + { + PSendSysMessage(LANG_IS_TELEPORTED, GetNameLink(target).c_str()); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if (target->isInFlight()) + { + target->GetMotionMaster()->MovementExpired(); + target->CleanupAfterTaxiFlight(); + } + + target->TeleportTo(target->m_recallMap, target->m_recallX, target->m_recallY, target->m_recallZ, target->m_recallO); + return true; +} + +//Edit Player HP +bool ChatHandler::HandleModifyHPCommand(const char* args) +{ + if (!*args) + return false; + + int32 hp = atoi((char*)args); + int32 hpm = atoi((char*)args); + + if (hp < 1 || hpm < 1 || hpm < hp) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if (HasLowerSecurity(chr, 0)) + return false; + + PSendSysMessage(LANG_YOU_CHANGE_HP, GetNameLink(chr).c_str(), hp, hpm); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_HP_CHANGED, GetNameLink().c_str(), hp, hpm); + + chr->SetMaxHealth(hpm); + chr->SetHealth(hp); + + return true; +} + +//Edit Player Mana +bool ChatHandler::HandleModifyManaCommand(const char* args) +{ + if (!*args) + return false; + + // char* pmana = strtok((char*)args, " "); + // if (!pmana) + // return false; + + // char* pmanaMax = strtok(NULL, " "); + // if (!pmanaMax) + // return false; + + // int32 manam = atoi(pmanaMax); + // int32 mana = atoi(pmana); + int32 mana = atoi((char*)args); + int32 manam = atoi((char*)args); + + if (mana <= 0 || manam <= 0 || manam < mana) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(chr, 0)) + return false; + + PSendSysMessage(LANG_YOU_CHANGE_MANA, GetNameLink(chr).c_str(), mana, manam); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_MANA_CHANGED, GetNameLink().c_str(), mana, manam); + + chr->SetMaxPower(POWER_MANA,manam); + chr->SetPower(POWER_MANA, mana); + + return true; +} + +//Edit Player Energy +bool ChatHandler::HandleModifyEnergyCommand(const char* args) +{ + if (!*args) + return false; + + // char* pmana = strtok((char*)args, " "); + // if (!pmana) + // return false; + + // char* pmanaMax = strtok(NULL, " "); + // if (!pmanaMax) + // return false; + + // int32 manam = atoi(pmanaMax); + // int32 mana = atoi(pmana); + + int32 energy = atoi((char*)args)*10; + int32 energym = atoi((char*)args)*10; + + if (energy <= 0 || energym <= 0 || energym < energy) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (!chr) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(chr, 0)) + return false; + + PSendSysMessage(LANG_YOU_CHANGE_ENERGY, GetNameLink(chr).c_str(), energy/10, energym/10); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_ENERGY_CHANGED, GetNameLink().c_str(), energy/10, energym/10); + + chr->SetMaxPower(POWER_ENERGY,energym); + chr->SetPower(POWER_ENERGY, energy); + + sLog.outDetail(GetTrinityString(LANG_CURRENT_ENERGY),chr->GetMaxPower(POWER_ENERGY)); + + return true; +} + +//Edit Player Rage +bool ChatHandler::HandleModifyRageCommand(const char* args) +{ + if (!*args) + return false; + + // char* pmana = strtok((char*)args, " "); + // if (!pmana) + // return false; + + // char* pmanaMax = strtok(NULL, " "); + // if (!pmanaMax) + // return false; + + // int32 manam = atoi(pmanaMax); + // int32 mana = atoi(pmana); + + int32 rage = atoi((char*)args)*10; + int32 ragem = atoi((char*)args)*10; + + if (rage <= 0 || ragem <= 0 || ragem < rage) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(chr, 0)) + return false; + + PSendSysMessage(LANG_YOU_CHANGE_RAGE, GetNameLink(chr).c_str(), rage/10, ragem/10); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_RAGE_CHANGED, GetNameLink().c_str(), rage/10, ragem/10); + + chr->SetMaxPower(POWER_RAGE,ragem); + chr->SetPower(POWER_RAGE, rage); + + return true; +} + +// Edit Player Runic Power +bool ChatHandler::HandleModifyRunicPowerCommand(const char* args) +{ + if (!*args) + return false; + + int32 rune = atoi((char*)args)*10; + int32 runem = atoi((char*)args)*10; + + if (rune <= 0 || runem <= 0 || runem < rune) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_RUNIC_POWER, GetNameLink(chr).c_str(), rune/10, runem/10); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_RUNIC_POWER_CHANGED, GetNameLink().c_str(), rune/10, runem/10); + + chr->SetMaxPower(POWER_RUNIC_POWER,runem); + chr->SetPower(POWER_RUNIC_POWER, rune); + + return true; +} + +//Edit Player Faction +bool ChatHandler::HandleModifyFactionCommand(const char* args) +{ + if (!*args) + return false; + + char* pfactionid = extractKeyFromLink((char*)args,"Hfaction"); + + Creature* chr = getSelectedCreature(); + if (!chr) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if (!pfactionid) + { + if (chr) + { + uint32 factionid = chr->getFaction(); + uint32 flag = chr->GetUInt32Value(UNIT_FIELD_FLAGS); + uint32 npcflag = chr->GetUInt32Value(UNIT_NPC_FLAGS); + uint32 dyflag = chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS); + PSendSysMessage(LANG_CURRENT_FACTION,chr->GetGUIDLow(),factionid,flag,npcflag,dyflag); + } + return true; + } + + if (!chr) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + uint32 factionid = atoi(pfactionid); + uint32 flag; + + char *pflag = strtok(NULL, " "); + if (!pflag) + flag = chr->GetUInt32Value(UNIT_FIELD_FLAGS); + else + flag = atoi(pflag); + + char* pnpcflag = strtok(NULL, " "); + + uint32 npcflag; + if (!pnpcflag) + npcflag = chr->GetUInt32Value(UNIT_NPC_FLAGS); + else + npcflag = atoi(pnpcflag); + + char* pdyflag = strtok(NULL, " "); + + uint32 dyflag; + if (!pdyflag) + dyflag = chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS); + else + dyflag = atoi(pdyflag); + + if (!sFactionTemplateStore.LookupEntry(factionid)) + { + PSendSysMessage(LANG_WRONG_FACTION, factionid); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_FACTION, chr->GetGUIDLow(),factionid,flag,npcflag,dyflag); + + chr->setFaction(factionid); + chr->SetUInt32Value(UNIT_FIELD_FLAGS,flag); + chr->SetUInt32Value(UNIT_NPC_FLAGS,npcflag); + chr->SetUInt32Value(UNIT_DYNAMIC_FLAGS,dyflag); + + return true; +} + +//Edit Player Spell +bool ChatHandler::HandleModifySpellCommand(const char* args) +{ + if (!*args) return false; + char* pspellflatid = strtok((char*)args, " "); + if (!pspellflatid) + return false; + + char* pop = strtok(NULL, " "); + if (!pop) + return false; + + char* pval = strtok(NULL, " "); + if (!pval) + return false; + + uint16 mark; + + char* pmark = strtok(NULL, " "); + + uint8 spellflatid = atoi(pspellflatid); + uint8 op = atoi(pop); + uint16 val = atoi(pval); + if (!pmark) + mark = 65535; + else + mark = atoi(pmark); + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(chr, 0)) + return false; + + PSendSysMessage(LANG_YOU_CHANGE_SPELLFLATID, spellflatid, val, mark, GetNameLink(chr).c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_SPELLFLATID_CHANGED, GetNameLink().c_str(), spellflatid, val, mark); + + WorldPacket data(SMSG_SET_FLAT_SPELL_MODIFIER, (1+1+2+2)); + data << uint8(spellflatid); + data << uint8(op); + data << uint16(val); + data << uint16(mark); + chr->GetSession()->SendPacket(&data); + + return true; +} + +//Edit Player TP +bool ChatHandler::HandleModifyTalentCommand (const char* args) +{ + if (!*args) + return false; + + int tp = atoi((char*)args); + if (tp < 0) + return false; + + Unit* target = getSelectedUnit(); + if (!target) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if (target->GetTypeId() == TYPEID_PLAYER) + { + // check online security + if (HasLowerSecurity((Player*)target, 0)) + return false; + target->ToPlayer()->SetFreeTalentPoints(tp); + target->ToPlayer()->SendTalentsInfoData(false); + return true; + } + else if (target->ToCreature()->isPet()) + { + Unit *owner = target->GetOwner(); + if (owner && owner->GetTypeId() == TYPEID_PLAYER && ((Pet *)target)->IsPermanentPetFor(owner->ToPlayer())) + { + // check online security + if (HasLowerSecurity((Player*)owner, 0)) + return false; + ((Pet *)target)->SetFreeTalentPoints(tp); + owner->ToPlayer()->SendTalentsInfoData(true); + return true; + } + } + + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; +} + +//Enable On\OFF all taxi paths +bool ChatHandler::HandleTaxiCheatCommand(const char* args) +{ + if (!*args) + { + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; + } + + std::string argstr = (char*)args; + + Player *chr = getSelectedPlayer(); + if (!chr) + { + chr=m_session->GetPlayer(); + } + + // check online security + else if (HasLowerSecurity(chr, 0)) + return false; + + if (argstr == "on") + { + chr->SetTaxiCheater(true); + PSendSysMessage(LANG_YOU_GIVE_TAXIS, GetNameLink(chr).c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_TAXIS_ADDED, GetNameLink().c_str()); + return true; + } + + if (argstr == "off") + { + chr->SetTaxiCheater(false); + PSendSysMessage(LANG_YOU_REMOVE_TAXIS, GetNameLink(chr).c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_TAXIS_REMOVED, GetNameLink().c_str()); + + return true; + } + + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; +} + +//Edit Player Aspeed +bool ChatHandler::HandleModifyASpeedCommand(const char* args) +{ + if (!*args) + return false; + + float ASpeed = (float)atof((char*)args); + + if (ASpeed > 50.0f || ASpeed < 0.1f) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(chr, 0)) + return false; + + std::string chrNameLink = GetNameLink(chr); + + if (chr->isInFlight()) + { + PSendSysMessage(LANG_CHAR_IN_FLIGHT,chrNameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_ASPEED, ASpeed, chrNameLink.c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_ASPEED_CHANGED, GetNameLink().c_str(), ASpeed); + + chr->SetSpeed(MOVE_WALK, ASpeed,true); + chr->SetSpeed(MOVE_RUN, ASpeed,true); + chr->SetSpeed(MOVE_SWIM, ASpeed,true); + //chr->SetSpeed(MOVE_TURN, ASpeed,true); + chr->SetSpeed(MOVE_FLIGHT, ASpeed,true); + return true; +} + +//Edit Player Speed +bool ChatHandler::HandleModifySpeedCommand(const char* args) +{ + if (!*args) + return false; + + float Speed = (float)atof((char*)args); + + if (Speed > 50.0f || Speed < 0.1f) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(chr, 0)) + return false; + + std::string chrNameLink = GetNameLink(chr); + + if (chr->isInFlight()) + { + PSendSysMessage(LANG_CHAR_IN_FLIGHT,chrNameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_SPEED, Speed, chrNameLink.c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_SPEED_CHANGED, GetNameLink().c_str(), Speed); + + chr->SetSpeed(MOVE_RUN,Speed,true); + + return true; +} + +//Edit Player Swim Speed +bool ChatHandler::HandleModifySwimCommand(const char* args) +{ + if (!*args) + return false; + + float Swim = (float)atof((char*)args); + + if (Swim > 50.0f || Swim < 0.1f) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(chr, 0)) + return false; + + std::string chrNameLink = GetNameLink(chr); + + if (chr->isInFlight()) + { + PSendSysMessage(LANG_CHAR_IN_FLIGHT,chrNameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_SWIM_SPEED, Swim, chrNameLink.c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_SWIM_SPEED_CHANGED, GetNameLink().c_str(), Swim); + + chr->SetSpeed(MOVE_SWIM,Swim,true); + + return true; +} + +//Edit Player Walk Speed +bool ChatHandler::HandleModifyBWalkCommand(const char* args) +{ + if (!*args) + return false; + + float BSpeed = (float)atof((char*)args); + + if (BSpeed > 50.0f || BSpeed < 0.1f) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(chr, 0)) + return false; + + std::string chrNameLink = GetNameLink(chr); + + if (chr->isInFlight()) + { + PSendSysMessage(LANG_CHAR_IN_FLIGHT,chrNameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_YOU_CHANGE_BACK_SPEED, BSpeed, chrNameLink.c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_BACK_SPEED_CHANGED, GetNameLink().c_str(), BSpeed); + + chr->SetSpeed(MOVE_RUN_BACK,BSpeed,true); + + return true; +} + +//Edit Player Fly +bool ChatHandler::HandleModifyFlyCommand(const char* args) +{ + if (!*args) + return false; + + float FSpeed = (float)atof((char*)args); + + if (FSpeed > 50.0f || FSpeed < 0.1f) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(chr, 0)) + return false; + + PSendSysMessage(LANG_YOU_CHANGE_FLY_SPEED, FSpeed, GetNameLink(chr).c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_FLY_SPEED_CHANGED, GetNameLink().c_str(), FSpeed); + + chr->SetSpeed(MOVE_FLIGHT,FSpeed,true); + + return true; +} + +//Edit Player Scale +bool ChatHandler::HandleModifyScaleCommand(const char* args) +{ + if (!*args) + return false; + + float Scale = (float)atof((char*)args); + if (Scale > 10.0f || Scale < 0.1f) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(chr, 0)) + return false; + + PSendSysMessage(LANG_YOU_CHANGE_SIZE, Scale, GetNameLink(chr).c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_SIZE_CHANGED, GetNameLink().c_str(), Scale); + + chr->SetFloatValue(OBJECT_FIELD_SCALE_X, Scale); + + return true; +} + +//Enable Player mount +bool ChatHandler::HandleModifyMountCommand(const char* args) +{ + if (!*args) + return false; + + uint16 mId = 1147; + float speed = (float)15; + uint32 num = 0; + + num = atoi((char*)args); + switch(num) + { + case 1: + mId=14340; + break; + case 2: + mId=4806; + break; + case 3: + mId=6471; + break; + case 4: + mId=12345; + break; + case 5: + mId=6472; + break; + case 6: + mId=6473; + break; + case 7: + mId=10670; + break; + case 8: + mId=10719; + break; + case 9: + mId=10671; + break; + case 10: + mId=10672; + break; + case 11: + mId=10720; + break; + case 12: + mId=14349; + break; + case 13: + mId=11641; + break; + case 14: + mId=12244; + break; + case 15: + mId=12242; + break; + case 16: + mId=14578; + break; + case 17: + mId=14579; + break; + case 18: + mId=14349; + break; + case 19: + mId=12245; + break; + case 20: + mId=14335; + break; + case 21: + mId=207; + break; + case 22: + mId=2328; + break; + case 23: + mId=2327; + break; + case 24: + mId=2326; + break; + case 25: + mId=14573; + break; + case 26: + mId=14574; + break; + case 27: + mId=14575; + break; + case 28: + mId=604; + break; + case 29: + mId=1166; + break; + case 30: + mId=2402; + break; + case 31: + mId=2410; + break; + case 32: + mId=2409; + break; + case 33: + mId=2408; + break; + case 34: + mId=2405; + break; + case 35: + mId=14337; + break; + case 36: + mId=6569; + break; + case 37: + mId=10661; + break; + case 38: + mId=10666; + break; + case 39: + mId=9473; + break; + case 40: + mId=9476; + break; + case 41: + mId=9474; + break; + case 42: + mId=14374; + break; + case 43: + mId=14376; + break; + case 44: + mId=14377; + break; + case 45: + mId=2404; + break; + case 46: + mId=2784; + break; + case 47: + mId=2787; + break; + case 48: + mId=2785; + break; + case 49: + mId=2736; + break; + case 50: + mId=2786; + break; + case 51: + mId=14347; + break; + case 52: + mId=14346; + break; + case 53: + mId=14576; + break; + case 54: + mId=9695; + break; + case 55: + mId=9991; + break; + case 56: + mId=6448; + break; + case 57: + mId=6444; + break; + case 58: + mId=6080; + break; + case 59: + mId=6447; + break; + case 60: + mId=4805; + break; + case 61: + mId=9714; + break; + case 62: + mId=6448; + break; + case 63: + mId=6442; + break; + case 64: + mId=14632; + break; + case 65: + mId=14332; + break; + case 66: + mId=14331; + break; + case 67: + mId=8469; + break; + case 68: + mId=2830; + break; + case 69: + mId=2346; + break; + default: + SendSysMessage(LANG_NO_MOUNT); + SetSentErrorMessage(true); + return false; + } + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(chr, 0)) + return false; + + PSendSysMessage(LANG_YOU_GIVE_MOUNT, GetNameLink(chr).c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_MOUNT_GIVED, GetNameLink().c_str()); + + chr->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP); + chr->Mount(mId); + + WorldPacket data(SMSG_FORCE_RUN_SPEED_CHANGE, (8+4+1+4)); + data.append(chr->GetPackGUID()); + data << (uint32)0; + data << (uint8)0; //new 2.1.0 + data << float(speed); + chr->SendMessageToSet(&data, true); + + data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE, (8+4+4)); + data.append(chr->GetPackGUID()); + data << (uint32)0; + data << float(speed); + chr->SendMessageToSet(&data, true); + + return true; +} + +//Edit Player money +bool ChatHandler::HandleModifyMoneyCommand(const char* args) +{ + if (!*args) + return false; + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(chr, 0)) + return false; + + int32 addmoney = atoi((char*)args); + + uint32 moneyuser = chr->GetMoney(); + + if (addmoney < 0) + { + int32 newmoney = int32(moneyuser) + addmoney; + + sLog.outDetail(GetTrinityString(LANG_CURRENT_MONEY), moneyuser, addmoney, newmoney); + if (newmoney <= 0) + { + PSendSysMessage(LANG_YOU_TAKE_ALL_MONEY, GetNameLink(chr).c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_ALL_MONEY_GONE, GetNameLink().c_str()); + + chr->SetMoney(0); + } + else + { + if (newmoney > MAX_MONEY_AMOUNT) + newmoney = MAX_MONEY_AMOUNT; + + PSendSysMessage(LANG_YOU_TAKE_MONEY, abs(addmoney), GetNameLink(chr).c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_MONEY_TAKEN, GetNameLink().c_str(), abs(addmoney)); + chr->SetMoney(newmoney); + } + } + else + { + PSendSysMessage(LANG_YOU_GIVE_MONEY, addmoney, GetNameLink(chr).c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_MONEY_GIVEN, GetNameLink().c_str(), addmoney); + + if (addmoney >=MAX_MONEY_AMOUNT) + chr->SetMoney(MAX_MONEY_AMOUNT); + else + chr->ModifyMoney(addmoney); + } + + sLog.outDetail(GetTrinityString(LANG_NEW_MONEY), moneyuser, addmoney, chr->GetMoney()); + + return true; +} + +//Edit Unit field +bool ChatHandler::HandleModifyBitCommand(const char* args) +{ + if (!*args) + return false; + + Unit *unit = getSelectedUnit(); + if (!unit) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (unit->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity(unit->ToPlayer(), 0)) + return false; + + char* pField = strtok((char*)args, " "); + if (!pField) + return false; + + char* pBit = strtok(NULL, " "); + if (!pBit) + return false; + + uint16 field = atoi(pField); + uint32 bit = atoi(pBit); + + if (field < OBJECT_END || field >= unit->GetValuesCount()) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + if (bit < 1 || bit > 32) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + if (unit->HasFlag(field, (1<<(bit-1)))) + { + unit->RemoveFlag(field, (1<<(bit-1))); + PSendSysMessage(LANG_REMOVE_BIT, bit, field); + } + else + { + unit->SetFlag(field, (1<<(bit-1))); + PSendSysMessage(LANG_SET_BIT, bit, field); + } + return true; +} + +bool ChatHandler::HandleModifyHonorCommand (const char* args) +{ + if (!*args) + return false; + + Player *target = getSelectedPlayer(); + if (!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + int32 amount = (uint32)atoi(args); + + target->ModifyHonorPoints(amount); + + PSendSysMessage(LANG_COMMAND_MODIFY_HONOR, GetNameLink(target).c_str(), target->GetHonorPoints()); + + return true; +} + +bool ChatHandler::HandleTeleCommand(const char * args) +{ + if (!*args) + return false; + + Player* _player = m_session->GetPlayer(); + + // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r + GameTele const* tele = extractGameTeleFromLink((char*)args); + + if (!tele) + { + SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); + SetSentErrorMessage(true); + return false; + } + + if (_player->isInCombat()) + { + SendSysMessage(LANG_YOU_IN_COMBAT); + SetSentErrorMessage(true); + return false; + } + + MapEntry const * me = sMapStore.LookupEntry(tele->mapId); + if (!me || me->IsBattleGroundOrArena()) + { + SendSysMessage(LANG_CANNOT_TELE_TO_BG); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation); + return true; +} + +bool ChatHandler::HandleLookupAreaCommand(const char* args) +{ + if (!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + if (!Utf8toWStr (namepart,wnamepart)) + return false; + + bool found = false; + + // converting string that we try to find to lower case + wstrToLower (wnamepart); + + // Search in AreaTable.dbc + for (uint32 areaflag = 0; areaflag < sAreaStore.GetNumRows (); ++areaflag) + { + AreaTableEntry const *areaEntry = sAreaStore.LookupEntry (areaflag); + if (areaEntry) + { + int loc = GetSessionDbcLocale (); + std::string name = areaEntry->area_name[loc]; + if (name.empty()) + continue; + + if (!Utf8FitTo (name, wnamepart)) + { + loc = 0; + for (; loc < MAX_LOCALE; ++loc) + { + if (loc == GetSessionDbcLocale ()) + continue; + + name = areaEntry->area_name[loc]; + if (name.empty ()) + continue; + + if (Utf8FitTo (name, wnamepart)) + break; + } + } + + if (loc < MAX_LOCALE) + { + // send area in "id - [name]" format + std::ostringstream ss; + if (m_session) + ss << areaEntry->ID << " - |cffffffff|Harea:" << areaEntry->ID << "|h[" << name << " " << localeNames[loc]<< "]|h|r"; + else + ss << areaEntry->ID << " - " << name << " " << localeNames[loc]; + + SendSysMessage (ss.str ().c_str()); + + if (!found) + found = true; + } + } + } + + if (!found) + SendSysMessage (LANG_COMMAND_NOAREAFOUND); + + return true; +} + +//Find tele in game_tele order by name +bool ChatHandler::HandleLookupTeleCommand(const char * args) +{ + if (!*args) + { + SendSysMessage(LANG_COMMAND_TELE_PARAMETER); + SetSentErrorMessage(true); + return false; + } + + char const* str = strtok((char*)args, " "); + if (!str) + return false; + + std::string namepart = str; + std::wstring wnamepart; + + if (!Utf8toWStr(namepart,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower(wnamepart); + + std::ostringstream reply; + + GameTeleMap const & teleMap = objmgr.GetGameTeleMap(); + for (GameTeleMap::const_iterator itr = teleMap.begin(); itr != teleMap.end(); ++itr) + { + GameTele const* tele = &itr->second; + + if (tele->wnameLow.find(wnamepart) == std::wstring::npos) + continue; + + if (m_session) + reply << " |cffffffff|Htele:" << itr->first << "|h[" << tele->name << "]|h|r\n"; + else + reply << " " << itr->first << " " << tele->name << "\n"; + } + + if (reply.str().empty()) + SendSysMessage(LANG_COMMAND_TELE_NOLOCATION); + else + PSendSysMessage(LANG_COMMAND_TELE_LOCATION,reply.str().c_str()); + + return true; +} + +//Enable\Dissable accept whispers (for GM) +bool ChatHandler::HandleWhispersCommand(const char* args) +{ + if (!*args) + { + PSendSysMessage(LANG_COMMAND_WHISPERACCEPTING, m_session->GetPlayer()->isAcceptWhispers() ? GetTrinityString(LANG_ON) : GetTrinityString(LANG_OFF)); + return true; + } + + std::string argstr = (char*)args; + // whisper on + if (argstr == "on") + { + m_session->GetPlayer()->SetAcceptWhispers(true); + SendSysMessage(LANG_COMMAND_WHISPERON); + return true; + } + + // whisper off + if (argstr == "off") + { + m_session->GetPlayer()->SetAcceptWhispers(false); + SendSysMessage(LANG_COMMAND_WHISPEROFF); + return true; + } + + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; +} + +//Save all players in the world +bool ChatHandler::HandleSaveAllCommand(const char* /*args*/) +{ + ObjectAccessor::Instance().SaveAllPlayers(); + SendSysMessage(LANG_PLAYERS_SAVED); + return true; +} + +//Send mail by command +bool ChatHandler::HandleSendMailCommand(const char* args) +{ + // format: name "subject text" "mail text" + Player* target; + uint64 target_guid; + std::string target_name; + if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) + return false; + + char* tail1 = strtok(NULL, ""); + if (!tail1) + return false; + + char* msgSubject = extractQuotedArg(tail1); + if (!msgSubject) + return false; + + char* tail2 = strtok(NULL, ""); + if (!tail2) + return false; + + char* msgText = extractQuotedArg(tail2); + if (!msgText) + return false; + + // msgSubject, msgText isn't NUL after prev. check + std::string subject = msgSubject; + std::string text = msgText; + + // from console show not existed sender + MailSender sender(MAIL_NORMAL,m_session ? m_session->GetPlayer()->GetGUIDLow() : 0, MAIL_STATIONERY_GM); + + MailDraft(subject, text) + .SendMailTo(MailReceiver(target,GUID_LOPART(target_guid)),sender); + + std::string nameLink = playerLink(target_name); + PSendSysMessage(LANG_MAIL_SENT, nameLink.c_str()); + return true; +} + +// teleport player to given game_tele.entry +bool ChatHandler::HandleTeleNameCommand(const char * args) +{ + char* nameStr; + char* teleStr; + extractOptFirstArg((char*)args,&nameStr,&teleStr); + if (!teleStr) + return false; + + Player* target; + uint64 target_guid; + std::string target_name; + if (!extractPlayerTarget(nameStr,&target,&target_guid,&target_name)) + return false; + + // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r + GameTele const* tele = extractGameTeleFromLink(teleStr); + if (!tele) + { + SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); + SetSentErrorMessage(true); + return false; + } + +/* MapEntry const * me = sMapStore.LookupEntry(tele->mapId); + if (!me || me->IsBattleGroundOrArena()) + { + SendSysMessage(LANG_CANNOT_TELE_TO_BG); + SetSentErrorMessage(true); + return false; + } + + Player *chr = objmgr.GetPlayer(name.c_str());*/ + + if (target) + { + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + std::string chrNameLink = playerLink(target_name); + + if (target->IsBeingTeleported() == true) + { + PSendSysMessage(LANG_IS_TELEPORTED, chrNameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_TELEPORTING_TO, chrNameLink.c_str(),"", tele->name.c_str()); + if (needReportToTarget(target)) + ChatHandler(target).PSendSysMessage(LANG_TELEPORTED_TO_BY, GetNameLink().c_str()); + + // stop flight if need + if (target->isInFlight()) + { + target->GetMotionMaster()->MovementExpired(); + target->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + target->SaveRecallPosition(); + + target->TeleportTo(tele->mapId,tele->position_x,tele->position_y,tele->position_z,tele->orientation); + } + else + { + // check offline security + if (HasLowerSecurity(NULL, target_guid)) + return false; + + std::string nameLink = playerLink(target_name); + + PSendSysMessage(LANG_TELEPORTING_TO, nameLink.c_str(), GetTrinityString(LANG_OFFLINE), tele->name.c_str()); + Player::SavePositionInDB(tele->mapId,tele->position_x,tele->position_y,tele->position_z,tele->orientation, + MapManager::Instance().GetZoneId(tele->mapId,tele->position_x,tele->position_y,tele->position_z),target_guid); + } + + return true; +} + +//Teleport group to given game_tele.entry +bool ChatHandler::HandleTeleGroupCommand(const char * args) +{ + if (!*args) + return false; + + Player *player = getSelectedPlayer(); + if (!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(player, 0)) + return false; + + // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r + GameTele const* tele = extractGameTeleFromLink((char*)args); + if (!tele) + { + SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); + SetSentErrorMessage(true); + return false; + } + + MapEntry const * me = sMapStore.LookupEntry(tele->mapId); + if (!me || me->IsBattleGroundOrArena()) + { + SendSysMessage(LANG_CANNOT_TELE_TO_BG); + SetSentErrorMessage(true); + return false; + } + + std::string nameLink = GetNameLink(player); + + Group *grp = player->GetGroup(); + if (!grp) + { + PSendSysMessage(LANG_NOT_IN_GROUP,nameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player *pl = itr->getSource(); + + if (!pl || !pl->GetSession()) + continue; + + // check online security + if (HasLowerSecurity(pl, 0)) + return false; + + std::string plNameLink = GetNameLink(pl); + + if (pl->IsBeingTeleported()) + { + PSendSysMessage(LANG_IS_TELEPORTED, plNameLink.c_str()); + continue; + } + + PSendSysMessage(LANG_TELEPORTING_TO, plNameLink.c_str(),"", tele->name.c_str()); + if (needReportToTarget(pl)) + ChatHandler(pl).PSendSysMessage(LANG_TELEPORTED_TO_BY, nameLink.c_str()); + + // stop flight if need + if (pl->isInFlight()) + { + pl->GetMotionMaster()->MovementExpired(); + pl->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + pl->SaveRecallPosition(); + + pl->TeleportTo(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation); + } + + return true; +} + +//Summon group of player +bool ChatHandler::HandleGroupgoCommand(const char* args) +{ + Player* target; + if (!extractPlayerTarget((char*)args,&target)) + return false; + + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + Group *grp = target->GetGroup(); + + std::string nameLink = GetNameLink(target); + + if (!grp) + { + PSendSysMessage(LANG_NOT_IN_GROUP,nameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + + Map* gmMap = m_session->GetPlayer()->GetMap(); + bool to_instance = gmMap->Instanceable(); + + // we are in instance, and can summon only player in our group with us as lead + if (to_instance && ( + !m_session->GetPlayer()->GetGroup() || (grp->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) || + (m_session->GetPlayer()->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()))) + // the last check is a bit excessive, but let it be, just in case + { + SendSysMessage(LANG_CANNOT_SUMMON_TO_INST); + SetSentErrorMessage(true); + return false; + } + + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player *pl = itr->getSource(); + + if (!pl || pl == m_session->GetPlayer() || !pl->GetSession()) + continue; + + // check online security + if (HasLowerSecurity(pl, 0)) + return false; + + std::string plNameLink = GetNameLink(pl); + + if (pl->IsBeingTeleported() == true) + { + PSendSysMessage(LANG_IS_TELEPORTED, plNameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + + if (to_instance) + { + Map* plMap = pl->GetMap(); + + if (plMap->Instanceable() && plMap->GetInstanceId() != gmMap->GetInstanceId()) + { + // cannot summon from instance to instance + PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,plNameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + } + + PSendSysMessage(LANG_SUMMONING, plNameLink.c_str(),""); + if (needReportToTarget(pl)) + ChatHandler(pl).PSendSysMessage(LANG_SUMMONED_BY, GetNameLink().c_str()); + + // stop flight if need + if (pl->isInFlight()) + { + pl->GetMotionMaster()->MovementExpired(); + pl->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + pl->SaveRecallPosition(); + + // before GM + float x,y,z; + m_session->GetPlayer()->GetClosePoint(x,y,z,pl->GetObjectSize()); + pl->TeleportTo(m_session->GetPlayer()->GetMapId(),x,y,z,pl->GetOrientation()); + } + + return true; +} + +bool ChatHandler::HandleGoTaxinodeCommand(const char* args) +{ + Player* _player = m_session->GetPlayer(); + + if (!*args) + return false; + + char* cNodeId = extractKeyFromLink((char*)args,"Htaxinode"); + if (!cNodeId) + return false; + + int32 i_nodeId = atoi(cNodeId); + if (!i_nodeId) + return false; + + TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i_nodeId); + if (!node) + { + PSendSysMessage(LANG_COMMAND_GOTAXINODENOTFOUND,i_nodeId); + SetSentErrorMessage(true); + return false; + } + + if ((node->x == 0.0f && node->y == 0.0f && node->z == 0.0f) || + !MapManager::IsValidMapCoord(node->map_id,node->x,node->y,node->z)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,node->x,node->y,node->map_id); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(node->map_id, node->x, node->y, node->z, _player->GetOrientation()); + return true; +} + +//teleport at coordinates +bool ChatHandler::HandleGoXYCommand(const char* args) +{ + if (!*args) + return false; + + Player* _player = m_session->GetPlayer(); + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + char* pmapid = strtok(NULL, " "); + + if (!px || !py) + return false; + + float x = (float)atof(px); + float y = (float)atof(py); + uint32 mapid; + if (pmapid) + mapid = (uint32)atoi(pmapid); + else mapid = _player->GetMapId(); + + if (!MapManager::IsValidMapCoord(mapid,x,y)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + Map const *map = MapManager::Instance().CreateBaseMap(mapid); + float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); + + _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); + + return true; +} + +//teleport at coordinates, including Z +bool ChatHandler::HandleGoXYZCommand(const char* args) +{ + if (!*args) + return false; + + Player* _player = m_session->GetPlayer(); + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + char* pz = strtok(NULL, " "); + char* pmapid = strtok(NULL, " "); + + if (!px || !py || !pz) + return false; + + float x = (float)atof(px); + float y = (float)atof(py); + float z = (float)atof(pz); + uint32 mapid; + if (pmapid) + mapid = (uint32)atoi(pmapid); + else + mapid = _player->GetMapId(); + + if (!MapManager::IsValidMapCoord(mapid,x,y,z)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); + + return true; +} + +//teleport at coordinates +bool ChatHandler::HandleGoZoneXYCommand(const char* args) +{ + if (!*args) + return false; + + Player* _player = m_session->GetPlayer(); + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + char* tail = strtok(NULL,""); + + char* cAreaId = extractKeyFromLink(tail,"Harea"); // string or [name] Shift-click form |color|Harea:area_id|h[name]|h|r + + if (!px || !py) + return false; + + float x = (float)atof(px); + float y = (float)atof(py); + + // prevent accept wrong numeric args + if ((x == 0.0f && *px != '0') || (y == 0.0f && *py != '0')) + return false; + + uint32 areaid = cAreaId ? (uint32)atoi(cAreaId) : _player->GetZoneId(); + + AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaid); + + if (x<0 || x>100 || y<0 || y>100 || !areaEntry) + { + PSendSysMessage(LANG_INVALID_ZONE_COORD,x,y,areaid); + SetSentErrorMessage(true); + return false; + } + + // update to parent zone if exist (client map show only zones without parents) + AreaTableEntry const* zoneEntry = areaEntry->zone ? GetAreaEntryByAreaID(areaEntry->zone) : areaEntry; + + Map const *map = MapManager::Instance().CreateBaseMap(zoneEntry->mapid); + + if (map->Instanceable()) + { + PSendSysMessage(LANG_INVALID_ZONE_MAP,areaEntry->ID,areaEntry->area_name[GetSessionDbcLocale()],map->GetId(),map->GetMapName()); + SetSentErrorMessage(true); + return false; + } + + Zone2MapCoordinates(x,y,zoneEntry->ID); + + if (!MapManager::IsValidMapCoord(zoneEntry->mapid,x,y)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,zoneEntry->mapid); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); + _player->TeleportTo(zoneEntry->mapid, x, y, z, _player->GetOrientation()); + + return true; +} + +//teleport to grid +bool ChatHandler::HandleGoGridCommand(const char* args) +{ + if (!*args) return false; + Player* _player = m_session->GetPlayer(); + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + char* pmapid = strtok(NULL, " "); + + if (!px || !py) + return false; + + float grid_x = (float)atof(px); + float grid_y = (float)atof(py); + uint32 mapid; + if (pmapid) + mapid = (uint32)atoi(pmapid); + else mapid = _player->GetMapId(); + + // center of grid + float x = (grid_x-CENTER_GRID_ID+0.5f)*SIZE_OF_GRIDS; + float y = (grid_y-CENTER_GRID_ID+0.5f)*SIZE_OF_GRIDS; + + if (!MapManager::IsValidMapCoord(mapid,x,y)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + Map const *map = MapManager::Instance().CreateBaseMap(mapid); + float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); + _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); + + return true; +} + +bool ChatHandler::HandleModifyDrunkCommand(const char* args) +{ + if (!*args) return false; + + uint32 drunklevel = (uint32)atoi(args); + if (drunklevel > 100) + drunklevel = 100; + + uint16 drunkMod = drunklevel * 0xFFFF / 100; + + m_session->GetPlayer()->SetDrunkValue(drunkMod); + + return true; +} + diff --git a/src/server/game/Chat/Commands/Level2.cpp b/src/server/game/Chat/Commands/Level2.cpp new file mode 100644 index 00000000000..4f299c932e8 --- /dev/null +++ b/src/server/game/Chat/Commands/Level2.cpp @@ -0,0 +1,4526 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "DBCStores.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "Item.h" +#include "GameObject.h" +#include "Opcodes.h" +#include "Chat.h" +#include "MapManager.h" +#include "Language.h" +#include "World.h" +#include "GameEventMgr.h" +#include "SpellMgr.h" +#include "PoolHandler.h" +#include "AccountMgr.h" +#include "WaypointManager.h" +#include "Util.h" +#include +#include +#include +#include +#include "GlobalEvents.h" +#include "OutdoorPvPMgr.h" + +#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand +#include "CreatureGroups.h" + +//mute player for some times +bool ChatHandler::HandleMuteCommand(const char* args) +{ + char* nameStr; + char* delayStr; + extractOptFirstArg((char*)args,&nameStr,&delayStr); + if (!delayStr) + return false; + + char *mutereason = strtok(NULL, "\r"); + std::string mutereasonstr = "No reason"; + if (mutereason != NULL) + mutereasonstr = mutereason; + + Player* target; + uint64 target_guid; + std::string target_name; + if (!extractPlayerTarget(nameStr,&target,&target_guid,&target_name)) + return false; + + uint32 account_id = target ? target->GetSession()->GetAccountId() : objmgr.GetPlayerAccountIdByGUID(target_guid); + + // find only player from same account if any + if (!target) + if (WorldSession* session = sWorld.FindSession(account_id)) + target = session->GetPlayer(); + + uint32 notspeaktime = (uint32) atoi(delayStr); + + // must have strong lesser security level + if (HasLowerSecurity (target,target_guid,true)) + return false; + + time_t mutetime = time(NULL) + notspeaktime*60; + + if (target) + target->GetSession()->m_muteTime = mutetime; + + LoginDatabase.PExecute("UPDATE account SET mutetime = " UI64FMTD " WHERE id = '%u'",uint64(mutetime), account_id); + + if (target) + ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime, mutereasonstr.c_str()); + + std::string nameLink = playerLink(target_name); + + PSendSysMessage(LANG_YOU_DISABLE_CHAT, nameLink.c_str(), notspeaktime, mutereasonstr.c_str()); + + return true; +} + +//unmute player +bool ChatHandler::HandleUnmuteCommand(const char* args) +{ + Player* target; + uint64 target_guid; + std::string target_name; + if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) + return false; + + uint32 account_id = target ? target->GetSession()->GetAccountId() : objmgr.GetPlayerAccountIdByGUID(target_guid); + + // find only player from same account if any + if (!target) + if (WorldSession* session = sWorld.FindSession(account_id)) + target = session->GetPlayer(); + + // must have strong lesser security level + if (HasLowerSecurity (target,target_guid,true)) + return false; + + if (target) + { + if (target->CanSpeak()) + { + SendSysMessage(LANG_CHAT_ALREADY_ENABLED); + SetSentErrorMessage(true); + return false; + } + + target->GetSession()->m_muteTime = 0; + } + + LoginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id); + + if (target) + ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_ENABLED); + + std::string nameLink = playerLink(target_name); + + PSendSysMessage(LANG_YOU_ENABLE_CHAT, nameLink.c_str()); + return true; +} + +bool ChatHandler::HandleGoTicketCommand(const char * args) +{ + if (!*args) + return false; + + char *cstrticket_id = strtok((char*)args, " "); + + if (!cstrticket_id) + return false; + + uint64 ticket_id = atoi(cstrticket_id); + if (!ticket_id) + return false; + + GM_Ticket *ticket = objmgr.GetGMTicket(ticket_id); + if (!ticket) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + float x, y, z; + int mapid; + + x = ticket->pos_x; + y = ticket->pos_y; + z = ticket->pos_z; + mapid = ticket->map; + + Player* _player = m_session->GetPlayer(); + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + else + _player->SaveRecallPosition(); + + _player->TeleportTo(mapid, x, y, z, 1, 0); + return true; +} + +bool ChatHandler::HandleGoTriggerCommand(const char* args) +{ + Player* _player = m_session->GetPlayer(); + + if (!*args) + return false; + + char *atId = strtok((char*)args, " "); + if (!atId) + return false; + + int32 i_atId = atoi(atId); + + if (!i_atId) + return false; + + AreaTriggerEntry const* at = sAreaTriggerStore.LookupEntry(i_atId); + if (!at) + { + PSendSysMessage(LANG_COMMAND_GOAREATRNOTFOUND,i_atId); + SetSentErrorMessage(true); + return false; + } + + if (!MapManager::IsValidMapCoord(at->mapid,at->x,at->y,at->z)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,at->x,at->y,at->mapid); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(at->mapid, at->x, at->y, at->z, _player->GetOrientation()); + return true; +} + +bool ChatHandler::HandleGoGraveyardCommand(const char* args) +{ + Player* _player = m_session->GetPlayer(); + + if (!*args) + return false; + + char *gyId = strtok((char*)args, " "); + if (!gyId) + return false; + + int32 i_gyId = atoi(gyId); + + if (!i_gyId) + return false; + + WorldSafeLocsEntry const* gy = sWorldSafeLocsStore.LookupEntry(i_gyId); + if (!gy) + { + PSendSysMessage(LANG_COMMAND_GRAVEYARDNOEXIST,i_gyId); + SetSentErrorMessage(true); + return false; + } + + if (!MapManager::IsValidMapCoord(gy->map_id,gy->x,gy->y,gy->z)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,gy->x,gy->y,gy->map_id); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(gy->map_id, gy->x, gy->y, gy->z, _player->GetOrientation()); + return true; +} + +/** \brief Teleport the GM to the specified creature +* +* .gocreature --> TP using creature.guid +* .gocreature azuregos --> TP player to the mob with this name +* Warning: If there is more than one mob with this name +* you will be teleported to the first one that is found. +* .gocreature id 6109 --> TP player to the mob, that has this creature_template.entry +* Warning: If there is more than one mob with this "id" +* you will be teleported to the first one that is found. +*/ +//teleport to creature +bool ChatHandler::HandleGoCreatureCommand(const char* args) +{ + if (!*args) + return false; + Player* _player = m_session->GetPlayer(); + + // "id" or number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r + char* pParam1 = extractKeyFromLink((char*)args,"Hcreature"); + if (!pParam1) + return false; + + std::ostringstream whereClause; + + // User wants to teleport to the NPC's template entry + if (strcmp(pParam1, "id") == 0) + { + //sLog.outError("DEBUG: ID found"); + + // Get the "creature_template.entry" + // number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r + char* tail = strtok(NULL,""); + if (!tail) + return false; + char* cId = extractKeyFromLink(tail,"Hcreature_entry"); + if (!cId) + return false; + + int32 tEntry = atoi(cId); + //sLog.outError("DEBUG: ID value: %d", tEntry); + if (!tEntry) + return false; + + whereClause << "WHERE id = '" << tEntry << "'"; + } + else + { + //sLog.outError("DEBUG: ID *not found*"); + + int32 guid = atoi(pParam1); + + // Number is invalid - maybe the user specified the mob's name + if (!guid) + { + std::string name = pParam1; + WorldDatabase.escape_string(name); + whereClause << ", creature_template WHERE creature.id = creature_template.entry AND creature_template.name "_LIKE_" '" << name << "'"; + } + else + { + whereClause << "WHERE guid = '" << guid << "'"; + } + } + //sLog.outError("DEBUG: %s", whereClause.c_str()); + + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM creature %s", whereClause.str().c_str()); + if (!result) + { + SendSysMessage(LANG_COMMAND_GOCREATNOTFOUND); + SetSentErrorMessage(true); + return false; + } + if (result->GetRowCount() > 1) + SendSysMessage(LANG_COMMAND_GOCREATMULTIPLE); + + Field *fields = result->Fetch(); + float x = fields[0].GetFloat(); + float y = fields[1].GetFloat(); + float z = fields[2].GetFloat(); + float ort = fields[3].GetFloat(); + int mapid = fields[4].GetUInt16(); + + if (!MapManager::IsValidMapCoord(mapid,x,y,z,ort)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(mapid, x, y, z, ort); + return true; +} + +//teleport to gameobject +bool ChatHandler::HandleGoObjectCommand(const char* args) +{ + if (!*args) + return false; + + Player* _player = m_session->GetPlayer(); + + // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject"); + if (!cId) + return false; + + int32 guid = atoi(cId); + if (!guid) + return false; + + float x, y, z, ort; + int mapid; + + // by DB guid + if (GameObjectData const* go_data = objmgr.GetGOData(guid)) + { + x = go_data->posX; + y = go_data->posY; + z = go_data->posZ; + ort = go_data->orientation; + mapid = go_data->mapid; + } + else + { + SendSysMessage(LANG_COMMAND_GOOBJNOTFOUND); + SetSentErrorMessage(true); + return false; + } + + if (!MapManager::IsValidMapCoord(mapid,x,y,z,ort)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(mapid, x, y, z, ort); + return true; +} + +bool ChatHandler::HandleGameObjectTargetCommand(const char* args) +{ + Player* pl = m_session->GetPlayer(); + QueryResult_AutoPtr result; + GameEventMgr::ActiveEvents const& activeEventsList = gameeventmgr.GetActiveEventList(); + if (*args) + { + // number or [name] Shift-click form |color|Hgameobject_entry:go_id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject_entry"); + if (!cId) + return false; + + uint32 id = atol(cId); + + if (id) + result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, orientation, map, phaseMask, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM gameobject WHERE map = '%i' AND id = '%u' ORDER BY order_ ASC LIMIT 1", + pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),id); + else + { + std::string name = cId; + WorldDatabase.escape_string(name); + result = WorldDatabase.PQuery( + "SELECT guid, id, position_x, position_y, position_z, orientation, map, phaseMask, (POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ " + "FROM gameobject,gameobject_template WHERE gameobject_template.entry = gameobject.id AND map = %i AND name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")" ORDER BY order_ ASC LIMIT 1", + pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),name.c_str()); + } + } + else + { + std::ostringstream eventFilter; + eventFilter << " AND (event IS NULL "; + bool initString = true; + + for (GameEventMgr::ActiveEvents::const_iterator itr = activeEventsList.begin(); itr != activeEventsList.end(); ++itr) + { + if (initString) + { + eventFilter << "OR event IN (" <<*itr; + initString =false; + } + else + eventFilter << "," << *itr; + } + + if (!initString) + eventFilter << "))"; + else + eventFilter << ")"; + + result = WorldDatabase.PQuery("SELECT gameobject.guid, id, position_x, position_y, position_z, orientation, map, phaseMask, " + "(POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ FROM gameobject " + "LEFT OUTER JOIN game_event_gameobject on gameobject.guid=game_event_gameobject.guid WHERE map = '%i' %s ORDER BY order_ ASC LIMIT 10", + m_session->GetPlayer()->GetPositionX(), m_session->GetPlayer()->GetPositionY(), m_session->GetPlayer()->GetPositionZ(), m_session->GetPlayer()->GetMapId(),eventFilter.str().c_str()); + } + + if (!result) + { + SendSysMessage(LANG_COMMAND_TARGETOBJNOTFOUND); + return true; + } + + bool found = false; + float x, y, z, o; + uint32 lowguid, id; + uint16 mapid, pool_id, phase; + + do + { + Field *fields = result->Fetch(); + lowguid = fields[0].GetUInt32(); + id = fields[1].GetUInt32(); + x = fields[2].GetFloat(); + y = fields[3].GetFloat(); + z = fields[4].GetFloat(); + o = fields[5].GetFloat(); + mapid = fields[6].GetUInt16(); + phase = fields[7].GetUInt16(); + pool_id = poolhandler.IsPartOfAPool(lowguid); + if (!pool_id || poolhandler.IsSpawnedObject(lowguid)) + found = true; + } while (result->NextRow() && (!found)); + + if (!found) + { + PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id); + return false; + } + + GameObjectInfo const* goI = objmgr.GetGameObjectInfo(id); + + if (!goI) + { + PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id); + return false; + } + + GameObject* target = m_session->GetPlayer()->GetMap()->GetGameObject(MAKE_NEW_GUID(lowguid,id,HIGHGUID_GAMEOBJECT)); + + PSendSysMessage(LANG_GAMEOBJECT_DETAIL, lowguid, goI->name, lowguid, id, x, y, z, mapid, o, phase); + + if (target) + { + int32 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL); + if (curRespawnDelay < 0) + curRespawnDelay = 0; + + std::string curRespawnDelayStr = secsToTimeString(curRespawnDelay,true); + std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(),true); + + PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(),curRespawnDelayStr.c_str()); + } + return true; +} + +//delete object by selection or guid +bool ChatHandler::HandleGameObjectDeleteCommand(const char* args) +{ + // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject"); + if (!cId) + return false; + + uint32 lowguid = atoi(cId); + if (!lowguid) + return false; + + GameObject* obj = NULL; + + // by DB guid + if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) + obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); + + if (!obj) + { + PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + uint64 owner_guid = obj->GetOwnerGUID(); + if (owner_guid) + { + Unit* owner = ObjectAccessor::GetUnit(*m_session->GetPlayer(),owner_guid); + if (!owner || !IS_PLAYER_GUID(owner_guid)) + { + PSendSysMessage(LANG_COMMAND_DELOBJREFERCREATURE, GUID_LOPART(owner_guid), obj->GetGUIDLow()); + SetSentErrorMessage(true); + return false; + } + + owner->RemoveGameObject(obj,false); + } + + obj->SetRespawnTime(0); // not save respawn time + obj->Delete(); + obj->DeleteFromDB(); + + PSendSysMessage(LANG_COMMAND_DELOBJMESSAGE, obj->GetGUIDLow()); + + return true; +} + +//turn selected object +bool ChatHandler::HandleGameObjectTurnCommand(const char* args) +{ + // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject"); + if (!cId) + return false; + + uint32 lowguid = atoi(cId); + if (!lowguid) + return false; + + GameObject* obj = NULL; + + // by DB guid + if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) + obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); + + if (!obj) + { + PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + char* po = strtok(NULL, " "); + float o; + + if (po) + { + o = (float)atof(po); + } + else + { + Player *chr = m_session->GetPlayer(); + o = chr->GetOrientation(); + } + + obj->Relocate(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), o); + obj->UpdateRotationFields(); + obj->DestroyForNearbyPlayers(); + obj->UpdateObjectVisibility(); + + obj->SaveToDB(); + obj->Refresh(); + + PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, obj->GetGUIDLow(), obj->GetGOInfo()->name, obj->GetGUIDLow(), o); + + return true; +} + +//move selected object +bool ChatHandler::HandleGameObjectMoveCommand(const char* args) +{ + // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject"); + if (!cId) + return false; + + uint32 lowguid = atoi(cId); + if (!lowguid) + return false; + + GameObject* obj = NULL; + + // by DB guid + if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) + obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); + + if (!obj) + { + PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + char* px = strtok(NULL, " "); + char* py = strtok(NULL, " "); + char* pz = strtok(NULL, " "); + + if (!px) + { + Player *chr = m_session->GetPlayer(); + obj->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), obj->GetOrientation()); + obj->DestroyForNearbyPlayers(); + obj->UpdateObjectVisibility(); + } + else + { + if (!py || !pz) + return false; + + float x = (float)atof(px); + float y = (float)atof(py); + float z = (float)atof(pz); + + if (!MapManager::IsValidMapCoord(obj->GetMapId(),x,y,z)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,obj->GetMapId()); + SetSentErrorMessage(true); + return false; + } + + obj->Relocate(x, y, z, obj->GetOrientation()); + obj->DestroyForNearbyPlayers(); + obj->UpdateObjectVisibility(); + } + + obj->SaveToDB(); + obj->Refresh(); + + PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, obj->GetGUIDLow(), obj->GetGOInfo()->name, obj->GetGUIDLow()); + + return true; +} + +//spawn go +bool ChatHandler::HandleGameObjectAddCommand(const char* args) +{ + if (!*args) + return false; + + // number or [name] Shift-click form |color|Hgameobject_entry:go_id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject_entry"); + if (!cId) + return false; + + uint32 id = atol(cId); + if (!id) + return false; + + char* spawntimeSecs = strtok(NULL, " "); + + const GameObjectInfo *gInfo = objmgr.GetGameObjectInfo(id); + + if (!gInfo) + { + PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id); + SetSentErrorMessage(true); + return false; + } + + if (gInfo->displayId && !sGameObjectDisplayInfoStore.LookupEntry(gInfo->displayId)) + { + // report to DB errors log as in loading case + sLog.outErrorDb("Gameobject (Entry %u GoType: %u) have invalid displayId (%u), not spawned.",id, gInfo->type, gInfo->displayId); + PSendSysMessage(LANG_GAMEOBJECT_HAVE_INVALID_DATA,id); + SetSentErrorMessage(true); + return false; + } + + Player *chr = m_session->GetPlayer(); + float x = float(chr->GetPositionX()); + float y = float(chr->GetPositionY()); + float z = float(chr->GetPositionZ()); + float o = float(chr->GetOrientation()); + Map *map = chr->GetMap(); + + GameObject* pGameObj = new GameObject; + uint32 db_lowGUID = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT); + + if (!pGameObj->Create(db_lowGUID, gInfo->id, map, chr->GetPhaseMaskForSpawn(), x, y, z, o, 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) + { + delete pGameObj; + return false; + } + + if (spawntimeSecs) + { + uint32 value = atoi((char*)spawntimeSecs); + pGameObj->SetRespawnTime(value); + //sLog.outDebug("*** spawntimeSecs: %d", value); + } + + // fill the gameobject data and save to the db + pGameObj->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()),chr->GetPhaseMaskForSpawn()); + + // this will generate a new guid if the object is in an instance + if (!pGameObj->LoadFromDB(db_lowGUID, map)) + { + delete pGameObj; + return false; + } + + sLog.outDebug(GetTrinityString(LANG_GAMEOBJECT_CURRENT), gInfo->name, db_lowGUID, x, y, z, o); + + map->Add(pGameObj); + + // TODO: is it really necessary to add both the real and DB table guid here ? + objmgr.AddGameobjectToGrid(db_lowGUID, objmgr.GetGOData(db_lowGUID)); + + PSendSysMessage(LANG_GAMEOBJECT_ADD,id,gInfo->name,db_lowGUID,x,y,z); + return true; +} + +//set pahsemask for selected object +bool ChatHandler::HandleGameObjectPhaseCommand(const char* args) +{ + // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject"); + if (!cId) + return false; + + uint32 lowguid = atoi(cId); + if (!lowguid) + return false; + + GameObject* obj = NULL; + + // by DB guid + if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) + obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); + + if (!obj) + { + PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + char* phaseStr = strtok (NULL, " "); + uint32 phasemask = phaseStr? atoi(phaseStr) : 0; + if (phasemask == 0) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + obj->SetPhaseMask(phasemask,true); + obj->SaveToDB(); + return true; +} + +bool ChatHandler::HandleGameObjectNearCommand(const char* args) +{ + float distance = (!*args) ? 10 : atol(args); + uint32 count = 0; + + Player* pl = m_session->GetPlayer(); + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, map, " + "(POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ " + "FROM gameobject WHERE map='%u' AND (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) <= '%f' ORDER BY order_", + pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), + pl->GetMapId(),pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(),distance*distance); + + if (result) + { + do + { + Field *fields = result->Fetch(); + uint32 guid = fields[0].GetUInt32(); + uint32 entry = fields[1].GetUInt32(); + float x = fields[2].GetFloat(); + float y = fields[3].GetFloat(); + float z = fields[4].GetFloat(); + int mapid = fields[5].GetUInt16(); + + GameObjectInfo const * gInfo = objmgr.GetGameObjectInfo(entry); + + if (!gInfo) + continue; + + PSendSysMessage(LANG_GO_LIST_CHAT, guid, guid, gInfo->name, x, y, z, mapid); + + ++count; + } while (result->NextRow()); + } + + PSendSysMessage(LANG_COMMAND_NEAROBJMESSAGE,distance,count); + return true; +} + +bool ChatHandler::HandleGUIDCommand(const char* /*args*/) +{ + uint64 guid = m_session->GetPlayer()->GetSelection(); + + if (guid == 0) + { + SendSysMessage(LANG_NO_SELECTION); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_OBJECT_GUID, GUID_LOPART(guid), GUID_HIPART(guid)); + return true; +} + +bool ChatHandler::HandleModifyRepCommand(const char * args) +{ + if (!*args) return false; + + Player* target = NULL; + target = getSelectedPlayer(); + + if (!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + char* factionTxt = extractKeyFromLink((char*)args,"Hfaction"); + if (!factionTxt) + return false; + + uint32 factionId = atoi(factionTxt); + + int32 amount = 0; + char *rankTxt = strtok(NULL, " "); + if (!factionTxt || !rankTxt) + return false; + + amount = atoi(rankTxt); + if ((amount == 0) && (rankTxt[0] != '-') && !isdigit(rankTxt[0])) + { + std::string rankStr = rankTxt; + std::wstring wrankStr; + if (!Utf8toWStr(rankStr,wrankStr)) + return false; + wstrToLower(wrankStr); + + int r = 0; + amount = -42000; + for (; r < MAX_REPUTATION_RANK; ++r) + { + std::string rank = GetTrinityString(ReputationRankStrIndex[r]); + if (rank.empty()) + continue; + + std::wstring wrank; + if (!Utf8toWStr(rank,wrank)) + continue; + + wstrToLower(wrank); + + if (wrank.substr(0,wrankStr.size()) == wrankStr) + { + char *deltaTxt = strtok(NULL, " "); + if (deltaTxt) + { + int32 delta = atoi(deltaTxt); + if ((delta < 0) || (delta > ReputationMgr::PointsInRank[r] -1)) + { + PSendSysMessage(LANG_COMMAND_FACTION_DELTA, (ReputationMgr::PointsInRank[r]-1)); + SetSentErrorMessage(true); + return false; + } + amount += delta; + } + break; + } + amount += ReputationMgr::PointsInRank[r]; + } + if (r >= MAX_REPUTATION_RANK) + { + PSendSysMessage(LANG_COMMAND_FACTION_INVPARAM, rankTxt); + SetSentErrorMessage(true); + return false; + } + } + + FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionId); + + if (!factionEntry) + { + PSendSysMessage(LANG_COMMAND_FACTION_UNKNOWN, factionId); + SetSentErrorMessage(true); + return false; + } + + if (factionEntry->reputationListID < 0) + { + PSendSysMessage(LANG_COMMAND_FACTION_NOREP_ERROR, factionEntry->name[GetSessionDbcLocale()], factionId); + SetSentErrorMessage(true); + return false; + } + + target->GetReputationMgr().SetReputation(factionEntry,amount); + PSendSysMessage(LANG_COMMAND_MODIFY_REP, factionEntry->name[GetSessionDbcLocale()], factionId, + GetNameLink(target).c_str(), target->GetReputationMgr().GetReputation(factionEntry)); + return true; +} + +//-----------------------Npc Commands----------------------- +//add spawn of creature +bool ChatHandler::HandleNpcAddCommand(const char* args) +{ + if (!*args) + return false; + char* charID = extractKeyFromLink((char*)args,"Hcreature_entry"); + if (!charID) + return false; + + char* team = strtok(NULL, " "); + int32 teamval = 0; + if (team) { teamval = atoi(team); } + if (teamval < 0) { teamval = 0; } + + uint32 id = atoi(charID); + + Player *chr = m_session->GetPlayer(); + float x = chr->GetPositionX(); + float y = chr->GetPositionY(); + float z = chr->GetPositionZ(); + float o = chr->GetOrientation(); + Map *map = chr->GetMap(); + + Creature* pCreature = new Creature; + if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, (uint32)teamval, x, y, z, o)) + { + delete pCreature; + return false; + } + + pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + + uint32 db_guid = pCreature->GetDBTableGUIDLow(); + + // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); + pCreature->LoadFromDB(db_guid, map); + + map->Add(pCreature); + objmgr.AddCreatureToGrid(db_guid, objmgr.GetCreatureData(db_guid)); + return true; +} + +//add item in vendorlist +bool ChatHandler::HandleNpcAddVendorItemCommand(const char* args) +{ + if (!*args) + return false; + + char* pitem = extractKeyFromLink((char*)args,"Hitem"); + if (!pitem) + { + SendSysMessage(LANG_COMMAND_NEEDITEMSEND); + SetSentErrorMessage(true); + return false; + } + + uint32 itemId = atol(pitem); + + char* fmaxcount = strtok(NULL, " "); //add maxcount, default: 0 + uint32 maxcount = 0; + if (fmaxcount) + maxcount = atol(fmaxcount); + + char* fincrtime = strtok(NULL, " "); //add incrtime, default: 0 + uint32 incrtime = 0; + if (fincrtime) + incrtime = atol(fincrtime); + + char* fextendedcost = strtok(NULL, " "); //add ExtendedCost, default: 0 + uint32 extendedcost = fextendedcost ? atol(fextendedcost) : 0; + + Creature* vendor = getSelectedCreature(); + + uint32 vendor_entry = vendor ? vendor->GetEntry() : 0; + + if (!objmgr.IsVendorItemValid(vendor_entry,itemId,maxcount,incrtime,extendedcost,m_session->GetPlayer())) + { + SetSentErrorMessage(true); + return false; + } + + objmgr.AddVendorItem(vendor_entry,itemId,maxcount,incrtime,extendedcost); + + ItemPrototype const* pProto = objmgr.GetItemPrototype(itemId); + + PSendSysMessage(LANG_ITEM_ADDED_TO_LIST,itemId,pProto->Name1,maxcount,incrtime,extendedcost); + return true; +} + +//del item from vendor list +bool ChatHandler::HandleNpcDelVendorItemCommand(const char* args) +{ + if (!*args) + return false; + + Creature* vendor = getSelectedCreature(); + if (!vendor || !vendor->isVendor()) + { + SendSysMessage(LANG_COMMAND_VENDORSELECTION); + SetSentErrorMessage(true); + return false; + } + + char* pitem = extractKeyFromLink((char*)args,"Hitem"); + if (!pitem) + { + SendSysMessage(LANG_COMMAND_NEEDITEMSEND); + SetSentErrorMessage(true); + return false; + } + uint32 itemId = atol(pitem); + + if (!objmgr.RemoveVendorItem(vendor->GetEntry(),itemId)) + { + PSendSysMessage(LANG_ITEM_NOT_IN_LIST,itemId); + SetSentErrorMessage(true); + return false; + } + + ItemPrototype const* pProto = objmgr.GetItemPrototype(itemId); + + PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST,itemId,pProto->Name1); + return true; +} + +//add move for creature +bool ChatHandler::HandleNpcAddMoveCommand(const char* args) +{ + if (!*args) + return false; + + char* guid_str = strtok((char*)args, " "); + char* wait_str = strtok((char*)NULL, " "); + + uint32 lowguid = atoi((char*)guid_str); + + Creature* pCreature = NULL; + + /* FIXME: impossible without entry + if (lowguid) + pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); + */ + + // attempt check creature existence by DB data + if (!pCreature) + { + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if (!data) + { + PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + } + else + { + // obtain real GUID for DB operations + lowguid = pCreature->GetDBTableGUIDLow(); + } + + int wait = wait_str ? atoi(wait_str) : 0; + + if (wait < 0) + wait = 0; + + //Player* player = m_session->GetPlayer(); + + //WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), wait, 0); + + // update movement type + WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid); + if (pCreature && pCreature->GetWaypointPath()) + { + pCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); + pCreature->GetMotionMaster()->Initialize(); + if (pCreature->isAlive()) // dead creature will reset movement generator at respawn + { + pCreature->setDeathState(JUST_DIED); + pCreature->Respawn(true); + } + pCreature->SaveToDB(); + } + + SendSysMessage(LANG_WAYPOINT_ADDED); + + return true; +} + +//change level of creature or pet +bool ChatHandler::HandleNpcChangeLevelCommand(const char* args) +{ + if (!*args) + return false; + + uint8 lvl = (uint8) atoi((char*)args); + if (lvl < 1 || lvl > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) + 3) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Creature* pCreature = getSelectedCreature(); + if (!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if (pCreature->isPet()) + { + if (((Pet*)pCreature)->getPetType() == HUNTER_PET) + { + pCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, objmgr.GetXPForLevel(lvl)/4); + pCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0); + } + ((Pet*)pCreature)->GivePetLevel(lvl); + } + else + { + pCreature->SetMaxHealth(100 + 30*lvl); + pCreature->SetHealth(100 + 30*lvl); + pCreature->SetLevel(lvl); + pCreature->SaveToDB(); + } + + return true; +} + +//set npcflag of creature +bool ChatHandler::HandleNpcFlagCommand(const char* args) +{ + if (!*args) + return false; + + uint32 npcFlags = (uint32) atoi((char*)args); + + Creature* pCreature = getSelectedCreature(); + + if (!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags); + + WorldDatabase.PExecuteLog("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry()); + + SendSysMessage(LANG_VALUE_SAVED_REJOIN); + + return true; +} + +bool ChatHandler::HandleNpcDeleteCommand(const char* args) +{ + Creature* unit = NULL; + + if (*args) + { + // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hcreature"); + if (!cId) + return false; + + uint32 lowguid = atoi(cId); + if (!lowguid) + return false; + + if (CreatureData const* cr_data = objmgr.GetCreatureData(lowguid)) + unit = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(lowguid, cr_data->id, HIGHGUID_UNIT)); + } + else + unit = getSelectedCreature(); + + if (!unit || unit->isPet() || unit->isTotem()) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + // Delete the creature + unit->CombatStop(); + unit->DeleteFromDB(); + unit->AddObjectToRemoveList(); + + SendSysMessage(LANG_COMMAND_DELCREATMESSAGE); + + return true; +} + +//move selected creature +bool ChatHandler::HandleNpcMoveCommand(const char* args) +{ + uint32 lowguid = 0; + + Creature* pCreature = getSelectedCreature(); + + if (!pCreature) + { + // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hcreature"); + if (!cId) + return false; + + lowguid = atoi(cId); + + /* FIXME: impossibel without entry + if (lowguid) + pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); + */ + + // Attempting creature load from DB data + if (!pCreature) + { + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if (!data) + { + PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + uint32 map_id = data->mapid; + + if (m_session->GetPlayer()->GetMapId() != map_id) + { + PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid); + SetSentErrorMessage(true); + return false; + } + } + else + { + lowguid = pCreature->GetDBTableGUIDLow(); + } + } + else + { + lowguid = pCreature->GetDBTableGUIDLow(); + } + + float x = m_session->GetPlayer()->GetPositionX(); + float y = m_session->GetPlayer()->GetPositionY(); + float z = m_session->GetPlayer()->GetPositionZ(); + float o = m_session->GetPlayer()->GetOrientation(); + + if (pCreature) + { + if (CreatureData const* data = objmgr.GetCreatureData(pCreature->GetDBTableGUIDLow())) + { + const_cast(data)->posX = x; + const_cast(data)->posY = y; + const_cast(data)->posZ = z; + const_cast(data)->orientation = o; + } + pCreature->GetMap()->CreatureRelocation(pCreature,x, y, z,o); + pCreature->GetMotionMaster()->Initialize(); + if (pCreature->isAlive()) // dead creature will reset movement generator at respawn + { + pCreature->setDeathState(JUST_DIED); + pCreature->Respawn(); + } + } + + WorldDatabase.PExecuteLog("UPDATE creature SET position_x = '%f', position_y = '%f', position_z = '%f', orientation = '%f' WHERE guid = '%u'", x, y, z, o, lowguid); + PSendSysMessage(LANG_COMMAND_CREATUREMOVED); + return true; +} + +/**HandleNpcSetMoveTypeCommand + * Set the movement type for an NPC.
+ *
+ * Valid movement types are: + *
    + *
  • stay - NPC wont move
  • + *
  • random - NPC will move randomly according to the spawndist
  • + *
  • way - NPC will move with given waypoints set
  • + *
+ * additional parameter: NODEL - so no waypoints are deleted, if you + * change the movement type + */ +bool ChatHandler::HandleNpcSetMoveTypeCommand(const char* args) +{ + if (!*args) + return false; + + // 3 arguments: + // GUID (optional - you can also select the creature) + // stay|random|way (determines the kind of movement) + // NODEL (optional - tells the system NOT to delete any waypoints) + // this is very handy if you want to do waypoints, that are + // later switched on/off according to special events (like escort + // quests, etc) + char* guid_str = strtok((char*)args, " "); + char* type_str = strtok((char*)NULL, " "); + char* dontdel_str = strtok((char*)NULL, " "); + + bool doNotDelete = false; + + if (!guid_str) + return false; + + uint32 lowguid = 0; + Creature* pCreature = NULL; + + if (dontdel_str) + { + //sLog.outError("DEBUG: All 3 params are set"); + + // All 3 params are set + // GUID + // type + // doNotDEL + if (stricmp(dontdel_str, "NODEL") == 0) + { + //sLog.outError("DEBUG: doNotDelete = true;"); + doNotDelete = true; + } + } + else + { + // Only 2 params - but maybe NODEL is set + if (type_str) + { + sLog.outError("DEBUG: Only 2 params "); + if (stricmp(type_str, "NODEL") == 0) + { + //sLog.outError("DEBUG: type_str, NODEL "); + doNotDelete = true; + type_str = NULL; + } + } + } + + if (!type_str) // case .setmovetype $move_type (with selected creature) + { + type_str = guid_str; + pCreature = getSelectedCreature(); + if (!pCreature || pCreature->isPet()) + return false; + lowguid = pCreature->GetDBTableGUIDLow(); + } + else // case .setmovetype #creature_guid $move_type (with selected creature) + { + lowguid = atoi((char*)guid_str); + + /* impossible without entry + if (lowguid) + pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); + */ + + // attempt check creature existence by DB data + if (!pCreature) + { + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if (!data) + { + PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + } + else + { + lowguid = pCreature->GetDBTableGUIDLow(); + } + } + + // now lowguid is low guid really existed creature + // and pCreature point (maybe) to this creature or NULL + + MovementGeneratorType move_type; + + std::string type = type_str; + + if (type == "stay") + move_type = IDLE_MOTION_TYPE; + else if (type == "random") + move_type = RANDOM_MOTION_TYPE; + else if (type == "way") + move_type = WAYPOINT_MOTION_TYPE; + else + return false; + + // update movement type + //if (doNotDelete == false) + // WaypointMgr.DeletePath(lowguid); + + if (pCreature) + { + // update movement type + if (doNotDelete == false) + pCreature->LoadPath(0); + + pCreature->SetDefaultMovementType(move_type); + pCreature->GetMotionMaster()->Initialize(); + if (pCreature->isAlive()) // dead creature will reset movement generator at respawn + { + pCreature->setDeathState(JUST_DIED); + pCreature->Respawn(); + } + pCreature->SaveToDB(); + } + if (doNotDelete == false) + { + PSendSysMessage(LANG_MOVE_TYPE_SET,type_str); + } + else + { + PSendSysMessage(LANG_MOVE_TYPE_SET_NODEL,type_str); + } + + return true; +} + +//set model of creature +bool ChatHandler::HandleNpcSetModelCommand(const char* args) +{ + if (!*args) + return false; + + uint32 displayId = (uint32) atoi((char*)args); + + Creature *pCreature = getSelectedCreature(); + + if (!pCreature || pCreature->isPet()) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->SetDisplayId(displayId); + pCreature->SetNativeDisplayId(displayId); + + pCreature->SaveToDB(); + + return true; +} +//set faction of creature +bool ChatHandler::HandleNpcFactionIdCommand(const char* args) +{ + if (!*args) + return false; + + uint32 factionId = (uint32) atoi((char*)args); + + if (!sFactionTemplateStore.LookupEntry(factionId)) + { + PSendSysMessage(LANG_WRONG_FACTION, factionId); + SetSentErrorMessage(true); + return false; + } + + Creature* pCreature = getSelectedCreature(); + + if (!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->setFaction(factionId); + + // faction is set in creature_template - not inside creature + + // update in memory + if (CreatureInfo const *cinfo = pCreature->GetCreatureInfo()) + { + const_cast(cinfo)->faction_A = factionId; + const_cast(cinfo)->faction_H = factionId; + } + + // and DB + WorldDatabase.PExecuteLog("UPDATE creature_template SET faction_A = '%u', faction_H = '%u' WHERE entry = '%u'", factionId, factionId, pCreature->GetEntry()); + + return true; +} +//set spawn dist of creature +bool ChatHandler::HandleNpcSpawnDistCommand(const char* args) +{ + if (!*args) + return false; + + float option = atof((char*)args); + if (option < 0.0f) + { + SendSysMessage(LANG_BAD_VALUE); + return false; + } + + MovementGeneratorType mtype = IDLE_MOTION_TYPE; + if (option >0.0f) + mtype = RANDOM_MOTION_TYPE; + + Creature *pCreature = getSelectedCreature(); + uint32 u_guidlow = 0; + + if (pCreature) + u_guidlow = pCreature->GetDBTableGUIDLow(); + else + return false; + + pCreature->SetRespawnRadius((float)option); + pCreature->SetDefaultMovementType(mtype); + pCreature->GetMotionMaster()->Initialize(); + if (pCreature->isAlive()) // dead creature will reset movement generator at respawn + { + pCreature->setDeathState(JUST_DIED); + pCreature->Respawn(); + } + + WorldDatabase.PExecuteLog("UPDATE creature SET spawndist=%f, MovementType=%i WHERE guid=%u",option,mtype,u_guidlow); + PSendSysMessage(LANG_COMMAND_SPAWNDIST,option); + return true; +} +//spawn time handling +bool ChatHandler::HandleNpcSpawnTimeCommand(const char* args) +{ + if (!*args) + return false; + + char* stime = strtok((char*)args, " "); + + if (!stime) + return false; + + int i_stime = atoi((char*)stime); + + if (i_stime < 0) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Creature *pCreature = getSelectedCreature(); + uint32 u_guidlow = 0; + + if (pCreature) + u_guidlow = pCreature->GetDBTableGUIDLow(); + else + return false; + + WorldDatabase.PExecuteLog("UPDATE creature SET spawntimesecs=%i WHERE guid=%u",i_stime,u_guidlow); + pCreature->SetRespawnDelay((uint32)i_stime); + PSendSysMessage(LANG_COMMAND_SPAWNTIME,i_stime); + + return true; +} +//npc follow handling +bool ChatHandler::HandleNpcFollowCommand(const char* /*args*/) +{ + Player *player = m_session->GetPlayer(); + Creature *creature = getSelectedCreature(); + + if (!creature) + { + PSendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + // Follow player - Using pet's default dist and angle + creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, creature->GetFollowAngle()); + + PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName()); + return true; +} +//npc unfollow handling +bool ChatHandler::HandleNpcUnFollowCommand(const char* /*args*/) +{ + Player *player = m_session->GetPlayer(); + Creature *creature = getSelectedCreature(); + + if (!creature) + { + PSendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if (/*creature->GetMotionMaster()->empty() ||*/ + creature->GetMotionMaster()->GetCurrentMovementGeneratorType () != TARGETED_MOTION_TYPE) + { + PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU); + SetSentErrorMessage(true); + return false; + } + + TargetedMovementGenerator const* mgen + = static_cast const*>((creature->GetMotionMaster()->top())); + + if (mgen->GetTarget() != player) + { + PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU); + SetSentErrorMessage(true); + return false; + } + + // reset movement + creature->GetMotionMaster()->MovementExpired(true); + + PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU_NOW, creature->GetName()); + return true; +} +//npc tame handling +bool ChatHandler::HandleNpcTameCommand(const char* /*args*/) +{ + Creature *creatureTarget = getSelectedCreature (); + if (!creatureTarget || creatureTarget->isPet ()) + { + PSendSysMessage (LANG_SELECT_CREATURE); + SetSentErrorMessage (true); + return false; + } + + Player *player = m_session->GetPlayer (); + + if (player->GetPetGUID ()) + { + SendSysMessage (LANG_YOU_ALREADY_HAVE_PET); + SetSentErrorMessage (true); + return false; + } + + CreatureInfo const* cInfo = creatureTarget->GetCreatureInfo(); + + if (!cInfo->isTameable (player->CanTameExoticPets())) + { + PSendSysMessage (LANG_CREATURE_NON_TAMEABLE,cInfo->Entry); + SetSentErrorMessage (true); + return false; + } + + // Everything looks OK, create new pet + Pet* pet = player->CreateTamedPetFrom (creatureTarget); + if (!pet) + { + PSendSysMessage (LANG_CREATURE_NON_TAMEABLE,cInfo->Entry); + SetSentErrorMessage (true); + return false; + } + + // place pet before player + float x,y,z; + player->GetClosePoint (x,y,z,creatureTarget->GetObjectSize (),CONTACT_DISTANCE); + pet->Relocate (x,y,z,M_PI-player->GetOrientation ()); + + // set pet to defensive mode by default (some classes can't control controlled pets in fact). + pet->SetReactState(REACT_DEFENSIVE); + + // calculate proper level + uint8 level = (creatureTarget->getLevel() < (player->getLevel() - 5)) ? (player->getLevel() - 5) : creatureTarget->getLevel(); + + // prepare visual effect for levelup + pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1); + + // add to world + pet->GetMap()->Add(pet->ToCreature()); + + // visual effect for levelup + pet->SetUInt32Value(UNIT_FIELD_LEVEL, level); + + // caster have pet now + player->SetMinion(pet, true); + + pet->SavePetToDB(PET_SAVE_AS_CURRENT); + player->PetSpellInitialize(); + + return true; +} +//npc phasemask handling +//change phasemask of creature or pet +bool ChatHandler::HandleNpcSetPhaseCommand(const char* args) +{ + if (!*args) + return false; + + uint32 phasemask = (uint32) atoi((char*)args); + if (phasemask == 0) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Creature* pCreature = getSelectedCreature(); + if (!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->SetPhaseMask(phasemask,true); + + if (!pCreature->isPet()) + pCreature->SaveToDB(); + + return true; +} +//npc deathstate handling +bool ChatHandler::HandleNpcSetDeathStateCommand(const char* args) +{ + if (!*args) + return false; + + Creature* pCreature = getSelectedCreature(); + if (!pCreature || pCreature->isPet()) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if (strncmp(args, "on", 3) == 0) + pCreature->SetDeadByDefault(true); + else if (strncmp(args, "off", 4) == 0) + pCreature->SetDeadByDefault(false); + else + { + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; + } + + pCreature->SaveToDB(); + pCreature->Respawn(); + + return true; +} + +//TODO: NpcCommands that need to be fixed : + +bool ChatHandler::HandleNpcNameCommand(const char* /*args*/) +{ + /* Temp. disabled + if (!*args) + return false; + + if (strlen((char*)args)>75) + { + PSendSysMessage(LANG_TOO_LONG_NAME, strlen((char*)args)-75); + return true; + } + + for (uint8 i = 0; i < strlen(args); ++i) + { + if (!isalpha(args[i]) && args[i] != ' ') + { + SendSysMessage(LANG_CHARS_ONLY); + return false; + } + } + + uint64 guid; + guid = m_session->GetPlayer()->GetSelection(); + if (guid == 0) + { + SendSysMessage(LANG_NO_SELECTION); + return true; + } + + Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); + + if (!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + return true; + } + + pCreature->SetName(args); + uint32 idname = objmgr.AddCreatureTemplate(pCreature->GetName()); + pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname); + + pCreature->SaveToDB(); + */ + + return true; +} + +bool ChatHandler::HandleNpcSubNameCommand(const char* /*args*/) +{ + /* Temp. disabled + + if (!*args) + args = ""; + + if (strlen((char*)args)>75) + { + + PSendSysMessage(LANG_TOO_LONG_SUBNAME, strlen((char*)args)-75); + return true; + } + + for (uint8 i = 0; i < strlen(args); i++) + { + if (!isalpha(args[i]) && args[i] != ' ') + { + SendSysMessage(LANG_CHARS_ONLY); + return false; + } + } + uint64 guid; + guid = m_session->GetPlayer()->GetSelection(); + if (guid == 0) + { + SendSysMessage(LANG_NO_SELECTION); + return true; + } + + Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); + + if (!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + return true; + } + + uint32 idname = objmgr.AddCreatureSubName(pCreature->GetName(),args,pCreature->GetUInt32Value(UNIT_FIELD_DISPLAYID)); + pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname); + + pCreature->SaveToDB(); + */ + return true; +} + +//move item to other slot +bool ChatHandler::HandleItemMoveCommand(const char* args) +{ + if (!*args) + return false; + uint8 srcslot, dstslot; + + char* pParam1 = strtok((char*)args, " "); + if (!pParam1) + return false; + + char* pParam2 = strtok(NULL, " "); + if (!pParam2) + return false; + + srcslot = (uint8)atoi(pParam1); + dstslot = (uint8)atoi(pParam2); + + if (srcslot == dstslot) + return true; + + if (!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,srcslot)) + return false; + + if (!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,dstslot)) + return false; + + uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot); + uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot); + + m_session->GetPlayer()->SwapItem(src, dst); + + return true; +} + +//demorph player or unit +bool ChatHandler::HandleDeMorphCommand(const char* /*args*/) +{ + Unit *target = getSelectedUnit(); + if (!target) + target = m_session->GetPlayer(); + + // check online security + else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0)) + return false; + + target->DeMorph(); + + return true; +} + +//morph creature or player +bool ChatHandler::HandleModifyMorphCommand(const char* args) +{ + if (!*args) + return false; + + uint16 display_id = (uint16)atoi((char*)args); + + Unit *target = getSelectedUnit(); + if (!target) + target = m_session->GetPlayer(); + + // check online security + else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0)) + return false; + + target->SetDisplayId(display_id); + + return true; +} + +//kick player +bool ChatHandler::HandleKickPlayerCommand(const char *args) +{ +/* const char* kickName = strtok((char*)args, " "); + char* kickReason = strtok(NULL, "\n"); + std::string reason = "No Reason"; + std::string kicker = "Console"; + if (kickReason) + reason = kickReason; + if (m_session) + kicker = m_session->GetPlayer()->GetName(); + + if (!kickName) + { + Player* player = getSelectedPlayer(); + if (!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if (player == m_session->GetPlayer()) + { + SendSysMessage(LANG_COMMAND_KICKSELF); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(player, 0)) + return false; + + if (sWorld.getConfig(CONFIG_SHOW_KICK_IN_WORLD) == 1) + { + sWorld.SendWorldText(LANG_COMMAND_KICKMESSAGE, player->GetName(), kicker.c_str(), reason.c_str()); + } + else + { + PSendSysMessage(LANG_COMMAND_KICKMESSAGE, player->GetName(), kicker.c_str(), reason.c_str()); + } + + player->GetSession()->KickPlayer(); + } + else + { + std::string name = extractPlayerNameFromLink((char*)kickName); + if (name.empty()) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + if (m_session && name == m_session->GetPlayer()->GetName()) + { + SendSysMessage(LANG_COMMAND_KICKSELF); + SetSentErrorMessage(true); + return false; + } + + Player* player = objmgr.GetPlayer(kickName); + if (!player) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + if (HasLowerSecurity(player, 0)) + { + SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); //maybe replacement string for this later on + SetSentErrorMessage(true); + return false; + } + + std::string nameLink = playerLink(name); + + if (sWorld.KickPlayer(name)) + { + if (sWorld.getConfig(CONFIG_SHOW_KICK_IN_WORLD) == 1) + { + sWorld.SendWorldText(LANG_COMMAND_KICKMESSAGE, nameLink.c_str(), kicker.c_str(), reason.c_str()); + } + else + { + PSendSysMessage(LANG_COMMAND_KICKMESSAGE,nameLink.c_str()); + } + } + else + { + PSendSysMessage(LANG_COMMAND_KICKNOTFOUNDPLAYER,nameLink.c_str()); + return false; + } + }*/ + Player* target; + if (!extractPlayerTarget((char*)args,&target)) + return false; + + if (m_session && target == m_session->GetPlayer()) + { + SendSysMessage(LANG_COMMAND_KICKSELF); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + // send before target pointer invalidate + PSendSysMessage(LANG_COMMAND_KICKMESSAGE,GetNameLink(target).c_str()); + target->GetSession()->KickPlayer(); + return true; +} + +//set temporary phase mask for player +bool ChatHandler::HandleModifyPhaseCommand(const char* args) +{ + if (!*args) + return false; + + uint32 phasemask = (uint32)atoi((char*)args); + + Unit *target = getSelectedUnit(); + if (!target) + target = m_session->GetPlayer(); + + // check online security + else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0)) + return false; + + target->SetPhaseMask(phasemask,true); + + return true; +} +//show info of gameobject +bool ChatHandler::HandleGOInfoCommand(const char* args) +{ + uint32 entry = 0; + uint32 type = 0; + uint32 displayid = 0; + std::string name; + + if (!*args) + { + if (WorldObject * obj = getSelectedObject()) + entry = obj->GetEntry(); + } + else + entry = atoi((char*)args); + + GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(entry); + + if (!goinfo) + return false; + + type = goinfo->type; + displayid = goinfo->displayId; + name = goinfo->name; + + PSendSysMessage(LANG_GOINFO_ENTRY, entry); + PSendSysMessage(LANG_GOINFO_TYPE, type); + PSendSysMessage(LANG_GOINFO_DISPLAYID, displayid); + PSendSysMessage(LANG_GOINFO_NAME, name.c_str()); + + return true; +} + +//show info of player +bool ChatHandler::HandlePInfoCommand(const char* args) +{ + Player* target; + uint64 target_guid; + std::string target_name; + if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) + return false; + + uint32 accId = 0; + uint32 money = 0; + uint32 total_player_time = 0; + uint8 level = 0; + uint32 latency = 0; + uint8 race; + uint8 Class; + + // get additional information from Player object + if (target) + { + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + accId = target->GetSession()->GetAccountId(); + money = target->GetMoney(); + total_player_time = target->GetTotalPlayedTime(); + level = target->getLevel(); + latency = target->GetSession()->GetLatency(); + race = target->getRace(); + Class = target->getClass(); + } + // get additional information from DB + else + { + // check offline security + if (HasLowerSecurity(NULL, target_guid)) + return false; + + // 0 1 2 3 4 5 + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT totaltime, level, money, account, race, class FROM characters WHERE guid = '%u'", GUID_LOPART(target_guid)); + if (!result) + return false; + + Field *fields = result->Fetch(); + total_player_time = fields[0].GetUInt32(); + level = fields[1].GetUInt32(); + money = fields[2].GetUInt32(); + accId = fields[3].GetUInt32(); + race = fields[4].GetUInt8(); + Class = fields[5].GetUInt8(); + } + + std::string username = GetTrinityString(LANG_ERROR); + std::string email = GetTrinityString(LANG_ERROR); + std::string last_ip = GetTrinityString(LANG_ERROR); + uint32 security = 0; + std::string last_login = GetTrinityString(LANG_ERROR); + + QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT a.username,aa.gmlevel,a.email,a.last_ip,a.last_login " + "FROM account a " + "LEFT JOIN account_access aa " + "ON (a.id = aa.id) " + "WHERE a.id = '%u'",accId); + if (result) + { + Field* fields = result->Fetch(); + username = fields[0].GetCppString(); + security = fields[1].GetUInt32(); + email = fields[2].GetCppString(); + + if (email.empty()) + email = "-"; + + if (!m_session || m_session->GetSecurity() >= security) + { + last_ip = fields[3].GetCppString(); + last_login = fields[4].GetCppString(); + } + else + { + last_ip = "-"; + last_login = "-"; + } + } + + std::string nameLink = playerLink(target_name); + + PSendSysMessage(LANG_PINFO_ACCOUNT, (target?"":GetTrinityString(LANG_OFFLINE)), nameLink.c_str(), GUID_LOPART(target_guid), username.c_str(), accId, email.c_str(), security, last_ip.c_str(), last_login.c_str(), latency); + + std::string race_s, Class_s; + switch(race) + { + case RACE_HUMAN: race_s = "Human"; break; + case RACE_ORC: race_s = "Orc"; break; + case RACE_DWARF: race_s = "Dwarf"; break; + case RACE_NIGHTELF: race_s = "Night Elf"; break; + case RACE_UNDEAD_PLAYER: race_s = "Undead"; break; + case RACE_TAUREN: race_s = "Tauren"; break; + case RACE_GNOME: race_s = "Gnome"; break; + case RACE_TROLL: race_s = "Troll"; break; + case RACE_BLOODELF: race_s = "Blood Elf"; break; + case RACE_DRAENEI: race_s = "Draenei"; break; + } + switch(Class) + { + case CLASS_WARRIOR: Class_s = "Warrior"; break; + case CLASS_PALADIN: Class_s = "Paladin"; break; + case CLASS_HUNTER: Class_s = "Hunter"; break; + case CLASS_ROGUE: Class_s = "Rogue"; break; + case CLASS_PRIEST: Class_s = "Priest"; break; + case CLASS_DEATH_KNIGHT: Class_s = "Death Knight"; break; + case CLASS_SHAMAN: Class_s = "Shaman"; break; + case CLASS_MAGE: Class_s = "Mage"; break; + case CLASS_WARLOCK: Class_s = "Warlock"; break; + case CLASS_DRUID: Class_s = "Druid"; break; + } + + std::string timeStr = secsToTimeString(total_player_time,true,true); + uint32 gold = money /GOLD; + uint32 silv = (money % GOLD) / SILVER; + uint32 copp = (money % GOLD) % SILVER; + PSendSysMessage(LANG_PINFO_LEVEL, race_s.c_str(), Class_s.c_str(), timeStr.c_str(), level, gold, silv, copp); + + return true; +} + +/////WAYPOINT COMMANDS + +/** + * Add a waypoint to a creature. + * + * The user can either select an npc or provide its GUID. + * + * The user can even select a visual waypoint - then the new waypoint + * is placed *after* the selected one - this makes insertion of new + * waypoints possible. + * + * eg: + * .wp add 12345 + * -> adds a waypoint to the npc with the GUID 12345 + * + * .wp add + * -> adds a waypoint to the currently selected creature + * + * + * @param args if the user did not provide a GUID, it is NULL + * + * @return true - command did succeed, false - something went wrong + */ +bool ChatHandler::HandleWpAddCommand(const char* args) +{ + sLog.outDebug("DEBUG: HandleWpAddCommand"); + + // optional + char* path_number = NULL; + uint32 pathid = 0; + + if (*args) + path_number = strtok((char*)args, " "); + + uint32 point = 0; + Creature* target = getSelectedCreature(); + + if (!path_number) + { + if (target) + pathid = target->GetWaypointPath(); + else + { + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT MAX(id) FROM waypoint_data"); + uint32 maxpathid = result->Fetch()->GetInt32(); + pathid = maxpathid+1; + sLog.outDebug("DEBUG: HandleWpAddCommand - New path started."); + PSendSysMessage("%s%s|r", "|cff00ff00", "New path started."); + } + } + else + pathid = atoi(path_number); + + // path_id -> ID of the Path + // point -> number of the waypoint (if not 0) + + if (!pathid) + { + sLog.outDebug("DEBUG: HandleWpAddCommand - Current creature haven't loaded path."); + PSendSysMessage("%s%s|r", "|cffff33ff", "Current creature haven't loaded path."); + return true; + } + + sLog.outDebug("DEBUG: HandleWpAddCommand - point == 0"); + + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT MAX(point) FROM waypoint_data WHERE id = '%u'",pathid); + + if (result) + point = (*result)[0].GetUInt32(); + + Player* player = m_session->GetPlayer(); + //Map *map = player->GetMap(); + + WorldDatabase.PExecuteLog("INSERT INTO waypoint_data (id, point, position_x, position_y, position_z) VALUES ('%u','%u','%f', '%f', '%f')", + pathid, point+1, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); + + PSendSysMessage("%s%s%u%s%u%s|r", "|cff00ff00", "PathID: |r|cff00ffff", pathid, "|r|cff00ff00: Waypoint |r|cff00ffff", point+1,"|r|cff00ff00 created. "); + return true; +} // HandleWpAddCommand + +bool ChatHandler::HandleWpLoadPathCommand(const char *args) +{ + if (!*args) + return false; + + // optional + char* path_number = NULL; + + if (*args) + path_number = strtok((char*)args, " "); + + uint32 pathid = 0; + uint32 guidlow = 0; + Creature* target = getSelectedCreature(); + + // Did player provide a path_id? + if (!path_number) + sLog.outDebug("DEBUG: HandleWpLoadPathCommand - No path number provided"); + + if (!target) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if (target->GetEntry() == 1) + { + PSendSysMessage("%s%s|r", "|cffff33ff", "You want to load path to a waypoint? Aren't you?"); + SetSentErrorMessage(true); + return false; + } + + pathid = atoi(path_number); + + if (!pathid) + { + PSendSysMessage("%s%s|r", "|cffff33ff", "No vallid path number provided."); + return true; + } + + guidlow = target->GetDBTableGUIDLow(); + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT guid FROM creature_addon WHERE guid = '%u'",guidlow); + + if (result) + WorldDatabase.PExecute("UPDATE creature_addon SET path_id = '%u' WHERE guid = '%u'", pathid, guidlow); + else + WorldDatabase.PExecute("INSERT INTO creature_addon(guid,path_id) VALUES ('%u','%u')", guidlow, pathid); + + WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE, guidlow); + + target->LoadPath(pathid); + target->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); + target->GetMotionMaster()->Initialize(); + target->MonsterSay("Path loaded.",0,0); + + return true; +} + +bool ChatHandler::HandleReloadAllPaths(const char* args) +{ + if (!*args) + return false; + + uint32 id = atoi(args); + + if (!id) + return false; + + PSendSysMessage("%s%s|r|cff00ffff%u|r", "|cff00ff00", "Loading Path: ", id); + sWaypointMgr->UpdatePath(id); + return true; +} + +bool ChatHandler::HandleWpUnLoadPathCommand(const char * /*args*/) +{ + uint32 guidlow = 0; + Creature* target = getSelectedCreature(); + + if (!target) + { + PSendSysMessage("%s%s|r", "|cff33ffff", "You must select target."); + return true; + } + + if (target->GetCreatureAddon()) + { + if (target->GetCreatureAddon()->path_id != 0) + { + WorldDatabase.PExecute("DELETE FROM creature_addon WHERE guid = %u", target->GetGUIDLow()); + target->UpdateWaypointID(0); + WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", IDLE_MOTION_TYPE, guidlow); + target->LoadPath(0); + target->SetDefaultMovementType(IDLE_MOTION_TYPE); + target->GetMotionMaster()->MoveTargetedHome(); + target->GetMotionMaster()->Initialize(); + target->MonsterSay("Path unloaded.",0,0); + return true; + } + PSendSysMessage("%s%s|r", "|cffff33ff", "Target have no loaded path."); + } + return true; +} + +bool ChatHandler::HandleWpEventCommand(const char* args) +{ + if (!*args) + return false; + + char* show_str = strtok((char*)args, " "); + std::string show = show_str; + + // Check + if ((show != "add") && (show != "mod") && (show != "del") && (show != "listid")) return false; + + char* arg_id = strtok(NULL, " "); + uint32 id = 0; + + if (show == "add") + { + if (arg_id) + id = atoi(arg_id); + + if (id) + { + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT id FROM waypoint_scripts WHERE guid = %u", id); + + if (!result) + { + WorldDatabase.PExecute("INSERT INTO waypoint_scripts(guid)VALUES(%u)", id); + PSendSysMessage("%s%s%u|r", "|cff00ff00", "Wp Event: New waypoint event added: ", id); + } + else + PSendSysMessage("|cff00ff00Wp Event: You have choosed an existing waypoint script guid: %u|r", id); + } + else + { + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT MAX(guid) FROM waypoint_scripts"); + id = result->Fetch()->GetUInt32(); + WorldDatabase.PExecute("INSERT INTO waypoint_scripts(guid)VALUES(%u)", id+1); + PSendSysMessage("%s%s%u|r", "|cff00ff00","Wp Event: New waypoint event added: |r|cff00ffff", id+1); + } + + return true; + } + + if (show == "listid") + { + if (!arg_id) + { + PSendSysMessage("%s%s|r", "|cff33ffff","Wp Event: You must provide waypoint script id."); + return true; + } + + id = atoi(arg_id); + + uint32 a2, a3, a4, a5, a6; + float a8, a9, a10, a11; + char const* a7; + + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = %u", id); + + if (!result) + { + PSendSysMessage("%s%s%u|r", "|cff33ffff", "Wp Event: No waypoint scripts found on id: ", id); + return true; + } + + Field *fields; + + do + { + fields = result->Fetch(); + a2 = fields[0].GetUInt32(); + a3 = fields[1].GetUInt32(); + a4 = fields[2].GetUInt32(); + a5 = fields[3].GetUInt32(); + a6 = fields[4].GetUInt32(); + a7 = fields[5].GetString(); + a8 = fields[6].GetFloat(); + a9 = fields[7].GetFloat(); + a10 = fields[8].GetFloat(); + a11 = fields[9].GetFloat(); + + PSendSysMessage("|cffff33ffid:|r|cff00ffff %u|r|cff00ff00, guid: |r|cff00ffff%u|r|cff00ff00, delay: |r|cff00ffff%u|r|cff00ff00, command: |r|cff00ffff%u|r|cff00ff00, datalong: |r|cff00ffff%u|r|cff00ff00, datalong2: |r|cff00ffff%u|r|cff00ff00, datatext: |r|cff00ffff%s|r|cff00ff00, posx: |r|cff00ffff%f|r|cff00ff00, posy: |r|cff00ffff%f|r|cff00ff00, posz: |r|cff00ffff%f|r|cff00ff00, orientation: |r|cff00ffff%f|r", id, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); + } + while (result->NextRow()); + } + + if (show == "del") + { + id = atoi(arg_id); + + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT guid FROM waypoint_scripts WHERE guid = %u", id); + + if (result) + { + WorldDatabase.PExecuteLog("DELETE FROM waypoint_scripts WHERE guid = %u", id); + PSendSysMessage("%s%s%u|r","|cff00ff00","Wp Event: Waypoint script removed: ", id); + } + else + PSendSysMessage("|cffff33ffWp Event: ERROR: you have selected a non existing script: %u|r", id); + + return true; + } + + if (show == "mod") + { + if (!arg_id) + { + SendSysMessage("|cffff33ffERROR: Waypoint script guid not present.|r"); + return true; + } + + id = atoi(arg_id); + + if (!id) + { + SendSysMessage("|cffff33ffERROR: No vallid waypoint script id not present.|r"); + return true; + } + + char* arg_2 = strtok(NULL," "); + + if (!arg_2) + { + SendSysMessage("|cffff33ffERROR: No argument present.|r"); + return true; + } + + std::string arg_string = arg_2; + + if ((arg_string != "setid") && (arg_string != "delay") && (arg_string != "command") + && (arg_string != "datalong") && (arg_string != "datalong2") && (arg_string != "dataint") && (arg_string != "posx") + && (arg_string != "posy") && (arg_string != "posz") && (arg_string != "orientation")) + { + SendSysMessage("|cffff33ffERROR: No valid argument present.|r"); + return true; + } + + char* arg_3; + std::string arg_str_2 = arg_2; + arg_3 = strtok(NULL," "); + + if (!arg_3) + { + SendSysMessage("|cffff33ffERROR: No additional argument present.|r"); + return true; + } + + float coord; + + if (arg_str_2 == "setid") + { + uint32 newid = atoi(arg_3); + PSendSysMessage("%s%s|r|cff00ffff%u|r|cff00ff00%s|r|cff00ffff%u|r","|cff00ff00","Wp Event: Wypoint scipt guid: ", newid," id changed: ", id); + WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET id='%u' WHERE guid='%u'", + newid, id); return true; + } + else + { + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT id FROM waypoint_scripts WHERE guid='%u'",id); + + if (!result) + { + SendSysMessage("|cffff33ffERROR: You have selected an non existing waypoint script guid.|r"); + return true; + } + + if (arg_str_2 == "posx") + { + coord = atof(arg_3); + WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET x='%f' WHERE guid='%u'", + coord, id); + PSendSysMessage("|cff00ff00Waypoint script:|r|cff00ffff %u|r|cff00ff00 position_x updated.|r", id); + return true; + } + else if (arg_str_2 == "posy") + { + coord = atof(arg_3); + WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET y='%f' WHERE guid='%u'", + coord, id); + PSendSysMessage("|cff00ff00Waypoint script: %u position_y updated.|r", id); + return true; + } + else if (arg_str_2 == "posz") + { + coord = atof(arg_3); + WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET z='%f' WHERE guid='%u'", + coord, id); + PSendSysMessage("|cff00ff00Waypoint script: |r|cff00ffff%u|r|cff00ff00 position_z updated.|r", id); + return true; + } + else if (arg_str_2 == "orientation") + { + coord = atof(arg_3); + WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET o='%f' WHERE guid='%u'", + coord, id); + PSendSysMessage("|cff00ff00Waypoint script: |r|cff00ffff%u|r|cff00ff00 orientation updated.|r", id); + return true; + } + else if (arg_str_2 == "dataint") + { + WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET %s='%u' WHERE guid='%u'", + arg_2, atoi(arg_3), id); + PSendSysMessage("|cff00ff00Waypoint script: |r|cff00ffff%u|r|cff00ff00 dataint updated.|r", id); + return true; + } + else + { + std::string arg_str_3 = arg_3; + WorldDatabase.escape_string(arg_str_3); + WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET %s='%s' WHERE guid='%u'", + arg_2, arg_str_3.c_str(), id); + } + } + PSendSysMessage("%s%s|r|cff00ffff%u:|r|cff00ff00 %s %s|r","|cff00ff00","Waypoint script:", id, arg_2,"updated."); + } + return true; +} + +bool ChatHandler::HandleWpModifyCommand(const char* args) +{ + sLog.outDebug("DEBUG: HandleWpModifyCommand"); + + if (!*args) + return false; + + // first arg: add del text emote spell waittime move + char* show_str = strtok((char*)args, " "); + if (!show_str) + { + return false; + } + + std::string show = show_str; + // Check + // Remember: "show" must also be the name of a column! + if ((show != "delay") && (show != "action") && (show != "action_chance") + && (show != "move_flag") && (show != "del") && (show != "move") && (show != "wpadd") +) + { + return false; + } + + // Next arg is: + char* arg_str = NULL; + + // Did user provide a GUID + // or did the user select a creature? + // -> variable lowguid is filled with the GUID of the NPC + uint32 pathid = 0; + uint32 point = 0; + uint32 wpGuid = 0; + Creature* target = getSelectedCreature(); + + if (!target || target->GetEntry() != VISUAL_WAYPOINT) + { + SendSysMessage("|cffff33ffERROR: You must select a waypoint.|r"); + return false; + } + + sLog.outDebug("DEBUG: HandleWpModifyCommand - User did select an NPC"); + // The visual waypoint + Creature* wpCreature = NULL; + wpGuid = target->GetGUIDLow(); + + // Did the user select a visual spawnpoint? + if (wpGuid) + wpCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT)); + // attempt check creature existence by DB data + else + { + PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, wpGuid); + return false; + } + // User did select a visual waypoint? + // Check the creature + if (wpCreature->GetEntry() == VISUAL_WAYPOINT) + { + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT id, point FROM waypoint_data WHERE wpguid = %u", wpGuid); + + if (!result) + { + sLog.outDebug("DEBUG: HandleWpModifyCommand - No waypoint found - used 'wpguid'"); + + PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUIDLow()); + // Select waypoint number from database + // Since we compare float values, we have to deal with + // some difficulties. + // Here we search for all waypoints that only differ in one from 1 thousand + // (0.001) - There is no other way to compare C++ floats with mySQL floats + // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html + const char* maxDIFF = "0.01"; + result = WorldDatabase.PQuery("SELECT id, point FROM waypoint_data WHERE (abs(position_x - %f) <= %s) and (abs(position_y - %f) <= %s) and (abs(position_z - %f) <= %s)", + wpCreature->GetPositionX(), maxDIFF, wpCreature->GetPositionY(), maxDIFF, wpCreature->GetPositionZ(), maxDIFF); + if (!result) + { + PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, wpGuid); + return true; + } + } + sLog.outDebug("DEBUG: HandleWpModifyCommand - After getting wpGuid"); + + do + { + Field *fields = result->Fetch(); + pathid = fields[0].GetUInt32(); + point = fields[1].GetUInt32(); + } + while (result->NextRow()); + + // We have the waypoint number and the GUID of the "master npc" + // Text is enclosed in "<>", all other arguments not + arg_str = strtok((char*)NULL, " "); + } + + sLog.outDebug("DEBUG: HandleWpModifyCommand - Parameters parsed - now execute the command"); + + // Check for argument + if (show != "del" && show != "move" && arg_str == NULL) + { + PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, show_str); + return false; + } + + if (show == "del" && target) + { + PSendSysMessage("|cff00ff00DEBUG: wp modify del, PathID: |r|cff00ffff%u|r", pathid); + + // wpCreature + Creature* wpCreature = NULL; + + if (wpGuid != 0) + { + wpCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT)); + wpCreature->CombatStop(); + wpCreature->DeleteFromDB(); + wpCreature->AddObjectToRemoveList(); + } + + WorldDatabase.PExecuteLog("DELETE FROM waypoint_data WHERE id='%u' AND point='%u'", + pathid, point); + WorldDatabase.PExecuteLog("UPDATE waypoint_data SET point=point-1 WHERE id='%u' AND point>'%u'", + pathid, point); + + PSendSysMessage(LANG_WAYPOINT_REMOVED); + return true; + } // del + + if (show == "move" && target) + { + PSendSysMessage("|cff00ff00DEBUG: wp move, PathID: |r|cff00ffff%u|r", pathid); + + Player *chr = m_session->GetPlayer(); + Map *map = chr->GetMap(); + { + // wpCreature + Creature* wpCreature = NULL; + // What to do: + // Move the visual spawnpoint + // Respawn the owner of the waypoints + if (wpGuid != 0) + { + wpCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT)); + wpCreature->CombatStop(); + wpCreature->DeleteFromDB(); + wpCreature->AddObjectToRemoveList(); + // re-create + Creature* wpCreature2 = new Creature; + if (!wpCreature2->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), VISUAL_WAYPOINT, 0, 0, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation())) + { + PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); + delete wpCreature2; + return false; + } + + wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); + wpCreature2->LoadFromDB(wpCreature2->GetDBTableGUIDLow(), map); + map->Add(wpCreature2); + //MapManager::Instance().GetMap(npcCreature->GetMapId())->Add(wpCreature2); + } + + WorldDatabase.PExecuteLog("UPDATE waypoint_data SET position_x = '%f',position_y = '%f',position_z = '%f' where id = '%u' AND point='%u'", + chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), pathid, point); + + PSendSysMessage(LANG_WAYPOINT_CHANGED); + } + return true; + } // move + + const char *text = arg_str; + + if (text == 0) + { + // show_str check for present in list of correct values, no sql injection possible + WorldDatabase.PExecuteLog("UPDATE waypoint_data SET %s=NULL WHERE id='%u' AND point='%u'", + show_str, pathid, point); + } + else + { + // show_str check for present in list of correct values, no sql injection possible + std::string text2 = text; + WorldDatabase.escape_string(text2); + WorldDatabase.PExecuteLog("UPDATE waypoint_data SET %s='%s' WHERE id='%u' AND point='%u'", + show_str, text2.c_str(), pathid, point); + } + + PSendSysMessage(LANG_WAYPOINT_CHANGED_NO, show_str); + return true; +} + +bool ChatHandler::HandleWpShowCommand(const char* args) +{ + sLog.outDebug("DEBUG: HandleWpShowCommand"); + + if (!*args) + return false; + + // first arg: on, off, first, last + char* show_str = strtok((char*)args, " "); + if (!show_str) + return false; + + // second arg: GUID (optional, if a creature is selected) + char* guid_str = strtok((char*)NULL, " "); + sLog.outDebug("DEBUG: HandleWpShowCommand: show_str: %s guid_str: %s", show_str, guid_str); + + uint32 pathid = 0; + Creature* target = getSelectedCreature(); + + // Did player provide a PathID? + + if (!guid_str) + { + sLog.outDebug("DEBUG: HandleWpShowCommand: !guid_str"); + // No PathID provided + // -> Player must have selected a creature + + if (!target) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pathid = target->GetWaypointPath(); + } + else + { + sLog.outDebug("|cff00ff00DEBUG: HandleWpShowCommand: PathID provided|r"); + // PathID provided + // Warn if player also selected a creature + // -> Creature selection is ignored <- + if (target) + SendSysMessage(LANG_WAYPOINT_CREATSELECTED); + + pathid = atoi((char*)guid_str); + } + + sLog.outDebug("DEBUG: HandleWpShowCommand: danach"); + + std::string show = show_str; + uint32 Maxpoint; + + sLog.outDebug("DEBUG: HandleWpShowCommand: PathID: %u", pathid); + + //PSendSysMessage("wpshow - show: %s", show); + + // Show info for the selected waypoint + if (show == "info") + { + // Check if the user did specify a visual waypoint + if (target->GetEntry() != VISUAL_WAYPOINT) + { + PSendSysMessage(LANG_WAYPOINT_VP_SELECT); + SetSentErrorMessage(true); + return false; + } + + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT id, point, delay, move_flag, action, action_chance FROM waypoint_data WHERE wpguid = %u", target->GetGUIDLow()); + + if (!result) + { + SendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM); + return true; + } + + SendSysMessage("|cff00ffffDEBUG: wp show info:|r"); + do + { + Field *fields = result->Fetch(); + pathid = fields[0].GetUInt32(); + uint32 point = fields[1].GetUInt32(); + uint32 delay = fields[2].GetUInt32(); + uint32 flag = fields[3].GetUInt32(); + uint32 ev_id = fields[4].GetUInt32(); + uint32 ev_chance = fields[5].GetUInt32(); + + PSendSysMessage("|cff00ff00Show info: for current point: |r|cff00ffff%u|r|cff00ff00, Path ID: |r|cff00ffff%u|r", point, pathid); + PSendSysMessage("|cff00ff00Show info: delay: |r|cff00ffff%u|r", delay); + PSendSysMessage("|cff00ff00Show info: Move flag: |r|cff00ffff%u|r", flag); + PSendSysMessage("|cff00ff00Show info: Waypoint event: |r|cff00ffff%u|r", ev_id); + PSendSysMessage("|cff00ff00Show info: Event chance: |r|cff00ffff%u|r", ev_chance); + } + while (result->NextRow()); + + return true; + } + + if (show == "on") + { + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT point, position_x,position_y,position_z FROM waypoint_data WHERE id = '%u'", pathid); + + if (!result) + { + SendSysMessage("|cffff33ffPath no found.|r"); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage("|cff00ff00DEBUG: wp on, PathID: |cff00ffff%u|r", pathid); + + // Delete all visuals for this NPC + QueryResult_AutoPtr result2 = WorldDatabase.PQuery("SELECT wpguid FROM waypoint_data WHERE id = '%u' and wpguid <> 0", pathid); + + if (result2) + { + bool hasError = false; + do + { + Field *fields = result2->Fetch(); + uint32 wpguid = fields[0].GetUInt32(); + Creature* pCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(wpguid,VISUAL_WAYPOINT,HIGHGUID_UNIT)); + + if (!pCreature) + { + PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, wpguid); + hasError = true; + WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", wpguid); + } + else + { + pCreature->CombatStop(); + pCreature->DeleteFromDB(); + pCreature->AddObjectToRemoveList(); + } + + } + while (result2->NextRow()); + + if (hasError) + { + PSendSysMessage(LANG_WAYPOINT_TOOFAR1); + PSendSysMessage(LANG_WAYPOINT_TOOFAR2); + PSendSysMessage(LANG_WAYPOINT_TOOFAR3); + } + } + + do + { + Field *fields = result->Fetch(); + uint32 point = fields[0].GetUInt32(); + float x = fields[1].GetFloat(); + float y = fields[2].GetFloat(); + float z = fields[3].GetFloat(); + + uint32 id = VISUAL_WAYPOINT; + + Player *chr = m_session->GetPlayer(); + Map *map = chr->GetMap(); + float o = chr->GetOrientation(); + + Creature* wpCreature = new Creature; + if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o)) + { + PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); + delete wpCreature; + return false; + } + + sLog.outDebug("DEBUG: UPDATE waypoint_data SET wpguid = '%u"); + // set "wpguid" column to the visual waypoint + WorldDatabase.PExecuteLog("UPDATE waypoint_data SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), pathid, point); + + wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); + wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(),map); + map->Add(wpCreature); + + if (target) + { + wpCreature->SetDisplayId(target->GetDisplayId()); + wpCreature->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.5); + wpCreature->SetLevel(point > MAX_LEVEL ? MAX_LEVEL : point); + } + } + while (result->NextRow()); + + SendSysMessage("|cff00ff00Showing the current creature's path.|r"); + return true; + } + + if (show == "first") + { + PSendSysMessage("|cff00ff00DEBUG: wp first, GUID: %u|r", pathid); + + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z FROM waypoint_data WHERE point='1' AND id = '%u'",pathid); + if (!result) + { + PSendSysMessage(LANG_WAYPOINT_NOTFOUND, pathid); + SetSentErrorMessage(true); + return false; + } + + Field *fields = result->Fetch(); + float x = fields[0].GetFloat(); + float y = fields[1].GetFloat(); + float z = fields[2].GetFloat(); + uint32 id = VISUAL_WAYPOINT; + + Player *chr = m_session->GetPlayer(); + float o = chr->GetOrientation(); + Map *map = chr->GetMap(); + + Creature* pCreature = new Creature; + if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT),map, chr->GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o)) + { + PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); + delete pCreature; + return false; + } + + pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map); + map->Add(pCreature); + + if (target) + { + pCreature->SetDisplayId(target->GetDisplayId()); + pCreature->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.5); + } + + return true; + } + + if (show == "last") + { + PSendSysMessage("|cff00ff00DEBUG: wp last, PathID: |r|cff00ffff%u|r", pathid); + + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT MAX(point) FROM waypoint_data WHERE id = '%u'",pathid); + if (result) + Maxpoint = (*result)[0].GetUInt32(); + else + Maxpoint = 0; + + result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z FROM waypoint_data WHERE point ='%u' AND id = '%u'",Maxpoint, pathid); + if (!result) + { + PSendSysMessage(LANG_WAYPOINT_NOTFOUNDLAST, pathid); + SetSentErrorMessage(true); + return false; + } + Field *fields = result->Fetch(); + float x = fields[0].GetFloat(); + float y = fields[1].GetFloat(); + float z = fields[2].GetFloat(); + uint32 id = VISUAL_WAYPOINT; + + Player *chr = m_session->GetPlayer(); + float o = chr->GetOrientation(); + Map *map = chr->GetMap(); + + Creature* pCreature = new Creature; + if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o)) + { + PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id); + delete pCreature; + return false; + } + + pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map); + map->Add(pCreature); + + if (target) + { + pCreature->SetDisplayId(target->GetDisplayId()); + pCreature->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.5); + } + + return true; + } + + if (show == "off") + { + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE id = '%u'", 1); + if (!result) + { + SendSysMessage(LANG_WAYPOINT_VP_NOTFOUND); + SetSentErrorMessage(true); + return false; + } + bool hasError = false; + do + { + Field *fields = result->Fetch(); + uint32 guid = fields[0].GetUInt32(); + Creature* pCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(guid,VISUAL_WAYPOINT,HIGHGUID_UNIT)); + if (!pCreature) + { + PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, guid); + hasError = true; + WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", guid); + } + else + { + pCreature->CombatStop(); + pCreature->DeleteFromDB(); + pCreature->AddObjectToRemoveList(); + } + } + while (result->NextRow()); + // set "wpguid" column to "empty" - no visual waypoint spawned + WorldDatabase.PExecuteLog("UPDATE waypoint_data SET wpguid = '0'"); + //WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '0' WHERE wpguid <> '0'"); + + if (hasError) + { + PSendSysMessage(LANG_WAYPOINT_TOOFAR1); + PSendSysMessage(LANG_WAYPOINT_TOOFAR2); + PSendSysMessage(LANG_WAYPOINT_TOOFAR3); + } + + SendSysMessage(LANG_WAYPOINT_VP_ALLREMOVED); + return true; + } + + PSendSysMessage("|cffff33ffDEBUG: wpshow - no valid command found|r"); + return true; +} + +//////////// WAYPOINT COMMANDS // + +//rename characters +bool ChatHandler::HandleCharacterRenameCommand(const char* args) +{ + Player* target; + uint64 target_guid; + std::string target_name; + if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) + return false; + + if (target) + { + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + PSendSysMessage(LANG_RENAME_PLAYER, GetNameLink(target).c_str()); + target->SetAtLoginFlag(AT_LOGIN_RENAME); + } + else + { + // check offline security + if (HasLowerSecurity(NULL, target_guid)) + return false; + + std::string oldNameLink = playerLink(target_name); + + PSendSysMessage(LANG_RENAME_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(target_guid)); + CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '1' WHERE guid = '%u'", GUID_LOPART(target_guid)); + } + + return true; +} + +// customize characters +bool ChatHandler::HandleCharacterCustomizeCommand(const char* args) +{ + Player* target; + uint64 target_guid; + std::string target_name; + if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) + return false; + + if (target) + { + PSendSysMessage(LANG_CUSTOMIZE_PLAYER, GetNameLink(target).c_str()); + target->SetAtLoginFlag(AT_LOGIN_CUSTOMIZE); + CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '8' WHERE guid = '%u'", target->GetGUIDLow()); + } + else + { + std::string oldNameLink = playerLink(target_name); + + PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(target_guid)); + CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '8' WHERE guid = '%u'", GUID_LOPART(target_guid)); + } + + return true; +} + +bool ChatHandler::HandleCharacterReputationCommand(const char* args) +{ + Player* target; + if (!extractPlayerTarget((char*)args,&target)) + return false; + + LocaleConstant loc = GetSessionDbcLocale(); + + FactionStateList const& targetFSL = target->GetReputationMgr().GetStateList(); + for (FactionStateList::const_iterator itr = targetFSL.begin(); itr != targetFSL.end(); ++itr) + { + FactionEntry const *factionEntry = sFactionStore.LookupEntry(itr->second.ID); + char const* factionName = factionEntry ? factionEntry->name[loc] : "#Not found#"; + ReputationRank rank = target->GetReputationMgr().GetRank(factionEntry); + std::string rankName = GetTrinityString(ReputationRankStrIndex[rank]); + std::ostringstream ss; + if (m_session) + ss << itr->second.ID << " - |cffffffff|Hfaction:" << itr->second.ID << "|h[" << factionName << " " << localeNames[loc] << "]|h|r"; + else + ss << itr->second.ID << " - " << factionName << " " << localeNames[loc]; + + ss << " " << rankName << " (" << target->GetReputationMgr().GetReputation(factionEntry) << ")"; + + if (itr->second.Flags & FACTION_FLAG_VISIBLE) + ss << GetTrinityString(LANG_FACTION_VISIBLE); + if (itr->second.Flags & FACTION_FLAG_AT_WAR) + ss << GetTrinityString(LANG_FACTION_ATWAR); + if (itr->second.Flags & FACTION_FLAG_PEACE_FORCED) + ss << GetTrinityString(LANG_FACTION_PEACE_FORCED); + if (itr->second.Flags & FACTION_FLAG_HIDDEN) + ss << GetTrinityString(LANG_FACTION_HIDDEN); + if (itr->second.Flags & FACTION_FLAG_INVISIBLE_FORCED) + ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED); + if (itr->second.Flags & FACTION_FLAG_INACTIVE) + ss << GetTrinityString(LANG_FACTION_INACTIVE); + + SendSysMessage(ss.str().c_str()); + } + return true; +} + +//change standstate +bool ChatHandler::HandleModifyStandStateCommand(const char* args) +{ + if (!*args) + return false; + + uint32 anim_id = atoi((char*)args); + m_session->GetPlayer()->SetUInt32Value(UNIT_NPC_EMOTESTATE , anim_id); + + return true; +} + +bool ChatHandler::HandleHonorAddCommand(const char* args) +{ + if (!*args) + return false; + + Player *target = getSelectedPlayer(); + if (!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + uint32 amount = (uint32)atoi(args); + target->RewardHonor(NULL, 1, amount); + return true; +} + +bool ChatHandler::HandleHonorAddKillCommand(const char* /*args*/) +{ + Unit *target = getSelectedUnit(); + if (!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0)) + return false; + + m_session->GetPlayer()->RewardHonor(target, 1); + return true; +} + +bool ChatHandler::HandleHonorUpdateCommand(const char* /*args*/) +{ + Player *target = getSelectedPlayer(); + if (!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + target->UpdateHonorFields(); + return true; +} + +bool ChatHandler::HandleLookupEventCommand(const char* args) +{ + if (!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + // converting string that we try to find to lower case + if (!Utf8toWStr(namepart,wnamepart)) + return false; + + wstrToLower(wnamepart); + + bool found = false; + + GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + + for (uint32 id = 0; id < events.size(); ++id) + { + GameEventData const& eventData = events[id]; + + std::string descr = eventData.description; + if (descr.empty()) + continue; + + if (Utf8FitTo(descr, wnamepart)) + { + char const* active = activeEvents.find(id) != activeEvents.end() ? GetTrinityString(LANG_ACTIVE) : ""; + + if (m_session) + PSendSysMessage(LANG_EVENT_ENTRY_LIST_CHAT,id,id,eventData.description.c_str(),active); + else + PSendSysMessage(LANG_EVENT_ENTRY_LIST_CONSOLE,id,eventData.description.c_str(),active); + + if (!found) + found = true; + } + } + + if (!found) + SendSysMessage(LANG_NOEVENTFOUND); + + return true; +} + +bool ChatHandler::HandleEventActiveListCommand(const char* /*args*/) +{ + uint32 counter = 0; + + GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + + char const* active = GetTrinityString(LANG_ACTIVE); + + for (GameEventMgr::ActiveEvents::const_iterator itr = activeEvents.begin(); itr != activeEvents.end(); ++itr) + { + uint32 event_id = *itr; + GameEventData const& eventData = events[event_id]; + + if (m_session) + PSendSysMessage(LANG_EVENT_ENTRY_LIST_CHAT,event_id,event_id,eventData.description.c_str(),active); + else + PSendSysMessage(LANG_EVENT_ENTRY_LIST_CONSOLE,event_id,eventData.description.c_str(),active); + + ++counter; + } + + if (counter == 0) + SendSysMessage(LANG_NOEVENTFOUND); + + return true; +} + +bool ChatHandler::HandleEventInfoCommand(const char* args) +{ + if (!*args) + return false; + + // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameevent"); + if (!cId) + return false; + + uint32 event_id = atoi(cId); + + GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + + if (event_id >=events.size()) + { + SendSysMessage(LANG_EVENT_NOT_EXIST); + SetSentErrorMessage(true); + return false; + } + + GameEventData const& eventData = events[event_id]; + if (!eventData.isValid()) + { + SendSysMessage(LANG_EVENT_NOT_EXIST); + SetSentErrorMessage(true); + return false; + } + + GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + bool active = activeEvents.find(event_id) != activeEvents.end(); + char const* activeStr = active ? GetTrinityString(LANG_ACTIVE) : ""; + + std::string startTimeStr = TimeToTimestampStr(eventData.start); + std::string endTimeStr = TimeToTimestampStr(eventData.end); + + uint32 delay = gameeventmgr.NextCheck(event_id); + time_t nextTime = time(NULL)+delay; + std::string nextStr = nextTime >= eventData.start && nextTime < eventData.end ? TimeToTimestampStr(time(NULL)+delay) : "-"; + + std::string occurenceStr = secsToTimeString(eventData.occurence * MINUTE); + std::string lengthStr = secsToTimeString(eventData.length * MINUTE); + + PSendSysMessage(LANG_EVENT_INFO,event_id,eventData.description.c_str(),activeStr, + startTimeStr.c_str(),endTimeStr.c_str(),occurenceStr.c_str(),lengthStr.c_str(), + nextStr.c_str()); + return true; +} + +bool ChatHandler::HandleEventStartCommand(const char* args) +{ + if (!*args) + return false; + + // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameevent"); + if (!cId) + return false; + + int32 event_id = atoi(cId); + + GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + + if (event_id < 1 || event_id >=events.size()) + { + SendSysMessage(LANG_EVENT_NOT_EXIST); + SetSentErrorMessage(true); + return false; + } + + GameEventData const& eventData = events[event_id]; + if (!eventData.isValid()) + { + SendSysMessage(LANG_EVENT_NOT_EXIST); + SetSentErrorMessage(true); + return false; + } + + GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + if (activeEvents.find(event_id) != activeEvents.end()) + { + PSendSysMessage(LANG_EVENT_ALREADY_ACTIVE,event_id); + SetSentErrorMessage(true); + return false; + } + + gameeventmgr.StartEvent(event_id,true); + return true; +} + +bool ChatHandler::HandleEventStopCommand(const char* args) +{ + if (!*args) + return false; + + // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameevent"); + if (!cId) + return false; + + int32 event_id = atoi(cId); + + GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + + if (event_id < 1 || event_id >=events.size()) + { + SendSysMessage(LANG_EVENT_NOT_EXIST); + SetSentErrorMessage(true); + return false; + } + + GameEventData const& eventData = events[event_id]; + if (!eventData.isValid()) + { + SendSysMessage(LANG_EVENT_NOT_EXIST); + SetSentErrorMessage(true); + return false; + } + + GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + + if (activeEvents.find(event_id) == activeEvents.end()) + { + PSendSysMessage(LANG_EVENT_NOT_ACTIVE,event_id); + SetSentErrorMessage(true); + return false; + } + + gameeventmgr.StopEvent(event_id,true); + return true; +} + +bool ChatHandler::HandleCombatStopCommand(const char* args) +{ + Player* target; + if (!extractPlayerTarget((char*)args,&target)) + return false; + + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + target->CombatStop(); + target->getHostileRefManager().deleteReferences(); + return true; +} + +void ChatHandler::HandleLearnSkillRecipesHelper(Player* player,uint32 skill_id) +{ + uint32 classmask = player->getClassMask(); + + for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) + { + SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j); + if (!skillLine) + continue; + + // wrong skill + if (skillLine->skillId != skill_id) + continue; + + // not high rank + if (skillLine->forward_spellid) + continue; + + // skip racial skills + if (skillLine->racemask != 0) + continue; + + // skip wrong class skills + if (skillLine->classmask && (skillLine->classmask & classmask) == 0) + continue; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId); + if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo,player,false)) + continue; + + player->learnSpell(skillLine->spellId, false); + } +} + +bool ChatHandler::HandleLearnAllCraftsCommand(const char* /*args*/) +{ + + for (uint32 i = 0; i < sSkillLineStore.GetNumRows(); ++i) + { + SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(i); + if (!skillInfo) + continue; + + if ((skillInfo->categoryId == SKILL_CATEGORY_PROFESSION || skillInfo->categoryId == SKILL_CATEGORY_SECONDARY) && + skillInfo->canLink) // only prof. with recipes have + { + HandleLearnSkillRecipesHelper(m_session->GetPlayer(),skillInfo->id); + } + } + + SendSysMessage(LANG_COMMAND_LEARN_ALL_CRAFT); + return true; +} + +bool ChatHandler::HandleLearnAllRecipesCommand(const char* args) +{ + // Learns all recipes of specified profession and sets skill to max + // Example: .learn all_recipes enchanting + + Player* target = getSelectedPlayer(); + if (!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + return false; + } + + if (!*args) + return false; + + std::wstring wnamepart; + + if (!Utf8toWStr(args,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower(wnamepart); + + std::string name; + + SkillLineEntry const *targetSkillInfo = NULL; + for (uint32 i = 1; i < sSkillLineStore.GetNumRows(); ++i) + { + SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(i); + if (!skillInfo) + continue; + + if ((skillInfo->categoryId != SKILL_CATEGORY_PROFESSION && + skillInfo->categoryId != SKILL_CATEGORY_SECONDARY) || + !skillInfo->canLink) // only prof with recipes have set + continue; + + int loc = GetSessionDbcLocale(); + name = skillInfo->name[loc]; + if (name.empty()) + continue; + + if (!Utf8FitTo(name, wnamepart)) + { + loc = 0; + for (; loc < MAX_LOCALE; ++loc) + { + if (loc == GetSessionDbcLocale()) + continue; + + name = skillInfo->name[loc]; + if (name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if (loc < MAX_LOCALE) + { + targetSkillInfo = skillInfo; + break; + } + } + + if (!targetSkillInfo) + return false; + + HandleLearnSkillRecipesHelper(target,targetSkillInfo->id); + + uint16 maxLevel = target->GetPureMaxSkillValue(targetSkillInfo->id); + target->SetSkill(targetSkillInfo->id, target->GetSkillStep(targetSkillInfo->id), maxLevel, maxLevel); + PSendSysMessage(LANG_COMMAND_LEARN_ALL_RECIPES, name.c_str()); + return true; +} + +bool ChatHandler::HandleLookupPlayerIpCommand(const char* args) +{ + + if (!*args) + return false; + + std::string ip = strtok ((char*)args, " "); + char* limit_str = strtok (NULL, " "); + int32 limit = limit_str ? atoi (limit_str) : -1; + + LoginDatabase.escape_string (ip); + + QueryResult_AutoPtr result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE last_ip = '%s'", ip.c_str ()); + + return LookupPlayerSearchCommand (result,limit); +} + +bool ChatHandler::HandleLookupPlayerAccountCommand(const char* args) +{ + if (!*args) + return false; + + std::string account = strtok ((char*)args, " "); + char* limit_str = strtok (NULL, " "); + int32 limit = limit_str ? atoi (limit_str) : -1; + + if (!AccountMgr::normalizeString (account)) + return false; + + LoginDatabase.escape_string (account); + + QueryResult_AutoPtr result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE username = '%s'", account.c_str ()); + + return LookupPlayerSearchCommand (result,limit); +} + +bool ChatHandler::HandleLookupPlayerEmailCommand(const char* args) +{ + + if (!*args) + return false; + + std::string email = strtok ((char*)args, " "); + char* limit_str = strtok (NULL, " "); + int32 limit = limit_str ? atoi (limit_str) : -1; + + LoginDatabase.escape_string (email); + + QueryResult_AutoPtr result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE email = '%s'", email.c_str ()); + + return LookupPlayerSearchCommand (result,limit); +} + +bool ChatHandler::LookupPlayerSearchCommand(QueryResult_AutoPtr result, int32 limit) +{ + if (!result) + { + PSendSysMessage(LANG_NO_PLAYERS_FOUND); + SetSentErrorMessage(true); + return false; + } + + int i =0; + do + { + Field* fields = result->Fetch(); + uint32 acc_id = fields[0].GetUInt32(); + std::string acc_name = fields[1].GetCppString(); + + QueryResult_AutoPtr chars = CharacterDatabase.PQuery("SELECT guid,name FROM characters WHERE account = '%u'", acc_id); + if (chars) + { + PSendSysMessage(LANG_LOOKUP_PLAYER_ACCOUNT,acc_name.c_str(),acc_id); + + uint64 guid = 0; + std::string name; + + do + { + Field* charfields = chars->Fetch(); + guid = charfields[0].GetUInt64(); + name = charfields[1].GetCppString(); + + PSendSysMessage(LANG_LOOKUP_PLAYER_CHARACTER,name.c_str(),guid); + ++i; + + } while (chars->NextRow() && (limit == -1 || i < limit)); + } + } while (result->NextRow()); + + if (i == 0) // empty accounts only + { + PSendSysMessage(LANG_NO_PLAYERS_FOUND); + SetSentErrorMessage(true); + return false; + } + + return true; +} + +/// Triggering corpses expire check in world +bool ChatHandler::HandleServerCorpsesCommand(const char* /*args*/) +{ + CorpsesErase(); + return true; +} + +bool ChatHandler::HandleRepairitemsCommand(const char* args) +{ + Player* target; + if (!extractPlayerTarget((char*)args,&target)) + return false; + + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + // Repair items + target->DurabilityRepairAll(false, 0, false); + + PSendSysMessage(LANG_YOU_REPAIR_ITEMS, GetNameLink(target).c_str()); + if (needReportToTarget(target)) + ChatHandler(target).PSendSysMessage(LANG_YOUR_ITEMS_REPAIRED, GetNameLink().c_str()); + return true; +} + +bool ChatHandler::HandleWaterwalkCommand(const char* args) +{ + if (!*args) + return false; + + Player *player = getSelectedPlayer(); + + if (!player) + { + PSendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(player, 0)) + return false; + + if (strncmp(args, "on", 3) == 0) + player->SetMovement(MOVE_WATER_WALK); // ON + else if (strncmp(args, "off", 4) == 0) + player->SetMovement(MOVE_LAND_WALK); // OFF + else + { + SendSysMessage(LANG_USE_BOL); + return false; + } + + PSendSysMessage(LANG_YOU_SET_WATERWALK, args, GetNameLink(player).c_str()); + if (needReportToTarget(player)) + ChatHandler(player).PSendSysMessage(LANG_YOUR_WATERWALK_SET, args, GetNameLink().c_str()); + return true; +} + +bool ChatHandler::HandleCreatePetCommand(const char* /*args*/) +{ + Player *player = m_session->GetPlayer(); + Creature *creatureTarget = getSelectedCreature(); + + if (!creatureTarget || creatureTarget->isPet() || creatureTarget->GetTypeId() == TYPEID_PLAYER) + { + PSendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + CreatureInfo const* cInfo = objmgr.GetCreatureTemplate(creatureTarget->GetEntry()); + // Creatures with family 0 crashes the server + if (cInfo->family == 0) + { + PSendSysMessage("This creature cannot be tamed. (family id: 0)."); + SetSentErrorMessage(true); + return false; + } + + if (player->GetPetGUID()) + { + PSendSysMessage("You already have a pet"); + SetSentErrorMessage(true); + return false; + } + + // Everything looks OK, create new pet + Pet* pet = new Pet(player, HUNTER_PET); + + if (!pet) + return false; + + if (!pet->CreateBaseAtCreature(creatureTarget)) + { + delete pet; + PSendSysMessage("Error 1"); + return false; + } + + creatureTarget->setDeathState(JUST_DIED); + creatureTarget->RemoveCorpse(); + creatureTarget->SetHealth(0); // just for nice GM-mode view + + pet->SetUInt64Value(UNIT_FIELD_CREATEDBY, player->GetGUID()); + pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, player->getFaction()); + + if (!pet->InitStatsForLevel(creatureTarget->getLevel())) + { + sLog.outError("ERROR: InitStatsForLevel() in EffectTameCreature failed! Pet deleted."); + PSendSysMessage("Error 2"); + delete pet; + return false; + } + + // prepare visual effect for levelup + pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()-1); + + pet->GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true); + // this enables pet details window (Shift+P) + pet->InitPetCreateSpells(); + pet->SetHealth(pet->GetMaxHealth()); + + pet->GetMap()->Add(pet->ToCreature()); + + // visual effect for levelup + pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()); + + player->SetMinion(pet, true); + pet->SavePetToDB(PET_SAVE_AS_CURRENT); + player->PetSpellInitialize(); + + return true; +} + +bool ChatHandler::HandlePetLearnCommand(const char* args) +{ + if (!*args) + return false; + + Player *plr = m_session->GetPlayer(); + Pet *pet = plr->GetPet(); + + if (!pet) + { + PSendSysMessage("You have no pet"); + SetSentErrorMessage(true); + return false; + } + + uint32 spellId = extractSpellIdFromLink((char*)args); + + if (!spellId || !sSpellStore.LookupEntry(spellId)) + return false; + + // Check if pet already has it + if (pet->HasSpell(spellId)) + { + PSendSysMessage("Pet already has spell: %u", spellId); + SetSentErrorMessage(true); + return false; + } + + // Check if spell is valid + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); + if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo)) + { + PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spellId); + SetSentErrorMessage(true); + return false; + } + + pet->learnSpell(spellId); + + PSendSysMessage("Pet has learned spell %u", spellId); + return true; +} + +bool ChatHandler::HandlePetUnlearnCommand(const char *args) +{ + if (!*args) + return false; + + Player *plr = m_session->GetPlayer(); + Pet *pet = plr->GetPet(); + + if (!pet) + { + PSendSysMessage("You have no pet"); + SetSentErrorMessage(true); + return false; + } + + uint32 spellId = extractSpellIdFromLink((char*)args); + + if (pet->HasSpell(spellId)) + pet->removeSpell(spellId, false); + else + PSendSysMessage("Pet doesn't have that spell"); + + return true; +} + +bool ChatHandler::HandlePetTpCommand(const char *args) +{ + if (!*args) + return false; + + Player *plr = m_session->GetPlayer(); + Pet *pet = plr->GetPet(); + + if (!pet) + { + PSendSysMessage("You have no pet"); + SetSentErrorMessage(true); + return false; + } + + uint32 tp = atol(args); + + //pet->SetTP(tp); + + PSendSysMessage("Pet's tp changed to %u", tp); + return true; +} + +bool ChatHandler::HandleActivateObjectCommand(const char *args) +{ + if (!*args) + return false; + + char* cId = extractKeyFromLink((char*)args,"Hgameobject"); + if (!cId) + return false; + + uint32 lowguid = atoi(cId); + if (!lowguid) + return false; + + GameObject* obj = NULL; + + // by DB guid + if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) + obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); + + if (!obj) + { + PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + // Activate + obj->SetLootState(GO_READY); + obj->UseDoorOrButton(10000); + + PSendSysMessage("Object activated!"); + + return true; +} + +// add creature, temp only +bool ChatHandler::HandleTempAddSpwCommand(const char* args) +{ + if (!*args) + return false; + char* charID = strtok((char*)args, " "); + if (!charID) + return false; + + Player *chr = m_session->GetPlayer(); + + uint32 id = atoi(charID); + if (!id) + return false; + + chr->SummonCreature(id, *chr, TEMPSUMMON_CORPSE_DESPAWN, 120); + + return true; +} + +// add go, temp only +bool ChatHandler::HandleTempGameObjectCommand(const char* args) +{ + if (!*args) + return false; + char* charID = strtok((char*)args, " "); + if (!charID) + return false; + + Player *chr = m_session->GetPlayer(); + + char* spawntime = strtok(NULL, " "); + uint32 spawntm = 300; + + if (spawntime) + spawntm = atoi((char*)spawntime); + + float x = chr->GetPositionX(); + float y = chr->GetPositionY(); + float z = chr->GetPositionZ(); + float ang = chr->GetOrientation(); + + float rot2 = sin(ang/2); + float rot3 = cos(ang/2); + + uint32 id = atoi(charID); + + chr->SummonGameObject(id,x,y,z,ang,0,0,rot2,rot3,spawntm); + + return true; +} + +bool ChatHandler::HandleNpcAddFormationCommand(const char* args) +{ + if (!*args) + return false; + + uint32 leaderGUID = (uint32) atoi((char*)args); + Creature *pCreature = getSelectedCreature(); + + if (!pCreature || !pCreature->GetDBTableGUIDLow()) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + uint32 lowguid = pCreature->GetDBTableGUIDLow(); + if (pCreature->GetFormation()) + { + PSendSysMessage("Selected creature is already member of group %u", pCreature->GetFormation()->GetId()); + return false; + } + + if (!lowguid) + return false; + + Player *chr = m_session->GetPlayer(); + FormationInfo *group_member; + + group_member = new FormationInfo; + group_member->follow_angle = (pCreature->GetAngle(chr) - chr->GetOrientation()) * 180 / M_PI; + group_member->follow_dist = sqrtf(pow(chr->GetPositionX() - pCreature->GetPositionX(),int(2))+pow(chr->GetPositionY()-pCreature->GetPositionY(),int(2))); + group_member->leaderGUID = leaderGUID; + group_member->groupAI = 0; + + CreatureGroupMap[lowguid] = group_member; + pCreature->SearchFormation(); + + WorldDatabase.PExecuteLog("INSERT INTO creature_formations (leaderGUID, memberGUID, dist, angle, groupAI) VALUES ('%u','%u','%f', '%f', '%u')", + leaderGUID, lowguid, group_member->follow_dist, group_member->follow_angle, group_member->groupAI); + + PSendSysMessage("Creature %u added to formation with leader %u", lowguid, leaderGUID); + + return true; + } + +bool ChatHandler::HandleNpcSetLinkCommand(const char* args) +{ + if (!*args) + return false; + + uint32 linkguid = (uint32) atoi((char*)args); + + Creature* pCreature = getSelectedCreature(); + + if (!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if (!pCreature->GetDBTableGUIDLow()) + { + PSendSysMessage("Selected creature isn't in creature table", pCreature->GetGUIDLow()); + SetSentErrorMessage(true); + return false; + } + + if (!objmgr.SetCreatureLinkedRespawn(pCreature->GetDBTableGUIDLow(), linkguid)) + { + PSendSysMessage("Selected creature can't link with guid '%u'", linkguid); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage("LinkGUID '%u' added to creature with DBTableGUID: '%u'", linkguid, pCreature->GetDBTableGUIDLow()); + return true; +} + +bool ChatHandler::HandleLookupTitleCommand(const char* args) +{ + if (!*args) + return false; + + // can be NULL in console call + Player* target = getSelectedPlayer(); + + // title name have single string arg for player name + char const* targetName = target ? target->GetName() : "NAME"; + + std::string namepart = args; + std::wstring wnamepart; + + if (!Utf8toWStr(namepart,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower(wnamepart); + + uint32 counter = 0; // Counter for figure out that we found smth. + + // Search in CharTitles.dbc + for (uint32 id = 0; id < sCharTitlesStore.GetNumRows(); id++) + { + CharTitlesEntry const *titleInfo = sCharTitlesStore.LookupEntry(id); + if (titleInfo) + { + int loc = GetSessionDbcLocale(); + std::string name = titleInfo->name[loc]; + if (name.empty()) + continue; + + if (!Utf8FitTo(name, wnamepart)) + { + loc = 0; + for (; loc < MAX_LOCALE; ++loc) + { + if (loc == GetSessionDbcLocale()) + continue; + + name = titleInfo->name[loc]; + if (name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if (loc < MAX_LOCALE) + { + char const* knownStr = target && target->HasTitle(titleInfo) ? GetTrinityString(LANG_KNOWN) : ""; + + char const* activeStr = target && target->GetUInt32Value(PLAYER_CHOSEN_TITLE) == titleInfo->bit_index + ? GetTrinityString(LANG_ACTIVE) + : ""; + + char titleNameStr[80]; + snprintf(titleNameStr,80,name.c_str(),targetName); + + // send title in "id (idx:idx) - [namedlink locale]" format + if (m_session) + PSendSysMessage(LANG_TITLE_LIST_CHAT,id,titleInfo->bit_index,id,titleNameStr,localeNames[loc],knownStr,activeStr); + else + PSendSysMessage(LANG_TITLE_LIST_CONSOLE,id,titleInfo->bit_index,titleNameStr,localeNames[loc],knownStr,activeStr); + + ++counter; + } + } + } + if (counter == 0) // if counter == 0 then we found nth + SendSysMessage(LANG_COMMAND_NOTITLEFOUND); + return true; +} + +bool ChatHandler::HandleTitlesAddCommand(const char* args) +{ + // number or [name] Shift-click form |color|Htitle:title_id|h[name]|h|r + char* id_p = extractKeyFromLink((char*)args,"Htitle"); + if (!id_p) + return false; + + int32 id = atoi(id_p); + if (id <= 0) + { + PSendSysMessage(LANG_INVALID_TITLE_ID, id); + SetSentErrorMessage(true); + return false; + } + + Player * target = getSelectedPlayer(); + if (!target) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + CharTitlesEntry const* titleInfo = sCharTitlesStore.LookupEntry(id); + if (!titleInfo) + { + PSendSysMessage(LANG_INVALID_TITLE_ID, id); + SetSentErrorMessage(true); + return false; + } + + std::string tNameLink = GetNameLink(target); + + char const* targetName = target->GetName(); + char titleNameStr[80]; + snprintf(titleNameStr,80,titleInfo->name[GetSessionDbcLocale()],targetName); + + target->SetTitle(titleInfo); + PSendSysMessage(LANG_TITLE_ADD_RES, id, titleNameStr, tNameLink.c_str()); + + return true; +} + +bool ChatHandler::HandleTitlesRemoveCommand(const char* args) +{ + // number or [name] Shift-click form |color|Htitle:title_id|h[name]|h|r + char* id_p = extractKeyFromLink((char*)args,"Htitle"); + if (!id_p) + return false; + + int32 id = atoi(id_p); + if (id <= 0) + { + PSendSysMessage(LANG_INVALID_TITLE_ID, id); + SetSentErrorMessage(true); + return false; + } + + Player * target = getSelectedPlayer(); + if (!target) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + CharTitlesEntry const* titleInfo = sCharTitlesStore.LookupEntry(id); + if (!titleInfo) + { + PSendSysMessage(LANG_INVALID_TITLE_ID, id); + SetSentErrorMessage(true); + return false; + } + + target->SetTitle(titleInfo,true); + + std::string tNameLink = GetNameLink(target); + + char const* targetName = target->GetName(); + char titleNameStr[80]; + snprintf(titleNameStr,80,titleInfo->name[GetSessionDbcLocale()],targetName); + + PSendSysMessage(LANG_TITLE_REMOVE_RES, id, titleNameStr, tNameLink.c_str()); + + if (!target->HasTitle(target->GetInt32Value(PLAYER_CHOSEN_TITLE))) + { + target->SetUInt32Value(PLAYER_CHOSEN_TITLE,0); + PSendSysMessage(LANG_CURRENT_TITLE_RESET, tNameLink.c_str()); + } + + return true; +} + +//Edit Player KnownTitles +bool ChatHandler::HandleTitlesSetMaskCommand(const char* args) +{ + if (!*args) + return false; + + uint64 titles = 0; + + sscanf((char*)args, UI64FMTD, &titles); + + Player *target = getSelectedPlayer(); + if (!target) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + uint64 titles2 = titles; + + for (uint32 i = 1; i < sCharTitlesStore.GetNumRows(); ++i) + if (CharTitlesEntry const* tEntry = sCharTitlesStore.LookupEntry(i)) + titles2 &= ~(uint64(1) << tEntry->bit_index); + + titles &= ~titles2; // remove not existed titles + + target->SetUInt64Value(PLAYER__FIELD_KNOWN_TITLES, titles); + SendSysMessage(LANG_DONE); + + if (!target->HasTitle(target->GetInt32Value(PLAYER_CHOSEN_TITLE))) + { + target->SetUInt32Value(PLAYER_CHOSEN_TITLE,0); + PSendSysMessage(LANG_CURRENT_TITLE_RESET,GetNameLink(target).c_str()); + } + + return true; +} + +bool ChatHandler::HandleCharacterTitlesCommand(const char* args) +{ + Player* target; + if (!extractPlayerTarget((char*)args,&target)) + return false; + + LocaleConstant loc = GetSessionDbcLocale(); + char const* targetName = target->GetName(); + char const* knownStr = GetTrinityString(LANG_KNOWN); + + // Search in CharTitles.dbc + for (uint32 id = 0; id < sCharTitlesStore.GetNumRows(); id++) + { + CharTitlesEntry const *titleInfo = sCharTitlesStore.LookupEntry(id); + if (titleInfo && target->HasTitle(titleInfo)) + { + std::string name = titleInfo->name[loc]; + if (name.empty()) + continue; + + char const* activeStr = target && target->GetUInt32Value(PLAYER_CHOSEN_TITLE) == titleInfo->bit_index + ? GetTrinityString(LANG_ACTIVE) + : ""; + + char titleNameStr[80]; + snprintf(titleNameStr,80,name.c_str(),targetName); + + // send title in "id (idx:idx) - [namedlink locale]" format + if (m_session) + PSendSysMessage(LANG_TITLE_LIST_CHAT,id,titleInfo->bit_index,id,titleNameStr,localeNames[loc],knownStr,activeStr); + else + PSendSysMessage(LANG_TITLE_LIST_CONSOLE,id,titleInfo->bit_index,name.c_str(),localeNames[loc],knownStr,activeStr); + } + } + return true; +} + +bool ChatHandler::HandleTitlesCurrentCommand(const char* args) +{ + // number or [name] Shift-click form |color|Htitle:title_id|h[name]|h|r + char* id_p = extractKeyFromLink((char*)args,"Htitle"); + if (!id_p) + return false; + + int32 id = atoi(id_p); + if (id <= 0) + { + PSendSysMessage(LANG_INVALID_TITLE_ID, id); + SetSentErrorMessage(true); + return false; + } + + Player * target = getSelectedPlayer(); + if (!target) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // check online security + if (HasLowerSecurity(target, 0)) + return false; + + CharTitlesEntry const* titleInfo = sCharTitlesStore.LookupEntry(id); + if (!titleInfo) + { + PSendSysMessage(LANG_INVALID_TITLE_ID, id); + SetSentErrorMessage(true); + return false; + } + + std::string tNameLink = GetNameLink(target); + + target->SetTitle(titleInfo); // to be sure that title now known + target->SetUInt32Value(PLAYER_CHOSEN_TITLE,titleInfo->bit_index); + + PSendSysMessage(LANG_TITLE_CURRENT_RES, id, titleInfo->name[GetSessionDbcLocale()], tNameLink.c_str()); + + return true; +} diff --git a/src/server/game/Chat/Commands/Level3.cpp b/src/server/game/Chat/Commands/Level3.cpp new file mode 100644 index 00000000000..f7ced44922b --- /dev/null +++ b/src/server/game/Chat/Commands/Level3.cpp @@ -0,0 +1,7743 @@ +/* +* Copyright (C) 2005-2009 MaNGOS +* +* Copyright (C) 2008-2010 Trinity +* +* 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, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectMgr.h" +#include "AuctionHouseMgr.h" +#include "AccountMgr.h" +#include "PlayerDump.h" +#include "SpellMgr.h" +#include "Player.h" +#include "Opcodes.h" +#include "GameObject.h" +#include "Chat.h" +#include "Log.h" +#include "Guild.h" +#include "ObjectAccessor.h" +#include "MapManager.h" +#include "Language.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" +#include "Weather.h" +#include "PointMovementGenerator.h" +#include "TargetedMovementGenerator.h" +#include "SkillDiscovery.h" +#include "SkillExtraItems.h" +#include "SystemConfig.h" +#include "Config/ConfigEnv.h" +#include "Util.h" +#include "ItemEnchantmentMgr.h" +#include "BattleGroundMgr.h" +#include "InstanceSaveMgr.h" +#include "InstanceData.h" +#include "AuctionHouseBot.h" +#include "CreatureEventAIMgr.h" +#include "SpellAuraEffects.h" +#include "DBCEnums.h" +#include "ConditionMgr.h" + +bool ChatHandler::HandleAHBotOptionsCommand(const char *args) +{ + uint32 ahMapID = 0; + char * opt = strtok((char*)args, " "); + char * ahMapIdStr = strtok(NULL, " "); + if (ahMapIdStr) + { + ahMapID = (uint32) strtoul(ahMapIdStr, NULL, 0); + switch (ahMapID) + { + case 2: + case 6: + case 7: + break; + default: + opt = NULL; + break; + } + } + if (!opt) + { + PSendSysMessage("Syntax is: ahbotoptions $option $ahMapID (2, 6 or 7) $parameter"); + PSendSysMessage("Try ahbotoptions help to see a list of options."); + return false; + } + int l = strlen(opt); + + if (strncmp(opt,"help",l) == 0) + { + PSendSysMessage("AHBot commands:"); + PSendSysMessage("ahexpire"); + PSendSysMessage("minitems"); + PSendSysMessage("maxitems"); + //PSendSysMessage(""); + //PSendSysMessage(""); + PSendSysMessage("percentages"); + PSendSysMessage("minprice"); + PSendSysMessage("maxprice"); + PSendSysMessage("minbidprice"); + PSendSysMessage("maxbidprice"); + PSendSysMessage("maxstack"); + PSendSysMessage("buyerprice"); + PSendSysMessage("bidinterval"); + PSendSysMessage("bidsperinterval"); + return true; + } + else if (strncmp(opt,"ahexpire",l) == 0) + { + if (!ahMapIdStr) + { + PSendSysMessage("Syntax is: ahbotoptions ahexpire $ahMapID (2, 6 or 7)"); + return false; + } + auctionbot.Commands(0, ahMapID, NULL, NULL); + } + else if (strncmp(opt,"minitems",l) == 0) + { + char * param1 = strtok(NULL, " "); + if ((!ahMapIdStr) || (!param1)) + { + PSendSysMessage("Syntax is: ahbotoptions minitems $ahMapID (2, 6 or 7) $minItems"); + return false; + } + auctionbot.Commands(1, ahMapID, NULL, param1); + } + else if (strncmp(opt,"maxitems",l) == 0) + { + char * param1 = strtok(NULL, " "); + if ((!ahMapIdStr) || (!param1)) + { + PSendSysMessage("Syntax is: ahbotoptions maxitems $ahMapID (2, 6 or 7) $maxItems"); + return false; + } + auctionbot.Commands(2, ahMapID, NULL, param1); + } + else if (strncmp(opt,"mintime",l) == 0) + { + PSendSysMessage("ahbotoptions mintime has been deprecated"); + return false; + /* + char * param1 = strtok(NULL, " "); + if ((!ahMapIdStr) || (!param1)) + { + PSendSysMessage("Syntax is: ahbotoptions mintime $ahMapID (2, 6 or 7) $mintime"); + return false; + } + auctionbot.Commands(3, ahMapID, NULL, param1); + */ + } + else if (strncmp(opt,"maxtime",l) == 0) + { + PSendSysMessage("ahbotoptions maxtime has been deprecated"); + return false; + /* + char * param1 = strtok(NULL, " "); + if ((!ahMapIdStr) || (!param1)) + { + PSendSysMessage("Syntax is: ahbotoptions maxtime $ahMapID (2, 6 or 7) $maxtime"); + return false; + } + auctionbot.Commands(4, ahMapID, NULL, param1); + */ + } + else if (strncmp(opt,"percentages",l) == 0) + { + char * param1 = strtok(NULL, " "); + char * param2 = strtok(NULL, " "); + char * param3 = strtok(NULL, " "); + char * param4 = strtok(NULL, " "); + char * param5 = strtok(NULL, " "); + char * param6 = strtok(NULL, " "); + char * param7 = strtok(NULL, " "); + char * param8 = strtok(NULL, " "); + char * param9 = strtok(NULL, " "); + char * param10 = strtok(NULL, " "); + char * param11 = strtok(NULL, " "); + char * param12 = strtok(NULL, " "); + char * param13 = strtok(NULL, " "); + char * param14 = strtok(NULL, " "); + if ((!ahMapIdStr) || (!param14)) + { + PSendSysMessage("Syntax is: ahbotoptions percentages $ahMapID (2, 6 or 7) $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14"); + PSendSysMessage("1 GreyTradeGoods 2 WhiteTradeGoods 3 GreenTradeGoods 4 BlueTradeGoods 5 PurpleTradeGoods"); + PSendSysMessage("6 OrangeTradeGoods 7 YellowTradeGoods 8 GreyItems 9 WhiteItems 10 GreenItems 11 BlueItems"); + PSendSysMessage("12 PurpleItems 13 OrangeItems 14 YellowItems"); + PSendSysMessage("The total must add up to 100%"); + return false; + } + uint32 greytg = (uint32) strtoul(param1, NULL, 0); + uint32 whitetg = (uint32) strtoul(param2, NULL, 0); + uint32 greentg = (uint32) strtoul(param3, NULL, 0); + uint32 bluetg = (uint32) strtoul(param3, NULL, 0); + uint32 purpletg = (uint32) strtoul(param5, NULL, 0); + uint32 orangetg = (uint32) strtoul(param6, NULL, 0); + uint32 yellowtg = (uint32) strtoul(param7, NULL, 0); + uint32 greyi = (uint32) strtoul(param8, NULL, 0); + uint32 whitei = (uint32) strtoul(param9, NULL, 0); + uint32 greeni = (uint32) strtoul(param10, NULL, 0); + uint32 bluei = (uint32) strtoul(param11, NULL, 0); + uint32 purplei = (uint32) strtoul(param12, NULL, 0); + uint32 orangei = (uint32) strtoul(param13, NULL, 0); + uint32 yellowi = (uint32) strtoul(param14, NULL, 0); + uint32 totalPercent = greytg + whitetg + greentg + bluetg + purpletg + orangetg + yellowtg + greyi + whitei + greeni + bluei + purplei + orangei + yellowi; + if ((totalPercent == 0) || (totalPercent != 100)) + { + PSendSysMessage("Syntax is: ahbotoptions percentages $ahMapID (2, 6 or 7) $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14"); + PSendSysMessage("1 GreyTradeGoods 2 WhiteTradeGoods 3 GreenTradeGoods 4 BlueTradeGoods 5 PurpleTradeGoods"); + PSendSysMessage("6 OrangeTradeGoods 7 YellowTradeGoods 8 GreyItems 9 WhiteItems 10 GreenItems 11 BlueItems"); + PSendSysMessage("12 PurpleItems 13 OrangeItems 14 YellowItems"); + PSendSysMessage("The total must add up to 100%"); + return false; + } + char param[100]; + param[0] = '\0'; + strcat(param, param1); + strcat(param, " "); + strcat(param, param2); + strcat(param, " "); + strcat(param, param3); + strcat(param, " "); + strcat(param, param4); + strcat(param, " "); + strcat(param, param5); + strcat(param, " "); + strcat(param, param6); + strcat(param, " "); + strcat(param, param7); + strcat(param, " "); + strcat(param, param8); + strcat(param, " "); + strcat(param, param9); + strcat(param, " "); + strcat(param, param10); + strcat(param, " "); + strcat(param, param11); + strcat(param, " "); + strcat(param, param12); + strcat(param, " "); + strcat(param, param13); + strcat(param, " "); + strcat(param, param14); + auctionbot.Commands(5, ahMapID, NULL, param); + } + else if (strncmp(opt,"minprice",l) == 0) + { + char * param1 = strtok(NULL, " "); + char * param2 = strtok(NULL, " "); + if ((!ahMapIdStr) || (!param1) || (!param2)) + { + PSendSysMessage("Syntax is: ahbotoptions minprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + if (strncmp(param1,"grey",l) == 0) + { + auctionbot.Commands(6, ahMapID, AHB_GREY, param2); + } + else if (strncmp(param1,"white",l) == 0) + { + auctionbot.Commands(6, ahMapID, AHB_WHITE, param2); + } + else if (strncmp(param1,"green",l) == 0) + { + auctionbot.Commands(6, ahMapID, AHB_GREEN, param2); + } + else if (strncmp(param1,"blue",l) == 0) + { + auctionbot.Commands(6, ahMapID, AHB_BLUE, param2); + } + else if (strncmp(param1,"purple",l) == 0) + { + auctionbot.Commands(6, ahMapID, AHB_PURPLE, param2); + } + else if (strncmp(param1,"orange",l) == 0) + { + auctionbot.Commands(6, ahMapID, AHB_ORANGE, param2); + } + else if (strncmp(param1,"yellow",l) == 0) + { + auctionbot.Commands(6, ahMapID, AHB_YELLOW, param2); + } + else + { + PSendSysMessage("Syntax is: ahbotoptions minprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + } + else if (strncmp(opt,"maxprice",l) == 0) + { + char * param1 = strtok(NULL, " "); + char * param2 = strtok(NULL, " "); + if ((!ahMapIdStr) || (!param1) || (!param2)) + { + PSendSysMessage("Syntax is: ahbotoptions maxprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + if (strncmp(param1,"grey",l) == 0) + { + auctionbot.Commands(7, ahMapID, AHB_GREY, param2); + } + else if (strncmp(param1,"white",l) == 0) + { + auctionbot.Commands(7, ahMapID, AHB_WHITE, param2); + } + else if (strncmp(param1,"green",l) == 0) + { + auctionbot.Commands(7, ahMapID, AHB_GREEN, param2); + } + else if (strncmp(param1,"blue",l) == 0) + { + auctionbot.Commands(7, ahMapID, AHB_BLUE, param2); + } + else if (strncmp(param1,"purple",l) == 0) + { + auctionbot.Commands(7, ahMapID, AHB_PURPLE, param2); + } + else if (strncmp(param1,"orange",l) == 0) + { + auctionbot.Commands(7, ahMapID, AHB_ORANGE, param2); + } + else if (strncmp(param1,"yellow",l) == 0) + { + auctionbot.Commands(7, ahMapID, AHB_YELLOW, param2); + } + else + { + PSendSysMessage("Syntax is: ahbotoptions maxprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + } + else if (strncmp(opt,"minbidprice",l) == 0) + { + char * param1 = strtok(NULL, " "); + char * param2 = strtok(NULL, " "); + if ((!ahMapIdStr) || (!param1) || (!param2)) + { + PSendSysMessage("Syntax is: ahbotoptions minbidprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + uint32 minBidPrice = (uint32) strtoul(param2, NULL, 0); + if ((minBidPrice < 1) || (minBidPrice > 100)) + { + PSendSysMessage("The min bid price multiplier must be between 1 and 100"); + return false; + } + if (strncmp(param1,"grey",l) == 0) + { + auctionbot.Commands(8, ahMapID, AHB_GREY, param2); + } + else if (strncmp(param1,"white",l) == 0) + { + auctionbot.Commands(8, ahMapID, AHB_WHITE, param2); + } + else if (strncmp(param1,"green",l) == 0) + { + auctionbot.Commands(8, ahMapID, AHB_GREEN, param2); + } + else if (strncmp(param1,"blue",l) == 0) + { + auctionbot.Commands(8, ahMapID, AHB_BLUE, param2); + } + else if (strncmp(param1,"purple",l) == 0) + { + auctionbot.Commands(8, ahMapID, AHB_PURPLE, param2); + } + else if (strncmp(param1,"orange",l) == 0) + { + auctionbot.Commands(8, ahMapID, AHB_ORANGE, param2); + } + else if (strncmp(param1,"yellow",l) == 0) + { + auctionbot.Commands(8, ahMapID, AHB_YELLOW, param2); + } + else + { + PSendSysMessage("Syntax is: ahbotoptions minbidprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + } + else if (strncmp(opt,"maxbidprice",l) == 0) + { + char * param1 = strtok(NULL, " "); + char * param2 = strtok(NULL, " "); + if ((!ahMapIdStr) || (!param1) || (!param2)) + { + PSendSysMessage("Syntax is: ahbotoptions maxbidprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + uint32 maxBidPrice = (uint32) strtoul(param2, NULL, 0); + if ((maxBidPrice < 1) || (maxBidPrice > 100)) + { + PSendSysMessage("The max bid price multiplier must be between 1 and 100"); + return false; + } + if (strncmp(param1,"grey",l) == 0) + { + auctionbot.Commands(9, ahMapID, AHB_GREY, param2); + } + else if (strncmp(param1,"white",l) == 0) + { + auctionbot.Commands(9, ahMapID, AHB_WHITE, param2); + } + else if (strncmp(param1,"green",l) == 0) + { + auctionbot.Commands(9, ahMapID, AHB_GREEN, param2); + } + else if (strncmp(param1,"blue",l) == 0) + { + auctionbot.Commands(9, ahMapID, AHB_BLUE, param2); + } + else if (strncmp(param1,"purple",l) == 0) + { + auctionbot.Commands(9, ahMapID, AHB_PURPLE, param2); + } + else if (strncmp(param1,"orange",l) == 0) + { + auctionbot.Commands(9, ahMapID, AHB_ORANGE, param2); + } + else if (strncmp(param1,"yellow",l) == 0) + { + auctionbot.Commands(9, ahMapID, AHB_YELLOW, param2); + } + else + { + PSendSysMessage("Syntax is: ahbotoptions max bidprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); + return false; + } + } + else if (strncmp(opt,"maxstack",l) == 0) + { + char * param1 = strtok(NULL, " "); + char * param2 = strtok(NULL, " "); + if ((!ahMapIdStr) || (!param1) || (!param2)) + { + PSendSysMessage("Syntax is: ahbotoptions maxstack $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $value"); + return false; + } + uint32 maxStack = (uint32) strtoul(param2, NULL, 0); + if (maxStack < 0) + { + PSendSysMessage("maxstack can't be a negative number."); + return false; + } + if (strncmp(param1,"grey",l) == 0) + { + auctionbot.Commands(10, ahMapID, AHB_GREY, param2); + } + else if (strncmp(param1,"white",l) == 0) + { + auctionbot.Commands(10, ahMapID, AHB_WHITE, param2); + } + else if (strncmp(param1,"green",l) == 0) + { + auctionbot.Commands(10, ahMapID, AHB_GREEN, param2); + } + else if (strncmp(param1,"blue",l) == 0) + { + auctionbot.Commands(10, ahMapID, AHB_BLUE, param2); + } + else if (strncmp(param1,"purple",l) == 0) + { + auctionbot.Commands(10, ahMapID, AHB_PURPLE, param2); + } + else if (strncmp(param1,"orange",l) == 0) + { + auctionbot.Commands(10, ahMapID, AHB_ORANGE, param2); + } + else if (strncmp(param1,"yellow",l) == 0) + { + auctionbot.Commands(10, ahMapID, AHB_YELLOW, param2); + } + else + { + PSendSysMessage("Syntax is: ahbotoptions maxstack $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $value"); + return false; + } + } + else if (strncmp(opt,"buyerprice",l) == 0) + { + char * param1 = strtok(NULL, " "); + char * param2 = strtok(NULL, " "); + if ((!ahMapIdStr) || (!param1) || (!param2)) + { + PSendSysMessage("Syntax is: ahbotoptions buyerprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue or purple) $price"); + return false; + } + if (strncmp(param1,"grey",l) == 0) + { + auctionbot.Commands(11, ahMapID, AHB_GREY, param2); + } + else if (strncmp(param1,"white",l) == 0) + { + auctionbot.Commands(11, ahMapID, AHB_WHITE, param2); + } + else if (strncmp(param1,"green",l) == 0) + { + auctionbot.Commands(11, ahMapID, AHB_GREEN, param2); + } + else if (strncmp(param1,"blue",l) == 0) + { + auctionbot.Commands(11, ahMapID, AHB_BLUE, param2); + } + else if (strncmp(param1,"purple",l) == 0) + { + auctionbot.Commands(11, ahMapID, AHB_PURPLE, param2); + } + else if (strncmp(param1,"orange",l) == 0) + { + auctionbot.Commands(11, ahMapID, AHB_ORANGE, param2); + } + else if (strncmp(param1,"yellow",l) == 0) + { + auctionbot.Commands(11, ahMapID, AHB_YELLOW, param2); + } + else + { + PSendSysMessage("Syntax is: ahbotoptions buyerprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue or purple) $price"); + return false; + } + } + else if (strncmp(opt,"bidinterval",l) == 0) + { + char * param1 = strtok(NULL, " "); + if ((!ahMapIdStr) || (!param1)) + { + PSendSysMessage("Syntax is: ahbotoptions bidinterval $ahMapID (2, 6 or 7) $interval(in minutes)"); + return false; + } + auctionbot.Commands(12, ahMapID, NULL, param1); + } + else if (strncmp(opt,"bidsperinterval",l) == 0) + { + char * param1 = strtok(NULL, " "); + if ((!ahMapIdStr) || (!param1)) + { + PSendSysMessage("Syntax is: ahbotoptions bidsperinterval $ahMapID (2, 6 or 7) $bids"); + return false; + } + auctionbot.Commands(13, ahMapID, NULL, param1); + } + else + { + PSendSysMessage("Syntax is: ahbotoptions $option $ahMapID (2, 6 or 7) $parameter"); + PSendSysMessage("Try ahbotoptions help to see a list of options."); + return false; + } + return true; +} + +//reload commands +bool ChatHandler::HandleReloadAllCommand(const char*) +{ + HandleReloadSkillFishingBaseLevelCommand(""); + + HandleReloadAllAchievementCommand(""); + HandleReloadAllAreaCommand(""); + HandleReloadAllEventAICommand(""); + HandleReloadAllLootCommand(""); + HandleReloadAllNpcCommand(""); + HandleReloadAllQuestCommand(""); + HandleReloadAllSpellCommand(""); + HandleReloadAllItemCommand(""); + HandleReloadAllLocalesCommand(""); + + HandleReloadAccessRequirementCommand(""); + HandleReloadMailLevelRewardCommand(""); + HandleReloadCommandCommand(""); + HandleReloadReservedNameCommand(""); + HandleReloadTrinityStringCommand(""); + HandleReloadGameTeleCommand(""); + + HandleReloadAutobroadcastCommand(""); + return true; +} + +bool ChatHandler::HandleReloadAllAchievementCommand(const char*) +{ + HandleReloadAchievementCriteriaDataCommand(""); + HandleReloadAchievementRewardCommand(""); + return true; +} + +bool ChatHandler::HandleReloadAllAreaCommand(const char*) +{ + //HandleReloadQuestAreaTriggersCommand(""); -- reloaded in HandleReloadAllQuestCommand + HandleReloadAreaTriggerTeleportCommand(""); + HandleReloadAreaTriggerTavernCommand(""); + HandleReloadGameGraveyardZoneCommand(""); + return true; +} + +bool ChatHandler::HandleReloadAllLootCommand(const char*) +{ + sLog.outString("Re-Loading Loot Tables..."); + LoadLootTables(); + SendGlobalGMSysMessage("DB tables `*_loot_template` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadAllNpcCommand(const char* /*args*/) +{ + HandleReloadNpcGossipCommand("a"); + HandleReloadNpcTrainerCommand("a"); + HandleReloadNpcVendorCommand("a"); + HandleReloadPointsOfInterestCommand("a"); + HandleReloadSpellClickSpellsCommand("a"); + return true; +} + +bool ChatHandler::HandleReloadAllQuestCommand(const char* /*args*/) +{ + HandleReloadQuestAreaTriggersCommand("a"); + HandleReloadQuestTemplateCommand("a"); + + sLog.outString("Re-Loading Quests Relations..."); + objmgr.LoadQuestRelations(); + SendGlobalGMSysMessage("DB tables `*_questrelation` and `*_involvedrelation` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadAllScriptsCommand(const char*) +{ + if (sWorld.IsScriptScheduled()) + { + PSendSysMessage("DB scripts used currently, please attempt reload later."); + SetSentErrorMessage(true); + return false; + } + + sLog.outString("Re-Loading Scripts..."); + HandleReloadGameObjectScriptsCommand("a"); + HandleReloadEventScriptsCommand("a"); + HandleReloadQuestEndScriptsCommand("a"); + HandleReloadQuestStartScriptsCommand("a"); + HandleReloadSpellScriptsCommand("a"); + SendGlobalGMSysMessage("DB tables `*_scripts` reloaded."); + HandleReloadDbScriptStringCommand("a"); + HandleReloadWpScriptsCommand("a"); + return true; +} + +bool ChatHandler::HandleReloadAllEventAICommand(const char*) +{ + HandleReloadEventAITextsCommand("a"); + HandleReloadEventAISummonsCommand("a"); + HandleReloadEventAIScriptsCommand("a"); + return true; +} + +bool ChatHandler::HandleReloadAllSpellCommand(const char*) +{ + HandleReloadSkillDiscoveryTemplateCommand("a"); + HandleReloadSkillExtraItemTemplateCommand("a"); + HandleReloadSpellRequiredCommand("a"); + HandleReloadSpellAreaCommand("a"); + HandleReloadSpellGroupsCommand("a"); + HandleReloadSpellLearnSpellCommand("a"); + HandleReloadSpellLinkedSpellCommand("a"); + HandleReloadSpellProcEventCommand("a"); + HandleReloadSpellBonusesCommand("a"); + HandleReloadSpellTargetPositionCommand("a"); + HandleReloadSpellThreatsCommand("a"); + HandleReloadSpellGroupStackRulesCommand("a"); + HandleReloadSpellPetAurasCommand("a"); + HandleReloadSpellDisabledCommand("a"); + return true; +} + +bool ChatHandler::HandleReloadAllItemCommand(const char*) +{ + HandleReloadPageTextsCommand("a"); + HandleReloadItemEnchantementsCommand("a"); + return true; +} + +bool ChatHandler::HandleReloadAllLocalesCommand(const char* /*args*/) +{ + HandleReloadLocalesAchievementRewardCommand("a"); + HandleReloadLocalesCreatureCommand("a"); + HandleReloadLocalesGameobjectCommand("a"); + HandleReloadLocalesItemCommand("a"); + HandleReloadLocalesNpcTextCommand("a"); + HandleReloadLocalesPageTextCommand("a"); + HandleReloadLocalesPointsOfInterestCommand("a"); + HandleReloadLocalesQuestCommand("a"); + return true; +} + +bool ChatHandler::HandleReloadConfigCommand(const char* /*args*/) +{ + sLog.outString("Re-Loading config settings..."); + sWorld.LoadConfigSettings(true); + MapManager::Instance().InitializeVisibilityDistanceInfo(); + SendGlobalGMSysMessage("World config settings reloaded."); + return true; +} + +bool ChatHandler::HandleReloadAccessRequirementCommand(const char*) +{ + sLog.outString("Re-Loading Access Requirement definitions..."); + objmgr.LoadAccessRequirements(); + SendGlobalGMSysMessage("DB table `access_requirement` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadAchievementCriteriaDataCommand(const char*) +{ + sLog.outString("Re-Loading Additional Achievement Criteria Data..."); + achievementmgr.LoadAchievementCriteriaData(); + SendGlobalGMSysMessage("DB table `achievement_criteria_data` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadAchievementRewardCommand(const char*) +{ + sLog.outString("Re-Loading Achievement Reward Data..."); + achievementmgr.LoadRewards(); + SendGlobalGMSysMessage("DB table `achievement_reward` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadAreaTriggerTavernCommand(const char*) +{ + sLog.outString("Re-Loading Tavern Area Triggers..."); + objmgr.LoadTavernAreaTriggers(); + SendGlobalGMSysMessage("DB table `areatrigger_tavern` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadAreaTriggerTeleportCommand(const char*) +{ + sLog.outString("Re-Loading AreaTrigger teleport definitions..."); + objmgr.LoadAreaTriggerTeleports(); + SendGlobalGMSysMessage("DB table `areatrigger_teleport` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadAutobroadcastCommand(const char*) +{ + sLog.outString("Re-Loading Autobroadcast..."); + sWorld.LoadAutobroadcasts(); + SendGlobalGMSysMessage("DB table `autobroadcast` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadCommandCommand(const char*) +{ + load_command_table = true; + SendGlobalGMSysMessage("DB table `command` will be reloaded at next chat command use."); + return true; +} + +bool ChatHandler::HandleReloadCreatureTemplateCommand(const char* args) +{ + if (!*args) + return false; + + uint32 entry = (uint32) atoi((char*)args); + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT difficulty_entry_1,difficulty_entry_2,difficulty_entry_3,KillCredit1,KillCredit2,modelid1,modelid2,modelid3,modelid4,name,subname,IconName,gossip_menu_id,minlevel,maxlevel,exp,faction_A,faction_H,npcflag,speed_walk,speed_run,scale,rank,mindmg,maxdmg,dmgschool,attackpower,dmg_multiplier,baseattacktime,rangeattacktime,unit_class,unit_flags,dynamicflags,family,trainer_type,trainer_spell,trainer_class,trainer_race,minrangedmg,maxrangedmg,rangedattackpower,type,type_flags,lootid,pickpocketloot,skinloot,resistance1,resistance2,resistance3,resistance4,resistance5,resistance6,spell1,spell2,spell3,spell4,spell5,spell6,spell7,spell8,PetSpellDataId,VehicleId,mingold,maxgold,AIName,MovementType,InhabitType,Health_mod,Mana_mod,Armor_mod,RacialLeader,questItem1,questItem2,questItem3,questItem4,questItem5,questItem6,movementId,RegenHealth,equipment_id,mechanic_immune_mask,flags_extra,ScriptName FROM creature_template WHERE entry = %u", entry); + if (!result) + { + PSendSysMessage(LANG_COMMAND_CREATURETEMPLATE_NOTFOUND, entry); + SetSentErrorMessage(true); + return false; + } + + CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(entry); + if (!cInfo) + { + PSendSysMessage(LANG_COMMAND_CREATURESTORAGE_NOTFOUND, entry); + SetSentErrorMessage(true); + return false; + } + + sLog.outString("Reloading creature template entry %u", entry); + + Field *fields = result->Fetch(); + + const_cast(cInfo)->DifficultyEntry[0] = fields[0].GetUInt32(); + const_cast(cInfo)->DifficultyEntry[1] = fields[1].GetUInt32(); + const_cast(cInfo)->DifficultyEntry[2] = fields[2].GetUInt32(); + const_cast(cInfo)->KillCredit[0] = fields[3].GetUInt32(); + const_cast(cInfo)->KillCredit[1] = fields[4].GetUInt32(); + const_cast(cInfo)->Modelid1 = fields[5].GetUInt32(); + const_cast(cInfo)->Modelid2 = fields[6].GetUInt32(); + const_cast(cInfo)->Modelid3 = fields[7].GetUInt32(); + const_cast(cInfo)->Modelid4 = fields[8].GetUInt32(); + size_t len = 0; + if (const char* temp = fields[9].GetString()) + { + if (cInfo->Name) + delete cInfo->Name; + len = strlen(temp)+1; + const_cast(cInfo)->Name = new char[len]; + strncpy(cInfo->Name, temp, len); + } + if (const char* temp = fields[10].GetString()) + { + if (cInfo->SubName) + delete cInfo->SubName; + len = strlen(temp)+1; + const_cast(cInfo)->SubName = new char[len]; + strncpy(cInfo->SubName, temp, len); + } + if (const char* temp = fields[11].GetString()) + { + if (cInfo->IconName) + delete cInfo->IconName; + len = strlen(temp)+1; + const_cast(cInfo)->IconName = new char[len]; + strncpy(cInfo->IconName, temp, len); + } + const_cast(cInfo)->GossipMenuId = fields[12].GetUInt32(); + const_cast(cInfo)->minlevel = fields[13].GetUInt32(); + const_cast(cInfo)->maxlevel = fields[14].GetUInt32(); + const_cast(cInfo)->expansion = fields[15].GetUInt32(); + const_cast(cInfo)->faction_A = fields[16].GetUInt32(); + const_cast(cInfo)->faction_H = fields[17].GetUInt32(); + const_cast(cInfo)->npcflag = fields[18].GetUInt32(); + const_cast(cInfo)->speed_walk = fields[19].GetFloat(); + const_cast(cInfo)->speed_run = fields[20].GetFloat(); + const_cast(cInfo)->scale = fields[21].GetFloat(); + const_cast(cInfo)->rank = fields[22].GetUInt32(); + const_cast(cInfo)->mindmg = fields[23].GetFloat(); + const_cast(cInfo)->maxdmg = fields[24].GetFloat(); + const_cast(cInfo)->dmgschool = fields[25].GetUInt32(); + const_cast(cInfo)->attackpower = fields[26].GetUInt32(); + const_cast(cInfo)->dmg_multiplier = fields[27].GetFloat(); + const_cast(cInfo)->baseattacktime = fields[28].GetUInt32(); + const_cast(cInfo)->rangeattacktime = fields[29].GetUInt32(); + const_cast(cInfo)->unit_class = fields[30].GetUInt32(); + const_cast(cInfo)->unit_flags = fields[31].GetUInt32(); + const_cast(cInfo)->dynamicflags = fields[32].GetUInt32(); + const_cast(cInfo)->family = fields[33].GetUInt32(); + const_cast(cInfo)->trainer_type = fields[34].GetUInt32(); + const_cast(cInfo)->trainer_spell = fields[35].GetUInt32(); + const_cast(cInfo)->trainer_class = fields[36].GetUInt32(); + const_cast(cInfo)->trainer_race = fields[37].GetUInt32(); + const_cast(cInfo)->minrangedmg = fields[38].GetFloat(); + const_cast(cInfo)->maxrangedmg = fields[39].GetFloat(); + const_cast(cInfo)->rangedattackpower = fields[40].GetUInt32(); + const_cast(cInfo)->type = fields[41].GetUInt32(); + const_cast(cInfo)->type_flags = fields[42].GetUInt32(); + const_cast(cInfo)->lootid = fields[43].GetUInt32(); + const_cast(cInfo)->pickpocketLootId = fields[44].GetUInt32(); + const_cast(cInfo)->SkinLootId = fields[45].GetUInt32(); + const_cast(cInfo)->resistance1 = fields[46].GetUInt32(); + const_cast(cInfo)->resistance2 = fields[47].GetUInt32(); + const_cast(cInfo)->resistance3 = fields[48].GetUInt32(); + const_cast(cInfo)->resistance4 = fields[49].GetUInt32(); + const_cast(cInfo)->resistance5 = fields[50].GetUInt32(); + const_cast(cInfo)->resistance6 = fields[51].GetUInt32(); + const_cast(cInfo)->spells[0] = fields[52].GetUInt32(); + const_cast(cInfo)->spells[1] = fields[53].GetUInt32(); + const_cast(cInfo)->spells[2] = fields[54].GetUInt32(); + const_cast(cInfo)->spells[3] = fields[55].GetUInt32(); + const_cast(cInfo)->spells[4] = fields[56].GetUInt32(); + const_cast(cInfo)->spells[5] = fields[57].GetUInt32(); + const_cast(cInfo)->spells[6] = fields[58].GetUInt32(); + const_cast(cInfo)->spells[7] = fields[59].GetUInt32(); + const_cast(cInfo)->PetSpellDataId = fields[60].GetUInt32(); + const_cast(cInfo)->VehicleId = fields[61].GetUInt32(); + const_cast(cInfo)->mingold = fields[62].GetUInt32(); + const_cast(cInfo)->maxgold = fields[63].GetUInt32(); + if (const char* temp = fields[64].GetString()) + { + if (cInfo->AIName) + delete cInfo->AIName; + len = strlen(temp)+1; + const_cast(cInfo)->AIName = new char[len]; + strncpy(const_cast(cInfo->AIName), temp, len); + } + const_cast(cInfo)->MovementType = fields[65].GetUInt32(); + const_cast(cInfo)->InhabitType = fields[66].GetUInt32(); + const_cast(cInfo)->ModHealth = fields[67].GetFloat(); + const_cast(cInfo)->ModMana = fields[68].GetFloat(); + const_cast(cInfo)->ModArmor = fields[69].GetFloat(); + const_cast(cInfo)->RacialLeader = fields[70].GetBool(); + const_cast(cInfo)->questItems[0] = fields[71].GetUInt32(); + const_cast(cInfo)->questItems[1] = fields[72].GetUInt32(); + const_cast(cInfo)->questItems[2] = fields[73].GetUInt32(); + const_cast(cInfo)->questItems[3] = fields[74].GetUInt32(); + const_cast(cInfo)->questItems[4] = fields[75].GetUInt32(); + const_cast(cInfo)->questItems[5] = fields[76].GetUInt32(); + const_cast(cInfo)->movementId = fields[77].GetUInt32(); + const_cast(cInfo)->RegenHealth = fields[78].GetBool(); + const_cast(cInfo)->equipmentId = fields[79].GetUInt32(); + const_cast(cInfo)->MechanicImmuneMask = fields[80].GetUInt32(); + const_cast(cInfo)->flags_extra = fields[81].GetUInt32(); + const_cast(cInfo)->ScriptID = objmgr.GetScriptId(fields[82].GetString()); + + objmgr.CheckCreatureTemplate(cInfo); + + SendGlobalGMSysMessage("Creature template reloaded."); + return true; +} + +bool ChatHandler::HandleReloadCreatureQuestRelationsCommand(const char*) +{ + sLog.outString("Loading Quests Relations... (`creature_questrelation`)"); + objmgr.LoadCreatureQuestRelations(); + SendGlobalGMSysMessage("DB table `creature_questrelation` (creature quest givers) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadCreatureLinkedRespawnCommand(const char * /*args*/) +{ + sLog.outString("Loading Linked Respawns... (`creature_linked_respawn`)"); + objmgr.LoadCreatureLinkedRespawn(); + SendGlobalGMSysMessage("DB table `creature_linked_respawn` (creature linked respawns) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadCreatureQuestInvRelationsCommand(const char*) +{ + sLog.outString("Loading Quests Relations... (`creature_involvedrelation`)"); + objmgr.LoadCreatureInvolvedRelations(); + SendGlobalGMSysMessage("DB table `creature_involvedrelation` (creature quest takers) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadGossipMenuCommand(const char*) +{ + sLog.outString("Re-Loading `gossip_menu` Table!"); + objmgr.LoadGossipMenu(); + SendGlobalGMSysMessage("DB table `gossip_menu` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadGossipMenuOptionCommand(const char*) +{ + sLog.outString("Re-Loading `gossip_menu_option` Table!"); + objmgr.LoadGossipMenuItems(); + SendGlobalGMSysMessage("DB table `gossip_menu_option` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadGOQuestRelationsCommand(const char*) +{ + sLog.outString("Loading Quests Relations... (`gameobject_questrelation`)"); + objmgr.LoadGameobjectQuestRelations(); + SendGlobalGMSysMessage("DB table `gameobject_questrelation` (gameobject quest givers) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadGOQuestInvRelationsCommand(const char*) +{ + sLog.outString("Loading Quests Relations... (`gameobject_involvedrelation`)"); + objmgr.LoadGameobjectInvolvedRelations(); + SendGlobalGMSysMessage("DB table `gameobject_involvedrelation` (gameobject quest takers) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadQuestAreaTriggersCommand(const char*) +{ + sLog.outString("Re-Loading Quest Area Triggers..."); + objmgr.LoadQuestAreaTriggers(); + SendGlobalGMSysMessage("DB table `areatrigger_involvedrelation` (quest area triggers) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadQuestTemplateCommand(const char*) +{ + sLog.outString("Re-Loading Quest Templates..."); + objmgr.LoadQuests(); + SendGlobalGMSysMessage("DB table `quest_template` (quest definitions) reloaded."); + + /// dependent also from `gameobject` but this table not reloaded anyway + sLog.outString("Re-Loading GameObjects for quests..."); + objmgr.LoadGameObjectForQuests(); + SendGlobalGMSysMessage("Data GameObjects for quests reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesCreatureCommand(const char*) +{ + sLog.outString("Re-Loading Loot Tables... (`creature_loot_template`)"); + LoadLootTemplates_Creature(); + LootTemplates_Creature.CheckLootRefs(); + SendGlobalGMSysMessage("DB table `creature_loot_template` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesDisenchantCommand(const char*) +{ + sLog.outString("Re-Loading Loot Tables... (`disenchant_loot_template`)"); + LoadLootTemplates_Disenchant(); + LootTemplates_Disenchant.CheckLootRefs(); + SendGlobalGMSysMessage("DB table `disenchant_loot_template` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesFishingCommand(const char*) +{ + sLog.outString("Re-Loading Loot Tables... (`fishing_loot_template`)"); + LoadLootTemplates_Fishing(); + LootTemplates_Fishing.CheckLootRefs(); + SendGlobalGMSysMessage("DB table `fishing_loot_template` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesGameobjectCommand(const char*) +{ + sLog.outString("Re-Loading Loot Tables... (`gameobject_loot_template`)"); + LoadLootTemplates_Gameobject(); + LootTemplates_Gameobject.CheckLootRefs(); + SendGlobalGMSysMessage("DB table `gameobject_loot_template` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesItemCommand(const char*) +{ + sLog.outString("Re-Loading Loot Tables... (`item_loot_template`)"); + LoadLootTemplates_Item(); + LootTemplates_Item.CheckLootRefs(); + SendGlobalGMSysMessage("DB table `item_loot_template` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesMillingCommand(const char*) +{ + sLog.outString("Re-Loading Loot Tables... (`milling_loot_template`)"); + LoadLootTemplates_Milling(); + LootTemplates_Milling.CheckLootRefs(); + SendGlobalGMSysMessage("DB table `milling_loot_template` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesPickpocketingCommand(const char*) +{ + sLog.outString("Re-Loading Loot Tables... (`pickpocketing_loot_template`)"); + LoadLootTemplates_Pickpocketing(); + LootTemplates_Pickpocketing.CheckLootRefs(); + SendGlobalGMSysMessage("DB table `pickpocketing_loot_template` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesProspectingCommand(const char*) +{ + sLog.outString("Re-Loading Loot Tables... (`prospecting_loot_template`)"); + LoadLootTemplates_Prospecting(); + LootTemplates_Prospecting.CheckLootRefs(); + SendGlobalGMSysMessage("DB table `prospecting_loot_template` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesMailCommand(const char*) +{ + sLog.outString("Re-Loading Loot Tables... (`mail_loot_template`)"); + LoadLootTemplates_Mail(); + LootTemplates_Mail.CheckLootRefs(); + SendGlobalGMSysMessage("DB table `mail_loot_template` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesReferenceCommand(const char*) +{ + sLog.outString("Re-Loading Loot Tables... (`reference_loot_template`)"); + LoadLootTemplates_Reference(); + SendGlobalGMSysMessage("DB table `reference_loot_template` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesSkinningCommand(const char*) +{ + sLog.outString("Re-Loading Loot Tables... (`skinning_loot_template`)"); + LoadLootTemplates_Skinning(); + LootTemplates_Skinning.CheckLootRefs(); + SendGlobalGMSysMessage("DB table `skinning_loot_template` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadLootTemplatesSpellCommand(const char*) +{ + sLog.outString("Re-Loading Loot Tables... (`spell_loot_template`)"); + LoadLootTemplates_Spell(); + LootTemplates_Spell.CheckLootRefs(); + SendGlobalGMSysMessage("DB table `spell_loot_template` reloaded."); + sConditionMgr.LoadConditions(true); + return true; +} + +bool ChatHandler::HandleReloadTrinityStringCommand(const char*) +{ + sLog.outString("Re-Loading trinity_string Table!"); + objmgr.LoadTrinityStrings(); + SendGlobalGMSysMessage("DB table `trinity_string` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadNpcGossipCommand(const char*) +{ + sLog.outString("Re-Loading `npc_gossip` Table!"); + objmgr.LoadNpcTextId(); + SendGlobalGMSysMessage("DB table `npc_gossip` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadNpcTrainerCommand(const char*) +{ + sLog.outString("Re-Loading `npc_trainer` Table!"); + objmgr.LoadTrainerSpell(); + SendGlobalGMSysMessage("DB table `npc_trainer` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadNpcVendorCommand(const char*) +{ + sLog.outString("Re-Loading `npc_vendor` Table!"); + objmgr.LoadVendors(); + SendGlobalGMSysMessage("DB table `npc_vendor` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadPointsOfInterestCommand(const char*) +{ + sLog.outString("Re-Loading `points_of_interest` Table!"); + objmgr.LoadPointsOfInterest(); + SendGlobalGMSysMessage("DB table `points_of_interest` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellClickSpellsCommand(const char*) +{ + sLog.outString("Re-Loading `npc_spellclick_spells` Table!"); + objmgr.LoadNPCSpellClickSpells(); + SendGlobalGMSysMessage("DB table `npc_spellclick_spells` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadReservedNameCommand(const char*) +{ + sLog.outString("Loading ReservedNames... (`reserved_name`)"); + objmgr.LoadReservedPlayersNames(); + SendGlobalGMSysMessage("DB table `reserved_name` (player reserved names) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSkillDiscoveryTemplateCommand(const char* /*args*/) +{ + sLog.outString("Re-Loading Skill Discovery Table..."); + LoadSkillDiscoveryTable(); + SendGlobalGMSysMessage("DB table `skill_discovery_template` (recipes discovered at crafting) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSkillExtraItemTemplateCommand(const char* /*args*/) +{ + sLog.outString("Re-Loading Skill Extra Item Table..."); + LoadSkillExtraItemTable(); + SendGlobalGMSysMessage("DB table `skill_extra_item_template` (extra item creation when crafting) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSkillFishingBaseLevelCommand(const char* /*args*/) +{ + sLog.outString("Re-Loading Skill Fishing base level requirements..."); + objmgr.LoadFishingBaseSkillLevel(); + SendGlobalGMSysMessage("DB table `skill_fishing_base_level` (fishing base level for zone/subzone) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellAreaCommand(const char*) +{ + sLog.outString("Re-Loading SpellArea Data..."); + spellmgr.LoadSpellAreas(); + SendGlobalGMSysMessage("DB table `spell_area` (spell dependences from area/quest/auras state) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellRequiredCommand(const char*) +{ + sLog.outString("Re-Loading Spell Required Data... "); + spellmgr.LoadSpellRequired(); + SendGlobalGMSysMessage("DB table `spell_required` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellGroupsCommand(const char*) +{ + sLog.outString("Re-Loading Spell Groups..."); + spellmgr.LoadSpellGroups(); + SendGlobalGMSysMessage("DB table `spell_group` (spell groups) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellLearnSpellCommand(const char*) +{ + sLog.outString("Re-Loading Spell Learn Spells..."); + spellmgr.LoadSpellLearnSpells(); + SendGlobalGMSysMessage("DB table `spell_learn_spell` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellLinkedSpellCommand(const char*) +{ + sLog.outString("Re-Loading Spell Linked Spells..."); + spellmgr.LoadSpellLinked(); + SendGlobalGMSysMessage("DB table `spell_linked_spell` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellProcEventCommand(const char*) +{ + sLog.outString("Re-Loading Spell Proc Event conditions..."); + spellmgr.LoadSpellProcEvents(); + SendGlobalGMSysMessage("DB table `spell_proc_event` (spell proc trigger requirements) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellBonusesCommand(const char*) +{ + sLog.outString("Re-Loading Spell Bonus Data..."); + spellmgr.LoadSpellBonusess(); + SendGlobalGMSysMessage("DB table `spell_bonus_data` (spell damage/healing coefficients) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellTargetPositionCommand(const char*) +{ + sLog.outString("Re-Loading Spell target coordinates..."); + spellmgr.LoadSpellTargetPositions(); + SendGlobalGMSysMessage("DB table `spell_target_position` (destination coordinates for spell targets) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellThreatsCommand(const char*) +{ + sLog.outString("Re-Loading Aggro Spells Definitions..."); + spellmgr.LoadSpellThreats(); + SendGlobalGMSysMessage("DB table `spell_threat` (spell aggro definitions) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellGroupStackRulesCommand(const char*) +{ + sLog.outString("Re-Loading Spell Group Stack Rules..."); + spellmgr.LoadSpellGroupStackRules(); + SendGlobalGMSysMessage("DB table `spell_group_stack_rules` (spell stacking definitions) reloaded."); + return true; +} + +bool ChatHandler::HandleReloadSpellPetAurasCommand(const char*) +{ + sLog.outString("Re-Loading Spell pet auras..."); + spellmgr.LoadSpellPetAuras(); + SendGlobalGMSysMessage("DB table `spell_pet_auras` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadPageTextsCommand(const char*) +{ + sLog.outString("Re-Loading Page Texts..."); + objmgr.LoadPageTexts(); + SendGlobalGMSysMessage("DB table `page_texts` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadItemEnchantementsCommand(const char*) +{ + sLog.outString("Re-Loading Item Random Enchantments Table..."); + LoadRandomEnchantmentsTable(); + SendGlobalGMSysMessage("DB table `item_enchantment_template` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadGameObjectScriptsCommand(const char* arg) +{ + if (sWorld.IsScriptScheduled()) + { + SendSysMessage("DB scripts used currently, please attempt reload later."); + SetSentErrorMessage(true); + return false; + } + + if (*arg != 'a') + sLog.outString("Re-Loading Scripts from `gameobject_scripts`..."); + + objmgr.LoadGameObjectScripts(); + + if (*arg != 'a') + SendGlobalGMSysMessage("DB table `gameobject_scripts` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadEventScriptsCommand(const char* arg) +{ + if (sWorld.IsScriptScheduled()) + { + SendSysMessage("DB scripts used currently, please attempt reload later."); + SetSentErrorMessage(true); + return false; + } + + if (*arg != 'a') + sLog.outString("Re-Loading Scripts from `event_scripts`..."); + + objmgr.LoadEventScripts(); + + if (*arg != 'a') + SendGlobalGMSysMessage("DB table `event_scripts` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadWpScriptsCommand(const char* arg) +{ + if (sWorld.IsScriptScheduled()) + { + SendSysMessage("DB scripts used currently, please attempt reload later."); + SetSentErrorMessage(true); + return false; + } + + if (*arg != 'a') + sLog.outString("Re-Loading Scripts from `waypoint_scripts`..."); + + objmgr.LoadWaypointScripts(); + + if (*arg != 'a') + SendGlobalGMSysMessage("DB table `waypoint_scripts` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadEventAITextsCommand(const char* /*args*/) +{ + + sLog.outString("Re-Loading Texts from `creature_ai_texts`..."); + CreatureEAI_Mgr.LoadCreatureEventAI_Texts(); + SendGlobalGMSysMessage("DB table `creature_ai_texts` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadEventAISummonsCommand(const char* /*args*/) +{ + sLog.outString("Re-Loading Summons from `creature_ai_summons`..."); + CreatureEAI_Mgr.LoadCreatureEventAI_Summons(); + SendGlobalGMSysMessage("DB table `creature_ai_summons` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadEventAIScriptsCommand(const char* /*args*/) +{ + sLog.outString("Re-Loading Scripts from `creature_ai_scripts`..."); + CreatureEAI_Mgr.LoadCreatureEventAI_Scripts(); + SendGlobalGMSysMessage("DB table `creature_ai_scripts` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadQuestEndScriptsCommand(const char* arg) +{ + if (sWorld.IsScriptScheduled()) + { + SendSysMessage("DB scripts used currently, please attempt reload later."); + SetSentErrorMessage(true); + return false; + } + + if (*arg != 'a') + sLog.outString("Re-Loading Scripts from `quest_end_scripts`..."); + + objmgr.LoadQuestEndScripts(); + + if (*arg != 'a') + SendGlobalGMSysMessage("DB table `quest_end_scripts` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadQuestStartScriptsCommand(const char* arg) +{ + if (sWorld.IsScriptScheduled()) + { + SendSysMessage("DB scripts used currently, please attempt reload later."); + SetSentErrorMessage(true); + return false; + } + + if (*arg != 'a') + sLog.outString("Re-Loading Scripts from `quest_start_scripts`..."); + + objmgr.LoadQuestStartScripts(); + + if (*arg != 'a') + SendGlobalGMSysMessage("DB table `quest_start_scripts` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadSpellScriptsCommand(const char* arg) +{ + if (sWorld.IsScriptScheduled()) + { + SendSysMessage("DB scripts used currently, please attempt reload later."); + SetSentErrorMessage(true); + return false; + } + + if (*arg != 'a') + sLog.outString("Re-Loading Scripts from `spell_scripts`..."); + + objmgr.LoadSpellScripts(); + + if (*arg != 'a') + SendGlobalGMSysMessage("DB table `spell_scripts` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadDbScriptStringCommand(const char* /*arg*/) +{ + sLog.outString("Re-Loading Script strings from `db_script_string`..."); + objmgr.LoadDbScriptStrings(); + SendGlobalGMSysMessage("DB table `db_script_string` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadGameGraveyardZoneCommand(const char* /*arg*/) +{ + sLog.outString("Re-Loading Graveyard-zone links..."); + + objmgr.LoadGraveyardZones(); + + SendGlobalGMSysMessage("DB table `game_graveyard_zone` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadGameTeleCommand(const char* /*arg*/) +{ + sLog.outString("Re-Loading Game Tele coordinates..."); + + objmgr.LoadGameTele(); + + SendGlobalGMSysMessage("DB table `game_tele` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadSpellDisabledCommand(const char* /*arg*/) +{ + sLog.outString("Re-Loading spell disabled table..."); + + objmgr.LoadSpellDisabledEntrys(); + + SendGlobalGMSysMessage("DB table `spell_disabled` reloaded."); + + return true; +} + +bool ChatHandler::HandleReloadLocalesAchievementRewardCommand(const char*) +{ + sLog.outString("Re-Loading Locales Achievement Reward Data..."); + achievementmgr.LoadRewardLocales(); + SendGlobalGMSysMessage("DB table `locales_achievement_reward` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLocalesCreatureCommand(const char* /*arg*/) +{ + sLog.outString("Re-Loading Locales Creature ..."); + objmgr.LoadCreatureLocales(); + SendGlobalGMSysMessage("DB table `locales_creature` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLocalesGameobjectCommand(const char* /*arg*/) +{ + sLog.outString("Re-Loading Locales Gameobject ... "); + objmgr.LoadGameObjectLocales(); + SendGlobalGMSysMessage("DB table `locales_gameobject` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLocalesItemCommand(const char* /*arg*/) +{ + sLog.outString("Re-Loading Locales Item ... "); + objmgr.LoadItemLocales(); + SendGlobalGMSysMessage("DB table `locales_item` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLocalesNpcTextCommand(const char* /*arg*/) +{ + sLog.outString("Re-Loading Locales NPC Text ... "); + objmgr.LoadNpcTextLocales(); + SendGlobalGMSysMessage("DB table `locales_npc_text` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLocalesPageTextCommand(const char* /*arg*/) +{ + sLog.outString("Re-Loading Locales Page Text ... "); + objmgr.LoadPageTextLocales(); + SendGlobalGMSysMessage("DB table `locales_page_text` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLocalesPointsOfInterestCommand(const char* /*arg*/) +{ + sLog.outString("Re-Loading Locales Points Of Interest ... "); + objmgr.LoadPointOfInterestLocales(); + SendGlobalGMSysMessage("DB table `locales_points_of_interest` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLocalesQuestCommand(const char* /*arg*/) +{ + sLog.outString("Re-Loading Locales Quest ... "); + objmgr.LoadQuestLocales(); + SendGlobalGMSysMessage("DB table `locales_quest` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadMailLevelRewardCommand(const char* /*arg*/) +{ + sLog.outString("Re-Loading Player level dependent mail rewards..."); + objmgr.LoadMailLevelRewards(); + SendGlobalGMSysMessage("DB table `mail_level_reward` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadAuctionsCommand(const char * /*args*/) +{ + ///- Reload dynamic data tables from the database + sLog.outString("Re-Loading Auctions..."); + auctionmgr.LoadAuctionItems(); + auctionmgr.LoadAuctions(); + SendGlobalGMSysMessage("Auctions reloaded."); + return true; +} + +bool ChatHandler::HandleReloadConditions(const char* args) +{ + sLog.outString("Re-Loading Conditions..."); + sConditionMgr.LoadConditions(true); + SendGlobalGMSysMessage("Conditions reloaded."); + return true; +} + +bool ChatHandler::HandleAccountSetGmLevelCommand(const char *args) +{ + if (!*args) + return false; + + std::string targetAccountName; + uint32 targetAccountId = 0; + uint32 targetSecurity = 0; + uint32 gm = 0; + char* arg1 = strtok((char*)args, " "); + char* arg2 = strtok(NULL, " "); + char* arg3 = strtok(NULL, " "); + bool isAccountNameGiven = true; + + if (arg1 && !arg3) + { + if (!getSelectedPlayer()) + return false; + isAccountNameGiven = false; + } + + // Check for second parameter + if (!isAccountNameGiven && !arg2) + return false; + + // Check for account + if (isAccountNameGiven) + { + targetAccountName = arg1; + if (!AccountMgr::normalizeString(targetAccountName)) + { + PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,targetAccountName.c_str()); + SetSentErrorMessage(true); + return false; + } + } + + // Check for invalid specified GM level. + gm = (isAccountNameGiven) ? atoi(arg2) : atoi(arg1); + if (gm < SEC_PLAYER) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + // m_session == NULL only for console + targetAccountId = (isAccountNameGiven) ? accmgr.GetId(targetAccountName) : getSelectedPlayer()->GetSession()->GetAccountId(); + int32 gmRealmID = (isAccountNameGiven) ? atoi(arg3) : atoi(arg2); + uint32 plSecurity = m_session ? accmgr.GetSecurity(m_session->GetAccountId(), gmRealmID) : SEC_CONSOLE; + + // can set security level only for target with less security and to less security that we have + // This is also reject self apply in fact + targetSecurity = accmgr.GetSecurity(targetAccountId, gmRealmID); + if (targetSecurity >= plSecurity || gm >= plSecurity) + { + SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); + SetSentErrorMessage(true); + return false; + } + + // Check and abort if the target gm has a higher rank on one of the realms and the new realm is -1 + if (gmRealmID == -1) + { + QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT * FROM account_access WHERE id = '%u' AND gmlevel > '%d'", targetAccountId, gm); + if (result) + { + SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); + SetSentErrorMessage(true); + return false; + } + } + + // Check if provided realmID has a negative value other than -1 + if (gmRealmID < -1) + { + SendSysMessage(LANG_INVALID_REALMID); + SetSentErrorMessage(true); + return false; + } + + // If gmRealmID is -1, delete all values for the account id, else, insert values for the specific realmID + if (gmRealmID == -1) + LoginDatabase.PExecute("DELETE FROM account_access WHERE id = '%u'", targetAccountId); + else + LoginDatabase.PExecute("DELETE FROM account_access WHERE id = '%u' AND (RealmID = '%d' OR RealmID = '-1')", targetAccountId, realmID); + + if (gm != 0) + LoginDatabase.PExecute("INSERT INTO account_access VALUES ('%u','%d','%d')", targetAccountId, gm, realmID); + PSendSysMessage(LANG_YOU_CHANGE_SECURITY, targetAccountName.c_str(), gm); + return true; +} + +/// Set password for account +bool ChatHandler::HandleAccountSetPasswordCommand(const char *args) +{ + if (!*args) + return false; + + ///- Get the command line arguments + char *szAccount = strtok ((char*)args," "); + char *szPassword1 = strtok (NULL," "); + char *szPassword2 = strtok (NULL," "); + + if (!szAccount||!szPassword1 || !szPassword2) + return false; + + std::string account_name = szAccount; + if (!AccountMgr::normalizeString(account_name)) + { + PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); + SetSentErrorMessage(true); + return false; + } + + uint32 targetAccountId = accmgr.GetId(account_name); + if (!targetAccountId) + { + PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); + SetSentErrorMessage(true); + return false; + } + + /// can set password only for target with less security + /// This is also reject self apply in fact + if (HasLowerSecurityAccount (NULL,targetAccountId,true)) + return false; + + if (strcmp(szPassword1,szPassword2)) + { + SendSysMessage (LANG_NEW_PASSWORDS_NOT_MATCH); + SetSentErrorMessage (true); + return false; + } + + AccountOpResult result = accmgr.ChangePassword(targetAccountId, szPassword1); + + switch (result) + { + case AOR_OK: + SendSysMessage(LANG_COMMAND_PASSWORD); + break; + case AOR_NAME_NOT_EXIST: + PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); + SetSentErrorMessage(true); + return false; + case AOR_PASS_TOO_LONG: + SendSysMessage(LANG_PASSWORD_TOO_LONG); + SetSentErrorMessage(true); + return false; + default: + SendSysMessage(LANG_COMMAND_NOTCHANGEPASSWORD); + SetSentErrorMessage(true); + return false; + } + + return true; +} + +bool ChatHandler::HandleMaxSkillCommand(const char* /*args*/) +{ + Player* SelectedPlayer = getSelectedPlayer(); + if (!SelectedPlayer) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // each skills that have max skill value dependent from level seted to current level max skill value + SelectedPlayer->UpdateSkillsToMaxSkillsForLevel(); + return true; +} + +bool ChatHandler::HandleSetSkillCommand(const char *args) +{ + // number or [name] Shift-click form |color|Hskill:skill_id|h[name]|h|r + char* skill_p = extractKeyFromLink((char*)args,"Hskill"); + if (!skill_p) + return false; + + char *level_p = strtok (NULL, " "); + + if (!level_p) + return false; + + char *max_p = strtok (NULL, " "); + + int32 skill = atoi(skill_p); + if (skill <= 0) + { + PSendSysMessage(LANG_INVALID_SKILL_ID, skill); + SetSentErrorMessage(true); + return false; + } + + int32 level = atol (level_p); + + Player * target = getSelectedPlayer(); + if (!target) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + SkillLineEntry const* sl = sSkillLineStore.LookupEntry(skill); + if (!sl) + { + PSendSysMessage(LANG_INVALID_SKILL_ID, skill); + SetSentErrorMessage(true); + return false; + } + + std::string tNameLink = GetNameLink(target); + + if (!target->GetSkillValue(skill)) + { + PSendSysMessage(LANG_SET_SKILL_ERROR, tNameLink.c_str(), skill, sl->name[GetSessionDbcLocale()]); + SetSentErrorMessage(true); + return false; + } + + int32 max = max_p ? atol (max_p) : target->GetPureMaxSkillValue(skill); + + if (level <= 0 || level > max || max <= 0) + return false; + + target->SetSkill(skill, target->GetSkillStep(skill), level, max); + PSendSysMessage(LANG_SET_SKILL, skill, sl->name[GetSessionDbcLocale()], tNameLink.c_str(), level, max); + + return true; +} + +bool ChatHandler::HandleUnLearnCommand(const char *args) +{ + if (!*args) + return false; + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r + uint32 spell_id = extractSpellIdFromLink((char*)args); + if (!spell_id) + return false; + + char const* allStr = strtok(NULL," "); + bool allRanks = allStr ? (strncmp(allStr, "all", strlen(allStr)) == 0) : false; + + Player* target = getSelectedPlayer(); + if (!target) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if (allRanks) + spell_id = spellmgr.GetFirstSpellInChain (spell_id); + + if (target->HasSpell(spell_id)) + target->removeSpell(spell_id,false,!allRanks); + else + SendSysMessage(LANG_FORGET_SPELL); + + if (GetTalentSpellCost(spell_id)) + target->SendTalentsInfoData(false); + + return true; +} + +bool ChatHandler::HandleCooldownCommand(const char *args) +{ + Player* target = getSelectedPlayer(); + if (!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + std::string tNameLink = GetNameLink(target); + + if (!*args) + { + target->RemoveAllSpellCooldown(); + PSendSysMessage(LANG_REMOVEALL_COOLDOWN, tNameLink.c_str()); + } + else + { + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spell_id = extractSpellIdFromLink((char*)args); + if (!spell_id) + return false; + + if (!sSpellStore.LookupEntry(spell_id)) + { + PSendSysMessage(LANG_UNKNOWN_SPELL, target == m_session->GetPlayer() ? GetTrinityString(LANG_YOU) : tNameLink.c_str()); + SetSentErrorMessage(true); + return false; + } + + target->RemoveSpellCooldown(spell_id,true); + PSendSysMessage(LANG_REMOVE_COOLDOWN, spell_id, target == m_session->GetPlayer() ? GetTrinityString(LANG_YOU) : tNameLink.c_str()); + } + return true; +} + +bool ChatHandler::HandleLearnAllCommand(const char* /*args*/) +{ + static const char *allSpellList[] = + { + "3365", + "6233", + "6247", + "6246", + "6477", + "6478", + "22810", + "8386", + "21651", + "21652", + "522", + "7266", + "8597", + "2479", + "22027", + "6603", + "5019", + "133", + "168", + "227", + "5009", + "9078", + "668", + "203", + "20599", + "20600", + "81", + "20597", + "20598", + "20864", + "1459", + "5504", + "587", + "5143", + "118", + "5505", + "597", + "604", + "1449", + "1460", + "2855", + "1008", + "475", + "5506", + "1463", + "12824", + "8437", + "990", + "5145", + "8450", + "1461", + "759", + "8494", + "8455", + "8438", + "6127", + "8416", + "6129", + "8451", + "8495", + "8439", + "3552", + "8417", + "10138", + "12825", + "10169", + "10156", + "10144", + "10191", + "10201", + "10211", + "10053", + "10173", + "10139", + "10145", + "10192", + "10170", + "10202", + "10054", + "10174", + "10193", + "12826", + "2136", + "143", + "145", + "2137", + "2120", + "3140", + "543", + "2138", + "2948", + "8400", + "2121", + "8444", + "8412", + "8457", + "8401", + "8422", + "8445", + "8402", + "8413", + "8458", + "8423", + "8446", + "10148", + "10197", + "10205", + "10149", + "10215", + "10223", + "10206", + "10199", + "10150", + "10216", + "10207", + "10225", + "10151", + "116", + "205", + "7300", + "122", + "837", + "10", + "7301", + "7322", + "6143", + "120", + "865", + "8406", + "6141", + "7302", + "8461", + "8407", + "8492", + "8427", + "8408", + "6131", + "7320", + "10159", + "8462", + "10185", + "10179", + "10160", + "10180", + "10219", + "10186", + "10177", + "10230", + "10181", + "10161", + "10187", + "10220", + "2018", + "2663", + "12260", + "2660", + "3115", + "3326", + "2665", + "3116", + "2738", + "3293", + "2661", + "3319", + "2662", + "9983", + "8880", + "2737", + "2739", + "7408", + "3320", + "2666", + "3323", + "3324", + "3294", + "22723", + "23219", + "23220", + "23221", + "23228", + "23338", + "10788", + "10790", + "5611", + "5016", + "5609", + "2060", + "10963", + "10964", + "10965", + "22593", + "22594", + "596", + "996", + "499", + "768", + "17002", + "1448", + "1082", + "16979", + "1079", + "5215", + "20484", + "5221", + "15590", + "17007", + "6795", + "6807", + "5487", + "1446", + "1066", + "5421", + "3139", + "779", + "6811", + "6808", + "1445", + "5216", + "1737", + "5222", + "5217", + "1432", + "6812", + "9492", + "5210", + "3030", + "1441", + "783", + "6801", + "20739", + "8944", + "9491", + "22569", + "5226", + "6786", + "1433", + "8973", + "1828", + "9495", + "9006", + "6794", + "8993", + "5203", + "16914", + "6784", + "9635", + "22830", + "20722", + "9748", + "6790", + "9753", + "9493", + "9752", + "9831", + "9825", + "9822", + "5204", + "5401", + "22831", + "6793", + "9845", + "17401", + "9882", + "9868", + "20749", + "9893", + "9899", + "9895", + "9832", + "9902", + "9909", + "22832", + "9828", + "9851", + "9883", + "9869", + "17406", + "17402", + "9914", + "20750", + "9897", + "9848", + "3127", + "107", + "204", + "9116", + "2457", + "78", + "18848", + "331", + "403", + "2098", + "1752", + "11278", + "11288", + "11284", + "6461", + "2344", + "2345", + "6463", + "2346", + "2352", + "775", + "1434", + "1612", + "71", + "2468", + "2458", + "2467", + "7164", + "7178", + "7367", + "7376", + "7381", + "21156", + "5209", + "3029", + "5201", + "9849", + "9850", + "20719", + "22568", + "22827", + "22828", + "22829", + "6809", + "8972", + "9005", + "9823", + "9827", + "6783", + "9913", + "6785", + "6787", + "9866", + "9867", + "9894", + "9896", + "6800", + "8992", + "9829", + "9830", + "780", + "769", + "6749", + "6750", + "9755", + "9754", + "9908", + "20745", + "20742", + "20747", + "20748", + "9746", + "9745", + "9880", + "9881", + "5391", + "842", + "3025", + "3031", + "3287", + "3329", + "1945", + "3559", + "4933", + "4934", + "4935", + "4936", + "5142", + "5390", + "5392", + "5404", + "5420", + "6405", + "7293", + "7965", + "8041", + "8153", + "9033", + "9034", + //"9036", problems with ghost state + "16421", + "21653", + "22660", + "5225", + "9846", + "2426", + "5916", + "6634", + //"6718", phasing stealth, annoying for learn all case. + "6719", + "8822", + "9591", + "9590", + "10032", + "17746", + "17747", + "8203", + "11392", + "12495", + "16380", + "23452", + "4079", + "4996", + "4997", + "4998", + "4999", + "5000", + "6348", + "6349", + "6481", + "6482", + "6483", + "6484", + "11362", + "11410", + "11409", + "12510", + "12509", + "12885", + "13142", + "21463", + "23460", + "11421", + "11416", + "11418", + "1851", + "10059", + "11423", + "11417", + "11422", + "11419", + "11424", + "11420", + "27", + "31", + "33", + "34", + "35", + "15125", + "21127", + "22950", + "1180", + "201", + "12593", + "16770", + "6057", + "12051", + "18468", + "12606", + "12605", + "18466", + "12502", + "12043", + "15060", + "12042", + "12341", + "12848", + "12344", + "12353", + "18460", + "11366", + "12350", + "12352", + "13043", + "11368", + "11113", + "12400", + "11129", + "16766", + "12573", + "12580", + "12472", + "12953", + "12488", + "11189", + "12985", + "12519", + "16758", + "11958", + "12490", + "11426", + "3565", + "3562", + "18960", + "3567", + "3561", + "3566", + "3563", + "1953", + "2139", + "12505", + "13018", + "12522", + "12523", + "5146", + "5144", + "5148", + "8419", + "8418", + "10213", + "10212", + "10157", + "12524", + "13019", + "12525", + "13020", + "12526", + "13021", + "18809", + "13031", + "13032", + "13033", + "4036", + "3920", + "3919", + "3918", + "7430", + "3922", + "3923", + "7411", + "7418", + "7421", + "13262", + "7412", + "7415", + "7413", + "7416", + "13920", + "13921", + "7745", + "7779", + "7428", + "7457", + "7857", + "7748", + "7426", + "13421", + "7454", + "13378", + "7788", + "14807", + "14293", + "7795", + "6296", + "20608", + "755", + "444", + "427", + "428", + "442", + "447", + "3578", + "3581", + "19027", + "3580", + "665", + "3579", + "3577", + "6755", + "3576", + "2575", + "2577", + "2578", + "2579", + "2580", + "2656", + "2657", + "2576", + "3564", + "10248", + "8388", + "2659", + "14891", + "3308", + "3307", + "10097", + "2658", + "3569", + "16153", + "3304", + "10098", + "4037", + "3929", + "3931", + "3926", + "3924", + "3930", + "3977", + "3925", + "136", + "228", + "5487", + "43", + "202", + "0" + }; + + int loop = 0; + while (strcmp(allSpellList[loop], "0")) + { + uint32 spell = atol((char*)allSpellList[loop++]); + + if (m_session->GetPlayer()->HasSpell(spell)) + continue; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); + if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) + { + PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); + continue; + } + + m_session->GetPlayer()->learnSpell(spell, false); + } + + SendSysMessage(LANG_COMMAND_LEARN_MANY_SPELLS); + + return true; +} + +bool ChatHandler::HandleLearnAllGMCommand(const char* /*args*/) +{ + static const char *gmSpellList[] = + { + "24347", // Become A Fish, No Breath Bar + "35132", // Visual Boom + "38488", // Attack 4000-8000 AOE + "38795", // Attack 2000 AOE + Slow Down 90% + "15712", // Attack 200 + "1852", // GM Spell Silence + "31899", // Kill + "31924", // Kill + "29878", // Kill My Self + "26644", // More Kill + + "28550", //Invisible 24 + "23452", //Invisible + Target + "0" + }; + + uint16 gmSpellIter = 0; + while (strcmp(gmSpellList[gmSpellIter], "0")) + { + uint32 spell = atol((char*)gmSpellList[gmSpellIter++]); + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); + if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) + { + PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); + continue; + } + + m_session->GetPlayer()->learnSpell(spell, false); + } + + SendSysMessage(LANG_LEARNING_GM_SKILLS); + return true; +} + +bool ChatHandler::HandleLearnAllMyClassCommand(const char* /*args*/) +{ + HandleLearnAllMySpellsCommand(""); + HandleLearnAllMyTalentsCommand(""); + return true; +} + +bool ChatHandler::HandleLearnAllMySpellsCommand(const char* /*args*/) +{ + ChrClassesEntry const* clsEntry = sChrClassesStore.LookupEntry(m_session->GetPlayer()->getClass()); + if (!clsEntry) + return true; + uint32 family = clsEntry->spellfamily; + + for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(i); + if (!spellInfo) + continue; + + // skip server-side/triggered spells + if (spellInfo->spellLevel == 0) + continue; + + // skip wrong class/race skills + if (!m_session->GetPlayer()->IsSpellFitByClassAndRace(spellInfo->Id)) + continue; + + // skip other spell families + if (spellInfo->SpellFamilyName != family) + continue; + + // skip spells with first rank learned as talent (and all talents then also) + uint32 first_rank = spellmgr.GetFirstSpellInChain(spellInfo->Id); + if (GetTalentSpellCost(first_rank) > 0) + continue; + + // skip broken spells + if (!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) + continue; + + m_session->GetPlayer()->learnSpell(i, false); + } + + SendSysMessage(LANG_COMMAND_LEARN_CLASS_SPELLS); + return true; +} + +bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/) +{ + Player* player = m_session->GetPlayer(); + uint32 classMask = player->getClassMask(); + + for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i) + { + TalentEntry const *talentInfo = sTalentStore.LookupEntry(i); + if (!talentInfo) + continue; + + TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab); + if (!talentTabInfo) + continue; + + if ((classMask & talentTabInfo->ClassMask) == 0) + continue; + + // search highest talent rank + uint32 spellId = 0; + for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank) + { + if (talentInfo->RankID[rank] != 0) + { + spellId = talentInfo->RankID[rank]; + break; + } + } + + if (!spellId) // ??? none spells in talent + continue; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); + if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) + continue; + + // learn highest rank of talent and learn all non-talent spell ranks (recursive by tree) + player->learnSpellHighRank(spellId); + player->AddTalent(spellId, player->GetActiveSpec(), true); + } + + player->SetFreeTalentPoints(0); + + SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS); + return true; +} + +bool ChatHandler::HandleLearnAllMyPetTalentsCommand(const char* /*args*/) +{ + Player* player = m_session->GetPlayer(); + + Pet* pet = player->GetPet(); + if (!pet) + { + SendSysMessage(LANG_NO_PET_FOUND); + SetSentErrorMessage(true); + return false; + } + + CreatureInfo const *ci = pet->GetCreatureInfo(); + if (!ci) + { + SendSysMessage(LANG_WRONG_PET_TYPE); + SetSentErrorMessage(true); + return false; + } + + CreatureFamilyEntry const *pet_family = sCreatureFamilyStore.LookupEntry(ci->family); + if (!pet_family) + { + SendSysMessage(LANG_WRONG_PET_TYPE); + SetSentErrorMessage(true); + return false; + } + + if (pet_family->petTalentType < 0) // not hunter pet + { + SendSysMessage(LANG_WRONG_PET_TYPE); + SetSentErrorMessage(true); + return false; + } + + for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i) + { + TalentEntry const *talentInfo = sTalentStore.LookupEntry(i); + if (!talentInfo) + continue; + + TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab); + if (!talentTabInfo) + continue; + + // prevent learn talent for different family (cheating) + if (((1 << pet_family->petTalentType) & talentTabInfo->petTalentMask) == 0) + continue; + + // search highest talent rank + uint32 spellid = 0; + + for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank) + { + if (talentInfo->RankID[rank] != 0) + { + spellid = talentInfo->RankID[rank]; + break; + } + } + + if (!spellid) // ??? none spells in talent + continue; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid); + if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) + continue; + + // learn highest rank of talent and learn all non-talent spell ranks (recursive by tree) + pet->learnSpellHighRank(spellid); + } + + pet->SetFreeTalentPoints(0); + + SendSysMessage(LANG_COMMAND_LEARN_PET_TALENTS); + return true; +} + +bool ChatHandler::HandleLearnAllLangCommand(const char* /*args*/) +{ + // skipping UNIVERSAL language (0) + for (uint8 i = 1; i < LANGUAGES_COUNT; ++i) + m_session->GetPlayer()->learnSpell(lang_description[i].spell_id, false); + + SendSysMessage(LANG_COMMAND_LEARN_ALL_LANG); + return true; +} + +bool ChatHandler::HandleLearnAllDefaultCommand(const char *args) +{ + Player* target; + if (!extractPlayerTarget((char*)args,&target)) + return false; + + target->learnDefaultSpells(); + target->learnQuestRewardedSpells(); + + PSendSysMessage(LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST,GetNameLink(target).c_str()); + return true; +} + +bool ChatHandler::HandleLearnCommand(const char *args) +{ + Player* targetPlayer = getSelectedPlayer(); + + if (!targetPlayer) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spell = extractSpellIdFromLink((char*)args); + if (!spell || !sSpellStore.LookupEntry(spell)) + return false; + + char const* allStr = strtok(NULL," "); + bool allRanks = allStr ? (strncmp(allStr, "all", strlen(allStr)) == 0) : false; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); + if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) + { + PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); + SetSentErrorMessage(true); + return false; + } + + if (!allRanks && targetPlayer->HasSpell(spell)) + { + if (targetPlayer == m_session->GetPlayer()) + SendSysMessage(LANG_YOU_KNOWN_SPELL); + else + PSendSysMessage(LANG_TARGET_KNOWN_SPELL,GetNameLink(targetPlayer).c_str()); + SetSentErrorMessage(true); + return false; + } + + if (allRanks) + targetPlayer->learnSpellHighRank(spell); + else + targetPlayer->learnSpell(spell, false); + + uint32 first_spell = spellmgr.GetFirstSpellInChain(spell); + if (GetTalentSpellCost(first_spell)) + targetPlayer->SendTalentsInfoData(false); + + return true; +} + +bool ChatHandler::HandleAddItemCommand(const char *args) +{ + if (!*args) + return false; + + uint32 itemId = 0; + + if (args[0] == '[') // [name] manual form + { + char* citemName = strtok((char*)args, "]"); + + if (citemName && citemName[0]) + { + std::string itemName = citemName+1; + WorldDatabase.escape_string(itemName); + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT entry FROM item_template WHERE name = '%s'", itemName.c_str()); + if (!result) + { + PSendSysMessage(LANG_COMMAND_COULDNOTFIND, citemName+1); + SetSentErrorMessage(true); + return false; + } + itemId = result->Fetch()->GetUInt16(); + } + else + return false; + } + else // item_id or [name] Shift-click form |color|Hitem:item_id:0:0:0|h[name]|h|r + { + char* cId = extractKeyFromLink((char*)args,"Hitem"); + if (!cId) + return false; + itemId = atol(cId); + } + + char* ccount = strtok(NULL, " "); + + int32 count = 1; + + if (ccount) + count = strtol(ccount, NULL, 10); + + if (count == 0) + count = 1; + + Player* pl = m_session->GetPlayer(); + Player* plTarget = getSelectedPlayer(); + if (!plTarget) + plTarget = pl; + + sLog.outDetail(GetTrinityString(LANG_ADDITEM), itemId, count); + + ItemPrototype const *pProto = objmgr.GetItemPrototype(itemId); + if (!pProto) + { + PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, itemId); + SetSentErrorMessage(true); + return false; + } + + //Subtract + if (count < 0) + { + plTarget->DestroyItemCount(itemId, -count, true, false); + PSendSysMessage(LANG_REMOVEITEM, itemId, -count, GetNameLink(plTarget).c_str()); + return true; + } + + //Adding items + uint32 noSpaceForCount = 0; + + // check space and find places + ItemPosCountVec dest; + uint8 msg = plTarget->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, count, &noSpaceForCount); + if (msg != EQUIP_ERR_OK) // convert to possible store amount + count -= noSpaceForCount; + + if (count == 0 || dest.empty()) // can't add any + { + PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemId, noSpaceForCount); + SetSentErrorMessage(true); + return false; + } + + Item* item = plTarget->StoreNewItem(dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId)); + + // remove binding (let GM give it to another player later) + if (pl == plTarget) + for (ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ++itr) + if (Item* item1 = pl->GetItemByPos(itr->pos)) + item1->SetBinding(false); + + if (count > 0 && item) + { + pl->SendNewItem(item,count,false,true); + if (pl != plTarget) + plTarget->SendNewItem(item,count,true,false); + } + + if (noSpaceForCount > 0) + PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemId, noSpaceForCount); + + return true; +} + +bool ChatHandler::HandleAddItemSetCommand(const char *args) +{ + if (!*args) + return false; + + char* cId = extractKeyFromLink((char*)args,"Hitemset"); // number or [name] Shift-click form |color|Hitemset:itemset_id|h[name]|h|r + if (!cId) + return false; + + uint32 itemsetId = atol(cId); + + // prevent generation all items with itemset field value '0' + if (itemsetId == 0) + { + PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND,itemsetId); + SetSentErrorMessage(true); + return false; + } + + Player* pl = m_session->GetPlayer(); + Player* plTarget = getSelectedPlayer(); + if (!plTarget) + plTarget = pl; + + sLog.outDetail(GetTrinityString(LANG_ADDITEMSET), itemsetId); + + bool found = false; + for (uint32 id = 0; id < sItemStorage.MaxEntry; id++) + { + ItemPrototype const *pProto = sItemStorage.LookupEntry(id); + if (!pProto) + continue; + + if (pProto->ItemSet == itemsetId) + { + found = true; + ItemPosCountVec dest; + uint8 msg = plTarget->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, pProto->ItemId, 1); + if (msg == EQUIP_ERR_OK) + { + Item* item = plTarget->StoreNewItem(dest, pProto->ItemId, true); + + // remove binding (let GM give it to another player later) + if (pl == plTarget) + item->SetBinding(false); + + pl->SendNewItem(item,1,false,true); + if (pl != plTarget) + plTarget->SendNewItem(item,1,true,false); + } + else + { + pl->SendEquipError(msg, NULL, NULL); + PSendSysMessage(LANG_ITEM_CANNOT_CREATE, pProto->ItemId, 1); + } + } + } + + if (!found) + { + PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND,itemsetId); + + SetSentErrorMessage(true); + return false; + } + + return true; +} + +bool ChatHandler::HandleListItemCommand(const char *args) +{ + if (!*args) + return false; + + char* cId = extractKeyFromLink((char*)args,"Hitem"); + if (!cId) + return false; + + uint32 item_id = atol(cId); + if (!item_id) + { + PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, item_id); + SetSentErrorMessage(true); + return false; + } + + ItemPrototype const* itemProto = objmgr.GetItemPrototype(item_id); + if (!itemProto) + { + PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, item_id); + SetSentErrorMessage(true); + return false; + } + + char* c_count = strtok(NULL, " "); + int count = c_count ? atol(c_count) : 10; + + if (count < 0) + return false; + + QueryResult_AutoPtr result; + + // inventory case + uint32 inv_count = 0; + result=CharacterDatabase.PQuery("SELECT COUNT(item_template) FROM character_inventory WHERE item_template='%u'",item_id); + if (result) + inv_count = (*result)[0].GetUInt32(); + + result=CharacterDatabase.PQuery( + // 0 1 2 3 4 5 + "SELECT ci.item, cibag.slot AS bag, ci.slot, ci.guid, characters.account,characters.name " + "FROM character_inventory AS ci LEFT JOIN character_inventory AS cibag ON (cibag.item=ci.bag),characters " + "WHERE ci.item_template='%u' AND ci.guid = characters.guid LIMIT %u ", + item_id,uint32(count)); + + if (result) + { + do + { + Field *fields = result->Fetch(); + uint32 item_guid = fields[0].GetUInt32(); + uint32 item_bag = fields[1].GetUInt32(); + uint32 item_slot = fields[2].GetUInt32(); + uint32 owner_guid = fields[3].GetUInt32(); + uint32 owner_acc = fields[4].GetUInt32(); + std::string owner_name = fields[5].GetCppString(); + + char const* item_pos = 0; + if (Player::IsEquipmentPos(item_bag,item_slot)) + item_pos = "[equipped]"; + else if (Player::IsInventoryPos(item_bag,item_slot)) + item_pos = "[in inventory]"; + else if (Player::IsBankPos(item_bag,item_slot)) + item_pos = "[in bank]"; + else + item_pos = ""; + + PSendSysMessage(LANG_ITEMLIST_SLOT, + item_guid,owner_name.c_str(),owner_guid,owner_acc,item_pos); + } while (result->NextRow()); + + int64 res_count = result->GetRowCount(); + + if (count > res_count) + count-=res_count; + else if (count) + count = 0; + } + + // mail case + uint32 mail_count = 0; + result=CharacterDatabase.PQuery("SELECT COUNT(item_template) FROM mail_items WHERE item_template='%u'", item_id); + if (result) + mail_count = (*result)[0].GetUInt32(); + + if (count > 0) + { + result=CharacterDatabase.PQuery( + // 0 1 2 3 4 5 6 + "SELECT mail_items.item_guid, mail.sender, mail.receiver, char_s.account, char_s.name, char_r.account, char_r.name " + "FROM mail,mail_items,characters as char_s,characters as char_r " + "WHERE mail_items.item_template='%u' AND char_s.guid = mail.sender AND char_r.guid = mail.receiver AND mail.id=mail_items.mail_id LIMIT %u", + item_id,uint32(count)); + } + else + result = QueryResult_AutoPtr(NULL); + + if (result) + { + do + { + Field *fields = result->Fetch(); + uint32 item_guid = fields[0].GetUInt32(); + uint32 item_s = fields[1].GetUInt32(); + uint32 item_r = fields[2].GetUInt32(); + uint32 item_s_acc = fields[3].GetUInt32(); + std::string item_s_name = fields[4].GetCppString(); + uint32 item_r_acc = fields[5].GetUInt32(); + std::string item_r_name = fields[6].GetCppString(); + + char const* item_pos = "[in mail]"; + + PSendSysMessage(LANG_ITEMLIST_MAIL, + item_guid,item_s_name.c_str(),item_s,item_s_acc,item_r_name.c_str(),item_r,item_r_acc,item_pos); + } while (result->NextRow()); + + int64 res_count = result->GetRowCount(); + + if (count > res_count) + count-=res_count; + else if (count) + count = 0; + } + + // auction case + uint32 auc_count = 0; + result=CharacterDatabase.PQuery("SELECT COUNT(item_template) FROM auctionhouse WHERE item_template='%u'",item_id); + if (result) + auc_count = (*result)[0].GetUInt32(); + + if (count > 0) + { + result=CharacterDatabase.PQuery( + // 0 1 2 3 + "SELECT auctionhouse.itemguid, auctionhouse.itemowner, characters.account, characters.name " + "FROM auctionhouse,characters WHERE auctionhouse.item_template='%u' AND characters.guid = auctionhouse.itemowner LIMIT %u", + item_id,uint32(count)); + } + else + result = QueryResult_AutoPtr(NULL); + + if (result) + { + do + { + Field *fields = result->Fetch(); + uint32 item_guid = fields[0].GetUInt32(); + uint32 owner = fields[1].GetUInt32(); + uint32 owner_acc = fields[2].GetUInt32(); + std::string owner_name = fields[3].GetCppString(); + + char const* item_pos = "[in auction]"; + + PSendSysMessage(LANG_ITEMLIST_AUCTION, item_guid, owner_name.c_str(), owner, owner_acc,item_pos); + } while (result->NextRow()); + } + + // guild bank case + uint32 guild_count = 0; + result=CharacterDatabase.PQuery("SELECT COUNT(item_entry) FROM guild_bank_item WHERE item_entry='%u'",item_id); + if (result) + guild_count = (*result)[0].GetUInt32(); + + result=CharacterDatabase.PQuery( + // 0 1 2 + "SELECT gi.item_guid, gi.guildid, guild.name " + "FROM guild_bank_item AS gi, guild WHERE gi.item_entry='%u' AND gi.guildid = guild.guildid LIMIT %u ", + item_id,uint32(count)); + + if (result) + { + do + { + Field *fields = result->Fetch(); + uint32 item_guid = fields[0].GetUInt32(); + uint32 guild_guid = fields[1].GetUInt32(); + std::string guild_name = fields[2].GetCppString(); + + char const* item_pos = "[in guild bank]"; + + PSendSysMessage(LANG_ITEMLIST_GUILD,item_guid,guild_name.c_str(),guild_guid,item_pos); + } while (result->NextRow()); + + int64 res_count = result->GetRowCount(); + + if (count > res_count) + count-=res_count; + else if (count) + count = 0; + } + + if (inv_count+mail_count+auc_count+guild_count == 0) + { + SendSysMessage(LANG_COMMAND_NOITEMFOUND); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_COMMAND_LISTITEMMESSAGE,item_id,inv_count+mail_count+auc_count+guild_count,inv_count,mail_count,auc_count,guild_count); + + return true; +} + +bool ChatHandler::HandleListObjectCommand(const char *args) +{ + if (!*args) + return false; + + // number or [name] Shift-click form |color|Hgameobject_entry:go_id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject_entry"); + if (!cId) + return false; + + uint32 go_id = atol(cId); + if (!go_id) + { + PSendSysMessage(LANG_COMMAND_LISTOBJINVALIDID, go_id); + SetSentErrorMessage(true); + return false; + } + + GameObjectInfo const * gInfo = objmgr.GetGameObjectInfo(go_id); + if (!gInfo) + { + PSendSysMessage(LANG_COMMAND_LISTOBJINVALIDID, go_id); + SetSentErrorMessage(true); + return false; + } + + char* c_count = strtok(NULL, " "); + int count = c_count ? atol(c_count) : 10; + + if (count < 0) + return false; + + QueryResult_AutoPtr result; + + uint32 obj_count = 0; + result=WorldDatabase.PQuery("SELECT COUNT(guid) FROM gameobject WHERE id='%u'",go_id); + if (result) + obj_count = (*result)[0].GetUInt32(); + + if (m_session) + { + Player* pl = m_session->GetPlayer(); + result = WorldDatabase.PQuery("SELECT guid, position_x, position_y, position_z, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM gameobject WHERE id = '%u' ORDER BY order_ ASC LIMIT %u", + pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(),go_id,uint32(count)); + } + else + result = WorldDatabase.PQuery("SELECT guid, position_x, position_y, position_z, map FROM gameobject WHERE id = '%u' LIMIT %u", + go_id,uint32(count)); + + if (result) + { + do + { + Field *fields = result->Fetch(); + uint32 guid = fields[0].GetUInt32(); + float x = fields[1].GetFloat(); + float y = fields[2].GetFloat(); + float z = fields[3].GetFloat(); + int mapid = fields[4].GetUInt16(); + + if (m_session) + PSendSysMessage(LANG_GO_LIST_CHAT, guid, guid, gInfo->name, x, y, z, mapid); + else + PSendSysMessage(LANG_GO_LIST_CONSOLE, guid, gInfo->name, x, y, z, mapid); + } while (result->NextRow()); + } + + PSendSysMessage(LANG_COMMAND_LISTOBJMESSAGE,go_id,obj_count); + return true; +} + +bool ChatHandler::HandleGameObjectStateCommand(const char *args) +{ + // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args, "Hgameobject"); + if (!cId) + return false; + + uint32 lowguid = atoi(cId); + if (!lowguid) + return false; + + GameObject* gobj = NULL; + + if (GameObjectData const* goData = objmgr.GetGOData(lowguid)) + gobj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid, goData->id); + + if (!gobj) + { + PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + char* ctype = strtok(NULL, " "); + if (!ctype) + return false; + + int32 type = atoi(ctype); + if (type < 0) + { + if (type == -1) + gobj->SendObjectDeSpawnAnim(gobj->GetGUID()); + else if (type == -2) + { + return false; + } + return true; + } + + char* cstate = strtok(NULL, " "); + if (!cstate) + return false; + + int32 state = atoi(cstate); + + if (type < 4) + gobj->SetByteValue(GAMEOBJECT_BYTES_1, type, state); + else if (type == 4) + { + WorldPacket data(SMSG_GAMEOBJECT_CUSTOM_ANIM,8+4); + data << gobj->GetGUID(); + data << (uint32)(state); + gobj->SendMessageToSet(&data, true); + } + PSendSysMessage("Set gobject type %d state %d", type, state); + + return true; +} + +bool ChatHandler::HandleListCreatureCommand(const char *args) +{ + if (!*args) + return false; + + // number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hcreature_entry"); + if (!cId) + return false; + + uint32 cr_id = atol(cId); + if (!cr_id) + { + PSendSysMessage(LANG_COMMAND_INVALIDCREATUREID, cr_id); + SetSentErrorMessage(true); + return false; + } + + CreatureInfo const* cInfo = objmgr.GetCreatureTemplate(cr_id); + if (!cInfo) + { + PSendSysMessage(LANG_COMMAND_INVALIDCREATUREID, cr_id); + SetSentErrorMessage(true); + return false; + } + + char* c_count = strtok(NULL, " "); + int count = c_count ? atol(c_count) : 10; + + if (count < 0) + return false; + + QueryResult_AutoPtr result; + + uint32 cr_count = 0; + result=WorldDatabase.PQuery("SELECT COUNT(guid) FROM creature WHERE id='%u'",cr_id); + if (result) + cr_count = (*result)[0].GetUInt32(); + + if (m_session) + { + Player* pl = m_session->GetPlayer(); + result = WorldDatabase.PQuery("SELECT guid, position_x, position_y, position_z, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM creature WHERE id = '%u' ORDER BY order_ ASC LIMIT %u", + pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), cr_id,uint32(count)); + } + else + result = WorldDatabase.PQuery("SELECT guid, position_x, position_y, position_z, map FROM creature WHERE id = '%u' LIMIT %u", + cr_id,uint32(count)); + + if (result) + { + do + { + Field *fields = result->Fetch(); + uint32 guid = fields[0].GetUInt32(); + float x = fields[1].GetFloat(); + float y = fields[2].GetFloat(); + float z = fields[3].GetFloat(); + int mapid = fields[4].GetUInt16(); + + if (m_session) + PSendSysMessage(LANG_CREATURE_LIST_CHAT, guid, guid, cInfo->Name, x, y, z, mapid); + else + PSendSysMessage(LANG_CREATURE_LIST_CONSOLE, guid, cInfo->Name, x, y, z, mapid); + } while (result->NextRow()); + } + + PSendSysMessage(LANG_COMMAND_LISTCREATUREMESSAGE,cr_id,cr_count); + return true; +} + +bool ChatHandler::HandleLookupItemCommand(const char *args) +{ + if (!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + // converting string that we try to find to lower case + if (!Utf8toWStr(namepart,wnamepart)) + return false; + + wstrToLower(wnamepart); + + bool found = false; + + // Search in `item_template` + for (uint32 id = 0; id < sItemStorage.MaxEntry; id++) + { + ItemPrototype const *pProto = sItemStorage.LookupEntry(id); + if (!pProto) + continue; + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId); + if (il) + { + if (il->Name.size() > loc_idx && !il->Name[loc_idx].empty()) + { + std::string name = il->Name[loc_idx]; + + if (Utf8FitTo(name, wnamepart)) + { + if (m_session) + PSendSysMessage(LANG_ITEM_LIST_CHAT, id, id, name.c_str()); + else + PSendSysMessage(LANG_ITEM_LIST_CONSOLE, id, name.c_str()); + + if (!found) + found = true; + + continue; + } + } + } + } + + std::string name = pProto->Name1; + if (name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + { + if (m_session) + PSendSysMessage(LANG_ITEM_LIST_CHAT, id, id, name.c_str()); + else + PSendSysMessage(LANG_ITEM_LIST_CONSOLE, id, name.c_str()); + + if (!found) + found = true; + } + } + + if (!found) + SendSysMessage(LANG_COMMAND_NOITEMFOUND); + + return true; +} + +bool ChatHandler::HandleLookupItemSetCommand(const char *args) +{ + if (!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + if (!Utf8toWStr(namepart,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower(wnamepart); + + bool found = false; + + // Search in ItemSet.dbc + for (uint32 id = 0; id < sItemSetStore.GetNumRows(); id++) + { + ItemSetEntry const *set = sItemSetStore.LookupEntry(id); + if (set) + { + int loc = GetSessionDbcLocale(); + std::string name = set->name[loc]; + if (name.empty()) + continue; + + if (!Utf8FitTo(name, wnamepart)) + { + loc = 0; + for (; loc < MAX_LOCALE; ++loc) + { + if (loc == GetSessionDbcLocale()) + continue; + + name = set->name[loc]; + if (name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if (loc < MAX_LOCALE) + { + // send item set in "id - [namedlink locale]" format + if (m_session) + PSendSysMessage(LANG_ITEMSET_LIST_CHAT,id,id,name.c_str(),localeNames[loc]); + else + PSendSysMessage(LANG_ITEMSET_LIST_CONSOLE,id,name.c_str(),localeNames[loc]); + + if (!found) + found = true; + } + } + } + if (!found) + SendSysMessage(LANG_COMMAND_NOITEMSETFOUND); + return true; +} + +bool ChatHandler::HandleLookupSkillCommand(const char *args) +{ + if (!*args) + return false; + + // can be NULL in console call + Player* target = getSelectedPlayer(); + + std::string namepart = args; + std::wstring wnamepart; + + if (!Utf8toWStr(namepart,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower(wnamepart); + + bool found = false; + + // Search in SkillLine.dbc + for (uint32 id = 0; id < sSkillLineStore.GetNumRows(); id++) + { + SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(id); + if (skillInfo) + { + int loc = GetSessionDbcLocale(); + std::string name = skillInfo->name[loc]; + if (name.empty()) + continue; + + if (!Utf8FitTo(name, wnamepart)) + { + loc = 0; + for (; loc < MAX_LOCALE; ++loc) + { + if (loc == GetSessionDbcLocale()) + continue; + + name = skillInfo->name[loc]; + if (name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if (loc < MAX_LOCALE) + { + char valStr[50] = ""; + char const* knownStr = ""; + if (target && target->HasSkill(id)) + { + knownStr = GetTrinityString(LANG_KNOWN); + uint32 curValue = target->GetPureSkillValue(id); + uint32 maxValue = target->GetPureMaxSkillValue(id); + uint32 permValue = target->GetSkillPermBonusValue(id); + uint32 tempValue = target->GetSkillTempBonusValue(id); + + char const* valFormat = GetTrinityString(LANG_SKILL_VALUES); + snprintf(valStr,50,valFormat,curValue,maxValue,permValue,tempValue); + } + + // send skill in "id - [namedlink locale]" format + if (m_session) + PSendSysMessage(LANG_SKILL_LIST_CHAT,id,id,name.c_str(),localeNames[loc],knownStr,valStr); + else + PSendSysMessage(LANG_SKILL_LIST_CONSOLE,id,name.c_str(),localeNames[loc],knownStr,valStr); + + if (!found) + found = true; + } + } + } + if (!found) + SendSysMessage(LANG_COMMAND_NOSKILLFOUND); + return true; +} + +bool ChatHandler::HandleLookupSpellCommand(const char *args) +{ + if (!*args) + return false; + + // can be NULL at console call + Player* target = getSelectedPlayer(); + + std::string namepart = args; + std::wstring wnamepart; + + if (!Utf8toWStr(namepart,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower(wnamepart); + + bool found = false; + + // Search in Spell.dbc + for (uint32 id = 0; id < sSpellStore.GetNumRows(); id++) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(id); + if (spellInfo) + { + int loc = GetSessionDbcLocale(); + std::string name = spellInfo->SpellName[loc]; + if (name.empty()) + continue; + + if (!Utf8FitTo(name, wnamepart)) + { + loc = 0; + for (; loc < MAX_LOCALE; ++loc) + { + if (loc == GetSessionDbcLocale()) + continue; + + name = spellInfo->SpellName[loc]; + if (name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if (loc < MAX_LOCALE) + { + bool known = target && target->HasSpell(id); + bool learn = (spellInfo->Effect[0] == SPELL_EFFECT_LEARN_SPELL); + + uint32 talentCost = GetTalentSpellCost(id); + + bool talent = (talentCost > 0); + bool passive = IsPassiveSpell(id); + bool active = target && target->HasAura(id); + + // unit32 used to prevent interpreting uint8 as char at output + // find rank of learned spell for learning spell, or talent rank + uint32 rank = talentCost ? talentCost : spellmgr.GetSpellRank(learn ? spellInfo->EffectTriggerSpell[0] : id); + + // send spell in "id - [name, rank N] [talent] [passive] [learn] [known]" format + std::ostringstream ss; + if (m_session) + ss << id << " - |cffffffff|Hspell:" << id << "|h[" << name; + else + ss << id << " - " << name; + + // include rank in link name + if (rank) + ss << GetTrinityString(LANG_SPELL_RANK) << rank; + + if (m_session) + ss << " " << localeNames[loc] << "]|h|r"; + else + ss << " " << localeNames[loc]; + + if (talent) + ss << GetTrinityString(LANG_TALENT); + if (passive) + ss << GetTrinityString(LANG_PASSIVE); + if (learn) + ss << GetTrinityString(LANG_LEARN); + if (known) + ss << GetTrinityString(LANG_KNOWN); + if (active) + ss << GetTrinityString(LANG_ACTIVE); + + SendSysMessage(ss.str().c_str()); + + if (!found) + found = true; + } + } + } + if (!found) + SendSysMessage(LANG_COMMAND_NOSPELLFOUND); + return true; +} + +bool ChatHandler::HandleLookupQuestCommand(const char *args) +{ + if (!*args) + return false; + + // can be NULL at console call + Player* target = getSelectedPlayer(); + + std::string namepart = args; + std::wstring wnamepart; + + // converting string that we try to find to lower case + if (!Utf8toWStr(namepart,wnamepart)) + return false; + + wstrToLower(wnamepart); + + bool found = false; + + ObjectMgr::QuestMap const& qTemplates = objmgr.GetQuestTemplates(); + for (ObjectMgr::QuestMap::const_iterator iter = qTemplates.begin(); iter != qTemplates.end(); ++iter) + { + Quest * qinfo = iter->second; + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + QuestLocale const *il = objmgr.GetQuestLocale(qinfo->GetQuestId()); + if (il) + { + if (il->Title.size() > loc_idx && !il->Title[loc_idx].empty()) + { + std::string title = il->Title[loc_idx]; + + if (Utf8FitTo(title, wnamepart)) + { + char const* statusStr = ""; + + if (target) + { + QuestStatus status = target->GetQuestStatus(qinfo->GetQuestId()); + + if (status == QUEST_STATUS_COMPLETE) + { + if (target->GetQuestRewardStatus(qinfo->GetQuestId())) + statusStr = GetTrinityString(LANG_COMMAND_QUEST_REWARDED); + else + statusStr = GetTrinityString(LANG_COMMAND_QUEST_COMPLETE); + } + else if (status == QUEST_STATUS_INCOMPLETE) + statusStr = GetTrinityString(LANG_COMMAND_QUEST_ACTIVE); + } + + if (m_session) + PSendSysMessage(LANG_QUEST_LIST_CHAT,qinfo->GetQuestId(),qinfo->GetQuestId(),qinfo->GetQuestLevel(),title.c_str(),statusStr); + else + PSendSysMessage(LANG_QUEST_LIST_CONSOLE,qinfo->GetQuestId(),title.c_str(),statusStr); + + if (!found) + found = true; + + continue; + } + } + } + } + + std::string title = qinfo->GetTitle(); + if (title.empty()) + continue; + + if (Utf8FitTo(title, wnamepart)) + { + char const* statusStr = ""; + + if (target) + { + QuestStatus status = target->GetQuestStatus(qinfo->GetQuestId()); + + if (status == QUEST_STATUS_COMPLETE) + { + if (target->GetQuestRewardStatus(qinfo->GetQuestId())) + statusStr = GetTrinityString(LANG_COMMAND_QUEST_REWARDED); + else + statusStr = GetTrinityString(LANG_COMMAND_QUEST_COMPLETE); + } + else if (status == QUEST_STATUS_INCOMPLETE) + statusStr = GetTrinityString(LANG_COMMAND_QUEST_ACTIVE); + } + + if (m_session) + PSendSysMessage(LANG_QUEST_LIST_CHAT,qinfo->GetQuestId(),qinfo->GetQuestId(),qinfo->GetQuestLevel(),title.c_str(),statusStr); + else + PSendSysMessage(LANG_QUEST_LIST_CONSOLE,qinfo->GetQuestId(),title.c_str(),statusStr); + + if (!found) + found = true; + } + } + + if (!found) + SendSysMessage(LANG_COMMAND_NOQUESTFOUND); + + return true; +} + +bool ChatHandler::HandleLookupCreatureCommand(const char *args) +{ + if (!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + // converting string that we try to find to lower case + if (!Utf8toWStr (namepart,wnamepart)) + return false; + + wstrToLower (wnamepart); + + bool found = false; + + for (uint32 id = 0; id< sCreatureStorage.MaxEntry; ++id) + { + CreatureInfo const* cInfo = sCreatureStorage.LookupEntry (id); + if (!cInfo) + continue; + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + CreatureLocale const *cl = objmgr.GetCreatureLocale (id); + if (cl) + { + if (cl->Name.size() > loc_idx && !cl->Name[loc_idx].empty ()) + { + std::string name = cl->Name[loc_idx]; + + if (Utf8FitTo (name, wnamepart)) + { + if (m_session) + PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CHAT, id, id, name.c_str ()); + else + PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CONSOLE, id, name.c_str ()); + + if (!found) + found = true; + + continue; + } + } + } + } + + std::string name = cInfo->Name; + if (name.empty ()) + continue; + + if (Utf8FitTo(name, wnamepart)) + { + if (m_session) + PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CHAT, id, id, name.c_str ()); + else + PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CONSOLE, id, name.c_str ()); + + if (!found) + found = true; + } + } + + if (!found) + SendSysMessage (LANG_COMMAND_NOCREATUREFOUND); + + return true; +} + +bool ChatHandler::HandleLookupObjectCommand(const char *args) +{ + if (!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + // converting string that we try to find to lower case + if (!Utf8toWStr(namepart,wnamepart)) + return false; + + wstrToLower(wnamepart); + + bool found = false; + + for (uint32 id = 0; id< sGOStorage.MaxEntry; id++) + { + GameObjectInfo const* gInfo = sGOStorage.LookupEntry(id); + if (!gInfo) + continue; + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + GameObjectLocale const *gl = objmgr.GetGameObjectLocale(id); + if (gl) + { + if (gl->Name.size() > loc_idx && !gl->Name[loc_idx].empty()) + { + std::string name = gl->Name[loc_idx]; + + if (Utf8FitTo(name, wnamepart)) + { + if (m_session) + PSendSysMessage(LANG_GO_ENTRY_LIST_CHAT, id, id, name.c_str()); + else + PSendSysMessage(LANG_GO_ENTRY_LIST_CONSOLE, id, name.c_str()); + + if (!found) + found = true; + + continue; + } + } + } + } + + std::string name = gInfo->name; + if (name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + { + if (m_session) + PSendSysMessage(LANG_GO_ENTRY_LIST_CHAT, id, id, name.c_str()); + else + PSendSysMessage(LANG_GO_ENTRY_LIST_CONSOLE, id, name.c_str()); + + if (!found) + found = true; + } + } + + if (!found) + SendSysMessage(LANG_COMMAND_NOGAMEOBJECTFOUND); + + return true; +} + +bool ChatHandler::HandleLookupFactionCommand(const char *args) +{ + if (!*args) + return false; + + // Can be NULL at console call + Player *target = getSelectedPlayer (); + + std::string namepart = args; + std::wstring wnamepart; + + if (!Utf8toWStr (namepart,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower (wnamepart); + + bool found = false; + + for (uint32 id = 0; id < sFactionStore.GetNumRows(); ++id) + { + FactionEntry const *factionEntry = sFactionStore.LookupEntry (id); + if (factionEntry) + { + FactionState const* repState = target ? target->GetReputationMgr().GetState(factionEntry) : NULL; + + int loc = GetSessionDbcLocale(); + std::string name = factionEntry->name[loc]; + if (name.empty()) + continue; + + if (!Utf8FitTo(name, wnamepart)) + { + loc = 0; + for (; loc < MAX_LOCALE; ++loc) + { + if (loc == GetSessionDbcLocale()) + continue; + + name = factionEntry->name[loc]; + if (name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if (loc < MAX_LOCALE) + { + // send faction in "id - [faction] rank reputation [visible] [at war] [own team] [unknown] [invisible] [inactive]" format + // or "id - [faction] [no reputation]" format + std::ostringstream ss; + if (m_session) + ss << id << " - |cffffffff|Hfaction:" << id << "|h[" << name << " " << localeNames[loc] << "]|h|r"; + else + ss << id << " - " << name << " " << localeNames[loc]; + + if (repState) // and then target != NULL also + { + ReputationRank rank = target->GetReputationMgr().GetRank(factionEntry); + std::string rankName = GetTrinityString(ReputationRankStrIndex[rank]); + + ss << " " << rankName << "|h|r (" << target->GetReputationMgr().GetReputation(factionEntry) << ")"; + + if (repState->Flags & FACTION_FLAG_VISIBLE) + ss << GetTrinityString(LANG_FACTION_VISIBLE); + if (repState->Flags & FACTION_FLAG_AT_WAR) + ss << GetTrinityString(LANG_FACTION_ATWAR); + if (repState->Flags & FACTION_FLAG_PEACE_FORCED) + ss << GetTrinityString(LANG_FACTION_PEACE_FORCED); + if (repState->Flags & FACTION_FLAG_HIDDEN) + ss << GetTrinityString(LANG_FACTION_HIDDEN); + if (repState->Flags & FACTION_FLAG_INVISIBLE_FORCED) + ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED); + if (repState->Flags & FACTION_FLAG_INACTIVE) + ss << GetTrinityString(LANG_FACTION_INACTIVE); + } + else + ss << GetTrinityString(LANG_FACTION_NOREPUTATION); + + SendSysMessage(ss.str().c_str()); + + if (!found) + found = true; + } + } + } + + if (!found) + SendSysMessage(LANG_COMMAND_FACTION_NOTFOUND); + return true; +} + +bool ChatHandler::HandleLookupTaxiNodeCommand(const char * args) +{ + if (!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + if (!Utf8toWStr(namepart,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower(wnamepart); + + bool found = false; + + // Search in TaxiNodes.dbc + for (uint32 id = 0; id < sTaxiNodesStore.GetNumRows(); id++) + { + TaxiNodesEntry const *nodeEntry = sTaxiNodesStore.LookupEntry(id); + if (nodeEntry) + { + int loc = GetSessionDbcLocale(); + std::string name = nodeEntry->name[loc]; + if (name.empty()) + continue; + + if (!Utf8FitTo(name, wnamepart)) + { + loc = 0; + for (; loc < MAX_LOCALE; ++loc) + { + if (loc == GetSessionDbcLocale()) + continue; + + name = nodeEntry->name[loc]; + if (name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if (loc < MAX_LOCALE) + { + // send taxinode in "id - [name] (Map:m X:x Y:y Z:z)" format + if (m_session) + PSendSysMessage (LANG_TAXINODE_ENTRY_LIST_CHAT, id, id, name.c_str(),localeNames[loc], + nodeEntry->map_id,nodeEntry->x,nodeEntry->y,nodeEntry->z); + else + PSendSysMessage (LANG_TAXINODE_ENTRY_LIST_CONSOLE, id, name.c_str(), localeNames[loc], + nodeEntry->map_id,nodeEntry->x,nodeEntry->y,nodeEntry->z); + + if (!found) + found = true; + } + } + } + if (!found) + SendSysMessage(LANG_COMMAND_NOTAXINODEFOUND); + return true; +} + +bool ChatHandler::HandleLookupMapCommand(const char *args) +{ + if (!*args) + return false; + + /*std::string namepart = args; + std::wstring wnamepart; + + // converting string that we try to find to lower case + if (!Utf8toWStr(namepart, wnamepart)) + return false; + + wstrToLower(wnamepart); + + bool found = false; + + // search in Map.dbc + for (uint32 id = 0; id < sMapStore.GetNumRows(); id++) + { + MapEntry const* MapInfo = sMapStore.LookupEntry(id); + if (MapInfo) + { + uint8 loc = m_session ? m_session->GetSessionDbcLocale() : sWorld.GetDefaultDbcLocale(); + + std::string name = MapInfo->name[loc]; + if (name.empty()) + continue; + + if (!Utf8FitTo(name, wnamepart)) + { + loc = LOCALE_enUS; + for (; loc < MAX_LOCALE; loc++) + { + if (m_session && loc == m_session->GetSessionDbcLocale()) + continue; + + name = MapInfo->name[loc]; + if (name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if (loc < MAX_LOCALE) + { + // send map in "id - [name][Continent][Instance/Battleground/Arena][Raid reset time:][Heroic reset time:][Mountable]" format + std::ostringstream ss; + + if (m_session) + ss << id << " - |cffffffff|Hmap:" << id << "|h[" << name << "]"; + else // console + ss << id << " - [" << name << "]"; + + if (MapInfo->IsContinent()) + ss << GetTrinityString(LANG_CONTINENT); + + switch(MapInfo->map_type) + { + case MAP_INSTANCE: ss << GetTrinityString(LANG_INSTANCE); break; + case MAP_BATTLEGROUND: ss << GetTrinityString(LANG_BATTLEGROUND); break; + case MAP_ARENA: ss << GetTrinityString(LANG_ARENA); break; + } + + if (MapInfo->IsRaid()) + ss << GetTrinityString(LANG_RAID); + + if (MapInfo->SupportsHeroicMode()) + ss << GetTrinityString(LANG_HEROIC); + + uint32 ResetTimeRaid = MapInfo->resetTimeRaid; + + std::string ResetTimeRaidStr; + if (ResetTimeRaid) + ResetTimeRaidStr = secsToTimeString(ResetTimeRaid, true, false); + + uint32 ResetTimeHeroic = MapInfo->resetTimeHeroic; + std::string ResetTimeHeroicStr; + if (ResetTimeHeroic) + ResetTimeHeroicStr = secsToTimeString(ResetTimeHeroic, true, false); + + if (MapInfo->IsMountAllowed()) + ss << GetTrinityString(LANG_MOUNTABLE); + + if (ResetTimeRaid && !ResetTimeHeroic) + PSendSysMessage(ss.str().c_str(), ResetTimeRaidStr.c_str()); + else if (!ResetTimeRaid && ResetTimeHeroic) + PSendSysMessage(ss.str().c_str(), ResetTimeHeroicStr.c_str()); + else if (ResetTimeRaid && ResetTimeHeroic) + PSendSysMessage(ss.str().c_str(), ResetTimeRaidStr.c_str(), ResetTimeHeroicStr.c_str()); + else + SendSysMessage(ss.str().c_str()); + + if (!found) + found = true; + } + } + } + + if (!found) + SendSysMessage(LANG_COMMAND_NOMAPFOUND); + */ + return true; +} + +/** \brief GM command level 3 - Create a guild. + * + * This command allows a GM (level 3) to create a guild. + * + * The "args" parameter contains the name of the guild leader + * and then the name of the guild. + * + */ +bool ChatHandler::HandleGuildCreateCommand(const char *args) +{ + if (!*args) + return false; + + // if not guild name only (in "") then player name + Player* target; + if (!extractPlayerTarget(*args != '"' ? (char*)args : NULL, &target)) + return false; + + char* tailStr = *args != '"' ? strtok(NULL, "") : (char*)args; + if (!tailStr) + return false; + + char* guildStr = extractQuotedArg(tailStr); + if (!guildStr) + return false; + + std::string guildname = guildStr; + + if (target->GetGuildId()) + { + SendSysMessage (LANG_PLAYER_IN_GUILD); + return true; + } + + Guild *guild = new Guild; + if (!guild->Create (target,guildname)) + { + delete guild; + SendSysMessage (LANG_GUILD_NOT_CREATED); + SetSentErrorMessage (true); + return false; + } + + objmgr.AddGuild (guild); + return true; +} + +bool ChatHandler::HandleGuildInviteCommand(const char *args) +{ + if (!*args) + return false; + + // if not guild name only (in "") then player name + uint64 target_guid; + if (!extractPlayerTarget(*args != '"' ? (char*)args : NULL, NULL, &target_guid)) + return false; + + char* tailStr = *args != '"' ? strtok(NULL, "") : (char*)args; + if (!tailStr) + return false; + + char* guildStr = extractQuotedArg(tailStr); + if (!guildStr) + return false; + + std::string glName = guildStr; + Guild* targetGuild = objmgr.GetGuildByName (glName); + if (!targetGuild) + return false; + + // player's guild membership checked in AddMember before add + if (!targetGuild->AddMember (target_guid,targetGuild->GetLowestRank ())) + return false; + + return true; +} + +bool ChatHandler::HandleGuildUninviteCommand(const char *args) +{ + Player* target; + uint64 target_guid; + if (!extractPlayerTarget((char*)args,&target,&target_guid)) + return false; + + uint32 glId = target ? target->GetGuildId () : Player::GetGuildIdFromDB (target_guid); + if (!glId) + return false; + + Guild* targetGuild = objmgr.GetGuildById (glId); + if (!targetGuild) + return false; + + targetGuild->DelMember (target_guid); + return true; +} + +bool ChatHandler::HandleGuildRankCommand(const char *args) +{ + char* nameStr; + char* rankStr; + extractOptFirstArg((char*)args,&nameStr,&rankStr); + if (!rankStr) + return false; + + Player* target; + uint64 target_guid; + std::string target_name; + if (!extractPlayerTarget(nameStr,&target,&target_guid,&target_name)) + return false; + + uint32 glId = target ? target->GetGuildId () : Player::GetGuildIdFromDB (target_guid); + if (!glId) + return false; + + Guild* targetGuild = objmgr.GetGuildById (glId); + if (!targetGuild) + return false; + + uint32 newrank = uint32 (atoi (rankStr)); + if (newrank > targetGuild->GetLowestRank ()) + return false; + + targetGuild->ChangeRank (target_guid,newrank); + return true; +} + +bool ChatHandler::HandleGuildDeleteCommand(const char *args) +{ + if (!*args) + return false; + + char* guildStr = extractQuotedArg((char*)args); + if (!guildStr) + return false; + + std::string gld = guildStr; + + Guild* targetGuild = objmgr.GetGuildByName (gld); + if (!targetGuild) + return false; + + targetGuild->Disband (); + + return true; +} + +bool ChatHandler::HandleGetDistanceCommand(const char *args) +{ + WorldObject* obj = NULL; + + if (*args) + { + uint64 guid = extractGuidFromLink((char*)args); + if (guid) + obj = (WorldObject*)ObjectAccessor::GetObjectByTypeMask(*m_session->GetPlayer(),guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); + + if (!obj) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + } + else + { + obj = getSelectedUnit(); + + if (!obj) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + } + + PSendSysMessage(LANG_DISTANCE, m_session->GetPlayer()->GetDistance(obj), m_session->GetPlayer()->GetDistance2d(obj), m_session->GetPlayer()->GetExactDist(obj), m_session->GetPlayer()->GetExactDist2d(obj)); + return true; +} + +bool ChatHandler::HandleDieCommand(const char* /*args*/) +{ + Unit* target = getSelectedUnit(); + + if (!target || !m_session->GetPlayer()->GetSelection()) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if (target->GetTypeId() == TYPEID_PLAYER) + { + if (HasLowerSecurity((Player*)target,0,false)) + return false; + } + + if (target->isAlive()) + { + if (sWorld.getConfig(CONFIG_DIE_COMMAND_MODE)) + m_session->GetPlayer()->Kill(target); + else + m_session->GetPlayer()->DealDamage(target, target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + + return true; +} + +bool ChatHandler::HandleDamageCommand(const char * args) +{ + if (!*args) + return false; + + Unit* target = getSelectedUnit(); + + if (!target || !m_session->GetPlayer()->GetSelection()) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if (!target->isAlive()) + return true; + + char* damageStr = strtok((char*)args, " "); + if (!damageStr) + return false; + + int32 damage_int = atoi((char*)damageStr); + if (damage_int <= 0) + return true; + + uint32 damage = damage_int; + + char* schoolStr = strtok((char*)NULL, " "); + + // flat melee damage without resistence/etc reduction + if (!schoolStr) + { + m_session->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + if (target != m_session->GetPlayer()) + m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_NORMAL, 0); + return true; + } + + uint32 school = schoolStr ? atoi((char*)schoolStr) : SPELL_SCHOOL_NORMAL; + if (school >= MAX_SPELL_SCHOOL) + return false; + + SpellSchoolMask schoolmask = SpellSchoolMask(1 << school); + + if (schoolmask & SPELL_SCHOOL_MASK_NORMAL) + damage = m_session->GetPlayer()->CalcArmorReducedDamage(target, damage, NULL, BASE_ATTACK); + + char* spellStr = strtok((char*)NULL, " "); + + // melee damage by specific school + if (!spellStr) + { + uint32 absorb = 0; + uint32 resist = 0; + + m_session->GetPlayer()->CalcAbsorbResist(target,schoolmask, SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); + + if (damage <= absorb + resist) + return true; + + damage -= absorb + resist; + + m_session->GetPlayer()->DealDamageMods(target,damage,&absorb); + m_session->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, schoolmask, NULL, false); + m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, schoolmask, damage, absorb, resist, VICTIMSTATE_NORMAL, 0); + return true; + } + + // non-melee damage + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spellid = extractSpellIdFromLink((char*)args); + if (!spellid || !sSpellStore.LookupEntry(spellid)) + return false; + + m_session->GetPlayer()->SpellNonMeleeDamageLog(target, spellid, damage); + return true; +} + +bool ChatHandler::HandleModifyArenaCommand(const char * args) +{ + if (!*args) + return false; + + Player *target = getSelectedPlayer(); + if (!target) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + int32 amount = (uint32)atoi(args); + + target->ModifyArenaPoints(amount); + + PSendSysMessage(LANG_COMMAND_MODIFY_ARENA, GetNameLink(target).c_str(), target->GetArenaPoints()); + + return true; +} + +bool ChatHandler::HandleReviveCommand(const char *args) +{ + Player* target; + uint64 target_guid; + if (!extractPlayerTarget((char*)args,&target,&target_guid)) + return false; + + if (target) + { + target->ResurrectPlayer(target->GetSession()->GetSecurity() > SEC_PLAYER ? 1.0f : 0.5f); + target->SpawnCorpseBones(); + target->SaveToDB(); + } + else + // will resurrected at login without corpse + ObjectAccessor::Instance().ConvertCorpseForPlayer(target_guid); + + return true; +} + +bool ChatHandler::HandleAuraCommand(const char *args) +{ + Unit *target = getSelectedUnit(); + if (!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spellID = extractSpellIdFromLink((char*)args); + + if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID)) + Aura::TryCreate(spellInfo, target, target); + + return true; +} + +bool ChatHandler::HandleUnAuraCommand(const char *args) +{ + Unit *target = getSelectedUnit(); + if (!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + std::string argstr = args; + if (argstr == "all") + { + target->RemoveAllAuras(); + return true; + } + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spellID = extractSpellIdFromLink((char*)args); + if (!spellID) + return false; + + target->RemoveAurasDueToSpell(spellID); + + return true; +} + +bool ChatHandler::HandleLinkGraveCommand(const char *args) +{ + if (!*args) + return false; + + char* px = strtok((char*)args, " "); + if (!px) + return false; + + uint32 g_id = (uint32)atoi(px); + + uint32 g_team; + + char* px2 = strtok(NULL, " "); + + if (!px2) + g_team = 0; + else if (strncmp(px2,"horde",6) == 0) + g_team = HORDE; + else if (strncmp(px2,"alliance",9) == 0) + g_team = ALLIANCE; + else + return false; + + WorldSafeLocsEntry const* graveyard = sWorldSafeLocsStore.LookupEntry(g_id); + + if (!graveyard) + { + PSendSysMessage(LANG_COMMAND_GRAVEYARDNOEXIST, g_id); + SetSentErrorMessage(true); + return false; + } + + Player* player = m_session->GetPlayer(); + + uint32 zoneId = player->GetZoneId(); + + AreaTableEntry const *areaEntry = GetAreaEntryByAreaID(zoneId); + if (!areaEntry || areaEntry->zone !=0) + { + PSendSysMessage(LANG_COMMAND_GRAVEYARDWRONGZONE, g_id,zoneId); + SetSentErrorMessage(true); + return false; + } + + if (objmgr.AddGraveYardLink(g_id,zoneId,g_team)) + PSendSysMessage(LANG_COMMAND_GRAVEYARDLINKED, g_id,zoneId); + else + PSendSysMessage(LANG_COMMAND_GRAVEYARDALRLINKED, g_id,zoneId); + + return true; +} + +bool ChatHandler::HandleNearGraveCommand(const char *args) +{ + uint32 g_team; + + size_t argslen = strlen(args); + + if (!*args) + g_team = 0; + else if (strncmp((char*)args,"horde",argslen) == 0) + g_team = HORDE; + else if (strncmp((char*)args,"alliance",argslen) == 0) + g_team = ALLIANCE; + else + return false; + + Player* player = m_session->GetPlayer(); + uint32 zone_id = player->GetZoneId(); + + WorldSafeLocsEntry const* graveyard = objmgr.GetClosestGraveYard( + player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(),player->GetMapId(),g_team); + + if (graveyard) + { + uint32 g_id = graveyard->ID; + + GraveYardData const* data = objmgr.FindGraveYardData(g_id,zone_id); + if (!data) + { + PSendSysMessage(LANG_COMMAND_GRAVEYARDERROR,g_id); + SetSentErrorMessage(true); + return false; + } + + g_team = data->team; + + std::string team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_NOTEAM); + + if (g_team == 0) + team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_ANY); + else if (g_team == HORDE) + team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_HORDE); + else if (g_team == ALLIANCE) + team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_ALLIANCE); + + PSendSysMessage(LANG_COMMAND_GRAVEYARDNEAREST, g_id,team_name.c_str(),zone_id); + } + else + { + std::string team_name; + + if (g_team == 0) + team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_ANY); + else if (g_team == HORDE) + team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_HORDE); + else if (g_team == ALLIANCE) + team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_ALLIANCE); + + if (g_team == ~uint32(0)) + PSendSysMessage(LANG_COMMAND_ZONENOGRAVEYARDS, zone_id); + else + PSendSysMessage(LANG_COMMAND_ZONENOGRAFACTION, zone_id,team_name.c_str()); + } + + return true; +} + +//-----------------------Npc Commands----------------------- +bool ChatHandler::HandleNpcAllowMovementCommand(const char* /*args*/) +{ + if (sWorld.getAllowMovement()) + { + sWorld.SetAllowMovement(false); + SendSysMessage(LANG_CREATURE_MOVE_DISABLED); + } + else + { + sWorld.SetAllowMovement(true); + SendSysMessage(LANG_CREATURE_MOVE_ENABLED); + } + return true; +} + +bool ChatHandler::HandleNpcChangeEntryCommand(const char *args) +{ + if (!*args) + return false; + + uint32 newEntryNum = atoi(args); + if (!newEntryNum) + return false; + + Unit* unit = getSelectedUnit(); + if (!unit || unit->GetTypeId() != TYPEID_UNIT) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + Creature* creature = unit->ToCreature(); + if (creature->UpdateEntry(newEntryNum)) + SendSysMessage(LANG_DONE); + else + SendSysMessage(LANG_ERROR); + return true; +} + +bool ChatHandler::HandleNpcInfoCommand(const char* /*args*/) +{ + Creature* target = getSelectedCreature(); + + if (!target) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + uint32 faction = target->getFaction(); + uint32 npcflags = target->GetUInt32Value(UNIT_NPC_FLAGS); + uint32 displayid = target->GetDisplayId(); + uint32 nativeid = target->GetNativeDisplayId(); + uint32 Entry = target->GetEntry(); + CreatureInfo const* cInfo = target->GetCreatureInfo(); + + int32 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL); + if (curRespawnDelay < 0) + curRespawnDelay = 0; + std::string curRespawnDelayStr = secsToTimeString(curRespawnDelay,true); + std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(),true); + + PSendSysMessage(LANG_NPCINFO_CHAR, target->GetDBTableGUIDLow(), faction, npcflags, Entry, displayid, nativeid); + PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel()); + PSendSysMessage(LANG_NPCINFO_HEALTH,target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth()); + PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS), target->GetUInt32Value(UNIT_DYNAMIC_FLAGS), target->getFaction()); + PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(),curRespawnDelayStr.c_str()); + PSendSysMessage(LANG_NPCINFO_LOOT, cInfo->lootid,cInfo->pickpocketLootId,cInfo->SkinLootId); + PSendSysMessage(LANG_NPCINFO_DUNGEON_ID, target->GetInstanceId()); + PSendSysMessage(LANG_NPCINFO_PHASEMASK, target->GetPhaseMask()); + PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor()); + PSendSysMessage(LANG_NPCINFO_POSITION,float(target->GetPositionX()), float(target->GetPositionY()), float(target->GetPositionZ())); + if (const CreatureData* const linked = target->GetLinkedRespawnCreatureData()) + if (CreatureInfo const *master = GetCreatureInfo(linked->id)) + PSendSysMessage(LANG_NPCINFO_LINKGUID, objmgr.GetLinkedRespawnGuid(target->GetDBTableGUIDLow()), linked->id, master->Name); + + if ((npcflags & UNIT_NPC_FLAG_VENDOR)) + { + SendSysMessage(LANG_NPCINFO_VENDOR); + } + if ((npcflags & UNIT_NPC_FLAG_TRAINER)) + { + SendSysMessage(LANG_NPCINFO_TRAINER); + } + + return true; +} + +//play npc emote +bool ChatHandler::HandleNpcPlayEmoteCommand(const char *args) +{ + uint32 emote = atoi((char*)args); + + Creature* target = getSelectedCreature(); + if (!target) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + target->SetUInt32Value(UNIT_NPC_EMOTESTATE,emote); + + return true; +} + +//TODO: NpcCommands that needs to be fixed : + +bool ChatHandler::HandleNpcAddWeaponCommand(const char* /*args*/) +{ + /*if (!*args) + return false; + + uint64 guid = m_session->GetPlayer()->GetSelection(); + if (guid == 0) + { + SendSysMessage(LANG_NO_SELECTION); + return true; + } + + Creature *pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); + + if (!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + return true; + } + + char* pSlotID = strtok((char*)args, " "); + if (!pSlotID) + return false; + + char* pItemID = strtok(NULL, " "); + if (!pItemID) + return false; + + uint32 ItemID = atoi(pItemID); + uint32 SlotID = atoi(pSlotID); + + ItemPrototype* tmpItem = objmgr.GetItemPrototype(ItemID); + + bool added = false; + if (tmpItem) + { + switch(SlotID) + { + case 1: + pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, ItemID); + added = true; + break; + case 2: + pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, ItemID); + added = true; + break; + case 3: + pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, ItemID); + added = true; + break; + default: + PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST,SlotID); + added = false; + break; + } + + if (added) + PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT,ItemID,tmpItem->Name1,SlotID); + } + else + { + PSendSysMessage(LANG_ITEM_NOT_FOUND,ItemID); + return true; + } + */ + return true; +} +//---------------------------------------------------------- + +bool ChatHandler::HandleExploreCheatCommand(const char *args) +{ + if (!*args) + return false; + + int flag = atoi((char*)args); + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if (flag != 0) + { + PSendSysMessage(LANG_YOU_SET_EXPLORE_ALL, GetNameLink(chr).c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_ALL,GetNameLink().c_str()); + } + else + { + PSendSysMessage(LANG_YOU_SET_EXPLORE_NOTHING, GetNameLink(chr).c_str()); + if (needReportToTarget(chr)) + ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_NOTHING,GetNameLink().c_str()); + } + + for (uint8 i=0; iGetPlayer()->SetFlag(PLAYER_EXPLORED_ZONES_1+i,0xFFFFFFFF); + } + else + { + m_session->GetPlayer()->SetFlag(PLAYER_EXPLORED_ZONES_1+i,0); + } + } + + return true; +} + +bool ChatHandler::HandleHoverCommand(const char *args) +{ + char* px = strtok((char*)args, " "); + uint32 flag; + if (!px) + flag = 1; + else + flag = atoi(px); + + m_session->GetPlayer()->SetHover(flag); + + if (flag) + SendSysMessage(LANG_HOVER_ENABLED); + else + SendSysMessage(LANG_HOVER_DISABLED); + + return true; +} + +void ChatHandler::HandleCharacterLevel(Player* player, uint64 player_guid, uint32 oldlevel, uint32 newlevel) +{ + if (player) + { + player->GiveLevel(newlevel); + player->InitTalentForLevel(); + player->SetUInt32Value(PLAYER_XP,0); + + if (needReportToTarget(player)) + { + if (oldlevel == newlevel) + ChatHandler(player).PSendSysMessage(LANG_YOURS_LEVEL_PROGRESS_RESET,GetNameLink().c_str()); + else if (oldlevel < newlevel) + ChatHandler(player).PSendSysMessage(LANG_YOURS_LEVEL_UP,GetNameLink().c_str(),newlevel); + else // if (oldlevel > newlevel) + ChatHandler(player).PSendSysMessage(LANG_YOURS_LEVEL_DOWN,GetNameLink().c_str(),newlevel); + } + } + else + { + // update level and XP at level, all other will be updated at loading + CharacterDatabase.PExecute("UPDATE characters SET level = '%u', xp = 0 WHERE guid = '%u'", newlevel, GUID_LOPART(player_guid)); + } +} + +bool ChatHandler::HandleCharacterLevelCommand(const char *args) +{ + char* nameStr; + char* levelStr; + extractOptFirstArg((char*)args,&nameStr,&levelStr); + if (!levelStr) + return false; + + // exception opt second arg: .character level $name + if (isalpha(levelStr[0])) + { + nameStr = levelStr; + levelStr = NULL; // current level will used + } + + Player* target; + uint64 target_guid; + std::string target_name; + if (!extractPlayerTarget(nameStr,&target,&target_guid,&target_name)) + return false; + + int32 oldlevel = target ? target->getLevel() : Player::GetLevelFromDB(target_guid); + int32 newlevel = levelStr ? atoi(levelStr) : oldlevel; + + if (newlevel < 1) + return false; // invalid level + + if (newlevel > STRONG_MAX_LEVEL) // hardcoded maximum level + newlevel = STRONG_MAX_LEVEL; + + HandleCharacterLevel(target,target_guid,oldlevel,newlevel); + + if (!m_session || m_session->GetPlayer() != target) // including player == NULL + { + std::string nameLink = playerLink(target_name); + PSendSysMessage(LANG_YOU_CHANGE_LVL,nameLink.c_str(),newlevel); + } + + return true; +} + +bool ChatHandler::HandleLevelUpCommand(const char *args) +{ + char* nameStr; + char* levelStr; + extractOptFirstArg((char*)args,&nameStr,&levelStr); + + // exception opt second arg: .character level $name + if (levelStr && isalpha(levelStr[0])) + { + nameStr = levelStr; + levelStr = NULL; // current level will used + } + + Player* target; + uint64 target_guid; + std::string target_name; + if (!extractPlayerTarget(nameStr,&target,&target_guid,&target_name)) + return false; + + int32 oldlevel = target ? target->getLevel() : Player::GetLevelFromDB(target_guid); + int32 addlevel = levelStr ? atoi(levelStr) : 1; + int32 newlevel = oldlevel + addlevel; + + if (newlevel < 1) + newlevel = 1; + + if (newlevel > STRONG_MAX_LEVEL) // hardcoded maximum level + newlevel = STRONG_MAX_LEVEL; + + HandleCharacterLevel(target,target_guid,oldlevel,newlevel); + + if (!m_session || m_session->GetPlayer() != target) // including chr == NULL + { + std::string nameLink = playerLink(target_name); + PSendSysMessage(LANG_YOU_CHANGE_LVL,nameLink.c_str(),newlevel); + } + + return true; +} + +bool ChatHandler::HandleShowAreaCommand(const char *args) +{ + if (!*args) + return false; + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + int area = GetAreaFlagByAreaID(atoi((char*)args)); + int offset = area / 32; + uint32 val = (uint32)(1 << (area % 32)); + + if (area<0 || offset >= PLAYER_EXPLORED_ZONES_SIZE) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + uint32 currFields = chr->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); + chr->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields | val)); + + SendSysMessage(LANG_EXPLORE_AREA); + return true; +} + +bool ChatHandler::HandleHideAreaCommand(const char *args) +{ + if (!*args) + return false; + + Player *chr = getSelectedPlayer(); + if (chr == NULL) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + int area = GetAreaFlagByAreaID(atoi((char*)args)); + int offset = area / 32; + uint32 val = (uint32)(1 << (area % 32)); + + if (area<0 || offset >= PLAYER_EXPLORED_ZONES_SIZE) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + uint32 currFields = chr->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); + chr->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields ^ val)); + + SendSysMessage(LANG_UNEXPLORE_AREA); + return true; +} + +bool ChatHandler::HandleBankCommand(const char* /*args*/) +{ + m_session->SendShowBank(m_session->GetPlayer()->GetGUID()); + + return true; +} + +bool ChatHandler::HandleChangeWeather(const char *args) +{ + if (!*args) + return false; + + //Weather is OFF + if (!sWorld.getConfig(CONFIG_WEATHER)) + { + SendSysMessage(LANG_WEATHER_DISABLED); + SetSentErrorMessage(true); + return false; + } + + //*Change the weather of a cell + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + + if (!px || !py) + return false; + + uint32 type = (uint32)atoi(px); //0 to 3, 0: fine, 1: rain, 2: snow, 3: sand + float grade = (float)atof(py); //0 to 1, sending -1 is instand good weather + + Player *player = m_session->GetPlayer(); + uint32 zoneid = player->GetZoneId(); + + Weather* wth = sWorld.FindWeather(zoneid); + + if (!wth) + wth = sWorld.AddWeather(zoneid); + if (!wth) + { + SendSysMessage(LANG_NO_WEATHER); + SetSentErrorMessage(true); + return false; + } + + wth->SetWeather(WeatherType(type), grade); + + return true; +} + +bool ChatHandler::HandleDebugSet32Bit(const char *args) +{ + if (!*args) + return false; + + WorldObject* target = getSelectedObject(); + if (!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + + if (!px || !py) + return false; + + uint32 Opcode = (uint32)atoi(px); + uint32 Value = (uint32)atoi(py); + if (Value > 32) //uint32 = 32 bits + return false; + + sLog.outDebug(GetTrinityString(LANG_SET_32BIT), Opcode, Value); + + uint32 iValue = Value ? 1 << (Value - 1) : 0; + target->SetUInt32Value(Opcode , iValue); + + PSendSysMessage(LANG_SET_32BIT_FIELD, Opcode, iValue); + return true; +} + +bool ChatHandler::HandleTeleAddCommand(const char * args) +{ + if (!*args) + return false; + + Player *player=m_session->GetPlayer(); + if (!player) + return false; + + std::string name = args; + + if (objmgr.GetGameTele(name)) + { + SendSysMessage(LANG_COMMAND_TP_ALREADYEXIST); + SetSentErrorMessage(true); + return false; + } + + GameTele tele; + tele.position_x = player->GetPositionX(); + tele.position_y = player->GetPositionY(); + tele.position_z = player->GetPositionZ(); + tele.orientation = player->GetOrientation(); + tele.mapId = player->GetMapId(); + tele.name = name; + + if (objmgr.AddGameTele(tele)) + { + SendSysMessage(LANG_COMMAND_TP_ADDED); + } + else + { + SendSysMessage(LANG_COMMAND_TP_ADDEDERR); + SetSentErrorMessage(true); + return false; + } + + return true; +} + +bool ChatHandler::HandleTeleDelCommand(const char * args) +{ + if (!*args) + return false; + + std::string name = args; + + if (!objmgr.DeleteGameTele(name)) + { + SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); + SetSentErrorMessage(true); + return false; + } + + SendSysMessage(LANG_COMMAND_TP_DELETED); + return true; +} + +bool ChatHandler::HandleListAurasCommand (const char * /*args*/) +{ + Unit *unit = getSelectedUnit(); + if (!unit) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + char const* talentStr = GetTrinityString(LANG_TALENT); + char const* passiveStr = GetTrinityString(LANG_PASSIVE); + + Unit::AuraApplicationMap const& uAuras = unit->GetAppliedAuras(); + PSendSysMessage(LANG_COMMAND_TARGET_LISTAURAS, uAuras.size()); + for (Unit::AuraApplicationMap::const_iterator itr = uAuras.begin(); itr != uAuras.end(); ++itr) + { + bool talent = GetTalentSpellCost(itr->second->GetBase()->GetId()) > 0; + + AuraApplication const * aurApp = itr->second; + Aura const * aura = aurApp->GetBase(); + char const* name = aura->GetSpellProto()->SpellName[GetSessionDbcLocale()]; + + if (m_session) + { + std::ostringstream ss_name; + ss_name << "|cffffffff|Hspell:" << aura->GetId() << "|h[" << name << "]|h|r"; + + PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, aura->GetId(), aurApp->GetEffectMask(), + aura->GetCharges(), aura->GetStackAmount(), aurApp->GetSlot(), + aura->GetDuration(), aura->GetMaxDuration(), + ss_name.str().c_str(), + (aura->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), + IS_PLAYER_GUID(aura->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(aura->GetCasterGUID())); + } + else + { + PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, aura->GetId(), aurApp->GetEffectMask(), + aura->GetCharges(), aura->GetStackAmount(), aurApp->GetSlot(), + aura->GetDuration(), aura->GetMaxDuration(), + name, + (aura->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), + IS_PLAYER_GUID(aura->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(aura->GetCasterGUID())); + } + } + for (uint16 i = 0; i < TOTAL_AURAS; ++i) + { + Unit::AuraEffectList const& uAuraList = unit->GetAuraEffectsByType(AuraType(i)); + if (uAuraList.empty()) continue; + PSendSysMessage(LANG_COMMAND_TARGET_LISTAURATYPE, uAuraList.size(), i); + for (Unit::AuraEffectList::const_iterator itr = uAuraList.begin(); itr != uAuraList.end(); ++itr) + { + //bool talent = GetTalentSpellCost((*itr)->GetId()) > 0; + + char const* name = (*itr)->GetSpellProto()->SpellName[GetSessionDbcLocale()]; + + std::ostringstream ss_name; + ss_name << "|cffffffff|Hspell:" << (*itr)->GetId() << "|h[" << name << "]|h|r"; + + PSendSysMessage(LANG_COMMAND_TARGET_AURASIMPLE, (*itr)->GetId(), (*itr)->GetEffIndex(), + (*itr)->GetAmount()); + } + } + return true; +} + +bool ChatHandler::HandleResetAchievementsCommand (const char * args) +{ + Player* target; + uint64 target_guid; + if (!extractPlayerTarget((char*)args,&target,&target_guid)) + return false; + + if (target) + target->GetAchievementMgr().Reset(); + else + AchievementMgr::DeleteFromDB(GUID_LOPART(target_guid)); + + return true; +} + +bool ChatHandler::HandleResetHonorCommand (const char * args) +{ + Player* target; + if (!extractPlayerTarget((char*)args,&target)) + return false; + + target->SetUInt32Value(PLAYER_FIELD_KILLS, 0); + target->SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 0); + target->SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, 0); + target->SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0); + target->SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0); + target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL); + + return true; +} + +static bool HandleResetStatsOrLevelHelper(Player* player) +{ + ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(player->getClass()); + if (!cEntry) + { + sLog.outError("Class %u not found in DBC (Wrong DBC files?)",player->getClass()); + return false; + } + + uint8 powertype = cEntry->powerType; + + // reset m_form if no aura + if (!player->HasAuraType(SPELL_AURA_MOD_SHAPESHIFT)) + player->m_form = FORM_NONE; + + player->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE); + player->SetFloatValue(UNIT_FIELD_COMBATREACH, DEFAULT_COMBAT_REACH); + + player->setFactionForRace(player->getRace()); + + player->SetUInt32Value(UNIT_FIELD_BYTES_0, ((player->getRace()) | (player->getClass() << 8) | (player->getGender() << 16) | (powertype << 24))); + + // reset only if player not in some form; + if (player->m_form == FORM_NONE) + player->InitDisplayIds(); + + player->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); + player->SetByteValue(UNIT_FIELD_BYTES_2, 3, player->m_form); + + player->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + + //-1 is default value + player->SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1)); + + //player->SetUInt32Value(PLAYER_FIELD_BYTES, 0xEEE00000); + return true; +} + +bool ChatHandler::HandleResetLevelCommand(const char * args) +{ + Player* target; + if (!extractPlayerTarget((char*)args,&target)) + return false; + + if (!HandleResetStatsOrLevelHelper(target)) + return false; + + // set starting level + uint32 start_level = target->getClass() != CLASS_DEATH_KNIGHT + ? sWorld.getConfig(CONFIG_START_PLAYER_LEVEL) + : sWorld.getConfig(CONFIG_START_HEROIC_PLAYER_LEVEL); + + target->_ApplyAllLevelScaleItemMods(false); + + target->SetLevel(start_level); + target->InitRunes(); + target->InitStatsForLevel(true); + target->InitTaxiNodesForLevel(); + target->InitGlyphsForLevel(); + target->InitTalentForLevel(); + target->SetUInt32Value(PLAYER_XP,0); + + target->_ApplyAllLevelScaleItemMods(true); + + // reset level for pet + if (Pet* pet = target->GetPet()) + pet->SynchronizeLevelWithOwner(); + + return true; +} + +bool ChatHandler::HandleResetStatsCommand(const char * args) +{ + Player* target; + if (!extractPlayerTarget((char*)args,&target)) + return false; + + if (!HandleResetStatsOrLevelHelper(target)) + return false; + + target->InitRunes(); + target->InitStatsForLevel(true); + target->InitTaxiNodesForLevel(); + target->InitGlyphsForLevel(); + target->InitTalentForLevel(); + + return true; +} + +bool ChatHandler::HandleResetSpellsCommand(const char * args) +{ + Player* target; + uint64 target_guid; + std::string target_name; + if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) + return false; + + if (target) + { + target->resetSpells(/* bool myClassOnly */); + + ChatHandler(target).SendSysMessage(LANG_RESET_SPELLS); + if (!m_session || m_session->GetPlayer() != target) + PSendSysMessage(LANG_RESET_SPELLS_ONLINE,GetNameLink(target).c_str()); + } + else + { + CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",uint32(AT_LOGIN_RESET_SPELLS), GUID_LOPART(target_guid)); + PSendSysMessage(LANG_RESET_SPELLS_OFFLINE,target_name.c_str()); + } + + return true; +} + +bool ChatHandler::HandleResetTalentsCommand(const char * args) +{ + Player* target; + uint64 target_guid; + std::string target_name; + if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) + { + // Try reset talents as Hunter Pet + Creature* creature = getSelectedCreature(); + if (!*args && creature && creature->isPet()) + { + Unit *owner = creature->GetOwner(); + if (owner && owner->GetTypeId() == TYPEID_PLAYER && ((Pet *)creature)->IsPermanentPetFor(owner->ToPlayer())) + { + ((Pet *)creature)->resetTalents(true); + owner->ToPlayer()->SendTalentsInfoData(true); + + ChatHandler(owner->ToPlayer()).SendSysMessage(LANG_RESET_PET_TALENTS); + if (!m_session || m_session->GetPlayer() != owner->ToPlayer()) + PSendSysMessage(LANG_RESET_PET_TALENTS_ONLINE,GetNameLink(owner->ToPlayer()).c_str()); + } + return true; + } + + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + if (target) + { + target->resetTalents(true); + target->SendTalentsInfoData(false); + ChatHandler(target).SendSysMessage(LANG_RESET_TALENTS); + if (!m_session || m_session->GetPlayer() != target) + PSendSysMessage(LANG_RESET_TALENTS_ONLINE,GetNameLink(target).c_str()); + + Pet* pet = target->GetPet(); + Pet::resetTalentsForAllPetsOf(target,pet); + if (pet) + target->SendTalentsInfoData(true); + return true; + } + else if (target_guid) + { + uint32 at_flags = AT_LOGIN_NONE | AT_LOGIN_RESET_PET_TALENTS; + CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",at_flags, GUID_LOPART(target_guid)); + std::string nameLink = playerLink(target_name); + PSendSysMessage(LANG_RESET_TALENTS_OFFLINE,nameLink.c_str()); + return true; + } + + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; +} + +bool ChatHandler::HandleResetAllCommand(const char * args) +{ + if (!*args) + return false; + + std::string casename = args; + + AtLoginFlags atLogin; + + // Command specially created as single command to prevent using short case names + if (casename == "spells") + { + atLogin = AT_LOGIN_RESET_SPELLS; + sWorld.SendWorldText(LANG_RESETALL_SPELLS); + if (!m_session) + SendSysMessage(LANG_RESETALL_SPELLS); + } + else if (casename == "talents") + { + atLogin = AtLoginFlags(AT_LOGIN_RESET_TALENTS | AT_LOGIN_RESET_PET_TALENTS); + sWorld.SendWorldText(LANG_RESETALL_TALENTS); + if (!m_session) + SendSysMessage(LANG_RESETALL_TALENTS); + } + else + { + PSendSysMessage(LANG_RESETALL_UNKNOWN_CASE,args); + SetSentErrorMessage(true); + return false; + } + + CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE (at_login & '%u') = '0'",atLogin,atLogin); + + ObjectAccessor::Guard guard(*HashMapHolder::GetLock()); + HashMapHolder::MapType const& plist = ObjectAccessor::Instance().GetPlayers(); + for (HashMapHolder::MapType::const_iterator itr = plist.begin(); itr != plist.end(); ++itr) + itr->second->SetAtLoginFlag(atLogin); + + return true; +} + +bool ChatHandler::HandleServerShutDownCancelCommand(const char* /*args*/) +{ + sWorld.ShutdownCancel(); + return true; +} + +bool ChatHandler::HandleServerShutDownCommand(const char *args) +{ + if (!*args) + return false; + + char* time_str = strtok ((char*) args, " "); + char* exitcode_str = strtok (NULL, ""); + + int32 time = atoi (time_str); + + ///- Prevent interpret wrong arg value as 0 secs shutdown time + if ((time == 0 && (time_str[0] != '0' || time_str[1] != '\0')) || time < 0) + return false; + + if (exitcode_str) + { + int32 exitcode = atoi (exitcode_str); + + // Handle atoi() errors + if (exitcode == 0 && (exitcode_str[0] != '0' || exitcode_str[1] != '\0')) + return false; + + // Exit code should be in range of 0-125, 126-255 is used + // in many shells for their own return codes and code > 255 + // is not supported in many others + if (exitcode < 0 || exitcode > 125) + return false; + + sWorld.ShutdownServ (time, 0, exitcode); + } + else + sWorld.ShutdownServ(time,0,SHUTDOWN_EXIT_CODE); + return true; +} + +bool ChatHandler::HandleServerRestartCommand(const char *args) +{ + if (!*args) + return false; + + char* time_str = strtok ((char*) args, " "); + char* exitcode_str = strtok (NULL, ""); + + int32 time = atoi (time_str); + + ///- Prevent interpret wrong arg value as 0 secs shutdown time + if ((time == 0 && (time_str[0] != '0' || time_str[1] != '\0') || time < 0)) + return false; + + if (exitcode_str) + { + int32 exitcode = atoi (exitcode_str); + + // Handle atoi() errors + if (exitcode == 0 && (exitcode_str[0] != '0' || exitcode_str[1] != '\0')) + return false; + + // Exit code should be in range of 0-125, 126-255 is used + // in many shells for their own return codes and code > 255 + // is not supported in many others + if (exitcode < 0 || exitcode > 125) + return false; + + sWorld.ShutdownServ (time, SHUTDOWN_MASK_RESTART, exitcode); + } + else + sWorld.ShutdownServ(time, SHUTDOWN_MASK_RESTART, RESTART_EXIT_CODE); + return true; +} + +bool ChatHandler::HandleServerIdleRestartCommand(const char *args) +{ + if (!*args) + return false; + + char* time_str = strtok ((char*) args, " "); + char* exitcode_str = strtok (NULL, ""); + + int32 time = atoi (time_str); + + ///- Prevent interpret wrong arg value as 0 secs shutdown time + if ((time == 0 && (time_str[0] != '0' || time_str[1] != '\0') || time < 0)) + return false; + + if (exitcode_str) + { + int32 exitcode = atoi (exitcode_str); + + // Handle atoi() errors + if (exitcode == 0 && (exitcode_str[0] != '0' || exitcode_str[1] != '\0')) + return false; + + // Exit code should be in range of 0-125, 126-255 is used + // in many shells for their own return codes and code > 255 + // is not supported in many others + if (exitcode < 0 || exitcode > 125) + return false; + + sWorld.ShutdownServ (time, SHUTDOWN_MASK_RESTART|SHUTDOWN_MASK_IDLE, exitcode); + } + else + sWorld.ShutdownServ(time,SHUTDOWN_MASK_RESTART|SHUTDOWN_MASK_IDLE,RESTART_EXIT_CODE); + return true; +} + +bool ChatHandler::HandleServerIdleShutDownCommand(const char *args) +{ + if (!*args) + return false; + + char* time_str = strtok ((char*) args, " "); + char* exitcode_str = strtok (NULL, ""); + + int32 time = atoi (time_str); + + ///- Prevent interpret wrong arg value as 0 secs shutdown time + if (time == 0 && (time_str[0] != '0' || time_str[1] != '\0') || time < 0) + return false; + + if (exitcode_str) + { + int32 exitcode = atoi (exitcode_str); + + // Handle atoi() errors + if (exitcode == 0 && (exitcode_str[0] != '0' || exitcode_str[1] != '\0')) + return false; + + // Exit code should be in range of 0-125, 126-255 is used + // in many shells for their own return codes and code > 255 + // is not supported in many others + if (exitcode < 0 || exitcode > 125) + return false; + + sWorld.ShutdownServ (time, SHUTDOWN_MASK_IDLE, exitcode); + } + else + sWorld.ShutdownServ(time,SHUTDOWN_MASK_IDLE,SHUTDOWN_EXIT_CODE); + return true; +} + +bool ChatHandler::HandleQuestAdd(const char *args) +{ + Player* player = getSelectedPlayer(); + if (!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // .addquest #entry' + // number or [name] Shift-click form |color|Hquest:quest_id:quest_level|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hquest"); + if (!cId) + return false; + + uint32 entry = atol(cId); + + Quest const* pQuest = objmgr.GetQuestTemplate(entry); + + if (!pQuest) + { + PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND,entry); + SetSentErrorMessage(true); + return false; + } + + // check item starting quest (it can work incorrectly if added without item in inventory) + for (uint32 id = 0; id < sItemStorage.MaxEntry; id++) + { + ItemPrototype const *pProto = sItemStorage.LookupEntry(id); + if (!pProto) + continue; + + if (pProto->StartQuest == entry) + { + PSendSysMessage(LANG_COMMAND_QUEST_STARTFROMITEM, entry, pProto->ItemId); + SetSentErrorMessage(true); + return false; + } + } + + // ok, normal (creature/GO starting) quest + if (player->CanAddQuest(pQuest, true)) + { + player->AddQuest(pQuest, NULL); + + if (player->CanCompleteQuest(entry)) + player->CompleteQuest(entry); + } + + return true; +} + +bool ChatHandler::HandleQuestRemove(const char *args) +{ + Player* player = getSelectedPlayer(); + if (!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // .removequest #entry' + // number or [name] Shift-click form |color|Hquest:quest_id:quest_level|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hquest"); + if (!cId) + return false; + + uint32 entry = atol(cId); + + Quest const* pQuest = objmgr.GetQuestTemplate(entry); + + if (!pQuest) + { + PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND, entry); + SetSentErrorMessage(true); + return false; + } + + // remove all quest entries for 'entry' from quest log + for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 quest = player->GetQuestSlotQuestId(slot); + if (quest == entry) + { + player->SetQuestSlot(slot,0); + + // we ignore unequippable quest items in this case, its' still be equipped + player->TakeQuestSourceItem(quest, false); + } + } + + // set quest status to not started (will updated in DB at next save) + player->SetQuestStatus(entry, QUEST_STATUS_NONE); + + // reset rewarded for restart repeatable quest + player->getQuestStatusMap()[entry].m_rewarded = false; + + SendSysMessage(LANG_COMMAND_QUEST_REMOVED); + return true; +} + +bool ChatHandler::HandleQuestComplete(const char *args) +{ + Player* player = getSelectedPlayer(); + if (!player) + { + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + + // .quest complete #entry + // number or [name] Shift-click form |color|Hquest:quest_id:quest_level|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hquest"); + if (!cId) + return false; + + uint32 entry = atol(cId); + + Quest const* pQuest = objmgr.GetQuestTemplate(entry); + + // If player doesn't have the quest + if (!pQuest || player->GetQuestStatus(entry) == QUEST_STATUS_NONE) + { + PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND, entry); + SetSentErrorMessage(true); + return false; + } + + // Add quest items for quests that require items + for (uint8 x = 0; x < QUEST_ITEM_OBJECTIVES_COUNT; ++x) + { + uint32 id = pQuest->ReqItemId[x]; + uint32 count = pQuest->ReqItemCount[x]; + if (!id || !count) + continue; + + uint32 curItemCount = player->GetItemCount(id,true); + + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, id, count-curItemCount); + if (msg == EQUIP_ERR_OK) + { + Item* item = player->StoreNewItem(dest, id, true); + player->SendNewItem(item,count-curItemCount,true,false); + } + } + + // All creature/GO slain/casted (not required, but otherwise it will display "Creature slain 0/10") + for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + { + uint32 creature = pQuest->ReqCreatureOrGOId[i]; + uint32 creaturecount = pQuest->ReqCreatureOrGOCount[i]; + + if (uint32 spell_id = pQuest->ReqSpell[i]) + { + for (uint16 z = 0; z < creaturecount; ++z) + player->CastedCreatureOrGO(creature,0,spell_id); + } + else if (creature > 0) + { + if (CreatureInfo const* cInfo = objmgr.GetCreatureTemplate(creature)) + for (uint16 z = 0; z < creaturecount; ++z) + player->KilledMonster(cInfo,0); + } + else if (creature < 0) + { + for (uint16 z = 0; z < creaturecount; ++z) + player->CastedCreatureOrGO(creature,0,0); + } + } + + // If the quest requires reputation to complete + if (uint32 repFaction = pQuest->GetRepObjectiveFaction()) + { + uint32 repValue = pQuest->GetRepObjectiveValue(); + uint32 curRep = player->GetReputationMgr().GetReputation(repFaction); + if (curRep < repValue) + if (FactionEntry const *factionEntry = sFactionStore.LookupEntry(repFaction)) + player->GetReputationMgr().SetReputation(factionEntry,repValue); + } + + // If the quest requires a SECOND reputation to complete + if (uint32 repFaction = pQuest->GetRepObjectiveFaction2()) + { + uint32 repValue2 = pQuest->GetRepObjectiveValue2(); + uint32 curRep = player->GetReputationMgr().GetReputation(repFaction); + if (curRep < repValue2) + if (FactionEntry const *factionEntry = sFactionStore.LookupEntry(repFaction)) + player->GetReputationMgr().SetReputation(factionEntry,repValue2); + } + + // If the quest requires money + int32 ReqOrRewMoney = pQuest->GetRewOrReqMoney(); + if (ReqOrRewMoney < 0) + player->ModifyMoney(-ReqOrRewMoney); + + player->CompleteQuest(entry); + return true; +} + +bool ChatHandler::HandleBanAccountCommand(const char *args) +{ + return HandleBanHelper(BAN_ACCOUNT,args); +} + +bool ChatHandler::HandleBanCharacterCommand(const char *args) +{ + return HandleBanHelper(BAN_CHARACTER,args); +} + +bool ChatHandler::HandleBanIPCommand(const char *args) +{ + return HandleBanHelper(BAN_IP,args); +} + +bool ChatHandler::HandleBanHelper(BanMode mode, const char *args) +{ + if (!*args) + return false; + + char* cnameOrIP = strtok ((char*)args, " "); + if (!cnameOrIP) + return false; + + std::string nameOrIP = cnameOrIP; + + char* duration = strtok (NULL," "); + if (!duration || !atoi(duration)) + return false; + + char* reason = strtok (NULL,""); + if (!reason) + return false; + + switch(mode) + { + case BAN_ACCOUNT: + if (!AccountMgr::normalizeString(nameOrIP)) + { + PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,nameOrIP.c_str()); + SetSentErrorMessage(true); + return false; + } + break; + case BAN_CHARACTER: + if (!normalizePlayerName(nameOrIP)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + break; + case BAN_IP: + if (!IsIPAddress(nameOrIP.c_str())) + return false; + break; + } + + switch(sWorld.BanAccount(mode, nameOrIP, duration, reason,m_session ? m_session->GetPlayerName() : "")) + { + case BAN_SUCCESS: + if (atoi(duration)>0) + PSendSysMessage(LANG_BAN_YOUBANNED,nameOrIP.c_str(),secsToTimeString(TimeStringToSecs(duration),true).c_str(),reason); + else + PSendSysMessage(LANG_BAN_YOUPERMBANNED,nameOrIP.c_str(),reason); + break; + case BAN_SYNTAX_ERROR: + return false; + case BAN_NOTFOUND: + switch(mode) + { + default: + PSendSysMessage(LANG_BAN_NOTFOUND,"account",nameOrIP.c_str()); + break; + case BAN_CHARACTER: + PSendSysMessage(LANG_BAN_NOTFOUND,"character",nameOrIP.c_str()); + break; + case BAN_IP: + PSendSysMessage(LANG_BAN_NOTFOUND,"ip",nameOrIP.c_str()); + break; + } + SetSentErrorMessage(true); + return false; + } + + return true; +} + +bool ChatHandler::HandleUnBanAccountCommand(const char *args) +{ + return HandleUnBanHelper(BAN_ACCOUNT,args); +} + +bool ChatHandler::HandleUnBanCharacterCommand(const char *args) +{ + return HandleUnBanHelper(BAN_CHARACTER,args); +} + +bool ChatHandler::HandleUnBanIPCommand(const char *args) +{ + return HandleUnBanHelper(BAN_IP,args); +} + +bool ChatHandler::HandleUnBanHelper(BanMode mode, const char *args) +{ + if (!*args) + return false; + + char* cnameOrIP = strtok ((char*)args, " "); + if (!cnameOrIP) + return false; + + std::string nameOrIP = cnameOrIP; + + switch(mode) + { + case BAN_ACCOUNT: + if (!AccountMgr::normalizeString(nameOrIP)) + { + PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,nameOrIP.c_str()); + SetSentErrorMessage(true); + return false; + } + break; + case BAN_CHARACTER: + if (!normalizePlayerName(nameOrIP)) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + break; + case BAN_IP: + if (!IsIPAddress(nameOrIP.c_str())) + return false; + break; + } + + if (sWorld.RemoveBanAccount(mode,nameOrIP)) + PSendSysMessage(LANG_UNBAN_UNBANNED,nameOrIP.c_str()); + else + PSendSysMessage(LANG_UNBAN_ERROR,nameOrIP.c_str()); + + return true; +} + +bool ChatHandler::HandleBanInfoAccountCommand(const char *args) +{ + if (!*args) + return false; + + char* cname = strtok((char*)args, ""); + if (!cname) + return false; + + std::string account_name = cname; + if (!AccountMgr::normalizeString(account_name)) + { + PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); + SetSentErrorMessage(true); + return false; + } + + uint32 accountid = accmgr.GetId(account_name); + if (!accountid) + { + PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); + return true; + } + + return HandleBanInfoHelper(accountid,account_name.c_str()); +} + +bool ChatHandler::HandleBanInfoCharacterCommand(const char *args) +{ + Player* target; + uint64 target_guid; + if (!extractPlayerTarget((char*)args,&target,&target_guid)) + return false; + + uint32 accountid = target ? target->GetSession()->GetAccountId() : objmgr.GetPlayerAccountIdByGUID(target_guid); + + std::string accountname; + if (!accmgr.GetName(accountid,accountname)) + { + PSendSysMessage(LANG_BANINFO_NOCHARACTER); + return true; + } + + return HandleBanInfoHelper(accountid,accountname.c_str()); +} + +bool ChatHandler::HandleBanInfoHelper(uint32 accountid, char const* accountname) +{ + QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT FROM_UNIXTIME(bandate), unbandate-bandate, active, unbandate,banreason,bannedby FROM account_banned WHERE id = '%u' ORDER BY bandate ASC",accountid); + if (!result) + { + PSendSysMessage(LANG_BANINFO_NOACCOUNTBAN, accountname); + return true; + } + + PSendSysMessage(LANG_BANINFO_BANHISTORY,accountname); + do + { + Field* fields = result->Fetch(); + + time_t unbandate = time_t(fields[3].GetUInt64()); + bool active = false; + if (fields[2].GetBool() && (fields[1].GetUInt64() == (uint64)0 ||unbandate >= time(NULL))) + active = true; + bool permanent = (fields[1].GetUInt64() == (uint64)0); + std::string bantime = permanent?GetTrinityString(LANG_BANINFO_INFINITE):secsToTimeString(fields[1].GetUInt64(), true); + PSendSysMessage(LANG_BANINFO_HISTORYENTRY, + fields[0].GetString(), bantime.c_str(), active ? GetTrinityString(LANG_BANINFO_YES):GetTrinityString(LANG_BANINFO_NO), fields[4].GetString(), fields[5].GetString()); + }while (result->NextRow()); + + return true; +} + +bool ChatHandler::HandleBanInfoIPCommand(const char *args) +{ + if (!*args) + return false; + + char* cIP = strtok ((char*)args, ""); + if (!cIP) + return false; + + if (!IsIPAddress(cIP)) + return false; + + std::string IP = cIP; + + LoginDatabase.escape_string(IP); + QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT ip, FROM_UNIXTIME(bandate), FROM_UNIXTIME(unbandate), unbandate-UNIX_TIMESTAMP(), banreason,bannedby,unbandate-bandate FROM ip_banned WHERE ip = '%s'",IP.c_str()); + if (!result) + { + PSendSysMessage(LANG_BANINFO_NOIP); + return true; + } + + Field *fields = result->Fetch(); + bool permanent = !fields[6].GetUInt64(); + PSendSysMessage(LANG_BANINFO_IPENTRY, + fields[0].GetString(), fields[1].GetString(), permanent ? GetTrinityString(LANG_BANINFO_NEVER):fields[2].GetString(), + permanent ? GetTrinityString(LANG_BANINFO_INFINITE):secsToTimeString(fields[3].GetUInt64(), true).c_str(), fields[4].GetString(), fields[5].GetString()); + + return true; +} + +bool ChatHandler::HandleBanListCharacterCommand(const char *args) +{ + LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate<>bandate"); + + char* cFilter = strtok ((char*)args, " "); + if (!cFilter) + return false; + + std::string filter = cFilter; + LoginDatabase.escape_string(filter); + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'"),filter.c_str()); + if (!result) + { + PSendSysMessage(LANG_BANLIST_NOCHARACTER); + return true; + } + + return HandleBanListHelper(result); +} + +bool ChatHandler::HandleBanListAccountCommand(const char *args) +{ + LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate<>bandate"); + + char* cFilter = strtok((char*)args, " "); + std::string filter = cFilter ? cFilter : ""; + LoginDatabase.escape_string(filter); + + QueryResult_AutoPtr result; + + if (filter.empty()) + { + result = LoginDatabase.Query("SELECT account.id, username FROM account, account_banned" + " WHERE account.id = account_banned.id AND active = 1 GROUP BY account.id"); + } + else + { + result = LoginDatabase.PQuery("SELECT account.id, username FROM account, account_banned" + " WHERE account.id = account_banned.id AND active = 1 AND username "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")" GROUP BY account.id", + filter.c_str()); + } + + if (!result) + { + PSendSysMessage(LANG_BANLIST_NOACCOUNT); + return true; + } + + return HandleBanListHelper(result); +} + +bool ChatHandler::HandleBanListHelper(QueryResult_AutoPtr result) +{ + PSendSysMessage(LANG_BANLIST_MATCHINGACCOUNT); + + // Chat short output + if (m_session) + { + do + { + Field* fields = result->Fetch(); + uint32 accountid = fields[0].GetUInt32(); + + QueryResult_AutoPtr banresult = LoginDatabase.PQuery("SELECT account.username FROM account,account_banned WHERE account_banned.id='%u' AND account_banned.id=account.id",accountid); + if (banresult) + { + Field* fields2 = banresult->Fetch(); + PSendSysMessage("%s",fields2[0].GetString()); + } + } while (result->NextRow()); + } + // Console wide output + else + { + SendSysMessage(LANG_BANLIST_ACCOUNTS); + SendSysMessage(" ==============================================================================="); + SendSysMessage(LANG_BANLIST_ACCOUNTS_HEADER); + do + { + SendSysMessage("-------------------------------------------------------------------------------"); + Field *fields = result->Fetch(); + uint32 account_id = fields[0].GetUInt32 (); + + std::string account_name; + + // "account" case, name can be get in same query + if (result->GetFieldCount() > 1) + account_name = fields[1].GetCppString(); + // "character" case, name need extract from another DB + else + accmgr.GetName (account_id,account_name); + + // No SQL injection. id is uint32. + QueryResult_AutoPtr banInfo = LoginDatabase.PQuery("SELECT bandate,unbandate,bannedby,banreason FROM account_banned WHERE id = %u ORDER BY unbandate", account_id); + if (banInfo) + { + Field *fields2 = banInfo->Fetch(); + do + { + time_t t_ban = fields2[0].GetUInt64(); + tm* aTm_ban = localtime(&t_ban); + + if (fields2[0].GetUInt64() == fields2[1].GetUInt64()) + { + PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d| permanent |%-15.15s|%-15.15s|", + account_name.c_str(),aTm_ban->tm_year%100, aTm_ban->tm_mon+1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min, + fields2[2].GetString(),fields2[3].GetString()); + } + else + { + time_t t_unban = fields2[1].GetUInt64(); + tm* aTm_unban = localtime(&t_unban); + PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d|%02d-%02d-%02d %02d:%02d|%-15.15s|%-15.15s|", + account_name.c_str(),aTm_ban->tm_year%100, aTm_ban->tm_mon+1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min, + aTm_unban->tm_year%100, aTm_unban->tm_mon+1, aTm_unban->tm_mday, aTm_unban->tm_hour, aTm_unban->tm_min, + fields2[2].GetString(),fields2[3].GetString()); + } + }while (banInfo->NextRow()); + } + }while (result->NextRow()); + SendSysMessage(" ==============================================================================="); + } + return true; +} + +bool ChatHandler::HandleBanListIPCommand(const char *args) +{ + LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate<>bandate"); + + char* cFilter = strtok((char*)args, " "); + std::string filter = cFilter ? cFilter : ""; + LoginDatabase.escape_string(filter); + + QueryResult_AutoPtr result; + + if (filter.empty()) + { + result = LoginDatabase.Query ("SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned" + " WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP())" + " ORDER BY unbandate"); + } + else + { + result = LoginDatabase.PQuery("SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned" + " WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP()) AND ip "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'") + " ORDER BY unbandate",filter.c_str()); + } + + if (!result) + { + PSendSysMessage(LANG_BANLIST_NOIP); + return true; + } + + PSendSysMessage(LANG_BANLIST_MATCHINGIP); + // Chat short output + if (m_session) + { + do + { + Field* fields = result->Fetch(); + PSendSysMessage("%s",fields[0].GetString()); + } while (result->NextRow()); + } + // Console wide output + else + { + SendSysMessage(LANG_BANLIST_IPS); + SendSysMessage(" ==============================================================================="); + SendSysMessage(LANG_BANLIST_IPS_HEADER); + do + { + SendSysMessage("-------------------------------------------------------------------------------"); + Field *fields = result->Fetch(); + time_t t_ban = fields[1].GetUInt64(); + tm* aTm_ban = localtime(&t_ban); + if (fields[1].GetUInt64() == fields[2].GetUInt64()) + { + PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d| permanent |%-15.15s|%-15.15s|", + fields[0].GetString(), aTm_ban->tm_year%100, aTm_ban->tm_mon+1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min, + fields[3].GetString(), fields[4].GetString()); + } + else + { + time_t t_unban = fields[2].GetUInt64(); + tm* aTm_unban = localtime(&t_unban); + PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d|%02d-%02d-%02d %02d:%02d|%-15.15s|%-15.15s|", + fields[0].GetString(), aTm_ban->tm_year%100, aTm_ban->tm_mon+1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min, + aTm_unban->tm_year%100, aTm_unban->tm_mon+1, aTm_unban->tm_mday, aTm_unban->tm_hour, aTm_unban->tm_min, + fields[3].GetString(), fields[4].GetString()); + } + }while (result->NextRow()); + SendSysMessage(" ==============================================================================="); + } + + return true; +} + +bool ChatHandler::HandleRespawnCommand(const char* /*args*/) +{ + Player* pl = m_session->GetPlayer(); + + // accept only explicitly selected target (not implicitly self targeting case) + Unit* target = getSelectedUnit(); + if (pl->GetSelection() && target) + { + if (target->GetTypeId() != TYPEID_UNIT || target->isPet()) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if (target->isDead()) + target->ToCreature()->Respawn(); + return true; + } + + CellPair p(Trinity::ComputeCellPair(pl->GetPositionX(), pl->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + Trinity::RespawnDo u_do; + Trinity::WorldObjectWorker worker(pl,u_do); + + TypeContainerVisitor, GridTypeMapContainer > obj_worker(worker); + cell.Visit(p, obj_worker, *pl->GetMap()); + + return true; +} + +bool ChatHandler::HandleGMFlyCommand(const char *args) +{ + if (!*args) + return false; + + Player *target = getSelectedPlayer(); + if (!target) + target = m_session->GetPlayer(); + + WorldPacket data(12); + if (strncmp(args, "on", 3) == 0) + data.SetOpcode(SMSG_MOVE_SET_CAN_FLY); + else if (strncmp(args, "off", 4) == 0) + data.SetOpcode(SMSG_MOVE_UNSET_CAN_FLY); + else + { + SendSysMessage(LANG_USE_BOL); + return false; + } + data.append(target->GetPackGUID()); + data << uint32(0); // unknown + target->SendMessageToSet(&data, true); + PSendSysMessage(LANG_COMMAND_FLYMODE_STATUS, GetNameLink(target).c_str(), args); + return true; +} + +bool ChatHandler::HandlePDumpLoadCommand(const char *args) +{ + if (!*args) + return false; + + char * file = strtok((char*)args, " "); + if (!file) + return false; + + char * account = strtok(NULL, " "); + if (!account) + return false; + + std::string account_name = account; + if (!AccountMgr::normalizeString(account_name)) + { + PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); + SetSentErrorMessage(true); + return false; + } + + uint32 account_id = accmgr.GetId(account_name); + if (!account_id) + { + account_id = atoi(account); // use original string + if (!account_id) + { + PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); + SetSentErrorMessage(true); + return false; + } + } + + if (!accmgr.GetName(account_id,account_name)) + { + PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); + SetSentErrorMessage(true); + return false; + } + + char* guid_str = NULL; + char* name_str = strtok(NULL, " "); + + std::string name; + if (name_str) + { + name = name_str; + // normalize the name if specified and check if it exists + if (!normalizePlayerName(name)) + { + PSendSysMessage(LANG_INVALID_CHARACTER_NAME); + SetSentErrorMessage(true); + return false; + } + + if (ObjectMgr::CheckPlayerName(name,true) != CHAR_NAME_SUCCESS) + { + PSendSysMessage(LANG_INVALID_CHARACTER_NAME); + SetSentErrorMessage(true); + return false; + } + + guid_str = strtok(NULL, " "); + } + + uint32 guid = 0; + + if (guid_str) + { + guid = atoi(guid_str); + if (!guid) + { + PSendSysMessage(LANG_INVALID_CHARACTER_GUID); + SetSentErrorMessage(true); + return false; + } + + if (objmgr.GetPlayerAccountIdByGUID(guid)) + { + PSendSysMessage(LANG_CHARACTER_GUID_IN_USE,guid); + SetSentErrorMessage(true); + return false; + } + } + + switch(PlayerDumpReader().LoadDump(file, account_id, name, guid)) + { + case DUMP_SUCCESS: + PSendSysMessage(LANG_COMMAND_IMPORT_SUCCESS); + break; + case DUMP_FILE_OPEN_ERROR: + PSendSysMessage(LANG_FILE_OPEN_FAIL,file); + SetSentErrorMessage(true); + return false; + case DUMP_FILE_BROKEN: + PSendSysMessage(LANG_DUMP_BROKEN,file); + SetSentErrorMessage(true); + return false; + case DUMP_TOO_MANY_CHARS: + PSendSysMessage(LANG_ACCOUNT_CHARACTER_LIST_FULL,account_name.c_str(),account_id); + SetSentErrorMessage(true); + return false; + default: + PSendSysMessage(LANG_COMMAND_IMPORT_FAILED); + SetSentErrorMessage(true); + return false; + } + + return true; +} + +bool ChatHandler::HandlePDumpWriteCommand(const char *args) +{ + if (!*args) + return false; + + char* file = strtok((char*)args, " "); + char* p2 = strtok(NULL, " "); + + if (!file || !p2) + return false; + + uint32 guid; + // character name can't start from number + if (isNumeric(p2[0])) + guid = atoi(p2); + else + { + std::string name = extractPlayerNameFromLink(p2); + if (name.empty()) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + guid = objmgr.GetPlayerGUIDByName(name); + } + + if (!objmgr.GetPlayerAccountIdByGUID(guid)) + { + PSendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + switch(PlayerDumpWriter().WriteDump(file, guid)) + { + case DUMP_SUCCESS: + PSendSysMessage(LANG_COMMAND_EXPORT_SUCCESS); + break; + case DUMP_FILE_OPEN_ERROR: + PSendSysMessage(LANG_FILE_OPEN_FAIL,file); + SetSentErrorMessage(true); + return false; + default: + PSendSysMessage(LANG_COMMAND_EXPORT_FAILED); + SetSentErrorMessage(true); + return false; + } + + return true; +} + +bool ChatHandler::HandleMovegensCommand(const char* /*args*/) +{ + Unit* unit = getSelectedUnit(); + if (!unit) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + PSendSysMessage(LANG_MOVEGENS_LIST,(unit->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"),unit->GetGUIDLow()); + + MotionMaster* mm = unit->GetMotionMaster(); + for (uint8 i = 0; i < MAX_MOTION_SLOT; ++i) + { + MovementGenerator* mg = mm->GetMotionSlot(i); + if (!mg) + { + SendSysMessage("Empty"); + continue; + } + switch(mg->GetMovementGeneratorType()) + { + case IDLE_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_IDLE); break; + case RANDOM_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_RANDOM); break; + case WAYPOINT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_WAYPOINT); break; + case ANIMAL_RANDOM_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_ANIMAL_RANDOM); break; + case CONFUSED_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_CONFUSED); break; + case TARGETED_MOTION_TYPE: + { + if (unit->GetTypeId() == TYPEID_PLAYER) + { + TargetedMovementGenerator const* mgen = static_cast const*>(mg); + Unit* target = mgen->GetTarget(); + if (target) + PSendSysMessage(LANG_MOVEGENS_TARGETED_PLAYER,target->GetName(),target->GetGUIDLow()); + else + SendSysMessage(LANG_MOVEGENS_TARGETED_NULL); + } + else + { + TargetedMovementGenerator const* mgen = static_cast const*>(mg); + Unit* target = mgen->GetTarget(); + if (target) + PSendSysMessage(LANG_MOVEGENS_TARGETED_CREATURE,target->GetName(),target->GetGUIDLow()); + else + SendSysMessage(LANG_MOVEGENS_TARGETED_NULL); + } + break; + } + case HOME_MOTION_TYPE: + if (unit->GetTypeId() == TYPEID_UNIT) + { + float x,y,z; + mg->GetDestination(x,y,z); + PSendSysMessage(LANG_MOVEGENS_HOME_CREATURE,x,y,z); + } + else + SendSysMessage(LANG_MOVEGENS_HOME_PLAYER); + break; + case FLIGHT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FLIGHT); break; + case POINT_MOTION_TYPE: + { + float x,y,z; + mg->GetDestination(x,y,z); + PSendSysMessage(LANG_MOVEGENS_POINT,x,y,z); + break; + } + case FLEEING_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FEAR); break; + case DISTRACT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_DISTRACT); break; + default: + PSendSysMessage(LANG_MOVEGENS_UNKNOWN,mg->GetMovementGeneratorType()); + break; + } + } + return true; +} + +bool ChatHandler::HandleServerPLimitCommand(const char *args) +{ + if (*args) + { + char* param = strtok((char*)args, " "); + if (!param) + return false; + + int l = strlen(param); + + if (strncmp(param,"player",l) == 0) + sWorld.SetPlayerSecurityLimit(SEC_PLAYER); + else if (strncmp(param,"moderator",l) == 0) + sWorld.SetPlayerSecurityLimit(SEC_MODERATOR); + else if (strncmp(param,"gamemaster",l) == 0) + sWorld.SetPlayerSecurityLimit(SEC_GAMEMASTER); + else if (strncmp(param,"administrator",l) == 0) + sWorld.SetPlayerSecurityLimit(SEC_ADMINISTRATOR); + else if (strncmp(param,"reset",l) == 0) + sWorld.SetPlayerLimit(sConfig.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT)); + else + { + int val = atoi(param); + if (val < 0) + sWorld.SetPlayerSecurityLimit(AccountTypes(uint32(-val))); + else + sWorld.SetPlayerLimit(val); + } + + // kick all low security level players + if (sWorld.GetPlayerSecurityLimit() > SEC_PLAYER) + sWorld.KickAllLess(sWorld.GetPlayerSecurityLimit()); + } + + uint32 pLimit = sWorld.GetPlayerAmountLimit(); + AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit(); + char const* secName = ""; + switch(allowedAccountType) + { + case SEC_PLAYER: secName = "Player"; break; + case SEC_MODERATOR: secName = "Moderator"; break; + case SEC_GAMEMASTER: secName = "Gamemaster"; break; + case SEC_ADMINISTRATOR: secName = "Administrator"; break; + default: secName = ""; break; + } + + PSendSysMessage("Player limits: amount %u, min. security level %s.",pLimit,secName); + + return true; +} + +bool ChatHandler::HandleCastCommand(const char *args) +{ + if (!*args) + return false; + + Unit* target = getSelectedUnit(); + + if (!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spell = extractSpellIdFromLink((char*)args); + if (!spell) + return false; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); + if (!spellInfo) + { + PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); + SetSentErrorMessage(true); + return false; + } + + if (!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) + { + PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); + SetSentErrorMessage(true); + return false; + } + + char* trig_str = strtok(NULL, " "); + if (trig_str) + { + int l = strlen(trig_str); + if (strncmp(trig_str,"triggered",l) != 0) + return false; + } + + bool triggered = (trig_str != NULL); + + m_session->GetPlayer()->CastSpell(target,spell,triggered); + + return true; +} + +bool ChatHandler::HandleCastBackCommand(const char *args) +{ + Creature* caster = getSelectedCreature(); + + if (!caster) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spell = extractSpellIdFromLink((char*)args); + if (!spell || !sSpellStore.LookupEntry(spell)) + { + PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); + SetSentErrorMessage(true); + return false; + } + + char* trig_str = strtok(NULL, " "); + if (trig_str) + { + int l = strlen(trig_str); + if (strncmp(trig_str,"triggered",l) != 0) + return false; + } + + bool triggered = (trig_str != NULL); + + caster->SetFacingToObject(m_session->GetPlayer()); + + caster->CastSpell(m_session->GetPlayer(),spell,triggered); + + return true; +} + +bool ChatHandler::HandleCastDistCommand(const char *args) +{ + if (!*args) + return false; + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spell = extractSpellIdFromLink((char*)args); + if (!spell) + return false; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); + if (!spellInfo) + { + PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); + SetSentErrorMessage(true); + return false; + } + + if (!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) + { + PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); + SetSentErrorMessage(true); + return false; + } + + char *distStr = strtok(NULL, " "); + + float dist = 0; + + if (distStr) + sscanf(distStr, "%f", &dist); + + char* trig_str = strtok(NULL, " "); + if (trig_str) + { + int l = strlen(trig_str); + if (strncmp(trig_str,"triggered",l) != 0) + return false; + } + + bool triggered = (trig_str != NULL); + + float x,y,z; + m_session->GetPlayer()->GetClosePoint(x,y,z,dist); + + m_session->GetPlayer()->CastSpell(x,y,z,spell,triggered); + return true; +} + +bool ChatHandler::HandleCastTargetCommand(const char *args) +{ + Creature* caster = getSelectedCreature(); + + if (!caster) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if (!caster->getVictim()) + { + SendSysMessage(LANG_SELECTED_TARGET_NOT_HAVE_VICTIM); + SetSentErrorMessage(true); + return false; + } + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spell = extractSpellIdFromLink((char*)args); + if (!spell || !sSpellStore.LookupEntry(spell)) + { + PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); + SetSentErrorMessage(true); + return false; + } + + char* trig_str = strtok(NULL, " "); + if (trig_str) + { + int l = strlen(trig_str); + if (strncmp(trig_str,"triggered",l) != 0) + return false; + } + + bool triggered = (trig_str != NULL); + + caster->SetFacingToObject(m_session->GetPlayer()); + + caster->CastSpell(caster->getVictim(),spell,triggered); + + return true; +} + +/* +ComeToMe command REQUIRED for 3rd party scripting library to have access to PointMovementGenerator +Without this function 3rd party scripting library will get linking errors (unresolved external) +when attempting to use the PointMovementGenerator +*/ +bool ChatHandler::HandleComeToMeCommand(const char *args) +{ + char* newFlagStr = strtok((char*)args, " "); + + if (!newFlagStr) + return false; + + uint32 newFlags = (uint32)strtoul(newFlagStr, NULL, 0); + + Creature* caster = getSelectedCreature(); + if (!caster) + { + m_session->GetPlayer()->SetUnitMovementFlags(newFlags); + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + caster->SetUnitMovementFlags(newFlags); + + Player* pl = m_session->GetPlayer(); + + caster->GetMotionMaster()->MovePoint(0, pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ()); + return true; +} + +bool ChatHandler::HandleCastSelfCommand(const char *args) +{ + if (!*args) + return false; + + Unit* target = getSelectedUnit(); + + if (!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form + uint32 spell = extractSpellIdFromLink((char*)args); + if (!spell) + return false; + + SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); + if (!spellInfo) + return false; + + if (!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) + { + PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); + SetSentErrorMessage(true); + return false; + } + + target->CastSpell(target,spell,false); + + return true; +} + +std::string GetTimeString(uint32 time) +{ + uint16 days = time / DAY, hours = (time % DAY) / HOUR, minute = (time % HOUR) / MINUTE; + std::ostringstream ss; + if (days) ss << days << "d "; + if (hours) ss << hours << "h "; + ss << minute << "m"; + return ss.str(); +} + +bool ChatHandler::HandleInstanceListBindsCommand(const char* /*args*/) +{ + Player* player = getSelectedPlayer(); + if (!player) player = m_session->GetPlayer(); + uint32 counter = 0; + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) + { + Player::BoundInstancesMap &binds = player->GetBoundInstances(Difficulty(i)); + for (Player::BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end(); ++itr) + { + InstanceSave *save = itr->second.save; + std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); + PSendSysMessage("map: %d inst: %d perm: %s diff: %d canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); + counter++; + } + } + PSendSysMessage("player binds: %d", counter); + counter = 0; + Group *group = player->GetGroup(); + if (group) + { + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) + { + Group::BoundInstancesMap &binds = group->GetBoundInstances(Difficulty(i)); + for (Group::BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end(); ++itr) + { + InstanceSave *save = itr->second.save; + std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); + PSendSysMessage("map: %d inst: %d perm: %s diff: %d canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); counter++; + } + } + } + PSendSysMessage("group binds: %d", counter); + + return true; +} + +bool ChatHandler::HandleInstanceUnbindCommand(const char *args) +{ + if (!*args) + return false; + + std::string cmd = args; + if (cmd == "all") + { + Player* player = getSelectedPlayer(); + if (!player) player = m_session->GetPlayer(); + uint32 counter = 0; + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) + { + Player::BoundInstancesMap &binds = player->GetBoundInstances(Difficulty(i)); + for (Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end();) + { + if (itr->first != player->GetMapId()) + { + InstanceSave *save = itr->second.save; + std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); + PSendSysMessage("unbinding map: %d inst: %d perm: %s diff: %d canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); + player->UnbindInstance(itr, Difficulty(i)); + counter++; + } + else + ++itr; + } + } + PSendSysMessage("instances unbound: %d", counter); + } + return true; +} + +bool ChatHandler::HandleInstanceStatsCommand(const char* /*args*/) +{ + PSendSysMessage("instances loaded: %d", MapManager::Instance().GetNumInstances()); + PSendSysMessage("players in instances: %d", MapManager::Instance().GetNumPlayersInInstances()); + PSendSysMessage("instance saves: %d", sInstanceSaveManager.GetNumInstanceSaves()); + PSendSysMessage("players bound: %d", sInstanceSaveManager.GetNumBoundPlayersTotal()); + PSendSysMessage("groups bound: %d", sInstanceSaveManager.GetNumBoundGroupsTotal()); + return true; +} + +bool ChatHandler::HandleInstanceSaveDataCommand(const char * /*args*/) +{ + Player* pl = m_session->GetPlayer(); + + Map* map = pl->GetMap(); + if (!map->IsDungeon()) + { + PSendSysMessage("Map is not a dungeon."); + SetSentErrorMessage(true); + return false; + } + + if (!((InstanceMap*)map)->GetInstanceData()) + { + PSendSysMessage("Map has no instance data."); + SetSentErrorMessage(true); + return false; + } + + ((InstanceMap*)map)->GetInstanceData()->SaveToDB(); + return true; +} + +bool ChatHandler::HandleInstanceOpenCommand(const char *args) +{ + return HandleInstanceOpenCloseCommand(args,true); +} + +bool ChatHandler::HandleInstanceCloseCommand(const char *args) +{ + return HandleInstanceOpenCloseCommand(args,false); +} + +bool ChatHandler::HandleInstanceOpenCloseCommand(const char *args,bool open) +{ + char *mapIdStr; + char *instanceModeStr; + extractOptFirstArg((char*)args,&mapIdStr,&instanceModeStr); + if (!mapIdStr || !instanceModeStr) + return false; + + uint32 mapid = atoi(mapIdStr); + + InstanceTemplate const* instance = objmgr.GetInstanceTemplate(mapid); + if (!instance) + { + PSendSysMessage("Invalid map id"); + SetSentErrorMessage(true); + return false; + } + + uint8 status = objmgr.GetAccessRequirement(instance->access_id)->status; + uint8 flag = 0; + + if (strcmp(instanceModeStr,"normal") || strcmp(instanceModeStr,"10normal")) + flag = DUNGEON_STATUSFLAG_NORMAL; + else if (strcmp(instanceModeStr,"heroic") || strcmp(instanceModeStr,"25normal")) + flag = DUNGEON_STATUSFLAG_HEROIC; + else if (strcmp(instanceModeStr,"10heroic")) + flag = RAID_STATUSFLAG_10MAN_HEROIC; + else if (strcmp(instanceModeStr,"25heroic")) + flag = RAID_STATUSFLAG_25MAN_HEROIC; + else + { + PSendSysMessage("Unrecognized difficulty string"); + SetSentErrorMessage(true); + return false; + } + if (open) + status |= flag; + else + status &= ~flag; + + WorldDatabase.PExecute("UPDATE access_requirement SET status = '%u' WHERE id = '%u'", status, instance->access_id); + PSendSysMessage("Instance status changed. Don't forget to reload access_requirement table"); + return true; +} + +/// Display the list of GMs +bool ChatHandler::HandleGMListFullCommand(const char* /*args*/) +{ + ///- Get the accounts with GM Level >0 + QueryResult_AutoPtr result = LoginDatabase.Query("SELECT a.username,aa.gmlevel FROM account a, account_access aa WHERE a.id=aa.id AND aa.gmlevel > 0"); + if (result) + { + SendSysMessage(LANG_GMLIST); + SendSysMessage(" ======================== "); + SendSysMessage(LANG_GMLIST_HEADER); + SendSysMessage(" ======================== "); + + ///- Circle through them. Display username and GM level + do + { + Field *fields = result->Fetch(); + PSendSysMessage("|%15s|%6s|", fields[0].GetString(),fields[1].GetString()); + }while (result->NextRow()); + + PSendSysMessage(" ======================== "); + } + else + PSendSysMessage(LANG_GMLIST_EMPTY); + return true; +} + +/// Define the 'Message of the day' for the realm +bool ChatHandler::HandleServerSetMotdCommand(const char *args) +{ + sWorld.SetMotd(args); + PSendSysMessage(LANG_MOTD_NEW, args); + return true; +} + +/// Set whether we accept new clients +bool ChatHandler::HandleServerSetClosedCommand(const char *args) +{ + std::string arg = args; + + if (strncmp(args, "on", 3) == 0) + { + SendSysMessage(LANG_WORLD_CLOSED); + sWorld.SetClosed(true); + return true; + } + else if (strncmp(args, "off", 4) == 0) + { + SendSysMessage(LANG_WORLD_OPENED); + sWorld.SetClosed(false); + return true; + } + + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; +} + +/// Set/Unset the expansion level for an account +bool ChatHandler::HandleAccountSetAddonCommand(const char *args) +{ + ///- Get the command line arguments + char *szAcc = strtok((char*)args," "); + char *szExp = strtok(NULL," "); + + if (!szAcc) + return false; + + std::string account_name; + uint32 account_id; + + if (!szExp) + { + Player* player = getSelectedPlayer(); + if (!player) + return false; + + account_id = player->GetSession()->GetAccountId(); + accmgr.GetName(account_id,account_name); + szExp = szAcc; + } + else + { + ///- Convert Account name to Upper Format + account_name = szAcc; + if (!AccountMgr::normalizeString(account_name)) + { + PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); + SetSentErrorMessage(true); + return false; + } + + account_id = accmgr.GetId(account_name); + if (!account_id) + { + PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); + SetSentErrorMessage(true); + return false; + } + + } + + // Let set addon state only for lesser (strong) security level + // or to self account + if (m_session && m_session->GetAccountId () != account_id && + HasLowerSecurityAccount (NULL,account_id,true)) + return false; + + int expansion = atoi(szExp); //get int anyway (0 if error) + if (expansion < 0 || expansion > sWorld.getConfig(CONFIG_EXPANSION)) + return false; + + // No SQL injection + LoginDatabase.PExecute("UPDATE account SET expansion = '%d' WHERE id = '%u'",expansion,account_id); + PSendSysMessage(LANG_ACCOUNT_SETADDON,account_name.c_str(),account_id,expansion); + return true; +} + +//Send items by mail +bool ChatHandler::HandleSendItemsCommand(const char *args) +{ + // format: name "subject text" "mail text" item1[:count1] item2[:count2] ... item12[:count12] + Player* receiver; + uint64 receiver_guid; + std::string receiver_name; + if (!extractPlayerTarget((char*)args,&receiver,&receiver_guid,&receiver_name)) + return false; + + char* tail1 = strtok(NULL, ""); + if (!tail1) + return false; + + char* msgSubject = extractQuotedArg(tail1); + if (!msgSubject) + return false; + + char* tail2 = strtok(NULL, ""); + if (!tail2) + return false; + + char* msgText = extractQuotedArg(tail2); + if (!msgText) + return false; + + // msgSubject, msgText isn't NUL after prev. check + std::string subject = msgSubject; + std::string text = msgText; + + // extract items + typedef std::pair ItemPair; + typedef std::list< ItemPair > ItemPairs; + ItemPairs items; + + // get all tail string + char* tail = strtok(NULL, ""); + + // get from tail next item str + while (char* itemStr = strtok(tail, " ")) + { + // and get new tail + tail = strtok(NULL, ""); + + // parse item str + char* itemIdStr = strtok(itemStr, ":"); + char* itemCountStr = strtok(NULL, " "); + + uint32 item_id = atoi(itemIdStr); + if (!item_id) + return false; + + ItemPrototype const* item_proto = objmgr.GetItemPrototype(item_id); + if (!item_proto) + { + PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, item_id); + SetSentErrorMessage(true); + return false; + } + + uint32 item_count = itemCountStr ? atoi(itemCountStr) : 1; + if (item_count < 1 || (item_proto->MaxCount > 0 && item_count > uint32(item_proto->MaxCount))) + { + PSendSysMessage(LANG_COMMAND_INVALID_ITEM_COUNT, item_count,item_id); + SetSentErrorMessage(true); + return false; + } + + while (item_count > item_proto->GetMaxStackSize()) + { + items.push_back(ItemPair(item_id,item_proto->GetMaxStackSize())); + item_count -= item_proto->GetMaxStackSize(); + } + + items.push_back(ItemPair(item_id,item_count)); + + if (items.size() > MAX_MAIL_ITEMS) + { + PSendSysMessage(LANG_COMMAND_MAIL_ITEMS_LIMIT, MAX_MAIL_ITEMS); + SetSentErrorMessage(true); + return false; + } + } + + // from console show not existed sender + MailSender sender(MAIL_NORMAL,m_session ? m_session->GetPlayer()->GetGUIDLow() : 0, MAIL_STATIONERY_GM); + + // fill mail + MailDraft draft(subject, text); + + for (ItemPairs::const_iterator itr = items.begin(); itr != items.end(); ++itr) + { + if (Item* item = Item::CreateItem(itr->first,itr->second,m_session ? m_session->GetPlayer() : 0)) + { + item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted + draft.AddItem(item); + } + } + + draft.SendMailTo(MailReceiver(receiver,GUID_LOPART(receiver_guid)), sender); + + std::string nameLink = playerLink(receiver_name); + PSendSysMessage(LANG_MAIL_SENT, nameLink.c_str()); + return true; +} + +///Send money by mail +bool ChatHandler::HandleSendMoneyCommand(const char *args) +{ + /// format: name "subject text" "mail text" money + + Player* receiver; + uint64 receiver_guid; + std::string receiver_name; + if (!extractPlayerTarget((char*)args,&receiver,&receiver_guid,&receiver_name)) + return false; + + char* tail1 = strtok(NULL, ""); + if (!tail1) + return false; + + char* msgSubject = extractQuotedArg(tail1); + if (!msgSubject) + return false; + + char* tail2 = strtok(NULL, ""); + if (!tail2) + return false; + + char* msgText = extractQuotedArg(tail2); + if (!msgText) + return false; + + char* money_str = strtok(NULL, ""); + int32 money = money_str ? atoi(money_str) : 0; + if (money <= 0) + return false; + + // msgSubject, msgText isn't NUL after prev. check + std::string subject = msgSubject; + std::string text = msgText; + + // from console show not existed sender + MailSender sender(MAIL_NORMAL,m_session ? m_session->GetPlayer()->GetGUIDLow() : 0, MAIL_STATIONERY_GM); + + MailDraft(subject, text) + .AddMoney(money) + .SendMailTo(MailReceiver(receiver,GUID_LOPART(receiver_guid)),sender); + + std::string nameLink = playerLink(receiver_name); + PSendSysMessage(LANG_MAIL_SENT, nameLink.c_str()); + return true; +} + +/// Send a message to a player in game +bool ChatHandler::HandleSendMessageCommand(const char *args) +{ + ///- Find the player + Player *rPlayer; + if (!extractPlayerTarget((char*)args, &rPlayer)) + return false; + + char* msg_str = strtok(NULL, ""); + if (!msg_str) + return false; + + ///- Check that he is not logging out. + if (rPlayer->GetSession()->isLogingOut()) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + ///- Send the message + //Use SendAreaTriggerMessage for fastest delivery. + rPlayer->GetSession()->SendAreaTriggerMessage("%s", msg_str); + rPlayer->GetSession()->SendAreaTriggerMessage("|cffff0000[Message from administrator]:|r"); + + //Confirmation message + std::string nameLink = GetNameLink(rPlayer); + PSendSysMessage(LANG_SENDMESSAGE,nameLink.c_str(),msg_str); + return true; +} + +bool ChatHandler::HandleFlushArenaPointsCommand(const char * /*args*/) +{ + sBattleGroundMgr.DistributeArenaPoints(); + return true; +} + +bool ChatHandler::HandleModifyGenderCommand(const char *args) +{ + if (!*args) + return false; + + Player *player = getSelectedPlayer(); + + if (!player) + { + PSendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + PlayerInfo const* info = objmgr.GetPlayerInfo(player->getRace(), player->getClass()); + if (!info) + return false; + + char const* gender_str = (char*)args; + int gender_len = strlen(gender_str); + + Gender gender; + + if (!strncmp(gender_str, "male", gender_len)) // MALE + { + if (player->getGender() == GENDER_MALE) + return true; + + gender = GENDER_MALE; + } + else if (!strncmp(gender_str, "female", gender_len)) // FEMALE + { + if (player->getGender() == GENDER_FEMALE) + return true; + + gender = GENDER_FEMALE; + } + else + { + SendSysMessage(LANG_MUST_MALE_OR_FEMALE); + SetSentErrorMessage(true); + return false; + } + + // Set gender + player->SetByteValue(UNIT_FIELD_BYTES_0, 2, gender); + player->SetByteValue(PLAYER_BYTES_3, 0, gender); + + // Change display ID + player->InitDisplayIds(); + + char const* gender_full = gender ? "female" : "male"; + + PSendSysMessage(LANG_YOU_CHANGE_GENDER, GetNameLink(player).c_str(), gender_full); + + if (needReportToTarget(player)) + ChatHandler(player).PSendSysMessage(LANG_YOUR_GENDER_CHANGED, gender_full, GetNameLink().c_str()); + + return true; +} + +bool ChatHandler::HandleChannelSetPublic(const char *args) +{ + if (!*args) + return false; + std::string channel = strtok((char*)args, " "); + uint32 val = atoi((char*)args); + + if (val) + { + CharacterDatabase.PExecute("UPDATE channels SET m_public = 1 WHERE m_name LIKE '%s'", channel.c_str()); + val = 1; + } + else + { + CharacterDatabase.PExecute("UPDATE channels SET m_public = 0 WHERE m_name LIKE '%s'", channel.c_str()); + val = 0; + } + + PSendSysMessage(LANG_CHANNEL_PUBLIC_CHANGED, channel.c_str(), val); + + return true; +} + + +/*------------------------------------------ + *-------------TRINITY---------------------- + *-------------------------------------*/ + +bool ChatHandler::HandlePlayAllCommand(const char *args) +{ + if (!*args) + return false; + + uint32 soundId = atoi((char*)args); + + if (!sSoundEntriesStore.LookupEntry(soundId)) + { + PSendSysMessage(LANG_SOUND_NOT_EXIST, soundId); + SetSentErrorMessage(true); + return false; + } + + WorldPacket data(SMSG_PLAY_SOUND, 4); + data << uint32(soundId) << m_session->GetPlayer()->GetGUID(); + sWorld.SendGlobalMessage(&data); + + PSendSysMessage(LANG_COMMAND_PLAYED_TO_ALL, soundId); + return true; +} + +bool ChatHandler::HandleFreezeCommand(const char *args) +{ + std::string name; + Player *player; + char *TargetName = strtok((char*)args, " "); //get entered name + if (!TargetName) //if no name entered use target + { + player = getSelectedPlayer(); + if (player) //prevent crash with creature as target + { + name = player->GetName(); + normalizePlayerName(name); + } + } + else // if name entered + { + name = TargetName; + normalizePlayerName(name); + player = objmgr.GetPlayer(name.c_str()); //get player by name + } + + if (!player) + { + SendSysMessage(LANG_COMMAND_FREEZE_WRONG); + return true; + } + + if (player == m_session->GetPlayer()) + { + SendSysMessage(LANG_COMMAND_FREEZE_ERROR); + return true; + } + + //effect + if (player && player != m_session->GetPlayer()) + { + PSendSysMessage(LANG_COMMAND_FREEZE,name.c_str()); + + //stop combat + make player unattackable + duel stop + stop some spells + player->setFaction(35); + player->CombatStop(); + if (player->IsNonMeleeSpellCasted(true)) + player->InterruptNonMeleeSpells(true); + player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + player->SetUInt32Value(PLAYER_DUEL_TEAM, 1); + + //if player class = hunter || warlock remove pet if alive + if ((player->getClass() == CLASS_HUNTER) || (player->getClass() == CLASS_WARLOCK)) + { + if (Pet *pet = player->GetPet()) + { + pet->SavePetToDB(PET_SAVE_AS_CURRENT); + // not let dismiss dead pet + if (pet && pet->isAlive()) + player->RemovePet(pet,PET_SAVE_NOT_IN_SLOT); + } + } + + //m_session->GetPlayer()->CastSpell(player,spellID,false); + if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(9454)) + Aura::TryCreate(spellInfo, player, player); + + //save player + player->SaveToDB(); + } + return true; +} + +bool ChatHandler::HandleUnFreezeCommand(const char *args) +{ + std::string name; + Player *player; + char *TargetName = strtok((char*)args, " "); //get entered name + if (!TargetName) //if no name entered use target + { + player = getSelectedPlayer(); + if (player) //prevent crash with creature as target + name = player->GetName(); + } + + else // if name entered + { + name = TargetName; + normalizePlayerName(name); + player = objmgr.GetPlayer(name.c_str()); //get player by name + } + + //effect + if (player) + { + PSendSysMessage(LANG_COMMAND_UNFREEZE,name.c_str()); + + //Reset player faction + allow combat + allow duels + player->setFactionForRace(player->getRace()); + player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + //allow movement and spells + player->RemoveAurasDueToSpell(9454); + + //save player + player->SaveToDB(); + } + + if (!player) + { + if (TargetName) + { + //check for offline players + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT characters.guid FROM characters WHERE characters.name = '%s'",name.c_str()); + if (!result) + { + SendSysMessage(LANG_COMMAND_FREEZE_WRONG); + return true; + } + //if player found: delete his freeze aura + Field *fields=result->Fetch(); + uint64 pguid = fields[0].GetUInt64(); + + CharacterDatabase.PQuery("DELETE FROM character_aura WHERE character_aura.spell = 9454 AND character_aura.guid = '%u'",pguid); + PSendSysMessage(LANG_COMMAND_UNFREEZE,name.c_str()); + return true; + } + else + { + SendSysMessage(LANG_COMMAND_FREEZE_WRONG); + return true; + } + } + + return true; +} + +bool ChatHandler::HandleListFreezeCommand(const char * /*args*/) +{ + //Get names from DB + QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT characters.name FROM characters LEFT JOIN character_aura ON (characters.guid = character_aura.guid) WHERE character_aura.spell = 9454"); + if (!result) + { + SendSysMessage(LANG_COMMAND_NO_FROZEN_PLAYERS); + return true; + } + //Header of the names + PSendSysMessage(LANG_COMMAND_LIST_FREEZE); + + //Output of the results + do + { + Field *fields = result->Fetch(); + std::string fplayers = fields[0].GetCppString(); + PSendSysMessage(LANG_COMMAND_FROZEN_PLAYERS,fplayers.c_str()); + } while (result->NextRow()); + + return true; +} + +bool ChatHandler::HandleGroupLeaderCommand(const char *args) +{ + Player* plr = NULL; + Group* group = NULL; + uint64 guid = 0; + char* cname = strtok((char*)args, " "); + + if (GetPlayerGroupAndGUIDByName(cname, plr, group, guid)) + if (group && group->GetLeaderGUID() != guid) + group->ChangeLeader(guid); + + return true; +} + +bool ChatHandler::HandleGroupDisbandCommand(const char *args) +{ + Player* plr = NULL; + Group* group = NULL; + uint64 guid = 0; + char* cname = strtok((char*)args, " "); + + if (GetPlayerGroupAndGUIDByName(cname, plr, group, guid)) + if (group) + group->Disband(); + + return true; +} + +bool ChatHandler::HandleGroupRemoveCommand(const char *args) +{ + Player* plr = NULL; + Group* group = NULL; + uint64 guid = 0; + char* cname = strtok((char*)args, " "); + + if (GetPlayerGroupAndGUIDByName(cname, plr, group, guid, true)) + if (group) + group->RemoveMember(guid, 0); + + return true; +} + +bool ChatHandler::HandlePossessCommand(const char * /*args*/) +{ + Unit *pUnit = getSelectedUnit(); + if (!pUnit) + return false; + + m_session->GetPlayer()->CastSpell(pUnit, 530, true); + return true; +} + +bool ChatHandler::HandleUnPossessCommand(const char * /*args*/) +{ + Unit *pUnit = getSelectedUnit(); + if (!pUnit) + pUnit = m_session->GetPlayer(); + + pUnit->RemoveCharmAuras(); + + return true; +} + +bool ChatHandler::HandleBindSightCommand(const char * /*args*/) +{ + Unit *pUnit = getSelectedUnit(); + if (!pUnit) + return false; + + m_session->GetPlayer()->CastSpell(pUnit, 6277, true); + return true; +} + +bool ChatHandler::HandleUnbindSightCommand(const char * /*args*/) +{ + if (m_session->GetPlayer()->isPossessing()) + return false; + + m_session->GetPlayer()->StopCastingBindSight(); + return true; +} diff --git a/src/server/game/Chat/Debugcmds.cpp b/src/server/game/Chat/Debugcmds.cpp deleted file mode 100644 index ee8c623c3d0..00000000000 --- a/src/server/game/Chat/Debugcmds.cpp +++ /dev/null @@ -1,1127 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "Vehicle.h" -#include "Player.h" -#include "Opcodes.h" -#include "Chat.h" -#include "Log.h" -#include "Unit.h" -#include "GossipDef.h" -#include "Language.h" -#include "BattleGroundMgr.h" -#include -#include "ObjectMgr.h" -#include "Cell.h" -#include "CellImpl.h" -#include "GridNotifiers.h" -#include "GridNotifiersImpl.h" -#include "SpellMgr.h" -#include "ScriptMgr.h" - -bool ChatHandler::HandleDebugSendSpellFailCommand(const char* args) -{ - if (!*args) - return false; - - char* px = strtok((char*)args, " "); - if (!px) - return false; - - uint8 failnum = (uint8)atoi(px); - if (failnum == 0 && *px != '0') - return false; - - char* p1 = strtok(NULL, " "); - uint8 failarg1 = p1 ? (uint8)atoi(p1) : 0; - - char* p2 = strtok(NULL, " "); - uint8 failarg2 = p2 ? (uint8)atoi(p2) : 0; - - WorldPacket data(SMSG_CAST_FAILED, 5); - data << uint8(0); - data << uint32(133); - data << uint8(failnum); - if (p1 || p2) - data << uint32(failarg1); - if (p2) - data << uint32(failarg2); - - m_session->SendPacket(&data); - - return true; -} - -bool ChatHandler::HandleDebugSendPoiCommand(const char* args) -{ - if (!*args) - return false; - - Player *pPlayer = m_session->GetPlayer(); - Unit* target = getSelectedUnit(); - if (!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - return true; - } - - char* icon_text = strtok((char*)args, " "); - char* flags_text = strtok(NULL, " "); - if (!icon_text || !flags_text) - return false; - - uint32 icon = atol(icon_text); - uint32 flags = atol(flags_text); - - sLog.outDetail("Command : POI, NPC = %u, icon = %u flags = %u", target->GetGUIDLow(), icon,flags); - pPlayer->PlayerTalkClass->SendPointOfInterest(target->GetPositionX(), target->GetPositionY(), Poi_Icon(icon), flags, 30, "Test POI"); - return true; -} - -bool ChatHandler::HandleDebugSendEquipErrorCommand(const char* args) -{ - if (!*args) - return false; - - uint8 msg = atoi(args); - m_session->GetPlayer()->SendEquipError(msg, 0, 0); - return true; -} - -bool ChatHandler::HandleDebugSendSellErrorCommand(const char* args) -{ - if (!*args) - return false; - - uint8 msg = atoi(args); - m_session->GetPlayer()->SendSellError(msg, 0, 0, 0); - return true; -} - -bool ChatHandler::HandleDebugSendBuyErrorCommand(const char* args) -{ - if (!*args) - return false; - - uint8 msg = atoi(args); - m_session->GetPlayer()->SendBuyError(msg, 0, 0, 0); - return true; -} - -bool ChatHandler::HandleDebugSendOpcodeCommand(const char* /*args*/) -{ - Unit *unit = getSelectedUnit(); - Player *player = NULL; - if (!unit || (unit->GetTypeId() != TYPEID_PLAYER)) - player = m_session->GetPlayer(); - else - player = (Player*)unit; - if (!unit) unit = player; - - std::ifstream ifs("opcode.txt"); - if (ifs.bad()) - return false; - - uint32 opcode; - ifs >> opcode; - - WorldPacket data(opcode, 0); - - while (!ifs.eof()) - { - std::string type; - ifs >> type; - - if (type == "") - break; - - if (type == "uint8") - { - uint16 val1; - ifs >> val1; - data << uint8(val1); - } - else if (type == "uint16") - { - uint16 val2; - ifs >> val2; - data << val2; - } - else if (type == "uint32") - { - uint32 val3; - ifs >> val3; - data << val3; - } - else if (type == "uint64") - { - uint64 val4; - ifs >> val4; - data << val4; - } - else if (type == "float") - { - float val5; - ifs >> val5; - data << val5; - } - else if (type == "string") - { - std::string val6; - ifs >> val6; - data << val6; - } - else if (type == "appitsguid") - { - data.append(unit->GetPackGUID()); - } - else if (type == "appmyguid") - { - data.append(player->GetPackGUID()); - } - else if (type == "appgoguid") - { - GameObject *obj = GetNearbyGameObject(); - if (!obj) - { - PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, 0); - SetSentErrorMessage(true); - ifs.close(); - return false; - } - data.append(obj->GetPackGUID()); - } - else if (type == "goguid") - { - GameObject *obj = GetNearbyGameObject(); - if (!obj) - { - PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, 0); - SetSentErrorMessage(true); - ifs.close(); - return false; - } - data << uint64(obj->GetGUID()); - } - else if (type == "myguid") - { - data << uint64(player->GetGUID()); - } - else if (type == "itsguid") - { - data << uint64(unit->GetGUID()); - } - else if (type == "pos") - { - data << unit->GetPositionX(); - data << unit->GetPositionY(); - data << unit->GetPositionZ(); - } - else if (type == "mypos") - { - data << player->GetPositionX(); - data << player->GetPositionY(); - data << player->GetPositionZ(); - } - else - { - sLog.outDebug("Sending opcode: unknown type '%s'", type.c_str()); - break; - } - } - ifs.close(); - sLog.outDebug("Sending opcode %u", data.GetOpcode()); - data.hexlike(); - player->GetSession()->SendPacket(&data); - PSendSysMessage(LANG_COMMAND_OPCODESENT, data.GetOpcode(), unit->GetName()); - return true; -} - -bool ChatHandler::HandleDebugUpdateWorldStateCommand(const char* args) -{ - char* w = strtok((char*)args, " "); - char* s = strtok(NULL, " "); - - if (!w || !s) - return false; - - uint32 world = (uint32)atoi(w); - uint32 state = (uint32)atoi(s); - m_session->GetPlayer()->SendUpdateWorldState(world, state); - return true; -} - -bool ChatHandler::HandleDebugPlayCinematicCommand(const char* args) -{ - // USAGE: .debug play cinematic #cinematicid - // #cinematicid - ID decimal number from CinemaicSequences.dbc (1st column) - if (!*args) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - uint32 dwId = atoi((char*)args); - - if (!sCinematicSequencesStore.LookupEntry(dwId)) - { - PSendSysMessage(LANG_CINEMATIC_NOT_EXIST, dwId); - SetSentErrorMessage(true); - return false; - } - - m_session->GetPlayer()->SendCinematicStart(dwId); - return true; -} - -bool ChatHandler::HandleDebugPlayMovieCommand(const char* args) -{ - // USAGE: .debug play movie #movieid - // #movieid - ID decimal number from Movie.dbc (1st column) - if (!*args) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - uint32 dwId = atoi((char*)args); - - if (!sMovieStore.LookupEntry(dwId)) - { - PSendSysMessage(LANG_MOVIE_NOT_EXIST, dwId); - SetSentErrorMessage(true); - return false; - } - - m_session->GetPlayer()->SendMovieStart(dwId); - return true; -} - -//Play sound -bool ChatHandler::HandleDebugPlaySoundCommand(const char* args) -{ - // USAGE: .debug playsound #soundid - // #soundid - ID decimal number from SoundEntries.dbc (1st column) - if (!*args) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - uint32 dwSoundId = atoi((char*)args); - - if (!sSoundEntriesStore.LookupEntry(dwSoundId)) - { - PSendSysMessage(LANG_SOUND_NOT_EXIST, dwSoundId); - SetSentErrorMessage(true); - return false; - } - - Unit* unit = getSelectedUnit(); - if (!unit) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if (m_session->GetPlayer()->GetSelection()) - unit->PlayDistanceSound(dwSoundId,m_session->GetPlayer()); - else - unit->PlayDirectSound(dwSoundId,m_session->GetPlayer()); - - PSendSysMessage(LANG_YOU_HEAR_SOUND, dwSoundId); - return true; -} - -//Send notification in channel -bool ChatHandler::HandleDebugSendChannelNotifyCommand(const char* args) -{ - if (!*args) - return false; - - const char *name = "test"; - uint8 code = atoi(args); - - WorldPacket data(SMSG_CHANNEL_NOTIFY, (1+10)); - data << code; // notify type - data << name; // channel name - data << uint32(0); - data << uint32(0); - m_session->SendPacket(&data); - return true; -} - -//Send notification in chat -bool ChatHandler::HandleDebugSendChatMsgCommand(const char* args) -{ - if (!*args) - return false; - - const char *msg = "testtest"; - uint8 type = atoi(args); - WorldPacket data; - ChatHandler::FillMessageData(&data, m_session, type, 0, "chan", m_session->GetPlayer()->GetGUID(), msg, m_session->GetPlayer()); - m_session->SendPacket(&data); - return true; -} - -bool ChatHandler::HandleDebugSendQuestPartyMsgCommand(const char* args) -{ - uint32 msg = atol((char*)args); - m_session->GetPlayer()->SendPushToPartyResponse(m_session->GetPlayer(), msg); - return true; -} - -bool ChatHandler::HandleDebugGetLootRecipientCommand(const char* /*args*/) -{ - Creature* target = getSelectedCreature(); - if (!target) - return false; - - PSendSysMessage("loot recipient: %s", target->hasLootRecipient()?(target->GetLootRecipient()?target->GetLootRecipient()->GetName():"offline"):"no loot recipient"); - return true; -} - -bool ChatHandler::HandleDebugSendQuestInvalidMsgCommand(const char* args) -{ - uint32 msg = atol((char*)args); - m_session->GetPlayer()->SendCanTakeQuestResponse(msg); - return true; -} - -bool ChatHandler::HandleDebugGetItemStateCommand(const char* args) -{ - if (!*args) - return false; - - std::string state_str = args; - - ItemUpdateState state = ITEM_UNCHANGED; - bool list_queue = false, check_all = false; - if (state_str == "unchanged") state = ITEM_UNCHANGED; - else if (state_str == "changed") state = ITEM_CHANGED; - else if (state_str == "new") state = ITEM_NEW; - else if (state_str == "removed") state = ITEM_REMOVED; - else if (state_str == "queue") list_queue = true; - else if (state_str == "check_all") check_all = true; - else return false; - - Player* player = getSelectedPlayer(); - if (!player) player = m_session->GetPlayer(); - - if (!list_queue && !check_all) - { - state_str = "The player has the following " + state_str + " items: "; - SendSysMessage(state_str.c_str()); - for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i) - { - if (i >= BUYBACK_SLOT_START && i < BUYBACK_SLOT_END) - continue; - - Item *item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); - if (!item) continue; - if (!item->IsBag()) - { - if (item->GetState() == state) - PSendSysMessage("bag: 255 slot: %d guid: %d owner: %d", item->GetSlot(), item->GetGUIDLow(), GUID_LOPART(item->GetOwnerGUID())); - } - else - { - Bag *bag = (Bag*)item; - for (uint8 j = 0; j < bag->GetBagSize(); ++j) - { - Item* item2 = bag->GetItemByPos(j); - if (item2 && item2->GetState() == state) - PSendSysMessage("bag: 255 slot: %d guid: %d owner: %d", item2->GetSlot(), item2->GetGUIDLow(), GUID_LOPART(item2->GetOwnerGUID())); - } - } - } - } - - if (list_queue) - { - std::vector &updateQueue = player->GetItemUpdateQueue(); - for (size_t i = 0; i < updateQueue.size(); ++i) - { - Item *item = updateQueue[i]; - if (!item) continue; - - Bag *container = item->GetContainer(); - uint8 bag_slot = container ? container->GetSlot() : uint8(INVENTORY_SLOT_BAG_0); - - std::string st; - switch(item->GetState()) - { - case ITEM_UNCHANGED: st = "unchanged"; break; - case ITEM_CHANGED: st = "changed"; break; - case ITEM_NEW: st = "new"; break; - case ITEM_REMOVED: st = "removed"; break; - } - - PSendSysMessage("bag: %d slot: %d guid: %d - state: %s", bag_slot, item->GetSlot(), item->GetGUIDLow(), st.c_str()); - } - if (updateQueue.empty()) - PSendSysMessage("updatequeue empty"); - } - - if (check_all) - { - bool error = false; - std::vector &updateQueue = player->GetItemUpdateQueue(); - for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i) - { - if (i >= BUYBACK_SLOT_START && i < BUYBACK_SLOT_END) - continue; - - Item *item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); - if (!item) continue; - - if (item->GetSlot() != i) - { - PSendSysMessage("item at slot %d, guid %d has an incorrect slot value: %d", i, item->GetGUIDLow(), item->GetSlot()); - error = true; continue; - } - - if (item->GetOwnerGUID() != player->GetGUID()) - { - PSendSysMessage("for the item at slot %d and itemguid %d, owner's guid (%d) and player's guid (%d) don't match!", item->GetSlot(), item->GetGUIDLow(), GUID_LOPART(item->GetOwnerGUID()), player->GetGUIDLow()); - error = true; continue; - } - - if (Bag *container = item->GetContainer()) - { - PSendSysMessage("item at slot: %d guid: %d has a container (slot: %d, guid: %d) but shouldnt!", item->GetSlot(), item->GetGUIDLow(), container->GetSlot(), container->GetGUIDLow()); - error = true; continue; - } - - if (item->IsInUpdateQueue()) - { - uint16 qp = item->GetQueuePos(); - if (qp > updateQueue.size()) - { - PSendSysMessage("item at slot: %d guid: %d has a queuepos (%d) larger than the update queue size! ", item->GetSlot(), item->GetGUIDLow(), qp); - error = true; continue; - } - - if (updateQueue[qp] == NULL) - { - PSendSysMessage("item at slot: %d guid: %d has a queuepos (%d) that points to NULL in the queue!", item->GetSlot(), item->GetGUIDLow(), qp); - error = true; continue; - } - - if (updateQueue[qp] != item) - { - PSendSysMessage("item at slot: %d guid: %d has has a queuepos (%d) that points to another item in the queue (bag: %d, slot: %d, guid: %d)", item->GetSlot(), item->GetGUIDLow(), qp, updateQueue[qp]->GetBagSlot(), updateQueue[qp]->GetSlot(), updateQueue[qp]->GetGUIDLow()); - error = true; continue; - } - } - else if (item->GetState() != ITEM_UNCHANGED) - { - PSendSysMessage("item at slot: %d guid: %d is not in queue but should be (state: %d)!", item->GetSlot(), item->GetGUIDLow(), item->GetState()); - error = true; continue; - } - - if (item->IsBag()) - { - Bag *bag = (Bag*)item; - for (uint8 j = 0; j < bag->GetBagSize(); ++j) - { - Item* item2 = bag->GetItemByPos(j); - if (!item2) continue; - - if (item2->GetSlot() != j) - { - PSendSysMessage("the item in bag %d slot %d, guid %d has an incorrect slot value: %d", bag->GetSlot(), j, item2->GetGUIDLow(), item2->GetSlot()); - error = true; continue; - } - - if (item2->GetOwnerGUID() != player->GetGUID()) - { - PSendSysMessage("for the item in bag %d at slot %d and itemguid %d, owner's guid (%d) and player's guid (%d) don't match!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), GUID_LOPART(item2->GetOwnerGUID()), player->GetGUIDLow()); - error = true; continue; - } - - Bag *container = item2->GetContainer(); - if (!container) - { - PSendSysMessage("the item in bag %d at slot %d with guid %d has no container!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow()); - error = true; continue; - } - - if (container != bag) - { - PSendSysMessage("the item in bag %d at slot %d with guid %d has a different container(slot %d guid %d)!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), container->GetSlot(), container->GetGUIDLow()); - error = true; continue; - } - - if (item2->IsInUpdateQueue()) - { - uint16 qp = item2->GetQueuePos(); - if (qp > updateQueue.size()) - { - PSendSysMessage("item in bag: %d at slot: %d guid: %d has a queuepos (%d) larger than the update queue size! ", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), qp); - error = true; continue; - } - - if (updateQueue[qp] == NULL) - { - PSendSysMessage("item in bag: %d at slot: %d guid: %d has a queuepos (%d) that points to NULL in the queue!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), qp); - error = true; continue; - } - - if (updateQueue[qp] != item2) - { - PSendSysMessage("item in bag: %d at slot: %d guid: %d has has a queuepos (%d) that points to another item in the queue (bag: %d, slot: %d, guid: %d)", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), qp, updateQueue[qp]->GetBagSlot(), updateQueue[qp]->GetSlot(), updateQueue[qp]->GetGUIDLow()); - error = true; continue; - } - } - else if (item2->GetState() != ITEM_UNCHANGED) - { - PSendSysMessage("item in bag: %d at slot: %d guid: %d is not in queue but should be (state: %d)!", bag->GetSlot(), item2->GetSlot(), item2->GetGUIDLow(), item2->GetState()); - error = true; continue; - } - } - } - } - - for (size_t i = 0; i < updateQueue.size(); ++i) - { - Item *item = updateQueue[i]; - if (!item) continue; - - if (item->GetOwnerGUID() != player->GetGUID()) - { - PSendSysMessage("queue(" SIZEFMTD "): for the an item (guid %d), the owner's guid (%d) and player's guid (%d) don't match!", i, item->GetGUIDLow(), GUID_LOPART(item->GetOwnerGUID()), player->GetGUIDLow()); - error = true; continue; - } - - if (item->GetQueuePos() != i) - { - PSendSysMessage("queue(" SIZEFMTD "): for the an item (guid %d), the queuepos doesn't match it's position in the queue!", i, item->GetGUIDLow()); - error = true; continue; - } - - if (item->GetState() == ITEM_REMOVED) continue; - Item *test = player->GetItemByPos(item->GetBagSlot(), item->GetSlot()); - - if (test == NULL) - { - PSendSysMessage("queue(" SIZEFMTD "): the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the player doesn't have an item at that position!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow()); - error = true; continue; - } - - if (test != item) - { - PSendSysMessage("queue(" SIZEFMTD "): the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the item with guid %d is there instead!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), test->GetGUIDLow()); - error = true; continue; - } - } - if (!error) - SendSysMessage("All OK!"); - } - - return true; -} - -bool ChatHandler::HandleDebugBattlegroundCommand(const char * /*args*/) -{ - sBattleGroundMgr.ToggleTesting(); - return true; -} - -bool ChatHandler::HandleDebugArenaCommand(const char * /*args*/) -{ - sBattleGroundMgr.ToggleArenaTesting(); - return true; -} - -bool ChatHandler::HandleDebugThreatList(const char * /*args*/) -{ - Creature* target = getSelectedCreature(); - if (!target || target->isTotem() || target->isPet()) - return false; - - std::list& tlist = target->getThreatManager().getThreatList(); - std::list::iterator itr; - uint32 cnt = 0; - PSendSysMessage("Threat list of %s (guid %u)",target->GetName(), target->GetGUIDLow()); - for (itr = tlist.begin(); itr != tlist.end(); ++itr) - { - Unit* unit = (*itr)->getTarget(); - if (!unit) - continue; - ++cnt; - PSendSysMessage(" %u. %s (guid %u) - threat %f",cnt,unit->GetName(), unit->GetGUIDLow(), (*itr)->getThreat()); - } - SendSysMessage("End of threat list."); - return true; -} - -bool ChatHandler::HandleDebugHostileRefList(const char * /*args*/) -{ - Unit* target = getSelectedUnit(); - if (!target) - target = m_session->GetPlayer(); - HostileReference* ref = target->getHostileRefManager().getFirst(); - uint32 cnt = 0; - PSendSysMessage("Hostil reference list of %s (guid %u)",target->GetName(), target->GetGUIDLow()); - while (ref) - { - if (Unit * unit = ref->getSource()->getOwner()) - { - ++cnt; - PSendSysMessage(" %u. %s (guid %u) - threat %f",cnt,unit->GetName(), unit->GetGUIDLow(), ref->getThreat()); - } - ref = ref->next(); - } - SendSysMessage("End of hostil reference list."); - return true; -} - -bool ChatHandler::HandleDebugSetVehicleId(const char *args) -{ - Unit* target = getSelectedUnit(); - if (!target || target->IsVehicle()) - return false; - - if (!args) - return false; - - char* i = strtok((char*)args, " "); - if (!i) - return false; - - uint32 id = (uint32)atoi(i); - //target->SetVehicleId(id); - PSendSysMessage("Vehicle id set to %u", id); - return true; -} - -bool ChatHandler::HandleDebugEnterVehicle(const char * args) -{ - Unit* target = getSelectedUnit(); - if (!target || !target->IsVehicle()) - return false; - - if (!args) - return false; - - char* i = strtok((char*)args, " "); - if (!i) - return false; - - char* j = strtok(NULL, " "); - - uint32 entry = (uint32)atoi(i); - int8 seatId = j ? (int8)atoi(j) : -1; - - if (!entry) - m_session->GetPlayer()->EnterVehicle(target, seatId); - else - { - Creature *passenger = NULL; - Trinity::AllCreaturesOfEntryInRange check(m_session->GetPlayer(), entry, 20.0f); - Trinity::CreatureSearcher searcher(m_session->GetPlayer(), passenger, check); - m_session->GetPlayer()->VisitNearbyObject(30.0f, searcher); - if (!passenger || passenger == target) - return false; - passenger->EnterVehicle(target, seatId); - } - - PSendSysMessage("Unit %u entered vehicle %d", entry, (int32)seatId); - return true; -} - -bool ChatHandler::HandleDebugSpawnVehicle(const char* args) -{ - if (!*args) - return false; - - char* e = strtok((char*)args, " "); - char* i = strtok(NULL, " "); - - if (!e) - return false; - - uint32 entry = (uint32)atoi(e); - - float x, y, z, o = m_session->GetPlayer()->GetOrientation(); - m_session->GetPlayer()->GetClosePoint(x, y, z, m_session->GetPlayer()->GetObjectSize()); - - if (!i) - return m_session->GetPlayer()->SummonCreature(entry, x, y, z, o); - - uint32 id = (uint32)atoi(i); - - CreatureInfo const *ci = objmgr.GetCreatureTemplate(entry); - - if (!ci) - return false; - - VehicleEntry const *ve = sVehicleStore.LookupEntry(id); - - if (!ve) - return false; - - Creature *v = new Creature; - - Map *map = m_session->GetPlayer()->GetMap(); - - if (!v->Create(objmgr.GenerateLowGuid(HIGHGUID_VEHICLE), map, m_session->GetPlayer()->GetPhaseMask(), entry, id, m_session->GetPlayer()->GetTeam(), x, y, z, o)) - { - delete v; - return false; - } - - map->Add(v->ToCreature()); - - return true; -} - -bool ChatHandler::HandleDebugSendLargePacketCommand(const char* /*args*/) -{ - const char* stuffingString = "This is a dummy string to push the packet's size beyond 128000 bytes. "; - std::ostringstream ss; - while (ss.str().size() < 128000) - ss << stuffingString; - SendSysMessage(ss.str().c_str()); - return true; -} - -bool ChatHandler::HandleDebugSendSetPhaseShiftCommand(const char* args) -{ - if (!*args) - return false; - - uint32 PhaseShift = atoi(args); - m_session->SendSetPhaseShift(PhaseShift); - return true; -} - -bool ChatHandler::HandleDebugGetItemValueCommand(const char* args) -{ - if (!*args) - return false; - - char* e = strtok((char*)args, " "); - char* f = strtok(NULL, " "); - - if (!e || !f) - return false; - - uint32 guid = (uint32)atoi(e); - uint32 index = (uint32)atoi(f); - - Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM)); - - if (!i) - return false; - - if (index >= i->GetValuesCount()) - return false; - - uint32 value = i->GetUInt32Value(index); - - PSendSysMessage("Item %u: value at %u is %u", guid, index, value); - - return true; -} - -bool ChatHandler::HandleDebugSetItemValueCommand(const char* args) -{ - if (!*args) - return false; - - char* e = strtok((char*)args, " "); - char* f = strtok(NULL, " "); - char* g = strtok(NULL, " "); - - if (!e || !f || !g) - return false; - - uint32 guid = (uint32)atoi(e); - uint32 index = (uint32)atoi(f); - uint32 value = (uint32)atoi(g); - - Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM)); - - if (!i) - return false; - - if (index >= i->GetValuesCount()) - return false; - - i->SetUInt32Value(index, value); - - return true; -} - -bool ChatHandler::HandleDebugItemExpireCommand(const char* args) -{ - if (!*args) - return false; - - char* e = strtok((char*)args, " "); - if (!e) - return false; - - uint32 guid = (uint32)atoi(e); - - Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM)); - - if (!i) - return false; - - m_session->GetPlayer()->DestroyItem(i->GetBagSlot(),i->GetSlot(), true); - sScriptMgr.ItemExpire(m_session->GetPlayer(),i->GetProto()); - - return true; -} - -//show animation -bool ChatHandler::HandleDebugAnimCommand(const char* args) -{ - if (!*args) - return false; - - uint32 anim_id = atoi((char*)args); - m_session->GetPlayer()->HandleEmoteCommand(anim_id); - return true; -} - -bool ChatHandler::HandleDebugSetAuraStateCommand(const char* args) -{ - if (!*args) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Unit* unit = getSelectedUnit(); - if (!unit) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - int32 state = atoi((char*)args); - if (!state) - { - // reset all states - for (int i = 1; i <= 32; ++i) - unit->ModifyAuraState(AuraState(i),false); - return true; - } - - unit->ModifyAuraState(AuraState(abs(state)),state > 0); - return true; -} - -bool ChatHandler::HandleDebugSetValueCommand(const char* args) -{ - if (!*args) - return false; - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - char* pz = strtok(NULL, " "); - - if (!px || !py) - return false; - - WorldObject* target = getSelectedObject(); - if (!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - uint64 guid = target->GetGUID(); - - uint32 Opcode = (uint32)atoi(px); - if (Opcode >= target->GetValuesCount()) - { - PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount()); - return false; - } - uint32 iValue; - float fValue; - bool isint32 = true; - if (pz) - isint32 = (bool)atoi(pz); - if (isint32) - { - iValue = (uint32)atoi(py); - sLog.outDebug(GetTrinityString(LANG_SET_UINT), GUID_LOPART(guid), Opcode, iValue); - target->SetUInt32Value(Opcode , iValue); - PSendSysMessage(LANG_SET_UINT_FIELD, GUID_LOPART(guid), Opcode,iValue); - } - else - { - fValue = (float)atof(py); - sLog.outDebug(GetTrinityString(LANG_SET_FLOAT), GUID_LOPART(guid), Opcode, fValue); - target->SetFloatValue(Opcode , fValue); - PSendSysMessage(LANG_SET_FLOAT_FIELD, GUID_LOPART(guid), Opcode,fValue); - } - - return true; -} - -bool ChatHandler::HandleDebugGetValueCommand(const char* args) -{ - if (!*args) - return false; - - char* px = strtok((char*)args, " "); - char* pz = strtok(NULL, " "); - - if (!px) - return false; - - Unit* target = getSelectedUnit(); - if (!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - uint64 guid = target->GetGUID(); - - uint32 Opcode = (uint32)atoi(px); - if (Opcode >= target->GetValuesCount()) - { - PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount()); - return false; - } - uint32 iValue; - float fValue; - bool isint32 = true; - if (pz) - isint32 = (bool)atoi(pz); - - if (isint32) - { - iValue = target->GetUInt32Value(Opcode); - sLog.outDebug(GetTrinityString(LANG_GET_UINT), GUID_LOPART(guid), Opcode, iValue); - PSendSysMessage(LANG_GET_UINT_FIELD, GUID_LOPART(guid), Opcode, iValue); - } - else - { - fValue = target->GetFloatValue(Opcode); - sLog.outDebug(GetTrinityString(LANG_GET_FLOAT), GUID_LOPART(guid), Opcode, fValue); - PSendSysMessage(LANG_GET_FLOAT_FIELD, GUID_LOPART(guid), Opcode, fValue); - } - - return true; -} - -bool ChatHandler::HandleDebugMod32ValueCommand(const char* args) -{ - if (!*args) - return false; - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - - if (!px || !py) - return false; - - uint32 Opcode = (uint32)atoi(px); - int Value = atoi(py); - - if (Opcode >= m_session->GetPlayer()->GetValuesCount()) - { - PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, m_session->GetPlayer()->GetGUIDLow(), m_session->GetPlayer()->GetValuesCount()); - return false; - } - - sLog.outDebug(GetTrinityString(LANG_CHANGE_32BIT), Opcode, Value); - - int CurrentValue = (int)m_session->GetPlayer()->GetUInt32Value(Opcode); - - CurrentValue += Value; - m_session->GetPlayer()->SetUInt32Value(Opcode , (uint32)CurrentValue); - - PSendSysMessage(LANG_CHANGE_32BIT_FIELD, Opcode,CurrentValue); - - return true; -} - -bool ChatHandler::HandleDebugUpdateCommand(const char* args) -{ - if (!*args) - return false; - - uint32 updateIndex; - uint32 value; - - char* pUpdateIndex = strtok((char*)args, " "); - - Unit* chr = getSelectedUnit(); - if (chr == NULL) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if (!pUpdateIndex) - { - return true; - } - updateIndex = atoi(pUpdateIndex); - //check updateIndex - if (chr->GetTypeId() == TYPEID_PLAYER) - { - if (updateIndex >= PLAYER_END) return true; - } - else - { - if (updateIndex >= UNIT_END) return true; - } - - char* pvalue = strtok(NULL, " "); - if (!pvalue) - { - value=chr->GetUInt32Value(updateIndex); - - PSendSysMessage(LANG_UPDATE, chr->GetGUIDLow(),updateIndex,value); - return true; - } - - value=atoi(pvalue); - - PSendSysMessage(LANG_UPDATE_CHANGE, chr->GetGUIDLow(),updateIndex,value); - - chr->SetUInt32Value(updateIndex,value); - - return true; -} diff --git a/src/server/game/Chat/Level0.cpp b/src/server/game/Chat/Level0.cpp deleted file mode 100644 index ed021ac00d4..00000000000 --- a/src/server/game/Chat/Level0.cpp +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "World.h" -#include "Player.h" -#include "Opcodes.h" -#include "Chat.h" -#include "ObjectAccessor.h" -#include "Language.h" -#include "AccountMgr.h" -#include "SystemConfig.h" -#include "revision.h" -#include "Util.h" - -bool ChatHandler::HandleHelpCommand(const char* args) -{ - char* cmd = strtok((char*)args, " "); - if (!cmd) - { - ShowHelpForCommand(getCommandTable(), "help"); - ShowHelpForCommand(getCommandTable(), ""); - } - else - { - if (!ShowHelpForCommand(getCommandTable(), cmd)) - SendSysMessage(LANG_NO_HELP_CMD); - } - - return true; -} - -bool ChatHandler::HandleCommandsCommand(const char* /*args*/) -{ - ShowHelpForCommand(getCommandTable(), ""); - return true; -} - -bool ChatHandler::HandleAccountCommand(const char* /*args*/) -{ - AccountTypes gmlevel = m_session->GetSecurity(); - PSendSysMessage(LANG_ACCOUNT_LEVEL, uint32(gmlevel)); - return true; -} - -bool ChatHandler::HandleStartCommand(const char* /*args*/) -{ - Player *chr = m_session->GetPlayer(); - - if (chr->isInFlight()) - { - SendSysMessage(LANG_YOU_IN_FLIGHT); - SetSentErrorMessage(true); - return false; - } - - if (chr->isInCombat()) - { - SendSysMessage(LANG_YOU_IN_COMBAT); - SetSentErrorMessage(true); - return false; - } - - if ((chr->isDead()) || (chr->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))) - { - // if player is dead and stuck, send ghost to graveyard - chr->RepopAtGraveyard(); - return true; - } - - // cast spell Stuck - chr->CastSpell(chr,7355,false); - return true; -} - -bool ChatHandler::HandleServerInfoCommand(const char* /*args*/) -{ - uint32 PlayersNum = sWorld.GetPlayerCount(); - uint32 MaxPlayersNum = sWorld.GetMaxPlayerCount(); - uint32 activeClientsNum = sWorld.GetActiveSessionCount(); - uint32 queuedClientsNum = sWorld.GetQueuedSessionCount(); - uint32 maxActiveClientsNum = sWorld.GetMaxActiveSessionCount(); - uint32 maxQueuedClientsNum = sWorld.GetMaxQueuedSessionCount(); - std::string uptime = secsToTimeString(sWorld.GetUptime()); - uint32 updateTime = sWorld.GetUpdateTime(); - - PSendSysMessage(_FULLVERSION); - //if (m_session) - // full = _FULLVERSION(REVISION_DATE,REVISION_TIME,"|cffffffff|Hurl:" REVISION_ID "|h" REVISION_ID "|h|r"); - //else - // full = _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_ID); - - //SendSysMessage(full); - //PSendSysMessage(LANG_USING_WORLD_DB,sWorld.GetDBVersion()); - //PSendSysMessage(LANG_USING_EVENT_AI,sWorld.GetCreatureEventAIVersion()); - PSendSysMessage(LANG_CONNECTED_PLAYERS, PlayersNum, MaxPlayersNum); - PSendSysMessage(LANG_CONNECTED_USERS, activeClientsNum, maxActiveClientsNum, queuedClientsNum, maxQueuedClientsNum); - PSendSysMessage(LANG_UPTIME, uptime.c_str()); - PSendSysMessage("Update time diff: %u.", updateTime); - - return true; -} - -bool ChatHandler::HandleDismountCommand(const char* /*args*/) -{ - //If player is not mounted, so go out :) - if (!m_session->GetPlayer()->IsMounted()) - { - SendSysMessage(LANG_CHAR_NON_MOUNTED); - SetSentErrorMessage(true); - return false; - } - - if (m_session->GetPlayer()->isInFlight()) - { - SendSysMessage(LANG_YOU_IN_FLIGHT); - SetSentErrorMessage(true); - return false; - } - - m_session->GetPlayer()->Unmount(); - m_session->GetPlayer()->RemoveAurasByType(SPELL_AURA_MOUNTED); - return true; -} - -bool ChatHandler::HandleSaveCommand(const char* /*args*/) -{ - Player *player=m_session->GetPlayer(); - - // save GM account without delay and output message (testing, etc) - if (m_session->GetSecurity() > SEC_PLAYER) - { - player->SaveToDB(); - SendSysMessage(LANG_PLAYER_SAVED); - return true; - } - - // save or plan save after 20 sec (logout delay) if current next save time more this value and _not_ output any messages to prevent cheat planning - uint32 save_interval = sWorld.getConfig(CONFIG_INTERVAL_SAVE); - if ((save_interval == 0 || save_interval > 20*IN_MILISECONDS && player->GetSaveTimer() <= save_interval - 20*IN_MILISECONDS)) - player->SaveToDB(); - - return true; -} - -bool ChatHandler::HandleGMListIngameCommand(const char* /*args*/) -{ - bool first = true; - - ObjectAccessor::Guard guard(*HashMapHolder::GetLock()); - HashMapHolder::MapType &m = ObjectAccessor::Instance().GetPlayers(); - for (HashMapHolder::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) - { - AccountTypes itr_sec = itr->second->GetSession()->GetSecurity(); - if ((itr->second->isGameMaster() || (itr_sec > SEC_PLAYER && itr_sec <= sWorld.getConfig(CONFIG_GM_LEVEL_IN_GM_LIST))) && - (!m_session || itr->second->IsVisibleGloballyFor(m_session->GetPlayer()))) - { - if (first) - { - SendSysMessage(LANG_GMS_ON_SRV); - first = false; - } - - SendSysMessage(GetNameLink(itr->second).c_str()); - } - } - - if (first) - SendSysMessage(LANG_GMS_NOT_LOGGED); - - return true; -} - -bool ChatHandler::HandleAccountPasswordCommand(const char* args) -{ - if (!*args) - return false; - - char *old_pass = strtok ((char*)args, " "); - char *new_pass = strtok (NULL, " "); - char *new_pass_c = strtok (NULL, " "); - - if (!old_pass || !new_pass || !new_pass_c) - return false; - - std::string password_old = old_pass; - std::string password_new = new_pass; - std::string password_new_c = new_pass_c; - - if (strcmp(new_pass, new_pass_c) != 0) - { - SendSysMessage (LANG_NEW_PASSWORDS_NOT_MATCH); - SetSentErrorMessage (true); - return false; - } - - if (!accmgr.CheckPassword (m_session->GetAccountId(), password_old)) - { - SendSysMessage (LANG_COMMAND_WRONGOLDPASSWORD); - SetSentErrorMessage (true); - return false; - } - - AccountOpResult result = accmgr.ChangePassword(m_session->GetAccountId(), password_new); - - switch(result) - { - case AOR_OK: - SendSysMessage(LANG_COMMAND_PASSWORD); - break; - case AOR_PASS_TOO_LONG: - SendSysMessage(LANG_PASSWORD_TOO_LONG); - SetSentErrorMessage(true); - return false; - case AOR_NAME_NOT_EXIST: // not possible case, don't want get account name for output - default: - SendSysMessage(LANG_COMMAND_NOTCHANGEPASSWORD); - SetSentErrorMessage(true); - return false; - } - - return true; -} - -bool ChatHandler::HandleAccountAddonCommand(const char* args) -{ - if (!*args) - return false; - - char *szExp = strtok((char*)args," "); - - uint32 account_id = m_session->GetAccountId(); - - int expansion=atoi(szExp); //get int anyway (0 if error) - if (expansion < 0 || expansion > sWorld.getConfig(CONFIG_EXPANSION)) - return false; - - // No SQL injection - LoginDatabase.PExecute("UPDATE account SET expansion = '%d' WHERE id = '%u'", expansion, account_id); - PSendSysMessage(LANG_ACCOUNT_ADDON, expansion); - return true; -} - -bool ChatHandler::HandleAccountLockCommand(const char* args) -{ - if (!*args) - { - SendSysMessage(LANG_USE_BOL); - return true; - } - - std::string argstr = (char*)args; - if (argstr == "on") - { - LoginDatabase.PExecute("UPDATE account SET locked = '1' WHERE id = '%d'",m_session->GetAccountId()); - PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED); - return true; - } - - if (argstr == "off") - { - LoginDatabase.PExecute("UPDATE account SET locked = '0' WHERE id = '%d'",m_session->GetAccountId()); - PSendSysMessage(LANG_COMMAND_ACCLOCKUNLOCKED); - return true; - } - - SendSysMessage(LANG_USE_BOL); - return true; -} - -/// Display the 'Message of the day' for the realm -bool ChatHandler::HandleServerMotdCommand(const char* /*args*/) -{ - PSendSysMessage(LANG_MOTD_CURRENT, sWorld.GetMotd()); - return true; -} - diff --git a/src/server/game/Chat/Level1.cpp b/src/server/game/Chat/Level1.cpp deleted file mode 100644 index 11189d519a0..00000000000 --- a/src/server/game/Chat/Level1.cpp +++ /dev/null @@ -1,2960 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "AccountMgr.h" -#include "Opcodes.h" -#include "Chat.h" -#include "Log.h" -#include "MapManager.h" -#include "ObjectAccessor.h" -#include "Language.h" -#include "CellImpl.h" -#include "InstanceSaveMgr.h" -#include "Util.h" - -#ifdef _DEBUG_VMAPS -#include "VMapFactory.h" -#endif - -//-----------------------Npc Commands----------------------- -bool ChatHandler::HandleNpcSayCommand(const char* args) -{ - if (!*args) - return false; - - Creature* pCreature = getSelectedCreature(); - if (!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->MonsterSay(args, LANG_UNIVERSAL, 0); - - // make some emotes - char lastchar = args[strlen(args) - 1]; - switch(lastchar) - { - case '?': pCreature->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION); break; - case '!': pCreature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); break; - default: pCreature->HandleEmoteCommand(EMOTE_ONESHOT_TALK); break; - } - - return true; -} - -bool ChatHandler::HandleNpcYellCommand(const char* args) -{ - if (!*args) - return false; - - Creature* pCreature = getSelectedCreature(); - if (!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->MonsterYell(args, LANG_UNIVERSAL, 0); - - // make an emote - pCreature->HandleEmoteCommand(EMOTE_ONESHOT_SHOUT); - - return true; -} - -//show text emote by creature in chat -bool ChatHandler::HandleNpcTextEmoteCommand(const char* args) -{ - if (!*args) - return false; - - Creature* pCreature = getSelectedCreature(); - - if (!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->MonsterTextEmote(args, 0); - - return true; -} - -// make npc whisper to player -bool ChatHandler::HandleNpcWhisperCommand(const char* args) -{ - if (!*args) - return false; - - char* receiver_str = strtok((char*)args, " "); - char* text = strtok(NULL, ""); - - uint64 guid = m_session->GetPlayer()->GetSelection(); - Creature* pCreature = m_session->GetPlayer()->GetMap()->GetCreature(guid); - - if (!pCreature || !receiver_str || !text) - { - return false; - } - - uint64 receiver_guid= atol(receiver_str); - - // check online security - if (HasLowerSecurity(objmgr.GetPlayer(receiver_guid), 0)) - return false; - - pCreature->MonsterWhisper(text,receiver_guid); - - return true; -} -//---------------------------------------------------------- - -bool ChatHandler::HandleNameAnnounceCommand(const char* args) -{ - WorldPacket data; - if (!*args) - return false; - - sWorld.SendWorldText(LANG_ANNOUNCE_COLOR, m_session->GetPlayer()->GetName(), args); - return true; -} - -bool ChatHandler::HandleGMNameAnnounceCommand(const char* args) -{ - WorldPacket data; - if (!*args) - return false; - - sWorld.SendGMText(LANG_GM_ANNOUNCE_COLOR, m_session->GetPlayer()->GetName(), args); - return true; -} - -// global announce -bool ChatHandler::HandleAnnounceCommand(const char* args) -{ - if (!*args) - return false; - - sWorld.SendWorldText(LANG_SYSTEMMESSAGE,args); - return true; -} - -// announce to logged in GMs -bool ChatHandler::HandleGMAnnounceCommand(const char* args) -{ - if (!*args) - return false; - - sWorld.SendGMText(LANG_GM_BROADCAST,args); - return true; -} - -//notification player at the screen -bool ChatHandler::HandleNotifyCommand(const char* args) -{ - if (!*args) - return false; - - std::string str = GetTrinityString(LANG_GLOBAL_NOTIFY); - str += args; - - WorldPacket data(SMSG_NOTIFICATION, (str.size()+1)); - data << str; - sWorld.SendGlobalMessage(&data); - - return true; -} - -//notification GM at the screen -bool ChatHandler::HandleGMNotifyCommand(const char* args) -{ - if (!*args) - return false; - - std::string str = GetTrinityString(LANG_GM_NOTIFY); - str += args; - - WorldPacket data(SMSG_NOTIFICATION, (str.size()+1)); - data << str; - sWorld.SendGlobalGMMessage(&data); - - return true; -} - -//Enable\Dissable GM Mode -bool ChatHandler::HandleGMCommand(const char* args) -{ - if (!*args) - { - if (m_session->GetPlayer()->isGameMaster()) - m_session->SendNotification(LANG_GM_ON); - else - m_session->SendNotification(LANG_GM_OFF); - return true; - } - - std::string argstr = (char*)args; - - if (argstr == "on") - { - m_session->GetPlayer()->SetGameMaster(true); - m_session->SendNotification(LANG_GM_ON); - m_session->GetPlayer()->UpdateTriggerVisibility(); - #ifdef _DEBUG_VMAPS - VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager(); - vMapManager->processCommand("stoplog"); - #endif - return true; - } - - if (argstr == "off") - { - m_session->GetPlayer()->SetGameMaster(false); - m_session->SendNotification(LANG_GM_OFF); - m_session->GetPlayer()->UpdateTriggerVisibility(); - #ifdef _DEBUG_VMAPS - VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager(); - vMapManager->processCommand("startlog"); - #endif - return true; - } - - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; -} - -// Enables or disables hiding of the staff badge -bool ChatHandler::HandleGMChatCommand(const char* args) -{ - if (!*args) - { - if (m_session->GetPlayer()->isGMChat()) - m_session->SendNotification(LANG_GM_CHAT_ON); - else - m_session->SendNotification(LANG_GM_CHAT_OFF); - return true; - } - - std::string argstr = (char*)args; - - if (argstr == "on") - { - m_session->GetPlayer()->SetGMChat(true); - m_session->SendNotification(LANG_GM_CHAT_ON); - return true; - } - - if (argstr == "off") - { - m_session->GetPlayer()->SetGMChat(false); - m_session->SendNotification(LANG_GM_CHAT_OFF); - return true; - } - - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; -} - -std::string ChatHandler::PGetParseString(int32 entry, ...) -{ - const char *format = GetTrinityString(entry); - va_list ap; - char str [1024]; - va_start(ap, entry); - vsnprintf(str,1024,format, ap); - va_end(ap); - return (std::string)str; -} - -bool ChatHandler::HandleGMTicketListCommand(const char* /*args*/) -{ - SendSysMessage(LANG_COMMAND_TICKETSHOWLIST); - for (GmTicketList::iterator itr = objmgr.m_GMTicketList.begin(); itr != objmgr.m_GMTicketList.end(); ++itr) - { - if ((*itr)->closed != 0) - continue; - std::string gmname; - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, (*itr)->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, (*itr)->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - (*itr)->createtime, true, false)).c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - (*itr)->timestamp, true, false)).c_str()); - if (objmgr.GetPlayerNameByGUID((*itr)->assignedToGM, gmname)) - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - } - SendSysMessage(ss.str().c_str()); - } - return true; -} - -bool ChatHandler::HandleGMTicketListOnlineCommand(const char* /*args*/) -{ - SendSysMessage(LANG_COMMAND_TICKETSHOWONLINELIST); - for (GmTicketList::iterator itr = objmgr.m_GMTicketList.begin(); itr != objmgr.m_GMTicketList.end(); ++itr) - { - if ((*itr)->closed != 0 || !objmgr.GetPlayer((*itr)->playerGuid)) - continue; - - std::string gmname; - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, (*itr)->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, (*itr)->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - (*itr)->createtime, true, false)).c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - (*itr)->timestamp, true, false)).c_str()); - if (objmgr.GetPlayerNameByGUID((*itr)->assignedToGM, gmname)) - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - } - SendSysMessage(ss.str().c_str()); - } - return true; -} - -bool ChatHandler::HandleGMTicketListClosedCommand(const char* /*args*/) -{ - SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST); - for (GmTicketList::iterator itr = objmgr.m_GMTicketList.begin(); itr != objmgr.m_GMTicketList.end(); ++itr) - { - if ((*itr)->closed == 0) - continue; - - std::string gmname; - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, (*itr)->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, (*itr)->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - (*itr)->createtime, true, false)).c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - (*itr)->timestamp, true, false)).c_str()); - if (objmgr.GetPlayerNameByGUID((*itr)->assignedToGM, gmname)) - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - } - SendSysMessage(ss.str().c_str()); - } - return true; -} - -bool ChatHandler::HandleGMTicketGetByIdCommand(const char* args) -{ - if (!*args) - return false; - - uint64 tguid = atoi(args); - GM_Ticket *ticket = objmgr.GetGMTicket(tguid); - if (!ticket || ticket->closed != 0) - { - SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - - std::string gmname; - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - ticket->createtime, true, false)).c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - ticket->timestamp, true, false)).c_str()); - if (objmgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname)) - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - } - ss << PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, ticket->message.c_str()); - if (ticket->comment != "") - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, ticket->comment.c_str()); - } - SendSysMessage(ss.str().c_str()); - return true; -} - -bool ChatHandler::HandleGMTicketGetByNameCommand(const char* args) -{ - if (!*args) - return false; - - std::string name = (char*)args; - normalizePlayerName(name); - - Player *plr = objmgr.GetPlayer(name.c_str()); - if (!plr) - { - SendSysMessage(LANG_NO_PLAYERS_FOUND); - return true; - } - - GM_Ticket *ticket = objmgr.GetGMTicketByPlayer(plr->GetGUID()); - if (!ticket) - { - SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - - std::string gmname; - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - ticket->createtime, true, false)).c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - ticket->timestamp, true, false)).c_str()); - if (objmgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname)) - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - } - ss << PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, ticket->message.c_str()); - if (ticket->comment != "") - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, ticket->comment.c_str()); - } - SendSysMessage(ss.str().c_str()); - return true; -} - -bool ChatHandler::HandleGMTicketCloseByIdCommand(const char* args) -{ - if (!*args) - return false; - - uint64 tguid = atoi(args); - GM_Ticket *ticket = objmgr.GetGMTicket(tguid); - if (!ticket || ticket->closed != 0) - { - SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - if (ticket && ticket->assignedToGM != 0 && ticket->assignedToGM != m_session->GetPlayer()->GetGUID()) - { - PSendSysMessage(LANG_COMMAND_TICKETCANNOTCLOSE, ticket->guid); - return true; - } - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETCLOSED, m_session->GetPlayer()->GetName()); - SendGlobalGMSysMessage(ss.str().c_str()); - Player *plr = objmgr.GetPlayer(ticket->playerGuid); - objmgr.RemoveGMTicket(ticket, m_session->GetPlayer()->GetGUID()); - - if (!plr || !plr->IsInWorld()) - return true; - - // send abandon ticket - WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4); - data << uint32(9); - plr->GetSession()->SendPacket(&data); - return true; -} - -bool ChatHandler::HandleGMTicketAssignToCommand(const char* args) -{ - if (!*args) - return false; - - char* tguid = strtok((char*)args, " "); - uint64 ticketGuid = atoi(tguid); - char* targetgm = strtok(NULL, " "); - - if (!targetgm) - return false; - - std::string targm = targetgm; - if (!normalizePlayerName(targm)) - return false; - - Player *cplr = m_session->GetPlayer(); - GM_Ticket *ticket = objmgr.GetGMTicket(ticketGuid); - - if (!ticket || ticket->closed != 0) - { - SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - - uint64 tarGUID = objmgr.GetPlayerGUIDByName(targm.c_str()); - uint64 accid = objmgr.GetPlayerAccountIdByGUID(tarGUID); - uint32 gmlevel = accmgr.GetSecurity(accid, realmID); - - if (!tarGUID || gmlevel == SEC_PLAYER) - { - SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A); - return true; - } - - if (ticket->assignedToGM == tarGUID) - { - PSendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_B, ticket->guid); - return true; - } - - std::string gmname; - objmgr.GetPlayerNameByGUID(tarGUID, gmname); - if (ticket->assignedToGM != 0 && ticket->assignedToGM != cplr->GetGUID()) - { - PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->guid, gmname.c_str()); - return true; - } - - ticket->assignedToGM = tarGUID; - objmgr.AddOrUpdateGMTicket(*ticket); - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - SendGlobalGMSysMessage(ss.str().c_str()); - return true; -} - -bool ChatHandler::HandleGMTicketUnAssignCommand(const char* args) -{ - if (!*args) - return false; - - uint64 ticketGuid = atoi(args); - Player *cplr = m_session->GetPlayer(); - GM_Ticket *ticket = objmgr.GetGMTicket(ticketGuid); - - if (!ticket|| ticket->closed != 0) - { - SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - if (ticket->assignedToGM == 0) - { - PSendSysMessage(LANG_COMMAND_TICKETNOTASSIGNED, ticket->guid); - return true; - } - - std::string gmname; - objmgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname); - Player *plr = objmgr.GetPlayer(ticket->assignedToGM); - if (plr && plr->IsInWorld() && plr->GetSession()->GetSecurity() > cplr->GetSession()->GetSecurity()) - { - SendSysMessage(LANG_COMMAND_TICKETUNASSIGNSECURITY); - return true; - } - - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTUNASSIGNED, cplr->GetName()); - SendGlobalGMSysMessage(ss.str().c_str()); - ticket->assignedToGM = 0; - objmgr.AddOrUpdateGMTicket(*ticket); - return true; -} - -bool ChatHandler::HandleGMTicketCommentCommand(const char* args) -{ - if (!*args) - return false; - - char* tguid = strtok((char*)args, " "); - uint64 ticketGuid = atoi(tguid); - char* comment = strtok(NULL, "\n"); - - if (!comment) - return false; - - Player *cplr = m_session->GetPlayer(); - GM_Ticket *ticket = objmgr.GetGMTicket(ticketGuid); - - if (!ticket || ticket->closed != 0) - { - PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - if (ticket->assignedToGM != 0 && ticket->assignedToGM != cplr->GetGUID()) - { - PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->guid); - return true; - } - - std::string gmname; - objmgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname); - ticket->comment = comment; - objmgr.AddOrUpdateGMTicket(*ticket); - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); - if (objmgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname)) - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - } - ss << PGetParseString(LANG_COMMAND_TICKETLISTADDCOMMENT, cplr->GetName(), ticket->comment.c_str()); - SendGlobalGMSysMessage(ss.str().c_str()); - return true; -} - -bool ChatHandler::HandleGMTicketDeleteByIdCommand(const char* args) -{ - if (!*args) - return false; - uint64 ticketGuid = atoi(args); - GM_Ticket *ticket = objmgr.GetGMTicket(ticketGuid); - - if (!ticket) - { - SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - if (ticket->closed == 0) - { - SendSysMessage(LANG_COMMAND_TICKETCLOSEFIRST); - return true; - } - - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETDELETED, m_session->GetPlayer()->GetName()); - SendGlobalGMSysMessage(ss.str().c_str()); - Player *plr = objmgr.GetPlayer(ticket->playerGuid); - objmgr.RemoveGMTicket(ticket, -1, true); - if (plr && plr->IsInWorld()) - { - // Force abandon ticket - WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4); - data << uint32(9); - plr->GetSession()->SendPacket(&data); - } - - ticket = NULL; - return true; -} - -bool ChatHandler::HandleGMTicketReloadCommand(const char*) -{ - objmgr.LoadGMTickets(); - return true; -} - -//Enable\Dissable Invisible mode -bool ChatHandler::HandleGMVisibleCommand(const char* args) -{ - if (!*args) - { - PSendSysMessage(LANG_YOU_ARE, m_session->GetPlayer()->isGMVisible() ? GetTrinityString(LANG_VISIBLE) : GetTrinityString(LANG_INVISIBLE)); - return true; - } - - std::string argstr = (char*)args; - - if (argstr == "on") - { - m_session->GetPlayer()->SetGMVisible(true); - m_session->SendNotification(LANG_INVISIBLE_VISIBLE); - return true; - } - - if (argstr == "off") - { - m_session->SendNotification(LANG_INVISIBLE_INVISIBLE); - m_session->GetPlayer()->SetGMVisible(false); - return true; - } - - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; -} - -bool ChatHandler::HandleGPSCommand(const char* args) -{ - WorldObject *obj = NULL; - if (*args) - { - uint64 guid = extractGuidFromLink((char*)args); - if (guid) - obj = (WorldObject*)ObjectAccessor::GetObjectByTypeMask(*m_session->GetPlayer(),guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); - - if (!obj) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - } - else - { - obj = getSelectedUnit(); - - if (!obj) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - } - CellPair cell_val = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); - Cell cell(cell_val); - - uint32 zone_id, area_id; - obj->GetZoneAndAreaId(zone_id,area_id); - - MapEntry const* mapEntry = sMapStore.LookupEntry(obj->GetMapId()); - AreaTableEntry const* zoneEntry = GetAreaEntryByAreaID(zone_id); - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(area_id); - - float zone_x = obj->GetPositionX(); - float zone_y = obj->GetPositionY(); - - Map2ZoneCoordinates(zone_x,zone_y,zone_id); - - Map const *map = obj->GetMap(); - float ground_z = map->GetHeight(obj->GetPositionX(), obj->GetPositionY(), MAX_HEIGHT); - float floor_z = map->GetHeight(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ()); - - GridPair p = Trinity::ComputeGridPair(obj->GetPositionX(), obj->GetPositionY()); - - int gx=63-p.x_coord; - int gy=63-p.y_coord; - - uint32 have_map = Map::ExistMap(obj->GetMapId(),gx,gy) ? 1 : 0; - uint32 have_vmap = Map::ExistVMap(obj->GetMapId(),gx,gy) ? 1 : 0; - - if(have_vmap) - { - if(map->IsOutdoors(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ())) - PSendSysMessage("You are outdoors"); - else - PSendSysMessage("You are indoor"); - } - else PSendSysMessage("no VMAP available for area info"); - - PSendSysMessage(LANG_MAP_POSITION, - obj->GetMapId(), (mapEntry ? mapEntry->name[GetSessionDbcLocale()] : ""), - zone_id, (zoneEntry ? zoneEntry->area_name[GetSessionDbcLocale()] : ""), - area_id, (areaEntry ? areaEntry->area_name[GetSessionDbcLocale()] : ""), - obj->GetPhaseMask(), - obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(), - cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), obj->GetInstanceId(), - zone_x, zone_y, ground_z, floor_z, have_map, have_vmap); - - sLog.outDebug("Player %s GPS call for %s '%s' (%s: %u):", - m_session ? GetNameLink().c_str() : GetTrinityString(LANG_CONSOLE_COMMAND), - (obj->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), obj->GetName(), - (obj->GetTypeId() == TYPEID_PLAYER ? "GUID" : "Entry"), (obj->GetTypeId() == TYPEID_PLAYER ? obj->GetGUIDLow(): obj->GetEntry())); - sLog.outDebug(GetTrinityString(LANG_MAP_POSITION), - obj->GetMapId(), (mapEntry ? mapEntry->name[sWorld.GetDefaultDbcLocale()] : ""), - zone_id, (zoneEntry ? zoneEntry->area_name[sWorld.GetDefaultDbcLocale()] : ""), - area_id, (areaEntry ? areaEntry->area_name[sWorld.GetDefaultDbcLocale()] : ""), - obj->GetPhaseMask(), - obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(), - cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), obj->GetInstanceId(), - zone_x, zone_y, ground_z, floor_z, have_map, have_vmap); - - LiquidData liquid_status; - ZLiquidStatus res = map->getLiquidStatus(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), MAP_ALL_LIQUIDS, &liquid_status); - if (res) - { - PSendSysMessage(LANG_LIQUID_STATUS, liquid_status.level, liquid_status.depth_level, liquid_status.type, res); - } - return true; -} - -//Summon Player -bool ChatHandler::HandleNamegoCommand(const char* args) -{ - Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) - return false; - - Player* _player = m_session->GetPlayer(); - if (target == _player || target_guid == _player->GetGUID()) - { - PSendSysMessage(LANG_CANT_TELEPORT_SELF); - SetSentErrorMessage(true); - return false; - } - - if (target) - { - std::string nameLink = playerLink(target_name); - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - if (target->IsBeingTeleported()) - { - PSendSysMessage(LANG_IS_TELEPORTED, nameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - - Map* pMap = m_session->GetPlayer()->GetMap(); - - if (pMap->IsBattleGroundOrArena()) - { - // only allow if gm mode is on - if (!target->isGameMaster()) - { - PSendSysMessage(LANG_CANNOT_GO_TO_BG_GM,nameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - // if both players are in different bgs - else if (target->GetBattleGroundId() && m_session->GetPlayer()->GetBattleGroundId() != target->GetBattleGroundId()) - { - target->LeaveBattleground(false); // Note: should be changed so target gets no Deserter debuff - //PSendSysMessage(LANG_CANNOT_GO_TO_BG_FROM_BG,nameLink.c_str()); - //SetSentErrorMessage(true); - //return false; - } - // all's well, set bg id - // when porting out from the bg, it will be reset to 0 - target->SetBattleGroundId(m_session->GetPlayer()->GetBattleGroundId(), m_session->GetPlayer()->GetBattleGroundTypeId()); - // remember current position as entry point for return at bg end teleportation - if (!target->GetMap()->IsBattleGroundOrArena()) - target->SetBattleGroundEntryPoint(); - } - else if (pMap->IsDungeon()) - { - Map* cMap = target->GetMap(); - if (cMap->Instanceable() && cMap->GetInstanceId() != pMap->GetInstanceId()) - { - target->UnbindInstance(pMap->GetInstanceId(), target->GetDungeonDifficulty(), true); - // cannot summon from instance to instance - //PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,nameLink.c_str()); - //SetSentErrorMessage(true); - //return false; - } - - // we are in instance, and can summon only player in our group with us as lead - if (!m_session->GetPlayer()->GetGroup() || !target->GetGroup() || - (target->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) || - (m_session->GetPlayer()->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID())) - // the last check is a bit excessive, but let it be, just in case - { - PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,nameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - } - - PSendSysMessage(LANG_SUMMONING, nameLink.c_str(),""); - if (needReportToTarget(target)) - ChatHandler(target).PSendSysMessage(LANG_SUMMONED_BY, playerLink(_player->GetName()).c_str()); - - // stop flight if need - if (target->isInFlight()) - { - target->GetMotionMaster()->MovementExpired(); - target->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - target->SaveRecallPosition(); - - // before GM - float x,y,z; - m_session->GetPlayer()->GetClosePoint(x,y,z,target->GetObjectSize()); - target->TeleportTo(m_session->GetPlayer()->GetMapId(),x,y,z,target->GetOrientation()); - target->SetPhaseMask(m_session->GetPlayer()->GetPhaseMask(), true); - } - else - { - // check offline security - if (HasLowerSecurity(NULL, target_guid)) - return false; - - std::string nameLink = playerLink(target_name); - - PSendSysMessage(LANG_SUMMONING, nameLink.c_str(),GetTrinityString(LANG_OFFLINE)); - - // in point where GM stay - Player::SavePositionInDB(m_session->GetPlayer()->GetMapId(), - m_session->GetPlayer()->GetPositionX(), - m_session->GetPlayer()->GetPositionY(), - m_session->GetPlayer()->GetPositionZ(), - m_session->GetPlayer()->GetOrientation(), - m_session->GetPlayer()->GetZoneId(), - target_guid); - } - - return true; -} - -//Teleport to Player -bool ChatHandler::HandleGonameCommand(const char* args) -{ - Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) - return false; - - Player* _player = m_session->GetPlayer(); - if (target == _player || target_guid == _player->GetGUID()) - { - SendSysMessage(LANG_CANT_TELEPORT_SELF); - SetSentErrorMessage(true); - return false; - } - - if (target) - { - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - std::string chrNameLink = playerLink(target_name); - - Map* cMap = target->GetMap(); - if (cMap->IsBattleGroundOrArena()) - { - // only allow if gm mode is on - if (!_player->isGameMaster()) - { - PSendSysMessage(LANG_CANNOT_GO_TO_BG_GM,chrNameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - // if both players are in different bgs - else if (_player->GetBattleGroundId() && _player->GetBattleGroundId() != target->GetBattleGroundId()) - { - _player->LeaveBattleground(false); // Note: should be changed so _player gets no Deserter debuff - //PSendSysMessage(LANG_CANNOT_GO_TO_BG_FROM_BG,chrNameLink.c_str()); - //SetSentErrorMessage(true); - //return false; - } - // all's well, set bg id - // when porting out from the bg, it will be reset to 0 - _player->SetBattleGroundId(target->GetBattleGroundId(), target->GetBattleGroundTypeId()); - // remember current position as entry point for return at bg end teleportation - if (!_player->GetMap()->IsBattleGroundOrArena()) - _player->SetBattleGroundEntryPoint(); - } - else if (cMap->IsDungeon()) - { - //Map* pMap = _player->GetMap(); - - // we have to go to instance, and can go to player only if: - // 1) we are in his group (either as leader or as member) - // 2) we are not bound to any group and have GM mode on - if (_player->GetGroup()) - { - // we are in group, we can go only if we are in the player group - if (_player->GetGroup() != target->GetGroup()) - { - PSendSysMessage(LANG_CANNOT_GO_TO_INST_PARTY,chrNameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - } - else - { - // we are not in group, let's verify our GM mode - if (!_player->isGameMaster()) - { - PSendSysMessage(LANG_CANNOT_GO_TO_INST_GM,chrNameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - } - - // if the player or the player's group is bound to another instance - // the player will not be bound to another one - InstancePlayerBind *pBind = _player->GetBoundInstance(target->GetMapId(), target->GetDifficulty(cMap->IsRaid())); - if (!pBind) - { - Group *group = _player->GetGroup(); - // if no bind exists, create a solo bind - InstanceGroupBind *gBind = group ? group->GetBoundInstance(target) : NULL; // if no bind exists, create a solo bind - if (!gBind) - if (InstanceSave *save = sInstanceSaveManager.GetInstanceSave(target->GetInstanceId())) - _player->BindToInstance(save, !save->CanReset()); - } - - if (cMap->IsRaid()) - _player->SetRaidDifficulty(target->GetRaidDifficulty()); - else - _player->SetDungeonDifficulty(target->GetDungeonDifficulty()); - } - - PSendSysMessage(LANG_APPEARING_AT, chrNameLink.c_str()); - //if (needReportToTarget(target)) - // ChatHandler(target).PSendSysMessage(LANG_APPEARING_TO, GetNameLink().c_str()); - - // stop flight if need - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - // to point to see at target with same orientation - float x,y,z; - target->GetContactPoint(_player,x,y,z); - - _player->TeleportTo(target->GetMapId(), x, y, z, _player->GetAngle(target), TELE_TO_GM_MODE); - _player->SetPhaseMask(target->GetPhaseMask(), true); - } - else - { - // check offline security - if (HasLowerSecurity(NULL, target_guid)) - return false; - - std::string nameLink = playerLink(target_name); - - PSendSysMessage(LANG_APPEARING_AT, nameLink.c_str()); - - // to point where player stay (if loaded) - float x,y,z,o; - uint32 map; - bool in_flight; - if (!Player::LoadPositionFromDB(map,x,y,z,o,in_flight,target_guid)) - return false; - - // stop flight if need - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(map, x, y, z,_player->GetOrientation()); - } - - return true; -} - -// Teleport player to last position -bool ChatHandler::HandleRecallCommand(const char* args) -{ - Player* target; - if (!extractPlayerTarget((char*)args,&target)) - return false; - - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - if (target->IsBeingTeleported()) - { - PSendSysMessage(LANG_IS_TELEPORTED, GetNameLink(target).c_str()); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if (target->isInFlight()) - { - target->GetMotionMaster()->MovementExpired(); - target->CleanupAfterTaxiFlight(); - } - - target->TeleportTo(target->m_recallMap, target->m_recallX, target->m_recallY, target->m_recallZ, target->m_recallO); - return true; -} - -//Edit Player HP -bool ChatHandler::HandleModifyHPCommand(const char* args) -{ - if (!*args) - return false; - - int32 hp = atoi((char*)args); - int32 hpm = atoi((char*)args); - - if (hp < 1 || hpm < 1 || hpm < hp) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if (HasLowerSecurity(chr, 0)) - return false; - - PSendSysMessage(LANG_YOU_CHANGE_HP, GetNameLink(chr).c_str(), hp, hpm); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_HP_CHANGED, GetNameLink().c_str(), hp, hpm); - - chr->SetMaxHealth(hpm); - chr->SetHealth(hp); - - return true; -} - -//Edit Player Mana -bool ChatHandler::HandleModifyManaCommand(const char* args) -{ - if (!*args) - return false; - - // char* pmana = strtok((char*)args, " "); - // if (!pmana) - // return false; - - // char* pmanaMax = strtok(NULL, " "); - // if (!pmanaMax) - // return false; - - // int32 manam = atoi(pmanaMax); - // int32 mana = atoi(pmana); - int32 mana = atoi((char*)args); - int32 manam = atoi((char*)args); - - if (mana <= 0 || manam <= 0 || manam < mana) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(chr, 0)) - return false; - - PSendSysMessage(LANG_YOU_CHANGE_MANA, GetNameLink(chr).c_str(), mana, manam); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_MANA_CHANGED, GetNameLink().c_str(), mana, manam); - - chr->SetMaxPower(POWER_MANA,manam); - chr->SetPower(POWER_MANA, mana); - - return true; -} - -//Edit Player Energy -bool ChatHandler::HandleModifyEnergyCommand(const char* args) -{ - if (!*args) - return false; - - // char* pmana = strtok((char*)args, " "); - // if (!pmana) - // return false; - - // char* pmanaMax = strtok(NULL, " "); - // if (!pmanaMax) - // return false; - - // int32 manam = atoi(pmanaMax); - // int32 mana = atoi(pmana); - - int32 energy = atoi((char*)args)*10; - int32 energym = atoi((char*)args)*10; - - if (energy <= 0 || energym <= 0 || energym < energy) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (!chr) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(chr, 0)) - return false; - - PSendSysMessage(LANG_YOU_CHANGE_ENERGY, GetNameLink(chr).c_str(), energy/10, energym/10); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_ENERGY_CHANGED, GetNameLink().c_str(), energy/10, energym/10); - - chr->SetMaxPower(POWER_ENERGY,energym); - chr->SetPower(POWER_ENERGY, energy); - - sLog.outDetail(GetTrinityString(LANG_CURRENT_ENERGY),chr->GetMaxPower(POWER_ENERGY)); - - return true; -} - -//Edit Player Rage -bool ChatHandler::HandleModifyRageCommand(const char* args) -{ - if (!*args) - return false; - - // char* pmana = strtok((char*)args, " "); - // if (!pmana) - // return false; - - // char* pmanaMax = strtok(NULL, " "); - // if (!pmanaMax) - // return false; - - // int32 manam = atoi(pmanaMax); - // int32 mana = atoi(pmana); - - int32 rage = atoi((char*)args)*10; - int32 ragem = atoi((char*)args)*10; - - if (rage <= 0 || ragem <= 0 || ragem < rage) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(chr, 0)) - return false; - - PSendSysMessage(LANG_YOU_CHANGE_RAGE, GetNameLink(chr).c_str(), rage/10, ragem/10); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_RAGE_CHANGED, GetNameLink().c_str(), rage/10, ragem/10); - - chr->SetMaxPower(POWER_RAGE,ragem); - chr->SetPower(POWER_RAGE, rage); - - return true; -} - -// Edit Player Runic Power -bool ChatHandler::HandleModifyRunicPowerCommand(const char* args) -{ - if (!*args) - return false; - - int32 rune = atoi((char*)args)*10; - int32 runem = atoi((char*)args)*10; - - if (rune <= 0 || runem <= 0 || runem < rune) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_RUNIC_POWER, GetNameLink(chr).c_str(), rune/10, runem/10); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_RUNIC_POWER_CHANGED, GetNameLink().c_str(), rune/10, runem/10); - - chr->SetMaxPower(POWER_RUNIC_POWER,runem); - chr->SetPower(POWER_RUNIC_POWER, rune); - - return true; -} - -//Edit Player Faction -bool ChatHandler::HandleModifyFactionCommand(const char* args) -{ - if (!*args) - return false; - - char* pfactionid = extractKeyFromLink((char*)args,"Hfaction"); - - Creature* chr = getSelectedCreature(); - if (!chr) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if (!pfactionid) - { - if (chr) - { - uint32 factionid = chr->getFaction(); - uint32 flag = chr->GetUInt32Value(UNIT_FIELD_FLAGS); - uint32 npcflag = chr->GetUInt32Value(UNIT_NPC_FLAGS); - uint32 dyflag = chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS); - PSendSysMessage(LANG_CURRENT_FACTION,chr->GetGUIDLow(),factionid,flag,npcflag,dyflag); - } - return true; - } - - if (!chr) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - uint32 factionid = atoi(pfactionid); - uint32 flag; - - char *pflag = strtok(NULL, " "); - if (!pflag) - flag = chr->GetUInt32Value(UNIT_FIELD_FLAGS); - else - flag = atoi(pflag); - - char* pnpcflag = strtok(NULL, " "); - - uint32 npcflag; - if (!pnpcflag) - npcflag = chr->GetUInt32Value(UNIT_NPC_FLAGS); - else - npcflag = atoi(pnpcflag); - - char* pdyflag = strtok(NULL, " "); - - uint32 dyflag; - if (!pdyflag) - dyflag = chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS); - else - dyflag = atoi(pdyflag); - - if (!sFactionTemplateStore.LookupEntry(factionid)) - { - PSendSysMessage(LANG_WRONG_FACTION, factionid); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_FACTION, chr->GetGUIDLow(),factionid,flag,npcflag,dyflag); - - chr->setFaction(factionid); - chr->SetUInt32Value(UNIT_FIELD_FLAGS,flag); - chr->SetUInt32Value(UNIT_NPC_FLAGS,npcflag); - chr->SetUInt32Value(UNIT_DYNAMIC_FLAGS,dyflag); - - return true; -} - -//Edit Player Spell -bool ChatHandler::HandleModifySpellCommand(const char* args) -{ - if (!*args) return false; - char* pspellflatid = strtok((char*)args, " "); - if (!pspellflatid) - return false; - - char* pop = strtok(NULL, " "); - if (!pop) - return false; - - char* pval = strtok(NULL, " "); - if (!pval) - return false; - - uint16 mark; - - char* pmark = strtok(NULL, " "); - - uint8 spellflatid = atoi(pspellflatid); - uint8 op = atoi(pop); - uint16 val = atoi(pval); - if (!pmark) - mark = 65535; - else - mark = atoi(pmark); - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(chr, 0)) - return false; - - PSendSysMessage(LANG_YOU_CHANGE_SPELLFLATID, spellflatid, val, mark, GetNameLink(chr).c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_SPELLFLATID_CHANGED, GetNameLink().c_str(), spellflatid, val, mark); - - WorldPacket data(SMSG_SET_FLAT_SPELL_MODIFIER, (1+1+2+2)); - data << uint8(spellflatid); - data << uint8(op); - data << uint16(val); - data << uint16(mark); - chr->GetSession()->SendPacket(&data); - - return true; -} - -//Edit Player TP -bool ChatHandler::HandleModifyTalentCommand (const char* args) -{ - if (!*args) - return false; - - int tp = atoi((char*)args); - if (tp < 0) - return false; - - Unit* target = getSelectedUnit(); - if (!target) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if (target->GetTypeId() == TYPEID_PLAYER) - { - // check online security - if (HasLowerSecurity((Player*)target, 0)) - return false; - target->ToPlayer()->SetFreeTalentPoints(tp); - target->ToPlayer()->SendTalentsInfoData(false); - return true; - } - else if (target->ToCreature()->isPet()) - { - Unit *owner = target->GetOwner(); - if (owner && owner->GetTypeId() == TYPEID_PLAYER && ((Pet *)target)->IsPermanentPetFor(owner->ToPlayer())) - { - // check online security - if (HasLowerSecurity((Player*)owner, 0)) - return false; - ((Pet *)target)->SetFreeTalentPoints(tp); - owner->ToPlayer()->SendTalentsInfoData(true); - return true; - } - } - - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; -} - -//Enable On\OFF all taxi paths -bool ChatHandler::HandleTaxiCheatCommand(const char* args) -{ - if (!*args) - { - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; - } - - std::string argstr = (char*)args; - - Player *chr = getSelectedPlayer(); - if (!chr) - { - chr=m_session->GetPlayer(); - } - - // check online security - else if (HasLowerSecurity(chr, 0)) - return false; - - if (argstr == "on") - { - chr->SetTaxiCheater(true); - PSendSysMessage(LANG_YOU_GIVE_TAXIS, GetNameLink(chr).c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_TAXIS_ADDED, GetNameLink().c_str()); - return true; - } - - if (argstr == "off") - { - chr->SetTaxiCheater(false); - PSendSysMessage(LANG_YOU_REMOVE_TAXIS, GetNameLink(chr).c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_TAXIS_REMOVED, GetNameLink().c_str()); - - return true; - } - - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; -} - -//Edit Player Aspeed -bool ChatHandler::HandleModifyASpeedCommand(const char* args) -{ - if (!*args) - return false; - - float ASpeed = (float)atof((char*)args); - - if (ASpeed > 50.0f || ASpeed < 0.1f) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(chr, 0)) - return false; - - std::string chrNameLink = GetNameLink(chr); - - if (chr->isInFlight()) - { - PSendSysMessage(LANG_CHAR_IN_FLIGHT,chrNameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_ASPEED, ASpeed, chrNameLink.c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_ASPEED_CHANGED, GetNameLink().c_str(), ASpeed); - - chr->SetSpeed(MOVE_WALK, ASpeed,true); - chr->SetSpeed(MOVE_RUN, ASpeed,true); - chr->SetSpeed(MOVE_SWIM, ASpeed,true); - //chr->SetSpeed(MOVE_TURN, ASpeed,true); - chr->SetSpeed(MOVE_FLIGHT, ASpeed,true); - return true; -} - -//Edit Player Speed -bool ChatHandler::HandleModifySpeedCommand(const char* args) -{ - if (!*args) - return false; - - float Speed = (float)atof((char*)args); - - if (Speed > 50.0f || Speed < 0.1f) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(chr, 0)) - return false; - - std::string chrNameLink = GetNameLink(chr); - - if (chr->isInFlight()) - { - PSendSysMessage(LANG_CHAR_IN_FLIGHT,chrNameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_SPEED, Speed, chrNameLink.c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_SPEED_CHANGED, GetNameLink().c_str(), Speed); - - chr->SetSpeed(MOVE_RUN,Speed,true); - - return true; -} - -//Edit Player Swim Speed -bool ChatHandler::HandleModifySwimCommand(const char* args) -{ - if (!*args) - return false; - - float Swim = (float)atof((char*)args); - - if (Swim > 50.0f || Swim < 0.1f) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(chr, 0)) - return false; - - std::string chrNameLink = GetNameLink(chr); - - if (chr->isInFlight()) - { - PSendSysMessage(LANG_CHAR_IN_FLIGHT,chrNameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_SWIM_SPEED, Swim, chrNameLink.c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_SWIM_SPEED_CHANGED, GetNameLink().c_str(), Swim); - - chr->SetSpeed(MOVE_SWIM,Swim,true); - - return true; -} - -//Edit Player Walk Speed -bool ChatHandler::HandleModifyBWalkCommand(const char* args) -{ - if (!*args) - return false; - - float BSpeed = (float)atof((char*)args); - - if (BSpeed > 50.0f || BSpeed < 0.1f) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(chr, 0)) - return false; - - std::string chrNameLink = GetNameLink(chr); - - if (chr->isInFlight()) - { - PSendSysMessage(LANG_CHAR_IN_FLIGHT,chrNameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_YOU_CHANGE_BACK_SPEED, BSpeed, chrNameLink.c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_BACK_SPEED_CHANGED, GetNameLink().c_str(), BSpeed); - - chr->SetSpeed(MOVE_RUN_BACK,BSpeed,true); - - return true; -} - -//Edit Player Fly -bool ChatHandler::HandleModifyFlyCommand(const char* args) -{ - if (!*args) - return false; - - float FSpeed = (float)atof((char*)args); - - if (FSpeed > 50.0f || FSpeed < 0.1f) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(chr, 0)) - return false; - - PSendSysMessage(LANG_YOU_CHANGE_FLY_SPEED, FSpeed, GetNameLink(chr).c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_FLY_SPEED_CHANGED, GetNameLink().c_str(), FSpeed); - - chr->SetSpeed(MOVE_FLIGHT,FSpeed,true); - - return true; -} - -//Edit Player Scale -bool ChatHandler::HandleModifyScaleCommand(const char* args) -{ - if (!*args) - return false; - - float Scale = (float)atof((char*)args); - if (Scale > 10.0f || Scale < 0.1f) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(chr, 0)) - return false; - - PSendSysMessage(LANG_YOU_CHANGE_SIZE, Scale, GetNameLink(chr).c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_SIZE_CHANGED, GetNameLink().c_str(), Scale); - - chr->SetFloatValue(OBJECT_FIELD_SCALE_X, Scale); - - return true; -} - -//Enable Player mount -bool ChatHandler::HandleModifyMountCommand(const char* args) -{ - if (!*args) - return false; - - uint16 mId = 1147; - float speed = (float)15; - uint32 num = 0; - - num = atoi((char*)args); - switch(num) - { - case 1: - mId=14340; - break; - case 2: - mId=4806; - break; - case 3: - mId=6471; - break; - case 4: - mId=12345; - break; - case 5: - mId=6472; - break; - case 6: - mId=6473; - break; - case 7: - mId=10670; - break; - case 8: - mId=10719; - break; - case 9: - mId=10671; - break; - case 10: - mId=10672; - break; - case 11: - mId=10720; - break; - case 12: - mId=14349; - break; - case 13: - mId=11641; - break; - case 14: - mId=12244; - break; - case 15: - mId=12242; - break; - case 16: - mId=14578; - break; - case 17: - mId=14579; - break; - case 18: - mId=14349; - break; - case 19: - mId=12245; - break; - case 20: - mId=14335; - break; - case 21: - mId=207; - break; - case 22: - mId=2328; - break; - case 23: - mId=2327; - break; - case 24: - mId=2326; - break; - case 25: - mId=14573; - break; - case 26: - mId=14574; - break; - case 27: - mId=14575; - break; - case 28: - mId=604; - break; - case 29: - mId=1166; - break; - case 30: - mId=2402; - break; - case 31: - mId=2410; - break; - case 32: - mId=2409; - break; - case 33: - mId=2408; - break; - case 34: - mId=2405; - break; - case 35: - mId=14337; - break; - case 36: - mId=6569; - break; - case 37: - mId=10661; - break; - case 38: - mId=10666; - break; - case 39: - mId=9473; - break; - case 40: - mId=9476; - break; - case 41: - mId=9474; - break; - case 42: - mId=14374; - break; - case 43: - mId=14376; - break; - case 44: - mId=14377; - break; - case 45: - mId=2404; - break; - case 46: - mId=2784; - break; - case 47: - mId=2787; - break; - case 48: - mId=2785; - break; - case 49: - mId=2736; - break; - case 50: - mId=2786; - break; - case 51: - mId=14347; - break; - case 52: - mId=14346; - break; - case 53: - mId=14576; - break; - case 54: - mId=9695; - break; - case 55: - mId=9991; - break; - case 56: - mId=6448; - break; - case 57: - mId=6444; - break; - case 58: - mId=6080; - break; - case 59: - mId=6447; - break; - case 60: - mId=4805; - break; - case 61: - mId=9714; - break; - case 62: - mId=6448; - break; - case 63: - mId=6442; - break; - case 64: - mId=14632; - break; - case 65: - mId=14332; - break; - case 66: - mId=14331; - break; - case 67: - mId=8469; - break; - case 68: - mId=2830; - break; - case 69: - mId=2346; - break; - default: - SendSysMessage(LANG_NO_MOUNT); - SetSentErrorMessage(true); - return false; - } - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(chr, 0)) - return false; - - PSendSysMessage(LANG_YOU_GIVE_MOUNT, GetNameLink(chr).c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_MOUNT_GIVED, GetNameLink().c_str()); - - chr->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP); - chr->Mount(mId); - - WorldPacket data(SMSG_FORCE_RUN_SPEED_CHANGE, (8+4+1+4)); - data.append(chr->GetPackGUID()); - data << (uint32)0; - data << (uint8)0; //new 2.1.0 - data << float(speed); - chr->SendMessageToSet(&data, true); - - data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE, (8+4+4)); - data.append(chr->GetPackGUID()); - data << (uint32)0; - data << float(speed); - chr->SendMessageToSet(&data, true); - - return true; -} - -//Edit Player money -bool ChatHandler::HandleModifyMoneyCommand(const char* args) -{ - if (!*args) - return false; - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(chr, 0)) - return false; - - int32 addmoney = atoi((char*)args); - - uint32 moneyuser = chr->GetMoney(); - - if (addmoney < 0) - { - int32 newmoney = int32(moneyuser) + addmoney; - - sLog.outDetail(GetTrinityString(LANG_CURRENT_MONEY), moneyuser, addmoney, newmoney); - if (newmoney <= 0) - { - PSendSysMessage(LANG_YOU_TAKE_ALL_MONEY, GetNameLink(chr).c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_ALL_MONEY_GONE, GetNameLink().c_str()); - - chr->SetMoney(0); - } - else - { - if (newmoney > MAX_MONEY_AMOUNT) - newmoney = MAX_MONEY_AMOUNT; - - PSendSysMessage(LANG_YOU_TAKE_MONEY, abs(addmoney), GetNameLink(chr).c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_MONEY_TAKEN, GetNameLink().c_str(), abs(addmoney)); - chr->SetMoney(newmoney); - } - } - else - { - PSendSysMessage(LANG_YOU_GIVE_MONEY, addmoney, GetNameLink(chr).c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_MONEY_GIVEN, GetNameLink().c_str(), addmoney); - - if (addmoney >=MAX_MONEY_AMOUNT) - chr->SetMoney(MAX_MONEY_AMOUNT); - else - chr->ModifyMoney(addmoney); - } - - sLog.outDetail(GetTrinityString(LANG_NEW_MONEY), moneyuser, addmoney, chr->GetMoney()); - - return true; -} - -//Edit Unit field -bool ChatHandler::HandleModifyBitCommand(const char* args) -{ - if (!*args) - return false; - - Unit *unit = getSelectedUnit(); - if (!unit) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (unit->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity(unit->ToPlayer(), 0)) - return false; - - char* pField = strtok((char*)args, " "); - if (!pField) - return false; - - char* pBit = strtok(NULL, " "); - if (!pBit) - return false; - - uint16 field = atoi(pField); - uint32 bit = atoi(pBit); - - if (field < OBJECT_END || field >= unit->GetValuesCount()) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - if (bit < 1 || bit > 32) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - if (unit->HasFlag(field, (1<<(bit-1)))) - { - unit->RemoveFlag(field, (1<<(bit-1))); - PSendSysMessage(LANG_REMOVE_BIT, bit, field); - } - else - { - unit->SetFlag(field, (1<<(bit-1))); - PSendSysMessage(LANG_SET_BIT, bit, field); - } - return true; -} - -bool ChatHandler::HandleModifyHonorCommand (const char* args) -{ - if (!*args) - return false; - - Player *target = getSelectedPlayer(); - if (!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - int32 amount = (uint32)atoi(args); - - target->ModifyHonorPoints(amount); - - PSendSysMessage(LANG_COMMAND_MODIFY_HONOR, GetNameLink(target).c_str(), target->GetHonorPoints()); - - return true; -} - -bool ChatHandler::HandleTeleCommand(const char * args) -{ - if (!*args) - return false; - - Player* _player = m_session->GetPlayer(); - - // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r - GameTele const* tele = extractGameTeleFromLink((char*)args); - - if (!tele) - { - SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); - SetSentErrorMessage(true); - return false; - } - - if (_player->isInCombat()) - { - SendSysMessage(LANG_YOU_IN_COMBAT); - SetSentErrorMessage(true); - return false; - } - - MapEntry const * me = sMapStore.LookupEntry(tele->mapId); - if (!me || me->IsBattleGroundOrArena()) - { - SendSysMessage(LANG_CANNOT_TELE_TO_BG); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation); - return true; -} - -bool ChatHandler::HandleLookupAreaCommand(const char* args) -{ - if (!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - if (!Utf8toWStr (namepart,wnamepart)) - return false; - - bool found = false; - - // converting string that we try to find to lower case - wstrToLower (wnamepart); - - // Search in AreaTable.dbc - for (uint32 areaflag = 0; areaflag < sAreaStore.GetNumRows (); ++areaflag) - { - AreaTableEntry const *areaEntry = sAreaStore.LookupEntry (areaflag); - if (areaEntry) - { - int loc = GetSessionDbcLocale (); - std::string name = areaEntry->area_name[loc]; - if (name.empty()) - continue; - - if (!Utf8FitTo (name, wnamepart)) - { - loc = 0; - for (; loc < MAX_LOCALE; ++loc) - { - if (loc == GetSessionDbcLocale ()) - continue; - - name = areaEntry->area_name[loc]; - if (name.empty ()) - continue; - - if (Utf8FitTo (name, wnamepart)) - break; - } - } - - if (loc < MAX_LOCALE) - { - // send area in "id - [name]" format - std::ostringstream ss; - if (m_session) - ss << areaEntry->ID << " - |cffffffff|Harea:" << areaEntry->ID << "|h[" << name << " " << localeNames[loc]<< "]|h|r"; - else - ss << areaEntry->ID << " - " << name << " " << localeNames[loc]; - - SendSysMessage (ss.str ().c_str()); - - if (!found) - found = true; - } - } - } - - if (!found) - SendSysMessage (LANG_COMMAND_NOAREAFOUND); - - return true; -} - -//Find tele in game_tele order by name -bool ChatHandler::HandleLookupTeleCommand(const char * args) -{ - if (!*args) - { - SendSysMessage(LANG_COMMAND_TELE_PARAMETER); - SetSentErrorMessage(true); - return false; - } - - char const* str = strtok((char*)args, " "); - if (!str) - return false; - - std::string namepart = str; - std::wstring wnamepart; - - if (!Utf8toWStr(namepart,wnamepart)) - return false; - - // converting string that we try to find to lower case - wstrToLower(wnamepart); - - std::ostringstream reply; - - GameTeleMap const & teleMap = objmgr.GetGameTeleMap(); - for (GameTeleMap::const_iterator itr = teleMap.begin(); itr != teleMap.end(); ++itr) - { - GameTele const* tele = &itr->second; - - if (tele->wnameLow.find(wnamepart) == std::wstring::npos) - continue; - - if (m_session) - reply << " |cffffffff|Htele:" << itr->first << "|h[" << tele->name << "]|h|r\n"; - else - reply << " " << itr->first << " " << tele->name << "\n"; - } - - if (reply.str().empty()) - SendSysMessage(LANG_COMMAND_TELE_NOLOCATION); - else - PSendSysMessage(LANG_COMMAND_TELE_LOCATION,reply.str().c_str()); - - return true; -} - -//Enable\Dissable accept whispers (for GM) -bool ChatHandler::HandleWhispersCommand(const char* args) -{ - if (!*args) - { - PSendSysMessage(LANG_COMMAND_WHISPERACCEPTING, m_session->GetPlayer()->isAcceptWhispers() ? GetTrinityString(LANG_ON) : GetTrinityString(LANG_OFF)); - return true; - } - - std::string argstr = (char*)args; - // whisper on - if (argstr == "on") - { - m_session->GetPlayer()->SetAcceptWhispers(true); - SendSysMessage(LANG_COMMAND_WHISPERON); - return true; - } - - // whisper off - if (argstr == "off") - { - m_session->GetPlayer()->SetAcceptWhispers(false); - SendSysMessage(LANG_COMMAND_WHISPEROFF); - return true; - } - - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; -} - -//Save all players in the world -bool ChatHandler::HandleSaveAllCommand(const char* /*args*/) -{ - ObjectAccessor::Instance().SaveAllPlayers(); - SendSysMessage(LANG_PLAYERS_SAVED); - return true; -} - -//Send mail by command -bool ChatHandler::HandleSendMailCommand(const char* args) -{ - // format: name "subject text" "mail text" - Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) - return false; - - char* tail1 = strtok(NULL, ""); - if (!tail1) - return false; - - char* msgSubject = extractQuotedArg(tail1); - if (!msgSubject) - return false; - - char* tail2 = strtok(NULL, ""); - if (!tail2) - return false; - - char* msgText = extractQuotedArg(tail2); - if (!msgText) - return false; - - // msgSubject, msgText isn't NUL after prev. check - std::string subject = msgSubject; - std::string text = msgText; - - // from console show not existed sender - MailSender sender(MAIL_NORMAL,m_session ? m_session->GetPlayer()->GetGUIDLow() : 0, MAIL_STATIONERY_GM); - - MailDraft(subject, text) - .SendMailTo(MailReceiver(target,GUID_LOPART(target_guid)),sender); - - std::string nameLink = playerLink(target_name); - PSendSysMessage(LANG_MAIL_SENT, nameLink.c_str()); - return true; -} - -// teleport player to given game_tele.entry -bool ChatHandler::HandleTeleNameCommand(const char * args) -{ - char* nameStr; - char* teleStr; - extractOptFirstArg((char*)args,&nameStr,&teleStr); - if (!teleStr) - return false; - - Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget(nameStr,&target,&target_guid,&target_name)) - return false; - - // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r - GameTele const* tele = extractGameTeleFromLink(teleStr); - if (!tele) - { - SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); - SetSentErrorMessage(true); - return false; - } - -/* MapEntry const * me = sMapStore.LookupEntry(tele->mapId); - if (!me || me->IsBattleGroundOrArena()) - { - SendSysMessage(LANG_CANNOT_TELE_TO_BG); - SetSentErrorMessage(true); - return false; - } - - Player *chr = objmgr.GetPlayer(name.c_str());*/ - - if (target) - { - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - std::string chrNameLink = playerLink(target_name); - - if (target->IsBeingTeleported() == true) - { - PSendSysMessage(LANG_IS_TELEPORTED, chrNameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_TELEPORTING_TO, chrNameLink.c_str(),"", tele->name.c_str()); - if (needReportToTarget(target)) - ChatHandler(target).PSendSysMessage(LANG_TELEPORTED_TO_BY, GetNameLink().c_str()); - - // stop flight if need - if (target->isInFlight()) - { - target->GetMotionMaster()->MovementExpired(); - target->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - target->SaveRecallPosition(); - - target->TeleportTo(tele->mapId,tele->position_x,tele->position_y,tele->position_z,tele->orientation); - } - else - { - // check offline security - if (HasLowerSecurity(NULL, target_guid)) - return false; - - std::string nameLink = playerLink(target_name); - - PSendSysMessage(LANG_TELEPORTING_TO, nameLink.c_str(), GetTrinityString(LANG_OFFLINE), tele->name.c_str()); - Player::SavePositionInDB(tele->mapId,tele->position_x,tele->position_y,tele->position_z,tele->orientation, - MapManager::Instance().GetZoneId(tele->mapId,tele->position_x,tele->position_y,tele->position_z),target_guid); - } - - return true; -} - -//Teleport group to given game_tele.entry -bool ChatHandler::HandleTeleGroupCommand(const char * args) -{ - if (!*args) - return false; - - Player *player = getSelectedPlayer(); - if (!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(player, 0)) - return false; - - // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r - GameTele const* tele = extractGameTeleFromLink((char*)args); - if (!tele) - { - SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); - SetSentErrorMessage(true); - return false; - } - - MapEntry const * me = sMapStore.LookupEntry(tele->mapId); - if (!me || me->IsBattleGroundOrArena()) - { - SendSysMessage(LANG_CANNOT_TELE_TO_BG); - SetSentErrorMessage(true); - return false; - } - - std::string nameLink = GetNameLink(player); - - Group *grp = player->GetGroup(); - if (!grp) - { - PSendSysMessage(LANG_NOT_IN_GROUP,nameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - - for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player *pl = itr->getSource(); - - if (!pl || !pl->GetSession()) - continue; - - // check online security - if (HasLowerSecurity(pl, 0)) - return false; - - std::string plNameLink = GetNameLink(pl); - - if (pl->IsBeingTeleported()) - { - PSendSysMessage(LANG_IS_TELEPORTED, plNameLink.c_str()); - continue; - } - - PSendSysMessage(LANG_TELEPORTING_TO, plNameLink.c_str(),"", tele->name.c_str()); - if (needReportToTarget(pl)) - ChatHandler(pl).PSendSysMessage(LANG_TELEPORTED_TO_BY, nameLink.c_str()); - - // stop flight if need - if (pl->isInFlight()) - { - pl->GetMotionMaster()->MovementExpired(); - pl->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - pl->SaveRecallPosition(); - - pl->TeleportTo(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation); - } - - return true; -} - -//Summon group of player -bool ChatHandler::HandleGroupgoCommand(const char* args) -{ - Player* target; - if (!extractPlayerTarget((char*)args,&target)) - return false; - - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - Group *grp = target->GetGroup(); - - std::string nameLink = GetNameLink(target); - - if (!grp) - { - PSendSysMessage(LANG_NOT_IN_GROUP,nameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - - Map* gmMap = m_session->GetPlayer()->GetMap(); - bool to_instance = gmMap->Instanceable(); - - // we are in instance, and can summon only player in our group with us as lead - if (to_instance && ( - !m_session->GetPlayer()->GetGroup() || (grp->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()) || - (m_session->GetPlayer()->GetGroup()->GetLeaderGUID() != m_session->GetPlayer()->GetGUID()))) - // the last check is a bit excessive, but let it be, just in case - { - SendSysMessage(LANG_CANNOT_SUMMON_TO_INST); - SetSentErrorMessage(true); - return false; - } - - for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player *pl = itr->getSource(); - - if (!pl || pl == m_session->GetPlayer() || !pl->GetSession()) - continue; - - // check online security - if (HasLowerSecurity(pl, 0)) - return false; - - std::string plNameLink = GetNameLink(pl); - - if (pl->IsBeingTeleported() == true) - { - PSendSysMessage(LANG_IS_TELEPORTED, plNameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - - if (to_instance) - { - Map* plMap = pl->GetMap(); - - if (plMap->Instanceable() && plMap->GetInstanceId() != gmMap->GetInstanceId()) - { - // cannot summon from instance to instance - PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,plNameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - } - - PSendSysMessage(LANG_SUMMONING, plNameLink.c_str(),""); - if (needReportToTarget(pl)) - ChatHandler(pl).PSendSysMessage(LANG_SUMMONED_BY, GetNameLink().c_str()); - - // stop flight if need - if (pl->isInFlight()) - { - pl->GetMotionMaster()->MovementExpired(); - pl->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - pl->SaveRecallPosition(); - - // before GM - float x,y,z; - m_session->GetPlayer()->GetClosePoint(x,y,z,pl->GetObjectSize()); - pl->TeleportTo(m_session->GetPlayer()->GetMapId(),x,y,z,pl->GetOrientation()); - } - - return true; -} - -bool ChatHandler::HandleGoTaxinodeCommand(const char* args) -{ - Player* _player = m_session->GetPlayer(); - - if (!*args) - return false; - - char* cNodeId = extractKeyFromLink((char*)args,"Htaxinode"); - if (!cNodeId) - return false; - - int32 i_nodeId = atoi(cNodeId); - if (!i_nodeId) - return false; - - TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i_nodeId); - if (!node) - { - PSendSysMessage(LANG_COMMAND_GOTAXINODENOTFOUND,i_nodeId); - SetSentErrorMessage(true); - return false; - } - - if ((node->x == 0.0f && node->y == 0.0f && node->z == 0.0f) || - !MapManager::IsValidMapCoord(node->map_id,node->x,node->y,node->z)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,node->x,node->y,node->map_id); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(node->map_id, node->x, node->y, node->z, _player->GetOrientation()); - return true; -} - -//teleport at coordinates -bool ChatHandler::HandleGoXYCommand(const char* args) -{ - if (!*args) - return false; - - Player* _player = m_session->GetPlayer(); - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - char* pmapid = strtok(NULL, " "); - - if (!px || !py) - return false; - - float x = (float)atof(px); - float y = (float)atof(py); - uint32 mapid; - if (pmapid) - mapid = (uint32)atoi(pmapid); - else mapid = _player->GetMapId(); - - if (!MapManager::IsValidMapCoord(mapid,x,y)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - Map const *map = MapManager::Instance().CreateBaseMap(mapid); - float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); - - _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); - - return true; -} - -//teleport at coordinates, including Z -bool ChatHandler::HandleGoXYZCommand(const char* args) -{ - if (!*args) - return false; - - Player* _player = m_session->GetPlayer(); - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - char* pz = strtok(NULL, " "); - char* pmapid = strtok(NULL, " "); - - if (!px || !py || !pz) - return false; - - float x = (float)atof(px); - float y = (float)atof(py); - float z = (float)atof(pz); - uint32 mapid; - if (pmapid) - mapid = (uint32)atoi(pmapid); - else - mapid = _player->GetMapId(); - - if (!MapManager::IsValidMapCoord(mapid,x,y,z)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); - - return true; -} - -//teleport at coordinates -bool ChatHandler::HandleGoZoneXYCommand(const char* args) -{ - if (!*args) - return false; - - Player* _player = m_session->GetPlayer(); - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - char* tail = strtok(NULL,""); - - char* cAreaId = extractKeyFromLink(tail,"Harea"); // string or [name] Shift-click form |color|Harea:area_id|h[name]|h|r - - if (!px || !py) - return false; - - float x = (float)atof(px); - float y = (float)atof(py); - - // prevent accept wrong numeric args - if ((x == 0.0f && *px != '0') || (y == 0.0f && *py != '0')) - return false; - - uint32 areaid = cAreaId ? (uint32)atoi(cAreaId) : _player->GetZoneId(); - - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaid); - - if (x<0 || x>100 || y<0 || y>100 || !areaEntry) - { - PSendSysMessage(LANG_INVALID_ZONE_COORD,x,y,areaid); - SetSentErrorMessage(true); - return false; - } - - // update to parent zone if exist (client map show only zones without parents) - AreaTableEntry const* zoneEntry = areaEntry->zone ? GetAreaEntryByAreaID(areaEntry->zone) : areaEntry; - - Map const *map = MapManager::Instance().CreateBaseMap(zoneEntry->mapid); - - if (map->Instanceable()) - { - PSendSysMessage(LANG_INVALID_ZONE_MAP,areaEntry->ID,areaEntry->area_name[GetSessionDbcLocale()],map->GetId(),map->GetMapName()); - SetSentErrorMessage(true); - return false; - } - - Zone2MapCoordinates(x,y,zoneEntry->ID); - - if (!MapManager::IsValidMapCoord(zoneEntry->mapid,x,y)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,zoneEntry->mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); - _player->TeleportTo(zoneEntry->mapid, x, y, z, _player->GetOrientation()); - - return true; -} - -//teleport to grid -bool ChatHandler::HandleGoGridCommand(const char* args) -{ - if (!*args) return false; - Player* _player = m_session->GetPlayer(); - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - char* pmapid = strtok(NULL, " "); - - if (!px || !py) - return false; - - float grid_x = (float)atof(px); - float grid_y = (float)atof(py); - uint32 mapid; - if (pmapid) - mapid = (uint32)atoi(pmapid); - else mapid = _player->GetMapId(); - - // center of grid - float x = (grid_x-CENTER_GRID_ID+0.5f)*SIZE_OF_GRIDS; - float y = (grid_y-CENTER_GRID_ID+0.5f)*SIZE_OF_GRIDS; - - if (!MapManager::IsValidMapCoord(mapid,x,y)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - Map const *map = MapManager::Instance().CreateBaseMap(mapid); - float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); - _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); - - return true; -} - -bool ChatHandler::HandleModifyDrunkCommand(const char* args) -{ - if (!*args) return false; - - uint32 drunklevel = (uint32)atoi(args); - if (drunklevel > 100) - drunklevel = 100; - - uint16 drunkMod = drunklevel * 0xFFFF / 100; - - m_session->GetPlayer()->SetDrunkValue(drunkMod); - - return true; -} - diff --git a/src/server/game/Chat/Level2.cpp b/src/server/game/Chat/Level2.cpp deleted file mode 100644 index 4f299c932e8..00000000000 --- a/src/server/game/Chat/Level2.cpp +++ /dev/null @@ -1,4526 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "DBCStores.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "Item.h" -#include "GameObject.h" -#include "Opcodes.h" -#include "Chat.h" -#include "MapManager.h" -#include "Language.h" -#include "World.h" -#include "GameEventMgr.h" -#include "SpellMgr.h" -#include "PoolHandler.h" -#include "AccountMgr.h" -#include "WaypointManager.h" -#include "Util.h" -#include -#include -#include -#include -#include "GlobalEvents.h" -#include "OutdoorPvPMgr.h" - -#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand -#include "CreatureGroups.h" - -//mute player for some times -bool ChatHandler::HandleMuteCommand(const char* args) -{ - char* nameStr; - char* delayStr; - extractOptFirstArg((char*)args,&nameStr,&delayStr); - if (!delayStr) - return false; - - char *mutereason = strtok(NULL, "\r"); - std::string mutereasonstr = "No reason"; - if (mutereason != NULL) - mutereasonstr = mutereason; - - Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget(nameStr,&target,&target_guid,&target_name)) - return false; - - uint32 account_id = target ? target->GetSession()->GetAccountId() : objmgr.GetPlayerAccountIdByGUID(target_guid); - - // find only player from same account if any - if (!target) - if (WorldSession* session = sWorld.FindSession(account_id)) - target = session->GetPlayer(); - - uint32 notspeaktime = (uint32) atoi(delayStr); - - // must have strong lesser security level - if (HasLowerSecurity (target,target_guid,true)) - return false; - - time_t mutetime = time(NULL) + notspeaktime*60; - - if (target) - target->GetSession()->m_muteTime = mutetime; - - LoginDatabase.PExecute("UPDATE account SET mutetime = " UI64FMTD " WHERE id = '%u'",uint64(mutetime), account_id); - - if (target) - ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime, mutereasonstr.c_str()); - - std::string nameLink = playerLink(target_name); - - PSendSysMessage(LANG_YOU_DISABLE_CHAT, nameLink.c_str(), notspeaktime, mutereasonstr.c_str()); - - return true; -} - -//unmute player -bool ChatHandler::HandleUnmuteCommand(const char* args) -{ - Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) - return false; - - uint32 account_id = target ? target->GetSession()->GetAccountId() : objmgr.GetPlayerAccountIdByGUID(target_guid); - - // find only player from same account if any - if (!target) - if (WorldSession* session = sWorld.FindSession(account_id)) - target = session->GetPlayer(); - - // must have strong lesser security level - if (HasLowerSecurity (target,target_guid,true)) - return false; - - if (target) - { - if (target->CanSpeak()) - { - SendSysMessage(LANG_CHAT_ALREADY_ENABLED); - SetSentErrorMessage(true); - return false; - } - - target->GetSession()->m_muteTime = 0; - } - - LoginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id); - - if (target) - ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_ENABLED); - - std::string nameLink = playerLink(target_name); - - PSendSysMessage(LANG_YOU_ENABLE_CHAT, nameLink.c_str()); - return true; -} - -bool ChatHandler::HandleGoTicketCommand(const char * args) -{ - if (!*args) - return false; - - char *cstrticket_id = strtok((char*)args, " "); - - if (!cstrticket_id) - return false; - - uint64 ticket_id = atoi(cstrticket_id); - if (!ticket_id) - return false; - - GM_Ticket *ticket = objmgr.GetGMTicket(ticket_id); - if (!ticket) - { - SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - - float x, y, z; - int mapid; - - x = ticket->pos_x; - y = ticket->pos_y; - z = ticket->pos_z; - mapid = ticket->map; - - Player* _player = m_session->GetPlayer(); - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - else - _player->SaveRecallPosition(); - - _player->TeleportTo(mapid, x, y, z, 1, 0); - return true; -} - -bool ChatHandler::HandleGoTriggerCommand(const char* args) -{ - Player* _player = m_session->GetPlayer(); - - if (!*args) - return false; - - char *atId = strtok((char*)args, " "); - if (!atId) - return false; - - int32 i_atId = atoi(atId); - - if (!i_atId) - return false; - - AreaTriggerEntry const* at = sAreaTriggerStore.LookupEntry(i_atId); - if (!at) - { - PSendSysMessage(LANG_COMMAND_GOAREATRNOTFOUND,i_atId); - SetSentErrorMessage(true); - return false; - } - - if (!MapManager::IsValidMapCoord(at->mapid,at->x,at->y,at->z)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,at->x,at->y,at->mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(at->mapid, at->x, at->y, at->z, _player->GetOrientation()); - return true; -} - -bool ChatHandler::HandleGoGraveyardCommand(const char* args) -{ - Player* _player = m_session->GetPlayer(); - - if (!*args) - return false; - - char *gyId = strtok((char*)args, " "); - if (!gyId) - return false; - - int32 i_gyId = atoi(gyId); - - if (!i_gyId) - return false; - - WorldSafeLocsEntry const* gy = sWorldSafeLocsStore.LookupEntry(i_gyId); - if (!gy) - { - PSendSysMessage(LANG_COMMAND_GRAVEYARDNOEXIST,i_gyId); - SetSentErrorMessage(true); - return false; - } - - if (!MapManager::IsValidMapCoord(gy->map_id,gy->x,gy->y,gy->z)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,gy->x,gy->y,gy->map_id); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(gy->map_id, gy->x, gy->y, gy->z, _player->GetOrientation()); - return true; -} - -/** \brief Teleport the GM to the specified creature -* -* .gocreature --> TP using creature.guid -* .gocreature azuregos --> TP player to the mob with this name -* Warning: If there is more than one mob with this name -* you will be teleported to the first one that is found. -* .gocreature id 6109 --> TP player to the mob, that has this creature_template.entry -* Warning: If there is more than one mob with this "id" -* you will be teleported to the first one that is found. -*/ -//teleport to creature -bool ChatHandler::HandleGoCreatureCommand(const char* args) -{ - if (!*args) - return false; - Player* _player = m_session->GetPlayer(); - - // "id" or number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r - char* pParam1 = extractKeyFromLink((char*)args,"Hcreature"); - if (!pParam1) - return false; - - std::ostringstream whereClause; - - // User wants to teleport to the NPC's template entry - if (strcmp(pParam1, "id") == 0) - { - //sLog.outError("DEBUG: ID found"); - - // Get the "creature_template.entry" - // number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r - char* tail = strtok(NULL,""); - if (!tail) - return false; - char* cId = extractKeyFromLink(tail,"Hcreature_entry"); - if (!cId) - return false; - - int32 tEntry = atoi(cId); - //sLog.outError("DEBUG: ID value: %d", tEntry); - if (!tEntry) - return false; - - whereClause << "WHERE id = '" << tEntry << "'"; - } - else - { - //sLog.outError("DEBUG: ID *not found*"); - - int32 guid = atoi(pParam1); - - // Number is invalid - maybe the user specified the mob's name - if (!guid) - { - std::string name = pParam1; - WorldDatabase.escape_string(name); - whereClause << ", creature_template WHERE creature.id = creature_template.entry AND creature_template.name "_LIKE_" '" << name << "'"; - } - else - { - whereClause << "WHERE guid = '" << guid << "'"; - } - } - //sLog.outError("DEBUG: %s", whereClause.c_str()); - - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM creature %s", whereClause.str().c_str()); - if (!result) - { - SendSysMessage(LANG_COMMAND_GOCREATNOTFOUND); - SetSentErrorMessage(true); - return false; - } - if (result->GetRowCount() > 1) - SendSysMessage(LANG_COMMAND_GOCREATMULTIPLE); - - Field *fields = result->Fetch(); - float x = fields[0].GetFloat(); - float y = fields[1].GetFloat(); - float z = fields[2].GetFloat(); - float ort = fields[3].GetFloat(); - int mapid = fields[4].GetUInt16(); - - if (!MapManager::IsValidMapCoord(mapid,x,y,z,ort)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(mapid, x, y, z, ort); - return true; -} - -//teleport to gameobject -bool ChatHandler::HandleGoObjectCommand(const char* args) -{ - if (!*args) - return false; - - Player* _player = m_session->GetPlayer(); - - // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject"); - if (!cId) - return false; - - int32 guid = atoi(cId); - if (!guid) - return false; - - float x, y, z, ort; - int mapid; - - // by DB guid - if (GameObjectData const* go_data = objmgr.GetGOData(guid)) - { - x = go_data->posX; - y = go_data->posY; - z = go_data->posZ; - ort = go_data->orientation; - mapid = go_data->mapid; - } - else - { - SendSysMessage(LANG_COMMAND_GOOBJNOTFOUND); - SetSentErrorMessage(true); - return false; - } - - if (!MapManager::IsValidMapCoord(mapid,x,y,z,ort)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(mapid, x, y, z, ort); - return true; -} - -bool ChatHandler::HandleGameObjectTargetCommand(const char* args) -{ - Player* pl = m_session->GetPlayer(); - QueryResult_AutoPtr result; - GameEventMgr::ActiveEvents const& activeEventsList = gameeventmgr.GetActiveEventList(); - if (*args) - { - // number or [name] Shift-click form |color|Hgameobject_entry:go_id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject_entry"); - if (!cId) - return false; - - uint32 id = atol(cId); - - if (id) - result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, orientation, map, phaseMask, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM gameobject WHERE map = '%i' AND id = '%u' ORDER BY order_ ASC LIMIT 1", - pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),id); - else - { - std::string name = cId; - WorldDatabase.escape_string(name); - result = WorldDatabase.PQuery( - "SELECT guid, id, position_x, position_y, position_z, orientation, map, phaseMask, (POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ " - "FROM gameobject,gameobject_template WHERE gameobject_template.entry = gameobject.id AND map = %i AND name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")" ORDER BY order_ ASC LIMIT 1", - pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),name.c_str()); - } - } - else - { - std::ostringstream eventFilter; - eventFilter << " AND (event IS NULL "; - bool initString = true; - - for (GameEventMgr::ActiveEvents::const_iterator itr = activeEventsList.begin(); itr != activeEventsList.end(); ++itr) - { - if (initString) - { - eventFilter << "OR event IN (" <<*itr; - initString =false; - } - else - eventFilter << "," << *itr; - } - - if (!initString) - eventFilter << "))"; - else - eventFilter << ")"; - - result = WorldDatabase.PQuery("SELECT gameobject.guid, id, position_x, position_y, position_z, orientation, map, phaseMask, " - "(POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ FROM gameobject " - "LEFT OUTER JOIN game_event_gameobject on gameobject.guid=game_event_gameobject.guid WHERE map = '%i' %s ORDER BY order_ ASC LIMIT 10", - m_session->GetPlayer()->GetPositionX(), m_session->GetPlayer()->GetPositionY(), m_session->GetPlayer()->GetPositionZ(), m_session->GetPlayer()->GetMapId(),eventFilter.str().c_str()); - } - - if (!result) - { - SendSysMessage(LANG_COMMAND_TARGETOBJNOTFOUND); - return true; - } - - bool found = false; - float x, y, z, o; - uint32 lowguid, id; - uint16 mapid, pool_id, phase; - - do - { - Field *fields = result->Fetch(); - lowguid = fields[0].GetUInt32(); - id = fields[1].GetUInt32(); - x = fields[2].GetFloat(); - y = fields[3].GetFloat(); - z = fields[4].GetFloat(); - o = fields[5].GetFloat(); - mapid = fields[6].GetUInt16(); - phase = fields[7].GetUInt16(); - pool_id = poolhandler.IsPartOfAPool(lowguid); - if (!pool_id || poolhandler.IsSpawnedObject(lowguid)) - found = true; - } while (result->NextRow() && (!found)); - - if (!found) - { - PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id); - return false; - } - - GameObjectInfo const* goI = objmgr.GetGameObjectInfo(id); - - if (!goI) - { - PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id); - return false; - } - - GameObject* target = m_session->GetPlayer()->GetMap()->GetGameObject(MAKE_NEW_GUID(lowguid,id,HIGHGUID_GAMEOBJECT)); - - PSendSysMessage(LANG_GAMEOBJECT_DETAIL, lowguid, goI->name, lowguid, id, x, y, z, mapid, o, phase); - - if (target) - { - int32 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL); - if (curRespawnDelay < 0) - curRespawnDelay = 0; - - std::string curRespawnDelayStr = secsToTimeString(curRespawnDelay,true); - std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(),true); - - PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(),curRespawnDelayStr.c_str()); - } - return true; -} - -//delete object by selection or guid -bool ChatHandler::HandleGameObjectDeleteCommand(const char* args) -{ - // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject"); - if (!cId) - return false; - - uint32 lowguid = atoi(cId); - if (!lowguid) - return false; - - GameObject* obj = NULL; - - // by DB guid - if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) - obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); - - if (!obj) - { - PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - uint64 owner_guid = obj->GetOwnerGUID(); - if (owner_guid) - { - Unit* owner = ObjectAccessor::GetUnit(*m_session->GetPlayer(),owner_guid); - if (!owner || !IS_PLAYER_GUID(owner_guid)) - { - PSendSysMessage(LANG_COMMAND_DELOBJREFERCREATURE, GUID_LOPART(owner_guid), obj->GetGUIDLow()); - SetSentErrorMessage(true); - return false; - } - - owner->RemoveGameObject(obj,false); - } - - obj->SetRespawnTime(0); // not save respawn time - obj->Delete(); - obj->DeleteFromDB(); - - PSendSysMessage(LANG_COMMAND_DELOBJMESSAGE, obj->GetGUIDLow()); - - return true; -} - -//turn selected object -bool ChatHandler::HandleGameObjectTurnCommand(const char* args) -{ - // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject"); - if (!cId) - return false; - - uint32 lowguid = atoi(cId); - if (!lowguid) - return false; - - GameObject* obj = NULL; - - // by DB guid - if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) - obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); - - if (!obj) - { - PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - char* po = strtok(NULL, " "); - float o; - - if (po) - { - o = (float)atof(po); - } - else - { - Player *chr = m_session->GetPlayer(); - o = chr->GetOrientation(); - } - - obj->Relocate(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), o); - obj->UpdateRotationFields(); - obj->DestroyForNearbyPlayers(); - obj->UpdateObjectVisibility(); - - obj->SaveToDB(); - obj->Refresh(); - - PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, obj->GetGUIDLow(), obj->GetGOInfo()->name, obj->GetGUIDLow(), o); - - return true; -} - -//move selected object -bool ChatHandler::HandleGameObjectMoveCommand(const char* args) -{ - // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject"); - if (!cId) - return false; - - uint32 lowguid = atoi(cId); - if (!lowguid) - return false; - - GameObject* obj = NULL; - - // by DB guid - if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) - obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); - - if (!obj) - { - PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - char* px = strtok(NULL, " "); - char* py = strtok(NULL, " "); - char* pz = strtok(NULL, " "); - - if (!px) - { - Player *chr = m_session->GetPlayer(); - obj->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), obj->GetOrientation()); - obj->DestroyForNearbyPlayers(); - obj->UpdateObjectVisibility(); - } - else - { - if (!py || !pz) - return false; - - float x = (float)atof(px); - float y = (float)atof(py); - float z = (float)atof(pz); - - if (!MapManager::IsValidMapCoord(obj->GetMapId(),x,y,z)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,obj->GetMapId()); - SetSentErrorMessage(true); - return false; - } - - obj->Relocate(x, y, z, obj->GetOrientation()); - obj->DestroyForNearbyPlayers(); - obj->UpdateObjectVisibility(); - } - - obj->SaveToDB(); - obj->Refresh(); - - PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, obj->GetGUIDLow(), obj->GetGOInfo()->name, obj->GetGUIDLow()); - - return true; -} - -//spawn go -bool ChatHandler::HandleGameObjectAddCommand(const char* args) -{ - if (!*args) - return false; - - // number or [name] Shift-click form |color|Hgameobject_entry:go_id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject_entry"); - if (!cId) - return false; - - uint32 id = atol(cId); - if (!id) - return false; - - char* spawntimeSecs = strtok(NULL, " "); - - const GameObjectInfo *gInfo = objmgr.GetGameObjectInfo(id); - - if (!gInfo) - { - PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id); - SetSentErrorMessage(true); - return false; - } - - if (gInfo->displayId && !sGameObjectDisplayInfoStore.LookupEntry(gInfo->displayId)) - { - // report to DB errors log as in loading case - sLog.outErrorDb("Gameobject (Entry %u GoType: %u) have invalid displayId (%u), not spawned.",id, gInfo->type, gInfo->displayId); - PSendSysMessage(LANG_GAMEOBJECT_HAVE_INVALID_DATA,id); - SetSentErrorMessage(true); - return false; - } - - Player *chr = m_session->GetPlayer(); - float x = float(chr->GetPositionX()); - float y = float(chr->GetPositionY()); - float z = float(chr->GetPositionZ()); - float o = float(chr->GetOrientation()); - Map *map = chr->GetMap(); - - GameObject* pGameObj = new GameObject; - uint32 db_lowGUID = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT); - - if (!pGameObj->Create(db_lowGUID, gInfo->id, map, chr->GetPhaseMaskForSpawn(), x, y, z, o, 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) - { - delete pGameObj; - return false; - } - - if (spawntimeSecs) - { - uint32 value = atoi((char*)spawntimeSecs); - pGameObj->SetRespawnTime(value); - //sLog.outDebug("*** spawntimeSecs: %d", value); - } - - // fill the gameobject data and save to the db - pGameObj->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()),chr->GetPhaseMaskForSpawn()); - - // this will generate a new guid if the object is in an instance - if (!pGameObj->LoadFromDB(db_lowGUID, map)) - { - delete pGameObj; - return false; - } - - sLog.outDebug(GetTrinityString(LANG_GAMEOBJECT_CURRENT), gInfo->name, db_lowGUID, x, y, z, o); - - map->Add(pGameObj); - - // TODO: is it really necessary to add both the real and DB table guid here ? - objmgr.AddGameobjectToGrid(db_lowGUID, objmgr.GetGOData(db_lowGUID)); - - PSendSysMessage(LANG_GAMEOBJECT_ADD,id,gInfo->name,db_lowGUID,x,y,z); - return true; -} - -//set pahsemask for selected object -bool ChatHandler::HandleGameObjectPhaseCommand(const char* args) -{ - // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject"); - if (!cId) - return false; - - uint32 lowguid = atoi(cId); - if (!lowguid) - return false; - - GameObject* obj = NULL; - - // by DB guid - if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) - obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); - - if (!obj) - { - PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - char* phaseStr = strtok (NULL, " "); - uint32 phasemask = phaseStr? atoi(phaseStr) : 0; - if (phasemask == 0) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - obj->SetPhaseMask(phasemask,true); - obj->SaveToDB(); - return true; -} - -bool ChatHandler::HandleGameObjectNearCommand(const char* args) -{ - float distance = (!*args) ? 10 : atol(args); - uint32 count = 0; - - Player* pl = m_session->GetPlayer(); - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, map, " - "(POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ " - "FROM gameobject WHERE map='%u' AND (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) <= '%f' ORDER BY order_", - pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), - pl->GetMapId(),pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(),distance*distance); - - if (result) - { - do - { - Field *fields = result->Fetch(); - uint32 guid = fields[0].GetUInt32(); - uint32 entry = fields[1].GetUInt32(); - float x = fields[2].GetFloat(); - float y = fields[3].GetFloat(); - float z = fields[4].GetFloat(); - int mapid = fields[5].GetUInt16(); - - GameObjectInfo const * gInfo = objmgr.GetGameObjectInfo(entry); - - if (!gInfo) - continue; - - PSendSysMessage(LANG_GO_LIST_CHAT, guid, guid, gInfo->name, x, y, z, mapid); - - ++count; - } while (result->NextRow()); - } - - PSendSysMessage(LANG_COMMAND_NEAROBJMESSAGE,distance,count); - return true; -} - -bool ChatHandler::HandleGUIDCommand(const char* /*args*/) -{ - uint64 guid = m_session->GetPlayer()->GetSelection(); - - if (guid == 0) - { - SendSysMessage(LANG_NO_SELECTION); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_OBJECT_GUID, GUID_LOPART(guid), GUID_HIPART(guid)); - return true; -} - -bool ChatHandler::HandleModifyRepCommand(const char * args) -{ - if (!*args) return false; - - Player* target = NULL; - target = getSelectedPlayer(); - - if (!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - char* factionTxt = extractKeyFromLink((char*)args,"Hfaction"); - if (!factionTxt) - return false; - - uint32 factionId = atoi(factionTxt); - - int32 amount = 0; - char *rankTxt = strtok(NULL, " "); - if (!factionTxt || !rankTxt) - return false; - - amount = atoi(rankTxt); - if ((amount == 0) && (rankTxt[0] != '-') && !isdigit(rankTxt[0])) - { - std::string rankStr = rankTxt; - std::wstring wrankStr; - if (!Utf8toWStr(rankStr,wrankStr)) - return false; - wstrToLower(wrankStr); - - int r = 0; - amount = -42000; - for (; r < MAX_REPUTATION_RANK; ++r) - { - std::string rank = GetTrinityString(ReputationRankStrIndex[r]); - if (rank.empty()) - continue; - - std::wstring wrank; - if (!Utf8toWStr(rank,wrank)) - continue; - - wstrToLower(wrank); - - if (wrank.substr(0,wrankStr.size()) == wrankStr) - { - char *deltaTxt = strtok(NULL, " "); - if (deltaTxt) - { - int32 delta = atoi(deltaTxt); - if ((delta < 0) || (delta > ReputationMgr::PointsInRank[r] -1)) - { - PSendSysMessage(LANG_COMMAND_FACTION_DELTA, (ReputationMgr::PointsInRank[r]-1)); - SetSentErrorMessage(true); - return false; - } - amount += delta; - } - break; - } - amount += ReputationMgr::PointsInRank[r]; - } - if (r >= MAX_REPUTATION_RANK) - { - PSendSysMessage(LANG_COMMAND_FACTION_INVPARAM, rankTxt); - SetSentErrorMessage(true); - return false; - } - } - - FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionId); - - if (!factionEntry) - { - PSendSysMessage(LANG_COMMAND_FACTION_UNKNOWN, factionId); - SetSentErrorMessage(true); - return false; - } - - if (factionEntry->reputationListID < 0) - { - PSendSysMessage(LANG_COMMAND_FACTION_NOREP_ERROR, factionEntry->name[GetSessionDbcLocale()], factionId); - SetSentErrorMessage(true); - return false; - } - - target->GetReputationMgr().SetReputation(factionEntry,amount); - PSendSysMessage(LANG_COMMAND_MODIFY_REP, factionEntry->name[GetSessionDbcLocale()], factionId, - GetNameLink(target).c_str(), target->GetReputationMgr().GetReputation(factionEntry)); - return true; -} - -//-----------------------Npc Commands----------------------- -//add spawn of creature -bool ChatHandler::HandleNpcAddCommand(const char* args) -{ - if (!*args) - return false; - char* charID = extractKeyFromLink((char*)args,"Hcreature_entry"); - if (!charID) - return false; - - char* team = strtok(NULL, " "); - int32 teamval = 0; - if (team) { teamval = atoi(team); } - if (teamval < 0) { teamval = 0; } - - uint32 id = atoi(charID); - - Player *chr = m_session->GetPlayer(); - float x = chr->GetPositionX(); - float y = chr->GetPositionY(); - float z = chr->GetPositionZ(); - float o = chr->GetOrientation(); - Map *map = chr->GetMap(); - - Creature* pCreature = new Creature; - if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, (uint32)teamval, x, y, z, o)) - { - delete pCreature; - return false; - } - - pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); - - uint32 db_guid = pCreature->GetDBTableGUIDLow(); - - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - pCreature->LoadFromDB(db_guid, map); - - map->Add(pCreature); - objmgr.AddCreatureToGrid(db_guid, objmgr.GetCreatureData(db_guid)); - return true; -} - -//add item in vendorlist -bool ChatHandler::HandleNpcAddVendorItemCommand(const char* args) -{ - if (!*args) - return false; - - char* pitem = extractKeyFromLink((char*)args,"Hitem"); - if (!pitem) - { - SendSysMessage(LANG_COMMAND_NEEDITEMSEND); - SetSentErrorMessage(true); - return false; - } - - uint32 itemId = atol(pitem); - - char* fmaxcount = strtok(NULL, " "); //add maxcount, default: 0 - uint32 maxcount = 0; - if (fmaxcount) - maxcount = atol(fmaxcount); - - char* fincrtime = strtok(NULL, " "); //add incrtime, default: 0 - uint32 incrtime = 0; - if (fincrtime) - incrtime = atol(fincrtime); - - char* fextendedcost = strtok(NULL, " "); //add ExtendedCost, default: 0 - uint32 extendedcost = fextendedcost ? atol(fextendedcost) : 0; - - Creature* vendor = getSelectedCreature(); - - uint32 vendor_entry = vendor ? vendor->GetEntry() : 0; - - if (!objmgr.IsVendorItemValid(vendor_entry,itemId,maxcount,incrtime,extendedcost,m_session->GetPlayer())) - { - SetSentErrorMessage(true); - return false; - } - - objmgr.AddVendorItem(vendor_entry,itemId,maxcount,incrtime,extendedcost); - - ItemPrototype const* pProto = objmgr.GetItemPrototype(itemId); - - PSendSysMessage(LANG_ITEM_ADDED_TO_LIST,itemId,pProto->Name1,maxcount,incrtime,extendedcost); - return true; -} - -//del item from vendor list -bool ChatHandler::HandleNpcDelVendorItemCommand(const char* args) -{ - if (!*args) - return false; - - Creature* vendor = getSelectedCreature(); - if (!vendor || !vendor->isVendor()) - { - SendSysMessage(LANG_COMMAND_VENDORSELECTION); - SetSentErrorMessage(true); - return false; - } - - char* pitem = extractKeyFromLink((char*)args,"Hitem"); - if (!pitem) - { - SendSysMessage(LANG_COMMAND_NEEDITEMSEND); - SetSentErrorMessage(true); - return false; - } - uint32 itemId = atol(pitem); - - if (!objmgr.RemoveVendorItem(vendor->GetEntry(),itemId)) - { - PSendSysMessage(LANG_ITEM_NOT_IN_LIST,itemId); - SetSentErrorMessage(true); - return false; - } - - ItemPrototype const* pProto = objmgr.GetItemPrototype(itemId); - - PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST,itemId,pProto->Name1); - return true; -} - -//add move for creature -bool ChatHandler::HandleNpcAddMoveCommand(const char* args) -{ - if (!*args) - return false; - - char* guid_str = strtok((char*)args, " "); - char* wait_str = strtok((char*)NULL, " "); - - uint32 lowguid = atoi((char*)guid_str); - - Creature* pCreature = NULL; - - /* FIXME: impossible without entry - if (lowguid) - pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); - */ - - // attempt check creature existence by DB data - if (!pCreature) - { - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if (!data) - { - PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - } - else - { - // obtain real GUID for DB operations - lowguid = pCreature->GetDBTableGUIDLow(); - } - - int wait = wait_str ? atoi(wait_str) : 0; - - if (wait < 0) - wait = 0; - - //Player* player = m_session->GetPlayer(); - - //WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), wait, 0); - - // update movement type - WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid); - if (pCreature && pCreature->GetWaypointPath()) - { - pCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); - pCreature->GetMotionMaster()->Initialize(); - if (pCreature->isAlive()) // dead creature will reset movement generator at respawn - { - pCreature->setDeathState(JUST_DIED); - pCreature->Respawn(true); - } - pCreature->SaveToDB(); - } - - SendSysMessage(LANG_WAYPOINT_ADDED); - - return true; -} - -//change level of creature or pet -bool ChatHandler::HandleNpcChangeLevelCommand(const char* args) -{ - if (!*args) - return false; - - uint8 lvl = (uint8) atoi((char*)args); - if (lvl < 1 || lvl > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) + 3) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Creature* pCreature = getSelectedCreature(); - if (!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if (pCreature->isPet()) - { - if (((Pet*)pCreature)->getPetType() == HUNTER_PET) - { - pCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, objmgr.GetXPForLevel(lvl)/4); - pCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0); - } - ((Pet*)pCreature)->GivePetLevel(lvl); - } - else - { - pCreature->SetMaxHealth(100 + 30*lvl); - pCreature->SetHealth(100 + 30*lvl); - pCreature->SetLevel(lvl); - pCreature->SaveToDB(); - } - - return true; -} - -//set npcflag of creature -bool ChatHandler::HandleNpcFlagCommand(const char* args) -{ - if (!*args) - return false; - - uint32 npcFlags = (uint32) atoi((char*)args); - - Creature* pCreature = getSelectedCreature(); - - if (!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags); - - WorldDatabase.PExecuteLog("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry()); - - SendSysMessage(LANG_VALUE_SAVED_REJOIN); - - return true; -} - -bool ChatHandler::HandleNpcDeleteCommand(const char* args) -{ - Creature* unit = NULL; - - if (*args) - { - // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hcreature"); - if (!cId) - return false; - - uint32 lowguid = atoi(cId); - if (!lowguid) - return false; - - if (CreatureData const* cr_data = objmgr.GetCreatureData(lowguid)) - unit = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(lowguid, cr_data->id, HIGHGUID_UNIT)); - } - else - unit = getSelectedCreature(); - - if (!unit || unit->isPet() || unit->isTotem()) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - // Delete the creature - unit->CombatStop(); - unit->DeleteFromDB(); - unit->AddObjectToRemoveList(); - - SendSysMessage(LANG_COMMAND_DELCREATMESSAGE); - - return true; -} - -//move selected creature -bool ChatHandler::HandleNpcMoveCommand(const char* args) -{ - uint32 lowguid = 0; - - Creature* pCreature = getSelectedCreature(); - - if (!pCreature) - { - // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hcreature"); - if (!cId) - return false; - - lowguid = atoi(cId); - - /* FIXME: impossibel without entry - if (lowguid) - pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); - */ - - // Attempting creature load from DB data - if (!pCreature) - { - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if (!data) - { - PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - uint32 map_id = data->mapid; - - if (m_session->GetPlayer()->GetMapId() != map_id) - { - PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid); - SetSentErrorMessage(true); - return false; - } - } - else - { - lowguid = pCreature->GetDBTableGUIDLow(); - } - } - else - { - lowguid = pCreature->GetDBTableGUIDLow(); - } - - float x = m_session->GetPlayer()->GetPositionX(); - float y = m_session->GetPlayer()->GetPositionY(); - float z = m_session->GetPlayer()->GetPositionZ(); - float o = m_session->GetPlayer()->GetOrientation(); - - if (pCreature) - { - if (CreatureData const* data = objmgr.GetCreatureData(pCreature->GetDBTableGUIDLow())) - { - const_cast(data)->posX = x; - const_cast(data)->posY = y; - const_cast(data)->posZ = z; - const_cast(data)->orientation = o; - } - pCreature->GetMap()->CreatureRelocation(pCreature,x, y, z,o); - pCreature->GetMotionMaster()->Initialize(); - if (pCreature->isAlive()) // dead creature will reset movement generator at respawn - { - pCreature->setDeathState(JUST_DIED); - pCreature->Respawn(); - } - } - - WorldDatabase.PExecuteLog("UPDATE creature SET position_x = '%f', position_y = '%f', position_z = '%f', orientation = '%f' WHERE guid = '%u'", x, y, z, o, lowguid); - PSendSysMessage(LANG_COMMAND_CREATUREMOVED); - return true; -} - -/**HandleNpcSetMoveTypeCommand - * Set the movement type for an NPC.
- *
- * Valid movement types are: - *
    - *
  • stay - NPC wont move
  • - *
  • random - NPC will move randomly according to the spawndist
  • - *
  • way - NPC will move with given waypoints set
  • - *
- * additional parameter: NODEL - so no waypoints are deleted, if you - * change the movement type - */ -bool ChatHandler::HandleNpcSetMoveTypeCommand(const char* args) -{ - if (!*args) - return false; - - // 3 arguments: - // GUID (optional - you can also select the creature) - // stay|random|way (determines the kind of movement) - // NODEL (optional - tells the system NOT to delete any waypoints) - // this is very handy if you want to do waypoints, that are - // later switched on/off according to special events (like escort - // quests, etc) - char* guid_str = strtok((char*)args, " "); - char* type_str = strtok((char*)NULL, " "); - char* dontdel_str = strtok((char*)NULL, " "); - - bool doNotDelete = false; - - if (!guid_str) - return false; - - uint32 lowguid = 0; - Creature* pCreature = NULL; - - if (dontdel_str) - { - //sLog.outError("DEBUG: All 3 params are set"); - - // All 3 params are set - // GUID - // type - // doNotDEL - if (stricmp(dontdel_str, "NODEL") == 0) - { - //sLog.outError("DEBUG: doNotDelete = true;"); - doNotDelete = true; - } - } - else - { - // Only 2 params - but maybe NODEL is set - if (type_str) - { - sLog.outError("DEBUG: Only 2 params "); - if (stricmp(type_str, "NODEL") == 0) - { - //sLog.outError("DEBUG: type_str, NODEL "); - doNotDelete = true; - type_str = NULL; - } - } - } - - if (!type_str) // case .setmovetype $move_type (with selected creature) - { - type_str = guid_str; - pCreature = getSelectedCreature(); - if (!pCreature || pCreature->isPet()) - return false; - lowguid = pCreature->GetDBTableGUIDLow(); - } - else // case .setmovetype #creature_guid $move_type (with selected creature) - { - lowguid = atoi((char*)guid_str); - - /* impossible without entry - if (lowguid) - pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); - */ - - // attempt check creature existence by DB data - if (!pCreature) - { - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if (!data) - { - PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - } - else - { - lowguid = pCreature->GetDBTableGUIDLow(); - } - } - - // now lowguid is low guid really existed creature - // and pCreature point (maybe) to this creature or NULL - - MovementGeneratorType move_type; - - std::string type = type_str; - - if (type == "stay") - move_type = IDLE_MOTION_TYPE; - else if (type == "random") - move_type = RANDOM_MOTION_TYPE; - else if (type == "way") - move_type = WAYPOINT_MOTION_TYPE; - else - return false; - - // update movement type - //if (doNotDelete == false) - // WaypointMgr.DeletePath(lowguid); - - if (pCreature) - { - // update movement type - if (doNotDelete == false) - pCreature->LoadPath(0); - - pCreature->SetDefaultMovementType(move_type); - pCreature->GetMotionMaster()->Initialize(); - if (pCreature->isAlive()) // dead creature will reset movement generator at respawn - { - pCreature->setDeathState(JUST_DIED); - pCreature->Respawn(); - } - pCreature->SaveToDB(); - } - if (doNotDelete == false) - { - PSendSysMessage(LANG_MOVE_TYPE_SET,type_str); - } - else - { - PSendSysMessage(LANG_MOVE_TYPE_SET_NODEL,type_str); - } - - return true; -} - -//set model of creature -bool ChatHandler::HandleNpcSetModelCommand(const char* args) -{ - if (!*args) - return false; - - uint32 displayId = (uint32) atoi((char*)args); - - Creature *pCreature = getSelectedCreature(); - - if (!pCreature || pCreature->isPet()) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->SetDisplayId(displayId); - pCreature->SetNativeDisplayId(displayId); - - pCreature->SaveToDB(); - - return true; -} -//set faction of creature -bool ChatHandler::HandleNpcFactionIdCommand(const char* args) -{ - if (!*args) - return false; - - uint32 factionId = (uint32) atoi((char*)args); - - if (!sFactionTemplateStore.LookupEntry(factionId)) - { - PSendSysMessage(LANG_WRONG_FACTION, factionId); - SetSentErrorMessage(true); - return false; - } - - Creature* pCreature = getSelectedCreature(); - - if (!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->setFaction(factionId); - - // faction is set in creature_template - not inside creature - - // update in memory - if (CreatureInfo const *cinfo = pCreature->GetCreatureInfo()) - { - const_cast(cinfo)->faction_A = factionId; - const_cast(cinfo)->faction_H = factionId; - } - - // and DB - WorldDatabase.PExecuteLog("UPDATE creature_template SET faction_A = '%u', faction_H = '%u' WHERE entry = '%u'", factionId, factionId, pCreature->GetEntry()); - - return true; -} -//set spawn dist of creature -bool ChatHandler::HandleNpcSpawnDistCommand(const char* args) -{ - if (!*args) - return false; - - float option = atof((char*)args); - if (option < 0.0f) - { - SendSysMessage(LANG_BAD_VALUE); - return false; - } - - MovementGeneratorType mtype = IDLE_MOTION_TYPE; - if (option >0.0f) - mtype = RANDOM_MOTION_TYPE; - - Creature *pCreature = getSelectedCreature(); - uint32 u_guidlow = 0; - - if (pCreature) - u_guidlow = pCreature->GetDBTableGUIDLow(); - else - return false; - - pCreature->SetRespawnRadius((float)option); - pCreature->SetDefaultMovementType(mtype); - pCreature->GetMotionMaster()->Initialize(); - if (pCreature->isAlive()) // dead creature will reset movement generator at respawn - { - pCreature->setDeathState(JUST_DIED); - pCreature->Respawn(); - } - - WorldDatabase.PExecuteLog("UPDATE creature SET spawndist=%f, MovementType=%i WHERE guid=%u",option,mtype,u_guidlow); - PSendSysMessage(LANG_COMMAND_SPAWNDIST,option); - return true; -} -//spawn time handling -bool ChatHandler::HandleNpcSpawnTimeCommand(const char* args) -{ - if (!*args) - return false; - - char* stime = strtok((char*)args, " "); - - if (!stime) - return false; - - int i_stime = atoi((char*)stime); - - if (i_stime < 0) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Creature *pCreature = getSelectedCreature(); - uint32 u_guidlow = 0; - - if (pCreature) - u_guidlow = pCreature->GetDBTableGUIDLow(); - else - return false; - - WorldDatabase.PExecuteLog("UPDATE creature SET spawntimesecs=%i WHERE guid=%u",i_stime,u_guidlow); - pCreature->SetRespawnDelay((uint32)i_stime); - PSendSysMessage(LANG_COMMAND_SPAWNTIME,i_stime); - - return true; -} -//npc follow handling -bool ChatHandler::HandleNpcFollowCommand(const char* /*args*/) -{ - Player *player = m_session->GetPlayer(); - Creature *creature = getSelectedCreature(); - - if (!creature) - { - PSendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - // Follow player - Using pet's default dist and angle - creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, creature->GetFollowAngle()); - - PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName()); - return true; -} -//npc unfollow handling -bool ChatHandler::HandleNpcUnFollowCommand(const char* /*args*/) -{ - Player *player = m_session->GetPlayer(); - Creature *creature = getSelectedCreature(); - - if (!creature) - { - PSendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if (/*creature->GetMotionMaster()->empty() ||*/ - creature->GetMotionMaster()->GetCurrentMovementGeneratorType () != TARGETED_MOTION_TYPE) - { - PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU); - SetSentErrorMessage(true); - return false; - } - - TargetedMovementGenerator const* mgen - = static_cast const*>((creature->GetMotionMaster()->top())); - - if (mgen->GetTarget() != player) - { - PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU); - SetSentErrorMessage(true); - return false; - } - - // reset movement - creature->GetMotionMaster()->MovementExpired(true); - - PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU_NOW, creature->GetName()); - return true; -} -//npc tame handling -bool ChatHandler::HandleNpcTameCommand(const char* /*args*/) -{ - Creature *creatureTarget = getSelectedCreature (); - if (!creatureTarget || creatureTarget->isPet ()) - { - PSendSysMessage (LANG_SELECT_CREATURE); - SetSentErrorMessage (true); - return false; - } - - Player *player = m_session->GetPlayer (); - - if (player->GetPetGUID ()) - { - SendSysMessage (LANG_YOU_ALREADY_HAVE_PET); - SetSentErrorMessage (true); - return false; - } - - CreatureInfo const* cInfo = creatureTarget->GetCreatureInfo(); - - if (!cInfo->isTameable (player->CanTameExoticPets())) - { - PSendSysMessage (LANG_CREATURE_NON_TAMEABLE,cInfo->Entry); - SetSentErrorMessage (true); - return false; - } - - // Everything looks OK, create new pet - Pet* pet = player->CreateTamedPetFrom (creatureTarget); - if (!pet) - { - PSendSysMessage (LANG_CREATURE_NON_TAMEABLE,cInfo->Entry); - SetSentErrorMessage (true); - return false; - } - - // place pet before player - float x,y,z; - player->GetClosePoint (x,y,z,creatureTarget->GetObjectSize (),CONTACT_DISTANCE); - pet->Relocate (x,y,z,M_PI-player->GetOrientation ()); - - // set pet to defensive mode by default (some classes can't control controlled pets in fact). - pet->SetReactState(REACT_DEFENSIVE); - - // calculate proper level - uint8 level = (creatureTarget->getLevel() < (player->getLevel() - 5)) ? (player->getLevel() - 5) : creatureTarget->getLevel(); - - // prepare visual effect for levelup - pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1); - - // add to world - pet->GetMap()->Add(pet->ToCreature()); - - // visual effect for levelup - pet->SetUInt32Value(UNIT_FIELD_LEVEL, level); - - // caster have pet now - player->SetMinion(pet, true); - - pet->SavePetToDB(PET_SAVE_AS_CURRENT); - player->PetSpellInitialize(); - - return true; -} -//npc phasemask handling -//change phasemask of creature or pet -bool ChatHandler::HandleNpcSetPhaseCommand(const char* args) -{ - if (!*args) - return false; - - uint32 phasemask = (uint32) atoi((char*)args); - if (phasemask == 0) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Creature* pCreature = getSelectedCreature(); - if (!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->SetPhaseMask(phasemask,true); - - if (!pCreature->isPet()) - pCreature->SaveToDB(); - - return true; -} -//npc deathstate handling -bool ChatHandler::HandleNpcSetDeathStateCommand(const char* args) -{ - if (!*args) - return false; - - Creature* pCreature = getSelectedCreature(); - if (!pCreature || pCreature->isPet()) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if (strncmp(args, "on", 3) == 0) - pCreature->SetDeadByDefault(true); - else if (strncmp(args, "off", 4) == 0) - pCreature->SetDeadByDefault(false); - else - { - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; - } - - pCreature->SaveToDB(); - pCreature->Respawn(); - - return true; -} - -//TODO: NpcCommands that need to be fixed : - -bool ChatHandler::HandleNpcNameCommand(const char* /*args*/) -{ - /* Temp. disabled - if (!*args) - return false; - - if (strlen((char*)args)>75) - { - PSendSysMessage(LANG_TOO_LONG_NAME, strlen((char*)args)-75); - return true; - } - - for (uint8 i = 0; i < strlen(args); ++i) - { - if (!isalpha(args[i]) && args[i] != ' ') - { - SendSysMessage(LANG_CHARS_ONLY); - return false; - } - } - - uint64 guid; - guid = m_session->GetPlayer()->GetSelection(); - if (guid == 0) - { - SendSysMessage(LANG_NO_SELECTION); - return true; - } - - Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); - - if (!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - return true; - } - - pCreature->SetName(args); - uint32 idname = objmgr.AddCreatureTemplate(pCreature->GetName()); - pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname); - - pCreature->SaveToDB(); - */ - - return true; -} - -bool ChatHandler::HandleNpcSubNameCommand(const char* /*args*/) -{ - /* Temp. disabled - - if (!*args) - args = ""; - - if (strlen((char*)args)>75) - { - - PSendSysMessage(LANG_TOO_LONG_SUBNAME, strlen((char*)args)-75); - return true; - } - - for (uint8 i = 0; i < strlen(args); i++) - { - if (!isalpha(args[i]) && args[i] != ' ') - { - SendSysMessage(LANG_CHARS_ONLY); - return false; - } - } - uint64 guid; - guid = m_session->GetPlayer()->GetSelection(); - if (guid == 0) - { - SendSysMessage(LANG_NO_SELECTION); - return true; - } - - Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); - - if (!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - return true; - } - - uint32 idname = objmgr.AddCreatureSubName(pCreature->GetName(),args,pCreature->GetUInt32Value(UNIT_FIELD_DISPLAYID)); - pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname); - - pCreature->SaveToDB(); - */ - return true; -} - -//move item to other slot -bool ChatHandler::HandleItemMoveCommand(const char* args) -{ - if (!*args) - return false; - uint8 srcslot, dstslot; - - char* pParam1 = strtok((char*)args, " "); - if (!pParam1) - return false; - - char* pParam2 = strtok(NULL, " "); - if (!pParam2) - return false; - - srcslot = (uint8)atoi(pParam1); - dstslot = (uint8)atoi(pParam2); - - if (srcslot == dstslot) - return true; - - if (!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,srcslot)) - return false; - - if (!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,dstslot)) - return false; - - uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot); - uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot); - - m_session->GetPlayer()->SwapItem(src, dst); - - return true; -} - -//demorph player or unit -bool ChatHandler::HandleDeMorphCommand(const char* /*args*/) -{ - Unit *target = getSelectedUnit(); - if (!target) - target = m_session->GetPlayer(); - - // check online security - else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0)) - return false; - - target->DeMorph(); - - return true; -} - -//morph creature or player -bool ChatHandler::HandleModifyMorphCommand(const char* args) -{ - if (!*args) - return false; - - uint16 display_id = (uint16)atoi((char*)args); - - Unit *target = getSelectedUnit(); - if (!target) - target = m_session->GetPlayer(); - - // check online security - else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0)) - return false; - - target->SetDisplayId(display_id); - - return true; -} - -//kick player -bool ChatHandler::HandleKickPlayerCommand(const char *args) -{ -/* const char* kickName = strtok((char*)args, " "); - char* kickReason = strtok(NULL, "\n"); - std::string reason = "No Reason"; - std::string kicker = "Console"; - if (kickReason) - reason = kickReason; - if (m_session) - kicker = m_session->GetPlayer()->GetName(); - - if (!kickName) - { - Player* player = getSelectedPlayer(); - if (!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if (player == m_session->GetPlayer()) - { - SendSysMessage(LANG_COMMAND_KICKSELF); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(player, 0)) - return false; - - if (sWorld.getConfig(CONFIG_SHOW_KICK_IN_WORLD) == 1) - { - sWorld.SendWorldText(LANG_COMMAND_KICKMESSAGE, player->GetName(), kicker.c_str(), reason.c_str()); - } - else - { - PSendSysMessage(LANG_COMMAND_KICKMESSAGE, player->GetName(), kicker.c_str(), reason.c_str()); - } - - player->GetSession()->KickPlayer(); - } - else - { - std::string name = extractPlayerNameFromLink((char*)kickName); - if (name.empty()) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - if (m_session && name == m_session->GetPlayer()->GetName()) - { - SendSysMessage(LANG_COMMAND_KICKSELF); - SetSentErrorMessage(true); - return false; - } - - Player* player = objmgr.GetPlayer(kickName); - if (!player) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - if (HasLowerSecurity(player, 0)) - { - SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); //maybe replacement string for this later on - SetSentErrorMessage(true); - return false; - } - - std::string nameLink = playerLink(name); - - if (sWorld.KickPlayer(name)) - { - if (sWorld.getConfig(CONFIG_SHOW_KICK_IN_WORLD) == 1) - { - sWorld.SendWorldText(LANG_COMMAND_KICKMESSAGE, nameLink.c_str(), kicker.c_str(), reason.c_str()); - } - else - { - PSendSysMessage(LANG_COMMAND_KICKMESSAGE,nameLink.c_str()); - } - } - else - { - PSendSysMessage(LANG_COMMAND_KICKNOTFOUNDPLAYER,nameLink.c_str()); - return false; - } - }*/ - Player* target; - if (!extractPlayerTarget((char*)args,&target)) - return false; - - if (m_session && target == m_session->GetPlayer()) - { - SendSysMessage(LANG_COMMAND_KICKSELF); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - // send before target pointer invalidate - PSendSysMessage(LANG_COMMAND_KICKMESSAGE,GetNameLink(target).c_str()); - target->GetSession()->KickPlayer(); - return true; -} - -//set temporary phase mask for player -bool ChatHandler::HandleModifyPhaseCommand(const char* args) -{ - if (!*args) - return false; - - uint32 phasemask = (uint32)atoi((char*)args); - - Unit *target = getSelectedUnit(); - if (!target) - target = m_session->GetPlayer(); - - // check online security - else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0)) - return false; - - target->SetPhaseMask(phasemask,true); - - return true; -} -//show info of gameobject -bool ChatHandler::HandleGOInfoCommand(const char* args) -{ - uint32 entry = 0; - uint32 type = 0; - uint32 displayid = 0; - std::string name; - - if (!*args) - { - if (WorldObject * obj = getSelectedObject()) - entry = obj->GetEntry(); - } - else - entry = atoi((char*)args); - - GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(entry); - - if (!goinfo) - return false; - - type = goinfo->type; - displayid = goinfo->displayId; - name = goinfo->name; - - PSendSysMessage(LANG_GOINFO_ENTRY, entry); - PSendSysMessage(LANG_GOINFO_TYPE, type); - PSendSysMessage(LANG_GOINFO_DISPLAYID, displayid); - PSendSysMessage(LANG_GOINFO_NAME, name.c_str()); - - return true; -} - -//show info of player -bool ChatHandler::HandlePInfoCommand(const char* args) -{ - Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) - return false; - - uint32 accId = 0; - uint32 money = 0; - uint32 total_player_time = 0; - uint8 level = 0; - uint32 latency = 0; - uint8 race; - uint8 Class; - - // get additional information from Player object - if (target) - { - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - accId = target->GetSession()->GetAccountId(); - money = target->GetMoney(); - total_player_time = target->GetTotalPlayedTime(); - level = target->getLevel(); - latency = target->GetSession()->GetLatency(); - race = target->getRace(); - Class = target->getClass(); - } - // get additional information from DB - else - { - // check offline security - if (HasLowerSecurity(NULL, target_guid)) - return false; - - // 0 1 2 3 4 5 - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT totaltime, level, money, account, race, class FROM characters WHERE guid = '%u'", GUID_LOPART(target_guid)); - if (!result) - return false; - - Field *fields = result->Fetch(); - total_player_time = fields[0].GetUInt32(); - level = fields[1].GetUInt32(); - money = fields[2].GetUInt32(); - accId = fields[3].GetUInt32(); - race = fields[4].GetUInt8(); - Class = fields[5].GetUInt8(); - } - - std::string username = GetTrinityString(LANG_ERROR); - std::string email = GetTrinityString(LANG_ERROR); - std::string last_ip = GetTrinityString(LANG_ERROR); - uint32 security = 0; - std::string last_login = GetTrinityString(LANG_ERROR); - - QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT a.username,aa.gmlevel,a.email,a.last_ip,a.last_login " - "FROM account a " - "LEFT JOIN account_access aa " - "ON (a.id = aa.id) " - "WHERE a.id = '%u'",accId); - if (result) - { - Field* fields = result->Fetch(); - username = fields[0].GetCppString(); - security = fields[1].GetUInt32(); - email = fields[2].GetCppString(); - - if (email.empty()) - email = "-"; - - if (!m_session || m_session->GetSecurity() >= security) - { - last_ip = fields[3].GetCppString(); - last_login = fields[4].GetCppString(); - } - else - { - last_ip = "-"; - last_login = "-"; - } - } - - std::string nameLink = playerLink(target_name); - - PSendSysMessage(LANG_PINFO_ACCOUNT, (target?"":GetTrinityString(LANG_OFFLINE)), nameLink.c_str(), GUID_LOPART(target_guid), username.c_str(), accId, email.c_str(), security, last_ip.c_str(), last_login.c_str(), latency); - - std::string race_s, Class_s; - switch(race) - { - case RACE_HUMAN: race_s = "Human"; break; - case RACE_ORC: race_s = "Orc"; break; - case RACE_DWARF: race_s = "Dwarf"; break; - case RACE_NIGHTELF: race_s = "Night Elf"; break; - case RACE_UNDEAD_PLAYER: race_s = "Undead"; break; - case RACE_TAUREN: race_s = "Tauren"; break; - case RACE_GNOME: race_s = "Gnome"; break; - case RACE_TROLL: race_s = "Troll"; break; - case RACE_BLOODELF: race_s = "Blood Elf"; break; - case RACE_DRAENEI: race_s = "Draenei"; break; - } - switch(Class) - { - case CLASS_WARRIOR: Class_s = "Warrior"; break; - case CLASS_PALADIN: Class_s = "Paladin"; break; - case CLASS_HUNTER: Class_s = "Hunter"; break; - case CLASS_ROGUE: Class_s = "Rogue"; break; - case CLASS_PRIEST: Class_s = "Priest"; break; - case CLASS_DEATH_KNIGHT: Class_s = "Death Knight"; break; - case CLASS_SHAMAN: Class_s = "Shaman"; break; - case CLASS_MAGE: Class_s = "Mage"; break; - case CLASS_WARLOCK: Class_s = "Warlock"; break; - case CLASS_DRUID: Class_s = "Druid"; break; - } - - std::string timeStr = secsToTimeString(total_player_time,true,true); - uint32 gold = money /GOLD; - uint32 silv = (money % GOLD) / SILVER; - uint32 copp = (money % GOLD) % SILVER; - PSendSysMessage(LANG_PINFO_LEVEL, race_s.c_str(), Class_s.c_str(), timeStr.c_str(), level, gold, silv, copp); - - return true; -} - -/////WAYPOINT COMMANDS - -/** - * Add a waypoint to a creature. - * - * The user can either select an npc or provide its GUID. - * - * The user can even select a visual waypoint - then the new waypoint - * is placed *after* the selected one - this makes insertion of new - * waypoints possible. - * - * eg: - * .wp add 12345 - * -> adds a waypoint to the npc with the GUID 12345 - * - * .wp add - * -> adds a waypoint to the currently selected creature - * - * - * @param args if the user did not provide a GUID, it is NULL - * - * @return true - command did succeed, false - something went wrong - */ -bool ChatHandler::HandleWpAddCommand(const char* args) -{ - sLog.outDebug("DEBUG: HandleWpAddCommand"); - - // optional - char* path_number = NULL; - uint32 pathid = 0; - - if (*args) - path_number = strtok((char*)args, " "); - - uint32 point = 0; - Creature* target = getSelectedCreature(); - - if (!path_number) - { - if (target) - pathid = target->GetWaypointPath(); - else - { - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT MAX(id) FROM waypoint_data"); - uint32 maxpathid = result->Fetch()->GetInt32(); - pathid = maxpathid+1; - sLog.outDebug("DEBUG: HandleWpAddCommand - New path started."); - PSendSysMessage("%s%s|r", "|cff00ff00", "New path started."); - } - } - else - pathid = atoi(path_number); - - // path_id -> ID of the Path - // point -> number of the waypoint (if not 0) - - if (!pathid) - { - sLog.outDebug("DEBUG: HandleWpAddCommand - Current creature haven't loaded path."); - PSendSysMessage("%s%s|r", "|cffff33ff", "Current creature haven't loaded path."); - return true; - } - - sLog.outDebug("DEBUG: HandleWpAddCommand - point == 0"); - - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT MAX(point) FROM waypoint_data WHERE id = '%u'",pathid); - - if (result) - point = (*result)[0].GetUInt32(); - - Player* player = m_session->GetPlayer(); - //Map *map = player->GetMap(); - - WorldDatabase.PExecuteLog("INSERT INTO waypoint_data (id, point, position_x, position_y, position_z) VALUES ('%u','%u','%f', '%f', '%f')", - pathid, point+1, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); - - PSendSysMessage("%s%s%u%s%u%s|r", "|cff00ff00", "PathID: |r|cff00ffff", pathid, "|r|cff00ff00: Waypoint |r|cff00ffff", point+1,"|r|cff00ff00 created. "); - return true; -} // HandleWpAddCommand - -bool ChatHandler::HandleWpLoadPathCommand(const char *args) -{ - if (!*args) - return false; - - // optional - char* path_number = NULL; - - if (*args) - path_number = strtok((char*)args, " "); - - uint32 pathid = 0; - uint32 guidlow = 0; - Creature* target = getSelectedCreature(); - - // Did player provide a path_id? - if (!path_number) - sLog.outDebug("DEBUG: HandleWpLoadPathCommand - No path number provided"); - - if (!target) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if (target->GetEntry() == 1) - { - PSendSysMessage("%s%s|r", "|cffff33ff", "You want to load path to a waypoint? Aren't you?"); - SetSentErrorMessage(true); - return false; - } - - pathid = atoi(path_number); - - if (!pathid) - { - PSendSysMessage("%s%s|r", "|cffff33ff", "No vallid path number provided."); - return true; - } - - guidlow = target->GetDBTableGUIDLow(); - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT guid FROM creature_addon WHERE guid = '%u'",guidlow); - - if (result) - WorldDatabase.PExecute("UPDATE creature_addon SET path_id = '%u' WHERE guid = '%u'", pathid, guidlow); - else - WorldDatabase.PExecute("INSERT INTO creature_addon(guid,path_id) VALUES ('%u','%u')", guidlow, pathid); - - WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE, guidlow); - - target->LoadPath(pathid); - target->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); - target->GetMotionMaster()->Initialize(); - target->MonsterSay("Path loaded.",0,0); - - return true; -} - -bool ChatHandler::HandleReloadAllPaths(const char* args) -{ - if (!*args) - return false; - - uint32 id = atoi(args); - - if (!id) - return false; - - PSendSysMessage("%s%s|r|cff00ffff%u|r", "|cff00ff00", "Loading Path: ", id); - sWaypointMgr->UpdatePath(id); - return true; -} - -bool ChatHandler::HandleWpUnLoadPathCommand(const char * /*args*/) -{ - uint32 guidlow = 0; - Creature* target = getSelectedCreature(); - - if (!target) - { - PSendSysMessage("%s%s|r", "|cff33ffff", "You must select target."); - return true; - } - - if (target->GetCreatureAddon()) - { - if (target->GetCreatureAddon()->path_id != 0) - { - WorldDatabase.PExecute("DELETE FROM creature_addon WHERE guid = %u", target->GetGUIDLow()); - target->UpdateWaypointID(0); - WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", IDLE_MOTION_TYPE, guidlow); - target->LoadPath(0); - target->SetDefaultMovementType(IDLE_MOTION_TYPE); - target->GetMotionMaster()->MoveTargetedHome(); - target->GetMotionMaster()->Initialize(); - target->MonsterSay("Path unloaded.",0,0); - return true; - } - PSendSysMessage("%s%s|r", "|cffff33ff", "Target have no loaded path."); - } - return true; -} - -bool ChatHandler::HandleWpEventCommand(const char* args) -{ - if (!*args) - return false; - - char* show_str = strtok((char*)args, " "); - std::string show = show_str; - - // Check - if ((show != "add") && (show != "mod") && (show != "del") && (show != "listid")) return false; - - char* arg_id = strtok(NULL, " "); - uint32 id = 0; - - if (show == "add") - { - if (arg_id) - id = atoi(arg_id); - - if (id) - { - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT id FROM waypoint_scripts WHERE guid = %u", id); - - if (!result) - { - WorldDatabase.PExecute("INSERT INTO waypoint_scripts(guid)VALUES(%u)", id); - PSendSysMessage("%s%s%u|r", "|cff00ff00", "Wp Event: New waypoint event added: ", id); - } - else - PSendSysMessage("|cff00ff00Wp Event: You have choosed an existing waypoint script guid: %u|r", id); - } - else - { - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT MAX(guid) FROM waypoint_scripts"); - id = result->Fetch()->GetUInt32(); - WorldDatabase.PExecute("INSERT INTO waypoint_scripts(guid)VALUES(%u)", id+1); - PSendSysMessage("%s%s%u|r", "|cff00ff00","Wp Event: New waypoint event added: |r|cff00ffff", id+1); - } - - return true; - } - - if (show == "listid") - { - if (!arg_id) - { - PSendSysMessage("%s%s|r", "|cff33ffff","Wp Event: You must provide waypoint script id."); - return true; - } - - id = atoi(arg_id); - - uint32 a2, a3, a4, a5, a6; - float a8, a9, a10, a11; - char const* a7; - - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = %u", id); - - if (!result) - { - PSendSysMessage("%s%s%u|r", "|cff33ffff", "Wp Event: No waypoint scripts found on id: ", id); - return true; - } - - Field *fields; - - do - { - fields = result->Fetch(); - a2 = fields[0].GetUInt32(); - a3 = fields[1].GetUInt32(); - a4 = fields[2].GetUInt32(); - a5 = fields[3].GetUInt32(); - a6 = fields[4].GetUInt32(); - a7 = fields[5].GetString(); - a8 = fields[6].GetFloat(); - a9 = fields[7].GetFloat(); - a10 = fields[8].GetFloat(); - a11 = fields[9].GetFloat(); - - PSendSysMessage("|cffff33ffid:|r|cff00ffff %u|r|cff00ff00, guid: |r|cff00ffff%u|r|cff00ff00, delay: |r|cff00ffff%u|r|cff00ff00, command: |r|cff00ffff%u|r|cff00ff00, datalong: |r|cff00ffff%u|r|cff00ff00, datalong2: |r|cff00ffff%u|r|cff00ff00, datatext: |r|cff00ffff%s|r|cff00ff00, posx: |r|cff00ffff%f|r|cff00ff00, posy: |r|cff00ffff%f|r|cff00ff00, posz: |r|cff00ffff%f|r|cff00ff00, orientation: |r|cff00ffff%f|r", id, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); - } - while (result->NextRow()); - } - - if (show == "del") - { - id = atoi(arg_id); - - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT guid FROM waypoint_scripts WHERE guid = %u", id); - - if (result) - { - WorldDatabase.PExecuteLog("DELETE FROM waypoint_scripts WHERE guid = %u", id); - PSendSysMessage("%s%s%u|r","|cff00ff00","Wp Event: Waypoint script removed: ", id); - } - else - PSendSysMessage("|cffff33ffWp Event: ERROR: you have selected a non existing script: %u|r", id); - - return true; - } - - if (show == "mod") - { - if (!arg_id) - { - SendSysMessage("|cffff33ffERROR: Waypoint script guid not present.|r"); - return true; - } - - id = atoi(arg_id); - - if (!id) - { - SendSysMessage("|cffff33ffERROR: No vallid waypoint script id not present.|r"); - return true; - } - - char* arg_2 = strtok(NULL," "); - - if (!arg_2) - { - SendSysMessage("|cffff33ffERROR: No argument present.|r"); - return true; - } - - std::string arg_string = arg_2; - - if ((arg_string != "setid") && (arg_string != "delay") && (arg_string != "command") - && (arg_string != "datalong") && (arg_string != "datalong2") && (arg_string != "dataint") && (arg_string != "posx") - && (arg_string != "posy") && (arg_string != "posz") && (arg_string != "orientation")) - { - SendSysMessage("|cffff33ffERROR: No valid argument present.|r"); - return true; - } - - char* arg_3; - std::string arg_str_2 = arg_2; - arg_3 = strtok(NULL," "); - - if (!arg_3) - { - SendSysMessage("|cffff33ffERROR: No additional argument present.|r"); - return true; - } - - float coord; - - if (arg_str_2 == "setid") - { - uint32 newid = atoi(arg_3); - PSendSysMessage("%s%s|r|cff00ffff%u|r|cff00ff00%s|r|cff00ffff%u|r","|cff00ff00","Wp Event: Wypoint scipt guid: ", newid," id changed: ", id); - WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET id='%u' WHERE guid='%u'", - newid, id); return true; - } - else - { - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT id FROM waypoint_scripts WHERE guid='%u'",id); - - if (!result) - { - SendSysMessage("|cffff33ffERROR: You have selected an non existing waypoint script guid.|r"); - return true; - } - - if (arg_str_2 == "posx") - { - coord = atof(arg_3); - WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET x='%f' WHERE guid='%u'", - coord, id); - PSendSysMessage("|cff00ff00Waypoint script:|r|cff00ffff %u|r|cff00ff00 position_x updated.|r", id); - return true; - } - else if (arg_str_2 == "posy") - { - coord = atof(arg_3); - WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET y='%f' WHERE guid='%u'", - coord, id); - PSendSysMessage("|cff00ff00Waypoint script: %u position_y updated.|r", id); - return true; - } - else if (arg_str_2 == "posz") - { - coord = atof(arg_3); - WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET z='%f' WHERE guid='%u'", - coord, id); - PSendSysMessage("|cff00ff00Waypoint script: |r|cff00ffff%u|r|cff00ff00 position_z updated.|r", id); - return true; - } - else if (arg_str_2 == "orientation") - { - coord = atof(arg_3); - WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET o='%f' WHERE guid='%u'", - coord, id); - PSendSysMessage("|cff00ff00Waypoint script: |r|cff00ffff%u|r|cff00ff00 orientation updated.|r", id); - return true; - } - else if (arg_str_2 == "dataint") - { - WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET %s='%u' WHERE guid='%u'", - arg_2, atoi(arg_3), id); - PSendSysMessage("|cff00ff00Waypoint script: |r|cff00ffff%u|r|cff00ff00 dataint updated.|r", id); - return true; - } - else - { - std::string arg_str_3 = arg_3; - WorldDatabase.escape_string(arg_str_3); - WorldDatabase.PExecuteLog("UPDATE waypoint_scripts SET %s='%s' WHERE guid='%u'", - arg_2, arg_str_3.c_str(), id); - } - } - PSendSysMessage("%s%s|r|cff00ffff%u:|r|cff00ff00 %s %s|r","|cff00ff00","Waypoint script:", id, arg_2,"updated."); - } - return true; -} - -bool ChatHandler::HandleWpModifyCommand(const char* args) -{ - sLog.outDebug("DEBUG: HandleWpModifyCommand"); - - if (!*args) - return false; - - // first arg: add del text emote spell waittime move - char* show_str = strtok((char*)args, " "); - if (!show_str) - { - return false; - } - - std::string show = show_str; - // Check - // Remember: "show" must also be the name of a column! - if ((show != "delay") && (show != "action") && (show != "action_chance") - && (show != "move_flag") && (show != "del") && (show != "move") && (show != "wpadd") -) - { - return false; - } - - // Next arg is: - char* arg_str = NULL; - - // Did user provide a GUID - // or did the user select a creature? - // -> variable lowguid is filled with the GUID of the NPC - uint32 pathid = 0; - uint32 point = 0; - uint32 wpGuid = 0; - Creature* target = getSelectedCreature(); - - if (!target || target->GetEntry() != VISUAL_WAYPOINT) - { - SendSysMessage("|cffff33ffERROR: You must select a waypoint.|r"); - return false; - } - - sLog.outDebug("DEBUG: HandleWpModifyCommand - User did select an NPC"); - // The visual waypoint - Creature* wpCreature = NULL; - wpGuid = target->GetGUIDLow(); - - // Did the user select a visual spawnpoint? - if (wpGuid) - wpCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT)); - // attempt check creature existence by DB data - else - { - PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, wpGuid); - return false; - } - // User did select a visual waypoint? - // Check the creature - if (wpCreature->GetEntry() == VISUAL_WAYPOINT) - { - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT id, point FROM waypoint_data WHERE wpguid = %u", wpGuid); - - if (!result) - { - sLog.outDebug("DEBUG: HandleWpModifyCommand - No waypoint found - used 'wpguid'"); - - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUIDLow()); - // Select waypoint number from database - // Since we compare float values, we have to deal with - // some difficulties. - // Here we search for all waypoints that only differ in one from 1 thousand - // (0.001) - There is no other way to compare C++ floats with mySQL floats - // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html - const char* maxDIFF = "0.01"; - result = WorldDatabase.PQuery("SELECT id, point FROM waypoint_data WHERE (abs(position_x - %f) <= %s) and (abs(position_y - %f) <= %s) and (abs(position_z - %f) <= %s)", - wpCreature->GetPositionX(), maxDIFF, wpCreature->GetPositionY(), maxDIFF, wpCreature->GetPositionZ(), maxDIFF); - if (!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, wpGuid); - return true; - } - } - sLog.outDebug("DEBUG: HandleWpModifyCommand - After getting wpGuid"); - - do - { - Field *fields = result->Fetch(); - pathid = fields[0].GetUInt32(); - point = fields[1].GetUInt32(); - } - while (result->NextRow()); - - // We have the waypoint number and the GUID of the "master npc" - // Text is enclosed in "<>", all other arguments not - arg_str = strtok((char*)NULL, " "); - } - - sLog.outDebug("DEBUG: HandleWpModifyCommand - Parameters parsed - now execute the command"); - - // Check for argument - if (show != "del" && show != "move" && arg_str == NULL) - { - PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, show_str); - return false; - } - - if (show == "del" && target) - { - PSendSysMessage("|cff00ff00DEBUG: wp modify del, PathID: |r|cff00ffff%u|r", pathid); - - // wpCreature - Creature* wpCreature = NULL; - - if (wpGuid != 0) - { - wpCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT)); - wpCreature->CombatStop(); - wpCreature->DeleteFromDB(); - wpCreature->AddObjectToRemoveList(); - } - - WorldDatabase.PExecuteLog("DELETE FROM waypoint_data WHERE id='%u' AND point='%u'", - pathid, point); - WorldDatabase.PExecuteLog("UPDATE waypoint_data SET point=point-1 WHERE id='%u' AND point>'%u'", - pathid, point); - - PSendSysMessage(LANG_WAYPOINT_REMOVED); - return true; - } // del - - if (show == "move" && target) - { - PSendSysMessage("|cff00ff00DEBUG: wp move, PathID: |r|cff00ffff%u|r", pathid); - - Player *chr = m_session->GetPlayer(); - Map *map = chr->GetMap(); - { - // wpCreature - Creature* wpCreature = NULL; - // What to do: - // Move the visual spawnpoint - // Respawn the owner of the waypoints - if (wpGuid != 0) - { - wpCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT)); - wpCreature->CombatStop(); - wpCreature->DeleteFromDB(); - wpCreature->AddObjectToRemoveList(); - // re-create - Creature* wpCreature2 = new Creature; - if (!wpCreature2->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), VISUAL_WAYPOINT, 0, 0, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation())) - { - PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); - delete wpCreature2; - return false; - } - - wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - wpCreature2->LoadFromDB(wpCreature2->GetDBTableGUIDLow(), map); - map->Add(wpCreature2); - //MapManager::Instance().GetMap(npcCreature->GetMapId())->Add(wpCreature2); - } - - WorldDatabase.PExecuteLog("UPDATE waypoint_data SET position_x = '%f',position_y = '%f',position_z = '%f' where id = '%u' AND point='%u'", - chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), pathid, point); - - PSendSysMessage(LANG_WAYPOINT_CHANGED); - } - return true; - } // move - - const char *text = arg_str; - - if (text == 0) - { - // show_str check for present in list of correct values, no sql injection possible - WorldDatabase.PExecuteLog("UPDATE waypoint_data SET %s=NULL WHERE id='%u' AND point='%u'", - show_str, pathid, point); - } - else - { - // show_str check for present in list of correct values, no sql injection possible - std::string text2 = text; - WorldDatabase.escape_string(text2); - WorldDatabase.PExecuteLog("UPDATE waypoint_data SET %s='%s' WHERE id='%u' AND point='%u'", - show_str, text2.c_str(), pathid, point); - } - - PSendSysMessage(LANG_WAYPOINT_CHANGED_NO, show_str); - return true; -} - -bool ChatHandler::HandleWpShowCommand(const char* args) -{ - sLog.outDebug("DEBUG: HandleWpShowCommand"); - - if (!*args) - return false; - - // first arg: on, off, first, last - char* show_str = strtok((char*)args, " "); - if (!show_str) - return false; - - // second arg: GUID (optional, if a creature is selected) - char* guid_str = strtok((char*)NULL, " "); - sLog.outDebug("DEBUG: HandleWpShowCommand: show_str: %s guid_str: %s", show_str, guid_str); - - uint32 pathid = 0; - Creature* target = getSelectedCreature(); - - // Did player provide a PathID? - - if (!guid_str) - { - sLog.outDebug("DEBUG: HandleWpShowCommand: !guid_str"); - // No PathID provided - // -> Player must have selected a creature - - if (!target) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pathid = target->GetWaypointPath(); - } - else - { - sLog.outDebug("|cff00ff00DEBUG: HandleWpShowCommand: PathID provided|r"); - // PathID provided - // Warn if player also selected a creature - // -> Creature selection is ignored <- - if (target) - SendSysMessage(LANG_WAYPOINT_CREATSELECTED); - - pathid = atoi((char*)guid_str); - } - - sLog.outDebug("DEBUG: HandleWpShowCommand: danach"); - - std::string show = show_str; - uint32 Maxpoint; - - sLog.outDebug("DEBUG: HandleWpShowCommand: PathID: %u", pathid); - - //PSendSysMessage("wpshow - show: %s", show); - - // Show info for the selected waypoint - if (show == "info") - { - // Check if the user did specify a visual waypoint - if (target->GetEntry() != VISUAL_WAYPOINT) - { - PSendSysMessage(LANG_WAYPOINT_VP_SELECT); - SetSentErrorMessage(true); - return false; - } - - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT id, point, delay, move_flag, action, action_chance FROM waypoint_data WHERE wpguid = %u", target->GetGUIDLow()); - - if (!result) - { - SendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM); - return true; - } - - SendSysMessage("|cff00ffffDEBUG: wp show info:|r"); - do - { - Field *fields = result->Fetch(); - pathid = fields[0].GetUInt32(); - uint32 point = fields[1].GetUInt32(); - uint32 delay = fields[2].GetUInt32(); - uint32 flag = fields[3].GetUInt32(); - uint32 ev_id = fields[4].GetUInt32(); - uint32 ev_chance = fields[5].GetUInt32(); - - PSendSysMessage("|cff00ff00Show info: for current point: |r|cff00ffff%u|r|cff00ff00, Path ID: |r|cff00ffff%u|r", point, pathid); - PSendSysMessage("|cff00ff00Show info: delay: |r|cff00ffff%u|r", delay); - PSendSysMessage("|cff00ff00Show info: Move flag: |r|cff00ffff%u|r", flag); - PSendSysMessage("|cff00ff00Show info: Waypoint event: |r|cff00ffff%u|r", ev_id); - PSendSysMessage("|cff00ff00Show info: Event chance: |r|cff00ffff%u|r", ev_chance); - } - while (result->NextRow()); - - return true; - } - - if (show == "on") - { - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT point, position_x,position_y,position_z FROM waypoint_data WHERE id = '%u'", pathid); - - if (!result) - { - SendSysMessage("|cffff33ffPath no found.|r"); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage("|cff00ff00DEBUG: wp on, PathID: |cff00ffff%u|r", pathid); - - // Delete all visuals for this NPC - QueryResult_AutoPtr result2 = WorldDatabase.PQuery("SELECT wpguid FROM waypoint_data WHERE id = '%u' and wpguid <> 0", pathid); - - if (result2) - { - bool hasError = false; - do - { - Field *fields = result2->Fetch(); - uint32 wpguid = fields[0].GetUInt32(); - Creature* pCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(wpguid,VISUAL_WAYPOINT,HIGHGUID_UNIT)); - - if (!pCreature) - { - PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, wpguid); - hasError = true; - WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", wpguid); - } - else - { - pCreature->CombatStop(); - pCreature->DeleteFromDB(); - pCreature->AddObjectToRemoveList(); - } - - } - while (result2->NextRow()); - - if (hasError) - { - PSendSysMessage(LANG_WAYPOINT_TOOFAR1); - PSendSysMessage(LANG_WAYPOINT_TOOFAR2); - PSendSysMessage(LANG_WAYPOINT_TOOFAR3); - } - } - - do - { - Field *fields = result->Fetch(); - uint32 point = fields[0].GetUInt32(); - float x = fields[1].GetFloat(); - float y = fields[2].GetFloat(); - float z = fields[3].GetFloat(); - - uint32 id = VISUAL_WAYPOINT; - - Player *chr = m_session->GetPlayer(); - Map *map = chr->GetMap(); - float o = chr->GetOrientation(); - - Creature* wpCreature = new Creature; - if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o)) - { - PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); - delete wpCreature; - return false; - } - - sLog.outDebug("DEBUG: UPDATE waypoint_data SET wpguid = '%u"); - // set "wpguid" column to the visual waypoint - WorldDatabase.PExecuteLog("UPDATE waypoint_data SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), pathid, point); - - wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); - // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(),map); - map->Add(wpCreature); - - if (target) - { - wpCreature->SetDisplayId(target->GetDisplayId()); - wpCreature->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.5); - wpCreature->SetLevel(point > MAX_LEVEL ? MAX_LEVEL : point); - } - } - while (result->NextRow()); - - SendSysMessage("|cff00ff00Showing the current creature's path.|r"); - return true; - } - - if (show == "first") - { - PSendSysMessage("|cff00ff00DEBUG: wp first, GUID: %u|r", pathid); - - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z FROM waypoint_data WHERE point='1' AND id = '%u'",pathid); - if (!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUND, pathid); - SetSentErrorMessage(true); - return false; - } - - Field *fields = result->Fetch(); - float x = fields[0].GetFloat(); - float y = fields[1].GetFloat(); - float z = fields[2].GetFloat(); - uint32 id = VISUAL_WAYPOINT; - - Player *chr = m_session->GetPlayer(); - float o = chr->GetOrientation(); - Map *map = chr->GetMap(); - - Creature* pCreature = new Creature; - if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT),map, chr->GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o)) - { - PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); - delete pCreature; - return false; - } - - pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); - pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map); - map->Add(pCreature); - - if (target) - { - pCreature->SetDisplayId(target->GetDisplayId()); - pCreature->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.5); - } - - return true; - } - - if (show == "last") - { - PSendSysMessage("|cff00ff00DEBUG: wp last, PathID: |r|cff00ffff%u|r", pathid); - - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT MAX(point) FROM waypoint_data WHERE id = '%u'",pathid); - if (result) - Maxpoint = (*result)[0].GetUInt32(); - else - Maxpoint = 0; - - result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z FROM waypoint_data WHERE point ='%u' AND id = '%u'",Maxpoint, pathid); - if (!result) - { - PSendSysMessage(LANG_WAYPOINT_NOTFOUNDLAST, pathid); - SetSentErrorMessage(true); - return false; - } - Field *fields = result->Fetch(); - float x = fields[0].GetFloat(); - float y = fields[1].GetFloat(); - float z = fields[2].GetFloat(); - uint32 id = VISUAL_WAYPOINT; - - Player *chr = m_session->GetPlayer(); - float o = chr->GetOrientation(); - Map *map = chr->GetMap(); - - Creature* pCreature = new Creature; - if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o)) - { - PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id); - delete pCreature; - return false; - } - - pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); - pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map); - map->Add(pCreature); - - if (target) - { - pCreature->SetDisplayId(target->GetDisplayId()); - pCreature->SetFloatValue(OBJECT_FIELD_SCALE_X, 0.5); - } - - return true; - } - - if (show == "off") - { - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE id = '%u'", 1); - if (!result) - { - SendSysMessage(LANG_WAYPOINT_VP_NOTFOUND); - SetSentErrorMessage(true); - return false; - } - bool hasError = false; - do - { - Field *fields = result->Fetch(); - uint32 guid = fields[0].GetUInt32(); - Creature* pCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(guid,VISUAL_WAYPOINT,HIGHGUID_UNIT)); - if (!pCreature) - { - PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, guid); - hasError = true; - WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", guid); - } - else - { - pCreature->CombatStop(); - pCreature->DeleteFromDB(); - pCreature->AddObjectToRemoveList(); - } - } - while (result->NextRow()); - // set "wpguid" column to "empty" - no visual waypoint spawned - WorldDatabase.PExecuteLog("UPDATE waypoint_data SET wpguid = '0'"); - //WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '0' WHERE wpguid <> '0'"); - - if (hasError) - { - PSendSysMessage(LANG_WAYPOINT_TOOFAR1); - PSendSysMessage(LANG_WAYPOINT_TOOFAR2); - PSendSysMessage(LANG_WAYPOINT_TOOFAR3); - } - - SendSysMessage(LANG_WAYPOINT_VP_ALLREMOVED); - return true; - } - - PSendSysMessage("|cffff33ffDEBUG: wpshow - no valid command found|r"); - return true; -} - -//////////// WAYPOINT COMMANDS // - -//rename characters -bool ChatHandler::HandleCharacterRenameCommand(const char* args) -{ - Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) - return false; - - if (target) - { - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - PSendSysMessage(LANG_RENAME_PLAYER, GetNameLink(target).c_str()); - target->SetAtLoginFlag(AT_LOGIN_RENAME); - } - else - { - // check offline security - if (HasLowerSecurity(NULL, target_guid)) - return false; - - std::string oldNameLink = playerLink(target_name); - - PSendSysMessage(LANG_RENAME_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(target_guid)); - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '1' WHERE guid = '%u'", GUID_LOPART(target_guid)); - } - - return true; -} - -// customize characters -bool ChatHandler::HandleCharacterCustomizeCommand(const char* args) -{ - Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) - return false; - - if (target) - { - PSendSysMessage(LANG_CUSTOMIZE_PLAYER, GetNameLink(target).c_str()); - target->SetAtLoginFlag(AT_LOGIN_CUSTOMIZE); - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '8' WHERE guid = '%u'", target->GetGUIDLow()); - } - else - { - std::string oldNameLink = playerLink(target_name); - - PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(target_guid)); - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '8' WHERE guid = '%u'", GUID_LOPART(target_guid)); - } - - return true; -} - -bool ChatHandler::HandleCharacterReputationCommand(const char* args) -{ - Player* target; - if (!extractPlayerTarget((char*)args,&target)) - return false; - - LocaleConstant loc = GetSessionDbcLocale(); - - FactionStateList const& targetFSL = target->GetReputationMgr().GetStateList(); - for (FactionStateList::const_iterator itr = targetFSL.begin(); itr != targetFSL.end(); ++itr) - { - FactionEntry const *factionEntry = sFactionStore.LookupEntry(itr->second.ID); - char const* factionName = factionEntry ? factionEntry->name[loc] : "#Not found#"; - ReputationRank rank = target->GetReputationMgr().GetRank(factionEntry); - std::string rankName = GetTrinityString(ReputationRankStrIndex[rank]); - std::ostringstream ss; - if (m_session) - ss << itr->second.ID << " - |cffffffff|Hfaction:" << itr->second.ID << "|h[" << factionName << " " << localeNames[loc] << "]|h|r"; - else - ss << itr->second.ID << " - " << factionName << " " << localeNames[loc]; - - ss << " " << rankName << " (" << target->GetReputationMgr().GetReputation(factionEntry) << ")"; - - if (itr->second.Flags & FACTION_FLAG_VISIBLE) - ss << GetTrinityString(LANG_FACTION_VISIBLE); - if (itr->second.Flags & FACTION_FLAG_AT_WAR) - ss << GetTrinityString(LANG_FACTION_ATWAR); - if (itr->second.Flags & FACTION_FLAG_PEACE_FORCED) - ss << GetTrinityString(LANG_FACTION_PEACE_FORCED); - if (itr->second.Flags & FACTION_FLAG_HIDDEN) - ss << GetTrinityString(LANG_FACTION_HIDDEN); - if (itr->second.Flags & FACTION_FLAG_INVISIBLE_FORCED) - ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED); - if (itr->second.Flags & FACTION_FLAG_INACTIVE) - ss << GetTrinityString(LANG_FACTION_INACTIVE); - - SendSysMessage(ss.str().c_str()); - } - return true; -} - -//change standstate -bool ChatHandler::HandleModifyStandStateCommand(const char* args) -{ - if (!*args) - return false; - - uint32 anim_id = atoi((char*)args); - m_session->GetPlayer()->SetUInt32Value(UNIT_NPC_EMOTESTATE , anim_id); - - return true; -} - -bool ChatHandler::HandleHonorAddCommand(const char* args) -{ - if (!*args) - return false; - - Player *target = getSelectedPlayer(); - if (!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - uint32 amount = (uint32)atoi(args); - target->RewardHonor(NULL, 1, amount); - return true; -} - -bool ChatHandler::HandleHonorAddKillCommand(const char* /*args*/) -{ - Unit *target = getSelectedUnit(); - if (!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0)) - return false; - - m_session->GetPlayer()->RewardHonor(target, 1); - return true; -} - -bool ChatHandler::HandleHonorUpdateCommand(const char* /*args*/) -{ - Player *target = getSelectedPlayer(); - if (!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - target->UpdateHonorFields(); - return true; -} - -bool ChatHandler::HandleLookupEventCommand(const char* args) -{ - if (!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - // converting string that we try to find to lower case - if (!Utf8toWStr(namepart,wnamepart)) - return false; - - wstrToLower(wnamepart); - - bool found = false; - - GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); - GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); - - for (uint32 id = 0; id < events.size(); ++id) - { - GameEventData const& eventData = events[id]; - - std::string descr = eventData.description; - if (descr.empty()) - continue; - - if (Utf8FitTo(descr, wnamepart)) - { - char const* active = activeEvents.find(id) != activeEvents.end() ? GetTrinityString(LANG_ACTIVE) : ""; - - if (m_session) - PSendSysMessage(LANG_EVENT_ENTRY_LIST_CHAT,id,id,eventData.description.c_str(),active); - else - PSendSysMessage(LANG_EVENT_ENTRY_LIST_CONSOLE,id,eventData.description.c_str(),active); - - if (!found) - found = true; - } - } - - if (!found) - SendSysMessage(LANG_NOEVENTFOUND); - - return true; -} - -bool ChatHandler::HandleEventActiveListCommand(const char* /*args*/) -{ - uint32 counter = 0; - - GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); - GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); - - char const* active = GetTrinityString(LANG_ACTIVE); - - for (GameEventMgr::ActiveEvents::const_iterator itr = activeEvents.begin(); itr != activeEvents.end(); ++itr) - { - uint32 event_id = *itr; - GameEventData const& eventData = events[event_id]; - - if (m_session) - PSendSysMessage(LANG_EVENT_ENTRY_LIST_CHAT,event_id,event_id,eventData.description.c_str(),active); - else - PSendSysMessage(LANG_EVENT_ENTRY_LIST_CONSOLE,event_id,eventData.description.c_str(),active); - - ++counter; - } - - if (counter == 0) - SendSysMessage(LANG_NOEVENTFOUND); - - return true; -} - -bool ChatHandler::HandleEventInfoCommand(const char* args) -{ - if (!*args) - return false; - - // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameevent"); - if (!cId) - return false; - - uint32 event_id = atoi(cId); - - GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); - - if (event_id >=events.size()) - { - SendSysMessage(LANG_EVENT_NOT_EXIST); - SetSentErrorMessage(true); - return false; - } - - GameEventData const& eventData = events[event_id]; - if (!eventData.isValid()) - { - SendSysMessage(LANG_EVENT_NOT_EXIST); - SetSentErrorMessage(true); - return false; - } - - GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); - bool active = activeEvents.find(event_id) != activeEvents.end(); - char const* activeStr = active ? GetTrinityString(LANG_ACTIVE) : ""; - - std::string startTimeStr = TimeToTimestampStr(eventData.start); - std::string endTimeStr = TimeToTimestampStr(eventData.end); - - uint32 delay = gameeventmgr.NextCheck(event_id); - time_t nextTime = time(NULL)+delay; - std::string nextStr = nextTime >= eventData.start && nextTime < eventData.end ? TimeToTimestampStr(time(NULL)+delay) : "-"; - - std::string occurenceStr = secsToTimeString(eventData.occurence * MINUTE); - std::string lengthStr = secsToTimeString(eventData.length * MINUTE); - - PSendSysMessage(LANG_EVENT_INFO,event_id,eventData.description.c_str(),activeStr, - startTimeStr.c_str(),endTimeStr.c_str(),occurenceStr.c_str(),lengthStr.c_str(), - nextStr.c_str()); - return true; -} - -bool ChatHandler::HandleEventStartCommand(const char* args) -{ - if (!*args) - return false; - - // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameevent"); - if (!cId) - return false; - - int32 event_id = atoi(cId); - - GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); - - if (event_id < 1 || event_id >=events.size()) - { - SendSysMessage(LANG_EVENT_NOT_EXIST); - SetSentErrorMessage(true); - return false; - } - - GameEventData const& eventData = events[event_id]; - if (!eventData.isValid()) - { - SendSysMessage(LANG_EVENT_NOT_EXIST); - SetSentErrorMessage(true); - return false; - } - - GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); - if (activeEvents.find(event_id) != activeEvents.end()) - { - PSendSysMessage(LANG_EVENT_ALREADY_ACTIVE,event_id); - SetSentErrorMessage(true); - return false; - } - - gameeventmgr.StartEvent(event_id,true); - return true; -} - -bool ChatHandler::HandleEventStopCommand(const char* args) -{ - if (!*args) - return false; - - // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameevent"); - if (!cId) - return false; - - int32 event_id = atoi(cId); - - GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); - - if (event_id < 1 || event_id >=events.size()) - { - SendSysMessage(LANG_EVENT_NOT_EXIST); - SetSentErrorMessage(true); - return false; - } - - GameEventData const& eventData = events[event_id]; - if (!eventData.isValid()) - { - SendSysMessage(LANG_EVENT_NOT_EXIST); - SetSentErrorMessage(true); - return false; - } - - GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); - - if (activeEvents.find(event_id) == activeEvents.end()) - { - PSendSysMessage(LANG_EVENT_NOT_ACTIVE,event_id); - SetSentErrorMessage(true); - return false; - } - - gameeventmgr.StopEvent(event_id,true); - return true; -} - -bool ChatHandler::HandleCombatStopCommand(const char* args) -{ - Player* target; - if (!extractPlayerTarget((char*)args,&target)) - return false; - - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - target->CombatStop(); - target->getHostileRefManager().deleteReferences(); - return true; -} - -void ChatHandler::HandleLearnSkillRecipesHelper(Player* player,uint32 skill_id) -{ - uint32 classmask = player->getClassMask(); - - for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) - { - SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j); - if (!skillLine) - continue; - - // wrong skill - if (skillLine->skillId != skill_id) - continue; - - // not high rank - if (skillLine->forward_spellid) - continue; - - // skip racial skills - if (skillLine->racemask != 0) - continue; - - // skip wrong class skills - if (skillLine->classmask && (skillLine->classmask & classmask) == 0) - continue; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId); - if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo,player,false)) - continue; - - player->learnSpell(skillLine->spellId, false); - } -} - -bool ChatHandler::HandleLearnAllCraftsCommand(const char* /*args*/) -{ - - for (uint32 i = 0; i < sSkillLineStore.GetNumRows(); ++i) - { - SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(i); - if (!skillInfo) - continue; - - if ((skillInfo->categoryId == SKILL_CATEGORY_PROFESSION || skillInfo->categoryId == SKILL_CATEGORY_SECONDARY) && - skillInfo->canLink) // only prof. with recipes have - { - HandleLearnSkillRecipesHelper(m_session->GetPlayer(),skillInfo->id); - } - } - - SendSysMessage(LANG_COMMAND_LEARN_ALL_CRAFT); - return true; -} - -bool ChatHandler::HandleLearnAllRecipesCommand(const char* args) -{ - // Learns all recipes of specified profession and sets skill to max - // Example: .learn all_recipes enchanting - - Player* target = getSelectedPlayer(); - if (!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - return false; - } - - if (!*args) - return false; - - std::wstring wnamepart; - - if (!Utf8toWStr(args,wnamepart)) - return false; - - // converting string that we try to find to lower case - wstrToLower(wnamepart); - - std::string name; - - SkillLineEntry const *targetSkillInfo = NULL; - for (uint32 i = 1; i < sSkillLineStore.GetNumRows(); ++i) - { - SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(i); - if (!skillInfo) - continue; - - if ((skillInfo->categoryId != SKILL_CATEGORY_PROFESSION && - skillInfo->categoryId != SKILL_CATEGORY_SECONDARY) || - !skillInfo->canLink) // only prof with recipes have set - continue; - - int loc = GetSessionDbcLocale(); - name = skillInfo->name[loc]; - if (name.empty()) - continue; - - if (!Utf8FitTo(name, wnamepart)) - { - loc = 0; - for (; loc < MAX_LOCALE; ++loc) - { - if (loc == GetSessionDbcLocale()) - continue; - - name = skillInfo->name[loc]; - if (name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - break; - } - } - - if (loc < MAX_LOCALE) - { - targetSkillInfo = skillInfo; - break; - } - } - - if (!targetSkillInfo) - return false; - - HandleLearnSkillRecipesHelper(target,targetSkillInfo->id); - - uint16 maxLevel = target->GetPureMaxSkillValue(targetSkillInfo->id); - target->SetSkill(targetSkillInfo->id, target->GetSkillStep(targetSkillInfo->id), maxLevel, maxLevel); - PSendSysMessage(LANG_COMMAND_LEARN_ALL_RECIPES, name.c_str()); - return true; -} - -bool ChatHandler::HandleLookupPlayerIpCommand(const char* args) -{ - - if (!*args) - return false; - - std::string ip = strtok ((char*)args, " "); - char* limit_str = strtok (NULL, " "); - int32 limit = limit_str ? atoi (limit_str) : -1; - - LoginDatabase.escape_string (ip); - - QueryResult_AutoPtr result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE last_ip = '%s'", ip.c_str ()); - - return LookupPlayerSearchCommand (result,limit); -} - -bool ChatHandler::HandleLookupPlayerAccountCommand(const char* args) -{ - if (!*args) - return false; - - std::string account = strtok ((char*)args, " "); - char* limit_str = strtok (NULL, " "); - int32 limit = limit_str ? atoi (limit_str) : -1; - - if (!AccountMgr::normalizeString (account)) - return false; - - LoginDatabase.escape_string (account); - - QueryResult_AutoPtr result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE username = '%s'", account.c_str ()); - - return LookupPlayerSearchCommand (result,limit); -} - -bool ChatHandler::HandleLookupPlayerEmailCommand(const char* args) -{ - - if (!*args) - return false; - - std::string email = strtok ((char*)args, " "); - char* limit_str = strtok (NULL, " "); - int32 limit = limit_str ? atoi (limit_str) : -1; - - LoginDatabase.escape_string (email); - - QueryResult_AutoPtr result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE email = '%s'", email.c_str ()); - - return LookupPlayerSearchCommand (result,limit); -} - -bool ChatHandler::LookupPlayerSearchCommand(QueryResult_AutoPtr result, int32 limit) -{ - if (!result) - { - PSendSysMessage(LANG_NO_PLAYERS_FOUND); - SetSentErrorMessage(true); - return false; - } - - int i =0; - do - { - Field* fields = result->Fetch(); - uint32 acc_id = fields[0].GetUInt32(); - std::string acc_name = fields[1].GetCppString(); - - QueryResult_AutoPtr chars = CharacterDatabase.PQuery("SELECT guid,name FROM characters WHERE account = '%u'", acc_id); - if (chars) - { - PSendSysMessage(LANG_LOOKUP_PLAYER_ACCOUNT,acc_name.c_str(),acc_id); - - uint64 guid = 0; - std::string name; - - do - { - Field* charfields = chars->Fetch(); - guid = charfields[0].GetUInt64(); - name = charfields[1].GetCppString(); - - PSendSysMessage(LANG_LOOKUP_PLAYER_CHARACTER,name.c_str(),guid); - ++i; - - } while (chars->NextRow() && (limit == -1 || i < limit)); - } - } while (result->NextRow()); - - if (i == 0) // empty accounts only - { - PSendSysMessage(LANG_NO_PLAYERS_FOUND); - SetSentErrorMessage(true); - return false; - } - - return true; -} - -/// Triggering corpses expire check in world -bool ChatHandler::HandleServerCorpsesCommand(const char* /*args*/) -{ - CorpsesErase(); - return true; -} - -bool ChatHandler::HandleRepairitemsCommand(const char* args) -{ - Player* target; - if (!extractPlayerTarget((char*)args,&target)) - return false; - - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - // Repair items - target->DurabilityRepairAll(false, 0, false); - - PSendSysMessage(LANG_YOU_REPAIR_ITEMS, GetNameLink(target).c_str()); - if (needReportToTarget(target)) - ChatHandler(target).PSendSysMessage(LANG_YOUR_ITEMS_REPAIRED, GetNameLink().c_str()); - return true; -} - -bool ChatHandler::HandleWaterwalkCommand(const char* args) -{ - if (!*args) - return false; - - Player *player = getSelectedPlayer(); - - if (!player) - { - PSendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(player, 0)) - return false; - - if (strncmp(args, "on", 3) == 0) - player->SetMovement(MOVE_WATER_WALK); // ON - else if (strncmp(args, "off", 4) == 0) - player->SetMovement(MOVE_LAND_WALK); // OFF - else - { - SendSysMessage(LANG_USE_BOL); - return false; - } - - PSendSysMessage(LANG_YOU_SET_WATERWALK, args, GetNameLink(player).c_str()); - if (needReportToTarget(player)) - ChatHandler(player).PSendSysMessage(LANG_YOUR_WATERWALK_SET, args, GetNameLink().c_str()); - return true; -} - -bool ChatHandler::HandleCreatePetCommand(const char* /*args*/) -{ - Player *player = m_session->GetPlayer(); - Creature *creatureTarget = getSelectedCreature(); - - if (!creatureTarget || creatureTarget->isPet() || creatureTarget->GetTypeId() == TYPEID_PLAYER) - { - PSendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - CreatureInfo const* cInfo = objmgr.GetCreatureTemplate(creatureTarget->GetEntry()); - // Creatures with family 0 crashes the server - if (cInfo->family == 0) - { - PSendSysMessage("This creature cannot be tamed. (family id: 0)."); - SetSentErrorMessage(true); - return false; - } - - if (player->GetPetGUID()) - { - PSendSysMessage("You already have a pet"); - SetSentErrorMessage(true); - return false; - } - - // Everything looks OK, create new pet - Pet* pet = new Pet(player, HUNTER_PET); - - if (!pet) - return false; - - if (!pet->CreateBaseAtCreature(creatureTarget)) - { - delete pet; - PSendSysMessage("Error 1"); - return false; - } - - creatureTarget->setDeathState(JUST_DIED); - creatureTarget->RemoveCorpse(); - creatureTarget->SetHealth(0); // just for nice GM-mode view - - pet->SetUInt64Value(UNIT_FIELD_CREATEDBY, player->GetGUID()); - pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, player->getFaction()); - - if (!pet->InitStatsForLevel(creatureTarget->getLevel())) - { - sLog.outError("ERROR: InitStatsForLevel() in EffectTameCreature failed! Pet deleted."); - PSendSysMessage("Error 2"); - delete pet; - return false; - } - - // prepare visual effect for levelup - pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()-1); - - pet->GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true); - // this enables pet details window (Shift+P) - pet->InitPetCreateSpells(); - pet->SetHealth(pet->GetMaxHealth()); - - pet->GetMap()->Add(pet->ToCreature()); - - // visual effect for levelup - pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()); - - player->SetMinion(pet, true); - pet->SavePetToDB(PET_SAVE_AS_CURRENT); - player->PetSpellInitialize(); - - return true; -} - -bool ChatHandler::HandlePetLearnCommand(const char* args) -{ - if (!*args) - return false; - - Player *plr = m_session->GetPlayer(); - Pet *pet = plr->GetPet(); - - if (!pet) - { - PSendSysMessage("You have no pet"); - SetSentErrorMessage(true); - return false; - } - - uint32 spellId = extractSpellIdFromLink((char*)args); - - if (!spellId || !sSpellStore.LookupEntry(spellId)) - return false; - - // Check if pet already has it - if (pet->HasSpell(spellId)) - { - PSendSysMessage("Pet already has spell: %u", spellId); - SetSentErrorMessage(true); - return false; - } - - // Check if spell is valid - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); - if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo)) - { - PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spellId); - SetSentErrorMessage(true); - return false; - } - - pet->learnSpell(spellId); - - PSendSysMessage("Pet has learned spell %u", spellId); - return true; -} - -bool ChatHandler::HandlePetUnlearnCommand(const char *args) -{ - if (!*args) - return false; - - Player *plr = m_session->GetPlayer(); - Pet *pet = plr->GetPet(); - - if (!pet) - { - PSendSysMessage("You have no pet"); - SetSentErrorMessage(true); - return false; - } - - uint32 spellId = extractSpellIdFromLink((char*)args); - - if (pet->HasSpell(spellId)) - pet->removeSpell(spellId, false); - else - PSendSysMessage("Pet doesn't have that spell"); - - return true; -} - -bool ChatHandler::HandlePetTpCommand(const char *args) -{ - if (!*args) - return false; - - Player *plr = m_session->GetPlayer(); - Pet *pet = plr->GetPet(); - - if (!pet) - { - PSendSysMessage("You have no pet"); - SetSentErrorMessage(true); - return false; - } - - uint32 tp = atol(args); - - //pet->SetTP(tp); - - PSendSysMessage("Pet's tp changed to %u", tp); - return true; -} - -bool ChatHandler::HandleActivateObjectCommand(const char *args) -{ - if (!*args) - return false; - - char* cId = extractKeyFromLink((char*)args,"Hgameobject"); - if (!cId) - return false; - - uint32 lowguid = atoi(cId); - if (!lowguid) - return false; - - GameObject* obj = NULL; - - // by DB guid - if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) - obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); - - if (!obj) - { - PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - // Activate - obj->SetLootState(GO_READY); - obj->UseDoorOrButton(10000); - - PSendSysMessage("Object activated!"); - - return true; -} - -// add creature, temp only -bool ChatHandler::HandleTempAddSpwCommand(const char* args) -{ - if (!*args) - return false; - char* charID = strtok((char*)args, " "); - if (!charID) - return false; - - Player *chr = m_session->GetPlayer(); - - uint32 id = atoi(charID); - if (!id) - return false; - - chr->SummonCreature(id, *chr, TEMPSUMMON_CORPSE_DESPAWN, 120); - - return true; -} - -// add go, temp only -bool ChatHandler::HandleTempGameObjectCommand(const char* args) -{ - if (!*args) - return false; - char* charID = strtok((char*)args, " "); - if (!charID) - return false; - - Player *chr = m_session->GetPlayer(); - - char* spawntime = strtok(NULL, " "); - uint32 spawntm = 300; - - if (spawntime) - spawntm = atoi((char*)spawntime); - - float x = chr->GetPositionX(); - float y = chr->GetPositionY(); - float z = chr->GetPositionZ(); - float ang = chr->GetOrientation(); - - float rot2 = sin(ang/2); - float rot3 = cos(ang/2); - - uint32 id = atoi(charID); - - chr->SummonGameObject(id,x,y,z,ang,0,0,rot2,rot3,spawntm); - - return true; -} - -bool ChatHandler::HandleNpcAddFormationCommand(const char* args) -{ - if (!*args) - return false; - - uint32 leaderGUID = (uint32) atoi((char*)args); - Creature *pCreature = getSelectedCreature(); - - if (!pCreature || !pCreature->GetDBTableGUIDLow()) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - uint32 lowguid = pCreature->GetDBTableGUIDLow(); - if (pCreature->GetFormation()) - { - PSendSysMessage("Selected creature is already member of group %u", pCreature->GetFormation()->GetId()); - return false; - } - - if (!lowguid) - return false; - - Player *chr = m_session->GetPlayer(); - FormationInfo *group_member; - - group_member = new FormationInfo; - group_member->follow_angle = (pCreature->GetAngle(chr) - chr->GetOrientation()) * 180 / M_PI; - group_member->follow_dist = sqrtf(pow(chr->GetPositionX() - pCreature->GetPositionX(),int(2))+pow(chr->GetPositionY()-pCreature->GetPositionY(),int(2))); - group_member->leaderGUID = leaderGUID; - group_member->groupAI = 0; - - CreatureGroupMap[lowguid] = group_member; - pCreature->SearchFormation(); - - WorldDatabase.PExecuteLog("INSERT INTO creature_formations (leaderGUID, memberGUID, dist, angle, groupAI) VALUES ('%u','%u','%f', '%f', '%u')", - leaderGUID, lowguid, group_member->follow_dist, group_member->follow_angle, group_member->groupAI); - - PSendSysMessage("Creature %u added to formation with leader %u", lowguid, leaderGUID); - - return true; - } - -bool ChatHandler::HandleNpcSetLinkCommand(const char* args) -{ - if (!*args) - return false; - - uint32 linkguid = (uint32) atoi((char*)args); - - Creature* pCreature = getSelectedCreature(); - - if (!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if (!pCreature->GetDBTableGUIDLow()) - { - PSendSysMessage("Selected creature isn't in creature table", pCreature->GetGUIDLow()); - SetSentErrorMessage(true); - return false; - } - - if (!objmgr.SetCreatureLinkedRespawn(pCreature->GetDBTableGUIDLow(), linkguid)) - { - PSendSysMessage("Selected creature can't link with guid '%u'", linkguid); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage("LinkGUID '%u' added to creature with DBTableGUID: '%u'", linkguid, pCreature->GetDBTableGUIDLow()); - return true; -} - -bool ChatHandler::HandleLookupTitleCommand(const char* args) -{ - if (!*args) - return false; - - // can be NULL in console call - Player* target = getSelectedPlayer(); - - // title name have single string arg for player name - char const* targetName = target ? target->GetName() : "NAME"; - - std::string namepart = args; - std::wstring wnamepart; - - if (!Utf8toWStr(namepart,wnamepart)) - return false; - - // converting string that we try to find to lower case - wstrToLower(wnamepart); - - uint32 counter = 0; // Counter for figure out that we found smth. - - // Search in CharTitles.dbc - for (uint32 id = 0; id < sCharTitlesStore.GetNumRows(); id++) - { - CharTitlesEntry const *titleInfo = sCharTitlesStore.LookupEntry(id); - if (titleInfo) - { - int loc = GetSessionDbcLocale(); - std::string name = titleInfo->name[loc]; - if (name.empty()) - continue; - - if (!Utf8FitTo(name, wnamepart)) - { - loc = 0; - for (; loc < MAX_LOCALE; ++loc) - { - if (loc == GetSessionDbcLocale()) - continue; - - name = titleInfo->name[loc]; - if (name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - break; - } - } - - if (loc < MAX_LOCALE) - { - char const* knownStr = target && target->HasTitle(titleInfo) ? GetTrinityString(LANG_KNOWN) : ""; - - char const* activeStr = target && target->GetUInt32Value(PLAYER_CHOSEN_TITLE) == titleInfo->bit_index - ? GetTrinityString(LANG_ACTIVE) - : ""; - - char titleNameStr[80]; - snprintf(titleNameStr,80,name.c_str(),targetName); - - // send title in "id (idx:idx) - [namedlink locale]" format - if (m_session) - PSendSysMessage(LANG_TITLE_LIST_CHAT,id,titleInfo->bit_index,id,titleNameStr,localeNames[loc],knownStr,activeStr); - else - PSendSysMessage(LANG_TITLE_LIST_CONSOLE,id,titleInfo->bit_index,titleNameStr,localeNames[loc],knownStr,activeStr); - - ++counter; - } - } - } - if (counter == 0) // if counter == 0 then we found nth - SendSysMessage(LANG_COMMAND_NOTITLEFOUND); - return true; -} - -bool ChatHandler::HandleTitlesAddCommand(const char* args) -{ - // number or [name] Shift-click form |color|Htitle:title_id|h[name]|h|r - char* id_p = extractKeyFromLink((char*)args,"Htitle"); - if (!id_p) - return false; - - int32 id = atoi(id_p); - if (id <= 0) - { - PSendSysMessage(LANG_INVALID_TITLE_ID, id); - SetSentErrorMessage(true); - return false; - } - - Player * target = getSelectedPlayer(); - if (!target) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - CharTitlesEntry const* titleInfo = sCharTitlesStore.LookupEntry(id); - if (!titleInfo) - { - PSendSysMessage(LANG_INVALID_TITLE_ID, id); - SetSentErrorMessage(true); - return false; - } - - std::string tNameLink = GetNameLink(target); - - char const* targetName = target->GetName(); - char titleNameStr[80]; - snprintf(titleNameStr,80,titleInfo->name[GetSessionDbcLocale()],targetName); - - target->SetTitle(titleInfo); - PSendSysMessage(LANG_TITLE_ADD_RES, id, titleNameStr, tNameLink.c_str()); - - return true; -} - -bool ChatHandler::HandleTitlesRemoveCommand(const char* args) -{ - // number or [name] Shift-click form |color|Htitle:title_id|h[name]|h|r - char* id_p = extractKeyFromLink((char*)args,"Htitle"); - if (!id_p) - return false; - - int32 id = atoi(id_p); - if (id <= 0) - { - PSendSysMessage(LANG_INVALID_TITLE_ID, id); - SetSentErrorMessage(true); - return false; - } - - Player * target = getSelectedPlayer(); - if (!target) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - CharTitlesEntry const* titleInfo = sCharTitlesStore.LookupEntry(id); - if (!titleInfo) - { - PSendSysMessage(LANG_INVALID_TITLE_ID, id); - SetSentErrorMessage(true); - return false; - } - - target->SetTitle(titleInfo,true); - - std::string tNameLink = GetNameLink(target); - - char const* targetName = target->GetName(); - char titleNameStr[80]; - snprintf(titleNameStr,80,titleInfo->name[GetSessionDbcLocale()],targetName); - - PSendSysMessage(LANG_TITLE_REMOVE_RES, id, titleNameStr, tNameLink.c_str()); - - if (!target->HasTitle(target->GetInt32Value(PLAYER_CHOSEN_TITLE))) - { - target->SetUInt32Value(PLAYER_CHOSEN_TITLE,0); - PSendSysMessage(LANG_CURRENT_TITLE_RESET, tNameLink.c_str()); - } - - return true; -} - -//Edit Player KnownTitles -bool ChatHandler::HandleTitlesSetMaskCommand(const char* args) -{ - if (!*args) - return false; - - uint64 titles = 0; - - sscanf((char*)args, UI64FMTD, &titles); - - Player *target = getSelectedPlayer(); - if (!target) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - uint64 titles2 = titles; - - for (uint32 i = 1; i < sCharTitlesStore.GetNumRows(); ++i) - if (CharTitlesEntry const* tEntry = sCharTitlesStore.LookupEntry(i)) - titles2 &= ~(uint64(1) << tEntry->bit_index); - - titles &= ~titles2; // remove not existed titles - - target->SetUInt64Value(PLAYER__FIELD_KNOWN_TITLES, titles); - SendSysMessage(LANG_DONE); - - if (!target->HasTitle(target->GetInt32Value(PLAYER_CHOSEN_TITLE))) - { - target->SetUInt32Value(PLAYER_CHOSEN_TITLE,0); - PSendSysMessage(LANG_CURRENT_TITLE_RESET,GetNameLink(target).c_str()); - } - - return true; -} - -bool ChatHandler::HandleCharacterTitlesCommand(const char* args) -{ - Player* target; - if (!extractPlayerTarget((char*)args,&target)) - return false; - - LocaleConstant loc = GetSessionDbcLocale(); - char const* targetName = target->GetName(); - char const* knownStr = GetTrinityString(LANG_KNOWN); - - // Search in CharTitles.dbc - for (uint32 id = 0; id < sCharTitlesStore.GetNumRows(); id++) - { - CharTitlesEntry const *titleInfo = sCharTitlesStore.LookupEntry(id); - if (titleInfo && target->HasTitle(titleInfo)) - { - std::string name = titleInfo->name[loc]; - if (name.empty()) - continue; - - char const* activeStr = target && target->GetUInt32Value(PLAYER_CHOSEN_TITLE) == titleInfo->bit_index - ? GetTrinityString(LANG_ACTIVE) - : ""; - - char titleNameStr[80]; - snprintf(titleNameStr,80,name.c_str(),targetName); - - // send title in "id (idx:idx) - [namedlink locale]" format - if (m_session) - PSendSysMessage(LANG_TITLE_LIST_CHAT,id,titleInfo->bit_index,id,titleNameStr,localeNames[loc],knownStr,activeStr); - else - PSendSysMessage(LANG_TITLE_LIST_CONSOLE,id,titleInfo->bit_index,name.c_str(),localeNames[loc],knownStr,activeStr); - } - } - return true; -} - -bool ChatHandler::HandleTitlesCurrentCommand(const char* args) -{ - // number or [name] Shift-click form |color|Htitle:title_id|h[name]|h|r - char* id_p = extractKeyFromLink((char*)args,"Htitle"); - if (!id_p) - return false; - - int32 id = atoi(id_p); - if (id <= 0) - { - PSendSysMessage(LANG_INVALID_TITLE_ID, id); - SetSentErrorMessage(true); - return false; - } - - Player * target = getSelectedPlayer(); - if (!target) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // check online security - if (HasLowerSecurity(target, 0)) - return false; - - CharTitlesEntry const* titleInfo = sCharTitlesStore.LookupEntry(id); - if (!titleInfo) - { - PSendSysMessage(LANG_INVALID_TITLE_ID, id); - SetSentErrorMessage(true); - return false; - } - - std::string tNameLink = GetNameLink(target); - - target->SetTitle(titleInfo); // to be sure that title now known - target->SetUInt32Value(PLAYER_CHOSEN_TITLE,titleInfo->bit_index); - - PSendSysMessage(LANG_TITLE_CURRENT_RES, id, titleInfo->name[GetSessionDbcLocale()], tNameLink.c_str()); - - return true; -} diff --git a/src/server/game/Chat/Level3.cpp b/src/server/game/Chat/Level3.cpp deleted file mode 100644 index f7ced44922b..00000000000 --- a/src/server/game/Chat/Level3.cpp +++ /dev/null @@ -1,7743 +0,0 @@ -/* -* Copyright (C) 2005-2009 MaNGOS -* -* Copyright (C) 2008-2010 Trinity -* -* 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, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectMgr.h" -#include "AuctionHouseMgr.h" -#include "AccountMgr.h" -#include "PlayerDump.h" -#include "SpellMgr.h" -#include "Player.h" -#include "Opcodes.h" -#include "GameObject.h" -#include "Chat.h" -#include "Log.h" -#include "Guild.h" -#include "ObjectAccessor.h" -#include "MapManager.h" -#include "Language.h" -#include "GridNotifiersImpl.h" -#include "CellImpl.h" -#include "Weather.h" -#include "PointMovementGenerator.h" -#include "TargetedMovementGenerator.h" -#include "SkillDiscovery.h" -#include "SkillExtraItems.h" -#include "SystemConfig.h" -#include "Config/ConfigEnv.h" -#include "Util.h" -#include "ItemEnchantmentMgr.h" -#include "BattleGroundMgr.h" -#include "InstanceSaveMgr.h" -#include "InstanceData.h" -#include "AuctionHouseBot.h" -#include "CreatureEventAIMgr.h" -#include "SpellAuraEffects.h" -#include "DBCEnums.h" -#include "ConditionMgr.h" - -bool ChatHandler::HandleAHBotOptionsCommand(const char *args) -{ - uint32 ahMapID = 0; - char * opt = strtok((char*)args, " "); - char * ahMapIdStr = strtok(NULL, " "); - if (ahMapIdStr) - { - ahMapID = (uint32) strtoul(ahMapIdStr, NULL, 0); - switch (ahMapID) - { - case 2: - case 6: - case 7: - break; - default: - opt = NULL; - break; - } - } - if (!opt) - { - PSendSysMessage("Syntax is: ahbotoptions $option $ahMapID (2, 6 or 7) $parameter"); - PSendSysMessage("Try ahbotoptions help to see a list of options."); - return false; - } - int l = strlen(opt); - - if (strncmp(opt,"help",l) == 0) - { - PSendSysMessage("AHBot commands:"); - PSendSysMessage("ahexpire"); - PSendSysMessage("minitems"); - PSendSysMessage("maxitems"); - //PSendSysMessage(""); - //PSendSysMessage(""); - PSendSysMessage("percentages"); - PSendSysMessage("minprice"); - PSendSysMessage("maxprice"); - PSendSysMessage("minbidprice"); - PSendSysMessage("maxbidprice"); - PSendSysMessage("maxstack"); - PSendSysMessage("buyerprice"); - PSendSysMessage("bidinterval"); - PSendSysMessage("bidsperinterval"); - return true; - } - else if (strncmp(opt,"ahexpire",l) == 0) - { - if (!ahMapIdStr) - { - PSendSysMessage("Syntax is: ahbotoptions ahexpire $ahMapID (2, 6 or 7)"); - return false; - } - auctionbot.Commands(0, ahMapID, NULL, NULL); - } - else if (strncmp(opt,"minitems",l) == 0) - { - char * param1 = strtok(NULL, " "); - if ((!ahMapIdStr) || (!param1)) - { - PSendSysMessage("Syntax is: ahbotoptions minitems $ahMapID (2, 6 or 7) $minItems"); - return false; - } - auctionbot.Commands(1, ahMapID, NULL, param1); - } - else if (strncmp(opt,"maxitems",l) == 0) - { - char * param1 = strtok(NULL, " "); - if ((!ahMapIdStr) || (!param1)) - { - PSendSysMessage("Syntax is: ahbotoptions maxitems $ahMapID (2, 6 or 7) $maxItems"); - return false; - } - auctionbot.Commands(2, ahMapID, NULL, param1); - } - else if (strncmp(opt,"mintime",l) == 0) - { - PSendSysMessage("ahbotoptions mintime has been deprecated"); - return false; - /* - char * param1 = strtok(NULL, " "); - if ((!ahMapIdStr) || (!param1)) - { - PSendSysMessage("Syntax is: ahbotoptions mintime $ahMapID (2, 6 or 7) $mintime"); - return false; - } - auctionbot.Commands(3, ahMapID, NULL, param1); - */ - } - else if (strncmp(opt,"maxtime",l) == 0) - { - PSendSysMessage("ahbotoptions maxtime has been deprecated"); - return false; - /* - char * param1 = strtok(NULL, " "); - if ((!ahMapIdStr) || (!param1)) - { - PSendSysMessage("Syntax is: ahbotoptions maxtime $ahMapID (2, 6 or 7) $maxtime"); - return false; - } - auctionbot.Commands(4, ahMapID, NULL, param1); - */ - } - else if (strncmp(opt,"percentages",l) == 0) - { - char * param1 = strtok(NULL, " "); - char * param2 = strtok(NULL, " "); - char * param3 = strtok(NULL, " "); - char * param4 = strtok(NULL, " "); - char * param5 = strtok(NULL, " "); - char * param6 = strtok(NULL, " "); - char * param7 = strtok(NULL, " "); - char * param8 = strtok(NULL, " "); - char * param9 = strtok(NULL, " "); - char * param10 = strtok(NULL, " "); - char * param11 = strtok(NULL, " "); - char * param12 = strtok(NULL, " "); - char * param13 = strtok(NULL, " "); - char * param14 = strtok(NULL, " "); - if ((!ahMapIdStr) || (!param14)) - { - PSendSysMessage("Syntax is: ahbotoptions percentages $ahMapID (2, 6 or 7) $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14"); - PSendSysMessage("1 GreyTradeGoods 2 WhiteTradeGoods 3 GreenTradeGoods 4 BlueTradeGoods 5 PurpleTradeGoods"); - PSendSysMessage("6 OrangeTradeGoods 7 YellowTradeGoods 8 GreyItems 9 WhiteItems 10 GreenItems 11 BlueItems"); - PSendSysMessage("12 PurpleItems 13 OrangeItems 14 YellowItems"); - PSendSysMessage("The total must add up to 100%"); - return false; - } - uint32 greytg = (uint32) strtoul(param1, NULL, 0); - uint32 whitetg = (uint32) strtoul(param2, NULL, 0); - uint32 greentg = (uint32) strtoul(param3, NULL, 0); - uint32 bluetg = (uint32) strtoul(param3, NULL, 0); - uint32 purpletg = (uint32) strtoul(param5, NULL, 0); - uint32 orangetg = (uint32) strtoul(param6, NULL, 0); - uint32 yellowtg = (uint32) strtoul(param7, NULL, 0); - uint32 greyi = (uint32) strtoul(param8, NULL, 0); - uint32 whitei = (uint32) strtoul(param9, NULL, 0); - uint32 greeni = (uint32) strtoul(param10, NULL, 0); - uint32 bluei = (uint32) strtoul(param11, NULL, 0); - uint32 purplei = (uint32) strtoul(param12, NULL, 0); - uint32 orangei = (uint32) strtoul(param13, NULL, 0); - uint32 yellowi = (uint32) strtoul(param14, NULL, 0); - uint32 totalPercent = greytg + whitetg + greentg + bluetg + purpletg + orangetg + yellowtg + greyi + whitei + greeni + bluei + purplei + orangei + yellowi; - if ((totalPercent == 0) || (totalPercent != 100)) - { - PSendSysMessage("Syntax is: ahbotoptions percentages $ahMapID (2, 6 or 7) $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14"); - PSendSysMessage("1 GreyTradeGoods 2 WhiteTradeGoods 3 GreenTradeGoods 4 BlueTradeGoods 5 PurpleTradeGoods"); - PSendSysMessage("6 OrangeTradeGoods 7 YellowTradeGoods 8 GreyItems 9 WhiteItems 10 GreenItems 11 BlueItems"); - PSendSysMessage("12 PurpleItems 13 OrangeItems 14 YellowItems"); - PSendSysMessage("The total must add up to 100%"); - return false; - } - char param[100]; - param[0] = '\0'; - strcat(param, param1); - strcat(param, " "); - strcat(param, param2); - strcat(param, " "); - strcat(param, param3); - strcat(param, " "); - strcat(param, param4); - strcat(param, " "); - strcat(param, param5); - strcat(param, " "); - strcat(param, param6); - strcat(param, " "); - strcat(param, param7); - strcat(param, " "); - strcat(param, param8); - strcat(param, " "); - strcat(param, param9); - strcat(param, " "); - strcat(param, param10); - strcat(param, " "); - strcat(param, param11); - strcat(param, " "); - strcat(param, param12); - strcat(param, " "); - strcat(param, param13); - strcat(param, " "); - strcat(param, param14); - auctionbot.Commands(5, ahMapID, NULL, param); - } - else if (strncmp(opt,"minprice",l) == 0) - { - char * param1 = strtok(NULL, " "); - char * param2 = strtok(NULL, " "); - if ((!ahMapIdStr) || (!param1) || (!param2)) - { - PSendSysMessage("Syntax is: ahbotoptions minprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); - return false; - } - if (strncmp(param1,"grey",l) == 0) - { - auctionbot.Commands(6, ahMapID, AHB_GREY, param2); - } - else if (strncmp(param1,"white",l) == 0) - { - auctionbot.Commands(6, ahMapID, AHB_WHITE, param2); - } - else if (strncmp(param1,"green",l) == 0) - { - auctionbot.Commands(6, ahMapID, AHB_GREEN, param2); - } - else if (strncmp(param1,"blue",l) == 0) - { - auctionbot.Commands(6, ahMapID, AHB_BLUE, param2); - } - else if (strncmp(param1,"purple",l) == 0) - { - auctionbot.Commands(6, ahMapID, AHB_PURPLE, param2); - } - else if (strncmp(param1,"orange",l) == 0) - { - auctionbot.Commands(6, ahMapID, AHB_ORANGE, param2); - } - else if (strncmp(param1,"yellow",l) == 0) - { - auctionbot.Commands(6, ahMapID, AHB_YELLOW, param2); - } - else - { - PSendSysMessage("Syntax is: ahbotoptions minprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); - return false; - } - } - else if (strncmp(opt,"maxprice",l) == 0) - { - char * param1 = strtok(NULL, " "); - char * param2 = strtok(NULL, " "); - if ((!ahMapIdStr) || (!param1) || (!param2)) - { - PSendSysMessage("Syntax is: ahbotoptions maxprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); - return false; - } - if (strncmp(param1,"grey",l) == 0) - { - auctionbot.Commands(7, ahMapID, AHB_GREY, param2); - } - else if (strncmp(param1,"white",l) == 0) - { - auctionbot.Commands(7, ahMapID, AHB_WHITE, param2); - } - else if (strncmp(param1,"green",l) == 0) - { - auctionbot.Commands(7, ahMapID, AHB_GREEN, param2); - } - else if (strncmp(param1,"blue",l) == 0) - { - auctionbot.Commands(7, ahMapID, AHB_BLUE, param2); - } - else if (strncmp(param1,"purple",l) == 0) - { - auctionbot.Commands(7, ahMapID, AHB_PURPLE, param2); - } - else if (strncmp(param1,"orange",l) == 0) - { - auctionbot.Commands(7, ahMapID, AHB_ORANGE, param2); - } - else if (strncmp(param1,"yellow",l) == 0) - { - auctionbot.Commands(7, ahMapID, AHB_YELLOW, param2); - } - else - { - PSendSysMessage("Syntax is: ahbotoptions maxprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); - return false; - } - } - else if (strncmp(opt,"minbidprice",l) == 0) - { - char * param1 = strtok(NULL, " "); - char * param2 = strtok(NULL, " "); - if ((!ahMapIdStr) || (!param1) || (!param2)) - { - PSendSysMessage("Syntax is: ahbotoptions minbidprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); - return false; - } - uint32 minBidPrice = (uint32) strtoul(param2, NULL, 0); - if ((minBidPrice < 1) || (minBidPrice > 100)) - { - PSendSysMessage("The min bid price multiplier must be between 1 and 100"); - return false; - } - if (strncmp(param1,"grey",l) == 0) - { - auctionbot.Commands(8, ahMapID, AHB_GREY, param2); - } - else if (strncmp(param1,"white",l) == 0) - { - auctionbot.Commands(8, ahMapID, AHB_WHITE, param2); - } - else if (strncmp(param1,"green",l) == 0) - { - auctionbot.Commands(8, ahMapID, AHB_GREEN, param2); - } - else if (strncmp(param1,"blue",l) == 0) - { - auctionbot.Commands(8, ahMapID, AHB_BLUE, param2); - } - else if (strncmp(param1,"purple",l) == 0) - { - auctionbot.Commands(8, ahMapID, AHB_PURPLE, param2); - } - else if (strncmp(param1,"orange",l) == 0) - { - auctionbot.Commands(8, ahMapID, AHB_ORANGE, param2); - } - else if (strncmp(param1,"yellow",l) == 0) - { - auctionbot.Commands(8, ahMapID, AHB_YELLOW, param2); - } - else - { - PSendSysMessage("Syntax is: ahbotoptions minbidprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); - return false; - } - } - else if (strncmp(opt,"maxbidprice",l) == 0) - { - char * param1 = strtok(NULL, " "); - char * param2 = strtok(NULL, " "); - if ((!ahMapIdStr) || (!param1) || (!param2)) - { - PSendSysMessage("Syntax is: ahbotoptions maxbidprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); - return false; - } - uint32 maxBidPrice = (uint32) strtoul(param2, NULL, 0); - if ((maxBidPrice < 1) || (maxBidPrice > 100)) - { - PSendSysMessage("The max bid price multiplier must be between 1 and 100"); - return false; - } - if (strncmp(param1,"grey",l) == 0) - { - auctionbot.Commands(9, ahMapID, AHB_GREY, param2); - } - else if (strncmp(param1,"white",l) == 0) - { - auctionbot.Commands(9, ahMapID, AHB_WHITE, param2); - } - else if (strncmp(param1,"green",l) == 0) - { - auctionbot.Commands(9, ahMapID, AHB_GREEN, param2); - } - else if (strncmp(param1,"blue",l) == 0) - { - auctionbot.Commands(9, ahMapID, AHB_BLUE, param2); - } - else if (strncmp(param1,"purple",l) == 0) - { - auctionbot.Commands(9, ahMapID, AHB_PURPLE, param2); - } - else if (strncmp(param1,"orange",l) == 0) - { - auctionbot.Commands(9, ahMapID, AHB_ORANGE, param2); - } - else if (strncmp(param1,"yellow",l) == 0) - { - auctionbot.Commands(9, ahMapID, AHB_YELLOW, param2); - } - else - { - PSendSysMessage("Syntax is: ahbotoptions max bidprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $price"); - return false; - } - } - else if (strncmp(opt,"maxstack",l) == 0) - { - char * param1 = strtok(NULL, " "); - char * param2 = strtok(NULL, " "); - if ((!ahMapIdStr) || (!param1) || (!param2)) - { - PSendSysMessage("Syntax is: ahbotoptions maxstack $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $value"); - return false; - } - uint32 maxStack = (uint32) strtoul(param2, NULL, 0); - if (maxStack < 0) - { - PSendSysMessage("maxstack can't be a negative number."); - return false; - } - if (strncmp(param1,"grey",l) == 0) - { - auctionbot.Commands(10, ahMapID, AHB_GREY, param2); - } - else if (strncmp(param1,"white",l) == 0) - { - auctionbot.Commands(10, ahMapID, AHB_WHITE, param2); - } - else if (strncmp(param1,"green",l) == 0) - { - auctionbot.Commands(10, ahMapID, AHB_GREEN, param2); - } - else if (strncmp(param1,"blue",l) == 0) - { - auctionbot.Commands(10, ahMapID, AHB_BLUE, param2); - } - else if (strncmp(param1,"purple",l) == 0) - { - auctionbot.Commands(10, ahMapID, AHB_PURPLE, param2); - } - else if (strncmp(param1,"orange",l) == 0) - { - auctionbot.Commands(10, ahMapID, AHB_ORANGE, param2); - } - else if (strncmp(param1,"yellow",l) == 0) - { - auctionbot.Commands(10, ahMapID, AHB_YELLOW, param2); - } - else - { - PSendSysMessage("Syntax is: ahbotoptions maxstack $ahMapID (2, 6 or 7) $color (grey, white, green, blue, purple, orange or yellow) $value"); - return false; - } - } - else if (strncmp(opt,"buyerprice",l) == 0) - { - char * param1 = strtok(NULL, " "); - char * param2 = strtok(NULL, " "); - if ((!ahMapIdStr) || (!param1) || (!param2)) - { - PSendSysMessage("Syntax is: ahbotoptions buyerprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue or purple) $price"); - return false; - } - if (strncmp(param1,"grey",l) == 0) - { - auctionbot.Commands(11, ahMapID, AHB_GREY, param2); - } - else if (strncmp(param1,"white",l) == 0) - { - auctionbot.Commands(11, ahMapID, AHB_WHITE, param2); - } - else if (strncmp(param1,"green",l) == 0) - { - auctionbot.Commands(11, ahMapID, AHB_GREEN, param2); - } - else if (strncmp(param1,"blue",l) == 0) - { - auctionbot.Commands(11, ahMapID, AHB_BLUE, param2); - } - else if (strncmp(param1,"purple",l) == 0) - { - auctionbot.Commands(11, ahMapID, AHB_PURPLE, param2); - } - else if (strncmp(param1,"orange",l) == 0) - { - auctionbot.Commands(11, ahMapID, AHB_ORANGE, param2); - } - else if (strncmp(param1,"yellow",l) == 0) - { - auctionbot.Commands(11, ahMapID, AHB_YELLOW, param2); - } - else - { - PSendSysMessage("Syntax is: ahbotoptions buyerprice $ahMapID (2, 6 or 7) $color (grey, white, green, blue or purple) $price"); - return false; - } - } - else if (strncmp(opt,"bidinterval",l) == 0) - { - char * param1 = strtok(NULL, " "); - if ((!ahMapIdStr) || (!param1)) - { - PSendSysMessage("Syntax is: ahbotoptions bidinterval $ahMapID (2, 6 or 7) $interval(in minutes)"); - return false; - } - auctionbot.Commands(12, ahMapID, NULL, param1); - } - else if (strncmp(opt,"bidsperinterval",l) == 0) - { - char * param1 = strtok(NULL, " "); - if ((!ahMapIdStr) || (!param1)) - { - PSendSysMessage("Syntax is: ahbotoptions bidsperinterval $ahMapID (2, 6 or 7) $bids"); - return false; - } - auctionbot.Commands(13, ahMapID, NULL, param1); - } - else - { - PSendSysMessage("Syntax is: ahbotoptions $option $ahMapID (2, 6 or 7) $parameter"); - PSendSysMessage("Try ahbotoptions help to see a list of options."); - return false; - } - return true; -} - -//reload commands -bool ChatHandler::HandleReloadAllCommand(const char*) -{ - HandleReloadSkillFishingBaseLevelCommand(""); - - HandleReloadAllAchievementCommand(""); - HandleReloadAllAreaCommand(""); - HandleReloadAllEventAICommand(""); - HandleReloadAllLootCommand(""); - HandleReloadAllNpcCommand(""); - HandleReloadAllQuestCommand(""); - HandleReloadAllSpellCommand(""); - HandleReloadAllItemCommand(""); - HandleReloadAllLocalesCommand(""); - - HandleReloadAccessRequirementCommand(""); - HandleReloadMailLevelRewardCommand(""); - HandleReloadCommandCommand(""); - HandleReloadReservedNameCommand(""); - HandleReloadTrinityStringCommand(""); - HandleReloadGameTeleCommand(""); - - HandleReloadAutobroadcastCommand(""); - return true; -} - -bool ChatHandler::HandleReloadAllAchievementCommand(const char*) -{ - HandleReloadAchievementCriteriaDataCommand(""); - HandleReloadAchievementRewardCommand(""); - return true; -} - -bool ChatHandler::HandleReloadAllAreaCommand(const char*) -{ - //HandleReloadQuestAreaTriggersCommand(""); -- reloaded in HandleReloadAllQuestCommand - HandleReloadAreaTriggerTeleportCommand(""); - HandleReloadAreaTriggerTavernCommand(""); - HandleReloadGameGraveyardZoneCommand(""); - return true; -} - -bool ChatHandler::HandleReloadAllLootCommand(const char*) -{ - sLog.outString("Re-Loading Loot Tables..."); - LoadLootTables(); - SendGlobalGMSysMessage("DB tables `*_loot_template` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadAllNpcCommand(const char* /*args*/) -{ - HandleReloadNpcGossipCommand("a"); - HandleReloadNpcTrainerCommand("a"); - HandleReloadNpcVendorCommand("a"); - HandleReloadPointsOfInterestCommand("a"); - HandleReloadSpellClickSpellsCommand("a"); - return true; -} - -bool ChatHandler::HandleReloadAllQuestCommand(const char* /*args*/) -{ - HandleReloadQuestAreaTriggersCommand("a"); - HandleReloadQuestTemplateCommand("a"); - - sLog.outString("Re-Loading Quests Relations..."); - objmgr.LoadQuestRelations(); - SendGlobalGMSysMessage("DB tables `*_questrelation` and `*_involvedrelation` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadAllScriptsCommand(const char*) -{ - if (sWorld.IsScriptScheduled()) - { - PSendSysMessage("DB scripts used currently, please attempt reload later."); - SetSentErrorMessage(true); - return false; - } - - sLog.outString("Re-Loading Scripts..."); - HandleReloadGameObjectScriptsCommand("a"); - HandleReloadEventScriptsCommand("a"); - HandleReloadQuestEndScriptsCommand("a"); - HandleReloadQuestStartScriptsCommand("a"); - HandleReloadSpellScriptsCommand("a"); - SendGlobalGMSysMessage("DB tables `*_scripts` reloaded."); - HandleReloadDbScriptStringCommand("a"); - HandleReloadWpScriptsCommand("a"); - return true; -} - -bool ChatHandler::HandleReloadAllEventAICommand(const char*) -{ - HandleReloadEventAITextsCommand("a"); - HandleReloadEventAISummonsCommand("a"); - HandleReloadEventAIScriptsCommand("a"); - return true; -} - -bool ChatHandler::HandleReloadAllSpellCommand(const char*) -{ - HandleReloadSkillDiscoveryTemplateCommand("a"); - HandleReloadSkillExtraItemTemplateCommand("a"); - HandleReloadSpellRequiredCommand("a"); - HandleReloadSpellAreaCommand("a"); - HandleReloadSpellGroupsCommand("a"); - HandleReloadSpellLearnSpellCommand("a"); - HandleReloadSpellLinkedSpellCommand("a"); - HandleReloadSpellProcEventCommand("a"); - HandleReloadSpellBonusesCommand("a"); - HandleReloadSpellTargetPositionCommand("a"); - HandleReloadSpellThreatsCommand("a"); - HandleReloadSpellGroupStackRulesCommand("a"); - HandleReloadSpellPetAurasCommand("a"); - HandleReloadSpellDisabledCommand("a"); - return true; -} - -bool ChatHandler::HandleReloadAllItemCommand(const char*) -{ - HandleReloadPageTextsCommand("a"); - HandleReloadItemEnchantementsCommand("a"); - return true; -} - -bool ChatHandler::HandleReloadAllLocalesCommand(const char* /*args*/) -{ - HandleReloadLocalesAchievementRewardCommand("a"); - HandleReloadLocalesCreatureCommand("a"); - HandleReloadLocalesGameobjectCommand("a"); - HandleReloadLocalesItemCommand("a"); - HandleReloadLocalesNpcTextCommand("a"); - HandleReloadLocalesPageTextCommand("a"); - HandleReloadLocalesPointsOfInterestCommand("a"); - HandleReloadLocalesQuestCommand("a"); - return true; -} - -bool ChatHandler::HandleReloadConfigCommand(const char* /*args*/) -{ - sLog.outString("Re-Loading config settings..."); - sWorld.LoadConfigSettings(true); - MapManager::Instance().InitializeVisibilityDistanceInfo(); - SendGlobalGMSysMessage("World config settings reloaded."); - return true; -} - -bool ChatHandler::HandleReloadAccessRequirementCommand(const char*) -{ - sLog.outString("Re-Loading Access Requirement definitions..."); - objmgr.LoadAccessRequirements(); - SendGlobalGMSysMessage("DB table `access_requirement` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadAchievementCriteriaDataCommand(const char*) -{ - sLog.outString("Re-Loading Additional Achievement Criteria Data..."); - achievementmgr.LoadAchievementCriteriaData(); - SendGlobalGMSysMessage("DB table `achievement_criteria_data` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadAchievementRewardCommand(const char*) -{ - sLog.outString("Re-Loading Achievement Reward Data..."); - achievementmgr.LoadRewards(); - SendGlobalGMSysMessage("DB table `achievement_reward` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadAreaTriggerTavernCommand(const char*) -{ - sLog.outString("Re-Loading Tavern Area Triggers..."); - objmgr.LoadTavernAreaTriggers(); - SendGlobalGMSysMessage("DB table `areatrigger_tavern` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadAreaTriggerTeleportCommand(const char*) -{ - sLog.outString("Re-Loading AreaTrigger teleport definitions..."); - objmgr.LoadAreaTriggerTeleports(); - SendGlobalGMSysMessage("DB table `areatrigger_teleport` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadAutobroadcastCommand(const char*) -{ - sLog.outString("Re-Loading Autobroadcast..."); - sWorld.LoadAutobroadcasts(); - SendGlobalGMSysMessage("DB table `autobroadcast` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadCommandCommand(const char*) -{ - load_command_table = true; - SendGlobalGMSysMessage("DB table `command` will be reloaded at next chat command use."); - return true; -} - -bool ChatHandler::HandleReloadCreatureTemplateCommand(const char* args) -{ - if (!*args) - return false; - - uint32 entry = (uint32) atoi((char*)args); - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT difficulty_entry_1,difficulty_entry_2,difficulty_entry_3,KillCredit1,KillCredit2,modelid1,modelid2,modelid3,modelid4,name,subname,IconName,gossip_menu_id,minlevel,maxlevel,exp,faction_A,faction_H,npcflag,speed_walk,speed_run,scale,rank,mindmg,maxdmg,dmgschool,attackpower,dmg_multiplier,baseattacktime,rangeattacktime,unit_class,unit_flags,dynamicflags,family,trainer_type,trainer_spell,trainer_class,trainer_race,minrangedmg,maxrangedmg,rangedattackpower,type,type_flags,lootid,pickpocketloot,skinloot,resistance1,resistance2,resistance3,resistance4,resistance5,resistance6,spell1,spell2,spell3,spell4,spell5,spell6,spell7,spell8,PetSpellDataId,VehicleId,mingold,maxgold,AIName,MovementType,InhabitType,Health_mod,Mana_mod,Armor_mod,RacialLeader,questItem1,questItem2,questItem3,questItem4,questItem5,questItem6,movementId,RegenHealth,equipment_id,mechanic_immune_mask,flags_extra,ScriptName FROM creature_template WHERE entry = %u", entry); - if (!result) - { - PSendSysMessage(LANG_COMMAND_CREATURETEMPLATE_NOTFOUND, entry); - SetSentErrorMessage(true); - return false; - } - - CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(entry); - if (!cInfo) - { - PSendSysMessage(LANG_COMMAND_CREATURESTORAGE_NOTFOUND, entry); - SetSentErrorMessage(true); - return false; - } - - sLog.outString("Reloading creature template entry %u", entry); - - Field *fields = result->Fetch(); - - const_cast(cInfo)->DifficultyEntry[0] = fields[0].GetUInt32(); - const_cast(cInfo)->DifficultyEntry[1] = fields[1].GetUInt32(); - const_cast(cInfo)->DifficultyEntry[2] = fields[2].GetUInt32(); - const_cast(cInfo)->KillCredit[0] = fields[3].GetUInt32(); - const_cast(cInfo)->KillCredit[1] = fields[4].GetUInt32(); - const_cast(cInfo)->Modelid1 = fields[5].GetUInt32(); - const_cast(cInfo)->Modelid2 = fields[6].GetUInt32(); - const_cast(cInfo)->Modelid3 = fields[7].GetUInt32(); - const_cast(cInfo)->Modelid4 = fields[8].GetUInt32(); - size_t len = 0; - if (const char* temp = fields[9].GetString()) - { - if (cInfo->Name) - delete cInfo->Name; - len = strlen(temp)+1; - const_cast(cInfo)->Name = new char[len]; - strncpy(cInfo->Name, temp, len); - } - if (const char* temp = fields[10].GetString()) - { - if (cInfo->SubName) - delete cInfo->SubName; - len = strlen(temp)+1; - const_cast(cInfo)->SubName = new char[len]; - strncpy(cInfo->SubName, temp, len); - } - if (const char* temp = fields[11].GetString()) - { - if (cInfo->IconName) - delete cInfo->IconName; - len = strlen(temp)+1; - const_cast(cInfo)->IconName = new char[len]; - strncpy(cInfo->IconName, temp, len); - } - const_cast(cInfo)->GossipMenuId = fields[12].GetUInt32(); - const_cast(cInfo)->minlevel = fields[13].GetUInt32(); - const_cast(cInfo)->maxlevel = fields[14].GetUInt32(); - const_cast(cInfo)->expansion = fields[15].GetUInt32(); - const_cast(cInfo)->faction_A = fields[16].GetUInt32(); - const_cast(cInfo)->faction_H = fields[17].GetUInt32(); - const_cast(cInfo)->npcflag = fields[18].GetUInt32(); - const_cast(cInfo)->speed_walk = fields[19].GetFloat(); - const_cast(cInfo)->speed_run = fields[20].GetFloat(); - const_cast(cInfo)->scale = fields[21].GetFloat(); - const_cast(cInfo)->rank = fields[22].GetUInt32(); - const_cast(cInfo)->mindmg = fields[23].GetFloat(); - const_cast(cInfo)->maxdmg = fields[24].GetFloat(); - const_cast(cInfo)->dmgschool = fields[25].GetUInt32(); - const_cast(cInfo)->attackpower = fields[26].GetUInt32(); - const_cast(cInfo)->dmg_multiplier = fields[27].GetFloat(); - const_cast(cInfo)->baseattacktime = fields[28].GetUInt32(); - const_cast(cInfo)->rangeattacktime = fields[29].GetUInt32(); - const_cast(cInfo)->unit_class = fields[30].GetUInt32(); - const_cast(cInfo)->unit_flags = fields[31].GetUInt32(); - const_cast(cInfo)->dynamicflags = fields[32].GetUInt32(); - const_cast(cInfo)->family = fields[33].GetUInt32(); - const_cast(cInfo)->trainer_type = fields[34].GetUInt32(); - const_cast(cInfo)->trainer_spell = fields[35].GetUInt32(); - const_cast(cInfo)->trainer_class = fields[36].GetUInt32(); - const_cast(cInfo)->trainer_race = fields[37].GetUInt32(); - const_cast(cInfo)->minrangedmg = fields[38].GetFloat(); - const_cast(cInfo)->maxrangedmg = fields[39].GetFloat(); - const_cast(cInfo)->rangedattackpower = fields[40].GetUInt32(); - const_cast(cInfo)->type = fields[41].GetUInt32(); - const_cast(cInfo)->type_flags = fields[42].GetUInt32(); - const_cast(cInfo)->lootid = fields[43].GetUInt32(); - const_cast(cInfo)->pickpocketLootId = fields[44].GetUInt32(); - const_cast(cInfo)->SkinLootId = fields[45].GetUInt32(); - const_cast(cInfo)->resistance1 = fields[46].GetUInt32(); - const_cast(cInfo)->resistance2 = fields[47].GetUInt32(); - const_cast(cInfo)->resistance3 = fields[48].GetUInt32(); - const_cast(cInfo)->resistance4 = fields[49].GetUInt32(); - const_cast(cInfo)->resistance5 = fields[50].GetUInt32(); - const_cast(cInfo)->resistance6 = fields[51].GetUInt32(); - const_cast(cInfo)->spells[0] = fields[52].GetUInt32(); - const_cast(cInfo)->spells[1] = fields[53].GetUInt32(); - const_cast(cInfo)->spells[2] = fields[54].GetUInt32(); - const_cast(cInfo)->spells[3] = fields[55].GetUInt32(); - const_cast(cInfo)->spells[4] = fields[56].GetUInt32(); - const_cast(cInfo)->spells[5] = fields[57].GetUInt32(); - const_cast(cInfo)->spells[6] = fields[58].GetUInt32(); - const_cast(cInfo)->spells[7] = fields[59].GetUInt32(); - const_cast(cInfo)->PetSpellDataId = fields[60].GetUInt32(); - const_cast(cInfo)->VehicleId = fields[61].GetUInt32(); - const_cast(cInfo)->mingold = fields[62].GetUInt32(); - const_cast(cInfo)->maxgold = fields[63].GetUInt32(); - if (const char* temp = fields[64].GetString()) - { - if (cInfo->AIName) - delete cInfo->AIName; - len = strlen(temp)+1; - const_cast(cInfo)->AIName = new char[len]; - strncpy(const_cast(cInfo->AIName), temp, len); - } - const_cast(cInfo)->MovementType = fields[65].GetUInt32(); - const_cast(cInfo)->InhabitType = fields[66].GetUInt32(); - const_cast(cInfo)->ModHealth = fields[67].GetFloat(); - const_cast(cInfo)->ModMana = fields[68].GetFloat(); - const_cast(cInfo)->ModArmor = fields[69].GetFloat(); - const_cast(cInfo)->RacialLeader = fields[70].GetBool(); - const_cast(cInfo)->questItems[0] = fields[71].GetUInt32(); - const_cast(cInfo)->questItems[1] = fields[72].GetUInt32(); - const_cast(cInfo)->questItems[2] = fields[73].GetUInt32(); - const_cast(cInfo)->questItems[3] = fields[74].GetUInt32(); - const_cast(cInfo)->questItems[4] = fields[75].GetUInt32(); - const_cast(cInfo)->questItems[5] = fields[76].GetUInt32(); - const_cast(cInfo)->movementId = fields[77].GetUInt32(); - const_cast(cInfo)->RegenHealth = fields[78].GetBool(); - const_cast(cInfo)->equipmentId = fields[79].GetUInt32(); - const_cast(cInfo)->MechanicImmuneMask = fields[80].GetUInt32(); - const_cast(cInfo)->flags_extra = fields[81].GetUInt32(); - const_cast(cInfo)->ScriptID = objmgr.GetScriptId(fields[82].GetString()); - - objmgr.CheckCreatureTemplate(cInfo); - - SendGlobalGMSysMessage("Creature template reloaded."); - return true; -} - -bool ChatHandler::HandleReloadCreatureQuestRelationsCommand(const char*) -{ - sLog.outString("Loading Quests Relations... (`creature_questrelation`)"); - objmgr.LoadCreatureQuestRelations(); - SendGlobalGMSysMessage("DB table `creature_questrelation` (creature quest givers) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadCreatureLinkedRespawnCommand(const char * /*args*/) -{ - sLog.outString("Loading Linked Respawns... (`creature_linked_respawn`)"); - objmgr.LoadCreatureLinkedRespawn(); - SendGlobalGMSysMessage("DB table `creature_linked_respawn` (creature linked respawns) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadCreatureQuestInvRelationsCommand(const char*) -{ - sLog.outString("Loading Quests Relations... (`creature_involvedrelation`)"); - objmgr.LoadCreatureInvolvedRelations(); - SendGlobalGMSysMessage("DB table `creature_involvedrelation` (creature quest takers) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadGossipMenuCommand(const char*) -{ - sLog.outString("Re-Loading `gossip_menu` Table!"); - objmgr.LoadGossipMenu(); - SendGlobalGMSysMessage("DB table `gossip_menu` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadGossipMenuOptionCommand(const char*) -{ - sLog.outString("Re-Loading `gossip_menu_option` Table!"); - objmgr.LoadGossipMenuItems(); - SendGlobalGMSysMessage("DB table `gossip_menu_option` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadGOQuestRelationsCommand(const char*) -{ - sLog.outString("Loading Quests Relations... (`gameobject_questrelation`)"); - objmgr.LoadGameobjectQuestRelations(); - SendGlobalGMSysMessage("DB table `gameobject_questrelation` (gameobject quest givers) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadGOQuestInvRelationsCommand(const char*) -{ - sLog.outString("Loading Quests Relations... (`gameobject_involvedrelation`)"); - objmgr.LoadGameobjectInvolvedRelations(); - SendGlobalGMSysMessage("DB table `gameobject_involvedrelation` (gameobject quest takers) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadQuestAreaTriggersCommand(const char*) -{ - sLog.outString("Re-Loading Quest Area Triggers..."); - objmgr.LoadQuestAreaTriggers(); - SendGlobalGMSysMessage("DB table `areatrigger_involvedrelation` (quest area triggers) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadQuestTemplateCommand(const char*) -{ - sLog.outString("Re-Loading Quest Templates..."); - objmgr.LoadQuests(); - SendGlobalGMSysMessage("DB table `quest_template` (quest definitions) reloaded."); - - /// dependent also from `gameobject` but this table not reloaded anyway - sLog.outString("Re-Loading GameObjects for quests..."); - objmgr.LoadGameObjectForQuests(); - SendGlobalGMSysMessage("Data GameObjects for quests reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesCreatureCommand(const char*) -{ - sLog.outString("Re-Loading Loot Tables... (`creature_loot_template`)"); - LoadLootTemplates_Creature(); - LootTemplates_Creature.CheckLootRefs(); - SendGlobalGMSysMessage("DB table `creature_loot_template` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesDisenchantCommand(const char*) -{ - sLog.outString("Re-Loading Loot Tables... (`disenchant_loot_template`)"); - LoadLootTemplates_Disenchant(); - LootTemplates_Disenchant.CheckLootRefs(); - SendGlobalGMSysMessage("DB table `disenchant_loot_template` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesFishingCommand(const char*) -{ - sLog.outString("Re-Loading Loot Tables... (`fishing_loot_template`)"); - LoadLootTemplates_Fishing(); - LootTemplates_Fishing.CheckLootRefs(); - SendGlobalGMSysMessage("DB table `fishing_loot_template` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesGameobjectCommand(const char*) -{ - sLog.outString("Re-Loading Loot Tables... (`gameobject_loot_template`)"); - LoadLootTemplates_Gameobject(); - LootTemplates_Gameobject.CheckLootRefs(); - SendGlobalGMSysMessage("DB table `gameobject_loot_template` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesItemCommand(const char*) -{ - sLog.outString("Re-Loading Loot Tables... (`item_loot_template`)"); - LoadLootTemplates_Item(); - LootTemplates_Item.CheckLootRefs(); - SendGlobalGMSysMessage("DB table `item_loot_template` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesMillingCommand(const char*) -{ - sLog.outString("Re-Loading Loot Tables... (`milling_loot_template`)"); - LoadLootTemplates_Milling(); - LootTemplates_Milling.CheckLootRefs(); - SendGlobalGMSysMessage("DB table `milling_loot_template` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesPickpocketingCommand(const char*) -{ - sLog.outString("Re-Loading Loot Tables... (`pickpocketing_loot_template`)"); - LoadLootTemplates_Pickpocketing(); - LootTemplates_Pickpocketing.CheckLootRefs(); - SendGlobalGMSysMessage("DB table `pickpocketing_loot_template` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesProspectingCommand(const char*) -{ - sLog.outString("Re-Loading Loot Tables... (`prospecting_loot_template`)"); - LoadLootTemplates_Prospecting(); - LootTemplates_Prospecting.CheckLootRefs(); - SendGlobalGMSysMessage("DB table `prospecting_loot_template` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesMailCommand(const char*) -{ - sLog.outString("Re-Loading Loot Tables... (`mail_loot_template`)"); - LoadLootTemplates_Mail(); - LootTemplates_Mail.CheckLootRefs(); - SendGlobalGMSysMessage("DB table `mail_loot_template` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesReferenceCommand(const char*) -{ - sLog.outString("Re-Loading Loot Tables... (`reference_loot_template`)"); - LoadLootTemplates_Reference(); - SendGlobalGMSysMessage("DB table `reference_loot_template` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesSkinningCommand(const char*) -{ - sLog.outString("Re-Loading Loot Tables... (`skinning_loot_template`)"); - LoadLootTemplates_Skinning(); - LootTemplates_Skinning.CheckLootRefs(); - SendGlobalGMSysMessage("DB table `skinning_loot_template` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadLootTemplatesSpellCommand(const char*) -{ - sLog.outString("Re-Loading Loot Tables... (`spell_loot_template`)"); - LoadLootTemplates_Spell(); - LootTemplates_Spell.CheckLootRefs(); - SendGlobalGMSysMessage("DB table `spell_loot_template` reloaded."); - sConditionMgr.LoadConditions(true); - return true; -} - -bool ChatHandler::HandleReloadTrinityStringCommand(const char*) -{ - sLog.outString("Re-Loading trinity_string Table!"); - objmgr.LoadTrinityStrings(); - SendGlobalGMSysMessage("DB table `trinity_string` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadNpcGossipCommand(const char*) -{ - sLog.outString("Re-Loading `npc_gossip` Table!"); - objmgr.LoadNpcTextId(); - SendGlobalGMSysMessage("DB table `npc_gossip` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadNpcTrainerCommand(const char*) -{ - sLog.outString("Re-Loading `npc_trainer` Table!"); - objmgr.LoadTrainerSpell(); - SendGlobalGMSysMessage("DB table `npc_trainer` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadNpcVendorCommand(const char*) -{ - sLog.outString("Re-Loading `npc_vendor` Table!"); - objmgr.LoadVendors(); - SendGlobalGMSysMessage("DB table `npc_vendor` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadPointsOfInterestCommand(const char*) -{ - sLog.outString("Re-Loading `points_of_interest` Table!"); - objmgr.LoadPointsOfInterest(); - SendGlobalGMSysMessage("DB table `points_of_interest` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellClickSpellsCommand(const char*) -{ - sLog.outString("Re-Loading `npc_spellclick_spells` Table!"); - objmgr.LoadNPCSpellClickSpells(); - SendGlobalGMSysMessage("DB table `npc_spellclick_spells` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadReservedNameCommand(const char*) -{ - sLog.outString("Loading ReservedNames... (`reserved_name`)"); - objmgr.LoadReservedPlayersNames(); - SendGlobalGMSysMessage("DB table `reserved_name` (player reserved names) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSkillDiscoveryTemplateCommand(const char* /*args*/) -{ - sLog.outString("Re-Loading Skill Discovery Table..."); - LoadSkillDiscoveryTable(); - SendGlobalGMSysMessage("DB table `skill_discovery_template` (recipes discovered at crafting) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSkillExtraItemTemplateCommand(const char* /*args*/) -{ - sLog.outString("Re-Loading Skill Extra Item Table..."); - LoadSkillExtraItemTable(); - SendGlobalGMSysMessage("DB table `skill_extra_item_template` (extra item creation when crafting) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSkillFishingBaseLevelCommand(const char* /*args*/) -{ - sLog.outString("Re-Loading Skill Fishing base level requirements..."); - objmgr.LoadFishingBaseSkillLevel(); - SendGlobalGMSysMessage("DB table `skill_fishing_base_level` (fishing base level for zone/subzone) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellAreaCommand(const char*) -{ - sLog.outString("Re-Loading SpellArea Data..."); - spellmgr.LoadSpellAreas(); - SendGlobalGMSysMessage("DB table `spell_area` (spell dependences from area/quest/auras state) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellRequiredCommand(const char*) -{ - sLog.outString("Re-Loading Spell Required Data... "); - spellmgr.LoadSpellRequired(); - SendGlobalGMSysMessage("DB table `spell_required` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellGroupsCommand(const char*) -{ - sLog.outString("Re-Loading Spell Groups..."); - spellmgr.LoadSpellGroups(); - SendGlobalGMSysMessage("DB table `spell_group` (spell groups) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellLearnSpellCommand(const char*) -{ - sLog.outString("Re-Loading Spell Learn Spells..."); - spellmgr.LoadSpellLearnSpells(); - SendGlobalGMSysMessage("DB table `spell_learn_spell` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellLinkedSpellCommand(const char*) -{ - sLog.outString("Re-Loading Spell Linked Spells..."); - spellmgr.LoadSpellLinked(); - SendGlobalGMSysMessage("DB table `spell_linked_spell` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellProcEventCommand(const char*) -{ - sLog.outString("Re-Loading Spell Proc Event conditions..."); - spellmgr.LoadSpellProcEvents(); - SendGlobalGMSysMessage("DB table `spell_proc_event` (spell proc trigger requirements) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellBonusesCommand(const char*) -{ - sLog.outString("Re-Loading Spell Bonus Data..."); - spellmgr.LoadSpellBonusess(); - SendGlobalGMSysMessage("DB table `spell_bonus_data` (spell damage/healing coefficients) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellTargetPositionCommand(const char*) -{ - sLog.outString("Re-Loading Spell target coordinates..."); - spellmgr.LoadSpellTargetPositions(); - SendGlobalGMSysMessage("DB table `spell_target_position` (destination coordinates for spell targets) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellThreatsCommand(const char*) -{ - sLog.outString("Re-Loading Aggro Spells Definitions..."); - spellmgr.LoadSpellThreats(); - SendGlobalGMSysMessage("DB table `spell_threat` (spell aggro definitions) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellGroupStackRulesCommand(const char*) -{ - sLog.outString("Re-Loading Spell Group Stack Rules..."); - spellmgr.LoadSpellGroupStackRules(); - SendGlobalGMSysMessage("DB table `spell_group_stack_rules` (spell stacking definitions) reloaded."); - return true; -} - -bool ChatHandler::HandleReloadSpellPetAurasCommand(const char*) -{ - sLog.outString("Re-Loading Spell pet auras..."); - spellmgr.LoadSpellPetAuras(); - SendGlobalGMSysMessage("DB table `spell_pet_auras` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadPageTextsCommand(const char*) -{ - sLog.outString("Re-Loading Page Texts..."); - objmgr.LoadPageTexts(); - SendGlobalGMSysMessage("DB table `page_texts` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadItemEnchantementsCommand(const char*) -{ - sLog.outString("Re-Loading Item Random Enchantments Table..."); - LoadRandomEnchantmentsTable(); - SendGlobalGMSysMessage("DB table `item_enchantment_template` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadGameObjectScriptsCommand(const char* arg) -{ - if (sWorld.IsScriptScheduled()) - { - SendSysMessage("DB scripts used currently, please attempt reload later."); - SetSentErrorMessage(true); - return false; - } - - if (*arg != 'a') - sLog.outString("Re-Loading Scripts from `gameobject_scripts`..."); - - objmgr.LoadGameObjectScripts(); - - if (*arg != 'a') - SendGlobalGMSysMessage("DB table `gameobject_scripts` reloaded."); - - return true; -} - -bool ChatHandler::HandleReloadEventScriptsCommand(const char* arg) -{ - if (sWorld.IsScriptScheduled()) - { - SendSysMessage("DB scripts used currently, please attempt reload later."); - SetSentErrorMessage(true); - return false; - } - - if (*arg != 'a') - sLog.outString("Re-Loading Scripts from `event_scripts`..."); - - objmgr.LoadEventScripts(); - - if (*arg != 'a') - SendGlobalGMSysMessage("DB table `event_scripts` reloaded."); - - return true; -} - -bool ChatHandler::HandleReloadWpScriptsCommand(const char* arg) -{ - if (sWorld.IsScriptScheduled()) - { - SendSysMessage("DB scripts used currently, please attempt reload later."); - SetSentErrorMessage(true); - return false; - } - - if (*arg != 'a') - sLog.outString("Re-Loading Scripts from `waypoint_scripts`..."); - - objmgr.LoadWaypointScripts(); - - if (*arg != 'a') - SendGlobalGMSysMessage("DB table `waypoint_scripts` reloaded."); - - return true; -} - -bool ChatHandler::HandleReloadEventAITextsCommand(const char* /*args*/) -{ - - sLog.outString("Re-Loading Texts from `creature_ai_texts`..."); - CreatureEAI_Mgr.LoadCreatureEventAI_Texts(); - SendGlobalGMSysMessage("DB table `creature_ai_texts` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadEventAISummonsCommand(const char* /*args*/) -{ - sLog.outString("Re-Loading Summons from `creature_ai_summons`..."); - CreatureEAI_Mgr.LoadCreatureEventAI_Summons(); - SendGlobalGMSysMessage("DB table `creature_ai_summons` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadEventAIScriptsCommand(const char* /*args*/) -{ - sLog.outString("Re-Loading Scripts from `creature_ai_scripts`..."); - CreatureEAI_Mgr.LoadCreatureEventAI_Scripts(); - SendGlobalGMSysMessage("DB table `creature_ai_scripts` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadQuestEndScriptsCommand(const char* arg) -{ - if (sWorld.IsScriptScheduled()) - { - SendSysMessage("DB scripts used currently, please attempt reload later."); - SetSentErrorMessage(true); - return false; - } - - if (*arg != 'a') - sLog.outString("Re-Loading Scripts from `quest_end_scripts`..."); - - objmgr.LoadQuestEndScripts(); - - if (*arg != 'a') - SendGlobalGMSysMessage("DB table `quest_end_scripts` reloaded."); - - return true; -} - -bool ChatHandler::HandleReloadQuestStartScriptsCommand(const char* arg) -{ - if (sWorld.IsScriptScheduled()) - { - SendSysMessage("DB scripts used currently, please attempt reload later."); - SetSentErrorMessage(true); - return false; - } - - if (*arg != 'a') - sLog.outString("Re-Loading Scripts from `quest_start_scripts`..."); - - objmgr.LoadQuestStartScripts(); - - if (*arg != 'a') - SendGlobalGMSysMessage("DB table `quest_start_scripts` reloaded."); - - return true; -} - -bool ChatHandler::HandleReloadSpellScriptsCommand(const char* arg) -{ - if (sWorld.IsScriptScheduled()) - { - SendSysMessage("DB scripts used currently, please attempt reload later."); - SetSentErrorMessage(true); - return false; - } - - if (*arg != 'a') - sLog.outString("Re-Loading Scripts from `spell_scripts`..."); - - objmgr.LoadSpellScripts(); - - if (*arg != 'a') - SendGlobalGMSysMessage("DB table `spell_scripts` reloaded."); - - return true; -} - -bool ChatHandler::HandleReloadDbScriptStringCommand(const char* /*arg*/) -{ - sLog.outString("Re-Loading Script strings from `db_script_string`..."); - objmgr.LoadDbScriptStrings(); - SendGlobalGMSysMessage("DB table `db_script_string` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadGameGraveyardZoneCommand(const char* /*arg*/) -{ - sLog.outString("Re-Loading Graveyard-zone links..."); - - objmgr.LoadGraveyardZones(); - - SendGlobalGMSysMessage("DB table `game_graveyard_zone` reloaded."); - - return true; -} - -bool ChatHandler::HandleReloadGameTeleCommand(const char* /*arg*/) -{ - sLog.outString("Re-Loading Game Tele coordinates..."); - - objmgr.LoadGameTele(); - - SendGlobalGMSysMessage("DB table `game_tele` reloaded."); - - return true; -} - -bool ChatHandler::HandleReloadSpellDisabledCommand(const char* /*arg*/) -{ - sLog.outString("Re-Loading spell disabled table..."); - - objmgr.LoadSpellDisabledEntrys(); - - SendGlobalGMSysMessage("DB table `spell_disabled` reloaded."); - - return true; -} - -bool ChatHandler::HandleReloadLocalesAchievementRewardCommand(const char*) -{ - sLog.outString("Re-Loading Locales Achievement Reward Data..."); - achievementmgr.LoadRewardLocales(); - SendGlobalGMSysMessage("DB table `locales_achievement_reward` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLocalesCreatureCommand(const char* /*arg*/) -{ - sLog.outString("Re-Loading Locales Creature ..."); - objmgr.LoadCreatureLocales(); - SendGlobalGMSysMessage("DB table `locales_creature` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLocalesGameobjectCommand(const char* /*arg*/) -{ - sLog.outString("Re-Loading Locales Gameobject ... "); - objmgr.LoadGameObjectLocales(); - SendGlobalGMSysMessage("DB table `locales_gameobject` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLocalesItemCommand(const char* /*arg*/) -{ - sLog.outString("Re-Loading Locales Item ... "); - objmgr.LoadItemLocales(); - SendGlobalGMSysMessage("DB table `locales_item` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLocalesNpcTextCommand(const char* /*arg*/) -{ - sLog.outString("Re-Loading Locales NPC Text ... "); - objmgr.LoadNpcTextLocales(); - SendGlobalGMSysMessage("DB table `locales_npc_text` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLocalesPageTextCommand(const char* /*arg*/) -{ - sLog.outString("Re-Loading Locales Page Text ... "); - objmgr.LoadPageTextLocales(); - SendGlobalGMSysMessage("DB table `locales_page_text` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLocalesPointsOfInterestCommand(const char* /*arg*/) -{ - sLog.outString("Re-Loading Locales Points Of Interest ... "); - objmgr.LoadPointOfInterestLocales(); - SendGlobalGMSysMessage("DB table `locales_points_of_interest` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadLocalesQuestCommand(const char* /*arg*/) -{ - sLog.outString("Re-Loading Locales Quest ... "); - objmgr.LoadQuestLocales(); - SendGlobalGMSysMessage("DB table `locales_quest` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadMailLevelRewardCommand(const char* /*arg*/) -{ - sLog.outString("Re-Loading Player level dependent mail rewards..."); - objmgr.LoadMailLevelRewards(); - SendGlobalGMSysMessage("DB table `mail_level_reward` reloaded."); - return true; -} - -bool ChatHandler::HandleReloadAuctionsCommand(const char * /*args*/) -{ - ///- Reload dynamic data tables from the database - sLog.outString("Re-Loading Auctions..."); - auctionmgr.LoadAuctionItems(); - auctionmgr.LoadAuctions(); - SendGlobalGMSysMessage("Auctions reloaded."); - return true; -} - -bool ChatHandler::HandleReloadConditions(const char* args) -{ - sLog.outString("Re-Loading Conditions..."); - sConditionMgr.LoadConditions(true); - SendGlobalGMSysMessage("Conditions reloaded."); - return true; -} - -bool ChatHandler::HandleAccountSetGmLevelCommand(const char *args) -{ - if (!*args) - return false; - - std::string targetAccountName; - uint32 targetAccountId = 0; - uint32 targetSecurity = 0; - uint32 gm = 0; - char* arg1 = strtok((char*)args, " "); - char* arg2 = strtok(NULL, " "); - char* arg3 = strtok(NULL, " "); - bool isAccountNameGiven = true; - - if (arg1 && !arg3) - { - if (!getSelectedPlayer()) - return false; - isAccountNameGiven = false; - } - - // Check for second parameter - if (!isAccountNameGiven && !arg2) - return false; - - // Check for account - if (isAccountNameGiven) - { - targetAccountName = arg1; - if (!AccountMgr::normalizeString(targetAccountName)) - { - PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,targetAccountName.c_str()); - SetSentErrorMessage(true); - return false; - } - } - - // Check for invalid specified GM level. - gm = (isAccountNameGiven) ? atoi(arg2) : atoi(arg1); - if (gm < SEC_PLAYER) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - // m_session == NULL only for console - targetAccountId = (isAccountNameGiven) ? accmgr.GetId(targetAccountName) : getSelectedPlayer()->GetSession()->GetAccountId(); - int32 gmRealmID = (isAccountNameGiven) ? atoi(arg3) : atoi(arg2); - uint32 plSecurity = m_session ? accmgr.GetSecurity(m_session->GetAccountId(), gmRealmID) : SEC_CONSOLE; - - // can set security level only for target with less security and to less security that we have - // This is also reject self apply in fact - targetSecurity = accmgr.GetSecurity(targetAccountId, gmRealmID); - if (targetSecurity >= plSecurity || gm >= plSecurity) - { - SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); - SetSentErrorMessage(true); - return false; - } - - // Check and abort if the target gm has a higher rank on one of the realms and the new realm is -1 - if (gmRealmID == -1) - { - QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT * FROM account_access WHERE id = '%u' AND gmlevel > '%d'", targetAccountId, gm); - if (result) - { - SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); - SetSentErrorMessage(true); - return false; - } - } - - // Check if provided realmID has a negative value other than -1 - if (gmRealmID < -1) - { - SendSysMessage(LANG_INVALID_REALMID); - SetSentErrorMessage(true); - return false; - } - - // If gmRealmID is -1, delete all values for the account id, else, insert values for the specific realmID - if (gmRealmID == -1) - LoginDatabase.PExecute("DELETE FROM account_access WHERE id = '%u'", targetAccountId); - else - LoginDatabase.PExecute("DELETE FROM account_access WHERE id = '%u' AND (RealmID = '%d' OR RealmID = '-1')", targetAccountId, realmID); - - if (gm != 0) - LoginDatabase.PExecute("INSERT INTO account_access VALUES ('%u','%d','%d')", targetAccountId, gm, realmID); - PSendSysMessage(LANG_YOU_CHANGE_SECURITY, targetAccountName.c_str(), gm); - return true; -} - -/// Set password for account -bool ChatHandler::HandleAccountSetPasswordCommand(const char *args) -{ - if (!*args) - return false; - - ///- Get the command line arguments - char *szAccount = strtok ((char*)args," "); - char *szPassword1 = strtok (NULL," "); - char *szPassword2 = strtok (NULL," "); - - if (!szAccount||!szPassword1 || !szPassword2) - return false; - - std::string account_name = szAccount; - if (!AccountMgr::normalizeString(account_name)) - { - PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); - SetSentErrorMessage(true); - return false; - } - - uint32 targetAccountId = accmgr.GetId(account_name); - if (!targetAccountId) - { - PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); - SetSentErrorMessage(true); - return false; - } - - /// can set password only for target with less security - /// This is also reject self apply in fact - if (HasLowerSecurityAccount (NULL,targetAccountId,true)) - return false; - - if (strcmp(szPassword1,szPassword2)) - { - SendSysMessage (LANG_NEW_PASSWORDS_NOT_MATCH); - SetSentErrorMessage (true); - return false; - } - - AccountOpResult result = accmgr.ChangePassword(targetAccountId, szPassword1); - - switch (result) - { - case AOR_OK: - SendSysMessage(LANG_COMMAND_PASSWORD); - break; - case AOR_NAME_NOT_EXIST: - PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); - SetSentErrorMessage(true); - return false; - case AOR_PASS_TOO_LONG: - SendSysMessage(LANG_PASSWORD_TOO_LONG); - SetSentErrorMessage(true); - return false; - default: - SendSysMessage(LANG_COMMAND_NOTCHANGEPASSWORD); - SetSentErrorMessage(true); - return false; - } - - return true; -} - -bool ChatHandler::HandleMaxSkillCommand(const char* /*args*/) -{ - Player* SelectedPlayer = getSelectedPlayer(); - if (!SelectedPlayer) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // each skills that have max skill value dependent from level seted to current level max skill value - SelectedPlayer->UpdateSkillsToMaxSkillsForLevel(); - return true; -} - -bool ChatHandler::HandleSetSkillCommand(const char *args) -{ - // number or [name] Shift-click form |color|Hskill:skill_id|h[name]|h|r - char* skill_p = extractKeyFromLink((char*)args,"Hskill"); - if (!skill_p) - return false; - - char *level_p = strtok (NULL, " "); - - if (!level_p) - return false; - - char *max_p = strtok (NULL, " "); - - int32 skill = atoi(skill_p); - if (skill <= 0) - { - PSendSysMessage(LANG_INVALID_SKILL_ID, skill); - SetSentErrorMessage(true); - return false; - } - - int32 level = atol (level_p); - - Player * target = getSelectedPlayer(); - if (!target) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - SkillLineEntry const* sl = sSkillLineStore.LookupEntry(skill); - if (!sl) - { - PSendSysMessage(LANG_INVALID_SKILL_ID, skill); - SetSentErrorMessage(true); - return false; - } - - std::string tNameLink = GetNameLink(target); - - if (!target->GetSkillValue(skill)) - { - PSendSysMessage(LANG_SET_SKILL_ERROR, tNameLink.c_str(), skill, sl->name[GetSessionDbcLocale()]); - SetSentErrorMessage(true); - return false; - } - - int32 max = max_p ? atol (max_p) : target->GetPureMaxSkillValue(skill); - - if (level <= 0 || level > max || max <= 0) - return false; - - target->SetSkill(skill, target->GetSkillStep(skill), level, max); - PSendSysMessage(LANG_SET_SKILL, skill, sl->name[GetSessionDbcLocale()], tNameLink.c_str(), level, max); - - return true; -} - -bool ChatHandler::HandleUnLearnCommand(const char *args) -{ - if (!*args) - return false; - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r - uint32 spell_id = extractSpellIdFromLink((char*)args); - if (!spell_id) - return false; - - char const* allStr = strtok(NULL," "); - bool allRanks = allStr ? (strncmp(allStr, "all", strlen(allStr)) == 0) : false; - - Player* target = getSelectedPlayer(); - if (!target) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if (allRanks) - spell_id = spellmgr.GetFirstSpellInChain (spell_id); - - if (target->HasSpell(spell_id)) - target->removeSpell(spell_id,false,!allRanks); - else - SendSysMessage(LANG_FORGET_SPELL); - - if (GetTalentSpellCost(spell_id)) - target->SendTalentsInfoData(false); - - return true; -} - -bool ChatHandler::HandleCooldownCommand(const char *args) -{ - Player* target = getSelectedPlayer(); - if (!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - std::string tNameLink = GetNameLink(target); - - if (!*args) - { - target->RemoveAllSpellCooldown(); - PSendSysMessage(LANG_REMOVEALL_COOLDOWN, tNameLink.c_str()); - } - else - { - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spell_id = extractSpellIdFromLink((char*)args); - if (!spell_id) - return false; - - if (!sSpellStore.LookupEntry(spell_id)) - { - PSendSysMessage(LANG_UNKNOWN_SPELL, target == m_session->GetPlayer() ? GetTrinityString(LANG_YOU) : tNameLink.c_str()); - SetSentErrorMessage(true); - return false; - } - - target->RemoveSpellCooldown(spell_id,true); - PSendSysMessage(LANG_REMOVE_COOLDOWN, spell_id, target == m_session->GetPlayer() ? GetTrinityString(LANG_YOU) : tNameLink.c_str()); - } - return true; -} - -bool ChatHandler::HandleLearnAllCommand(const char* /*args*/) -{ - static const char *allSpellList[] = - { - "3365", - "6233", - "6247", - "6246", - "6477", - "6478", - "22810", - "8386", - "21651", - "21652", - "522", - "7266", - "8597", - "2479", - "22027", - "6603", - "5019", - "133", - "168", - "227", - "5009", - "9078", - "668", - "203", - "20599", - "20600", - "81", - "20597", - "20598", - "20864", - "1459", - "5504", - "587", - "5143", - "118", - "5505", - "597", - "604", - "1449", - "1460", - "2855", - "1008", - "475", - "5506", - "1463", - "12824", - "8437", - "990", - "5145", - "8450", - "1461", - "759", - "8494", - "8455", - "8438", - "6127", - "8416", - "6129", - "8451", - "8495", - "8439", - "3552", - "8417", - "10138", - "12825", - "10169", - "10156", - "10144", - "10191", - "10201", - "10211", - "10053", - "10173", - "10139", - "10145", - "10192", - "10170", - "10202", - "10054", - "10174", - "10193", - "12826", - "2136", - "143", - "145", - "2137", - "2120", - "3140", - "543", - "2138", - "2948", - "8400", - "2121", - "8444", - "8412", - "8457", - "8401", - "8422", - "8445", - "8402", - "8413", - "8458", - "8423", - "8446", - "10148", - "10197", - "10205", - "10149", - "10215", - "10223", - "10206", - "10199", - "10150", - "10216", - "10207", - "10225", - "10151", - "116", - "205", - "7300", - "122", - "837", - "10", - "7301", - "7322", - "6143", - "120", - "865", - "8406", - "6141", - "7302", - "8461", - "8407", - "8492", - "8427", - "8408", - "6131", - "7320", - "10159", - "8462", - "10185", - "10179", - "10160", - "10180", - "10219", - "10186", - "10177", - "10230", - "10181", - "10161", - "10187", - "10220", - "2018", - "2663", - "12260", - "2660", - "3115", - "3326", - "2665", - "3116", - "2738", - "3293", - "2661", - "3319", - "2662", - "9983", - "8880", - "2737", - "2739", - "7408", - "3320", - "2666", - "3323", - "3324", - "3294", - "22723", - "23219", - "23220", - "23221", - "23228", - "23338", - "10788", - "10790", - "5611", - "5016", - "5609", - "2060", - "10963", - "10964", - "10965", - "22593", - "22594", - "596", - "996", - "499", - "768", - "17002", - "1448", - "1082", - "16979", - "1079", - "5215", - "20484", - "5221", - "15590", - "17007", - "6795", - "6807", - "5487", - "1446", - "1066", - "5421", - "3139", - "779", - "6811", - "6808", - "1445", - "5216", - "1737", - "5222", - "5217", - "1432", - "6812", - "9492", - "5210", - "3030", - "1441", - "783", - "6801", - "20739", - "8944", - "9491", - "22569", - "5226", - "6786", - "1433", - "8973", - "1828", - "9495", - "9006", - "6794", - "8993", - "5203", - "16914", - "6784", - "9635", - "22830", - "20722", - "9748", - "6790", - "9753", - "9493", - "9752", - "9831", - "9825", - "9822", - "5204", - "5401", - "22831", - "6793", - "9845", - "17401", - "9882", - "9868", - "20749", - "9893", - "9899", - "9895", - "9832", - "9902", - "9909", - "22832", - "9828", - "9851", - "9883", - "9869", - "17406", - "17402", - "9914", - "20750", - "9897", - "9848", - "3127", - "107", - "204", - "9116", - "2457", - "78", - "18848", - "331", - "403", - "2098", - "1752", - "11278", - "11288", - "11284", - "6461", - "2344", - "2345", - "6463", - "2346", - "2352", - "775", - "1434", - "1612", - "71", - "2468", - "2458", - "2467", - "7164", - "7178", - "7367", - "7376", - "7381", - "21156", - "5209", - "3029", - "5201", - "9849", - "9850", - "20719", - "22568", - "22827", - "22828", - "22829", - "6809", - "8972", - "9005", - "9823", - "9827", - "6783", - "9913", - "6785", - "6787", - "9866", - "9867", - "9894", - "9896", - "6800", - "8992", - "9829", - "9830", - "780", - "769", - "6749", - "6750", - "9755", - "9754", - "9908", - "20745", - "20742", - "20747", - "20748", - "9746", - "9745", - "9880", - "9881", - "5391", - "842", - "3025", - "3031", - "3287", - "3329", - "1945", - "3559", - "4933", - "4934", - "4935", - "4936", - "5142", - "5390", - "5392", - "5404", - "5420", - "6405", - "7293", - "7965", - "8041", - "8153", - "9033", - "9034", - //"9036", problems with ghost state - "16421", - "21653", - "22660", - "5225", - "9846", - "2426", - "5916", - "6634", - //"6718", phasing stealth, annoying for learn all case. - "6719", - "8822", - "9591", - "9590", - "10032", - "17746", - "17747", - "8203", - "11392", - "12495", - "16380", - "23452", - "4079", - "4996", - "4997", - "4998", - "4999", - "5000", - "6348", - "6349", - "6481", - "6482", - "6483", - "6484", - "11362", - "11410", - "11409", - "12510", - "12509", - "12885", - "13142", - "21463", - "23460", - "11421", - "11416", - "11418", - "1851", - "10059", - "11423", - "11417", - "11422", - "11419", - "11424", - "11420", - "27", - "31", - "33", - "34", - "35", - "15125", - "21127", - "22950", - "1180", - "201", - "12593", - "16770", - "6057", - "12051", - "18468", - "12606", - "12605", - "18466", - "12502", - "12043", - "15060", - "12042", - "12341", - "12848", - "12344", - "12353", - "18460", - "11366", - "12350", - "12352", - "13043", - "11368", - "11113", - "12400", - "11129", - "16766", - "12573", - "12580", - "12472", - "12953", - "12488", - "11189", - "12985", - "12519", - "16758", - "11958", - "12490", - "11426", - "3565", - "3562", - "18960", - "3567", - "3561", - "3566", - "3563", - "1953", - "2139", - "12505", - "13018", - "12522", - "12523", - "5146", - "5144", - "5148", - "8419", - "8418", - "10213", - "10212", - "10157", - "12524", - "13019", - "12525", - "13020", - "12526", - "13021", - "18809", - "13031", - "13032", - "13033", - "4036", - "3920", - "3919", - "3918", - "7430", - "3922", - "3923", - "7411", - "7418", - "7421", - "13262", - "7412", - "7415", - "7413", - "7416", - "13920", - "13921", - "7745", - "7779", - "7428", - "7457", - "7857", - "7748", - "7426", - "13421", - "7454", - "13378", - "7788", - "14807", - "14293", - "7795", - "6296", - "20608", - "755", - "444", - "427", - "428", - "442", - "447", - "3578", - "3581", - "19027", - "3580", - "665", - "3579", - "3577", - "6755", - "3576", - "2575", - "2577", - "2578", - "2579", - "2580", - "2656", - "2657", - "2576", - "3564", - "10248", - "8388", - "2659", - "14891", - "3308", - "3307", - "10097", - "2658", - "3569", - "16153", - "3304", - "10098", - "4037", - "3929", - "3931", - "3926", - "3924", - "3930", - "3977", - "3925", - "136", - "228", - "5487", - "43", - "202", - "0" - }; - - int loop = 0; - while (strcmp(allSpellList[loop], "0")) - { - uint32 spell = atol((char*)allSpellList[loop++]); - - if (m_session->GetPlayer()->HasSpell(spell)) - continue; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); - if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) - { - PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); - continue; - } - - m_session->GetPlayer()->learnSpell(spell, false); - } - - SendSysMessage(LANG_COMMAND_LEARN_MANY_SPELLS); - - return true; -} - -bool ChatHandler::HandleLearnAllGMCommand(const char* /*args*/) -{ - static const char *gmSpellList[] = - { - "24347", // Become A Fish, No Breath Bar - "35132", // Visual Boom - "38488", // Attack 4000-8000 AOE - "38795", // Attack 2000 AOE + Slow Down 90% - "15712", // Attack 200 - "1852", // GM Spell Silence - "31899", // Kill - "31924", // Kill - "29878", // Kill My Self - "26644", // More Kill - - "28550", //Invisible 24 - "23452", //Invisible + Target - "0" - }; - - uint16 gmSpellIter = 0; - while (strcmp(gmSpellList[gmSpellIter], "0")) - { - uint32 spell = atol((char*)gmSpellList[gmSpellIter++]); - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); - if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) - { - PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); - continue; - } - - m_session->GetPlayer()->learnSpell(spell, false); - } - - SendSysMessage(LANG_LEARNING_GM_SKILLS); - return true; -} - -bool ChatHandler::HandleLearnAllMyClassCommand(const char* /*args*/) -{ - HandleLearnAllMySpellsCommand(""); - HandleLearnAllMyTalentsCommand(""); - return true; -} - -bool ChatHandler::HandleLearnAllMySpellsCommand(const char* /*args*/) -{ - ChrClassesEntry const* clsEntry = sChrClassesStore.LookupEntry(m_session->GetPlayer()->getClass()); - if (!clsEntry) - return true; - uint32 family = clsEntry->spellfamily; - - for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i) - { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(i); - if (!spellInfo) - continue; - - // skip server-side/triggered spells - if (spellInfo->spellLevel == 0) - continue; - - // skip wrong class/race skills - if (!m_session->GetPlayer()->IsSpellFitByClassAndRace(spellInfo->Id)) - continue; - - // skip other spell families - if (spellInfo->SpellFamilyName != family) - continue; - - // skip spells with first rank learned as talent (and all talents then also) - uint32 first_rank = spellmgr.GetFirstSpellInChain(spellInfo->Id); - if (GetTalentSpellCost(first_rank) > 0) - continue; - - // skip broken spells - if (!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) - continue; - - m_session->GetPlayer()->learnSpell(i, false); - } - - SendSysMessage(LANG_COMMAND_LEARN_CLASS_SPELLS); - return true; -} - -bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/) -{ - Player* player = m_session->GetPlayer(); - uint32 classMask = player->getClassMask(); - - for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i) - { - TalentEntry const *talentInfo = sTalentStore.LookupEntry(i); - if (!talentInfo) - continue; - - TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab); - if (!talentTabInfo) - continue; - - if ((classMask & talentTabInfo->ClassMask) == 0) - continue; - - // search highest talent rank - uint32 spellId = 0; - for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank) - { - if (talentInfo->RankID[rank] != 0) - { - spellId = talentInfo->RankID[rank]; - break; - } - } - - if (!spellId) // ??? none spells in talent - continue; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId); - if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) - continue; - - // learn highest rank of talent and learn all non-talent spell ranks (recursive by tree) - player->learnSpellHighRank(spellId); - player->AddTalent(spellId, player->GetActiveSpec(), true); - } - - player->SetFreeTalentPoints(0); - - SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS); - return true; -} - -bool ChatHandler::HandleLearnAllMyPetTalentsCommand(const char* /*args*/) -{ - Player* player = m_session->GetPlayer(); - - Pet* pet = player->GetPet(); - if (!pet) - { - SendSysMessage(LANG_NO_PET_FOUND); - SetSentErrorMessage(true); - return false; - } - - CreatureInfo const *ci = pet->GetCreatureInfo(); - if (!ci) - { - SendSysMessage(LANG_WRONG_PET_TYPE); - SetSentErrorMessage(true); - return false; - } - - CreatureFamilyEntry const *pet_family = sCreatureFamilyStore.LookupEntry(ci->family); - if (!pet_family) - { - SendSysMessage(LANG_WRONG_PET_TYPE); - SetSentErrorMessage(true); - return false; - } - - if (pet_family->petTalentType < 0) // not hunter pet - { - SendSysMessage(LANG_WRONG_PET_TYPE); - SetSentErrorMessage(true); - return false; - } - - for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i) - { - TalentEntry const *talentInfo = sTalentStore.LookupEntry(i); - if (!talentInfo) - continue; - - TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab); - if (!talentTabInfo) - continue; - - // prevent learn talent for different family (cheating) - if (((1 << pet_family->petTalentType) & talentTabInfo->petTalentMask) == 0) - continue; - - // search highest talent rank - uint32 spellid = 0; - - for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank) - { - if (talentInfo->RankID[rank] != 0) - { - spellid = talentInfo->RankID[rank]; - break; - } - } - - if (!spellid) // ??? none spells in talent - continue; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid); - if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) - continue; - - // learn highest rank of talent and learn all non-talent spell ranks (recursive by tree) - pet->learnSpellHighRank(spellid); - } - - pet->SetFreeTalentPoints(0); - - SendSysMessage(LANG_COMMAND_LEARN_PET_TALENTS); - return true; -} - -bool ChatHandler::HandleLearnAllLangCommand(const char* /*args*/) -{ - // skipping UNIVERSAL language (0) - for (uint8 i = 1; i < LANGUAGES_COUNT; ++i) - m_session->GetPlayer()->learnSpell(lang_description[i].spell_id, false); - - SendSysMessage(LANG_COMMAND_LEARN_ALL_LANG); - return true; -} - -bool ChatHandler::HandleLearnAllDefaultCommand(const char *args) -{ - Player* target; - if (!extractPlayerTarget((char*)args,&target)) - return false; - - target->learnDefaultSpells(); - target->learnQuestRewardedSpells(); - - PSendSysMessage(LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST,GetNameLink(target).c_str()); - return true; -} - -bool ChatHandler::HandleLearnCommand(const char *args) -{ - Player* targetPlayer = getSelectedPlayer(); - - if (!targetPlayer) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spell = extractSpellIdFromLink((char*)args); - if (!spell || !sSpellStore.LookupEntry(spell)) - return false; - - char const* allStr = strtok(NULL," "); - bool allRanks = allStr ? (strncmp(allStr, "all", strlen(allStr)) == 0) : false; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); - if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) - { - PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); - SetSentErrorMessage(true); - return false; - } - - if (!allRanks && targetPlayer->HasSpell(spell)) - { - if (targetPlayer == m_session->GetPlayer()) - SendSysMessage(LANG_YOU_KNOWN_SPELL); - else - PSendSysMessage(LANG_TARGET_KNOWN_SPELL,GetNameLink(targetPlayer).c_str()); - SetSentErrorMessage(true); - return false; - } - - if (allRanks) - targetPlayer->learnSpellHighRank(spell); - else - targetPlayer->learnSpell(spell, false); - - uint32 first_spell = spellmgr.GetFirstSpellInChain(spell); - if (GetTalentSpellCost(first_spell)) - targetPlayer->SendTalentsInfoData(false); - - return true; -} - -bool ChatHandler::HandleAddItemCommand(const char *args) -{ - if (!*args) - return false; - - uint32 itemId = 0; - - if (args[0] == '[') // [name] manual form - { - char* citemName = strtok((char*)args, "]"); - - if (citemName && citemName[0]) - { - std::string itemName = citemName+1; - WorldDatabase.escape_string(itemName); - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT entry FROM item_template WHERE name = '%s'", itemName.c_str()); - if (!result) - { - PSendSysMessage(LANG_COMMAND_COULDNOTFIND, citemName+1); - SetSentErrorMessage(true); - return false; - } - itemId = result->Fetch()->GetUInt16(); - } - else - return false; - } - else // item_id or [name] Shift-click form |color|Hitem:item_id:0:0:0|h[name]|h|r - { - char* cId = extractKeyFromLink((char*)args,"Hitem"); - if (!cId) - return false; - itemId = atol(cId); - } - - char* ccount = strtok(NULL, " "); - - int32 count = 1; - - if (ccount) - count = strtol(ccount, NULL, 10); - - if (count == 0) - count = 1; - - Player* pl = m_session->GetPlayer(); - Player* plTarget = getSelectedPlayer(); - if (!plTarget) - plTarget = pl; - - sLog.outDetail(GetTrinityString(LANG_ADDITEM), itemId, count); - - ItemPrototype const *pProto = objmgr.GetItemPrototype(itemId); - if (!pProto) - { - PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, itemId); - SetSentErrorMessage(true); - return false; - } - - //Subtract - if (count < 0) - { - plTarget->DestroyItemCount(itemId, -count, true, false); - PSendSysMessage(LANG_REMOVEITEM, itemId, -count, GetNameLink(plTarget).c_str()); - return true; - } - - //Adding items - uint32 noSpaceForCount = 0; - - // check space and find places - ItemPosCountVec dest; - uint8 msg = plTarget->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, count, &noSpaceForCount); - if (msg != EQUIP_ERR_OK) // convert to possible store amount - count -= noSpaceForCount; - - if (count == 0 || dest.empty()) // can't add any - { - PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemId, noSpaceForCount); - SetSentErrorMessage(true); - return false; - } - - Item* item = plTarget->StoreNewItem(dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId)); - - // remove binding (let GM give it to another player later) - if (pl == plTarget) - for (ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ++itr) - if (Item* item1 = pl->GetItemByPos(itr->pos)) - item1->SetBinding(false); - - if (count > 0 && item) - { - pl->SendNewItem(item,count,false,true); - if (pl != plTarget) - plTarget->SendNewItem(item,count,true,false); - } - - if (noSpaceForCount > 0) - PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemId, noSpaceForCount); - - return true; -} - -bool ChatHandler::HandleAddItemSetCommand(const char *args) -{ - if (!*args) - return false; - - char* cId = extractKeyFromLink((char*)args,"Hitemset"); // number or [name] Shift-click form |color|Hitemset:itemset_id|h[name]|h|r - if (!cId) - return false; - - uint32 itemsetId = atol(cId); - - // prevent generation all items with itemset field value '0' - if (itemsetId == 0) - { - PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND,itemsetId); - SetSentErrorMessage(true); - return false; - } - - Player* pl = m_session->GetPlayer(); - Player* plTarget = getSelectedPlayer(); - if (!plTarget) - plTarget = pl; - - sLog.outDetail(GetTrinityString(LANG_ADDITEMSET), itemsetId); - - bool found = false; - for (uint32 id = 0; id < sItemStorage.MaxEntry; id++) - { - ItemPrototype const *pProto = sItemStorage.LookupEntry(id); - if (!pProto) - continue; - - if (pProto->ItemSet == itemsetId) - { - found = true; - ItemPosCountVec dest; - uint8 msg = plTarget->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, pProto->ItemId, 1); - if (msg == EQUIP_ERR_OK) - { - Item* item = plTarget->StoreNewItem(dest, pProto->ItemId, true); - - // remove binding (let GM give it to another player later) - if (pl == plTarget) - item->SetBinding(false); - - pl->SendNewItem(item,1,false,true); - if (pl != plTarget) - plTarget->SendNewItem(item,1,true,false); - } - else - { - pl->SendEquipError(msg, NULL, NULL); - PSendSysMessage(LANG_ITEM_CANNOT_CREATE, pProto->ItemId, 1); - } - } - } - - if (!found) - { - PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND,itemsetId); - - SetSentErrorMessage(true); - return false; - } - - return true; -} - -bool ChatHandler::HandleListItemCommand(const char *args) -{ - if (!*args) - return false; - - char* cId = extractKeyFromLink((char*)args,"Hitem"); - if (!cId) - return false; - - uint32 item_id = atol(cId); - if (!item_id) - { - PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, item_id); - SetSentErrorMessage(true); - return false; - } - - ItemPrototype const* itemProto = objmgr.GetItemPrototype(item_id); - if (!itemProto) - { - PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, item_id); - SetSentErrorMessage(true); - return false; - } - - char* c_count = strtok(NULL, " "); - int count = c_count ? atol(c_count) : 10; - - if (count < 0) - return false; - - QueryResult_AutoPtr result; - - // inventory case - uint32 inv_count = 0; - result=CharacterDatabase.PQuery("SELECT COUNT(item_template) FROM character_inventory WHERE item_template='%u'",item_id); - if (result) - inv_count = (*result)[0].GetUInt32(); - - result=CharacterDatabase.PQuery( - // 0 1 2 3 4 5 - "SELECT ci.item, cibag.slot AS bag, ci.slot, ci.guid, characters.account,characters.name " - "FROM character_inventory AS ci LEFT JOIN character_inventory AS cibag ON (cibag.item=ci.bag),characters " - "WHERE ci.item_template='%u' AND ci.guid = characters.guid LIMIT %u ", - item_id,uint32(count)); - - if (result) - { - do - { - Field *fields = result->Fetch(); - uint32 item_guid = fields[0].GetUInt32(); - uint32 item_bag = fields[1].GetUInt32(); - uint32 item_slot = fields[2].GetUInt32(); - uint32 owner_guid = fields[3].GetUInt32(); - uint32 owner_acc = fields[4].GetUInt32(); - std::string owner_name = fields[5].GetCppString(); - - char const* item_pos = 0; - if (Player::IsEquipmentPos(item_bag,item_slot)) - item_pos = "[equipped]"; - else if (Player::IsInventoryPos(item_bag,item_slot)) - item_pos = "[in inventory]"; - else if (Player::IsBankPos(item_bag,item_slot)) - item_pos = "[in bank]"; - else - item_pos = ""; - - PSendSysMessage(LANG_ITEMLIST_SLOT, - item_guid,owner_name.c_str(),owner_guid,owner_acc,item_pos); - } while (result->NextRow()); - - int64 res_count = result->GetRowCount(); - - if (count > res_count) - count-=res_count; - else if (count) - count = 0; - } - - // mail case - uint32 mail_count = 0; - result=CharacterDatabase.PQuery("SELECT COUNT(item_template) FROM mail_items WHERE item_template='%u'", item_id); - if (result) - mail_count = (*result)[0].GetUInt32(); - - if (count > 0) - { - result=CharacterDatabase.PQuery( - // 0 1 2 3 4 5 6 - "SELECT mail_items.item_guid, mail.sender, mail.receiver, char_s.account, char_s.name, char_r.account, char_r.name " - "FROM mail,mail_items,characters as char_s,characters as char_r " - "WHERE mail_items.item_template='%u' AND char_s.guid = mail.sender AND char_r.guid = mail.receiver AND mail.id=mail_items.mail_id LIMIT %u", - item_id,uint32(count)); - } - else - result = QueryResult_AutoPtr(NULL); - - if (result) - { - do - { - Field *fields = result->Fetch(); - uint32 item_guid = fields[0].GetUInt32(); - uint32 item_s = fields[1].GetUInt32(); - uint32 item_r = fields[2].GetUInt32(); - uint32 item_s_acc = fields[3].GetUInt32(); - std::string item_s_name = fields[4].GetCppString(); - uint32 item_r_acc = fields[5].GetUInt32(); - std::string item_r_name = fields[6].GetCppString(); - - char const* item_pos = "[in mail]"; - - PSendSysMessage(LANG_ITEMLIST_MAIL, - item_guid,item_s_name.c_str(),item_s,item_s_acc,item_r_name.c_str(),item_r,item_r_acc,item_pos); - } while (result->NextRow()); - - int64 res_count = result->GetRowCount(); - - if (count > res_count) - count-=res_count; - else if (count) - count = 0; - } - - // auction case - uint32 auc_count = 0; - result=CharacterDatabase.PQuery("SELECT COUNT(item_template) FROM auctionhouse WHERE item_template='%u'",item_id); - if (result) - auc_count = (*result)[0].GetUInt32(); - - if (count > 0) - { - result=CharacterDatabase.PQuery( - // 0 1 2 3 - "SELECT auctionhouse.itemguid, auctionhouse.itemowner, characters.account, characters.name " - "FROM auctionhouse,characters WHERE auctionhouse.item_template='%u' AND characters.guid = auctionhouse.itemowner LIMIT %u", - item_id,uint32(count)); - } - else - result = QueryResult_AutoPtr(NULL); - - if (result) - { - do - { - Field *fields = result->Fetch(); - uint32 item_guid = fields[0].GetUInt32(); - uint32 owner = fields[1].GetUInt32(); - uint32 owner_acc = fields[2].GetUInt32(); - std::string owner_name = fields[3].GetCppString(); - - char const* item_pos = "[in auction]"; - - PSendSysMessage(LANG_ITEMLIST_AUCTION, item_guid, owner_name.c_str(), owner, owner_acc,item_pos); - } while (result->NextRow()); - } - - // guild bank case - uint32 guild_count = 0; - result=CharacterDatabase.PQuery("SELECT COUNT(item_entry) FROM guild_bank_item WHERE item_entry='%u'",item_id); - if (result) - guild_count = (*result)[0].GetUInt32(); - - result=CharacterDatabase.PQuery( - // 0 1 2 - "SELECT gi.item_guid, gi.guildid, guild.name " - "FROM guild_bank_item AS gi, guild WHERE gi.item_entry='%u' AND gi.guildid = guild.guildid LIMIT %u ", - item_id,uint32(count)); - - if (result) - { - do - { - Field *fields = result->Fetch(); - uint32 item_guid = fields[0].GetUInt32(); - uint32 guild_guid = fields[1].GetUInt32(); - std::string guild_name = fields[2].GetCppString(); - - char const* item_pos = "[in guild bank]"; - - PSendSysMessage(LANG_ITEMLIST_GUILD,item_guid,guild_name.c_str(),guild_guid,item_pos); - } while (result->NextRow()); - - int64 res_count = result->GetRowCount(); - - if (count > res_count) - count-=res_count; - else if (count) - count = 0; - } - - if (inv_count+mail_count+auc_count+guild_count == 0) - { - SendSysMessage(LANG_COMMAND_NOITEMFOUND); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_COMMAND_LISTITEMMESSAGE,item_id,inv_count+mail_count+auc_count+guild_count,inv_count,mail_count,auc_count,guild_count); - - return true; -} - -bool ChatHandler::HandleListObjectCommand(const char *args) -{ - if (!*args) - return false; - - // number or [name] Shift-click form |color|Hgameobject_entry:go_id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject_entry"); - if (!cId) - return false; - - uint32 go_id = atol(cId); - if (!go_id) - { - PSendSysMessage(LANG_COMMAND_LISTOBJINVALIDID, go_id); - SetSentErrorMessage(true); - return false; - } - - GameObjectInfo const * gInfo = objmgr.GetGameObjectInfo(go_id); - if (!gInfo) - { - PSendSysMessage(LANG_COMMAND_LISTOBJINVALIDID, go_id); - SetSentErrorMessage(true); - return false; - } - - char* c_count = strtok(NULL, " "); - int count = c_count ? atol(c_count) : 10; - - if (count < 0) - return false; - - QueryResult_AutoPtr result; - - uint32 obj_count = 0; - result=WorldDatabase.PQuery("SELECT COUNT(guid) FROM gameobject WHERE id='%u'",go_id); - if (result) - obj_count = (*result)[0].GetUInt32(); - - if (m_session) - { - Player* pl = m_session->GetPlayer(); - result = WorldDatabase.PQuery("SELECT guid, position_x, position_y, position_z, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM gameobject WHERE id = '%u' ORDER BY order_ ASC LIMIT %u", - pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(),go_id,uint32(count)); - } - else - result = WorldDatabase.PQuery("SELECT guid, position_x, position_y, position_z, map FROM gameobject WHERE id = '%u' LIMIT %u", - go_id,uint32(count)); - - if (result) - { - do - { - Field *fields = result->Fetch(); - uint32 guid = fields[0].GetUInt32(); - float x = fields[1].GetFloat(); - float y = fields[2].GetFloat(); - float z = fields[3].GetFloat(); - int mapid = fields[4].GetUInt16(); - - if (m_session) - PSendSysMessage(LANG_GO_LIST_CHAT, guid, guid, gInfo->name, x, y, z, mapid); - else - PSendSysMessage(LANG_GO_LIST_CONSOLE, guid, gInfo->name, x, y, z, mapid); - } while (result->NextRow()); - } - - PSendSysMessage(LANG_COMMAND_LISTOBJMESSAGE,go_id,obj_count); - return true; -} - -bool ChatHandler::HandleGameObjectStateCommand(const char *args) -{ - // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args, "Hgameobject"); - if (!cId) - return false; - - uint32 lowguid = atoi(cId); - if (!lowguid) - return false; - - GameObject* gobj = NULL; - - if (GameObjectData const* goData = objmgr.GetGOData(lowguid)) - gobj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid, goData->id); - - if (!gobj) - { - PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - char* ctype = strtok(NULL, " "); - if (!ctype) - return false; - - int32 type = atoi(ctype); - if (type < 0) - { - if (type == -1) - gobj->SendObjectDeSpawnAnim(gobj->GetGUID()); - else if (type == -2) - { - return false; - } - return true; - } - - char* cstate = strtok(NULL, " "); - if (!cstate) - return false; - - int32 state = atoi(cstate); - - if (type < 4) - gobj->SetByteValue(GAMEOBJECT_BYTES_1, type, state); - else if (type == 4) - { - WorldPacket data(SMSG_GAMEOBJECT_CUSTOM_ANIM,8+4); - data << gobj->GetGUID(); - data << (uint32)(state); - gobj->SendMessageToSet(&data, true); - } - PSendSysMessage("Set gobject type %d state %d", type, state); - - return true; -} - -bool ChatHandler::HandleListCreatureCommand(const char *args) -{ - if (!*args) - return false; - - // number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hcreature_entry"); - if (!cId) - return false; - - uint32 cr_id = atol(cId); - if (!cr_id) - { - PSendSysMessage(LANG_COMMAND_INVALIDCREATUREID, cr_id); - SetSentErrorMessage(true); - return false; - } - - CreatureInfo const* cInfo = objmgr.GetCreatureTemplate(cr_id); - if (!cInfo) - { - PSendSysMessage(LANG_COMMAND_INVALIDCREATUREID, cr_id); - SetSentErrorMessage(true); - return false; - } - - char* c_count = strtok(NULL, " "); - int count = c_count ? atol(c_count) : 10; - - if (count < 0) - return false; - - QueryResult_AutoPtr result; - - uint32 cr_count = 0; - result=WorldDatabase.PQuery("SELECT COUNT(guid) FROM creature WHERE id='%u'",cr_id); - if (result) - cr_count = (*result)[0].GetUInt32(); - - if (m_session) - { - Player* pl = m_session->GetPlayer(); - result = WorldDatabase.PQuery("SELECT guid, position_x, position_y, position_z, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM creature WHERE id = '%u' ORDER BY order_ ASC LIMIT %u", - pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), cr_id,uint32(count)); - } - else - result = WorldDatabase.PQuery("SELECT guid, position_x, position_y, position_z, map FROM creature WHERE id = '%u' LIMIT %u", - cr_id,uint32(count)); - - if (result) - { - do - { - Field *fields = result->Fetch(); - uint32 guid = fields[0].GetUInt32(); - float x = fields[1].GetFloat(); - float y = fields[2].GetFloat(); - float z = fields[3].GetFloat(); - int mapid = fields[4].GetUInt16(); - - if (m_session) - PSendSysMessage(LANG_CREATURE_LIST_CHAT, guid, guid, cInfo->Name, x, y, z, mapid); - else - PSendSysMessage(LANG_CREATURE_LIST_CONSOLE, guid, cInfo->Name, x, y, z, mapid); - } while (result->NextRow()); - } - - PSendSysMessage(LANG_COMMAND_LISTCREATUREMESSAGE,cr_id,cr_count); - return true; -} - -bool ChatHandler::HandleLookupItemCommand(const char *args) -{ - if (!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - // converting string that we try to find to lower case - if (!Utf8toWStr(namepart,wnamepart)) - return false; - - wstrToLower(wnamepart); - - bool found = false; - - // Search in `item_template` - for (uint32 id = 0; id < sItemStorage.MaxEntry; id++) - { - ItemPrototype const *pProto = sItemStorage.LookupEntry(id); - if (!pProto) - continue; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId); - if (il) - { - if (il->Name.size() > loc_idx && !il->Name[loc_idx].empty()) - { - std::string name = il->Name[loc_idx]; - - if (Utf8FitTo(name, wnamepart)) - { - if (m_session) - PSendSysMessage(LANG_ITEM_LIST_CHAT, id, id, name.c_str()); - else - PSendSysMessage(LANG_ITEM_LIST_CONSOLE, id, name.c_str()); - - if (!found) - found = true; - - continue; - } - } - } - } - - std::string name = pProto->Name1; - if (name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - { - if (m_session) - PSendSysMessage(LANG_ITEM_LIST_CHAT, id, id, name.c_str()); - else - PSendSysMessage(LANG_ITEM_LIST_CONSOLE, id, name.c_str()); - - if (!found) - found = true; - } - } - - if (!found) - SendSysMessage(LANG_COMMAND_NOITEMFOUND); - - return true; -} - -bool ChatHandler::HandleLookupItemSetCommand(const char *args) -{ - if (!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - if (!Utf8toWStr(namepart,wnamepart)) - return false; - - // converting string that we try to find to lower case - wstrToLower(wnamepart); - - bool found = false; - - // Search in ItemSet.dbc - for (uint32 id = 0; id < sItemSetStore.GetNumRows(); id++) - { - ItemSetEntry const *set = sItemSetStore.LookupEntry(id); - if (set) - { - int loc = GetSessionDbcLocale(); - std::string name = set->name[loc]; - if (name.empty()) - continue; - - if (!Utf8FitTo(name, wnamepart)) - { - loc = 0; - for (; loc < MAX_LOCALE; ++loc) - { - if (loc == GetSessionDbcLocale()) - continue; - - name = set->name[loc]; - if (name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - break; - } - } - - if (loc < MAX_LOCALE) - { - // send item set in "id - [namedlink locale]" format - if (m_session) - PSendSysMessage(LANG_ITEMSET_LIST_CHAT,id,id,name.c_str(),localeNames[loc]); - else - PSendSysMessage(LANG_ITEMSET_LIST_CONSOLE,id,name.c_str(),localeNames[loc]); - - if (!found) - found = true; - } - } - } - if (!found) - SendSysMessage(LANG_COMMAND_NOITEMSETFOUND); - return true; -} - -bool ChatHandler::HandleLookupSkillCommand(const char *args) -{ - if (!*args) - return false; - - // can be NULL in console call - Player* target = getSelectedPlayer(); - - std::string namepart = args; - std::wstring wnamepart; - - if (!Utf8toWStr(namepart,wnamepart)) - return false; - - // converting string that we try to find to lower case - wstrToLower(wnamepart); - - bool found = false; - - // Search in SkillLine.dbc - for (uint32 id = 0; id < sSkillLineStore.GetNumRows(); id++) - { - SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(id); - if (skillInfo) - { - int loc = GetSessionDbcLocale(); - std::string name = skillInfo->name[loc]; - if (name.empty()) - continue; - - if (!Utf8FitTo(name, wnamepart)) - { - loc = 0; - for (; loc < MAX_LOCALE; ++loc) - { - if (loc == GetSessionDbcLocale()) - continue; - - name = skillInfo->name[loc]; - if (name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - break; - } - } - - if (loc < MAX_LOCALE) - { - char valStr[50] = ""; - char const* knownStr = ""; - if (target && target->HasSkill(id)) - { - knownStr = GetTrinityString(LANG_KNOWN); - uint32 curValue = target->GetPureSkillValue(id); - uint32 maxValue = target->GetPureMaxSkillValue(id); - uint32 permValue = target->GetSkillPermBonusValue(id); - uint32 tempValue = target->GetSkillTempBonusValue(id); - - char const* valFormat = GetTrinityString(LANG_SKILL_VALUES); - snprintf(valStr,50,valFormat,curValue,maxValue,permValue,tempValue); - } - - // send skill in "id - [namedlink locale]" format - if (m_session) - PSendSysMessage(LANG_SKILL_LIST_CHAT,id,id,name.c_str(),localeNames[loc],knownStr,valStr); - else - PSendSysMessage(LANG_SKILL_LIST_CONSOLE,id,name.c_str(),localeNames[loc],knownStr,valStr); - - if (!found) - found = true; - } - } - } - if (!found) - SendSysMessage(LANG_COMMAND_NOSKILLFOUND); - return true; -} - -bool ChatHandler::HandleLookupSpellCommand(const char *args) -{ - if (!*args) - return false; - - // can be NULL at console call - Player* target = getSelectedPlayer(); - - std::string namepart = args; - std::wstring wnamepart; - - if (!Utf8toWStr(namepart,wnamepart)) - return false; - - // converting string that we try to find to lower case - wstrToLower(wnamepart); - - bool found = false; - - // Search in Spell.dbc - for (uint32 id = 0; id < sSpellStore.GetNumRows(); id++) - { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(id); - if (spellInfo) - { - int loc = GetSessionDbcLocale(); - std::string name = spellInfo->SpellName[loc]; - if (name.empty()) - continue; - - if (!Utf8FitTo(name, wnamepart)) - { - loc = 0; - for (; loc < MAX_LOCALE; ++loc) - { - if (loc == GetSessionDbcLocale()) - continue; - - name = spellInfo->SpellName[loc]; - if (name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - break; - } - } - - if (loc < MAX_LOCALE) - { - bool known = target && target->HasSpell(id); - bool learn = (spellInfo->Effect[0] == SPELL_EFFECT_LEARN_SPELL); - - uint32 talentCost = GetTalentSpellCost(id); - - bool talent = (talentCost > 0); - bool passive = IsPassiveSpell(id); - bool active = target && target->HasAura(id); - - // unit32 used to prevent interpreting uint8 as char at output - // find rank of learned spell for learning spell, or talent rank - uint32 rank = talentCost ? talentCost : spellmgr.GetSpellRank(learn ? spellInfo->EffectTriggerSpell[0] : id); - - // send spell in "id - [name, rank N] [talent] [passive] [learn] [known]" format - std::ostringstream ss; - if (m_session) - ss << id << " - |cffffffff|Hspell:" << id << "|h[" << name; - else - ss << id << " - " << name; - - // include rank in link name - if (rank) - ss << GetTrinityString(LANG_SPELL_RANK) << rank; - - if (m_session) - ss << " " << localeNames[loc] << "]|h|r"; - else - ss << " " << localeNames[loc]; - - if (talent) - ss << GetTrinityString(LANG_TALENT); - if (passive) - ss << GetTrinityString(LANG_PASSIVE); - if (learn) - ss << GetTrinityString(LANG_LEARN); - if (known) - ss << GetTrinityString(LANG_KNOWN); - if (active) - ss << GetTrinityString(LANG_ACTIVE); - - SendSysMessage(ss.str().c_str()); - - if (!found) - found = true; - } - } - } - if (!found) - SendSysMessage(LANG_COMMAND_NOSPELLFOUND); - return true; -} - -bool ChatHandler::HandleLookupQuestCommand(const char *args) -{ - if (!*args) - return false; - - // can be NULL at console call - Player* target = getSelectedPlayer(); - - std::string namepart = args; - std::wstring wnamepart; - - // converting string that we try to find to lower case - if (!Utf8toWStr(namepart,wnamepart)) - return false; - - wstrToLower(wnamepart); - - bool found = false; - - ObjectMgr::QuestMap const& qTemplates = objmgr.GetQuestTemplates(); - for (ObjectMgr::QuestMap::const_iterator iter = qTemplates.begin(); iter != qTemplates.end(); ++iter) - { - Quest * qinfo = iter->second; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - QuestLocale const *il = objmgr.GetQuestLocale(qinfo->GetQuestId()); - if (il) - { - if (il->Title.size() > loc_idx && !il->Title[loc_idx].empty()) - { - std::string title = il->Title[loc_idx]; - - if (Utf8FitTo(title, wnamepart)) - { - char const* statusStr = ""; - - if (target) - { - QuestStatus status = target->GetQuestStatus(qinfo->GetQuestId()); - - if (status == QUEST_STATUS_COMPLETE) - { - if (target->GetQuestRewardStatus(qinfo->GetQuestId())) - statusStr = GetTrinityString(LANG_COMMAND_QUEST_REWARDED); - else - statusStr = GetTrinityString(LANG_COMMAND_QUEST_COMPLETE); - } - else if (status == QUEST_STATUS_INCOMPLETE) - statusStr = GetTrinityString(LANG_COMMAND_QUEST_ACTIVE); - } - - if (m_session) - PSendSysMessage(LANG_QUEST_LIST_CHAT,qinfo->GetQuestId(),qinfo->GetQuestId(),qinfo->GetQuestLevel(),title.c_str(),statusStr); - else - PSendSysMessage(LANG_QUEST_LIST_CONSOLE,qinfo->GetQuestId(),title.c_str(),statusStr); - - if (!found) - found = true; - - continue; - } - } - } - } - - std::string title = qinfo->GetTitle(); - if (title.empty()) - continue; - - if (Utf8FitTo(title, wnamepart)) - { - char const* statusStr = ""; - - if (target) - { - QuestStatus status = target->GetQuestStatus(qinfo->GetQuestId()); - - if (status == QUEST_STATUS_COMPLETE) - { - if (target->GetQuestRewardStatus(qinfo->GetQuestId())) - statusStr = GetTrinityString(LANG_COMMAND_QUEST_REWARDED); - else - statusStr = GetTrinityString(LANG_COMMAND_QUEST_COMPLETE); - } - else if (status == QUEST_STATUS_INCOMPLETE) - statusStr = GetTrinityString(LANG_COMMAND_QUEST_ACTIVE); - } - - if (m_session) - PSendSysMessage(LANG_QUEST_LIST_CHAT,qinfo->GetQuestId(),qinfo->GetQuestId(),qinfo->GetQuestLevel(),title.c_str(),statusStr); - else - PSendSysMessage(LANG_QUEST_LIST_CONSOLE,qinfo->GetQuestId(),title.c_str(),statusStr); - - if (!found) - found = true; - } - } - - if (!found) - SendSysMessage(LANG_COMMAND_NOQUESTFOUND); - - return true; -} - -bool ChatHandler::HandleLookupCreatureCommand(const char *args) -{ - if (!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - // converting string that we try to find to lower case - if (!Utf8toWStr (namepart,wnamepart)) - return false; - - wstrToLower (wnamepart); - - bool found = false; - - for (uint32 id = 0; id< sCreatureStorage.MaxEntry; ++id) - { - CreatureInfo const* cInfo = sCreatureStorage.LookupEntry (id); - if (!cInfo) - continue; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - CreatureLocale const *cl = objmgr.GetCreatureLocale (id); - if (cl) - { - if (cl->Name.size() > loc_idx && !cl->Name[loc_idx].empty ()) - { - std::string name = cl->Name[loc_idx]; - - if (Utf8FitTo (name, wnamepart)) - { - if (m_session) - PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CHAT, id, id, name.c_str ()); - else - PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CONSOLE, id, name.c_str ()); - - if (!found) - found = true; - - continue; - } - } - } - } - - std::string name = cInfo->Name; - if (name.empty ()) - continue; - - if (Utf8FitTo(name, wnamepart)) - { - if (m_session) - PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CHAT, id, id, name.c_str ()); - else - PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CONSOLE, id, name.c_str ()); - - if (!found) - found = true; - } - } - - if (!found) - SendSysMessage (LANG_COMMAND_NOCREATUREFOUND); - - return true; -} - -bool ChatHandler::HandleLookupObjectCommand(const char *args) -{ - if (!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - // converting string that we try to find to lower case - if (!Utf8toWStr(namepart,wnamepart)) - return false; - - wstrToLower(wnamepart); - - bool found = false; - - for (uint32 id = 0; id< sGOStorage.MaxEntry; id++) - { - GameObjectInfo const* gInfo = sGOStorage.LookupEntry(id); - if (!gInfo) - continue; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - GameObjectLocale const *gl = objmgr.GetGameObjectLocale(id); - if (gl) - { - if (gl->Name.size() > loc_idx && !gl->Name[loc_idx].empty()) - { - std::string name = gl->Name[loc_idx]; - - if (Utf8FitTo(name, wnamepart)) - { - if (m_session) - PSendSysMessage(LANG_GO_ENTRY_LIST_CHAT, id, id, name.c_str()); - else - PSendSysMessage(LANG_GO_ENTRY_LIST_CONSOLE, id, name.c_str()); - - if (!found) - found = true; - - continue; - } - } - } - } - - std::string name = gInfo->name; - if (name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - { - if (m_session) - PSendSysMessage(LANG_GO_ENTRY_LIST_CHAT, id, id, name.c_str()); - else - PSendSysMessage(LANG_GO_ENTRY_LIST_CONSOLE, id, name.c_str()); - - if (!found) - found = true; - } - } - - if (!found) - SendSysMessage(LANG_COMMAND_NOGAMEOBJECTFOUND); - - return true; -} - -bool ChatHandler::HandleLookupFactionCommand(const char *args) -{ - if (!*args) - return false; - - // Can be NULL at console call - Player *target = getSelectedPlayer (); - - std::string namepart = args; - std::wstring wnamepart; - - if (!Utf8toWStr (namepart,wnamepart)) - return false; - - // converting string that we try to find to lower case - wstrToLower (wnamepart); - - bool found = false; - - for (uint32 id = 0; id < sFactionStore.GetNumRows(); ++id) - { - FactionEntry const *factionEntry = sFactionStore.LookupEntry (id); - if (factionEntry) - { - FactionState const* repState = target ? target->GetReputationMgr().GetState(factionEntry) : NULL; - - int loc = GetSessionDbcLocale(); - std::string name = factionEntry->name[loc]; - if (name.empty()) - continue; - - if (!Utf8FitTo(name, wnamepart)) - { - loc = 0; - for (; loc < MAX_LOCALE; ++loc) - { - if (loc == GetSessionDbcLocale()) - continue; - - name = factionEntry->name[loc]; - if (name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - break; - } - } - - if (loc < MAX_LOCALE) - { - // send faction in "id - [faction] rank reputation [visible] [at war] [own team] [unknown] [invisible] [inactive]" format - // or "id - [faction] [no reputation]" format - std::ostringstream ss; - if (m_session) - ss << id << " - |cffffffff|Hfaction:" << id << "|h[" << name << " " << localeNames[loc] << "]|h|r"; - else - ss << id << " - " << name << " " << localeNames[loc]; - - if (repState) // and then target != NULL also - { - ReputationRank rank = target->GetReputationMgr().GetRank(factionEntry); - std::string rankName = GetTrinityString(ReputationRankStrIndex[rank]); - - ss << " " << rankName << "|h|r (" << target->GetReputationMgr().GetReputation(factionEntry) << ")"; - - if (repState->Flags & FACTION_FLAG_VISIBLE) - ss << GetTrinityString(LANG_FACTION_VISIBLE); - if (repState->Flags & FACTION_FLAG_AT_WAR) - ss << GetTrinityString(LANG_FACTION_ATWAR); - if (repState->Flags & FACTION_FLAG_PEACE_FORCED) - ss << GetTrinityString(LANG_FACTION_PEACE_FORCED); - if (repState->Flags & FACTION_FLAG_HIDDEN) - ss << GetTrinityString(LANG_FACTION_HIDDEN); - if (repState->Flags & FACTION_FLAG_INVISIBLE_FORCED) - ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED); - if (repState->Flags & FACTION_FLAG_INACTIVE) - ss << GetTrinityString(LANG_FACTION_INACTIVE); - } - else - ss << GetTrinityString(LANG_FACTION_NOREPUTATION); - - SendSysMessage(ss.str().c_str()); - - if (!found) - found = true; - } - } - } - - if (!found) - SendSysMessage(LANG_COMMAND_FACTION_NOTFOUND); - return true; -} - -bool ChatHandler::HandleLookupTaxiNodeCommand(const char * args) -{ - if (!*args) - return false; - - std::string namepart = args; - std::wstring wnamepart; - - if (!Utf8toWStr(namepart,wnamepart)) - return false; - - // converting string that we try to find to lower case - wstrToLower(wnamepart); - - bool found = false; - - // Search in TaxiNodes.dbc - for (uint32 id = 0; id < sTaxiNodesStore.GetNumRows(); id++) - { - TaxiNodesEntry const *nodeEntry = sTaxiNodesStore.LookupEntry(id); - if (nodeEntry) - { - int loc = GetSessionDbcLocale(); - std::string name = nodeEntry->name[loc]; - if (name.empty()) - continue; - - if (!Utf8FitTo(name, wnamepart)) - { - loc = 0; - for (; loc < MAX_LOCALE; ++loc) - { - if (loc == GetSessionDbcLocale()) - continue; - - name = nodeEntry->name[loc]; - if (name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - break; - } - } - - if (loc < MAX_LOCALE) - { - // send taxinode in "id - [name] (Map:m X:x Y:y Z:z)" format - if (m_session) - PSendSysMessage (LANG_TAXINODE_ENTRY_LIST_CHAT, id, id, name.c_str(),localeNames[loc], - nodeEntry->map_id,nodeEntry->x,nodeEntry->y,nodeEntry->z); - else - PSendSysMessage (LANG_TAXINODE_ENTRY_LIST_CONSOLE, id, name.c_str(), localeNames[loc], - nodeEntry->map_id,nodeEntry->x,nodeEntry->y,nodeEntry->z); - - if (!found) - found = true; - } - } - } - if (!found) - SendSysMessage(LANG_COMMAND_NOTAXINODEFOUND); - return true; -} - -bool ChatHandler::HandleLookupMapCommand(const char *args) -{ - if (!*args) - return false; - - /*std::string namepart = args; - std::wstring wnamepart; - - // converting string that we try to find to lower case - if (!Utf8toWStr(namepart, wnamepart)) - return false; - - wstrToLower(wnamepart); - - bool found = false; - - // search in Map.dbc - for (uint32 id = 0; id < sMapStore.GetNumRows(); id++) - { - MapEntry const* MapInfo = sMapStore.LookupEntry(id); - if (MapInfo) - { - uint8 loc = m_session ? m_session->GetSessionDbcLocale() : sWorld.GetDefaultDbcLocale(); - - std::string name = MapInfo->name[loc]; - if (name.empty()) - continue; - - if (!Utf8FitTo(name, wnamepart)) - { - loc = LOCALE_enUS; - for (; loc < MAX_LOCALE; loc++) - { - if (m_session && loc == m_session->GetSessionDbcLocale()) - continue; - - name = MapInfo->name[loc]; - if (name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - break; - } - } - - if (loc < MAX_LOCALE) - { - // send map in "id - [name][Continent][Instance/Battleground/Arena][Raid reset time:][Heroic reset time:][Mountable]" format - std::ostringstream ss; - - if (m_session) - ss << id << " - |cffffffff|Hmap:" << id << "|h[" << name << "]"; - else // console - ss << id << " - [" << name << "]"; - - if (MapInfo->IsContinent()) - ss << GetTrinityString(LANG_CONTINENT); - - switch(MapInfo->map_type) - { - case MAP_INSTANCE: ss << GetTrinityString(LANG_INSTANCE); break; - case MAP_BATTLEGROUND: ss << GetTrinityString(LANG_BATTLEGROUND); break; - case MAP_ARENA: ss << GetTrinityString(LANG_ARENA); break; - } - - if (MapInfo->IsRaid()) - ss << GetTrinityString(LANG_RAID); - - if (MapInfo->SupportsHeroicMode()) - ss << GetTrinityString(LANG_HEROIC); - - uint32 ResetTimeRaid = MapInfo->resetTimeRaid; - - std::string ResetTimeRaidStr; - if (ResetTimeRaid) - ResetTimeRaidStr = secsToTimeString(ResetTimeRaid, true, false); - - uint32 ResetTimeHeroic = MapInfo->resetTimeHeroic; - std::string ResetTimeHeroicStr; - if (ResetTimeHeroic) - ResetTimeHeroicStr = secsToTimeString(ResetTimeHeroic, true, false); - - if (MapInfo->IsMountAllowed()) - ss << GetTrinityString(LANG_MOUNTABLE); - - if (ResetTimeRaid && !ResetTimeHeroic) - PSendSysMessage(ss.str().c_str(), ResetTimeRaidStr.c_str()); - else if (!ResetTimeRaid && ResetTimeHeroic) - PSendSysMessage(ss.str().c_str(), ResetTimeHeroicStr.c_str()); - else if (ResetTimeRaid && ResetTimeHeroic) - PSendSysMessage(ss.str().c_str(), ResetTimeRaidStr.c_str(), ResetTimeHeroicStr.c_str()); - else - SendSysMessage(ss.str().c_str()); - - if (!found) - found = true; - } - } - } - - if (!found) - SendSysMessage(LANG_COMMAND_NOMAPFOUND); - */ - return true; -} - -/** \brief GM command level 3 - Create a guild. - * - * This command allows a GM (level 3) to create a guild. - * - * The "args" parameter contains the name of the guild leader - * and then the name of the guild. - * - */ -bool ChatHandler::HandleGuildCreateCommand(const char *args) -{ - if (!*args) - return false; - - // if not guild name only (in "") then player name - Player* target; - if (!extractPlayerTarget(*args != '"' ? (char*)args : NULL, &target)) - return false; - - char* tailStr = *args != '"' ? strtok(NULL, "") : (char*)args; - if (!tailStr) - return false; - - char* guildStr = extractQuotedArg(tailStr); - if (!guildStr) - return false; - - std::string guildname = guildStr; - - if (target->GetGuildId()) - { - SendSysMessage (LANG_PLAYER_IN_GUILD); - return true; - } - - Guild *guild = new Guild; - if (!guild->Create (target,guildname)) - { - delete guild; - SendSysMessage (LANG_GUILD_NOT_CREATED); - SetSentErrorMessage (true); - return false; - } - - objmgr.AddGuild (guild); - return true; -} - -bool ChatHandler::HandleGuildInviteCommand(const char *args) -{ - if (!*args) - return false; - - // if not guild name only (in "") then player name - uint64 target_guid; - if (!extractPlayerTarget(*args != '"' ? (char*)args : NULL, NULL, &target_guid)) - return false; - - char* tailStr = *args != '"' ? strtok(NULL, "") : (char*)args; - if (!tailStr) - return false; - - char* guildStr = extractQuotedArg(tailStr); - if (!guildStr) - return false; - - std::string glName = guildStr; - Guild* targetGuild = objmgr.GetGuildByName (glName); - if (!targetGuild) - return false; - - // player's guild membership checked in AddMember before add - if (!targetGuild->AddMember (target_guid,targetGuild->GetLowestRank ())) - return false; - - return true; -} - -bool ChatHandler::HandleGuildUninviteCommand(const char *args) -{ - Player* target; - uint64 target_guid; - if (!extractPlayerTarget((char*)args,&target,&target_guid)) - return false; - - uint32 glId = target ? target->GetGuildId () : Player::GetGuildIdFromDB (target_guid); - if (!glId) - return false; - - Guild* targetGuild = objmgr.GetGuildById (glId); - if (!targetGuild) - return false; - - targetGuild->DelMember (target_guid); - return true; -} - -bool ChatHandler::HandleGuildRankCommand(const char *args) -{ - char* nameStr; - char* rankStr; - extractOptFirstArg((char*)args,&nameStr,&rankStr); - if (!rankStr) - return false; - - Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget(nameStr,&target,&target_guid,&target_name)) - return false; - - uint32 glId = target ? target->GetGuildId () : Player::GetGuildIdFromDB (target_guid); - if (!glId) - return false; - - Guild* targetGuild = objmgr.GetGuildById (glId); - if (!targetGuild) - return false; - - uint32 newrank = uint32 (atoi (rankStr)); - if (newrank > targetGuild->GetLowestRank ()) - return false; - - targetGuild->ChangeRank (target_guid,newrank); - return true; -} - -bool ChatHandler::HandleGuildDeleteCommand(const char *args) -{ - if (!*args) - return false; - - char* guildStr = extractQuotedArg((char*)args); - if (!guildStr) - return false; - - std::string gld = guildStr; - - Guild* targetGuild = objmgr.GetGuildByName (gld); - if (!targetGuild) - return false; - - targetGuild->Disband (); - - return true; -} - -bool ChatHandler::HandleGetDistanceCommand(const char *args) -{ - WorldObject* obj = NULL; - - if (*args) - { - uint64 guid = extractGuidFromLink((char*)args); - if (guid) - obj = (WorldObject*)ObjectAccessor::GetObjectByTypeMask(*m_session->GetPlayer(),guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); - - if (!obj) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - } - else - { - obj = getSelectedUnit(); - - if (!obj) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - } - - PSendSysMessage(LANG_DISTANCE, m_session->GetPlayer()->GetDistance(obj), m_session->GetPlayer()->GetDistance2d(obj), m_session->GetPlayer()->GetExactDist(obj), m_session->GetPlayer()->GetExactDist2d(obj)); - return true; -} - -bool ChatHandler::HandleDieCommand(const char* /*args*/) -{ - Unit* target = getSelectedUnit(); - - if (!target || !m_session->GetPlayer()->GetSelection()) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if (target->GetTypeId() == TYPEID_PLAYER) - { - if (HasLowerSecurity((Player*)target,0,false)) - return false; - } - - if (target->isAlive()) - { - if (sWorld.getConfig(CONFIG_DIE_COMMAND_MODE)) - m_session->GetPlayer()->Kill(target); - else - m_session->GetPlayer()->DealDamage(target, target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - - return true; -} - -bool ChatHandler::HandleDamageCommand(const char * args) -{ - if (!*args) - return false; - - Unit* target = getSelectedUnit(); - - if (!target || !m_session->GetPlayer()->GetSelection()) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if (!target->isAlive()) - return true; - - char* damageStr = strtok((char*)args, " "); - if (!damageStr) - return false; - - int32 damage_int = atoi((char*)damageStr); - if (damage_int <= 0) - return true; - - uint32 damage = damage_int; - - char* schoolStr = strtok((char*)NULL, " "); - - // flat melee damage without resistence/etc reduction - if (!schoolStr) - { - m_session->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - if (target != m_session->GetPlayer()) - m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_NORMAL, 0); - return true; - } - - uint32 school = schoolStr ? atoi((char*)schoolStr) : SPELL_SCHOOL_NORMAL; - if (school >= MAX_SPELL_SCHOOL) - return false; - - SpellSchoolMask schoolmask = SpellSchoolMask(1 << school); - - if (schoolmask & SPELL_SCHOOL_MASK_NORMAL) - damage = m_session->GetPlayer()->CalcArmorReducedDamage(target, damage, NULL, BASE_ATTACK); - - char* spellStr = strtok((char*)NULL, " "); - - // melee damage by specific school - if (!spellStr) - { - uint32 absorb = 0; - uint32 resist = 0; - - m_session->GetPlayer()->CalcAbsorbResist(target,schoolmask, SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); - - if (damage <= absorb + resist) - return true; - - damage -= absorb + resist; - - m_session->GetPlayer()->DealDamageMods(target,damage,&absorb); - m_session->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, schoolmask, NULL, false); - m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, schoolmask, damage, absorb, resist, VICTIMSTATE_NORMAL, 0); - return true; - } - - // non-melee damage - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spellid = extractSpellIdFromLink((char*)args); - if (!spellid || !sSpellStore.LookupEntry(spellid)) - return false; - - m_session->GetPlayer()->SpellNonMeleeDamageLog(target, spellid, damage); - return true; -} - -bool ChatHandler::HandleModifyArenaCommand(const char * args) -{ - if (!*args) - return false; - - Player *target = getSelectedPlayer(); - if (!target) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - int32 amount = (uint32)atoi(args); - - target->ModifyArenaPoints(amount); - - PSendSysMessage(LANG_COMMAND_MODIFY_ARENA, GetNameLink(target).c_str(), target->GetArenaPoints()); - - return true; -} - -bool ChatHandler::HandleReviveCommand(const char *args) -{ - Player* target; - uint64 target_guid; - if (!extractPlayerTarget((char*)args,&target,&target_guid)) - return false; - - if (target) - { - target->ResurrectPlayer(target->GetSession()->GetSecurity() > SEC_PLAYER ? 1.0f : 0.5f); - target->SpawnCorpseBones(); - target->SaveToDB(); - } - else - // will resurrected at login without corpse - ObjectAccessor::Instance().ConvertCorpseForPlayer(target_guid); - - return true; -} - -bool ChatHandler::HandleAuraCommand(const char *args) -{ - Unit *target = getSelectedUnit(); - if (!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spellID = extractSpellIdFromLink((char*)args); - - if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID)) - Aura::TryCreate(spellInfo, target, target); - - return true; -} - -bool ChatHandler::HandleUnAuraCommand(const char *args) -{ - Unit *target = getSelectedUnit(); - if (!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - std::string argstr = args; - if (argstr == "all") - { - target->RemoveAllAuras(); - return true; - } - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spellID = extractSpellIdFromLink((char*)args); - if (!spellID) - return false; - - target->RemoveAurasDueToSpell(spellID); - - return true; -} - -bool ChatHandler::HandleLinkGraveCommand(const char *args) -{ - if (!*args) - return false; - - char* px = strtok((char*)args, " "); - if (!px) - return false; - - uint32 g_id = (uint32)atoi(px); - - uint32 g_team; - - char* px2 = strtok(NULL, " "); - - if (!px2) - g_team = 0; - else if (strncmp(px2,"horde",6) == 0) - g_team = HORDE; - else if (strncmp(px2,"alliance",9) == 0) - g_team = ALLIANCE; - else - return false; - - WorldSafeLocsEntry const* graveyard = sWorldSafeLocsStore.LookupEntry(g_id); - - if (!graveyard) - { - PSendSysMessage(LANG_COMMAND_GRAVEYARDNOEXIST, g_id); - SetSentErrorMessage(true); - return false; - } - - Player* player = m_session->GetPlayer(); - - uint32 zoneId = player->GetZoneId(); - - AreaTableEntry const *areaEntry = GetAreaEntryByAreaID(zoneId); - if (!areaEntry || areaEntry->zone !=0) - { - PSendSysMessage(LANG_COMMAND_GRAVEYARDWRONGZONE, g_id,zoneId); - SetSentErrorMessage(true); - return false; - } - - if (objmgr.AddGraveYardLink(g_id,zoneId,g_team)) - PSendSysMessage(LANG_COMMAND_GRAVEYARDLINKED, g_id,zoneId); - else - PSendSysMessage(LANG_COMMAND_GRAVEYARDALRLINKED, g_id,zoneId); - - return true; -} - -bool ChatHandler::HandleNearGraveCommand(const char *args) -{ - uint32 g_team; - - size_t argslen = strlen(args); - - if (!*args) - g_team = 0; - else if (strncmp((char*)args,"horde",argslen) == 0) - g_team = HORDE; - else if (strncmp((char*)args,"alliance",argslen) == 0) - g_team = ALLIANCE; - else - return false; - - Player* player = m_session->GetPlayer(); - uint32 zone_id = player->GetZoneId(); - - WorldSafeLocsEntry const* graveyard = objmgr.GetClosestGraveYard( - player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(),player->GetMapId(),g_team); - - if (graveyard) - { - uint32 g_id = graveyard->ID; - - GraveYardData const* data = objmgr.FindGraveYardData(g_id,zone_id); - if (!data) - { - PSendSysMessage(LANG_COMMAND_GRAVEYARDERROR,g_id); - SetSentErrorMessage(true); - return false; - } - - g_team = data->team; - - std::string team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_NOTEAM); - - if (g_team == 0) - team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_ANY); - else if (g_team == HORDE) - team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_HORDE); - else if (g_team == ALLIANCE) - team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_ALLIANCE); - - PSendSysMessage(LANG_COMMAND_GRAVEYARDNEAREST, g_id,team_name.c_str(),zone_id); - } - else - { - std::string team_name; - - if (g_team == 0) - team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_ANY); - else if (g_team == HORDE) - team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_HORDE); - else if (g_team == ALLIANCE) - team_name = GetTrinityString(LANG_COMMAND_GRAVEYARD_ALLIANCE); - - if (g_team == ~uint32(0)) - PSendSysMessage(LANG_COMMAND_ZONENOGRAVEYARDS, zone_id); - else - PSendSysMessage(LANG_COMMAND_ZONENOGRAFACTION, zone_id,team_name.c_str()); - } - - return true; -} - -//-----------------------Npc Commands----------------------- -bool ChatHandler::HandleNpcAllowMovementCommand(const char* /*args*/) -{ - if (sWorld.getAllowMovement()) - { - sWorld.SetAllowMovement(false); - SendSysMessage(LANG_CREATURE_MOVE_DISABLED); - } - else - { - sWorld.SetAllowMovement(true); - SendSysMessage(LANG_CREATURE_MOVE_ENABLED); - } - return true; -} - -bool ChatHandler::HandleNpcChangeEntryCommand(const char *args) -{ - if (!*args) - return false; - - uint32 newEntryNum = atoi(args); - if (!newEntryNum) - return false; - - Unit* unit = getSelectedUnit(); - if (!unit || unit->GetTypeId() != TYPEID_UNIT) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - Creature* creature = unit->ToCreature(); - if (creature->UpdateEntry(newEntryNum)) - SendSysMessage(LANG_DONE); - else - SendSysMessage(LANG_ERROR); - return true; -} - -bool ChatHandler::HandleNpcInfoCommand(const char* /*args*/) -{ - Creature* target = getSelectedCreature(); - - if (!target) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - uint32 faction = target->getFaction(); - uint32 npcflags = target->GetUInt32Value(UNIT_NPC_FLAGS); - uint32 displayid = target->GetDisplayId(); - uint32 nativeid = target->GetNativeDisplayId(); - uint32 Entry = target->GetEntry(); - CreatureInfo const* cInfo = target->GetCreatureInfo(); - - int32 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL); - if (curRespawnDelay < 0) - curRespawnDelay = 0; - std::string curRespawnDelayStr = secsToTimeString(curRespawnDelay,true); - std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(),true); - - PSendSysMessage(LANG_NPCINFO_CHAR, target->GetDBTableGUIDLow(), faction, npcflags, Entry, displayid, nativeid); - PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel()); - PSendSysMessage(LANG_NPCINFO_HEALTH,target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth()); - PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS), target->GetUInt32Value(UNIT_DYNAMIC_FLAGS), target->getFaction()); - PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(),curRespawnDelayStr.c_str()); - PSendSysMessage(LANG_NPCINFO_LOOT, cInfo->lootid,cInfo->pickpocketLootId,cInfo->SkinLootId); - PSendSysMessage(LANG_NPCINFO_DUNGEON_ID, target->GetInstanceId()); - PSendSysMessage(LANG_NPCINFO_PHASEMASK, target->GetPhaseMask()); - PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor()); - PSendSysMessage(LANG_NPCINFO_POSITION,float(target->GetPositionX()), float(target->GetPositionY()), float(target->GetPositionZ())); - if (const CreatureData* const linked = target->GetLinkedRespawnCreatureData()) - if (CreatureInfo const *master = GetCreatureInfo(linked->id)) - PSendSysMessage(LANG_NPCINFO_LINKGUID, objmgr.GetLinkedRespawnGuid(target->GetDBTableGUIDLow()), linked->id, master->Name); - - if ((npcflags & UNIT_NPC_FLAG_VENDOR)) - { - SendSysMessage(LANG_NPCINFO_VENDOR); - } - if ((npcflags & UNIT_NPC_FLAG_TRAINER)) - { - SendSysMessage(LANG_NPCINFO_TRAINER); - } - - return true; -} - -//play npc emote -bool ChatHandler::HandleNpcPlayEmoteCommand(const char *args) -{ - uint32 emote = atoi((char*)args); - - Creature* target = getSelectedCreature(); - if (!target) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - target->SetUInt32Value(UNIT_NPC_EMOTESTATE,emote); - - return true; -} - -//TODO: NpcCommands that needs to be fixed : - -bool ChatHandler::HandleNpcAddWeaponCommand(const char* /*args*/) -{ - /*if (!*args) - return false; - - uint64 guid = m_session->GetPlayer()->GetSelection(); - if (guid == 0) - { - SendSysMessage(LANG_NO_SELECTION); - return true; - } - - Creature *pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); - - if (!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - return true; - } - - char* pSlotID = strtok((char*)args, " "); - if (!pSlotID) - return false; - - char* pItemID = strtok(NULL, " "); - if (!pItemID) - return false; - - uint32 ItemID = atoi(pItemID); - uint32 SlotID = atoi(pSlotID); - - ItemPrototype* tmpItem = objmgr.GetItemPrototype(ItemID); - - bool added = false; - if (tmpItem) - { - switch(SlotID) - { - case 1: - pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, ItemID); - added = true; - break; - case 2: - pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, ItemID); - added = true; - break; - case 3: - pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, ItemID); - added = true; - break; - default: - PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST,SlotID); - added = false; - break; - } - - if (added) - PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT,ItemID,tmpItem->Name1,SlotID); - } - else - { - PSendSysMessage(LANG_ITEM_NOT_FOUND,ItemID); - return true; - } - */ - return true; -} -//---------------------------------------------------------- - -bool ChatHandler::HandleExploreCheatCommand(const char *args) -{ - if (!*args) - return false; - - int flag = atoi((char*)args); - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if (flag != 0) - { - PSendSysMessage(LANG_YOU_SET_EXPLORE_ALL, GetNameLink(chr).c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_ALL,GetNameLink().c_str()); - } - else - { - PSendSysMessage(LANG_YOU_SET_EXPLORE_NOTHING, GetNameLink(chr).c_str()); - if (needReportToTarget(chr)) - ChatHandler(chr).PSendSysMessage(LANG_YOURS_EXPLORE_SET_NOTHING,GetNameLink().c_str()); - } - - for (uint8 i=0; iGetPlayer()->SetFlag(PLAYER_EXPLORED_ZONES_1+i,0xFFFFFFFF); - } - else - { - m_session->GetPlayer()->SetFlag(PLAYER_EXPLORED_ZONES_1+i,0); - } - } - - return true; -} - -bool ChatHandler::HandleHoverCommand(const char *args) -{ - char* px = strtok((char*)args, " "); - uint32 flag; - if (!px) - flag = 1; - else - flag = atoi(px); - - m_session->GetPlayer()->SetHover(flag); - - if (flag) - SendSysMessage(LANG_HOVER_ENABLED); - else - SendSysMessage(LANG_HOVER_DISABLED); - - return true; -} - -void ChatHandler::HandleCharacterLevel(Player* player, uint64 player_guid, uint32 oldlevel, uint32 newlevel) -{ - if (player) - { - player->GiveLevel(newlevel); - player->InitTalentForLevel(); - player->SetUInt32Value(PLAYER_XP,0); - - if (needReportToTarget(player)) - { - if (oldlevel == newlevel) - ChatHandler(player).PSendSysMessage(LANG_YOURS_LEVEL_PROGRESS_RESET,GetNameLink().c_str()); - else if (oldlevel < newlevel) - ChatHandler(player).PSendSysMessage(LANG_YOURS_LEVEL_UP,GetNameLink().c_str(),newlevel); - else // if (oldlevel > newlevel) - ChatHandler(player).PSendSysMessage(LANG_YOURS_LEVEL_DOWN,GetNameLink().c_str(),newlevel); - } - } - else - { - // update level and XP at level, all other will be updated at loading - CharacterDatabase.PExecute("UPDATE characters SET level = '%u', xp = 0 WHERE guid = '%u'", newlevel, GUID_LOPART(player_guid)); - } -} - -bool ChatHandler::HandleCharacterLevelCommand(const char *args) -{ - char* nameStr; - char* levelStr; - extractOptFirstArg((char*)args,&nameStr,&levelStr); - if (!levelStr) - return false; - - // exception opt second arg: .character level $name - if (isalpha(levelStr[0])) - { - nameStr = levelStr; - levelStr = NULL; // current level will used - } - - Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget(nameStr,&target,&target_guid,&target_name)) - return false; - - int32 oldlevel = target ? target->getLevel() : Player::GetLevelFromDB(target_guid); - int32 newlevel = levelStr ? atoi(levelStr) : oldlevel; - - if (newlevel < 1) - return false; // invalid level - - if (newlevel > STRONG_MAX_LEVEL) // hardcoded maximum level - newlevel = STRONG_MAX_LEVEL; - - HandleCharacterLevel(target,target_guid,oldlevel,newlevel); - - if (!m_session || m_session->GetPlayer() != target) // including player == NULL - { - std::string nameLink = playerLink(target_name); - PSendSysMessage(LANG_YOU_CHANGE_LVL,nameLink.c_str(),newlevel); - } - - return true; -} - -bool ChatHandler::HandleLevelUpCommand(const char *args) -{ - char* nameStr; - char* levelStr; - extractOptFirstArg((char*)args,&nameStr,&levelStr); - - // exception opt second arg: .character level $name - if (levelStr && isalpha(levelStr[0])) - { - nameStr = levelStr; - levelStr = NULL; // current level will used - } - - Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget(nameStr,&target,&target_guid,&target_name)) - return false; - - int32 oldlevel = target ? target->getLevel() : Player::GetLevelFromDB(target_guid); - int32 addlevel = levelStr ? atoi(levelStr) : 1; - int32 newlevel = oldlevel + addlevel; - - if (newlevel < 1) - newlevel = 1; - - if (newlevel > STRONG_MAX_LEVEL) // hardcoded maximum level - newlevel = STRONG_MAX_LEVEL; - - HandleCharacterLevel(target,target_guid,oldlevel,newlevel); - - if (!m_session || m_session->GetPlayer() != target) // including chr == NULL - { - std::string nameLink = playerLink(target_name); - PSendSysMessage(LANG_YOU_CHANGE_LVL,nameLink.c_str(),newlevel); - } - - return true; -} - -bool ChatHandler::HandleShowAreaCommand(const char *args) -{ - if (!*args) - return false; - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - int area = GetAreaFlagByAreaID(atoi((char*)args)); - int offset = area / 32; - uint32 val = (uint32)(1 << (area % 32)); - - if (area<0 || offset >= PLAYER_EXPLORED_ZONES_SIZE) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - uint32 currFields = chr->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); - chr->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields | val)); - - SendSysMessage(LANG_EXPLORE_AREA); - return true; -} - -bool ChatHandler::HandleHideAreaCommand(const char *args) -{ - if (!*args) - return false; - - Player *chr = getSelectedPlayer(); - if (chr == NULL) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - int area = GetAreaFlagByAreaID(atoi((char*)args)); - int offset = area / 32; - uint32 val = (uint32)(1 << (area % 32)); - - if (area<0 || offset >= PLAYER_EXPLORED_ZONES_SIZE) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - uint32 currFields = chr->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); - chr->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields ^ val)); - - SendSysMessage(LANG_UNEXPLORE_AREA); - return true; -} - -bool ChatHandler::HandleBankCommand(const char* /*args*/) -{ - m_session->SendShowBank(m_session->GetPlayer()->GetGUID()); - - return true; -} - -bool ChatHandler::HandleChangeWeather(const char *args) -{ - if (!*args) - return false; - - //Weather is OFF - if (!sWorld.getConfig(CONFIG_WEATHER)) - { - SendSysMessage(LANG_WEATHER_DISABLED); - SetSentErrorMessage(true); - return false; - } - - //*Change the weather of a cell - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - - if (!px || !py) - return false; - - uint32 type = (uint32)atoi(px); //0 to 3, 0: fine, 1: rain, 2: snow, 3: sand - float grade = (float)atof(py); //0 to 1, sending -1 is instand good weather - - Player *player = m_session->GetPlayer(); - uint32 zoneid = player->GetZoneId(); - - Weather* wth = sWorld.FindWeather(zoneid); - - if (!wth) - wth = sWorld.AddWeather(zoneid); - if (!wth) - { - SendSysMessage(LANG_NO_WEATHER); - SetSentErrorMessage(true); - return false; - } - - wth->SetWeather(WeatherType(type), grade); - - return true; -} - -bool ChatHandler::HandleDebugSet32Bit(const char *args) -{ - if (!*args) - return false; - - WorldObject* target = getSelectedObject(); - if (!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - - if (!px || !py) - return false; - - uint32 Opcode = (uint32)atoi(px); - uint32 Value = (uint32)atoi(py); - if (Value > 32) //uint32 = 32 bits - return false; - - sLog.outDebug(GetTrinityString(LANG_SET_32BIT), Opcode, Value); - - uint32 iValue = Value ? 1 << (Value - 1) : 0; - target->SetUInt32Value(Opcode , iValue); - - PSendSysMessage(LANG_SET_32BIT_FIELD, Opcode, iValue); - return true; -} - -bool ChatHandler::HandleTeleAddCommand(const char * args) -{ - if (!*args) - return false; - - Player *player=m_session->GetPlayer(); - if (!player) - return false; - - std::string name = args; - - if (objmgr.GetGameTele(name)) - { - SendSysMessage(LANG_COMMAND_TP_ALREADYEXIST); - SetSentErrorMessage(true); - return false; - } - - GameTele tele; - tele.position_x = player->GetPositionX(); - tele.position_y = player->GetPositionY(); - tele.position_z = player->GetPositionZ(); - tele.orientation = player->GetOrientation(); - tele.mapId = player->GetMapId(); - tele.name = name; - - if (objmgr.AddGameTele(tele)) - { - SendSysMessage(LANG_COMMAND_TP_ADDED); - } - else - { - SendSysMessage(LANG_COMMAND_TP_ADDEDERR); - SetSentErrorMessage(true); - return false; - } - - return true; -} - -bool ChatHandler::HandleTeleDelCommand(const char * args) -{ - if (!*args) - return false; - - std::string name = args; - - if (!objmgr.DeleteGameTele(name)) - { - SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); - SetSentErrorMessage(true); - return false; - } - - SendSysMessage(LANG_COMMAND_TP_DELETED); - return true; -} - -bool ChatHandler::HandleListAurasCommand (const char * /*args*/) -{ - Unit *unit = getSelectedUnit(); - if (!unit) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - char const* talentStr = GetTrinityString(LANG_TALENT); - char const* passiveStr = GetTrinityString(LANG_PASSIVE); - - Unit::AuraApplicationMap const& uAuras = unit->GetAppliedAuras(); - PSendSysMessage(LANG_COMMAND_TARGET_LISTAURAS, uAuras.size()); - for (Unit::AuraApplicationMap::const_iterator itr = uAuras.begin(); itr != uAuras.end(); ++itr) - { - bool talent = GetTalentSpellCost(itr->second->GetBase()->GetId()) > 0; - - AuraApplication const * aurApp = itr->second; - Aura const * aura = aurApp->GetBase(); - char const* name = aura->GetSpellProto()->SpellName[GetSessionDbcLocale()]; - - if (m_session) - { - std::ostringstream ss_name; - ss_name << "|cffffffff|Hspell:" << aura->GetId() << "|h[" << name << "]|h|r"; - - PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, aura->GetId(), aurApp->GetEffectMask(), - aura->GetCharges(), aura->GetStackAmount(), aurApp->GetSlot(), - aura->GetDuration(), aura->GetMaxDuration(), - ss_name.str().c_str(), - (aura->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), - IS_PLAYER_GUID(aura->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(aura->GetCasterGUID())); - } - else - { - PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, aura->GetId(), aurApp->GetEffectMask(), - aura->GetCharges(), aura->GetStackAmount(), aurApp->GetSlot(), - aura->GetDuration(), aura->GetMaxDuration(), - name, - (aura->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), - IS_PLAYER_GUID(aura->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(aura->GetCasterGUID())); - } - } - for (uint16 i = 0; i < TOTAL_AURAS; ++i) - { - Unit::AuraEffectList const& uAuraList = unit->GetAuraEffectsByType(AuraType(i)); - if (uAuraList.empty()) continue; - PSendSysMessage(LANG_COMMAND_TARGET_LISTAURATYPE, uAuraList.size(), i); - for (Unit::AuraEffectList::const_iterator itr = uAuraList.begin(); itr != uAuraList.end(); ++itr) - { - //bool talent = GetTalentSpellCost((*itr)->GetId()) > 0; - - char const* name = (*itr)->GetSpellProto()->SpellName[GetSessionDbcLocale()]; - - std::ostringstream ss_name; - ss_name << "|cffffffff|Hspell:" << (*itr)->GetId() << "|h[" << name << "]|h|r"; - - PSendSysMessage(LANG_COMMAND_TARGET_AURASIMPLE, (*itr)->GetId(), (*itr)->GetEffIndex(), - (*itr)->GetAmount()); - } - } - return true; -} - -bool ChatHandler::HandleResetAchievementsCommand (const char * args) -{ - Player* target; - uint64 target_guid; - if (!extractPlayerTarget((char*)args,&target,&target_guid)) - return false; - - if (target) - target->GetAchievementMgr().Reset(); - else - AchievementMgr::DeleteFromDB(GUID_LOPART(target_guid)); - - return true; -} - -bool ChatHandler::HandleResetHonorCommand (const char * args) -{ - Player* target; - if (!extractPlayerTarget((char*)args,&target)) - return false; - - target->SetUInt32Value(PLAYER_FIELD_KILLS, 0); - target->SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 0); - target->SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, 0); - target->SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0); - target->SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0); - target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL); - - return true; -} - -static bool HandleResetStatsOrLevelHelper(Player* player) -{ - ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(player->getClass()); - if (!cEntry) - { - sLog.outError("Class %u not found in DBC (Wrong DBC files?)",player->getClass()); - return false; - } - - uint8 powertype = cEntry->powerType; - - // reset m_form if no aura - if (!player->HasAuraType(SPELL_AURA_MOD_SHAPESHIFT)) - player->m_form = FORM_NONE; - - player->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE); - player->SetFloatValue(UNIT_FIELD_COMBATREACH, DEFAULT_COMBAT_REACH); - - player->setFactionForRace(player->getRace()); - - player->SetUInt32Value(UNIT_FIELD_BYTES_0, ((player->getRace()) | (player->getClass() << 8) | (player->getGender() << 16) | (powertype << 24))); - - // reset only if player not in some form; - if (player->m_form == FORM_NONE) - player->InitDisplayIds(); - - player->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); - player->SetByteValue(UNIT_FIELD_BYTES_2, 3, player->m_form); - - player->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); - - //-1 is default value - player->SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1)); - - //player->SetUInt32Value(PLAYER_FIELD_BYTES, 0xEEE00000); - return true; -} - -bool ChatHandler::HandleResetLevelCommand(const char * args) -{ - Player* target; - if (!extractPlayerTarget((char*)args,&target)) - return false; - - if (!HandleResetStatsOrLevelHelper(target)) - return false; - - // set starting level - uint32 start_level = target->getClass() != CLASS_DEATH_KNIGHT - ? sWorld.getConfig(CONFIG_START_PLAYER_LEVEL) - : sWorld.getConfig(CONFIG_START_HEROIC_PLAYER_LEVEL); - - target->_ApplyAllLevelScaleItemMods(false); - - target->SetLevel(start_level); - target->InitRunes(); - target->InitStatsForLevel(true); - target->InitTaxiNodesForLevel(); - target->InitGlyphsForLevel(); - target->InitTalentForLevel(); - target->SetUInt32Value(PLAYER_XP,0); - - target->_ApplyAllLevelScaleItemMods(true); - - // reset level for pet - if (Pet* pet = target->GetPet()) - pet->SynchronizeLevelWithOwner(); - - return true; -} - -bool ChatHandler::HandleResetStatsCommand(const char * args) -{ - Player* target; - if (!extractPlayerTarget((char*)args,&target)) - return false; - - if (!HandleResetStatsOrLevelHelper(target)) - return false; - - target->InitRunes(); - target->InitStatsForLevel(true); - target->InitTaxiNodesForLevel(); - target->InitGlyphsForLevel(); - target->InitTalentForLevel(); - - return true; -} - -bool ChatHandler::HandleResetSpellsCommand(const char * args) -{ - Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) - return false; - - if (target) - { - target->resetSpells(/* bool myClassOnly */); - - ChatHandler(target).SendSysMessage(LANG_RESET_SPELLS); - if (!m_session || m_session->GetPlayer() != target) - PSendSysMessage(LANG_RESET_SPELLS_ONLINE,GetNameLink(target).c_str()); - } - else - { - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",uint32(AT_LOGIN_RESET_SPELLS), GUID_LOPART(target_guid)); - PSendSysMessage(LANG_RESET_SPELLS_OFFLINE,target_name.c_str()); - } - - return true; -} - -bool ChatHandler::HandleResetTalentsCommand(const char * args) -{ - Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) - { - // Try reset talents as Hunter Pet - Creature* creature = getSelectedCreature(); - if (!*args && creature && creature->isPet()) - { - Unit *owner = creature->GetOwner(); - if (owner && owner->GetTypeId() == TYPEID_PLAYER && ((Pet *)creature)->IsPermanentPetFor(owner->ToPlayer())) - { - ((Pet *)creature)->resetTalents(true); - owner->ToPlayer()->SendTalentsInfoData(true); - - ChatHandler(owner->ToPlayer()).SendSysMessage(LANG_RESET_PET_TALENTS); - if (!m_session || m_session->GetPlayer() != owner->ToPlayer()) - PSendSysMessage(LANG_RESET_PET_TALENTS_ONLINE,GetNameLink(owner->ToPlayer()).c_str()); - } - return true; - } - - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - if (target) - { - target->resetTalents(true); - target->SendTalentsInfoData(false); - ChatHandler(target).SendSysMessage(LANG_RESET_TALENTS); - if (!m_session || m_session->GetPlayer() != target) - PSendSysMessage(LANG_RESET_TALENTS_ONLINE,GetNameLink(target).c_str()); - - Pet* pet = target->GetPet(); - Pet::resetTalentsForAllPetsOf(target,pet); - if (pet) - target->SendTalentsInfoData(true); - return true; - } - else if (target_guid) - { - uint32 at_flags = AT_LOGIN_NONE | AT_LOGIN_RESET_PET_TALENTS; - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",at_flags, GUID_LOPART(target_guid)); - std::string nameLink = playerLink(target_name); - PSendSysMessage(LANG_RESET_TALENTS_OFFLINE,nameLink.c_str()); - return true; - } - - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; -} - -bool ChatHandler::HandleResetAllCommand(const char * args) -{ - if (!*args) - return false; - - std::string casename = args; - - AtLoginFlags atLogin; - - // Command specially created as single command to prevent using short case names - if (casename == "spells") - { - atLogin = AT_LOGIN_RESET_SPELLS; - sWorld.SendWorldText(LANG_RESETALL_SPELLS); - if (!m_session) - SendSysMessage(LANG_RESETALL_SPELLS); - } - else if (casename == "talents") - { - atLogin = AtLoginFlags(AT_LOGIN_RESET_TALENTS | AT_LOGIN_RESET_PET_TALENTS); - sWorld.SendWorldText(LANG_RESETALL_TALENTS); - if (!m_session) - SendSysMessage(LANG_RESETALL_TALENTS); - } - else - { - PSendSysMessage(LANG_RESETALL_UNKNOWN_CASE,args); - SetSentErrorMessage(true); - return false; - } - - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE (at_login & '%u') = '0'",atLogin,atLogin); - - ObjectAccessor::Guard guard(*HashMapHolder::GetLock()); - HashMapHolder::MapType const& plist = ObjectAccessor::Instance().GetPlayers(); - for (HashMapHolder::MapType::const_iterator itr = plist.begin(); itr != plist.end(); ++itr) - itr->second->SetAtLoginFlag(atLogin); - - return true; -} - -bool ChatHandler::HandleServerShutDownCancelCommand(const char* /*args*/) -{ - sWorld.ShutdownCancel(); - return true; -} - -bool ChatHandler::HandleServerShutDownCommand(const char *args) -{ - if (!*args) - return false; - - char* time_str = strtok ((char*) args, " "); - char* exitcode_str = strtok (NULL, ""); - - int32 time = atoi (time_str); - - ///- Prevent interpret wrong arg value as 0 secs shutdown time - if ((time == 0 && (time_str[0] != '0' || time_str[1] != '\0')) || time < 0) - return false; - - if (exitcode_str) - { - int32 exitcode = atoi (exitcode_str); - - // Handle atoi() errors - if (exitcode == 0 && (exitcode_str[0] != '0' || exitcode_str[1] != '\0')) - return false; - - // Exit code should be in range of 0-125, 126-255 is used - // in many shells for their own return codes and code > 255 - // is not supported in many others - if (exitcode < 0 || exitcode > 125) - return false; - - sWorld.ShutdownServ (time, 0, exitcode); - } - else - sWorld.ShutdownServ(time,0,SHUTDOWN_EXIT_CODE); - return true; -} - -bool ChatHandler::HandleServerRestartCommand(const char *args) -{ - if (!*args) - return false; - - char* time_str = strtok ((char*) args, " "); - char* exitcode_str = strtok (NULL, ""); - - int32 time = atoi (time_str); - - ///- Prevent interpret wrong arg value as 0 secs shutdown time - if ((time == 0 && (time_str[0] != '0' || time_str[1] != '\0') || time < 0)) - return false; - - if (exitcode_str) - { - int32 exitcode = atoi (exitcode_str); - - // Handle atoi() errors - if (exitcode == 0 && (exitcode_str[0] != '0' || exitcode_str[1] != '\0')) - return false; - - // Exit code should be in range of 0-125, 126-255 is used - // in many shells for their own return codes and code > 255 - // is not supported in many others - if (exitcode < 0 || exitcode > 125) - return false; - - sWorld.ShutdownServ (time, SHUTDOWN_MASK_RESTART, exitcode); - } - else - sWorld.ShutdownServ(time, SHUTDOWN_MASK_RESTART, RESTART_EXIT_CODE); - return true; -} - -bool ChatHandler::HandleServerIdleRestartCommand(const char *args) -{ - if (!*args) - return false; - - char* time_str = strtok ((char*) args, " "); - char* exitcode_str = strtok (NULL, ""); - - int32 time = atoi (time_str); - - ///- Prevent interpret wrong arg value as 0 secs shutdown time - if ((time == 0 && (time_str[0] != '0' || time_str[1] != '\0') || time < 0)) - return false; - - if (exitcode_str) - { - int32 exitcode = atoi (exitcode_str); - - // Handle atoi() errors - if (exitcode == 0 && (exitcode_str[0] != '0' || exitcode_str[1] != '\0')) - return false; - - // Exit code should be in range of 0-125, 126-255 is used - // in many shells for their own return codes and code > 255 - // is not supported in many others - if (exitcode < 0 || exitcode > 125) - return false; - - sWorld.ShutdownServ (time, SHUTDOWN_MASK_RESTART|SHUTDOWN_MASK_IDLE, exitcode); - } - else - sWorld.ShutdownServ(time,SHUTDOWN_MASK_RESTART|SHUTDOWN_MASK_IDLE,RESTART_EXIT_CODE); - return true; -} - -bool ChatHandler::HandleServerIdleShutDownCommand(const char *args) -{ - if (!*args) - return false; - - char* time_str = strtok ((char*) args, " "); - char* exitcode_str = strtok (NULL, ""); - - int32 time = atoi (time_str); - - ///- Prevent interpret wrong arg value as 0 secs shutdown time - if (time == 0 && (time_str[0] != '0' || time_str[1] != '\0') || time < 0) - return false; - - if (exitcode_str) - { - int32 exitcode = atoi (exitcode_str); - - // Handle atoi() errors - if (exitcode == 0 && (exitcode_str[0] != '0' || exitcode_str[1] != '\0')) - return false; - - // Exit code should be in range of 0-125, 126-255 is used - // in many shells for their own return codes and code > 255 - // is not supported in many others - if (exitcode < 0 || exitcode > 125) - return false; - - sWorld.ShutdownServ (time, SHUTDOWN_MASK_IDLE, exitcode); - } - else - sWorld.ShutdownServ(time,SHUTDOWN_MASK_IDLE,SHUTDOWN_EXIT_CODE); - return true; -} - -bool ChatHandler::HandleQuestAdd(const char *args) -{ - Player* player = getSelectedPlayer(); - if (!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // .addquest #entry' - // number or [name] Shift-click form |color|Hquest:quest_id:quest_level|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hquest"); - if (!cId) - return false; - - uint32 entry = atol(cId); - - Quest const* pQuest = objmgr.GetQuestTemplate(entry); - - if (!pQuest) - { - PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND,entry); - SetSentErrorMessage(true); - return false; - } - - // check item starting quest (it can work incorrectly if added without item in inventory) - for (uint32 id = 0; id < sItemStorage.MaxEntry; id++) - { - ItemPrototype const *pProto = sItemStorage.LookupEntry(id); - if (!pProto) - continue; - - if (pProto->StartQuest == entry) - { - PSendSysMessage(LANG_COMMAND_QUEST_STARTFROMITEM, entry, pProto->ItemId); - SetSentErrorMessage(true); - return false; - } - } - - // ok, normal (creature/GO starting) quest - if (player->CanAddQuest(pQuest, true)) - { - player->AddQuest(pQuest, NULL); - - if (player->CanCompleteQuest(entry)) - player->CompleteQuest(entry); - } - - return true; -} - -bool ChatHandler::HandleQuestRemove(const char *args) -{ - Player* player = getSelectedPlayer(); - if (!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // .removequest #entry' - // number or [name] Shift-click form |color|Hquest:quest_id:quest_level|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hquest"); - if (!cId) - return false; - - uint32 entry = atol(cId); - - Quest const* pQuest = objmgr.GetQuestTemplate(entry); - - if (!pQuest) - { - PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND, entry); - SetSentErrorMessage(true); - return false; - } - - // remove all quest entries for 'entry' from quest log - for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) - { - uint32 quest = player->GetQuestSlotQuestId(slot); - if (quest == entry) - { - player->SetQuestSlot(slot,0); - - // we ignore unequippable quest items in this case, its' still be equipped - player->TakeQuestSourceItem(quest, false); - } - } - - // set quest status to not started (will updated in DB at next save) - player->SetQuestStatus(entry, QUEST_STATUS_NONE); - - // reset rewarded for restart repeatable quest - player->getQuestStatusMap()[entry].m_rewarded = false; - - SendSysMessage(LANG_COMMAND_QUEST_REMOVED); - return true; -} - -bool ChatHandler::HandleQuestComplete(const char *args) -{ - Player* player = getSelectedPlayer(); - if (!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } - - // .quest complete #entry - // number or [name] Shift-click form |color|Hquest:quest_id:quest_level|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hquest"); - if (!cId) - return false; - - uint32 entry = atol(cId); - - Quest const* pQuest = objmgr.GetQuestTemplate(entry); - - // If player doesn't have the quest - if (!pQuest || player->GetQuestStatus(entry) == QUEST_STATUS_NONE) - { - PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND, entry); - SetSentErrorMessage(true); - return false; - } - - // Add quest items for quests that require items - for (uint8 x = 0; x < QUEST_ITEM_OBJECTIVES_COUNT; ++x) - { - uint32 id = pQuest->ReqItemId[x]; - uint32 count = pQuest->ReqItemCount[x]; - if (!id || !count) - continue; - - uint32 curItemCount = player->GetItemCount(id,true); - - ItemPosCountVec dest; - uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, id, count-curItemCount); - if (msg == EQUIP_ERR_OK) - { - Item* item = player->StoreNewItem(dest, id, true); - player->SendNewItem(item,count-curItemCount,true,false); - } - } - - // All creature/GO slain/casted (not required, but otherwise it will display "Creature slain 0/10") - for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) - { - uint32 creature = pQuest->ReqCreatureOrGOId[i]; - uint32 creaturecount = pQuest->ReqCreatureOrGOCount[i]; - - if (uint32 spell_id = pQuest->ReqSpell[i]) - { - for (uint16 z = 0; z < creaturecount; ++z) - player->CastedCreatureOrGO(creature,0,spell_id); - } - else if (creature > 0) - { - if (CreatureInfo const* cInfo = objmgr.GetCreatureTemplate(creature)) - for (uint16 z = 0; z < creaturecount; ++z) - player->KilledMonster(cInfo,0); - } - else if (creature < 0) - { - for (uint16 z = 0; z < creaturecount; ++z) - player->CastedCreatureOrGO(creature,0,0); - } - } - - // If the quest requires reputation to complete - if (uint32 repFaction = pQuest->GetRepObjectiveFaction()) - { - uint32 repValue = pQuest->GetRepObjectiveValue(); - uint32 curRep = player->GetReputationMgr().GetReputation(repFaction); - if (curRep < repValue) - if (FactionEntry const *factionEntry = sFactionStore.LookupEntry(repFaction)) - player->GetReputationMgr().SetReputation(factionEntry,repValue); - } - - // If the quest requires a SECOND reputation to complete - if (uint32 repFaction = pQuest->GetRepObjectiveFaction2()) - { - uint32 repValue2 = pQuest->GetRepObjectiveValue2(); - uint32 curRep = player->GetReputationMgr().GetReputation(repFaction); - if (curRep < repValue2) - if (FactionEntry const *factionEntry = sFactionStore.LookupEntry(repFaction)) - player->GetReputationMgr().SetReputation(factionEntry,repValue2); - } - - // If the quest requires money - int32 ReqOrRewMoney = pQuest->GetRewOrReqMoney(); - if (ReqOrRewMoney < 0) - player->ModifyMoney(-ReqOrRewMoney); - - player->CompleteQuest(entry); - return true; -} - -bool ChatHandler::HandleBanAccountCommand(const char *args) -{ - return HandleBanHelper(BAN_ACCOUNT,args); -} - -bool ChatHandler::HandleBanCharacterCommand(const char *args) -{ - return HandleBanHelper(BAN_CHARACTER,args); -} - -bool ChatHandler::HandleBanIPCommand(const char *args) -{ - return HandleBanHelper(BAN_IP,args); -} - -bool ChatHandler::HandleBanHelper(BanMode mode, const char *args) -{ - if (!*args) - return false; - - char* cnameOrIP = strtok ((char*)args, " "); - if (!cnameOrIP) - return false; - - std::string nameOrIP = cnameOrIP; - - char* duration = strtok (NULL," "); - if (!duration || !atoi(duration)) - return false; - - char* reason = strtok (NULL,""); - if (!reason) - return false; - - switch(mode) - { - case BAN_ACCOUNT: - if (!AccountMgr::normalizeString(nameOrIP)) - { - PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,nameOrIP.c_str()); - SetSentErrorMessage(true); - return false; - } - break; - case BAN_CHARACTER: - if (!normalizePlayerName(nameOrIP)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - break; - case BAN_IP: - if (!IsIPAddress(nameOrIP.c_str())) - return false; - break; - } - - switch(sWorld.BanAccount(mode, nameOrIP, duration, reason,m_session ? m_session->GetPlayerName() : "")) - { - case BAN_SUCCESS: - if (atoi(duration)>0) - PSendSysMessage(LANG_BAN_YOUBANNED,nameOrIP.c_str(),secsToTimeString(TimeStringToSecs(duration),true).c_str(),reason); - else - PSendSysMessage(LANG_BAN_YOUPERMBANNED,nameOrIP.c_str(),reason); - break; - case BAN_SYNTAX_ERROR: - return false; - case BAN_NOTFOUND: - switch(mode) - { - default: - PSendSysMessage(LANG_BAN_NOTFOUND,"account",nameOrIP.c_str()); - break; - case BAN_CHARACTER: - PSendSysMessage(LANG_BAN_NOTFOUND,"character",nameOrIP.c_str()); - break; - case BAN_IP: - PSendSysMessage(LANG_BAN_NOTFOUND,"ip",nameOrIP.c_str()); - break; - } - SetSentErrorMessage(true); - return false; - } - - return true; -} - -bool ChatHandler::HandleUnBanAccountCommand(const char *args) -{ - return HandleUnBanHelper(BAN_ACCOUNT,args); -} - -bool ChatHandler::HandleUnBanCharacterCommand(const char *args) -{ - return HandleUnBanHelper(BAN_CHARACTER,args); -} - -bool ChatHandler::HandleUnBanIPCommand(const char *args) -{ - return HandleUnBanHelper(BAN_IP,args); -} - -bool ChatHandler::HandleUnBanHelper(BanMode mode, const char *args) -{ - if (!*args) - return false; - - char* cnameOrIP = strtok ((char*)args, " "); - if (!cnameOrIP) - return false; - - std::string nameOrIP = cnameOrIP; - - switch(mode) - { - case BAN_ACCOUNT: - if (!AccountMgr::normalizeString(nameOrIP)) - { - PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,nameOrIP.c_str()); - SetSentErrorMessage(true); - return false; - } - break; - case BAN_CHARACTER: - if (!normalizePlayerName(nameOrIP)) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - break; - case BAN_IP: - if (!IsIPAddress(nameOrIP.c_str())) - return false; - break; - } - - if (sWorld.RemoveBanAccount(mode,nameOrIP)) - PSendSysMessage(LANG_UNBAN_UNBANNED,nameOrIP.c_str()); - else - PSendSysMessage(LANG_UNBAN_ERROR,nameOrIP.c_str()); - - return true; -} - -bool ChatHandler::HandleBanInfoAccountCommand(const char *args) -{ - if (!*args) - return false; - - char* cname = strtok((char*)args, ""); - if (!cname) - return false; - - std::string account_name = cname; - if (!AccountMgr::normalizeString(account_name)) - { - PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); - SetSentErrorMessage(true); - return false; - } - - uint32 accountid = accmgr.GetId(account_name); - if (!accountid) - { - PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); - return true; - } - - return HandleBanInfoHelper(accountid,account_name.c_str()); -} - -bool ChatHandler::HandleBanInfoCharacterCommand(const char *args) -{ - Player* target; - uint64 target_guid; - if (!extractPlayerTarget((char*)args,&target,&target_guid)) - return false; - - uint32 accountid = target ? target->GetSession()->GetAccountId() : objmgr.GetPlayerAccountIdByGUID(target_guid); - - std::string accountname; - if (!accmgr.GetName(accountid,accountname)) - { - PSendSysMessage(LANG_BANINFO_NOCHARACTER); - return true; - } - - return HandleBanInfoHelper(accountid,accountname.c_str()); -} - -bool ChatHandler::HandleBanInfoHelper(uint32 accountid, char const* accountname) -{ - QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT FROM_UNIXTIME(bandate), unbandate-bandate, active, unbandate,banreason,bannedby FROM account_banned WHERE id = '%u' ORDER BY bandate ASC",accountid); - if (!result) - { - PSendSysMessage(LANG_BANINFO_NOACCOUNTBAN, accountname); - return true; - } - - PSendSysMessage(LANG_BANINFO_BANHISTORY,accountname); - do - { - Field* fields = result->Fetch(); - - time_t unbandate = time_t(fields[3].GetUInt64()); - bool active = false; - if (fields[2].GetBool() && (fields[1].GetUInt64() == (uint64)0 ||unbandate >= time(NULL))) - active = true; - bool permanent = (fields[1].GetUInt64() == (uint64)0); - std::string bantime = permanent?GetTrinityString(LANG_BANINFO_INFINITE):secsToTimeString(fields[1].GetUInt64(), true); - PSendSysMessage(LANG_BANINFO_HISTORYENTRY, - fields[0].GetString(), bantime.c_str(), active ? GetTrinityString(LANG_BANINFO_YES):GetTrinityString(LANG_BANINFO_NO), fields[4].GetString(), fields[5].GetString()); - }while (result->NextRow()); - - return true; -} - -bool ChatHandler::HandleBanInfoIPCommand(const char *args) -{ - if (!*args) - return false; - - char* cIP = strtok ((char*)args, ""); - if (!cIP) - return false; - - if (!IsIPAddress(cIP)) - return false; - - std::string IP = cIP; - - LoginDatabase.escape_string(IP); - QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT ip, FROM_UNIXTIME(bandate), FROM_UNIXTIME(unbandate), unbandate-UNIX_TIMESTAMP(), banreason,bannedby,unbandate-bandate FROM ip_banned WHERE ip = '%s'",IP.c_str()); - if (!result) - { - PSendSysMessage(LANG_BANINFO_NOIP); - return true; - } - - Field *fields = result->Fetch(); - bool permanent = !fields[6].GetUInt64(); - PSendSysMessage(LANG_BANINFO_IPENTRY, - fields[0].GetString(), fields[1].GetString(), permanent ? GetTrinityString(LANG_BANINFO_NEVER):fields[2].GetString(), - permanent ? GetTrinityString(LANG_BANINFO_INFINITE):secsToTimeString(fields[3].GetUInt64(), true).c_str(), fields[4].GetString(), fields[5].GetString()); - - return true; -} - -bool ChatHandler::HandleBanListCharacterCommand(const char *args) -{ - LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate<>bandate"); - - char* cFilter = strtok ((char*)args, " "); - if (!cFilter) - return false; - - std::string filter = cFilter; - LoginDatabase.escape_string(filter); - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'"),filter.c_str()); - if (!result) - { - PSendSysMessage(LANG_BANLIST_NOCHARACTER); - return true; - } - - return HandleBanListHelper(result); -} - -bool ChatHandler::HandleBanListAccountCommand(const char *args) -{ - LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate<>bandate"); - - char* cFilter = strtok((char*)args, " "); - std::string filter = cFilter ? cFilter : ""; - LoginDatabase.escape_string(filter); - - QueryResult_AutoPtr result; - - if (filter.empty()) - { - result = LoginDatabase.Query("SELECT account.id, username FROM account, account_banned" - " WHERE account.id = account_banned.id AND active = 1 GROUP BY account.id"); - } - else - { - result = LoginDatabase.PQuery("SELECT account.id, username FROM account, account_banned" - " WHERE account.id = account_banned.id AND active = 1 AND username "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")" GROUP BY account.id", - filter.c_str()); - } - - if (!result) - { - PSendSysMessage(LANG_BANLIST_NOACCOUNT); - return true; - } - - return HandleBanListHelper(result); -} - -bool ChatHandler::HandleBanListHelper(QueryResult_AutoPtr result) -{ - PSendSysMessage(LANG_BANLIST_MATCHINGACCOUNT); - - // Chat short output - if (m_session) - { - do - { - Field* fields = result->Fetch(); - uint32 accountid = fields[0].GetUInt32(); - - QueryResult_AutoPtr banresult = LoginDatabase.PQuery("SELECT account.username FROM account,account_banned WHERE account_banned.id='%u' AND account_banned.id=account.id",accountid); - if (banresult) - { - Field* fields2 = banresult->Fetch(); - PSendSysMessage("%s",fields2[0].GetString()); - } - } while (result->NextRow()); - } - // Console wide output - else - { - SendSysMessage(LANG_BANLIST_ACCOUNTS); - SendSysMessage(" ==============================================================================="); - SendSysMessage(LANG_BANLIST_ACCOUNTS_HEADER); - do - { - SendSysMessage("-------------------------------------------------------------------------------"); - Field *fields = result->Fetch(); - uint32 account_id = fields[0].GetUInt32 (); - - std::string account_name; - - // "account" case, name can be get in same query - if (result->GetFieldCount() > 1) - account_name = fields[1].GetCppString(); - // "character" case, name need extract from another DB - else - accmgr.GetName (account_id,account_name); - - // No SQL injection. id is uint32. - QueryResult_AutoPtr banInfo = LoginDatabase.PQuery("SELECT bandate,unbandate,bannedby,banreason FROM account_banned WHERE id = %u ORDER BY unbandate", account_id); - if (banInfo) - { - Field *fields2 = banInfo->Fetch(); - do - { - time_t t_ban = fields2[0].GetUInt64(); - tm* aTm_ban = localtime(&t_ban); - - if (fields2[0].GetUInt64() == fields2[1].GetUInt64()) - { - PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d| permanent |%-15.15s|%-15.15s|", - account_name.c_str(),aTm_ban->tm_year%100, aTm_ban->tm_mon+1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min, - fields2[2].GetString(),fields2[3].GetString()); - } - else - { - time_t t_unban = fields2[1].GetUInt64(); - tm* aTm_unban = localtime(&t_unban); - PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d|%02d-%02d-%02d %02d:%02d|%-15.15s|%-15.15s|", - account_name.c_str(),aTm_ban->tm_year%100, aTm_ban->tm_mon+1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min, - aTm_unban->tm_year%100, aTm_unban->tm_mon+1, aTm_unban->tm_mday, aTm_unban->tm_hour, aTm_unban->tm_min, - fields2[2].GetString(),fields2[3].GetString()); - } - }while (banInfo->NextRow()); - } - }while (result->NextRow()); - SendSysMessage(" ==============================================================================="); - } - return true; -} - -bool ChatHandler::HandleBanListIPCommand(const char *args) -{ - LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate<>bandate"); - - char* cFilter = strtok((char*)args, " "); - std::string filter = cFilter ? cFilter : ""; - LoginDatabase.escape_string(filter); - - QueryResult_AutoPtr result; - - if (filter.empty()) - { - result = LoginDatabase.Query ("SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned" - " WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP())" - " ORDER BY unbandate"); - } - else - { - result = LoginDatabase.PQuery("SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned" - " WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP()) AND ip "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'") - " ORDER BY unbandate",filter.c_str()); - } - - if (!result) - { - PSendSysMessage(LANG_BANLIST_NOIP); - return true; - } - - PSendSysMessage(LANG_BANLIST_MATCHINGIP); - // Chat short output - if (m_session) - { - do - { - Field* fields = result->Fetch(); - PSendSysMessage("%s",fields[0].GetString()); - } while (result->NextRow()); - } - // Console wide output - else - { - SendSysMessage(LANG_BANLIST_IPS); - SendSysMessage(" ==============================================================================="); - SendSysMessage(LANG_BANLIST_IPS_HEADER); - do - { - SendSysMessage("-------------------------------------------------------------------------------"); - Field *fields = result->Fetch(); - time_t t_ban = fields[1].GetUInt64(); - tm* aTm_ban = localtime(&t_ban); - if (fields[1].GetUInt64() == fields[2].GetUInt64()) - { - PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d| permanent |%-15.15s|%-15.15s|", - fields[0].GetString(), aTm_ban->tm_year%100, aTm_ban->tm_mon+1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min, - fields[3].GetString(), fields[4].GetString()); - } - else - { - time_t t_unban = fields[2].GetUInt64(); - tm* aTm_unban = localtime(&t_unban); - PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d|%02d-%02d-%02d %02d:%02d|%-15.15s|%-15.15s|", - fields[0].GetString(), aTm_ban->tm_year%100, aTm_ban->tm_mon+1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min, - aTm_unban->tm_year%100, aTm_unban->tm_mon+1, aTm_unban->tm_mday, aTm_unban->tm_hour, aTm_unban->tm_min, - fields[3].GetString(), fields[4].GetString()); - } - }while (result->NextRow()); - SendSysMessage(" ==============================================================================="); - } - - return true; -} - -bool ChatHandler::HandleRespawnCommand(const char* /*args*/) -{ - Player* pl = m_session->GetPlayer(); - - // accept only explicitly selected target (not implicitly self targeting case) - Unit* target = getSelectedUnit(); - if (pl->GetSelection() && target) - { - if (target->GetTypeId() != TYPEID_UNIT || target->isPet()) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if (target->isDead()) - target->ToCreature()->Respawn(); - return true; - } - - CellPair p(Trinity::ComputeCellPair(pl->GetPositionX(), pl->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - Trinity::RespawnDo u_do; - Trinity::WorldObjectWorker worker(pl,u_do); - - TypeContainerVisitor, GridTypeMapContainer > obj_worker(worker); - cell.Visit(p, obj_worker, *pl->GetMap()); - - return true; -} - -bool ChatHandler::HandleGMFlyCommand(const char *args) -{ - if (!*args) - return false; - - Player *target = getSelectedPlayer(); - if (!target) - target = m_session->GetPlayer(); - - WorldPacket data(12); - if (strncmp(args, "on", 3) == 0) - data.SetOpcode(SMSG_MOVE_SET_CAN_FLY); - else if (strncmp(args, "off", 4) == 0) - data.SetOpcode(SMSG_MOVE_UNSET_CAN_FLY); - else - { - SendSysMessage(LANG_USE_BOL); - return false; - } - data.append(target->GetPackGUID()); - data << uint32(0); // unknown - target->SendMessageToSet(&data, true); - PSendSysMessage(LANG_COMMAND_FLYMODE_STATUS, GetNameLink(target).c_str(), args); - return true; -} - -bool ChatHandler::HandlePDumpLoadCommand(const char *args) -{ - if (!*args) - return false; - - char * file = strtok((char*)args, " "); - if (!file) - return false; - - char * account = strtok(NULL, " "); - if (!account) - return false; - - std::string account_name = account; - if (!AccountMgr::normalizeString(account_name)) - { - PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); - SetSentErrorMessage(true); - return false; - } - - uint32 account_id = accmgr.GetId(account_name); - if (!account_id) - { - account_id = atoi(account); // use original string - if (!account_id) - { - PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); - SetSentErrorMessage(true); - return false; - } - } - - if (!accmgr.GetName(account_id,account_name)) - { - PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); - SetSentErrorMessage(true); - return false; - } - - char* guid_str = NULL; - char* name_str = strtok(NULL, " "); - - std::string name; - if (name_str) - { - name = name_str; - // normalize the name if specified and check if it exists - if (!normalizePlayerName(name)) - { - PSendSysMessage(LANG_INVALID_CHARACTER_NAME); - SetSentErrorMessage(true); - return false; - } - - if (ObjectMgr::CheckPlayerName(name,true) != CHAR_NAME_SUCCESS) - { - PSendSysMessage(LANG_INVALID_CHARACTER_NAME); - SetSentErrorMessage(true); - return false; - } - - guid_str = strtok(NULL, " "); - } - - uint32 guid = 0; - - if (guid_str) - { - guid = atoi(guid_str); - if (!guid) - { - PSendSysMessage(LANG_INVALID_CHARACTER_GUID); - SetSentErrorMessage(true); - return false; - } - - if (objmgr.GetPlayerAccountIdByGUID(guid)) - { - PSendSysMessage(LANG_CHARACTER_GUID_IN_USE,guid); - SetSentErrorMessage(true); - return false; - } - } - - switch(PlayerDumpReader().LoadDump(file, account_id, name, guid)) - { - case DUMP_SUCCESS: - PSendSysMessage(LANG_COMMAND_IMPORT_SUCCESS); - break; - case DUMP_FILE_OPEN_ERROR: - PSendSysMessage(LANG_FILE_OPEN_FAIL,file); - SetSentErrorMessage(true); - return false; - case DUMP_FILE_BROKEN: - PSendSysMessage(LANG_DUMP_BROKEN,file); - SetSentErrorMessage(true); - return false; - case DUMP_TOO_MANY_CHARS: - PSendSysMessage(LANG_ACCOUNT_CHARACTER_LIST_FULL,account_name.c_str(),account_id); - SetSentErrorMessage(true); - return false; - default: - PSendSysMessage(LANG_COMMAND_IMPORT_FAILED); - SetSentErrorMessage(true); - return false; - } - - return true; -} - -bool ChatHandler::HandlePDumpWriteCommand(const char *args) -{ - if (!*args) - return false; - - char* file = strtok((char*)args, " "); - char* p2 = strtok(NULL, " "); - - if (!file || !p2) - return false; - - uint32 guid; - // character name can't start from number - if (isNumeric(p2[0])) - guid = atoi(p2); - else - { - std::string name = extractPlayerNameFromLink(p2); - if (name.empty()) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - guid = objmgr.GetPlayerGUIDByName(name); - } - - if (!objmgr.GetPlayerAccountIdByGUID(guid)) - { - PSendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - switch(PlayerDumpWriter().WriteDump(file, guid)) - { - case DUMP_SUCCESS: - PSendSysMessage(LANG_COMMAND_EXPORT_SUCCESS); - break; - case DUMP_FILE_OPEN_ERROR: - PSendSysMessage(LANG_FILE_OPEN_FAIL,file); - SetSentErrorMessage(true); - return false; - default: - PSendSysMessage(LANG_COMMAND_EXPORT_FAILED); - SetSentErrorMessage(true); - return false; - } - - return true; -} - -bool ChatHandler::HandleMovegensCommand(const char* /*args*/) -{ - Unit* unit = getSelectedUnit(); - if (!unit) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - PSendSysMessage(LANG_MOVEGENS_LIST,(unit->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"),unit->GetGUIDLow()); - - MotionMaster* mm = unit->GetMotionMaster(); - for (uint8 i = 0; i < MAX_MOTION_SLOT; ++i) - { - MovementGenerator* mg = mm->GetMotionSlot(i); - if (!mg) - { - SendSysMessage("Empty"); - continue; - } - switch(mg->GetMovementGeneratorType()) - { - case IDLE_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_IDLE); break; - case RANDOM_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_RANDOM); break; - case WAYPOINT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_WAYPOINT); break; - case ANIMAL_RANDOM_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_ANIMAL_RANDOM); break; - case CONFUSED_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_CONFUSED); break; - case TARGETED_MOTION_TYPE: - { - if (unit->GetTypeId() == TYPEID_PLAYER) - { - TargetedMovementGenerator const* mgen = static_cast const*>(mg); - Unit* target = mgen->GetTarget(); - if (target) - PSendSysMessage(LANG_MOVEGENS_TARGETED_PLAYER,target->GetName(),target->GetGUIDLow()); - else - SendSysMessage(LANG_MOVEGENS_TARGETED_NULL); - } - else - { - TargetedMovementGenerator const* mgen = static_cast const*>(mg); - Unit* target = mgen->GetTarget(); - if (target) - PSendSysMessage(LANG_MOVEGENS_TARGETED_CREATURE,target->GetName(),target->GetGUIDLow()); - else - SendSysMessage(LANG_MOVEGENS_TARGETED_NULL); - } - break; - } - case HOME_MOTION_TYPE: - if (unit->GetTypeId() == TYPEID_UNIT) - { - float x,y,z; - mg->GetDestination(x,y,z); - PSendSysMessage(LANG_MOVEGENS_HOME_CREATURE,x,y,z); - } - else - SendSysMessage(LANG_MOVEGENS_HOME_PLAYER); - break; - case FLIGHT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FLIGHT); break; - case POINT_MOTION_TYPE: - { - float x,y,z; - mg->GetDestination(x,y,z); - PSendSysMessage(LANG_MOVEGENS_POINT,x,y,z); - break; - } - case FLEEING_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FEAR); break; - case DISTRACT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_DISTRACT); break; - default: - PSendSysMessage(LANG_MOVEGENS_UNKNOWN,mg->GetMovementGeneratorType()); - break; - } - } - return true; -} - -bool ChatHandler::HandleServerPLimitCommand(const char *args) -{ - if (*args) - { - char* param = strtok((char*)args, " "); - if (!param) - return false; - - int l = strlen(param); - - if (strncmp(param,"player",l) == 0) - sWorld.SetPlayerSecurityLimit(SEC_PLAYER); - else if (strncmp(param,"moderator",l) == 0) - sWorld.SetPlayerSecurityLimit(SEC_MODERATOR); - else if (strncmp(param,"gamemaster",l) == 0) - sWorld.SetPlayerSecurityLimit(SEC_GAMEMASTER); - else if (strncmp(param,"administrator",l) == 0) - sWorld.SetPlayerSecurityLimit(SEC_ADMINISTRATOR); - else if (strncmp(param,"reset",l) == 0) - sWorld.SetPlayerLimit(sConfig.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT)); - else - { - int val = atoi(param); - if (val < 0) - sWorld.SetPlayerSecurityLimit(AccountTypes(uint32(-val))); - else - sWorld.SetPlayerLimit(val); - } - - // kick all low security level players - if (sWorld.GetPlayerSecurityLimit() > SEC_PLAYER) - sWorld.KickAllLess(sWorld.GetPlayerSecurityLimit()); - } - - uint32 pLimit = sWorld.GetPlayerAmountLimit(); - AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit(); - char const* secName = ""; - switch(allowedAccountType) - { - case SEC_PLAYER: secName = "Player"; break; - case SEC_MODERATOR: secName = "Moderator"; break; - case SEC_GAMEMASTER: secName = "Gamemaster"; break; - case SEC_ADMINISTRATOR: secName = "Administrator"; break; - default: secName = ""; break; - } - - PSendSysMessage("Player limits: amount %u, min. security level %s.",pLimit,secName); - - return true; -} - -bool ChatHandler::HandleCastCommand(const char *args) -{ - if (!*args) - return false; - - Unit* target = getSelectedUnit(); - - if (!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spell = extractSpellIdFromLink((char*)args); - if (!spell) - return false; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); - if (!spellInfo) - { - PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); - SetSentErrorMessage(true); - return false; - } - - if (!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) - { - PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); - SetSentErrorMessage(true); - return false; - } - - char* trig_str = strtok(NULL, " "); - if (trig_str) - { - int l = strlen(trig_str); - if (strncmp(trig_str,"triggered",l) != 0) - return false; - } - - bool triggered = (trig_str != NULL); - - m_session->GetPlayer()->CastSpell(target,spell,triggered); - - return true; -} - -bool ChatHandler::HandleCastBackCommand(const char *args) -{ - Creature* caster = getSelectedCreature(); - - if (!caster) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spell = extractSpellIdFromLink((char*)args); - if (!spell || !sSpellStore.LookupEntry(spell)) - { - PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); - SetSentErrorMessage(true); - return false; - } - - char* trig_str = strtok(NULL, " "); - if (trig_str) - { - int l = strlen(trig_str); - if (strncmp(trig_str,"triggered",l) != 0) - return false; - } - - bool triggered = (trig_str != NULL); - - caster->SetFacingToObject(m_session->GetPlayer()); - - caster->CastSpell(m_session->GetPlayer(),spell,triggered); - - return true; -} - -bool ChatHandler::HandleCastDistCommand(const char *args) -{ - if (!*args) - return false; - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spell = extractSpellIdFromLink((char*)args); - if (!spell) - return false; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); - if (!spellInfo) - { - PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); - SetSentErrorMessage(true); - return false; - } - - if (!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) - { - PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); - SetSentErrorMessage(true); - return false; - } - - char *distStr = strtok(NULL, " "); - - float dist = 0; - - if (distStr) - sscanf(distStr, "%f", &dist); - - char* trig_str = strtok(NULL, " "); - if (trig_str) - { - int l = strlen(trig_str); - if (strncmp(trig_str,"triggered",l) != 0) - return false; - } - - bool triggered = (trig_str != NULL); - - float x,y,z; - m_session->GetPlayer()->GetClosePoint(x,y,z,dist); - - m_session->GetPlayer()->CastSpell(x,y,z,spell,triggered); - return true; -} - -bool ChatHandler::HandleCastTargetCommand(const char *args) -{ - Creature* caster = getSelectedCreature(); - - if (!caster) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if (!caster->getVictim()) - { - SendSysMessage(LANG_SELECTED_TARGET_NOT_HAVE_VICTIM); - SetSentErrorMessage(true); - return false; - } - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spell = extractSpellIdFromLink((char*)args); - if (!spell || !sSpellStore.LookupEntry(spell)) - { - PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); - SetSentErrorMessage(true); - return false; - } - - char* trig_str = strtok(NULL, " "); - if (trig_str) - { - int l = strlen(trig_str); - if (strncmp(trig_str,"triggered",l) != 0) - return false; - } - - bool triggered = (trig_str != NULL); - - caster->SetFacingToObject(m_session->GetPlayer()); - - caster->CastSpell(caster->getVictim(),spell,triggered); - - return true; -} - -/* -ComeToMe command REQUIRED for 3rd party scripting library to have access to PointMovementGenerator -Without this function 3rd party scripting library will get linking errors (unresolved external) -when attempting to use the PointMovementGenerator -*/ -bool ChatHandler::HandleComeToMeCommand(const char *args) -{ - char* newFlagStr = strtok((char*)args, " "); - - if (!newFlagStr) - return false; - - uint32 newFlags = (uint32)strtoul(newFlagStr, NULL, 0); - - Creature* caster = getSelectedCreature(); - if (!caster) - { - m_session->GetPlayer()->SetUnitMovementFlags(newFlags); - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - caster->SetUnitMovementFlags(newFlags); - - Player* pl = m_session->GetPlayer(); - - caster->GetMotionMaster()->MovePoint(0, pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ()); - return true; -} - -bool ChatHandler::HandleCastSelfCommand(const char *args) -{ - if (!*args) - return false; - - Unit* target = getSelectedUnit(); - - if (!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spell = extractSpellIdFromLink((char*)args); - if (!spell) - return false; - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); - if (!spellInfo) - return false; - - if (!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) - { - PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spell); - SetSentErrorMessage(true); - return false; - } - - target->CastSpell(target,spell,false); - - return true; -} - -std::string GetTimeString(uint32 time) -{ - uint16 days = time / DAY, hours = (time % DAY) / HOUR, minute = (time % HOUR) / MINUTE; - std::ostringstream ss; - if (days) ss << days << "d "; - if (hours) ss << hours << "h "; - ss << minute << "m"; - return ss.str(); -} - -bool ChatHandler::HandleInstanceListBindsCommand(const char* /*args*/) -{ - Player* player = getSelectedPlayer(); - if (!player) player = m_session->GetPlayer(); - uint32 counter = 0; - for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) - { - Player::BoundInstancesMap &binds = player->GetBoundInstances(Difficulty(i)); - for (Player::BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end(); ++itr) - { - InstanceSave *save = itr->second.save; - std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); - PSendSysMessage("map: %d inst: %d perm: %s diff: %d canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); - counter++; - } - } - PSendSysMessage("player binds: %d", counter); - counter = 0; - Group *group = player->GetGroup(); - if (group) - { - for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) - { - Group::BoundInstancesMap &binds = group->GetBoundInstances(Difficulty(i)); - for (Group::BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end(); ++itr) - { - InstanceSave *save = itr->second.save; - std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); - PSendSysMessage("map: %d inst: %d perm: %s diff: %d canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); counter++; - } - } - } - PSendSysMessage("group binds: %d", counter); - - return true; -} - -bool ChatHandler::HandleInstanceUnbindCommand(const char *args) -{ - if (!*args) - return false; - - std::string cmd = args; - if (cmd == "all") - { - Player* player = getSelectedPlayer(); - if (!player) player = m_session->GetPlayer(); - uint32 counter = 0; - for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) - { - Player::BoundInstancesMap &binds = player->GetBoundInstances(Difficulty(i)); - for (Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end();) - { - if (itr->first != player->GetMapId()) - { - InstanceSave *save = itr->second.save; - std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); - PSendSysMessage("unbinding map: %d inst: %d perm: %s diff: %d canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); - player->UnbindInstance(itr, Difficulty(i)); - counter++; - } - else - ++itr; - } - } - PSendSysMessage("instances unbound: %d", counter); - } - return true; -} - -bool ChatHandler::HandleInstanceStatsCommand(const char* /*args*/) -{ - PSendSysMessage("instances loaded: %d", MapManager::Instance().GetNumInstances()); - PSendSysMessage("players in instances: %d", MapManager::Instance().GetNumPlayersInInstances()); - PSendSysMessage("instance saves: %d", sInstanceSaveManager.GetNumInstanceSaves()); - PSendSysMessage("players bound: %d", sInstanceSaveManager.GetNumBoundPlayersTotal()); - PSendSysMessage("groups bound: %d", sInstanceSaveManager.GetNumBoundGroupsTotal()); - return true; -} - -bool ChatHandler::HandleInstanceSaveDataCommand(const char * /*args*/) -{ - Player* pl = m_session->GetPlayer(); - - Map* map = pl->GetMap(); - if (!map->IsDungeon()) - { - PSendSysMessage("Map is not a dungeon."); - SetSentErrorMessage(true); - return false; - } - - if (!((InstanceMap*)map)->GetInstanceData()) - { - PSendSysMessage("Map has no instance data."); - SetSentErrorMessage(true); - return false; - } - - ((InstanceMap*)map)->GetInstanceData()->SaveToDB(); - return true; -} - -bool ChatHandler::HandleInstanceOpenCommand(const char *args) -{ - return HandleInstanceOpenCloseCommand(args,true); -} - -bool ChatHandler::HandleInstanceCloseCommand(const char *args) -{ - return HandleInstanceOpenCloseCommand(args,false); -} - -bool ChatHandler::HandleInstanceOpenCloseCommand(const char *args,bool open) -{ - char *mapIdStr; - char *instanceModeStr; - extractOptFirstArg((char*)args,&mapIdStr,&instanceModeStr); - if (!mapIdStr || !instanceModeStr) - return false; - - uint32 mapid = atoi(mapIdStr); - - InstanceTemplate const* instance = objmgr.GetInstanceTemplate(mapid); - if (!instance) - { - PSendSysMessage("Invalid map id"); - SetSentErrorMessage(true); - return false; - } - - uint8 status = objmgr.GetAccessRequirement(instance->access_id)->status; - uint8 flag = 0; - - if (strcmp(instanceModeStr,"normal") || strcmp(instanceModeStr,"10normal")) - flag = DUNGEON_STATUSFLAG_NORMAL; - else if (strcmp(instanceModeStr,"heroic") || strcmp(instanceModeStr,"25normal")) - flag = DUNGEON_STATUSFLAG_HEROIC; - else if (strcmp(instanceModeStr,"10heroic")) - flag = RAID_STATUSFLAG_10MAN_HEROIC; - else if (strcmp(instanceModeStr,"25heroic")) - flag = RAID_STATUSFLAG_25MAN_HEROIC; - else - { - PSendSysMessage("Unrecognized difficulty string"); - SetSentErrorMessage(true); - return false; - } - if (open) - status |= flag; - else - status &= ~flag; - - WorldDatabase.PExecute("UPDATE access_requirement SET status = '%u' WHERE id = '%u'", status, instance->access_id); - PSendSysMessage("Instance status changed. Don't forget to reload access_requirement table"); - return true; -} - -/// Display the list of GMs -bool ChatHandler::HandleGMListFullCommand(const char* /*args*/) -{ - ///- Get the accounts with GM Level >0 - QueryResult_AutoPtr result = LoginDatabase.Query("SELECT a.username,aa.gmlevel FROM account a, account_access aa WHERE a.id=aa.id AND aa.gmlevel > 0"); - if (result) - { - SendSysMessage(LANG_GMLIST); - SendSysMessage(" ======================== "); - SendSysMessage(LANG_GMLIST_HEADER); - SendSysMessage(" ======================== "); - - ///- Circle through them. Display username and GM level - do - { - Field *fields = result->Fetch(); - PSendSysMessage("|%15s|%6s|", fields[0].GetString(),fields[1].GetString()); - }while (result->NextRow()); - - PSendSysMessage(" ======================== "); - } - else - PSendSysMessage(LANG_GMLIST_EMPTY); - return true; -} - -/// Define the 'Message of the day' for the realm -bool ChatHandler::HandleServerSetMotdCommand(const char *args) -{ - sWorld.SetMotd(args); - PSendSysMessage(LANG_MOTD_NEW, args); - return true; -} - -/// Set whether we accept new clients -bool ChatHandler::HandleServerSetClosedCommand(const char *args) -{ - std::string arg = args; - - if (strncmp(args, "on", 3) == 0) - { - SendSysMessage(LANG_WORLD_CLOSED); - sWorld.SetClosed(true); - return true; - } - else if (strncmp(args, "off", 4) == 0) - { - SendSysMessage(LANG_WORLD_OPENED); - sWorld.SetClosed(false); - return true; - } - - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; -} - -/// Set/Unset the expansion level for an account -bool ChatHandler::HandleAccountSetAddonCommand(const char *args) -{ - ///- Get the command line arguments - char *szAcc = strtok((char*)args," "); - char *szExp = strtok(NULL," "); - - if (!szAcc) - return false; - - std::string account_name; - uint32 account_id; - - if (!szExp) - { - Player* player = getSelectedPlayer(); - if (!player) - return false; - - account_id = player->GetSession()->GetAccountId(); - accmgr.GetName(account_id,account_name); - szExp = szAcc; - } - else - { - ///- Convert Account name to Upper Format - account_name = szAcc; - if (!AccountMgr::normalizeString(account_name)) - { - PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); - SetSentErrorMessage(true); - return false; - } - - account_id = accmgr.GetId(account_name); - if (!account_id) - { - PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str()); - SetSentErrorMessage(true); - return false; - } - - } - - // Let set addon state only for lesser (strong) security level - // or to self account - if (m_session && m_session->GetAccountId () != account_id && - HasLowerSecurityAccount (NULL,account_id,true)) - return false; - - int expansion = atoi(szExp); //get int anyway (0 if error) - if (expansion < 0 || expansion > sWorld.getConfig(CONFIG_EXPANSION)) - return false; - - // No SQL injection - LoginDatabase.PExecute("UPDATE account SET expansion = '%d' WHERE id = '%u'",expansion,account_id); - PSendSysMessage(LANG_ACCOUNT_SETADDON,account_name.c_str(),account_id,expansion); - return true; -} - -//Send items by mail -bool ChatHandler::HandleSendItemsCommand(const char *args) -{ - // format: name "subject text" "mail text" item1[:count1] item2[:count2] ... item12[:count12] - Player* receiver; - uint64 receiver_guid; - std::string receiver_name; - if (!extractPlayerTarget((char*)args,&receiver,&receiver_guid,&receiver_name)) - return false; - - char* tail1 = strtok(NULL, ""); - if (!tail1) - return false; - - char* msgSubject = extractQuotedArg(tail1); - if (!msgSubject) - return false; - - char* tail2 = strtok(NULL, ""); - if (!tail2) - return false; - - char* msgText = extractQuotedArg(tail2); - if (!msgText) - return false; - - // msgSubject, msgText isn't NUL after prev. check - std::string subject = msgSubject; - std::string text = msgText; - - // extract items - typedef std::pair ItemPair; - typedef std::list< ItemPair > ItemPairs; - ItemPairs items; - - // get all tail string - char* tail = strtok(NULL, ""); - - // get from tail next item str - while (char* itemStr = strtok(tail, " ")) - { - // and get new tail - tail = strtok(NULL, ""); - - // parse item str - char* itemIdStr = strtok(itemStr, ":"); - char* itemCountStr = strtok(NULL, " "); - - uint32 item_id = atoi(itemIdStr); - if (!item_id) - return false; - - ItemPrototype const* item_proto = objmgr.GetItemPrototype(item_id); - if (!item_proto) - { - PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, item_id); - SetSentErrorMessage(true); - return false; - } - - uint32 item_count = itemCountStr ? atoi(itemCountStr) : 1; - if (item_count < 1 || (item_proto->MaxCount > 0 && item_count > uint32(item_proto->MaxCount))) - { - PSendSysMessage(LANG_COMMAND_INVALID_ITEM_COUNT, item_count,item_id); - SetSentErrorMessage(true); - return false; - } - - while (item_count > item_proto->GetMaxStackSize()) - { - items.push_back(ItemPair(item_id,item_proto->GetMaxStackSize())); - item_count -= item_proto->GetMaxStackSize(); - } - - items.push_back(ItemPair(item_id,item_count)); - - if (items.size() > MAX_MAIL_ITEMS) - { - PSendSysMessage(LANG_COMMAND_MAIL_ITEMS_LIMIT, MAX_MAIL_ITEMS); - SetSentErrorMessage(true); - return false; - } - } - - // from console show not existed sender - MailSender sender(MAIL_NORMAL,m_session ? m_session->GetPlayer()->GetGUIDLow() : 0, MAIL_STATIONERY_GM); - - // fill mail - MailDraft draft(subject, text); - - for (ItemPairs::const_iterator itr = items.begin(); itr != items.end(); ++itr) - { - if (Item* item = Item::CreateItem(itr->first,itr->second,m_session ? m_session->GetPlayer() : 0)) - { - item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted - draft.AddItem(item); - } - } - - draft.SendMailTo(MailReceiver(receiver,GUID_LOPART(receiver_guid)), sender); - - std::string nameLink = playerLink(receiver_name); - PSendSysMessage(LANG_MAIL_SENT, nameLink.c_str()); - return true; -} - -///Send money by mail -bool ChatHandler::HandleSendMoneyCommand(const char *args) -{ - /// format: name "subject text" "mail text" money - - Player* receiver; - uint64 receiver_guid; - std::string receiver_name; - if (!extractPlayerTarget((char*)args,&receiver,&receiver_guid,&receiver_name)) - return false; - - char* tail1 = strtok(NULL, ""); - if (!tail1) - return false; - - char* msgSubject = extractQuotedArg(tail1); - if (!msgSubject) - return false; - - char* tail2 = strtok(NULL, ""); - if (!tail2) - return false; - - char* msgText = extractQuotedArg(tail2); - if (!msgText) - return false; - - char* money_str = strtok(NULL, ""); - int32 money = money_str ? atoi(money_str) : 0; - if (money <= 0) - return false; - - // msgSubject, msgText isn't NUL after prev. check - std::string subject = msgSubject; - std::string text = msgText; - - // from console show not existed sender - MailSender sender(MAIL_NORMAL,m_session ? m_session->GetPlayer()->GetGUIDLow() : 0, MAIL_STATIONERY_GM); - - MailDraft(subject, text) - .AddMoney(money) - .SendMailTo(MailReceiver(receiver,GUID_LOPART(receiver_guid)),sender); - - std::string nameLink = playerLink(receiver_name); - PSendSysMessage(LANG_MAIL_SENT, nameLink.c_str()); - return true; -} - -/// Send a message to a player in game -bool ChatHandler::HandleSendMessageCommand(const char *args) -{ - ///- Find the player - Player *rPlayer; - if (!extractPlayerTarget((char*)args, &rPlayer)) - return false; - - char* msg_str = strtok(NULL, ""); - if (!msg_str) - return false; - - ///- Check that he is not logging out. - if (rPlayer->GetSession()->isLogingOut()) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - ///- Send the message - //Use SendAreaTriggerMessage for fastest delivery. - rPlayer->GetSession()->SendAreaTriggerMessage("%s", msg_str); - rPlayer->GetSession()->SendAreaTriggerMessage("|cffff0000[Message from administrator]:|r"); - - //Confirmation message - std::string nameLink = GetNameLink(rPlayer); - PSendSysMessage(LANG_SENDMESSAGE,nameLink.c_str(),msg_str); - return true; -} - -bool ChatHandler::HandleFlushArenaPointsCommand(const char * /*args*/) -{ - sBattleGroundMgr.DistributeArenaPoints(); - return true; -} - -bool ChatHandler::HandleModifyGenderCommand(const char *args) -{ - if (!*args) - return false; - - Player *player = getSelectedPlayer(); - - if (!player) - { - PSendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } - - PlayerInfo const* info = objmgr.GetPlayerInfo(player->getRace(), player->getClass()); - if (!info) - return false; - - char const* gender_str = (char*)args; - int gender_len = strlen(gender_str); - - Gender gender; - - if (!strncmp(gender_str, "male", gender_len)) // MALE - { - if (player->getGender() == GENDER_MALE) - return true; - - gender = GENDER_MALE; - } - else if (!strncmp(gender_str, "female", gender_len)) // FEMALE - { - if (player->getGender() == GENDER_FEMALE) - return true; - - gender = GENDER_FEMALE; - } - else - { - SendSysMessage(LANG_MUST_MALE_OR_FEMALE); - SetSentErrorMessage(true); - return false; - } - - // Set gender - player->SetByteValue(UNIT_FIELD_BYTES_0, 2, gender); - player->SetByteValue(PLAYER_BYTES_3, 0, gender); - - // Change display ID - player->InitDisplayIds(); - - char const* gender_full = gender ? "female" : "male"; - - PSendSysMessage(LANG_YOU_CHANGE_GENDER, GetNameLink(player).c_str(), gender_full); - - if (needReportToTarget(player)) - ChatHandler(player).PSendSysMessage(LANG_YOUR_GENDER_CHANGED, gender_full, GetNameLink().c_str()); - - return true; -} - -bool ChatHandler::HandleChannelSetPublic(const char *args) -{ - if (!*args) - return false; - std::string channel = strtok((char*)args, " "); - uint32 val = atoi((char*)args); - - if (val) - { - CharacterDatabase.PExecute("UPDATE channels SET m_public = 1 WHERE m_name LIKE '%s'", channel.c_str()); - val = 1; - } - else - { - CharacterDatabase.PExecute("UPDATE channels SET m_public = 0 WHERE m_name LIKE '%s'", channel.c_str()); - val = 0; - } - - PSendSysMessage(LANG_CHANNEL_PUBLIC_CHANGED, channel.c_str(), val); - - return true; -} - - -/*------------------------------------------ - *-------------TRINITY---------------------- - *-------------------------------------*/ - -bool ChatHandler::HandlePlayAllCommand(const char *args) -{ - if (!*args) - return false; - - uint32 soundId = atoi((char*)args); - - if (!sSoundEntriesStore.LookupEntry(soundId)) - { - PSendSysMessage(LANG_SOUND_NOT_EXIST, soundId); - SetSentErrorMessage(true); - return false; - } - - WorldPacket data(SMSG_PLAY_SOUND, 4); - data << uint32(soundId) << m_session->GetPlayer()->GetGUID(); - sWorld.SendGlobalMessage(&data); - - PSendSysMessage(LANG_COMMAND_PLAYED_TO_ALL, soundId); - return true; -} - -bool ChatHandler::HandleFreezeCommand(const char *args) -{ - std::string name; - Player *player; - char *TargetName = strtok((char*)args, " "); //get entered name - if (!TargetName) //if no name entered use target - { - player = getSelectedPlayer(); - if (player) //prevent crash with creature as target - { - name = player->GetName(); - normalizePlayerName(name); - } - } - else // if name entered - { - name = TargetName; - normalizePlayerName(name); - player = objmgr.GetPlayer(name.c_str()); //get player by name - } - - if (!player) - { - SendSysMessage(LANG_COMMAND_FREEZE_WRONG); - return true; - } - - if (player == m_session->GetPlayer()) - { - SendSysMessage(LANG_COMMAND_FREEZE_ERROR); - return true; - } - - //effect - if (player && player != m_session->GetPlayer()) - { - PSendSysMessage(LANG_COMMAND_FREEZE,name.c_str()); - - //stop combat + make player unattackable + duel stop + stop some spells - player->setFaction(35); - player->CombatStop(); - if (player->IsNonMeleeSpellCasted(true)) - player->InterruptNonMeleeSpells(true); - player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - player->SetUInt32Value(PLAYER_DUEL_TEAM, 1); - - //if player class = hunter || warlock remove pet if alive - if ((player->getClass() == CLASS_HUNTER) || (player->getClass() == CLASS_WARLOCK)) - { - if (Pet *pet = player->GetPet()) - { - pet->SavePetToDB(PET_SAVE_AS_CURRENT); - // not let dismiss dead pet - if (pet && pet->isAlive()) - player->RemovePet(pet,PET_SAVE_NOT_IN_SLOT); - } - } - - //m_session->GetPlayer()->CastSpell(player,spellID,false); - if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(9454)) - Aura::TryCreate(spellInfo, player, player); - - //save player - player->SaveToDB(); - } - return true; -} - -bool ChatHandler::HandleUnFreezeCommand(const char *args) -{ - std::string name; - Player *player; - char *TargetName = strtok((char*)args, " "); //get entered name - if (!TargetName) //if no name entered use target - { - player = getSelectedPlayer(); - if (player) //prevent crash with creature as target - name = player->GetName(); - } - - else // if name entered - { - name = TargetName; - normalizePlayerName(name); - player = objmgr.GetPlayer(name.c_str()); //get player by name - } - - //effect - if (player) - { - PSendSysMessage(LANG_COMMAND_UNFREEZE,name.c_str()); - - //Reset player faction + allow combat + allow duels - player->setFactionForRace(player->getRace()); - player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - //allow movement and spells - player->RemoveAurasDueToSpell(9454); - - //save player - player->SaveToDB(); - } - - if (!player) - { - if (TargetName) - { - //check for offline players - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT characters.guid FROM characters WHERE characters.name = '%s'",name.c_str()); - if (!result) - { - SendSysMessage(LANG_COMMAND_FREEZE_WRONG); - return true; - } - //if player found: delete his freeze aura - Field *fields=result->Fetch(); - uint64 pguid = fields[0].GetUInt64(); - - CharacterDatabase.PQuery("DELETE FROM character_aura WHERE character_aura.spell = 9454 AND character_aura.guid = '%u'",pguid); - PSendSysMessage(LANG_COMMAND_UNFREEZE,name.c_str()); - return true; - } - else - { - SendSysMessage(LANG_COMMAND_FREEZE_WRONG); - return true; - } - } - - return true; -} - -bool ChatHandler::HandleListFreezeCommand(const char * /*args*/) -{ - //Get names from DB - QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT characters.name FROM characters LEFT JOIN character_aura ON (characters.guid = character_aura.guid) WHERE character_aura.spell = 9454"); - if (!result) - { - SendSysMessage(LANG_COMMAND_NO_FROZEN_PLAYERS); - return true; - } - //Header of the names - PSendSysMessage(LANG_COMMAND_LIST_FREEZE); - - //Output of the results - do - { - Field *fields = result->Fetch(); - std::string fplayers = fields[0].GetCppString(); - PSendSysMessage(LANG_COMMAND_FROZEN_PLAYERS,fplayers.c_str()); - } while (result->NextRow()); - - return true; -} - -bool ChatHandler::HandleGroupLeaderCommand(const char *args) -{ - Player* plr = NULL; - Group* group = NULL; - uint64 guid = 0; - char* cname = strtok((char*)args, " "); - - if (GetPlayerGroupAndGUIDByName(cname, plr, group, guid)) - if (group && group->GetLeaderGUID() != guid) - group->ChangeLeader(guid); - - return true; -} - -bool ChatHandler::HandleGroupDisbandCommand(const char *args) -{ - Player* plr = NULL; - Group* group = NULL; - uint64 guid = 0; - char* cname = strtok((char*)args, " "); - - if (GetPlayerGroupAndGUIDByName(cname, plr, group, guid)) - if (group) - group->Disband(); - - return true; -} - -bool ChatHandler::HandleGroupRemoveCommand(const char *args) -{ - Player* plr = NULL; - Group* group = NULL; - uint64 guid = 0; - char* cname = strtok((char*)args, " "); - - if (GetPlayerGroupAndGUIDByName(cname, plr, group, guid, true)) - if (group) - group->RemoveMember(guid, 0); - - return true; -} - -bool ChatHandler::HandlePossessCommand(const char * /*args*/) -{ - Unit *pUnit = getSelectedUnit(); - if (!pUnit) - return false; - - m_session->GetPlayer()->CastSpell(pUnit, 530, true); - return true; -} - -bool ChatHandler::HandleUnPossessCommand(const char * /*args*/) -{ - Unit *pUnit = getSelectedUnit(); - if (!pUnit) - pUnit = m_session->GetPlayer(); - - pUnit->RemoveCharmAuras(); - - return true; -} - -bool ChatHandler::HandleBindSightCommand(const char * /*args*/) -{ - Unit *pUnit = getSelectedUnit(); - if (!pUnit) - return false; - - m_session->GetPlayer()->CastSpell(pUnit, 6277, true); - return true; -} - -bool ChatHandler::HandleUnbindSightCommand(const char * /*args*/) -{ - if (m_session->GetPlayer()->isPossessing()) - return false; - - m_session->GetPlayer()->StopCastingBindSight(); - return true; -} diff --git a/src/server/game/Combat/CombatHandler.cpp b/src/server/game/Combat/CombatHandler.cpp deleted file mode 100644 index 404b70c1c84..00000000000 --- a/src/server/game/Combat/CombatHandler.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Log.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "ObjectAccessor.h" -#include "CreatureAI.h" -#include "ObjectDefines.h" - -void WorldSession::HandleAttackSwingOpcode(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - - DEBUG_LOG("WORLD: Recvd CMSG_ATTACKSWING Message guidlow:%u guidhigh:%u", GUID_LOPART(guid), GUID_HIPART(guid)); - - Unit *pEnemy = ObjectAccessor::GetUnit(*_player, guid); - - if (!pEnemy) - { - if (!IS_UNIT_GUID(guid)) - sLog.outError("WORLD: Object %u (TypeID: %u) isn't player, pet or creature",GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(guid))); - else - sLog.outError("WORLD: Enemy %s %u not found",GetLogNameForGuid(guid),GUID_LOPART(guid)); - - // stop attack state at client - SendAttackStop(NULL); - return; - } - - if (!_player->canAttack(pEnemy)) - { - sLog.outError("WORLD: Enemy %s %u is friendly",(IS_PLAYER_GUID(guid) ? "player" : "creature"),GUID_LOPART(guid)); - - // stop attack state at client - SendAttackStop(pEnemy); - return; - } - - _player->Attack(pEnemy,true); -} - -void WorldSession::HandleAttackStopOpcode(WorldPacket & /*recv_data*/) -{ - GetPlayer()->AttackStop(); -} - -void WorldSession::HandleSetSheathedOpcode(WorldPacket & recv_data) -{ - uint32 sheathed; - recv_data >> sheathed; - - //sLog.outDebug("WORLD: Recvd CMSG_SETSHEATHED Message guidlow:%u value1:%u", GetPlayer()->GetGUIDLow(), sheathed); - - if (sheathed >= MAX_SHEATH_STATE) - { - sLog.outError("Unknown sheath state %u ??",sheathed); - return; - } - - GetPlayer()->SetSheath(SheathState(sheathed)); -} - -void WorldSession::SendAttackStop(Unit const* enemy) -{ - WorldPacket data(SMSG_ATTACKSTOP, (4+20)); // we guess size - data.append(GetPlayer()->GetPackGUID()); - data.append(enemy ? enemy->GetPackGUID() : 0); // must be packed guid - data << uint32(0); // unk, can be 1 also - SendPacket(&data); -} - diff --git a/src/server/game/Combat/UnitEvents.h b/src/server/game/Combat/UnitEvents.h new file mode 100644 index 00000000000..a218e0dd34d --- /dev/null +++ b/src/server/game/Combat/UnitEvents.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _UNITEVENTS +#define _UNITEVENTS + +#include "Common.h" + +class ThreatContainer; +class ThreatManager; +class HostileReference; + +//============================================================== +//============================================================== + +enum UNIT_EVENT_TYPE +{ + // Player/Pet changed on/offline status + UEV_THREAT_REF_ONLINE_STATUS = 1<<0, + + // Threat for Player/Pet changed + UEV_THREAT_REF_THREAT_CHANGE = 1<<1, + + // Player/Pet will be removed from list (dead) [for internal use] + UEV_THREAT_REF_REMOVE_FROM_LIST = 1<<2, + + // Player/Pet entered/left water or some other place where it is/was not accessible for the creature + UEV_THREAT_REF_ASSECCIBLE_STATUS = 1<<3, + + // Threat list is going to be sorted (if dirty flag is set) + UEV_THREAT_SORT_LIST = 1<<4, + + // New target should be fetched, could tbe the current target as well + UEV_THREAT_SET_NEXT_TARGET = 1<<5, + + // A new victim (target) was set. Could be NULL + UEV_THREAT_VICTIM_CHANGED = 1<<6, + + // Future use + //UEV_UNIT_KILLED = 1<<7, + + //Future use + //UEV_UNIT_HEALTH_CHANGE = 1<<8, +}; + +#define UEV_THREAT_REF_EVENT_MASK (UEV_THREAT_REF_ONLINE_STATUS | UEV_THREAT_REF_THREAT_CHANGE | UEV_THREAT_REF_REMOVE_FROM_LIST | UEV_THREAT_REF_ASSECCIBLE_STATUS) +#define UEV_THREAT_MANAGER_EVENT_MASK (UEV_THREAT_SORT_LIST | UEV_THREAT_SET_NEXT_TARGET | UEV_THREAT_VICTIM_CHANGED) +#define UEV_ALL_EVENT_MASK (0xffffffff) + +// Future use +//#define UEV_UNIT_EVENT_MASK (UEV_UNIT_KILLED | UEV_UNIT_HEALTH_CHANGE) + +//============================================================== + +class UnitBaseEvent +{ + private: + uint32 iType; + public: + UnitBaseEvent(uint32 pType) { iType = pType; } + uint32 getType() const { return iType; } + bool matchesTypeMask(uint32 pMask) const { return iType & pMask; } + + void setType(uint32 pType) { iType = pType; } + +}; + +//============================================================== + +class ThreatRefStatusChangeEvent : public UnitBaseEvent +{ + private: + HostileReference* iHostileReference; + union + { + float iFValue; + int32 iIValue; + bool iBValue; + }; + ThreatManager* iThreatManager; + public: + ThreatRefStatusChangeEvent(uint32 pType) : UnitBaseEvent(pType) { iHostileReference = NULL; } + + ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference) : UnitBaseEvent(pType) { iHostileReference = pHostileReference; } + + ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference, float pValue) : UnitBaseEvent(pType) { iHostileReference = pHostileReference; iFValue = pValue; } + + ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference, bool pValue) : UnitBaseEvent(pType) { iHostileReference = pHostileReference; iBValue = pValue; } + + int32 getIValue() const { return iIValue; } + + float getFValue() const { return iFValue; } + + bool getBValue() const { return iBValue; } + + void setBValue(bool pValue) { iBValue = pValue; } + + HostileReference* getReference() const { return iHostileReference; } + + void setThreatManager(ThreatManager* pThreatManager) { iThreatManager = pThreatManager; } + + ThreatManager* getThreatManager() const { return iThreatManager; } +}; + +//============================================================== + +class ThreatManagerEvent : public ThreatRefStatusChangeEvent +{ + private: + ThreatContainer* iThreatContainer; + public: + ThreatManagerEvent(uint32 pType) : ThreatRefStatusChangeEvent(pType) {} + ThreatManagerEvent(uint32 pType, HostileReference* pHostileReference) : ThreatRefStatusChangeEvent(pType, pHostileReference) {} + + void setThreatContainer(ThreatContainer* pThreatContainer) { iThreatContainer = pThreatContainer; } + + ThreatContainer* getThreatContainer() const { return iThreatContainer; } +}; + +//============================================================== +#endif + diff --git a/src/server/game/ConditionMgr/ConditionMgr.cpp b/src/server/game/ConditionMgr/ConditionMgr.cpp deleted file mode 100644 index 8e5a7e5677e..00000000000 --- a/src/server/game/ConditionMgr/ConditionMgr.cpp +++ /dev/null @@ -1,1145 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "Policies/SingletonImp.h" -#include "Player.h" -#include "SpellAuras.h" -#include "SpellMgr.h" -#include "GameEventMgr.h" -#include "ObjectMgr.h" -#include "ProgressBar.h" -#include "InstanceData.h" -#include "ConditionMgr.h" - -INSTANTIATE_SINGLETON_1(ConditionMgr); - -// Checks if player meets the condition -// Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: eventAI) -bool Condition::Meets(Player * player, Unit* targetOverride) -{ - if (!player) - { - sLog.outDebug("Condition player not found"); - return false; // player not present, return false - } - uint32 refId = 0; - bool condMeets = false; - bool sendErrorMsg = false; - refId = mConditionValue3;//value 3 can be a 'quick' reference - switch (mConditionType) - { - case CONDITION_NONE: - condMeets = true; // empty condition, always met - break; - case CONDITION_AURA: - condMeets = player->HasAuraEffect(mConditionValue1, mConditionValue2); - break; - case CONDITION_ITEM: - condMeets = player->HasItemCount(mConditionValue1, mConditionValue2); - break; - case CONDITION_ITEM_EQUIPPED: - condMeets = player->HasItemOrGemWithIdEquipped(mConditionValue1,1); - break; - case CONDITION_ZONEID: - condMeets = player->GetZoneId() == mConditionValue1; - break; - case CONDITION_REPUTATION_RANK: - { - FactionEntry const* faction = sFactionStore.LookupEntry(mConditionValue1); - condMeets = faction && uint32(player->GetReputationMgr().GetRank(faction)) >= int32(mConditionValue2); - break; - } - case CONDITION_ACHIEVEMENT: - { - AchievementEntry const* achievement = GetAchievementStore()->LookupEntry(mConditionValue1); - condMeets = player->GetAchievementMgr().HasAchieved(achievement); - break; - } - case CONDITION_TEAM: - condMeets = player->GetTeam() == mConditionValue1; - break; - case CONDITION_CLASS: - condMeets = player->getClass() == mConditionValue1; - break; - case CONDITION_RACE: - condMeets = player->getRace() == mConditionValue1; - break; - case CONDITION_SKILL: - condMeets = player->HasSkill(mConditionValue1) && player->GetBaseSkillValue(mConditionValue1) >= mConditionValue2; - break; - case CONDITION_QUESTREWARDED: - condMeets = player->GetQuestRewardStatus(mConditionValue1); - break; - case CONDITION_QUESTTAKEN: - { - QuestStatus status = player->GetQuestStatus(mConditionValue1); - condMeets = (status == QUEST_STATUS_INCOMPLETE); - break; - } - case CONDITION_QUEST_NONE: - { - QuestStatus status = player->GetQuestStatus(mConditionValue1); - condMeets = (status == QUEST_STATUS_NONE); - break; - } - case CONDITION_AD_COMMISSION_AURA: - { - Unit::AuraApplicationMap const& auras = player->GetAppliedAuras(); - for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - if ((itr->second->GetBase()->GetSpellProto()->Attributes & 0x1000010) && itr->second->GetBase()->GetSpellProto()->SpellVisual[0] == 3580) - { - condMeets = true; - break; - } - condMeets = false; - break; - } - case CONDITION_NO_AURA: - condMeets = !player->HasAuraEffect(mConditionValue1, mConditionValue2); - break; - case CONDITION_ACTIVE_EVENT: - condMeets = gameeventmgr.IsActiveEvent(mConditionValue1); - break; - case CONDITION_INSTANCE_DATA: - { - Map *map = player->GetMap(); - if (map && map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData()) - condMeets = ((InstanceMap*)map)->GetInstanceData()->GetData(mConditionValue1) == mConditionValue2; - break; - } - case CONDITION_SPELL_SCRIPT_TARGET: - condMeets = true;//spell target condition is handled in spellsystem, here it is always true - refId = 0;//cant have references! use CONDITION_SOURCE_TYPE_SPELL for it - break; - case CONDITION_CREATURE_TARGET: - { - Unit* target = player->GetSelectedUnit(); - if (targetOverride) - target = targetOverride; - if (target) - if (Creature* cTarget = target->ToCreature()) - if (cTarget->GetEntry() == mConditionValue1) - condMeets = true; - break; - } - case CONDITION_TARGET_HEALTH_BELOW_PCT: - { - Unit* target = player->GetSelectedUnit(); - if (targetOverride) - target = targetOverride; - if (target) - if ((target->GetHealth()*100 / target->GetMaxHealth()) <= mConditionValue1) - condMeets = true; - break; - } - case CONDITION_TARGET_RANGE: - { - if (Unit* target = player->GetSelectedUnit()) - if (player->GetDistance(target) >= mConditionValue1 && (!mConditionValue2 || player->GetDistance(target) <= mConditionValue2)) - condMeets = true; - break; - } - case CONDITION_MAPID: - condMeets = player->GetMapId() == mConditionValue1; - break; - case CONDITION_AREAID: - condMeets = player->GetAreaId() == mConditionValue1; - break; - case CONDITION_ITEM_TARGET: - { - condMeets = true;//handled in Item::IsTargetValidForItemUse - refId = 0;//cant have references for now - break; - } - default: - condMeets = false; - refId = 0; - break; - } - switch (mSourceType) - { - case CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET: - case CONDITION_SOURCE_TYPE_SPELL: - sendErrorMsg = true; - break; - } - - bool refMeets = false; - if (condMeets && refId)//only have to check references if 'this' is met - { - ConditionList ref = sConditionMgr.GetConditionReferences(refId); - refMeets = sConditionMgr.IsPlayerMeetToConditions(player, ref); - }else refMeets = true; - - if (sendErrorMsg && ErrorTextd && (!condMeets || !refMeets))//send special error from DB - player->m_ConditionErrorMsgId = ErrorTextd; - - return condMeets && refMeets; -} - -ConditionMgr::ConditionMgr() -{ -} - -ConditionMgr::~ConditionMgr() -{ -} - -ConditionList ConditionMgr::GetConditionReferences(uint32 refId) -{ - ConditionList conditions; - ConditionReferenceMap::const_iterator ref = m_ConditionReferenceMap.find(refId); - if (ref != m_ConditionReferenceMap.end()) - conditions = (*ref).second; - return conditions; -} - -bool ConditionMgr::IsPlayerMeetToConditionList(Player* player,const ConditionList& conditions, Unit* targetOverride) -{ - std::mapElseGroupMap; - for (ConditionList::const_iterator i = conditions.begin(); i != conditions.end(); ++i) - { - sLog.outDebug("ConditionMgr::IsPlayerMeetToConditionList condType: %u val1: %u",(*i)->mConditionType,(*i)->mConditionValue1); - if ((*i)->isLoaded()) - { - std::map::const_iterator itr = ElseGroupMap.find((*i)->mElseGroup); - if (itr == ElseGroupMap.end()) - ElseGroupMap[(*i)->mElseGroup] = true; - else if (!(*itr).second) - continue; - - if ((*i)->mReferenceId)//handle reference - { - ConditionReferenceMap::const_iterator ref = m_ConditionReferenceMap.find((*i)->mReferenceId); - if (ref != m_ConditionReferenceMap.end()) - { - if(!IsPlayerMeetToConditionList(player, (*ref).second, targetOverride)) - ElseGroupMap[(*i)->mElseGroup] = false; - }else{ - sLog.outDebug("IsPlayerMeetToConditionList: Reference template -%u not found", (*i)->mReferenceId);//checked at loading, should never happen - } - - } else//handle normal condition - { - if (!(*i)->Meets(player, targetOverride)) - ElseGroupMap[(*i)->mElseGroup] = false; - } - } - } - for (std::map::const_iterator i = ElseGroupMap.begin(); i != ElseGroupMap.end(); ++i) - if (i->second) - return true; - return false; -} - -bool ConditionMgr::IsPlayerMeetToConditions(Player* player, ConditionList conditions, Unit* targetOverride) -{ - if (conditions.empty()) - return true; - if(player) - player->m_ConditionErrorMsgId = 0; - - sLog.outDebug("ConditionMgr::IsPlayerMeetToConditions"); - bool result = IsPlayerMeetToConditionList(player, conditions, targetOverride); - - if (player && player->m_ConditionErrorMsgId && player->GetSession()) - player->GetSession()->SendNotification(player->m_ConditionErrorMsgId);//m_ConditionErrorMsgId is set only if a condition was not met - - return result; -} - -ConditionList ConditionMgr::GetConditionsForNotGroupedEntry(ConditionSourceType sType, uint32 uEntry) -{ - ConditionList spellCond; - if (sType > CONDITION_SOURCE_TYPE_NONE && sType < MAX_CONDITIONSOURCETYPE) - { - ConditionMap::const_iterator itr = m_ConditionMap.find(sType); - if (itr != m_ConditionMap.end()) - { - ConditionTypeMap::const_iterator i = (*itr).second.find(uEntry); - if (i != (*itr).second.end()) - { - spellCond = (*i).second; - sLog.outDebug("GetConditionsForNotGroupedEntry: found conditions for type %u and entry %u", uint32(sType), uEntry); - } - } - } - return spellCond; -} - -void ConditionMgr::LoadConditions(bool isReload) -{ - m_ConditionMap.clear(); // for reload case - m_ConditionReferenceMap.clear(); // for reload case - //must clear all custom handled cases (groupped types) before reload - if (isReload) - { - sLog.outString("Reseting Loot Conditions..."); - LootTemplates_Creature.ResetConditions(); - LootTemplates_Fishing.ResetConditions(); - LootTemplates_Gameobject.ResetConditions(); - LootTemplates_Item.ResetConditions(); - LootTemplates_Mail.ResetConditions(); - LootTemplates_Milling.ResetConditions(); - LootTemplates_Pickpocketing.ResetConditions(); - LootTemplates_Reference.ResetConditions(); - LootTemplates_Skinning.ResetConditions(); - LootTemplates_Disenchant.ResetConditions(); - LootTemplates_Prospecting.ResetConditions(); - LootTemplates_Spell.ResetConditions(); - - sLog.outString("Re-Loading `gossip_menu` Table for Conditions!"); - objmgr.LoadGossipMenu(); - - sLog.outString("Re-Loading `gossip_menu_option` Table for Conditions!"); - objmgr.LoadGossipMenuItems(); - } - - uint32 count = 0; - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, ElseGroup, ConditionTypeOrReference, ConditionValue1, ConditionValue2, ConditionValue3, ErrorTextId FROM conditions"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded `conditions`, table is empty!"); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - bar.step(); - - Field *fields = result->Fetch(); - - Condition* cond = new Condition(); - int32 iSourceTypeOrReferenceId = fields[0].GetInt32(); - cond->mSourceGroup = fields[1].GetUInt32(); - cond->mSourceEntry = fields[2].GetUInt32(); - cond->mElseGroup = fields[3].GetUInt32(); - int32 iConditionTypeOrReference = fields[4].GetInt32(); - cond->mConditionValue1 = fields[5].GetUInt32(); - cond->mConditionValue2 = fields[6].GetUInt32(); - cond->mConditionValue3 = fields[7].GetUInt32(); - cond->ErrorTextd = fields[8].GetUInt32(); - - if (iConditionTypeOrReference >= 0) - cond->mConditionType = ConditionType(iConditionTypeOrReference); - - if (iConditionTypeOrReference < 0)//it has a reference - { - if (iConditionTypeOrReference == iSourceTypeOrReferenceId)//self referencing, skipp - { - sLog.outErrorDb("Condition reference %i is referencing self, skipped", iSourceTypeOrReferenceId); - continue; - } - cond->mReferenceId = uint32(abs(iConditionTypeOrReference)); - - const char* rowType = "reference template"; - if (iSourceTypeOrReferenceId >= 0) - rowType = "reference"; - //check for useless data - if (cond->mConditionValue1) - sLog.outErrorDb("Condition %s %i has useless data in value1 (%u)!", rowType, iSourceTypeOrReferenceId, cond->mConditionValue1); - if (cond->mConditionValue2) - sLog.outErrorDb("Condition %s %i has useless data in value2 (%u)!", rowType, iSourceTypeOrReferenceId, cond->mConditionValue2); - if (cond->mConditionValue3) - sLog.outErrorDb("Condition %s %i has useless data in value3 (%u)!", rowType, iSourceTypeOrReferenceId, cond->mConditionValue3); - if (cond->mSourceGroup && iSourceTypeOrReferenceId < 0) - sLog.outErrorDb("Condition %s %i has useless data in SourceGroup (%u)!", rowType, iSourceTypeOrReferenceId, cond->mSourceGroup); - if (cond->mSourceEntry && iSourceTypeOrReferenceId < 0) - sLog.outErrorDb("Condition %s %i has useless data in SourceEntry (%u)!", rowType, iSourceTypeOrReferenceId, cond->mSourceEntry); - }else if (!isConditionTypeValid(cond))//doesn't have reference, validate ConditionType - continue; - - - if (iSourceTypeOrReferenceId < 0)//it is a reference template - { - uint32 uRefId = abs(iSourceTypeOrReferenceId); - if (m_ConditionReferenceMap.find(uRefId) == m_ConditionReferenceMap.end())//make sure we have a list for our conditions, based on reference id - { - ConditionList mCondList; - m_ConditionReferenceMap[uRefId] = mCondList; - } - m_ConditionReferenceMap[uRefId].push_back(cond);//add to reference storage - count++; - continue; - }//end of reference templates - - cond->mSourceType = ConditionSourceType(iSourceTypeOrReferenceId); - - //if not a reference and SourceType is invalid, skip - if (iConditionTypeOrReference >= 0 && !isSourceTypeValid(cond)) - continue; - - //Grouping is only allowed for some types (loot templates, gossip menus, gossip items) - if (cond->mSourceGroup && !isGroupable(cond->mSourceType)) - { - sLog.outErrorDb("Condition type %u has not allowed grouping %u!", uint32(cond->mSourceType), cond->mSourceGroup); - continue; - }else if (cond->mSourceGroup) - { - bool bIsDone = false; - //handle grouped conditions - switch (cond->mSourceType) - { - case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE: - bIsDone = addToLootTemplate(cond, LootTemplates_Creature.GetLootForConditionFill(cond->mSourceGroup)); - break; - case CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE: - bIsDone = addToLootTemplate(cond, LootTemplates_Disenchant.GetLootForConditionFill(cond->mSourceGroup)); - break; - case CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE: - bIsDone = addToLootTemplate(cond, LootTemplates_Fishing.GetLootForConditionFill(cond->mSourceGroup)); - break; - case CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE: - bIsDone = addToLootTemplate(cond, LootTemplates_Gameobject.GetLootForConditionFill(cond->mSourceGroup)); - break; - case CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE: - bIsDone = addToLootTemplate(cond, LootTemplates_Item.GetLootForConditionFill(cond->mSourceGroup)); - break; - case CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE: - bIsDone = addToLootTemplate(cond, LootTemplates_Mail.GetLootForConditionFill(cond->mSourceGroup)); - break; - case CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE: - bIsDone = addToLootTemplate(cond, LootTemplates_Milling.GetLootForConditionFill(cond->mSourceGroup)); - break; - case CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE: - bIsDone = addToLootTemplate(cond, LootTemplates_Pickpocketing.GetLootForConditionFill(cond->mSourceGroup)); - break; - case CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE: - bIsDone = addToLootTemplate(cond, LootTemplates_Prospecting.GetLootForConditionFill(cond->mSourceGroup)); - break; - case CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE: - bIsDone = addToLootTemplate(cond, LootTemplates_Reference.GetLootForConditionFill(cond->mSourceGroup)); - break; - case CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE: - bIsDone = addToLootTemplate(cond, LootTemplates_Skinning.GetLootForConditionFill(cond->mSourceGroup)); - break; - case CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE: - bIsDone = addToLootTemplate(cond, LootTemplates_Spell.GetLootForConditionFill(cond->mSourceGroup)); - break; - case CONDITION_SOURCE_TYPE_GOSSIP_MENU: - bIsDone = addToGossipMenus(cond); - break; - case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: - bIsDone = addToGossipMenuItems(cond); - break; - } - if (!bIsDone) - sLog.outErrorDb("Not handled grouped condition, SourceGroup %u", cond->mSourceGroup); - else - ++count; - continue; - } - - //handle not grouped conditions - //make sure we have a storage list for our SourceType - if (m_ConditionMap.find(cond->mSourceType) == m_ConditionMap.end()) - { - ConditionTypeMap mTypeMap; - m_ConditionMap[cond->mSourceType] = mTypeMap;//add new empty list for SourceType - } - - //make sure we have a condition list for our SourceType's entry - if (m_ConditionMap[cond->mSourceType].find(cond->mSourceEntry) == m_ConditionMap[cond->mSourceType].end()) - { - ConditionList mCondList; - m_ConditionMap[cond->mSourceType][cond->mSourceEntry] = mCondList; - } - - //add new Condition to storage based on Type/Entry - m_ConditionMap[cond->mSourceType][cond->mSourceEntry].push_back(cond); - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u conditions", count); -} - -bool ConditionMgr::addToLootTemplate(Condition* cond, LootTemplate* loot) -{ - if (!loot) - { - sLog.outErrorDb("ConditionMgr: LootTemplate %u not found", cond->mSourceGroup); - return false; - } - if (loot->addConditionItem(cond)) - return true; - sLog.outErrorDb("ConditionMgr: Item %u not found in LootTemplate %u", cond->mSourceEntry, cond->mSourceGroup); - return false; -} - -bool ConditionMgr::addToGossipMenus(Condition* cond) -{ - GossipMenusMapBoundsNonConst pMenuBounds = objmgr.GetGossipMenusMapBoundsNonConst(cond->mSourceGroup); - - if (pMenuBounds.first != pMenuBounds.second) - { - for (GossipMenusMap::iterator itr = pMenuBounds.first; itr != pMenuBounds.second; ++itr) - { - if ((*itr).second.entry == cond->mSourceGroup && (*itr).second.text_id == cond->mSourceEntry) - { - (*itr).second.conditions.push_back(cond); - sLog.outDebug("addToGossipMenus: entry %u textId %u", cond->mSourceGroup, cond->mSourceEntry); - return true; - } - } - } - sLog.outErrorDb("addToGossipMenus: GossipMenu %u not found", cond->mSourceGroup); - return false; -} - -bool ConditionMgr::addToGossipMenuItems(Condition* cond) -{ - GossipMenuItemsMapBoundsNonConst pMenuItemBounds = objmgr.GetGossipMenuItemsMapBoundsNonConst(cond->mSourceGroup); - if (pMenuItemBounds.first != pMenuItemBounds.second) - { - for (GossipMenuItemsMap::iterator itr = pMenuItemBounds.first; itr != pMenuItemBounds.second; ++itr) - { - if ((*itr).second.menu_id == cond->mSourceGroup && (*itr).second.id == cond->mSourceEntry) - { - (*itr).second.conditions.push_back(cond); - //sLog.outDebug("addToGossipMenuItems: menuId %u id %u", cond->mSourceGroup, cond->mSourceEntry); - return true; - } - } - } - sLog.outErrorDb("addToGossipMenuItems: GossipMenuIt %u Item %u not found", cond->mSourceGroup, cond->mSourceEntry); - return false; -} - -bool ConditionMgr::isSourceTypeValid(Condition* cond) -{ - if (cond->mSourceType == CONDITION_SOURCE_TYPE_NONE || cond->mSourceType >= MAX_CONDITIONSOURCETYPE) - { - sLog.outErrorDb("Invalid ConditionSourceType %u in `condition` table, ignoring.", uint32(cond->mSourceType)); - return false; - } - switch (cond->mSourceType) - { - case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE: - { - if (!LootTemplates_Creature.HaveLootFor(cond->mSourceGroup)) - { - sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `creature_loot_template`, ignoring.", cond->mSourceGroup); - return false; - } - LootTemplate* loot = LootTemplates_Creature.GetLootForConditionFill(cond->mSourceGroup); - ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) - { - sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE: - { - if (!LootTemplates_Disenchant.HaveLootFor(cond->mSourceGroup)) - { - sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `disenchant_loot_template`, ignoring.", cond->mSourceGroup); - return false; - } - LootTemplate* loot = LootTemplates_Disenchant.GetLootForConditionFill(cond->mSourceGroup); - ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) - { - sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE: - { - if (!LootTemplates_Fishing.HaveLootFor(cond->mSourceGroup)) - { - sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `fishing_loot_template`, ignoring.", cond->mSourceGroup); - return false; - } - LootTemplate* loot = LootTemplates_Fishing.GetLootForConditionFill(cond->mSourceGroup); - ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) - { - sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE: - { - if (!LootTemplates_Gameobject.HaveLootFor(cond->mSourceGroup)) - { - sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `gameobject_loot_template`, ignoring.", cond->mSourceGroup); - return false; - } - LootTemplate* loot = LootTemplates_Gameobject.GetLootForConditionFill(cond->mSourceGroup); - ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) - { - sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE: - { - if (!LootTemplates_Item.HaveLootFor(cond->mSourceGroup)) - { - sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `item_loot_template`, ignoring.", cond->mSourceGroup); - return false; - } - LootTemplate* loot = LootTemplates_Item.GetLootForConditionFill(cond->mSourceGroup); - ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) - { - sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE: - { - if (!LootTemplates_Mail.HaveLootFor(cond->mSourceGroup)) - { - sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `mail_loot_template`, ignoring.", cond->mSourceGroup); - return false; - } - LootTemplate* loot = LootTemplates_Mail.GetLootForConditionFill(cond->mSourceGroup); - ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) - { - sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE: - { - if (!LootTemplates_Milling.HaveLootFor(cond->mSourceGroup)) - { - sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `milling_loot_template`, ignoring.", cond->mSourceGroup); - return false; - } - LootTemplate* loot = LootTemplates_Milling.GetLootForConditionFill(cond->mSourceGroup); - ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) - { - sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE: - { - if (!LootTemplates_Pickpocketing.HaveLootFor(cond->mSourceGroup)) - { - sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `pickpocketing_loot_template`, ignoring.", cond->mSourceGroup); - return false; - } - LootTemplate* loot = LootTemplates_Pickpocketing.GetLootForConditionFill(cond->mSourceGroup); - ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) - { - sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE: - { - if (!LootTemplates_Prospecting.HaveLootFor(cond->mSourceGroup)) - { - sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `prospecting_loot_template`, ignoring.", cond->mSourceGroup); - return false; - } - LootTemplate* loot = LootTemplates_Prospecting.GetLootForConditionFill(cond->mSourceGroup); - ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) - { - sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE: - { - if (!LootTemplates_Reference.HaveLootFor(cond->mSourceGroup)) - { - sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `reference_loot_template`, ignoring.", cond->mSourceGroup); - return false; - } - LootTemplate* loot = LootTemplates_Reference.GetLootForConditionFill(cond->mSourceGroup); - ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) - { - sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE: - { - if (!LootTemplates_Skinning.HaveLootFor(cond->mSourceGroup)) - { - sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `skinning_loot_template`, ignoring.", cond->mSourceGroup); - return false; - } - LootTemplate* loot = LootTemplates_Skinning.GetLootForConditionFill(cond->mSourceGroup); - ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) - { - sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE: - { - if (!LootTemplates_Spell.HaveLootFor(cond->mSourceGroup)) - { - sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `spell_loot_template`, ignoring.", cond->mSourceGroup); - return false; - } - LootTemplate* loot = LootTemplates_Spell.GetLootForConditionFill(cond->mSourceGroup); - ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); - if (!pItemProto && !loot->isReference(cond->mSourceEntry)) - { - sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET: - { - if (cond->mConditionType != CONDITION_SPELL_SCRIPT_TARGET) - { - sLog.outErrorDb("SourceEntry %u in `condition` table, has ConditionType %u. Only CONDITION_SPELL_SCRIPT_TARGET(18) is valid for CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET(14), ignoring.", cond->mSourceEntry, uint32(cond->mConditionType)); - return false; - } - SpellEntry const* spellProto = sSpellStore.LookupEntry(cond->mSourceEntry); - - if (!spellProto) - { - sLog.outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->mSourceEntry); - return false; - } - - bool targetfound = false; - for (uint8 i = 0; i < 3; ++i) - { - if (spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENTRY_SRC || - spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_AREA_ENTRY_SRC || - spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENTRY_DST || - spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_AREA_ENTRY_DST || - spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_NEARBY_ENTRY || - spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_NEARBY_ENTRY || - spellProto->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT_NEARBY_ENTRY || - spellProto->EffectImplicitTargetB[i] == TARGET_GAMEOBJECT_NEARBY_ENTRY || - spellProto->EffectImplicitTargetA[i] == TARGET_DST_NEARBY_ENTRY || - spellProto->EffectImplicitTargetB[i] == TARGET_DST_NEARBY_ENTRY || - spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_CONE_ENTRY || - spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_CONE_ENTRY) - { - targetfound = true; - break; - } - } - if (!targetfound) - { - sLog.outErrorDb("SourceEntry %u in `condition` table does not have any implicit target TARGET_UNIT_NEARBY_ENTRY(38) or TARGET_DST_NEARBY_ENTRY (46)\ - ,TARGET_UNIT_AREA_ENTRY_SRC(7), TARGET_UNIT_AREA_ENTRY_DST(8), TARGET_UNIT_CONE_ENTRY(60), TARGET_GAMEOBJECT_NEARBY_ENTRY(40)",cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE: - { - if (!sCreatureStorage.LookupEntry(cond->mSourceEntry)) - { - sLog.outErrorDb("SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_SPELL: - { - SpellEntry const* spellProto = sSpellStore.LookupEntry(cond->mSourceEntry); - if (!spellProto) - { - sLog.outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->mSourceEntry); - return false; - } - break; - } - case CONDITION_SOURCE_TYPE_ITEM_REQUIRED_TARGET: - { - if (cond->mConditionType != CONDITION_ITEM_TARGET) - { - sLog.outErrorDb("SourceEntry %u in `condition` table, has ConditionType %u. Only CONDITION_ITEM_TARGET(24) is valid for CONDITION_SOURCE_TYPE_ITEM_REQUIRED_TARGET(18), ignoring.", cond->mSourceEntry, uint32(cond->mConditionType)); - return false; - } - ItemPrototype const *pItemProto = objmgr.GetItemPrototype(cond->mSourceEntry); - if (!pItemProto) - { - sLog.outErrorDb("SourceEntry %u in `condition` table, does not exist in `item_tamplate`, ignoring.", cond->mSourceEntry); - return false; - } - bool bIsItemSpellValid = false; - for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) - { - if (SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(pItemProto->Spells[i].SpellId)) - { - if (pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE || - pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE) - { - ConditionList conditions = sConditionMgr.GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, pSpellInfo->Id);//script loading is done before item target loading - if (!conditions.empty()) - break; - - for (int j = 0; j < 3; ++j) - { - if (pSpellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_TARGET_ENEMY || - pSpellInfo->EffectImplicitTargetB[i] == TARGET_UNIT_TARGET_ENEMY || - pSpellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_TARGET_ANY || - pSpellInfo->EffectImplicitTargetB[i] == TARGET_UNIT_TARGET_ANY) - { - bIsItemSpellValid = true; - break; - } - } - if (bIsItemSpellValid) - break; - } - } - } - - if (!bIsItemSpellValid) - { - sLog.outErrorDb("Conditions:ITEM_REQUIRED_TARGET used by item %u does not have implicit target TARGET_CHAIN_DAMAGE(6), TARGET_DUELVSPLAYER(25), already listed in scriptTargets or doesn't have item spelltrigger.", cond->mSourceEntry); - break; - } - break; - } - case CONDITION_SOURCE_TYPE_GOSSIP_MENU: - case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: - case CONDITION_SOURCE_TYPE_NONE: - break; - } - return true; -} -bool ConditionMgr::isConditionTypeValid(Condition* cond) -{ - if (cond->mConditionType == CONDITION_NONE || cond->mConditionType >= MAX_CONDITION) - { - sLog.outErrorDb("Invalid ConditionType %u at SourceEntry %u in `condition` table, ignoring.", uint32(cond->mConditionType),cond->mSourceEntry); - return false; - } - switch (cond->mConditionType) - { - case CONDITION_AURA: - { - if (!sSpellStore.LookupEntry(cond->mConditionValue1)) - { - sLog.outErrorDb("Aura condition has non existing spell (Id: %d), skipped", cond->mConditionValue1); - return false; - } - if (cond->mConditionValue2 > 2) - { - sLog.outErrorDb("Aura condition has non existing effect index (%u) (must be 0..2), skipped", cond->mConditionValue2); - return false; - } - break; - } - case CONDITION_ITEM: - { - ItemPrototype const *proto = objmgr.GetItemPrototype(cond->mConditionValue1); - if (!proto) - { - sLog.outErrorDb("Item condition has non existing item (%u), skipped", cond->mConditionValue1); - return false; - } - if (!cond->mConditionValue2) - { - sLog.outErrorDb("Item condition has 0 set for item count in value2 (%u), skipped", cond->mConditionValue2); - return false; - } - break; - } - case CONDITION_ITEM_EQUIPPED: - { - ItemPrototype const *proto = objmgr.GetItemPrototype(cond->mConditionValue1); - if (!proto) - { - sLog.outErrorDb("ItemEquipped condition has non existing item (%u), skipped", cond->mConditionValue1); - return false; - } - if (cond->mConditionValue2) - sLog.outErrorDb("ItemEquipped condition has useless data in value2 (%u)!", cond->mConditionValue2); - break; - } - case CONDITION_ZONEID: - { - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(cond->mConditionValue1); - if (!areaEntry) - { - sLog.outErrorDb("Zone condition has non existing area (%u), skipped", cond->mConditionValue1); - return false; - } - if (areaEntry->zone != 0) - { - sLog.outErrorDb("Zone condition requires to be in area (%u) which is a subzone but zone expected, skipped", cond->mConditionValue1); - return false; - } - if (cond->mConditionValue2) - sLog.outErrorDb("Zone condition has useless data in value2 (%u)!", cond->mConditionValue2); - break; - } - case CONDITION_REPUTATION_RANK: - { - FactionEntry const* factionEntry = sFactionStore.LookupEntry(cond->mConditionValue1); - if (!factionEntry) - { - sLog.outErrorDb("Reputation condition has non existing faction (%u), skipped", cond->mConditionValue1); - return false; - } - break; - } - case CONDITION_TEAM: - { - if (cond->mConditionValue1 != ALLIANCE && cond->mConditionValue1 != HORDE) - { - sLog.outErrorDb("Team condition specifies unknown team (%u), skipped", cond->mConditionValue1); - return false; - } - if (cond->mConditionValue2) - sLog.outErrorDb("Team condition has useless data in value2 (%u)!", cond->mConditionValue2); - break; - } - case CONDITION_SKILL: - { - SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(cond->mConditionValue1); - if (!pSkill) - { - sLog.outErrorDb("Skill condition specifies non-existing skill (%u), skipped", cond->mConditionValue1); - return false; - } - if (cond->mConditionValue2 < 1 || cond->mConditionValue2 > sWorld.GetConfigMaxSkillValue()) - { - sLog.outErrorDb("Skill condition specifies invalid skill value (%u), skipped", cond->mConditionValue2); - return false; - } - break; - } - case CONDITION_QUESTREWARDED: - case CONDITION_QUESTTAKEN: - case CONDITION_QUEST_NONE: - { - Quest const *Quest = objmgr.GetQuestTemplate(cond->mConditionValue1); - if (!Quest) - { - sLog.outErrorDb("Quest condition specifies non-existing quest (%u), skipped", cond->mConditionValue1); - return false; - } - if (cond->mConditionValue2) - sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", cond->mConditionValue2); - break; - } - case CONDITION_AD_COMMISSION_AURA: - { - if (cond->mConditionValue1) - sLog.outErrorDb("Quest condition has useless data in value1 (%u)!", cond->mConditionValue1); - if (cond->mConditionValue2) - sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", cond->mConditionValue2); - break; - } - case CONDITION_NO_AURA: - { - if (!sSpellStore.LookupEntry(cond->mConditionValue1)) - { - sLog.outErrorDb("Aura condition has non existing spell (Id: %d), skipped", cond->mConditionValue1); - return false; - } - if (cond->mConditionValue2 > 2) - { - sLog.outErrorDb("Aura condition has non existing effect index (%u) in value2 (must be 0..2), skipped", cond->mConditionValue2); - return false; - } - break; - } - case CONDITION_ACTIVE_EVENT: - { - GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); - if (cond->mConditionValue1 >=events.size() || !events[cond->mConditionValue1].isValid()) - { - sLog.outErrorDb("Active event condition has non existing event id (%u), skipped", cond->mConditionValue1); - return false; - } - if (cond->mConditionValue2) - sLog.outErrorDb("Active event condition has useless data in value2 (%u)!", cond->mConditionValue2); - break; - } - case CONDITION_ACHIEVEMENT: - { - AchievementEntry const* achievement = GetAchievementStore()->LookupEntry(cond->mConditionValue1); - if (!achievement) - { - sLog.outErrorDb("Achivemen condition has non existing achivement id (%u), skipped", cond->mConditionValue1); - return false; - } - if (cond->mConditionValue2) - sLog.outErrorDb("Achivemen condition has useless data in value2 (%u)!", cond->mConditionValue2); - break; - } - case CONDITION_CLASS: - { - if (cond->mConditionValue1 >= MAX_CLASSES) - { - sLog.outErrorDb("Class condition has non existing class (%u), skipped", cond->mConditionValue1); - return false; - } - if (cond->mConditionValue2) - sLog.outErrorDb("Class condition has useless data in value2 (%u)!", cond->mConditionValue2); - break; - } - case CONDITION_RACE: - { - if (cond->mConditionValue1 >= MAX_RACES) - { - sLog.outErrorDb("Race condition has non existing race (%u), skipped", cond->mConditionValue1); - return false; - } - if (cond->mConditionValue2) - sLog.outErrorDb("Race condition has useless data in value2 (%u)!", cond->mConditionValue2); - break; - } - case CONDITION_SPELL_SCRIPT_TARGET: - { - if (cond->mConditionValue1 >= MAX_SPELL_TARGET_TYPE) - { - sLog.outErrorDb("SpellTarget condition has non existing spell target type (%u), skipped", cond->mConditionValue1); - return false; - } - switch(cond->mConditionValue1) - { - case SPELL_TARGET_TYPE_GAMEOBJECT: - { - if (cond->mConditionValue2 && !sGOStorage.LookupEntry(cond->mConditionValue2)) - { - sLog.outErrorDb("SpellTarget condition has non existing gameobject (%u) as target, skipped", cond->mConditionValue2); - return false; - } - break; - } - case SPELL_TARGET_TYPE_CONTROLLED: - case SPELL_TARGET_TYPE_CREATURE: - case SPELL_TARGET_TYPE_DEAD: - { - if (cond->mConditionValue2 && !sCreatureStorage.LookupEntry(cond->mConditionValue2)) - { - sLog.outErrorDb("SpellTarget condition has non existing creature template entry (%u) as target, skipped", cond->mConditionValue2); - return false; - } - const CreatureInfo* cInfo = sCreatureStorage.LookupEntry(cond->mConditionValue2); - - if (cond->mSourceEntry == 30427 && !cInfo->SkinLootId) - { - sLog.outErrorDb("SpellTarget condition has creature entry %u as a target of spellid 30427, but this creature has no skinlootid. Gas extraction will not work!, skipped", cond->mConditionValue2); - return false; - } - break; - } - } - if (cond->mConditionValue3) - sLog.outErrorDb("SpellTarget condition has useless data in value3 (%u)!", cond->mConditionValue3); - break; - } - case CONDITION_CREATURE_TARGET: - { - if (!cond->mConditionValue1 && !sCreatureStorage.LookupEntry(cond->mConditionValue1)) - { - sLog.outErrorDb("CreatureTarget condition has non existing creature template entry (%u) as target, skipped", cond->mConditionValue1); - return false; - } - if (cond->mConditionValue2) - sLog.outErrorDb("CreatureTarget condition has useless data in value2 (%u)!", cond->mConditionValue2); - break; - } - case CONDITION_TARGET_HEALTH_BELOW_PCT: - { - if (cond->mConditionValue1 > 100) - { - sLog.outErrorDb("TargetHealthBelowPct condition has invalid data in value1 (%u), skipped", cond->mConditionValue1); - return false; - } - if (cond->mConditionValue2) - sLog.outErrorDb("TargetHealthBelowPct condition has useless data in value2 (%u)!", cond->mConditionValue2); - break; - } - case CONDITION_TARGET_RANGE: - { - if (cond->mConditionValue2 && cond->mConditionValue2 < cond->mConditionValue1)//maxDist can be 0 for infinit max range - { - sLog.outErrorDb("TargetRange condition has max distance closer then min distance, skipped"); - return false; - } - break; - } - case CONDITION_MAPID: - { - MapEntry const * me = sMapStore.LookupEntry(cond->mConditionValue1); - if (!me) - { - sLog.outErrorDb("Map condition has non existing map (%u), skipped", cond->mConditionValue1); - return false; - } - if (cond->mConditionValue2) - sLog.outErrorDb("Map condition has useless data in value2 (%u)!", cond->mConditionValue2); - break; - } - case CONDITION_ITEM_TARGET: - { - if (!cond->mConditionValue1 || cond->mConditionValue1 > MAX_ITEM_REQ_TARGET_TYPE) - { - sLog.outErrorDb("ItemTarget condition has incorrect target type (%u), skipped", cond->mConditionValue1); - return false; - } - if (!cond->mConditionValue2 && !sCreatureStorage.LookupEntry(cond->mConditionValue2)) - { - sLog.outErrorDb("ItemTarget condition has non existing creature template entry (%u) as target, skipped", cond->mConditionValue2); - return false; - } - if (cond->mConditionValue3) - sLog.outErrorDb("ItemTarget condition has useless data in value3 (%u)!", cond->mConditionValue3); - break; - } - case CONDITION_AREAID: - case CONDITION_INSTANCE_DATA: - break; - } - return true; -} diff --git a/src/server/game/ConditionMgr/ConditionMgr.h b/src/server/game/ConditionMgr/ConditionMgr.h deleted file mode 100644 index bc2ce8d01a2..00000000000 --- a/src/server/game/ConditionMgr/ConditionMgr.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_CONDITIONMGR_H -#define TRINITY_CONDITIONMGR_H - -#include "LootMgr.h" - -class Player; -class Unit; -class LootTemplate; - -enum ConditionType -{ // value1 value2 value3 - CONDITION_NONE = 0, // 0 0 0 always true - CONDITION_AURA = 1, // spell_id effindex +referenceID true if has aura of spell_id with effect effindex - CONDITION_ITEM = 2, // item_id count +referenceID true if has #count of item_ids - CONDITION_ITEM_EQUIPPED = 3, // item_id 0 +referenceID true if has item_id equipped - CONDITION_ZONEID = 4, // zone_id 0 +referenceID true if in zone_id - CONDITION_REPUTATION_RANK = 5, // faction_id min_rank +referenceID true if has min_rank for faction_id - CONDITION_TEAM = 6, // player_team 0, +referenceID 469 - Alliance, 67 - Horde) - CONDITION_SKILL = 7, // skill_id skill_value +referenceID true if has skill_value for skill_id - CONDITION_QUESTREWARDED = 8, // quest_id 0 +referenceID true if quest_id was rewarded before - CONDITION_QUESTTAKEN = 9, // quest_id 0, +referenceID true while quest active - CONDITION_AD_COMMISSION_AURA = 10, // 0 0, +referenceID true while one from AD commission aura active - CONDITION_NO_AURA = 11, // spell_id effindex +referenceID true if does not have aura of spell_id with effect effindex - CONDITION_ACTIVE_EVENT = 12, // event_id 0 +referenceID true if event is active - CONDITION_INSTANCE_DATA = 13, // entry data +referenceID true if data is set in current instance - CONDITION_QUEST_NONE = 14, // quest_id 0 +referenceID true if doesn't have quest saved - CONDITION_CLASS = 15, // class 0 +referenceID true if player's class is equal to class - CONDITION_RACE = 16, // race 0 +referenceID true if player's race is equal to race - CONDITION_ACHIEVEMENT = 17, // achievement_id 0 +referenceID true if achievement is complete - CONDITION_SPELL_SCRIPT_TARGET = 18, // SpellScriptTargetType, TargetEntry, 0 - CONDITION_CREATURE_TARGET = 19, // creature entry 0 +referenceID true if current target is creature with value1 entry - CONDITION_TARGET_HEALTH_BELOW_PCT = 20, // 0-100 0 +referenceID true if target's health is below value1 percent, false if over or no target - CONDITION_TARGET_RANGE = 21, // minDistance maxDist +referenceID true if target is closer then minDist and further then maxDist or if max is 0 then max dist is infinit - CONDITION_MAPID = 22, // map_id 0 +referenceID true if in map_id - CONDITION_AREAID = 23, // area_id 0 +referenceID true if in area_id - CONDITION_ITEM_TARGET = 24 // ItemRequiredTargetType, TargetEntry, 0 -}; - -#define MAX_CONDITION 25 // maximum value in ConditionType enum - -enum ConditionSourceType -{ - CONDITION_SOURCE_TYPE_NONE = 0,//DONE - CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE = 1,//DONE - CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE = 2,//DONE - CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE = 3,//DONE - CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE = 4,//DONE - CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE = 5,//DONE - CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE = 6,//DONE - CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE = 7,//DONE - CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE = 8,//DONE - CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE = 9,//DONE - CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE = 10,//DONE - CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE = 11,//DONE - CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE = 12,//DONE - CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET = 13,//DONE - CONDITION_SOURCE_TYPE_GOSSIP_MENU = 14,//DONE - CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION = 15,//DONE - CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE = 16,//DONE - CONDITION_SOURCE_TYPE_SPELL = 17,//DONE - CONDITION_SOURCE_TYPE_ITEM_REQUIRED_TARGET = 18//DONE -}; - -#define MAX_CONDITIONSOURCETYPE 19 - -struct Condition -{ - ConditionSourceType mSourceType; //SourceTypeOrReferenceId - uint32 mSourceGroup; - uint32 mSourceEntry; - uint32 mElseGroup; - ConditionType mConditionType; //ConditionTypeOrReference - uint32 mConditionValue1; - uint32 mConditionValue2; - uint32 mConditionValue3; - uint32 ErrorTextd; - uint32 mReferenceId; - - Condition() - { - mSourceType = CONDITION_SOURCE_TYPE_NONE; - mSourceGroup = 0; - mSourceEntry = 0; - mElseGroup = 0; - mConditionType = CONDITION_NONE; - mConditionValue1 = 0; - mConditionValue2 = 0; - mConditionValue3 = 0; - mReferenceId = 0; - ErrorTextd = 0; - } - bool Meets(Player * player, Unit* targetOverride = NULL); - bool isLoaded() { return mConditionType > CONDITION_NONE || mReferenceId; } -}; - -typedef std::list ConditionList; -typedef std::map ConditionTypeMap; -typedef std::map ConditionMap;//used for all conditions, except references - -typedef std::map ConditionReferenceMap;//only used for references - -class ConditionMgr -{ - public: - ConditionMgr(); - ~ConditionMgr(); - - void LoadConditions(bool isReload = false); - bool isConditionTypeValid(Condition* cond); - ConditionList GetConditionReferences(uint32 refId); - - bool IsPlayerMeetToConditions(Player* player, ConditionList conditions, Unit* targetOverride = NULL); - ConditionList GetConditionsForNotGroupedEntry(ConditionSourceType sType, uint32 uEntry); - - protected: - ConditionMap m_ConditionMap; - ConditionReferenceMap m_ConditionReferenceMap; - - private: - bool isSourceTypeValid(Condition* cond); - bool addToLootTemplate(Condition* cond, LootTemplate* loot); - bool addToGossipMenus(Condition* cond); - bool addToGossipMenuItems(Condition* cond); - bool IsPlayerMeetToConditionList(Player* player,const ConditionList& conditions, Unit* targetOverride = NULL); - - bool isGroupable(ConditionSourceType sourceType) - { - return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE || - sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU || - sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION); - } -}; - -#define sConditionMgr Trinity::Singleton::Instance() - -#endif diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp new file mode 100644 index 00000000000..8e5a7e5677e --- /dev/null +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -0,0 +1,1145 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "Policies/SingletonImp.h" +#include "Player.h" +#include "SpellAuras.h" +#include "SpellMgr.h" +#include "GameEventMgr.h" +#include "ObjectMgr.h" +#include "ProgressBar.h" +#include "InstanceData.h" +#include "ConditionMgr.h" + +INSTANTIATE_SINGLETON_1(ConditionMgr); + +// Checks if player meets the condition +// Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: eventAI) +bool Condition::Meets(Player * player, Unit* targetOverride) +{ + if (!player) + { + sLog.outDebug("Condition player not found"); + return false; // player not present, return false + } + uint32 refId = 0; + bool condMeets = false; + bool sendErrorMsg = false; + refId = mConditionValue3;//value 3 can be a 'quick' reference + switch (mConditionType) + { + case CONDITION_NONE: + condMeets = true; // empty condition, always met + break; + case CONDITION_AURA: + condMeets = player->HasAuraEffect(mConditionValue1, mConditionValue2); + break; + case CONDITION_ITEM: + condMeets = player->HasItemCount(mConditionValue1, mConditionValue2); + break; + case CONDITION_ITEM_EQUIPPED: + condMeets = player->HasItemOrGemWithIdEquipped(mConditionValue1,1); + break; + case CONDITION_ZONEID: + condMeets = player->GetZoneId() == mConditionValue1; + break; + case CONDITION_REPUTATION_RANK: + { + FactionEntry const* faction = sFactionStore.LookupEntry(mConditionValue1); + condMeets = faction && uint32(player->GetReputationMgr().GetRank(faction)) >= int32(mConditionValue2); + break; + } + case CONDITION_ACHIEVEMENT: + { + AchievementEntry const* achievement = GetAchievementStore()->LookupEntry(mConditionValue1); + condMeets = player->GetAchievementMgr().HasAchieved(achievement); + break; + } + case CONDITION_TEAM: + condMeets = player->GetTeam() == mConditionValue1; + break; + case CONDITION_CLASS: + condMeets = player->getClass() == mConditionValue1; + break; + case CONDITION_RACE: + condMeets = player->getRace() == mConditionValue1; + break; + case CONDITION_SKILL: + condMeets = player->HasSkill(mConditionValue1) && player->GetBaseSkillValue(mConditionValue1) >= mConditionValue2; + break; + case CONDITION_QUESTREWARDED: + condMeets = player->GetQuestRewardStatus(mConditionValue1); + break; + case CONDITION_QUESTTAKEN: + { + QuestStatus status = player->GetQuestStatus(mConditionValue1); + condMeets = (status == QUEST_STATUS_INCOMPLETE); + break; + } + case CONDITION_QUEST_NONE: + { + QuestStatus status = player->GetQuestStatus(mConditionValue1); + condMeets = (status == QUEST_STATUS_NONE); + break; + } + case CONDITION_AD_COMMISSION_AURA: + { + Unit::AuraApplicationMap const& auras = player->GetAppliedAuras(); + for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + if ((itr->second->GetBase()->GetSpellProto()->Attributes & 0x1000010) && itr->second->GetBase()->GetSpellProto()->SpellVisual[0] == 3580) + { + condMeets = true; + break; + } + condMeets = false; + break; + } + case CONDITION_NO_AURA: + condMeets = !player->HasAuraEffect(mConditionValue1, mConditionValue2); + break; + case CONDITION_ACTIVE_EVENT: + condMeets = gameeventmgr.IsActiveEvent(mConditionValue1); + break; + case CONDITION_INSTANCE_DATA: + { + Map *map = player->GetMap(); + if (map && map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData()) + condMeets = ((InstanceMap*)map)->GetInstanceData()->GetData(mConditionValue1) == mConditionValue2; + break; + } + case CONDITION_SPELL_SCRIPT_TARGET: + condMeets = true;//spell target condition is handled in spellsystem, here it is always true + refId = 0;//cant have references! use CONDITION_SOURCE_TYPE_SPELL for it + break; + case CONDITION_CREATURE_TARGET: + { + Unit* target = player->GetSelectedUnit(); + if (targetOverride) + target = targetOverride; + if (target) + if (Creature* cTarget = target->ToCreature()) + if (cTarget->GetEntry() == mConditionValue1) + condMeets = true; + break; + } + case CONDITION_TARGET_HEALTH_BELOW_PCT: + { + Unit* target = player->GetSelectedUnit(); + if (targetOverride) + target = targetOverride; + if (target) + if ((target->GetHealth()*100 / target->GetMaxHealth()) <= mConditionValue1) + condMeets = true; + break; + } + case CONDITION_TARGET_RANGE: + { + if (Unit* target = player->GetSelectedUnit()) + if (player->GetDistance(target) >= mConditionValue1 && (!mConditionValue2 || player->GetDistance(target) <= mConditionValue2)) + condMeets = true; + break; + } + case CONDITION_MAPID: + condMeets = player->GetMapId() == mConditionValue1; + break; + case CONDITION_AREAID: + condMeets = player->GetAreaId() == mConditionValue1; + break; + case CONDITION_ITEM_TARGET: + { + condMeets = true;//handled in Item::IsTargetValidForItemUse + refId = 0;//cant have references for now + break; + } + default: + condMeets = false; + refId = 0; + break; + } + switch (mSourceType) + { + case CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET: + case CONDITION_SOURCE_TYPE_SPELL: + sendErrorMsg = true; + break; + } + + bool refMeets = false; + if (condMeets && refId)//only have to check references if 'this' is met + { + ConditionList ref = sConditionMgr.GetConditionReferences(refId); + refMeets = sConditionMgr.IsPlayerMeetToConditions(player, ref); + }else refMeets = true; + + if (sendErrorMsg && ErrorTextd && (!condMeets || !refMeets))//send special error from DB + player->m_ConditionErrorMsgId = ErrorTextd; + + return condMeets && refMeets; +} + +ConditionMgr::ConditionMgr() +{ +} + +ConditionMgr::~ConditionMgr() +{ +} + +ConditionList ConditionMgr::GetConditionReferences(uint32 refId) +{ + ConditionList conditions; + ConditionReferenceMap::const_iterator ref = m_ConditionReferenceMap.find(refId); + if (ref != m_ConditionReferenceMap.end()) + conditions = (*ref).second; + return conditions; +} + +bool ConditionMgr::IsPlayerMeetToConditionList(Player* player,const ConditionList& conditions, Unit* targetOverride) +{ + std::mapElseGroupMap; + for (ConditionList::const_iterator i = conditions.begin(); i != conditions.end(); ++i) + { + sLog.outDebug("ConditionMgr::IsPlayerMeetToConditionList condType: %u val1: %u",(*i)->mConditionType,(*i)->mConditionValue1); + if ((*i)->isLoaded()) + { + std::map::const_iterator itr = ElseGroupMap.find((*i)->mElseGroup); + if (itr == ElseGroupMap.end()) + ElseGroupMap[(*i)->mElseGroup] = true; + else if (!(*itr).second) + continue; + + if ((*i)->mReferenceId)//handle reference + { + ConditionReferenceMap::const_iterator ref = m_ConditionReferenceMap.find((*i)->mReferenceId); + if (ref != m_ConditionReferenceMap.end()) + { + if(!IsPlayerMeetToConditionList(player, (*ref).second, targetOverride)) + ElseGroupMap[(*i)->mElseGroup] = false; + }else{ + sLog.outDebug("IsPlayerMeetToConditionList: Reference template -%u not found", (*i)->mReferenceId);//checked at loading, should never happen + } + + } else//handle normal condition + { + if (!(*i)->Meets(player, targetOverride)) + ElseGroupMap[(*i)->mElseGroup] = false; + } + } + } + for (std::map::const_iterator i = ElseGroupMap.begin(); i != ElseGroupMap.end(); ++i) + if (i->second) + return true; + return false; +} + +bool ConditionMgr::IsPlayerMeetToConditions(Player* player, ConditionList conditions, Unit* targetOverride) +{ + if (conditions.empty()) + return true; + if(player) + player->m_ConditionErrorMsgId = 0; + + sLog.outDebug("ConditionMgr::IsPlayerMeetToConditions"); + bool result = IsPlayerMeetToConditionList(player, conditions, targetOverride); + + if (player && player->m_ConditionErrorMsgId && player->GetSession()) + player->GetSession()->SendNotification(player->m_ConditionErrorMsgId);//m_ConditionErrorMsgId is set only if a condition was not met + + return result; +} + +ConditionList ConditionMgr::GetConditionsForNotGroupedEntry(ConditionSourceType sType, uint32 uEntry) +{ + ConditionList spellCond; + if (sType > CONDITION_SOURCE_TYPE_NONE && sType < MAX_CONDITIONSOURCETYPE) + { + ConditionMap::const_iterator itr = m_ConditionMap.find(sType); + if (itr != m_ConditionMap.end()) + { + ConditionTypeMap::const_iterator i = (*itr).second.find(uEntry); + if (i != (*itr).second.end()) + { + spellCond = (*i).second; + sLog.outDebug("GetConditionsForNotGroupedEntry: found conditions for type %u and entry %u", uint32(sType), uEntry); + } + } + } + return spellCond; +} + +void ConditionMgr::LoadConditions(bool isReload) +{ + m_ConditionMap.clear(); // for reload case + m_ConditionReferenceMap.clear(); // for reload case + //must clear all custom handled cases (groupped types) before reload + if (isReload) + { + sLog.outString("Reseting Loot Conditions..."); + LootTemplates_Creature.ResetConditions(); + LootTemplates_Fishing.ResetConditions(); + LootTemplates_Gameobject.ResetConditions(); + LootTemplates_Item.ResetConditions(); + LootTemplates_Mail.ResetConditions(); + LootTemplates_Milling.ResetConditions(); + LootTemplates_Pickpocketing.ResetConditions(); + LootTemplates_Reference.ResetConditions(); + LootTemplates_Skinning.ResetConditions(); + LootTemplates_Disenchant.ResetConditions(); + LootTemplates_Prospecting.ResetConditions(); + LootTemplates_Spell.ResetConditions(); + + sLog.outString("Re-Loading `gossip_menu` Table for Conditions!"); + objmgr.LoadGossipMenu(); + + sLog.outString("Re-Loading `gossip_menu_option` Table for Conditions!"); + objmgr.LoadGossipMenuItems(); + } + + uint32 count = 0; + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, ElseGroup, ConditionTypeOrReference, ConditionValue1, ConditionValue2, ConditionValue3, ErrorTextId FROM conditions"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `conditions`, table is empty!"); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + + Condition* cond = new Condition(); + int32 iSourceTypeOrReferenceId = fields[0].GetInt32(); + cond->mSourceGroup = fields[1].GetUInt32(); + cond->mSourceEntry = fields[2].GetUInt32(); + cond->mElseGroup = fields[3].GetUInt32(); + int32 iConditionTypeOrReference = fields[4].GetInt32(); + cond->mConditionValue1 = fields[5].GetUInt32(); + cond->mConditionValue2 = fields[6].GetUInt32(); + cond->mConditionValue3 = fields[7].GetUInt32(); + cond->ErrorTextd = fields[8].GetUInt32(); + + if (iConditionTypeOrReference >= 0) + cond->mConditionType = ConditionType(iConditionTypeOrReference); + + if (iConditionTypeOrReference < 0)//it has a reference + { + if (iConditionTypeOrReference == iSourceTypeOrReferenceId)//self referencing, skipp + { + sLog.outErrorDb("Condition reference %i is referencing self, skipped", iSourceTypeOrReferenceId); + continue; + } + cond->mReferenceId = uint32(abs(iConditionTypeOrReference)); + + const char* rowType = "reference template"; + if (iSourceTypeOrReferenceId >= 0) + rowType = "reference"; + //check for useless data + if (cond->mConditionValue1) + sLog.outErrorDb("Condition %s %i has useless data in value1 (%u)!", rowType, iSourceTypeOrReferenceId, cond->mConditionValue1); + if (cond->mConditionValue2) + sLog.outErrorDb("Condition %s %i has useless data in value2 (%u)!", rowType, iSourceTypeOrReferenceId, cond->mConditionValue2); + if (cond->mConditionValue3) + sLog.outErrorDb("Condition %s %i has useless data in value3 (%u)!", rowType, iSourceTypeOrReferenceId, cond->mConditionValue3); + if (cond->mSourceGroup && iSourceTypeOrReferenceId < 0) + sLog.outErrorDb("Condition %s %i has useless data in SourceGroup (%u)!", rowType, iSourceTypeOrReferenceId, cond->mSourceGroup); + if (cond->mSourceEntry && iSourceTypeOrReferenceId < 0) + sLog.outErrorDb("Condition %s %i has useless data in SourceEntry (%u)!", rowType, iSourceTypeOrReferenceId, cond->mSourceEntry); + }else if (!isConditionTypeValid(cond))//doesn't have reference, validate ConditionType + continue; + + + if (iSourceTypeOrReferenceId < 0)//it is a reference template + { + uint32 uRefId = abs(iSourceTypeOrReferenceId); + if (m_ConditionReferenceMap.find(uRefId) == m_ConditionReferenceMap.end())//make sure we have a list for our conditions, based on reference id + { + ConditionList mCondList; + m_ConditionReferenceMap[uRefId] = mCondList; + } + m_ConditionReferenceMap[uRefId].push_back(cond);//add to reference storage + count++; + continue; + }//end of reference templates + + cond->mSourceType = ConditionSourceType(iSourceTypeOrReferenceId); + + //if not a reference and SourceType is invalid, skip + if (iConditionTypeOrReference >= 0 && !isSourceTypeValid(cond)) + continue; + + //Grouping is only allowed for some types (loot templates, gossip menus, gossip items) + if (cond->mSourceGroup && !isGroupable(cond->mSourceType)) + { + sLog.outErrorDb("Condition type %u has not allowed grouping %u!", uint32(cond->mSourceType), cond->mSourceGroup); + continue; + }else if (cond->mSourceGroup) + { + bool bIsDone = false; + //handle grouped conditions + switch (cond->mSourceType) + { + case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE: + bIsDone = addToLootTemplate(cond, LootTemplates_Creature.GetLootForConditionFill(cond->mSourceGroup)); + break; + case CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE: + bIsDone = addToLootTemplate(cond, LootTemplates_Disenchant.GetLootForConditionFill(cond->mSourceGroup)); + break; + case CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE: + bIsDone = addToLootTemplate(cond, LootTemplates_Fishing.GetLootForConditionFill(cond->mSourceGroup)); + break; + case CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE: + bIsDone = addToLootTemplate(cond, LootTemplates_Gameobject.GetLootForConditionFill(cond->mSourceGroup)); + break; + case CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE: + bIsDone = addToLootTemplate(cond, LootTemplates_Item.GetLootForConditionFill(cond->mSourceGroup)); + break; + case CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE: + bIsDone = addToLootTemplate(cond, LootTemplates_Mail.GetLootForConditionFill(cond->mSourceGroup)); + break; + case CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE: + bIsDone = addToLootTemplate(cond, LootTemplates_Milling.GetLootForConditionFill(cond->mSourceGroup)); + break; + case CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE: + bIsDone = addToLootTemplate(cond, LootTemplates_Pickpocketing.GetLootForConditionFill(cond->mSourceGroup)); + break; + case CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE: + bIsDone = addToLootTemplate(cond, LootTemplates_Prospecting.GetLootForConditionFill(cond->mSourceGroup)); + break; + case CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE: + bIsDone = addToLootTemplate(cond, LootTemplates_Reference.GetLootForConditionFill(cond->mSourceGroup)); + break; + case CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE: + bIsDone = addToLootTemplate(cond, LootTemplates_Skinning.GetLootForConditionFill(cond->mSourceGroup)); + break; + case CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE: + bIsDone = addToLootTemplate(cond, LootTemplates_Spell.GetLootForConditionFill(cond->mSourceGroup)); + break; + case CONDITION_SOURCE_TYPE_GOSSIP_MENU: + bIsDone = addToGossipMenus(cond); + break; + case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: + bIsDone = addToGossipMenuItems(cond); + break; + } + if (!bIsDone) + sLog.outErrorDb("Not handled grouped condition, SourceGroup %u", cond->mSourceGroup); + else + ++count; + continue; + } + + //handle not grouped conditions + //make sure we have a storage list for our SourceType + if (m_ConditionMap.find(cond->mSourceType) == m_ConditionMap.end()) + { + ConditionTypeMap mTypeMap; + m_ConditionMap[cond->mSourceType] = mTypeMap;//add new empty list for SourceType + } + + //make sure we have a condition list for our SourceType's entry + if (m_ConditionMap[cond->mSourceType].find(cond->mSourceEntry) == m_ConditionMap[cond->mSourceType].end()) + { + ConditionList mCondList; + m_ConditionMap[cond->mSourceType][cond->mSourceEntry] = mCondList; + } + + //add new Condition to storage based on Type/Entry + m_ConditionMap[cond->mSourceType][cond->mSourceEntry].push_back(cond); + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u conditions", count); +} + +bool ConditionMgr::addToLootTemplate(Condition* cond, LootTemplate* loot) +{ + if (!loot) + { + sLog.outErrorDb("ConditionMgr: LootTemplate %u not found", cond->mSourceGroup); + return false; + } + if (loot->addConditionItem(cond)) + return true; + sLog.outErrorDb("ConditionMgr: Item %u not found in LootTemplate %u", cond->mSourceEntry, cond->mSourceGroup); + return false; +} + +bool ConditionMgr::addToGossipMenus(Condition* cond) +{ + GossipMenusMapBoundsNonConst pMenuBounds = objmgr.GetGossipMenusMapBoundsNonConst(cond->mSourceGroup); + + if (pMenuBounds.first != pMenuBounds.second) + { + for (GossipMenusMap::iterator itr = pMenuBounds.first; itr != pMenuBounds.second; ++itr) + { + if ((*itr).second.entry == cond->mSourceGroup && (*itr).second.text_id == cond->mSourceEntry) + { + (*itr).second.conditions.push_back(cond); + sLog.outDebug("addToGossipMenus: entry %u textId %u", cond->mSourceGroup, cond->mSourceEntry); + return true; + } + } + } + sLog.outErrorDb("addToGossipMenus: GossipMenu %u not found", cond->mSourceGroup); + return false; +} + +bool ConditionMgr::addToGossipMenuItems(Condition* cond) +{ + GossipMenuItemsMapBoundsNonConst pMenuItemBounds = objmgr.GetGossipMenuItemsMapBoundsNonConst(cond->mSourceGroup); + if (pMenuItemBounds.first != pMenuItemBounds.second) + { + for (GossipMenuItemsMap::iterator itr = pMenuItemBounds.first; itr != pMenuItemBounds.second; ++itr) + { + if ((*itr).second.menu_id == cond->mSourceGroup && (*itr).second.id == cond->mSourceEntry) + { + (*itr).second.conditions.push_back(cond); + //sLog.outDebug("addToGossipMenuItems: menuId %u id %u", cond->mSourceGroup, cond->mSourceEntry); + return true; + } + } + } + sLog.outErrorDb("addToGossipMenuItems: GossipMenuIt %u Item %u not found", cond->mSourceGroup, cond->mSourceEntry); + return false; +} + +bool ConditionMgr::isSourceTypeValid(Condition* cond) +{ + if (cond->mSourceType == CONDITION_SOURCE_TYPE_NONE || cond->mSourceType >= MAX_CONDITIONSOURCETYPE) + { + sLog.outErrorDb("Invalid ConditionSourceType %u in `condition` table, ignoring.", uint32(cond->mSourceType)); + return false; + } + switch (cond->mSourceType) + { + case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE: + { + if (!LootTemplates_Creature.HaveLootFor(cond->mSourceGroup)) + { + sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `creature_loot_template`, ignoring.", cond->mSourceGroup); + return false; + } + LootTemplate* loot = LootTemplates_Creature.GetLootForConditionFill(cond->mSourceGroup); + ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); + if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + { + sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE: + { + if (!LootTemplates_Disenchant.HaveLootFor(cond->mSourceGroup)) + { + sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `disenchant_loot_template`, ignoring.", cond->mSourceGroup); + return false; + } + LootTemplate* loot = LootTemplates_Disenchant.GetLootForConditionFill(cond->mSourceGroup); + ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); + if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + { + sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE: + { + if (!LootTemplates_Fishing.HaveLootFor(cond->mSourceGroup)) + { + sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `fishing_loot_template`, ignoring.", cond->mSourceGroup); + return false; + } + LootTemplate* loot = LootTemplates_Fishing.GetLootForConditionFill(cond->mSourceGroup); + ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); + if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + { + sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE: + { + if (!LootTemplates_Gameobject.HaveLootFor(cond->mSourceGroup)) + { + sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `gameobject_loot_template`, ignoring.", cond->mSourceGroup); + return false; + } + LootTemplate* loot = LootTemplates_Gameobject.GetLootForConditionFill(cond->mSourceGroup); + ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); + if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + { + sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE: + { + if (!LootTemplates_Item.HaveLootFor(cond->mSourceGroup)) + { + sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `item_loot_template`, ignoring.", cond->mSourceGroup); + return false; + } + LootTemplate* loot = LootTemplates_Item.GetLootForConditionFill(cond->mSourceGroup); + ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); + if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + { + sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE: + { + if (!LootTemplates_Mail.HaveLootFor(cond->mSourceGroup)) + { + sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `mail_loot_template`, ignoring.", cond->mSourceGroup); + return false; + } + LootTemplate* loot = LootTemplates_Mail.GetLootForConditionFill(cond->mSourceGroup); + ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); + if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + { + sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE: + { + if (!LootTemplates_Milling.HaveLootFor(cond->mSourceGroup)) + { + sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `milling_loot_template`, ignoring.", cond->mSourceGroup); + return false; + } + LootTemplate* loot = LootTemplates_Milling.GetLootForConditionFill(cond->mSourceGroup); + ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); + if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + { + sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE: + { + if (!LootTemplates_Pickpocketing.HaveLootFor(cond->mSourceGroup)) + { + sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `pickpocketing_loot_template`, ignoring.", cond->mSourceGroup); + return false; + } + LootTemplate* loot = LootTemplates_Pickpocketing.GetLootForConditionFill(cond->mSourceGroup); + ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); + if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + { + sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE: + { + if (!LootTemplates_Prospecting.HaveLootFor(cond->mSourceGroup)) + { + sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `prospecting_loot_template`, ignoring.", cond->mSourceGroup); + return false; + } + LootTemplate* loot = LootTemplates_Prospecting.GetLootForConditionFill(cond->mSourceGroup); + ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); + if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + { + sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE: + { + if (!LootTemplates_Reference.HaveLootFor(cond->mSourceGroup)) + { + sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `reference_loot_template`, ignoring.", cond->mSourceGroup); + return false; + } + LootTemplate* loot = LootTemplates_Reference.GetLootForConditionFill(cond->mSourceGroup); + ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); + if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + { + sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE: + { + if (!LootTemplates_Skinning.HaveLootFor(cond->mSourceGroup)) + { + sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `skinning_loot_template`, ignoring.", cond->mSourceGroup); + return false; + } + LootTemplate* loot = LootTemplates_Skinning.GetLootForConditionFill(cond->mSourceGroup); + ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); + if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + { + sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE: + { + if (!LootTemplates_Spell.HaveLootFor(cond->mSourceGroup)) + { + sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `spell_loot_template`, ignoring.", cond->mSourceGroup); + return false; + } + LootTemplate* loot = LootTemplates_Spell.GetLootForConditionFill(cond->mSourceGroup); + ItemPrototype const* pItemProto = sItemStorage.LookupEntry(cond->mSourceEntry); + if (!pItemProto && !loot->isReference(cond->mSourceEntry)) + { + sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET: + { + if (cond->mConditionType != CONDITION_SPELL_SCRIPT_TARGET) + { + sLog.outErrorDb("SourceEntry %u in `condition` table, has ConditionType %u. Only CONDITION_SPELL_SCRIPT_TARGET(18) is valid for CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET(14), ignoring.", cond->mSourceEntry, uint32(cond->mConditionType)); + return false; + } + SpellEntry const* spellProto = sSpellStore.LookupEntry(cond->mSourceEntry); + + if (!spellProto) + { + sLog.outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->mSourceEntry); + return false; + } + + bool targetfound = false; + for (uint8 i = 0; i < 3; ++i) + { + if (spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENTRY_SRC || + spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_AREA_ENTRY_SRC || + spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENTRY_DST || + spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_AREA_ENTRY_DST || + spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_NEARBY_ENTRY || + spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_NEARBY_ENTRY || + spellProto->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT_NEARBY_ENTRY || + spellProto->EffectImplicitTargetB[i] == TARGET_GAMEOBJECT_NEARBY_ENTRY || + spellProto->EffectImplicitTargetA[i] == TARGET_DST_NEARBY_ENTRY || + spellProto->EffectImplicitTargetB[i] == TARGET_DST_NEARBY_ENTRY || + spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_CONE_ENTRY || + spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_CONE_ENTRY) + { + targetfound = true; + break; + } + } + if (!targetfound) + { + sLog.outErrorDb("SourceEntry %u in `condition` table does not have any implicit target TARGET_UNIT_NEARBY_ENTRY(38) or TARGET_DST_NEARBY_ENTRY (46)\ + ,TARGET_UNIT_AREA_ENTRY_SRC(7), TARGET_UNIT_AREA_ENTRY_DST(8), TARGET_UNIT_CONE_ENTRY(60), TARGET_GAMEOBJECT_NEARBY_ENTRY(40)",cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE: + { + if (!sCreatureStorage.LookupEntry(cond->mSourceEntry)) + { + sLog.outErrorDb("SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_SPELL: + { + SpellEntry const* spellProto = sSpellStore.LookupEntry(cond->mSourceEntry); + if (!spellProto) + { + sLog.outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->mSourceEntry); + return false; + } + break; + } + case CONDITION_SOURCE_TYPE_ITEM_REQUIRED_TARGET: + { + if (cond->mConditionType != CONDITION_ITEM_TARGET) + { + sLog.outErrorDb("SourceEntry %u in `condition` table, has ConditionType %u. Only CONDITION_ITEM_TARGET(24) is valid for CONDITION_SOURCE_TYPE_ITEM_REQUIRED_TARGET(18), ignoring.", cond->mSourceEntry, uint32(cond->mConditionType)); + return false; + } + ItemPrototype const *pItemProto = objmgr.GetItemPrototype(cond->mSourceEntry); + if (!pItemProto) + { + sLog.outErrorDb("SourceEntry %u in `condition` table, does not exist in `item_tamplate`, ignoring.", cond->mSourceEntry); + return false; + } + bool bIsItemSpellValid = false; + for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) + { + if (SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(pItemProto->Spells[i].SpellId)) + { + if (pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE || + pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE) + { + ConditionList conditions = sConditionMgr.GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, pSpellInfo->Id);//script loading is done before item target loading + if (!conditions.empty()) + break; + + for (int j = 0; j < 3; ++j) + { + if (pSpellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_TARGET_ENEMY || + pSpellInfo->EffectImplicitTargetB[i] == TARGET_UNIT_TARGET_ENEMY || + pSpellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_TARGET_ANY || + pSpellInfo->EffectImplicitTargetB[i] == TARGET_UNIT_TARGET_ANY) + { + bIsItemSpellValid = true; + break; + } + } + if (bIsItemSpellValid) + break; + } + } + } + + if (!bIsItemSpellValid) + { + sLog.outErrorDb("Conditions:ITEM_REQUIRED_TARGET used by item %u does not have implicit target TARGET_CHAIN_DAMAGE(6), TARGET_DUELVSPLAYER(25), already listed in scriptTargets or doesn't have item spelltrigger.", cond->mSourceEntry); + break; + } + break; + } + case CONDITION_SOURCE_TYPE_GOSSIP_MENU: + case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: + case CONDITION_SOURCE_TYPE_NONE: + break; + } + return true; +} +bool ConditionMgr::isConditionTypeValid(Condition* cond) +{ + if (cond->mConditionType == CONDITION_NONE || cond->mConditionType >= MAX_CONDITION) + { + sLog.outErrorDb("Invalid ConditionType %u at SourceEntry %u in `condition` table, ignoring.", uint32(cond->mConditionType),cond->mSourceEntry); + return false; + } + switch (cond->mConditionType) + { + case CONDITION_AURA: + { + if (!sSpellStore.LookupEntry(cond->mConditionValue1)) + { + sLog.outErrorDb("Aura condition has non existing spell (Id: %d), skipped", cond->mConditionValue1); + return false; + } + if (cond->mConditionValue2 > 2) + { + sLog.outErrorDb("Aura condition has non existing effect index (%u) (must be 0..2), skipped", cond->mConditionValue2); + return false; + } + break; + } + case CONDITION_ITEM: + { + ItemPrototype const *proto = objmgr.GetItemPrototype(cond->mConditionValue1); + if (!proto) + { + sLog.outErrorDb("Item condition has non existing item (%u), skipped", cond->mConditionValue1); + return false; + } + if (!cond->mConditionValue2) + { + sLog.outErrorDb("Item condition has 0 set for item count in value2 (%u), skipped", cond->mConditionValue2); + return false; + } + break; + } + case CONDITION_ITEM_EQUIPPED: + { + ItemPrototype const *proto = objmgr.GetItemPrototype(cond->mConditionValue1); + if (!proto) + { + sLog.outErrorDb("ItemEquipped condition has non existing item (%u), skipped", cond->mConditionValue1); + return false; + } + if (cond->mConditionValue2) + sLog.outErrorDb("ItemEquipped condition has useless data in value2 (%u)!", cond->mConditionValue2); + break; + } + case CONDITION_ZONEID: + { + AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(cond->mConditionValue1); + if (!areaEntry) + { + sLog.outErrorDb("Zone condition has non existing area (%u), skipped", cond->mConditionValue1); + return false; + } + if (areaEntry->zone != 0) + { + sLog.outErrorDb("Zone condition requires to be in area (%u) which is a subzone but zone expected, skipped", cond->mConditionValue1); + return false; + } + if (cond->mConditionValue2) + sLog.outErrorDb("Zone condition has useless data in value2 (%u)!", cond->mConditionValue2); + break; + } + case CONDITION_REPUTATION_RANK: + { + FactionEntry const* factionEntry = sFactionStore.LookupEntry(cond->mConditionValue1); + if (!factionEntry) + { + sLog.outErrorDb("Reputation condition has non existing faction (%u), skipped", cond->mConditionValue1); + return false; + } + break; + } + case CONDITION_TEAM: + { + if (cond->mConditionValue1 != ALLIANCE && cond->mConditionValue1 != HORDE) + { + sLog.outErrorDb("Team condition specifies unknown team (%u), skipped", cond->mConditionValue1); + return false; + } + if (cond->mConditionValue2) + sLog.outErrorDb("Team condition has useless data in value2 (%u)!", cond->mConditionValue2); + break; + } + case CONDITION_SKILL: + { + SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(cond->mConditionValue1); + if (!pSkill) + { + sLog.outErrorDb("Skill condition specifies non-existing skill (%u), skipped", cond->mConditionValue1); + return false; + } + if (cond->mConditionValue2 < 1 || cond->mConditionValue2 > sWorld.GetConfigMaxSkillValue()) + { + sLog.outErrorDb("Skill condition specifies invalid skill value (%u), skipped", cond->mConditionValue2); + return false; + } + break; + } + case CONDITION_QUESTREWARDED: + case CONDITION_QUESTTAKEN: + case CONDITION_QUEST_NONE: + { + Quest const *Quest = objmgr.GetQuestTemplate(cond->mConditionValue1); + if (!Quest) + { + sLog.outErrorDb("Quest condition specifies non-existing quest (%u), skipped", cond->mConditionValue1); + return false; + } + if (cond->mConditionValue2) + sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", cond->mConditionValue2); + break; + } + case CONDITION_AD_COMMISSION_AURA: + { + if (cond->mConditionValue1) + sLog.outErrorDb("Quest condition has useless data in value1 (%u)!", cond->mConditionValue1); + if (cond->mConditionValue2) + sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", cond->mConditionValue2); + break; + } + case CONDITION_NO_AURA: + { + if (!sSpellStore.LookupEntry(cond->mConditionValue1)) + { + sLog.outErrorDb("Aura condition has non existing spell (Id: %d), skipped", cond->mConditionValue1); + return false; + } + if (cond->mConditionValue2 > 2) + { + sLog.outErrorDb("Aura condition has non existing effect index (%u) in value2 (must be 0..2), skipped", cond->mConditionValue2); + return false; + } + break; + } + case CONDITION_ACTIVE_EVENT: + { + GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + if (cond->mConditionValue1 >=events.size() || !events[cond->mConditionValue1].isValid()) + { + sLog.outErrorDb("Active event condition has non existing event id (%u), skipped", cond->mConditionValue1); + return false; + } + if (cond->mConditionValue2) + sLog.outErrorDb("Active event condition has useless data in value2 (%u)!", cond->mConditionValue2); + break; + } + case CONDITION_ACHIEVEMENT: + { + AchievementEntry const* achievement = GetAchievementStore()->LookupEntry(cond->mConditionValue1); + if (!achievement) + { + sLog.outErrorDb("Achivemen condition has non existing achivement id (%u), skipped", cond->mConditionValue1); + return false; + } + if (cond->mConditionValue2) + sLog.outErrorDb("Achivemen condition has useless data in value2 (%u)!", cond->mConditionValue2); + break; + } + case CONDITION_CLASS: + { + if (cond->mConditionValue1 >= MAX_CLASSES) + { + sLog.outErrorDb("Class condition has non existing class (%u), skipped", cond->mConditionValue1); + return false; + } + if (cond->mConditionValue2) + sLog.outErrorDb("Class condition has useless data in value2 (%u)!", cond->mConditionValue2); + break; + } + case CONDITION_RACE: + { + if (cond->mConditionValue1 >= MAX_RACES) + { + sLog.outErrorDb("Race condition has non existing race (%u), skipped", cond->mConditionValue1); + return false; + } + if (cond->mConditionValue2) + sLog.outErrorDb("Race condition has useless data in value2 (%u)!", cond->mConditionValue2); + break; + } + case CONDITION_SPELL_SCRIPT_TARGET: + { + if (cond->mConditionValue1 >= MAX_SPELL_TARGET_TYPE) + { + sLog.outErrorDb("SpellTarget condition has non existing spell target type (%u), skipped", cond->mConditionValue1); + return false; + } + switch(cond->mConditionValue1) + { + case SPELL_TARGET_TYPE_GAMEOBJECT: + { + if (cond->mConditionValue2 && !sGOStorage.LookupEntry(cond->mConditionValue2)) + { + sLog.outErrorDb("SpellTarget condition has non existing gameobject (%u) as target, skipped", cond->mConditionValue2); + return false; + } + break; + } + case SPELL_TARGET_TYPE_CONTROLLED: + case SPELL_TARGET_TYPE_CREATURE: + case SPELL_TARGET_TYPE_DEAD: + { + if (cond->mConditionValue2 && !sCreatureStorage.LookupEntry(cond->mConditionValue2)) + { + sLog.outErrorDb("SpellTarget condition has non existing creature template entry (%u) as target, skipped", cond->mConditionValue2); + return false; + } + const CreatureInfo* cInfo = sCreatureStorage.LookupEntry(cond->mConditionValue2); + + if (cond->mSourceEntry == 30427 && !cInfo->SkinLootId) + { + sLog.outErrorDb("SpellTarget condition has creature entry %u as a target of spellid 30427, but this creature has no skinlootid. Gas extraction will not work!, skipped", cond->mConditionValue2); + return false; + } + break; + } + } + if (cond->mConditionValue3) + sLog.outErrorDb("SpellTarget condition has useless data in value3 (%u)!", cond->mConditionValue3); + break; + } + case CONDITION_CREATURE_TARGET: + { + if (!cond->mConditionValue1 && !sCreatureStorage.LookupEntry(cond->mConditionValue1)) + { + sLog.outErrorDb("CreatureTarget condition has non existing creature template entry (%u) as target, skipped", cond->mConditionValue1); + return false; + } + if (cond->mConditionValue2) + sLog.outErrorDb("CreatureTarget condition has useless data in value2 (%u)!", cond->mConditionValue2); + break; + } + case CONDITION_TARGET_HEALTH_BELOW_PCT: + { + if (cond->mConditionValue1 > 100) + { + sLog.outErrorDb("TargetHealthBelowPct condition has invalid data in value1 (%u), skipped", cond->mConditionValue1); + return false; + } + if (cond->mConditionValue2) + sLog.outErrorDb("TargetHealthBelowPct condition has useless data in value2 (%u)!", cond->mConditionValue2); + break; + } + case CONDITION_TARGET_RANGE: + { + if (cond->mConditionValue2 && cond->mConditionValue2 < cond->mConditionValue1)//maxDist can be 0 for infinit max range + { + sLog.outErrorDb("TargetRange condition has max distance closer then min distance, skipped"); + return false; + } + break; + } + case CONDITION_MAPID: + { + MapEntry const * me = sMapStore.LookupEntry(cond->mConditionValue1); + if (!me) + { + sLog.outErrorDb("Map condition has non existing map (%u), skipped", cond->mConditionValue1); + return false; + } + if (cond->mConditionValue2) + sLog.outErrorDb("Map condition has useless data in value2 (%u)!", cond->mConditionValue2); + break; + } + case CONDITION_ITEM_TARGET: + { + if (!cond->mConditionValue1 || cond->mConditionValue1 > MAX_ITEM_REQ_TARGET_TYPE) + { + sLog.outErrorDb("ItemTarget condition has incorrect target type (%u), skipped", cond->mConditionValue1); + return false; + } + if (!cond->mConditionValue2 && !sCreatureStorage.LookupEntry(cond->mConditionValue2)) + { + sLog.outErrorDb("ItemTarget condition has non existing creature template entry (%u) as target, skipped", cond->mConditionValue2); + return false; + } + if (cond->mConditionValue3) + sLog.outErrorDb("ItemTarget condition has useless data in value3 (%u)!", cond->mConditionValue3); + break; + } + case CONDITION_AREAID: + case CONDITION_INSTANCE_DATA: + break; + } + return true; +} diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h new file mode 100644 index 00000000000..bc2ce8d01a2 --- /dev/null +++ b/src/server/game/Conditions/ConditionMgr.h @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_CONDITIONMGR_H +#define TRINITY_CONDITIONMGR_H + +#include "LootMgr.h" + +class Player; +class Unit; +class LootTemplate; + +enum ConditionType +{ // value1 value2 value3 + CONDITION_NONE = 0, // 0 0 0 always true + CONDITION_AURA = 1, // spell_id effindex +referenceID true if has aura of spell_id with effect effindex + CONDITION_ITEM = 2, // item_id count +referenceID true if has #count of item_ids + CONDITION_ITEM_EQUIPPED = 3, // item_id 0 +referenceID true if has item_id equipped + CONDITION_ZONEID = 4, // zone_id 0 +referenceID true if in zone_id + CONDITION_REPUTATION_RANK = 5, // faction_id min_rank +referenceID true if has min_rank for faction_id + CONDITION_TEAM = 6, // player_team 0, +referenceID 469 - Alliance, 67 - Horde) + CONDITION_SKILL = 7, // skill_id skill_value +referenceID true if has skill_value for skill_id + CONDITION_QUESTREWARDED = 8, // quest_id 0 +referenceID true if quest_id was rewarded before + CONDITION_QUESTTAKEN = 9, // quest_id 0, +referenceID true while quest active + CONDITION_AD_COMMISSION_AURA = 10, // 0 0, +referenceID true while one from AD commission aura active + CONDITION_NO_AURA = 11, // spell_id effindex +referenceID true if does not have aura of spell_id with effect effindex + CONDITION_ACTIVE_EVENT = 12, // event_id 0 +referenceID true if event is active + CONDITION_INSTANCE_DATA = 13, // entry data +referenceID true if data is set in current instance + CONDITION_QUEST_NONE = 14, // quest_id 0 +referenceID true if doesn't have quest saved + CONDITION_CLASS = 15, // class 0 +referenceID true if player's class is equal to class + CONDITION_RACE = 16, // race 0 +referenceID true if player's race is equal to race + CONDITION_ACHIEVEMENT = 17, // achievement_id 0 +referenceID true if achievement is complete + CONDITION_SPELL_SCRIPT_TARGET = 18, // SpellScriptTargetType, TargetEntry, 0 + CONDITION_CREATURE_TARGET = 19, // creature entry 0 +referenceID true if current target is creature with value1 entry + CONDITION_TARGET_HEALTH_BELOW_PCT = 20, // 0-100 0 +referenceID true if target's health is below value1 percent, false if over or no target + CONDITION_TARGET_RANGE = 21, // minDistance maxDist +referenceID true if target is closer then minDist and further then maxDist or if max is 0 then max dist is infinit + CONDITION_MAPID = 22, // map_id 0 +referenceID true if in map_id + CONDITION_AREAID = 23, // area_id 0 +referenceID true if in area_id + CONDITION_ITEM_TARGET = 24 // ItemRequiredTargetType, TargetEntry, 0 +}; + +#define MAX_CONDITION 25 // maximum value in ConditionType enum + +enum ConditionSourceType +{ + CONDITION_SOURCE_TYPE_NONE = 0,//DONE + CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE = 1,//DONE + CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE = 2,//DONE + CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE = 3,//DONE + CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE = 4,//DONE + CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE = 5,//DONE + CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE = 6,//DONE + CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE = 7,//DONE + CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE = 8,//DONE + CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE = 9,//DONE + CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE = 10,//DONE + CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE = 11,//DONE + CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE = 12,//DONE + CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET = 13,//DONE + CONDITION_SOURCE_TYPE_GOSSIP_MENU = 14,//DONE + CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION = 15,//DONE + CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE = 16,//DONE + CONDITION_SOURCE_TYPE_SPELL = 17,//DONE + CONDITION_SOURCE_TYPE_ITEM_REQUIRED_TARGET = 18//DONE +}; + +#define MAX_CONDITIONSOURCETYPE 19 + +struct Condition +{ + ConditionSourceType mSourceType; //SourceTypeOrReferenceId + uint32 mSourceGroup; + uint32 mSourceEntry; + uint32 mElseGroup; + ConditionType mConditionType; //ConditionTypeOrReference + uint32 mConditionValue1; + uint32 mConditionValue2; + uint32 mConditionValue3; + uint32 ErrorTextd; + uint32 mReferenceId; + + Condition() + { + mSourceType = CONDITION_SOURCE_TYPE_NONE; + mSourceGroup = 0; + mSourceEntry = 0; + mElseGroup = 0; + mConditionType = CONDITION_NONE; + mConditionValue1 = 0; + mConditionValue2 = 0; + mConditionValue3 = 0; + mReferenceId = 0; + ErrorTextd = 0; + } + bool Meets(Player * player, Unit* targetOverride = NULL); + bool isLoaded() { return mConditionType > CONDITION_NONE || mReferenceId; } +}; + +typedef std::list ConditionList; +typedef std::map ConditionTypeMap; +typedef std::map ConditionMap;//used for all conditions, except references + +typedef std::map ConditionReferenceMap;//only used for references + +class ConditionMgr +{ + public: + ConditionMgr(); + ~ConditionMgr(); + + void LoadConditions(bool isReload = false); + bool isConditionTypeValid(Condition* cond); + ConditionList GetConditionReferences(uint32 refId); + + bool IsPlayerMeetToConditions(Player* player, ConditionList conditions, Unit* targetOverride = NULL); + ConditionList GetConditionsForNotGroupedEntry(ConditionSourceType sType, uint32 uEntry); + + protected: + ConditionMap m_ConditionMap; + ConditionReferenceMap m_ConditionReferenceMap; + + private: + bool isSourceTypeValid(Condition* cond); + bool addToLootTemplate(Condition* cond, LootTemplate* loot); + bool addToGossipMenus(Condition* cond); + bool addToGossipMenuItems(Condition* cond); + bool IsPlayerMeetToConditionList(Player* player,const ConditionList& conditions, Unit* targetOverride = NULL); + + bool isGroupable(ConditionSourceType sourceType) + { + return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE || + sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU || + sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION); + } +}; + +#define sConditionMgr Trinity::Singleton::Instance() + +#endif diff --git a/src/server/game/DungeonFinding/LFG.h b/src/server/game/DungeonFinding/LFG.h new file mode 100644 index 00000000000..c1b55443852 --- /dev/null +++ b/src/server/game/DungeonFinding/LFG.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LFG_H +#define _LFG_H + +#include "Platform/Define.h" +#include "Object.h" + +enum LfgRoles +{ + ROLE_NONE = 0x00, + ROLE_LEADER = 0x01, + ROLE_TANK = 0x02, + ROLE_HEALER = 0x04, + ROLE_DAMAGE = 0x08, +}; + +enum LfgUpdateType +{ + LFG_UPDATETYPE_LEADER = 1, + LFG_UPDATETYPE_ROLECHECK_ABORTED = 4, + LFG_UPDATETYPE_JOIN_PROPOSAL = 5, + LFG_UPDATETYPE_ROLECHECK_FAILED = 6, + LFG_UPDATETYPE_REMOVED_FROM_QUEUE = 7, + LFG_UPDATETYPE_PROPOSAL_FAILED = 8, + LFG_UPDATETYPE_PROPOSAL_DECLINED = 9, + LFG_UPDATETYPE_GROUP_FOUND = 10, + LFG_UPDATETYPE_ADDED_TO_QUEUE = 12, + LFG_UPDATETYPE_PROPOSAL_FOUND = 13, + LFG_UPDATETYPE_CLEAR_LOCK_LIST = 14, + LFG_UPDATETYPE_GROUP_MEMBER_OFFLINE = 15, + LFG_UPDATETYPE_GROUP_DISBAND = 16, +}; + +typedef std::set LfgDungeonSet; + +struct LookingForGroup +{ + LookingForGroup(): roles(0) + { + donerandomDungeons.clear(); + applyDungeons.clear(); + } + std::string comment; + int8 roles; + + bool isDungeonDone(const uint32 entry) + { + return donerandomDungeons.find(entry) != donerandomDungeons.end(); + } + + LfgDungeonSet applyDungeons; // Dungeons the player have applied for + LfgDungeonSet donerandomDungeons; // Finished random Dungeons (to calculate the bonus); +}; + +#endif diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp new file mode 100644 index 00000000000..ba418cdb191 --- /dev/null +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -0,0 +1,1100 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "Policies/SingletonImp.h" +#include "Common.h" +#include "SharedDefines.h" +#include "Group.h" +#include "Player.h" +#include "LFGMgr.h" +#include "ObjectMgr.h" +#include "WorldPacket.h" + +INSTANTIATE_SINGLETON_1(LFGMgr); + +/*********************************************************/ +/*** LFG QUEUES ***/ +/*********************************************************/ + +LFGQueue::LFGQueue() +{ + m_LfgQueue.clear(); + avgWaitTime = -1; + waitTimeTanks = -1; + waitTimeHealer = -1; + waitTimeDps = -1; +} + +LFGQueue::~LFGQueue() +{ + m_LfgQueue.clear(); +} + +void LFGQueue::AddToQueue(uint64 guid, LfgQueueInfo* pqInfo) +{ + if (LfgQueueInfo* qInfo = m_LfgQueue[guid]) + delete qInfo; + m_LfgQueue[guid] = pqInfo; + // ATM will only add it to the queue... No find group implementation... yet (on purpose) +} + +bool LFGQueue::RemoveFromQueue(uint64 guid) +{ + if (m_LfgQueue.empty()) + return false; + + LfgQueueInfoMap::iterator itr = m_LfgQueue.find(guid); + if (itr == m_LfgQueue.end()) + return false; + + delete itr->second; + m_LfgQueue.erase(itr); + return true; +} + +LfgQueueInfo* LFGQueue::GetQueueInfo(uint64 guid) +{ + return m_LfgQueue[guid]; +} + +void LFGQueue::Update() +{ + if (m_LfgQueue.empty()) + return; + + Player *plr; + LfgQueueInfo *queue; + time_t currTime = time(NULL); + uint32 queuedTime; + uint8 role = 0; + int32 waitTime = -1; + for (LfgQueueInfoMap::const_iterator itQueue = m_LfgQueue.begin(); itQueue != m_LfgQueue.end(); ++itQueue) + { + queue = itQueue->second; + // Update queue status + queuedTime = uint32(currTime - queue->joinTime); + for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer) + { + plr = objmgr.GetPlayer(itPlayer->first); + if (!plr) + continue; + role = itPlayer->second; + if (role & ROLE_TANK) + { + if (role & ROLE_HEALER || role & ROLE_DAMAGE) + waitTime = avgWaitTime; + else + waitTime = waitTimeTanks; + } + else if (role & ROLE_HEALER) + { + if (role & ROLE_DAMAGE) + waitTime = avgWaitTime; + else + waitTime = waitTimeDps; + } + plr->GetSession()->SendLfgQueueStatus(queue->dungeonId, waitTime, avgWaitTime, waitTimeTanks, waitTimeHealer, waitTimeDps, queuedTime, queue->tanks, queue->healers, queue->dps); + } + } +} + +LFGMgr::LFGMgr() +{ + m_QueueTimer = 0; + m_update = true; +} + +LFGMgr::~LFGMgr() +{ + // RewardList to be removed -> query quest system + for (LfgRewardList::iterator it = m_RewardList.begin(); it != m_RewardList.end(); ++it) + delete *it; + m_RewardList.clear(); + + // RewardDoneList to be removed -> query quest system + for (LfgRewardList::iterator it = m_RewardDoneList.begin(); it != m_RewardDoneList.end(); ++it) + delete *it; + m_RewardDoneList.clear(); + + for(LFGQueueMap::iterator it = m_Queues.begin(); it != m_Queues.end(); ++it) + delete it->second; + m_Queues.clear(); + + for (LfgDungeonMap::iterator it = m_DungeonsMap.begin(); it != m_DungeonsMap.end(); ++it) + { + it->second->clear(); + delete it->second; + } + m_DungeonsMap.clear(); + + for (LfgRoleCheckMap::iterator it = m_RoleChecks.begin(); it != m_RoleChecks.end(); ++it) + delete it->second; + m_RoleChecks.clear(); +} + +void LFGMgr::Update(uint32 diff) +{ + if (!m_update) + return; + + // Update all players status queue info + if (m_QueueTimer > LFG_QUEUEUPDATE_INTERVAL) + { + m_QueueTimer = 0; + for (LFGQueueMap::iterator it = m_Queues.begin(); it != m_Queues.end(); ++it) + it->second->Update(); + } + else + m_QueueTimer += diff; + + time_t currTime = time(NULL); + + // Remove obsolete role checks + LfgRoleCheckMap::iterator itRoleCheck; + LfgRoleCheck *pRoleCheck; + for (LfgRoleCheckMap::iterator it = m_RoleChecks.begin(); it != m_RoleChecks.end();) + { + itRoleCheck = it++; + pRoleCheck = itRoleCheck->second; + if (currTime < pRoleCheck->cancelTime) + continue; + pRoleCheck->result = LFG_ROLECHECK_MISSING_ROLE; + + WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + pRoleCheck->dungeons.size() * 4 + 1 + pRoleCheck->roles.size() * (8 + 1 + 4 + 1)); + sLog.outDebug("SMSG_LFG_ROLE_CHECK_UPDATE"); + BuildLfgRoleCheck(data, pRoleCheck); + Player *plr = NULL; + for (LfgRolesMap::const_iterator itRoles = pRoleCheck->roles.begin(); itRoles != pRoleCheck->roles.end(); ++itRoles) + { + plr = objmgr.GetPlayer(itRoles->first); + if (!plr) + continue; + plr->GetSession()->SendPacket(&data); + plr->m_lookingForGroup.applyDungeons.clear(); + plr->m_lookingForGroup.roles = 0; + + if (itRoles->first == pRoleCheck->leader) + plr->GetSession()->SendLfgJoinResult(LFG_JOIN_FAILED, pRoleCheck->result); + } + delete pRoleCheck; + m_RoleChecks.erase(itRoleCheck); + } +} + +/// +/// Initialize Looking For Group +/// +void LFGMgr::InitLFG() +{ + // Fill reward data (to be removed -> query quest system) + LfgReward *reward; + for (uint8 i = 0; i <= LFG_REWARD_DATA_SIZE; ++i) + { + reward = new LfgReward(); + reward->strangers = 0; + reward->baseXP = RewardDungeonData[i][0]; + reward->baseMoney = RewardDungeonData[i][1]; + reward->variableMoney = 0; + reward->variableXP = 0; + reward->itemId = RewardDungeonData[i][2]; + reward->displayId = RewardDungeonData[i][3]; + reward->stackCount = RewardDungeonData[i][4]; + m_RewardList.push_back(reward); + } + + for (uint8 i = 0; i < LFG_REWARD_DATA_SIZE; ++i) + { + reward = new LfgReward(); + reward->strangers = 0; + reward->baseXP = RewardDungeonDoneData[i][0]; + reward->baseMoney = RewardDungeonDoneData[i][1]; + reward->variableMoney = 0; + reward->variableXP = 0; + reward->itemId = RewardDungeonDoneData[i][2]; + reward->displayId = RewardDungeonDoneData[i][3]; + reward->stackCount = RewardDungeonDoneData[i][4]; + m_RewardDoneList.push_back(reward); + } + // Initialize dungeonMap + m_DungeonsMap[LFG_ALL_DUNGEONS] = GetAllDungeons(); + m_DungeonsMap[LFG_RANDOM_CLASSIC] = GetDungeonsByRandom(LFG_RANDOM_CLASSIC); + m_DungeonsMap[LFG_RANDOM_BC_NORMAL] = GetDungeonsByRandom(LFG_RANDOM_BC_NORMAL); + m_DungeonsMap[LFG_RANDOM_BC_HEROIC] = GetDungeonsByRandom(LFG_RANDOM_BC_HEROIC); + m_DungeonsMap[LFG_RANDOM_LK_NORMAL] = GetDungeonsByRandom(LFG_RANDOM_LK_NORMAL); + m_DungeonsMap[LFG_RANDOM_LK_HEROIC] = GetDungeonsByRandom(LFG_RANDOM_LK_HEROIC); +} + +/// +/// Adds the player to lfg queue +/// +/// Player +void LFGMgr::Join(Player *plr) +{ + Group *grp = plr->GetGroup(); + + // TODO - 2010-05-27 Anyone can init rolecheck when already in a LFD Group? + if (grp && grp->GetLeaderGUID() != plr->GetGUID()) + return; + + // Previous checks before joining + LfgJoinResult result = LFG_JOIN_OK; + if (plr->InBattleGround() || plr->InArena()) + result = LFG_JOIN_USING_BG_SYSTEM; + else if (plr->HasAura(LFG_SPELL_DESERTER)) + result = LFG_JOIN_DESERTER; + else if (plr->HasAura(LFG_SPELL_COOLDOWN)) + result = LFG_JOIN_RANDOM_COOLDOWN; + else + { + // Check if all dungeons are valid + for (LfgDungeonSet::const_iterator it = plr->m_lookingForGroup.applyDungeons.begin(); it != plr->m_lookingForGroup.applyDungeons.end(); ++it) + { + if ((m_DungeonsMap[LFG_ALL_DUNGEONS])->find(*it) == (m_DungeonsMap[LFG_ALL_DUNGEONS])->end()) + { + result = LFG_JOIN_DUNGEON_INVALID; + break; + } + } + } + + if (grp && result == LFG_JOIN_OK) + { + if (grp->GetMembersCount() > MAXGROUPSIZE) + result = LFG_JOIN_TOO_MUCH_MEMBERS; + else if(grp->isRaidGroup()) + result = LFG_JOIN_MIXED_RAID_DUNGEON; + else + { + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL && result == LFG_JOIN_OK; itr = itr->next()) + { + if (Player *plrg = itr->getSource()) + { + if (plrg->HasAura(LFG_SPELL_DESERTER)) + result = LFG_JOIN_PARTY_DESERTER; + else if (plrg->HasAura(LFG_SPELL_COOLDOWN)) + result = LFG_JOIN_PARTY_RANDOM_COOLDOWN; + } + else + result = LFG_JOIN_DISCONNECTED; + } + } + } + + if (result != LFG_JOIN_OK) + { + plr->m_lookingForGroup.applyDungeons.clear(); + plr->m_lookingForGroup.roles = 0; + plr->GetSession()->SendLfgJoinResult(result, 0); + return; + } + + if (grp) + { + Player *plrg = NULL; + for (GroupReference *itr = plr->GetGroup()->GetFirstMember(); itr != NULL; itr = itr->next()) + { + plrg = itr->getSource(); // Not null, checked earlier + plrg->m_lookingForGroup.applyDungeons = plr->m_lookingForGroup.applyDungeons; + plrg->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_JOIN_PROPOSAL); + } + UpdateRoleCheck(grp, plr); + } + else + { + plr->GetSession()->SendLfgJoinResult(LFG_JOIN_OK, 0); + plr->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_JOIN_PROPOSAL); + + // Add player to queue + LfgQueueInfo *pqInfo; + uint8 groupType = 0; + uint8 tanks = LFG_TANKS_NEEDED; + uint8 healers = LFG_HEALERS_NEEDED; + uint8 dps = LFG_DPS_NEEDED; + if (plr->m_lookingForGroup.roles & ROLE_TANK) + --tanks; + else if (plr->m_lookingForGroup.roles & ROLE_HEALER) + --healers; + else + --dps; + m_update = false; + for (LfgDungeonSet::const_iterator it = plr->m_lookingForGroup.applyDungeons.begin(); it != plr->m_lookingForGroup.applyDungeons.end(); ++it) + { + groupType = GetDungeonGroupType(*it); + pqInfo = m_Queues[groupType] ? m_Queues[groupType]->GetQueueInfo(plr->GetGUID()) : NULL; + // if exist we have already added the player with another dungeon sharing same GroupType + if (pqInfo) + continue; + pqInfo = new LfgQueueInfo(); + pqInfo->dungeonId = *it; + pqInfo->joinTime = time_t(time(NULL)); + pqInfo->tanks = tanks; + pqInfo->healers = healers; + pqInfo->dps = dps; + pqInfo->roles[plr->GetGUID()] = plr->m_lookingForGroup.roles; + if (!m_Queues[groupType]) + m_Queues[groupType] = new LFGQueue(); + m_Queues[groupType]->AddToQueue(plr->GetGUID(), pqInfo); + } + m_update = true; + } +} + +/// +/// Leave the lfg queue +/// +/// Player (could be NULL) +/// Group (could be NULL) +void LFGMgr::Leave(Player *plr, Group *grp /* = NULL*/) +{ + uint64 guid = grp ? grp->GetGUID() : plr ? plr->GetGUID() : 0; + assert(guid); + + // Check if player was in a rolecheck + if (grp) + { + LfgRoleCheckMap::iterator itRoleCheck = m_RoleChecks.find(GUID_LOPART(grp->GetGUID())); + if (itRoleCheck != m_RoleChecks.end()) + { + UpdateRoleCheck(grp); // No player to update role = LFG_ROLECHECK_ABORTED + return; + } + } + + // Check if player/group was in the queue + bool inQueue = false; + for (LFGQueueMap::iterator it = m_Queues.begin(); it != m_Queues.end(); ++it) + inQueue |= it->second->RemoveFromQueue(guid); + + // Not in queue + if (!inQueue) + return; + + if (grp) + { + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + if (Player *plrg = itr->getSource()) + { + plrg->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); + plrg->m_lookingForGroup.applyDungeons.clear(); + plrg->m_lookingForGroup.roles = 0; + } + } + else + { + plr->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); + plr->m_lookingForGroup.applyDungeons.clear(); + plr->m_lookingForGroup.roles = 0; + } +} + +/// +/// Update the Role check info with the player selected role. +/// +/// Group +/// Player +void LFGMgr::UpdateRoleCheck(Group *grp, Player *plr /* = NULL*/) +{ + assert(grp); + + uint32 rolecheckId = GUID_LOPART(grp->GetGUID()); + LfgRoleCheck *pRoleCheck = NULL; + LfgRolesMap check_roles; + LfgRoleCheckMap::iterator itRoleCheck = m_RoleChecks.find(rolecheckId); + bool newRoleCheck = itRoleCheck == m_RoleChecks.end(); + if (newRoleCheck) + { + if (!grp->IsLeader(plr->GetGUID())) + return; + + pRoleCheck = new LfgRoleCheck(); + pRoleCheck->cancelTime = time_t(time(NULL)) + LFG_TIME_ROLECHECK; + pRoleCheck->result = LFG_ROLECHECK_INITIALITING; + pRoleCheck->leader = plr->GetGUID(); + + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + if (Player *plrg = itr->getSource()) + pRoleCheck->roles[plrg->GetGUID()] = 0; + + pRoleCheck->dungeons = plr->m_lookingForGroup.applyDungeons; + } + else + pRoleCheck = itRoleCheck->second; + + LfgLockStatusMap *playersLockMap = NULL; + if (plr) + { + // Player selected no role. + if (plr->m_lookingForGroup.roles < ROLE_TANK) + pRoleCheck->result = LFG_ROLECHECK_NO_ROLE; + else + { + // Check if all players have selected a role + pRoleCheck->roles[plr->GetGUID()] = plr->m_lookingForGroup.roles; + uint8 size = 0; + for (LfgRolesMap::const_iterator itRoles = pRoleCheck->roles.begin(); itRoles != pRoleCheck->roles.end() && itRoles->second != ROLE_NONE; ++itRoles) + ++size; + + if (pRoleCheck->roles.size() == size) + { + // use temporal var to check roles, CheckGroupRoles modifies the roles + for (LfgRolesMap::const_iterator itRoles = pRoleCheck->roles.begin(); itRoles != pRoleCheck->roles.end(); ++itRoles) + check_roles[itRoles->first] = itRoles->second; + + if (!CheckGroupRoles(check_roles)) // Group is not posible + pRoleCheck->result = LFG_ROLECHECK_WRONG_ROLES; + else + { + // Check if we can find a dungeon for that group + pRoleCheck->result = LFG_ROLECHECK_FINISHED; + if (pRoleCheck->dungeons.size() > 1) + playersLockMap = GetPartyLockStatusDungeons(plr, &pRoleCheck->dungeons); + else + { + LfgDungeonSet::const_iterator it = pRoleCheck->dungeons.begin(); + LFGDungeonEntry const *dungeon = sLFGDungeonStore.LookupEntry(*it); + if (dungeon && dungeon->type == LFG_TYPE_RANDOM) + playersLockMap = GetPartyLockStatusDungeons(plr, m_DungeonsMap[*it]); + else + playersLockMap = GetPartyLockStatusDungeons(plr, &pRoleCheck->dungeons); + } + } + } + } + } + else + pRoleCheck->result = LFG_ROLECHECK_ABORTED; + + WorldSession *session; + WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + pRoleCheck->dungeons.size() * 4 + 1 + pRoleCheck->roles.size() * (8 + 1 + 4 + 1)); + sLog.outDebug("SMSG_LFG_ROLE_CHECK_UPDATE"); + BuildLfgRoleCheck(data, pRoleCheck); + + Player *plrg = NULL; + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + plrg = itr->getSource(); + if (!plrg) + continue; + + session = plrg->GetSession(); + if (!newRoleCheck && plr) + session->SendLfgRoleChosen(plr->GetGUID(), plr->m_lookingForGroup.roles); + session->SendPacket(&data); + + switch(pRoleCheck->result) + { + case LFG_ROLECHECK_INITIALITING: + continue; + case LFG_ROLECHECK_FINISHED: + if (!playersLockMap) + { + session->SendLfgUpdateParty(LFG_UPDATETYPE_ADDED_TO_QUEUE); + } + else + { + if (grp->IsLeader(plrg->GetGUID())) + { + uint32 size = 0; + for (LfgLockStatusMap::const_iterator it = playersLockMap->begin(); it != playersLockMap->end(); ++it) + size += 8 + 4 + it->second->size() * (4 + 4); + WorldPacket data(SMSG_LFG_JOIN_RESULT, 4 + 4 + size); + sLog.outDebug("SMSG_LFG_JOIN_RESULT"); + data << uint32(LFG_JOIN_PARTY_NOT_MEET_REQS); // Check Result + data << uint32(0); // Check Value (always 0 when PartyNotMeetReqs + BuildPartyLockDungeonBlock(data, playersLockMap); + session->SendPacket(&data); + } + session->SendLfgUpdateParty(LFG_UPDATETYPE_ROLECHECK_FAILED); + plrg->m_lookingForGroup.applyDungeons.clear(); + plrg->m_lookingForGroup.roles = 0; + } + break; + default: + if (grp->IsLeader(plrg->GetGUID())) + session->SendLfgJoinResult(LFG_JOIN_FAILED, pRoleCheck->result); + session->SendLfgUpdateParty(LFG_UPDATETYPE_ROLECHECK_FAILED); + plrg->m_lookingForGroup.applyDungeons.clear(); + plrg->m_lookingForGroup.roles = 0; + break; + } + } + + if (pRoleCheck->result == LFG_ROLECHECK_FINISHED) + { + // Add qroup to queue + LfgQueueInfo *pqInfo; + uint8 groupType = 0; + uint8 tanks = LFG_TANKS_NEEDED; + uint8 healers = LFG_HEALERS_NEEDED; + uint8 dps = LFG_DPS_NEEDED; + for (LfgRolesMap::const_iterator it = check_roles.begin(); it != check_roles.end(); ++it) + { + if (it->second & ROLE_TANK) + --tanks; + else if (it->second & ROLE_HEALER) + --healers; + else + --dps; + } + uint64 guid = grp->GetGUID(); + m_update = false; + for (LfgDungeonSet::const_iterator it = pRoleCheck->dungeons.begin(); it != pRoleCheck->dungeons.end(); ++it) + { + groupType = GetDungeonGroupType(*it); + pqInfo = m_Queues[groupType] ? m_Queues[groupType]->GetQueueInfo(guid) : NULL; + // if exist we have already added the player with another dungeon sharing same GroupType + if (pqInfo) + continue; + pqInfo = new LfgQueueInfo(); + pqInfo->dungeonId = *it; + pqInfo->joinTime = time_t(time(NULL)); + pqInfo->tanks = tanks; + pqInfo->healers = healers; + pqInfo->dps = dps; + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + if (Player *plrg = itr->getSource()) + pqInfo->roles[plrg->GetGUID()] = plrg->m_lookingForGroup.roles; + } + if (!m_Queues[groupType]) + m_Queues[groupType] = new LFGQueue(); + m_Queues[groupType]->AddToQueue(guid, pqInfo); + } + m_update = true; + } + + if (pRoleCheck->result != LFG_ROLECHECK_INITIALITING) + { + delete pRoleCheck; + if (!newRoleCheck) + m_RoleChecks.erase(itRoleCheck); + } + else if (newRoleCheck) + m_RoleChecks[rolecheckId] = pRoleCheck; +} + +/// +/// Check if a group can be formed with the given group +/// +/// Map of roles +/// bool, will be used to remove ROLE_LEADER +/// bool +bool LFGMgr::CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag /*= true*/) +{ + if (!groles.size()) + return false; + + uint8 damage = 0; + uint8 tank = 0; + uint8 healer = 0; + uint64 tguid = 0; + uint64 hguid = 0; + uint64 dguid = 0; + uint64 guid = 0; + uint8 role = 0; + + if (removeLeaderFlag) + for (LfgRolesMap::iterator it = groles.begin(); it != groles.end(); ++it) + it->second &= ~ROLE_LEADER; + + for (LfgRolesMap::const_iterator it = groles.begin(); it != groles.end(); ++it) + { + guid = it->first; + role = it->second; + + if (role == ROLE_NONE) + return false; + + if (role & ROLE_TANK) + { + if (!tank) + { + tguid = guid; + ++tank; + } + else + { + if (groles[tguid] == ROLE_TANK) + tguid = guid; + groles[tguid] -= ROLE_TANK; + return CheckGroupRoles(groles, false); + } + } + + if (role & ROLE_HEALER) + { + if (!healer) + { + hguid = guid; + ++healer; + } + else + { + if (groles[hguid] == ROLE_HEALER) + hguid = guid; + groles[hguid] -= ROLE_HEALER; + return CheckGroupRoles(groles, false); + } + } + + if (role & ROLE_DAMAGE) + { + if (damage < 3) + { + if (!damage) + dguid = guid; + ++damage; + } + else + { + if (groles[dguid] == ROLE_DAMAGE) + dguid = guid; + groles[dguid] -= ROLE_DAMAGE; + if (!CheckGroupRoles(groles, false)) + groles[dguid] += ROLE_DAMAGE; + else + return true; + } + } + } + return true; +} + + + +// --------------------------------------------------------------------------// +// Packet Functions +// --------------------------------------------------------------------------// + +/// +/// Build lfgRolecheck packet +/// +/// WorldPacket +/// Player +/// Player status in LFG system +void LFGMgr::BuildLfgRoleCheck(WorldPacket &data, LfgRoleCheck *pRoleCheck) +{ + assert(pRoleCheck); + + Player *plr; + uint8 roles; + + data << uint32(pRoleCheck->result); // Check result + data << uint8(pRoleCheck->result == LFG_ROLECHECK_INITIALITING); + data << uint8(pRoleCheck->dungeons.size()); // Number of dungeons + LFGDungeonEntry const *dungeon; + for (LfgDungeonSet::iterator it = pRoleCheck->dungeons.begin(); it != pRoleCheck->dungeons.end(); ++it) + { + dungeon = sLFGDungeonStore.LookupEntry(*it); // not null - been checked at join time + data << uint32(dungeon->Entry()); // Dungeon + } + + data << uint8(pRoleCheck->roles.size()); // Players in group + // Leader info MUST be sent 1st :S + roles = pRoleCheck->roles[pRoleCheck->leader]; + data << uint64(pRoleCheck->leader); // Guid + data << uint8(roles > 0); // Ready + data << uint32(roles); // Roles + plr = objmgr.GetPlayer(pRoleCheck->leader); + if (plr) + data << uint8(plr->getLevel()); // Level + else + data << uint8(0); + + for (LfgRolesMap::const_iterator itPlayers = pRoleCheck->roles.begin(); itPlayers != pRoleCheck->roles.end(); ++itPlayers) + { + if (itPlayers->first == pRoleCheck->leader) + continue; + + roles = itPlayers->second; + data << uint64(itPlayers->first); // Guid + data << uint8(roles > 0); // Ready + data << uint32(roles); // Roles + plr = objmgr.GetPlayer(pRoleCheck->leader); + if (plr) + data << uint8(plr->getLevel()); // Level + else + data << uint8(0); + } +} + +/// +/// Build and Send LFG lock player info and reward +/// +/// Player +void LFGMgr::SendLfgPlayerInfo(Player *plr) +{ + uint32 rsize = 0; + uint32 lsize = 0; + LfgDungeonSet *randomlist = GetRandomDungeons(plr->getLevel(), plr->GetSession()->Expansion()); + LfgLockStatusSet *lockSet = GetPlayerLockStatusDungeons(plr, m_DungeonsMap[LFG_ALL_DUNGEONS]); + if (randomlist) + rsize = randomlist->size(); + if (lockSet) + lsize = lockSet->size(); + + sLog.outDebug("SMSG_LFG_PLAYER_INFO"); + WorldPacket data(SMSG_LFG_PLAYER_INFO, 1 + rsize * (4 + 1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4) + 4 + lsize * (4 + 4)); + if (!randomlist) + data << uint8(0); + else + { + data << uint8(randomlist->size()); // Random Dungeon count + for (LfgDungeonSet::iterator it = randomlist->begin(); it != randomlist->end(); ++it) + { + data << uint32(*it); // Entry + BuildRewardBlock(data, *it, plr); + } + randomlist->clear(); + delete randomlist; + } + BuildPlayerLockDungeonBlock(data, lockSet); + plr->GetSession()->SendPacket(&data); +} + +/// +/// Build and Send LFG lock party info and reward +/// +/// Player +void LFGMgr::SendLfgPartyInfo(Player *plr) +{ + if (LfgLockStatusMap *lockMap = GetPartyLockStatusDungeons(plr, m_DungeonsMap[LFG_ALL_DUNGEONS])) + { + uint32 size = 0; + for (LfgLockStatusMap::const_iterator it = lockMap->begin(); it != lockMap->end(); ++it) + size += 8 + 4 + it->second->size() * (4 + 4); + sLog.outDebug("SMSG_LFG_PARTY_INFO"); + WorldPacket data(SMSG_LFG_PARTY_INFO, 1 + size); + BuildPartyLockDungeonBlock(data, lockMap); + plr->GetSession()->SendPacket(&data); + } +} + +/// +/// Build Reward packet structure for a given dungeon +/// +/// WorldPacket +/// Dungeon entry +/// Player +void LFGMgr::BuildRewardBlock(WorldPacket &data, uint32 dungeon, Player *plr) +{ + bool done = plr->m_lookingForGroup.isDungeonDone(dungeon); + LfgReward *reward = GetRandomDungeonReward(dungeon, done, plr->getLevel()); + + if (!reward) + return; + + data << uint8(done); + if (data.GetOpcode() == SMSG_LFG_PLAYER_REWARD) + data << uint32(reward->strangers); + data << uint32(reward->baseMoney); + data << uint32(reward->baseXP); + data << uint32(reward->variableMoney); + data << uint32(reward->variableXP); + data << uint8(reward->itemId != 0); + if (reward->itemId) + { + data << uint32(reward->itemId); + data << uint32(reward->displayId); + data << uint32(reward->stackCount); + } +} + +/// +/// Build Party Dungeon lock status packet +/// +/// WorldPacket +/// lock status map +void LFGMgr::BuildPartyLockDungeonBlock(WorldPacket &data, LfgLockStatusMap *lockMap) +{ + assert(lockMap); + + data << uint8(lockMap->size()); + + LfgLockStatusSet *lockSet; + uint64 guid; + for (LfgLockStatusMap::const_iterator it = lockMap->begin(); it != lockMap->end(); ++it) + { + guid = it->first; + lockSet = it->second; + if (!lockSet) + continue; + + data << uint64(guid); // Player guid + BuildPlayerLockDungeonBlock(data, lockSet); + } + lockMap->clear(); + delete lockMap; +} + +/// +/// Build Player Dungeon lock status packet +/// +/// WorldPacket +/// lock status list +void LFGMgr::BuildPlayerLockDungeonBlock(WorldPacket &data, LfgLockStatusSet *lockSet) +{ + assert(lockSet); + data << uint32(lockSet->size()); // Size of lock dungeons + for (LfgLockStatusSet::iterator it = lockSet->begin(); it != lockSet->end(); ++it) + { + data << uint32((*it)->dungeon); // Dungeon entry + type + data << uint32((*it)->lockstatus); // Lock status + delete (*it); + } + lockSet->clear(); + delete lockSet; +} + + + + +// --------------------------------------------------------------------------// +// Auxiliar Functions +// --------------------------------------------------------------------------// + +/// +/// Get all Group members list of dungeons that can't be done and reason +/// leader excluded as the list given is he list he can do +/// +/// Group +/// Dungeons to check +/// LfgLockStatusMap* +LfgLockStatusMap* LFGMgr::GetPartyLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons) +{ + assert(plr); + assert(dungeons); + Group *grp = plr->GetGroup(); + if (!grp) + return NULL; + + Player *plrg; + LfgLockStatusSet *dungeonSet = NULL; + LfgLockStatusMap *dungeonMap = new LfgLockStatusMap(); + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + plrg = itr->getSource(); + if (!plrg || plrg == plr) + continue; + + dungeonSet = GetPlayerLockStatusDungeons(plrg, dungeons); + if (dungeonSet) + (*dungeonMap)[plrg->GetGUID()] = dungeonSet; + } + + if (!dungeonMap->size()) + { + delete dungeonMap; + dungeonMap = NULL; + } + return dungeonMap; +} + +/// +/// Get list of dungeons player can't do and reasons +/// +/// Player +/// Dungeons to check +/// LfgLockStatusSet* +LfgLockStatusSet* LFGMgr::GetPlayerLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons) +{ + LfgLockStatusSet *list = new LfgLockStatusSet(); + LfgLockStatus *lockstatus = NULL; + LFGDungeonEntry const *dungeon; + LfgLockStatusType locktype; + uint8 level = plr->getLevel(); + uint8 expansion = plr->GetSession()->Expansion(); + + for (LfgDungeonSet::const_iterator it = dungeons->begin(); it != dungeons->end(); ++it) + { + dungeon = sLFGDungeonStore.LookupEntry(*it); + assert(dungeon); // Will never happen - We provide a list from sLFGDungeonStore + + locktype = LFG_LOCKSTATUS_OK; + if (dungeon->expansion > expansion) + locktype = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION; + else if (dungeon->minlevel > level) + locktype = LFG_LOCKSTATUS_TOO_LOW_LEVEL; + else if (dungeon->maxlevel < level) + locktype = LFG_LOCKSTATUS_TOO_HIGH_LEVEL; + /* TODO - Use these types when needed... + else if () + locktype = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE; + else if () + locktype = LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE; + else if () // Locked due to WG, closed by GM, done daily, etc + locktype = LFG_LOCKSTATUS_RAID_LOCKED; + else if () + locktype = LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL; + else if () + locktype = LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL; + else if () // Need list of instances and needed quest to enter + locktype = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED; + else if () // Need list of instances and needed key to enter + locktype = LFG_LOCKSTATUS_MISSING_ITEM; + else if () // Need list of instances and needed season to open + locktype = LFG_LOCKSTATUS_NOT_IN_SEASON; + */ + + if (locktype != LFG_LOCKSTATUS_OK) + { + lockstatus = new LfgLockStatus(); + lockstatus->dungeon = dungeon->Entry(); + lockstatus->lockstatus = locktype; + list->insert(lockstatus); + } + } + if (!list->size()) + { + delete list; + list = NULL; + } + return list; +} + +/// +/// Get the dungeon list that can be done. +/// +/// LfgDungeonSet* +LfgDungeonSet* LFGMgr::GetAllDungeons() +{ + LfgDungeonSet *dungeons = new LfgDungeonSet(); + LFGDungeonEntry const *dungeon; + for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) + { + dungeon = sLFGDungeonStore.LookupEntry(i); + if (!dungeon || dungeon->type == LFG_TYPE_ZONE) + continue; + dungeons->insert(dungeon->ID); + } + if (!dungeons->size()) + { + delete dungeons; + return NULL; + } + else + return dungeons; +} + +/// +/// Get the dungeon list that can be done given a random dungeon entry. +/// +/// Random dungeon entry +/// LfgDungeonSet* +LfgDungeonSet* LFGMgr::GetDungeonsByRandom(uint32 randomdungeon) +{ + LFGDungeonEntry const *dungeon = sLFGDungeonStore.LookupEntry(randomdungeon); + if (!dungeon) + return NULL; + + uint32 grouptype = dungeon->grouptype; + LfgDungeonSet *random = new LfgDungeonSet(); + for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) + { + dungeon = sLFGDungeonStore.LookupEntry(i); + if (!dungeon || dungeon->type == LFG_TYPE_RANDOM || dungeon->grouptype != grouptype) + continue; + random->insert(dungeon->ID); + } + if (!random->size()) + { + delete random; + return NULL; + } + else + return random; +} + +/// +/// Get the random dungeon list that can be done at a certain level and expansion. +/// +/// Player level +/// Player account expansion +/// LfgDungeonSet* +LfgDungeonSet* LFGMgr::GetRandomDungeons(uint8 level, uint8 expansion) +{ + LfgDungeonSet *list = new LfgDungeonSet(); + LFGDungeonEntry const *dungeon; + for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) + { + dungeon = sLFGDungeonStore.LookupEntry(i); + if (dungeon && dungeon->expansion <= expansion && dungeon->type == LFG_TYPE_RANDOM && + dungeon->minlevel <= level && level <= dungeon->maxlevel) + list->insert(dungeon->Entry()); + } + return list; +} + +/// +/// Get the reward of a given random dungeon +/// +/// random dungeon id +/// Dungeon previously done +/// +LfgReward* LFGMgr::GetRandomDungeonReward(uint32 dungeon, bool done, uint8 level) +{ + uint8 index = 0; + switch((dungeon & 0x00FFFFFF)) // Get dungeon id from dungeon entry + { + case LFG_RANDOM_CLASSIC: + if (level < 15) + index = LFG_REWARD_LEVEL0; + else if (level < 24) + index = LFG_REWARD_LEVEL1; + else if (level < 35) + index = LFG_REWARD_LEVEL2; + else if (level < 46) + index = LFG_REWARD_LEVEL3; + else if (level < 56) + index = LFG_REWARD_LEVEL4; + else + index = LFG_REWARD_LEVEL5; + break; + case LFG_RANDOM_BC_NORMAL: + index = LFG_REWARD_BC_NORMAL; + break; + case LFG_RANDOM_BC_HEROIC: + index = LFG_REWARD_BC_HEROIC; + break; + case LFG_RANDOM_LK_NORMAL: + index = level == 80 ? LFG_REWARD_LK_NORMAL80 : LFG_REWARD_LK_NORMAL; + break; + case LFG_RANDOM_LK_HEROIC: + index = LFG_REWARD_LK_HEROIC; + break; + default: // This should never happen! + done = false; + index = LFG_REWARD_LEVEL0; + sLog.outError("LFGMgr::GetRandomDungeonReward: Dungeon %u is not random dungeon!", dungeon); + break; + } + return done ? m_RewardDoneList.at(index) : m_RewardList.at(index); +} + +/// +/// Given a Dungeon id returns the dungeon Group Type +/// +/// Dungeon id +/// uint8: GroupType +uint8 LFGMgr::GetDungeonGroupType(uint32 dungeonId) +{ + LFGDungeonEntry const *dungeon = sLFGDungeonStore.LookupEntry(dungeonId); + if (!dungeon) + return 0; + + return dungeon->grouptype; +} diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h new file mode 100644 index 00000000000..b19da4e3d00 --- /dev/null +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LFGMGR_H +#define _LFGMGR_H + +#include "Common.h" +#include "Policies/Singleton.h" +#include "Group.h" +#include "LFG.h" + +enum LFGenum +{ + LFG_TIME_ROLECHECK = 2*MINUTE, + LFG_TANKS_NEEDED = 1, + LFG_HEALERS_NEEDED = 1, + LFG_DPS_NEEDED = 3, + LFG_QUEUEUPDATE_INTERVAL = 15000, + LFG_SPELL_COOLDOWN = 71328, + LFG_SPELL_DESERTER = 71041, +}; + +enum LfgType +{ + LFG_TYPE_DUNGEON = 1, + LFG_TYPE_RAID = 2, + LFG_TYPE_QUEST = 3, + LFG_TYPE_ZONE = 4, + LFG_TYPE_HEROIC = 5, + LFG_TYPE_RANDOM = 6, +}; + +enum LfgGroupType +{ + LFG_GROUPTYPE_CLASSIC = 1, + LFG_GROUPTYPE_BC_NORMAL = 2, + LFG_GROUPTYPE_BC_HEROIC = 3, + LFG_GROUPTYPE_WTLK_NORMAL = 4, + LFG_GROUPTYPE_WTLK_HEROIC = 5, + LFG_GROUPTYPE_CLASSIC_RAID = 6, + LFG_GROUPTYPE_BC_RAID = 7, + LFG_GROUPTYPE_WTLK_RAID_10 = 8, + LFG_GROUPTYPE_WTLK_RAID_25 = 9, +}; + +enum LfgLockStatusType +{ + LFG_LOCKSTATUS_OK = 0, // Internal use only + LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION = 1, + LFG_LOCKSTATUS_TOO_LOW_LEVEL = 2, + LFG_LOCKSTATUS_TOO_HIGH_LEVEL = 3, + LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE = 4, + LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE = 5, + LFG_LOCKSTATUS_RAID_LOCKED = 6, + LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL = 1001, + LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL = 1002, + LFG_LOCKSTATUS_QUEST_NOT_COMPLETED = 1022, + LFG_LOCKSTATUS_MISSING_ITEM = 1025, + LFG_LOCKSTATUS_NOT_IN_SEASON = 1031, +}; + +enum LfgJoinResult +{ + LFG_JOIN_OK = 0, // Joined (no client msg) + LFG_JOIN_FAILED = 1, // RoleCheck Failed + LFG_JOIN_GROUPFULL = 2, // Your group is full + LFG_JOIN_UNK3 = 3, // No client reaction + LFG_JOIN_INTERNAL_ERROR = 4, // Internal LFG Error + LFG_JOIN_NOT_MEET_REQS = 5, // You do not meet the requirements for the chosen dungeons + LFG_JOIN_PARTY_NOT_MEET_REQS = 6, // One or more party members do not meet the requirements for the chosen dungeons + LFG_JOIN_MIXED_RAID_DUNGEON = 7, // You cannot mix dungeons, raids, and random when picking dungeons + LFG_JOIN_MULTI_REALM = 8, // The dungeon you chose does not support players from multiple realms + LFG_JOIN_DISCONNECTED = 9, // One or more party members are pending invites or disconnected + LFG_JOIN_PARTY_INFO_FAILED = 10, // Could not retrieve information about some party members + LFG_JOIN_DUNGEON_INVALID = 11, // One or more dungeons was not valid + LFG_JOIN_DESERTER = 12, // You can not queue for dungeons until your deserter debuff wears off + LFG_JOIN_PARTY_DESERTER = 13, // One or more party members has a deserter debuff + LFG_JOIN_RANDOM_COOLDOWN = 14, // You can not queue for random dungeons while on random dungeon cooldown + LFG_JOIN_PARTY_RANDOM_COOLDOWN = 15, // One or more party members are on random dungeon cooldown + LFG_JOIN_TOO_MUCH_MEMBERS = 16, // You can not enter dungeons with more that 5 party members + LFG_JOIN_USING_BG_SYSTEM = 17, // You can not use the dungeon system while in BG or arenas + LFG_JOIN_FAILED2 = 18, // RoleCheck Failed +}; + +enum LfgRoleCheckResult +{ + LFG_ROLECHECK_FINISHED = 1, // Role check finished + LFG_ROLECHECK_INITIALITING = 2, // Role check begins + LFG_ROLECHECK_MISSING_ROLE = 3, // Someone didn't selected a role after 2 mins + LFG_ROLECHECK_WRONG_ROLES = 4, // Can't form a group with that role selection + LFG_ROLECHECK_ABORTED = 5, // Someone leave the group + LFG_ROLECHECK_NO_ROLE = 6, // Someone selected no role +}; + +enum LfgRandomDungeonEntries +{ + LFG_ALL_DUNGEONS = 0, + LFG_RANDOM_CLASSIC = 258, + LFG_RANDOM_BC_NORMAL = 259, + LFG_RANDOM_BC_HEROIC = 260, + LFG_RANDOM_LK_NORMAL = 261, + LFG_RANDOM_LK_HEROIC = 262, +}; + +enum LfgRewardEnums +{ + LFG_REWARD_LEVEL0 = 10, + LFG_REWARD_LEVEL1 = 0, + LFG_REWARD_LEVEL2 = 1, + LFG_REWARD_LEVEL3 = 2, + LFG_REWARD_LEVEL4 = 3, + LFG_REWARD_LEVEL5 = 4, + LFG_REWARD_BC_NORMAL = 5, + LFG_REWARD_BC_HEROIC = 6, + LFG_REWARD_LK_NORMAL = 7, + LFG_REWARD_LK_NORMAL80 = 7, + LFG_REWARD_LK_HEROIC = 8, + LFG_REWARD_DATA_SIZE = 10, +}; + +const uint32 RewardDungeonData[LFG_REWARD_DATA_SIZE+1][5] = +{ // XP, money, item, item display, count + {310, 3500, 51999, 56915, 1}, // Classic 15-23 + {470, 7000, 52000, 56915, 1}, // Classic 24-34 + {825, 13000, 52001, 56915, 1}, // Classic 35-45 + {12250, 16500, 52002, 56915, 1}, // Classic 46-55 + {14300, 18000, 52003, 56915, 1}, // Classic 56-60 + {1600, 62000, 52004, 56915, 1}, // BC Normal + {1900, 88000, 52005, 56915, 1}, // BC Heroic + {33100, 148000, 47241, 62232, 2}, // LK Normal + {0, 198600, 47241, 62232, 2}, // LK Normal - Level 80 + {0, 264600, 49426, 64062, 2}, // LK Heroic + {0, 0, 0, 0, 0}, // Classic - No level +}; + +const uint32 RewardDungeonDoneData[LFG_REWARD_DATA_SIZE][5] = +{ // XP, money, item, item display, count + {200, 1800, 51999, 56915, 1}, // Classic 15-23 + {310, 3500, 52000, 56915, 1}, // Classic 24-34 + {550, 6500, 52001, 56915, 1}, // Classic 35-45 + {8150, 8500, 52002, 56915, 1}, // Classic 46-55 + {9550, 9000, 52003, 56915, 1}, // Classic 56-60 + {1100, 31000, 52004, 56915, 1}, // BC Normal + {12650, 44000, 52005, 56915, 1}, // BC Heroic + {16550, 74000, 0, 0, 0}, // LK Normal + {0, 99300, 0, 0, 0}, // LK Normal - Level 80 + {0, 132300, 47241, 62232, 2}, // LK Heroic +}; + +// Dungeon and reason why player can't join +struct LfgLockStatus +{ + uint32 dungeon; + LfgLockStatusType lockstatus; +}; + +// Reward info +struct LfgReward +{ + uint32 strangers; + uint32 baseMoney; + uint32 baseXP; + uint32 variableMoney; + uint32 variableXP; + uint32 itemId; + uint32 displayId; + uint32 stackCount; +}; + +typedef std::set LfgLockStatusSet; +typedef std::vector LfgRewardList; +typedef std::map LfgLockStatusMap; +typedef std::map LfgDungeonMap; + +typedef std::map LfgAnswerMap; +typedef std::map LfgRolesMap; +typedef std::set LfgGuidSet; + +// Stores player or group queue info +struct LfgQueueInfo +{ + time_t joinTime; // Player queue join time (to calculate wait times) + uint32 dungeonId; // Selected Player/Group Dungeon + LfgRolesMap roles; // Selected Player Role/s + uint8 tanks; // Tanks needed + uint8 healers; // Healers needed + uint8 dps; // Dps needed +}; + +// Stores all rolecheck info of a group that wants to join LFG +struct LfgRoleCheck +{ + time_t cancelTime; + LfgRolesMap roles; + LfgRoleCheckResult result; + LfgDungeonSet dungeons; + uint64 leader; +}; + +typedef std::map LfgQueueInfoMap; +typedef std::map LfgRoleCheckMap; + +class LFGQueue +{ + public: + LFGQueue(); + ~LFGQueue(); + + void Update(); + void AddToQueue(uint64 guid, LfgQueueInfo *pqInfo); + bool RemoveFromQueue(uint64 guid); + LfgQueueInfo* GetQueueInfo(uint64 guid); + private: + LfgQueueInfoMap m_LfgQueue; + int32 avgWaitTime; + int32 waitTimeTanks; + int32 waitTimeHealer; + int32 waitTimeDps; +}; + +typedef std::map LFGQueueMap; + +class LFGMgr +{ +public: + LFGMgr(); + ~LFGMgr(); + + void InitLFG(); + void SendLfgPlayerInfo(Player *plr); + void SendLfgPartyInfo(Player *plr); + void Join(Player *plr); + void Leave(Player *plr, Group *grp = NULL); + void UpdateRoleCheck(Group *grp, Player *plr = NULL); + void Update(uint32 diff); + +private: + void BuildLfgRoleCheck(WorldPacket &data, LfgRoleCheck *pRoleCheck); + void BuildAvailableRandomDungeonList(WorldPacket &data, Player *plr); + void BuildRewardBlock(WorldPacket &data, uint32 dungeon, Player *plr); + void BuildPlayerLockDungeonBlock(WorldPacket &data, LfgLockStatusSet *lockSet); + void BuildPartyLockDungeonBlock(WorldPacket &data, LfgLockStatusMap *lockMap); + bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true); + + LfgLockStatusMap* GetPartyLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons); + LfgLockStatusSet* GetPlayerLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons); + LfgDungeonSet* GetRandomDungeons(uint8 level, uint8 expansion); + LfgDungeonSet* GetDungeonsByRandom(uint32 randomdungeon); + LfgDungeonSet* GetAllDungeons(); + LfgReward* GetRandomDungeonReward(uint32 dungeon, bool done, uint8 level); + uint8 GetDungeonGroupType(uint32 dungeon); + + LfgRewardList m_RewardList; + LfgRewardList m_RewardDoneList; + LfgDungeonMap m_DungeonsMap; + + LFGQueueMap m_Queues; + LfgRoleCheckMap m_RoleChecks; + uint32 m_QueueTimer; + bool m_update; +}; + +#define sLFGMgr Trinity::Singleton::Instance() +#endif diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp new file mode 100644 index 00000000000..510ea13e78b --- /dev/null +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Corpse.h" +#include "Player.h" +#include "UpdateMask.h" +#include "ObjectAccessor.h" +#include "Database/DatabaseEnv.h" +#include "Opcodes.h" +#include "GossipDef.h" +#include "World.h" + +Corpse::Corpse(CorpseType type) : WorldObject() +, m_type(type) +{ + m_objectType |= TYPEMASK_CORPSE; + m_objectTypeId = TYPEID_CORPSE; + + m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_POSITION); + + m_valuesCount = CORPSE_END; + + m_time = time(NULL); + + lootForBody = false; + + if (type != CORPSE_BONES) + m_isWorldObject = true; +} + +Corpse::~Corpse() +{ +} + +void Corpse::AddToWorld() +{ + ///- Register the corpse for guid lookup + if (!IsInWorld()) + ObjectAccessor::Instance().AddObject(this); + + Object::AddToWorld(); +} + +void Corpse::RemoveFromWorld() +{ + ///- Remove the corpse from the accessor + if (IsInWorld()) + ObjectAccessor::Instance().RemoveObject(this); + + Object::RemoveFromWorld(); +} + +bool Corpse::Create(uint32 guidlow, Map *map) +{ + SetMap(map); + Object::_Create(guidlow, 0, HIGHGUID_CORPSE); + return true; +} + +bool Corpse::Create(uint32 guidlow, Player *owner) +{ + ASSERT(owner); + + Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation()); + + if (!IsPositionValid()) + { + sLog.outError("Corpse (guidlow %d, owner %s) not created. Suggested coordinates isn't valid (X: %f Y: %f)", + guidlow, owner->GetName(), owner->GetPositionX(), owner->GetPositionY()); + return false; + } + + //we need to assign owner's map for corpse + //in other way we will get a crash in Corpse::SaveToDB() + SetMap(owner->GetMap()); + + WorldObject::_Create(guidlow, HIGHGUID_CORPSE, owner->GetPhaseMask()); + + SetFloatValue(OBJECT_FIELD_SCALE_X, 1); + SetUInt64Value(CORPSE_FIELD_OWNER, owner->GetGUID()); + + m_grid = Trinity::ComputeGridPair(GetPositionX(), GetPositionY()); + + return true; +} + +void Corpse::SaveToDB() +{ + // prevent DB data inconsistence problems and duplicates + CharacterDatabase.BeginTransaction(); + DeleteFromDB(); + + std::ostringstream ss; + ss << "INSERT INTO corpse (guid,player,position_x,position_y,position_z,orientation,zone,map,data,time,corpse_type,instance,phaseMask) VALUES (" + << GetGUIDLow() << ", " + << GUID_LOPART(GetOwnerGUID()) << ", " + << GetPositionX() << ", " + << GetPositionY() << ", " + << GetPositionZ() << ", " + << GetOrientation() << ", " + << GetZoneId() << ", " + << GetMapId() << ", '"; + for (uint16 i = 0; i < m_valuesCount; ++i) + ss << GetUInt32Value(i) << " "; + ss << "'," + << uint64(m_time) <<", " + << uint32(GetType()) << ", " + << int(GetInstanceId()) << ", " + << uint16(GetPhaseMask()) << ")"; // prevent out of range error + CharacterDatabase.Execute(ss.str().c_str()); + CharacterDatabase.CommitTransaction(); +} + +void Corpse::DeleteBonesFromWorld() +{ + assert(GetType() == CORPSE_BONES); + Corpse* corpse = ObjectAccessor::GetCorpse(*this, GetGUID()); + + if (!corpse) + { + sLog.outError("Bones %u not found in world.", GetGUIDLow()); + return; + } + + AddObjectToRemoveList(); +} + +void Corpse::DeleteFromDB() +{ + if (GetType() == CORPSE_BONES) + // only specific bones + CharacterDatabase.PExecute("DELETE FROM corpse WHERE guid = '%d'", GetGUIDLow()); + else + // all corpses (not bones) + CharacterDatabase.PExecute("DELETE FROM corpse WHERE player = '%d' AND corpse_type <> '0'", GUID_LOPART(GetOwnerGUID())); +} + +/* +bool Corpse::LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId) +{ + bool external = (result != NULL); + if (!external) + // 0 1 2 3 4 5 6 7 8 9 + result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,data,time,corpse_type,instance,phaseMask FROM corpse WHERE guid = '%u'",guid); + + if (!result) + { + sLog.outError("Corpse (GUID: %u) not found in table `corpse`, can't load. ",guid); + return false; + } + + Field *fields = result->Fetch(); + + if (!LoadFromDB(guid, fields)) + { + if (!external) + delete result; + + return false; + } + + if (!external) + delete result; + + return true; +}*/ + +bool Corpse::LoadFromDB(uint32 guid, Field *fields) +{ + float positionX = fields[0].GetFloat(); + float positionY = fields[1].GetFloat(); + float positionZ = fields[2].GetFloat(); + float ort = fields[3].GetFloat(); + uint32 mapid = fields[4].GetUInt32(); + + Object::_Create(guid, 0, HIGHGUID_CORPSE); + + if (!LoadValues(fields[5].GetString())) + { + sLog.outError("Corpse #%d have broken data in `data` field. Can't be loaded.",guid); + return false; + } + + m_time = time_t(fields[6].GetUInt64()); + m_type = CorpseType(fields[7].GetUInt32()); + + if (m_type >= MAX_CORPSE_TYPE) + { + sLog.outError("Corpse (guidlow %d, owner %d) have wrong corpse type, not load.",GetGUIDLow(),GUID_LOPART(GetOwnerGUID())); + return false; + } + + if (m_type != CORPSE_BONES) + m_isWorldObject = true; + + uint32 instanceid = fields[8].GetUInt32(); + + uint32 phaseMask = fields[9].GetUInt32(); + + // overwrite possible wrong/corrupted guid + SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_CORPSE)); + + // place + SetLocationInstanceId(instanceid); + SetLocationMapId(mapid); + SetPhaseMask(phaseMask, false); + Relocate(positionX, positionY, positionZ, ort); + + if (!IsPositionValid()) + { + sLog.outError("Corpse (guidlow %d, owner %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)", + GetGUIDLow(), GUID_LOPART(GetOwnerGUID()), GetPositionX(), GetPositionY()); + return false; + } + + m_grid = Trinity::ComputeGridPair(GetPositionX(), GetPositionY()); + + return true; +} + +bool Corpse::isVisibleForInState(Player const* u, bool inVisibleList) const +{ + return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u->m_seer, World::GetMaxVisibleDistanceForObject() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false); +} + diff --git a/src/server/game/Entities/Corpse/Corpse.h b/src/server/game/Entities/Corpse/Corpse.h new file mode 100644 index 00000000000..bab95e99d14 --- /dev/null +++ b/src/server/game/Entities/Corpse/Corpse.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYCORE_CORPSE_H +#define TRINITYCORE_CORPSE_H + +#include "Object.h" +#include "Database/DatabaseEnv.h" +#include "GridDefines.h" +#include "LootMgr.h" + +enum CorpseType +{ + CORPSE_BONES = 0, + CORPSE_RESURRECTABLE_PVE = 1, + CORPSE_RESURRECTABLE_PVP = 2 +}; +#define MAX_CORPSE_TYPE 3 + +// Value equal client resurrection dialog show radius. +#define CORPSE_RECLAIM_RADIUS 39 + +enum CorpseFlags +{ + CORPSE_FLAG_NONE = 0x00, + CORPSE_FLAG_BONES = 0x01, + CORPSE_FLAG_UNK1 = 0x02, + CORPSE_FLAG_UNK2 = 0x04, + CORPSE_FLAG_HIDE_HELM = 0x08, + CORPSE_FLAG_HIDE_CLOAK = 0x10, + CORPSE_FLAG_LOOTABLE = 0x20 +}; + +class Corpse : public WorldObject, public GridObject +{ + public: + explicit Corpse(CorpseType type = CORPSE_BONES); + ~Corpse(); + + void AddToWorld(); + void RemoveFromWorld(); + + bool Create(uint32 guidlow, Map *map); + bool Create(uint32 guidlow, Player *owner); + + void SaveToDB(); + //bool LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId); + bool LoadFromDB(uint32 guid, Field *fields); + + void DeleteBonesFromWorld(); + void DeleteFromDB(); + + uint64 const& GetOwnerGUID() const { return GetUInt64Value(CORPSE_FIELD_OWNER); } + + time_t const& GetGhostTime() const { return m_time; } + void ResetGhostTime() { m_time = time(NULL); } + CorpseType GetType() const { return m_type; } + + GridPair const& GetGrid() const { return m_grid; } + void SetGrid(GridPair const& grid) { m_grid = grid; } + + bool isVisibleForInState(Player const* u, bool inVisibleList) const; + + Loot loot; // remove insignia ONLY at BG + Player* lootRecipient; + bool lootForBody; + + void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); } + void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); } + void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); } + void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); } + void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); } + + private: + CorpseType m_type; + time_t m_time; + GridPair m_grid; // gride for corpse position for fast search +}; +#endif + diff --git a/src/server/game/Entities/Creature/NPCHandler.cpp b/src/server/game/Entities/Creature/NPCHandler.cpp deleted file mode 100644 index 4e73fb381af..00000000000 --- a/src/server/game/Entities/Creature/NPCHandler.cpp +++ /dev/null @@ -1,869 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Language.h" -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "Player.h" -#include "GossipDef.h" -#include "UpdateMask.h" -#include "ObjectAccessor.h" -#include "Creature.h" -#include "Pet.h" -#include "BattleGroundMgr.h" -#include "BattleGround.h" -#include "Guild.h" -#include "ScriptMgr.h" - -void WorldSession::HandleTabardVendorActivateOpcode(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TABARDDESIGNER); - if (!unit) - { - sLog.outDebug("WORLD: HandleTabardVendorActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - SendTabardVendorActivate(guid); -} - -void WorldSession::SendTabardVendorActivate(uint64 guid) -{ - WorldPacket data(MSG_TABARDVENDOR_ACTIVATE, 8); - data << guid; - SendPacket(&data); -} - -void WorldSession::HandleBankerActivateOpcode(WorldPacket & recv_data) -{ - uint64 guid; - - sLog.outDebug("WORLD: Received CMSG_BANKER_ACTIVATE"); - - recv_data >> guid; - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_BANKER); - if (!unit) - { - sLog.outDebug("WORLD: HandleBankerActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - SendShowBank(guid); -} - -void WorldSession::SendShowBank(uint64 guid) -{ - WorldPacket data(SMSG_SHOW_BANK, 8); - data << guid; - SendPacket(&data); -} - -void WorldSession::HandleTrainerListOpcode(WorldPacket & recv_data) -{ - uint64 guid; - - recv_data >> guid; - SendTrainerList(guid); -} - -void WorldSession::SendTrainerList(uint64 guid) -{ - std::string str = GetTrinityString(LANG_NPC_TAINER_HELLO); - SendTrainerList(guid, str); -} - -void WorldSession::SendTrainerList(uint64 guid, const std::string& strTitle) -{ - sLog.outDebug("WORLD: SendTrainerList"); - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TRAINER); - if (!unit) - { - sLog.outDebug("WORLD: SendTrainerList - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - // trainer list loaded at check; - if (!unit->isCanTrainingOf(_player,true)) - return; - - CreatureInfo const *ci = unit->GetCreatureInfo(); - - if (!ci) - { - sLog.outDebug("WORLD: SendTrainerList - (GUID: %u) NO CREATUREINFO!",GUID_LOPART(guid)); - return; - } - - TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); - if (!trainer_spells) - { - sLog.outDebug("WORLD: SendTrainerList - Training spells not found for creature (GUID: %u Entry: %u)", - GUID_LOPART(guid), unit->GetEntry()); - return; - } - - WorldPacket data(SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1); - data << guid; - data << uint32(trainer_spells->trainerType); - - size_t count_pos = data.wpos(); - data << uint32(trainer_spells->spellList.size()); - - // reputation discount - float fDiscountMod = _player->GetReputationPriceDiscount(unit); - bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProfessionPoints() > 0; - - uint32 count = 0; - for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr) - { - TrainerSpell const* tSpell = &itr->second; - - bool valid = true; - bool primary_prof_first_rank = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i) - { - if (!tSpell->learnedSpell[i]) - continue; - if (!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell[i])) - { - valid = false; - break; - } - if (spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->learnedSpell[i])) - primary_prof_first_rank = true; - } - if (!valid) - continue; - - TrainerSpellState state = _player->GetTrainerSpellState(tSpell); - - data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case) - data << uint8(state == TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state); - data << uint32(floor(tSpell->spellCost * fDiscountMod)); - - data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0); - // primary prof. learn confirmation dialog - data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state - data << uint8(tSpell->reqLevel); - data << uint32(tSpell->reqSkill); - data << uint32(tSpell->reqSkillValue); - //prev + req or req + 0 - uint8 maxReq = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i) - { - if (!tSpell->learnedSpell[i]) - continue; - if (SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->learnedSpell[i])) - { - if (chain_node->prev) - { - data << uint32(chain_node->prev); - ++maxReq; - } - } - if (maxReq == 3) - break; - SpellsRequiringSpellMapBounds spellsRequired = spellmgr.GetSpellsRequiredForSpellBounds(tSpell->learnedSpell[i]); - for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second && maxReq < 3; ++itr2) - { - data << uint32(itr2->second); - ++maxReq; - } - if (maxReq == 3) - break; - } - while (maxReq < 3) - { - data << uint32(0); - ++maxReq; - } - - ++count; - } - - data << strTitle; - - data.put(count_pos,count); - SendPacket(&data); -} - -void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket & recv_data) -{ - uint64 guid; - uint32 spellId = 0; - - recv_data >> guid >> spellId; - sLog.outDebug("WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u",uint32(GUID_LOPART(guid)), spellId); - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); - if (!unit) - { - sLog.outDebug("WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - if (!unit->isCanTrainingOf(_player,true)) - return; - - // check present spell in trainer spell list - TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); - if (!trainer_spells) - return; - - // not found, cheat? - TrainerSpell const* trainer_spell = trainer_spells->Find(spellId); - if (!trainer_spell) - return; - - // can't be learn, cheat? Or double learn with lags... - if (_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN) - return; - - // apply reputation discount - uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit))); - - // check money requirement - if (_player->GetMoney() < nSpellCost) - return; - - _player->ModifyMoney(-int32(nSpellCost)); - - WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer - data << uint64(guid); - data << uint32(0xB3); // index from SpellVisualKit.dbc - SendPacket(&data); - - data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12); // visual effect on player - data << uint64(_player->GetGUID()); - data << uint32(0x016A); // index from SpellVisualKit.dbc - SendPacket(&data); - - // learn explicitly or cast explicitly - if (trainer_spell->IsCastable()) - _player->CastSpell(_player,trainer_spell->spell,true); - else - _player->learnSpell(spellId, false); - - data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12); - data << uint64(guid); - data << uint32(spellId); // should be same as in packet from client - SendPacket(&data); -} - -void WorldSession::HandleGossipHelloOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_GOSSIP_HELLO"); - - uint64 guid; - recv_data >> guid; - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); - if (!unit) - { - sLog.outDebug("WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - GetPlayer()->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK); - // remove fake death - //if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - // GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - if (unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider()) - { - unit->StopMoving(); - } - - // If spiritguide, no need for gossip menu, just put player into resurrect queue - if (unit->isSpiritGuide()) - { - BattleGround *bg = _player->GetBattleGround(); - if (bg) - { - bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID()); - sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID()); - return; - } - } - - if (!sScriptMgr.GossipHello(_player, unit)) - { -// _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID()); - _player->PrepareGossipMenu(unit, unit->GetCreatureInfo()->GossipMenuId, true); - _player->SendPreparedGossip(unit); - } -} - -/*void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION"); - - uint32 option; - uint32 unk; - uint64 guid; - std::string code = ""; - - recv_data >> guid >> unk >> option; - - if (_player->PlayerTalkClass->GossipOptionCoded(option)) - { - sLog.outDebug("reading string"); - recv_data >> code; - sLog.outDebug("string read: %s", code.c_str()); - } - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); - if (!unit) - { - sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - if (!code.empty()) - { - if (!Script->GossipSelectWithCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction(option), code.c_str())) - unit->OnGossipSelect (_player, option); - } - else - { - if (!Script->GossipSelect (_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction (option))) - unit->OnGossipSelect (_player, option); - } -}*/ - -void WorldSession::HandleSpiritHealerActivateOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_SPIRIT_HEALER_ACTIVATE"); - - uint64 guid; - - recv_data >> guid; - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_SPIRITHEALER); - if (!unit) - { - sLog.outDebug("WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - SendSpiritResurrect(); -} - -void WorldSession::SendSpiritResurrect() -{ - _player->ResurrectPlayer(0.5f, true); - - _player->DurabilityLossAll(0.25f,true); - - // get corpse nearest graveyard - WorldSafeLocsEntry const *corpseGrave = NULL; - Corpse *corpse = _player->GetCorpse(); - if (corpse) - corpseGrave = objmgr.GetClosestGraveYard( - corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam()); - - // now can spawn bones - _player->SpawnCorpseBones(); - - // teleport to nearest from corpse graveyard, if different from nearest to player ghost - if (corpseGrave) - { - WorldSafeLocsEntry const *ghostGrave = objmgr.GetClosestGraveYard( - _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam()); - - if (corpseGrave != ghostGrave) - _player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation()); - // or update at original position - else - _player->UpdateObjectVisibility(); - } - // or update at original position - else - _player->UpdateObjectVisibility(); -} - -void WorldSession::HandleBinderActivateOpcode(WorldPacket & recv_data) -{ - uint64 npcGUID; - recv_data >> npcGUID; - - if (!GetPlayer()->IsInWorld() || !GetPlayer()->isAlive()) - return; - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID,UNIT_NPC_FLAG_INNKEEPER); - if (!unit) - { - sLog.outDebug("WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - SendBindPoint(unit); -} - -void WorldSession::SendBindPoint(Creature *npc) -{ - // prevent set homebind to instances in any case - if (GetPlayer()->GetMap()->Instanceable()) - return; - - uint32 bindspell = 3286; - - // update sql homebind - CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'", - _player->GetMapId(), _player->GetAreaId(), _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetGUIDLow()); - _player->m_homebindMapId = _player->GetMapId(); - _player->m_homebindAreaId = _player->GetAreaId(); - _player->m_homebindX = _player->GetPositionX(); - _player->m_homebindY = _player->GetPositionY(); - _player->m_homebindZ = _player->GetPositionZ(); - - // send spell for homebinding (3286) - npc->CastSpell(_player, bindspell, true); - - WorldPacket data(SMSG_TRAINER_BUY_SUCCEEDED, (8+4)); - data << uint64(npc->GetGUID()); - data << uint32(bindspell); - SendPacket(&data); - - _player->PlayerTalkClass->CloseGossip(); -} - -void WorldSession::HandleListStabledPetsOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS"); - uint64 npcGUID; - - recv_data >> npcGUID; - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER); - if (!unit) - { - sLog.outDebug("WORLD: HandleListStabledPetsOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - // remove mounts this fix bug where getting pet from stable while mounted deletes pet. - if (GetPlayer()->IsMounted()) - GetPlayer()->RemoveAurasByType(SPELL_AURA_MOUNTED); - - SendStablePet(npcGUID); -} - -void WorldSession::SendStablePet(uint64 guid) -{ - sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS Send."); - - WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size - data << uint64 (guid); - - Pet *pet = _player->GetPet(); - - size_t wpos = data.wpos(); - data << uint8(0); // place holder for slot show number - - data << uint8(GetPlayer()->m_stableSlots); - - uint8 num = 0; // counter for place holder - - // not let move dead pet in slot - if (pet && pet->isAlive() && pet->getPetType() == HUNTER_PET) - { - data << uint32(pet->GetCharmInfo()->GetPetNumber()); - data << uint32(pet->GetEntry()); - data << uint32(pet->getLevel()); - data << pet->GetName(); // petname - data << uint8(1); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show) - ++num; - } - - // 0 1 2 3 4 - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT owner, id, entry, level, name FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot", - _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT); - - if (result) - { - do - { - Field *fields = result->Fetch(); - - data << uint32(fields[1].GetUInt32()); // petnumber - data << uint32(fields[2].GetUInt32()); // creature entry - data << uint32(fields[3].GetUInt32()); // level - data << fields[4].GetString(); // name - data << uint8(2); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show) - - ++num; - }while (result->NextRow()); - } - - data.put(wpos, num); // set real data to placeholder - SendPacket(&data); -} - -void WorldSession::HandleStablePet(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Recv CMSG_STABLE_PET"); - uint64 npcGUID; - - recv_data >> npcGUID; - - if (!GetPlayer()->isAlive()) - return; - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER); - if (!unit) - { - sLog.outDebug("WORLD: HandleStablePet - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - Pet *pet = _player->GetPet(); - - // can't place in stable dead pet - if (!pet||!pet->isAlive()||pet->getPetType() != HUNTER_PET) - { - WorldPacket data(SMSG_STABLE_RESULT, 1); - data << uint8(0x06); - SendPacket(&data); - return; - } - - uint32 free_slot = 1; - - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot ", - _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT); - if (result) - { - do - { - Field *fields = result->Fetch(); - - uint32 slot = fields[1].GetUInt32(); - - // slots ordered in query, and if not equal then free - if (slot != free_slot) - break; - - // this slot not free, skip - ++free_slot; - }while (result->NextRow()); - } - - WorldPacket data(SMSG_STABLE_RESULT, 1); - if (free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots) - { - _player->RemovePet(pet,PetSaveMode(free_slot)); - data << uint8(0x08); - } - else - data << uint8(0x06); - - SendPacket(&data); -} - -void WorldSession::HandleUnstablePet(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Recv CMSG_UNSTABLE_PET."); - uint64 npcGUID; - uint32 petnumber; - - recv_data >> npcGUID >> petnumber; - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER); - if (!unit) - { - sLog.outDebug("WORLD: HandleUnstablePet - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - uint32 creature_id = 0; - - { - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot >='%u' AND slot <= '%u'", - _player->GetGUIDLow(),petnumber,PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT); - if (result) - { - Field *fields = result->Fetch(); - creature_id = fields[0].GetUInt32(); - } - } - - if (!creature_id) - { - WorldPacket data(SMSG_STABLE_RESULT, 1); - data << uint8(0x06); - SendPacket(&data); - return; - } - - CreatureInfo const* creatureInfo = objmgr.GetCreatureTemplate(creature_id); - if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets())) - { - WorldPacket data(SMSG_STABLE_RESULT, 1); - data << uint8(0x06); - SendPacket(&data); - return; - } - - Pet* pet = _player->GetPet(); - if (pet && pet->isAlive()) - { - WorldPacket data(SMSG_STABLE_RESULT, 1); - data << uint8(0x06); - SendPacket(&data); - return; - } - - // delete dead pet - if (pet) - _player->RemovePet(pet,PET_SAVE_AS_DELETED); - - Pet *newpet = new Pet(_player, HUNTER_PET); - if (!newpet->LoadPetFromDB(_player,creature_id,petnumber)) - { - delete newpet; - newpet = NULL; - WorldPacket data(SMSG_STABLE_RESULT, 1); - data << uint8(0x06); - SendPacket(&data); - return; - } - - WorldPacket data(SMSG_STABLE_RESULT, 1); - data << uint8(0x09); - SendPacket(&data); -} - -void WorldSession::HandleBuyStableSlot(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Recv CMSG_BUY_STABLE_SLOT."); - uint64 npcGUID; - - recv_data >> npcGUID; - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER); - if (!unit) - { - sLog.outDebug("WORLD: HandleBuyStableSlot - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - WorldPacket data(SMSG_STABLE_RESULT, 200); - - if (GetPlayer()->m_stableSlots < MAX_PET_STABLES) - { - StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1); - if (_player->GetMoney() >= SlotPrice->Price) - { - ++GetPlayer()->m_stableSlots; - _player->ModifyMoney(-int32(SlotPrice->Price)); - data << uint8(0x0A); // success buy - } - else - data << uint8(0x06); - } - else - data << uint8(0x06); - - SendPacket(&data); -} - -void WorldSession::HandleStableRevivePet(WorldPacket &/* recv_data */) -{ - sLog.outDebug("HandleStableRevivePet: Not implemented"); -} - -void WorldSession::HandleStableSwapPet(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Recv CMSG_STABLE_SWAP_PET."); - uint64 npcGUID; - uint32 pet_number; - - recv_data >> npcGUID >> pet_number; - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER); - if (!unit) - { - sLog.outDebug("WORLD: HandleStableSwapPet - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size - - Pet* pet = _player->GetPet(); - - if (!pet || pet->getPetType() != HUNTER_PET) - return; - - // find swapped pet slot in stable - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'", - _player->GetGUIDLow(),pet_number); - if (!result) - return; - - Field *fields = result->Fetch(); - - uint32 slot = fields[0].GetUInt32(); - uint32 creature_id = fields[1].GetUInt32(); - - if (!creature_id) - { - WorldPacket data(SMSG_STABLE_RESULT, 1); - data << uint8(0x06); - SendPacket(&data); - return; - } - - CreatureInfo const* creatureInfo = objmgr.GetCreatureTemplate(creature_id); - if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets())) - { - WorldPacket data(SMSG_STABLE_RESULT, 1); - data << uint8(0x06); - SendPacket(&data); - return; - } - - // move alive pet to slot or delete dead pet - _player->RemovePet(pet,pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED); - - // summon unstabled pet - Pet *newpet = new Pet(_player); - if (!newpet->LoadPetFromDB(_player,creature_id,pet_number)) - { - delete newpet; - data << uint8(0x06); - } - else - data << uint8(0x09); - - SendPacket(&data); -} - -void WorldSession::HandleRepairItemOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_REPAIR_ITEM"); - - uint64 npcGUID, itemGUID; - uint8 guildBank; // new in 2.3.2, bool that means from guild bank money - - recv_data >> npcGUID >> itemGUID >> guildBank; - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_REPAIR); - if (!unit) - { - sLog.outDebug("WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - // reputation discount - float discountMod = _player->GetReputationPriceDiscount(unit); - - uint32 TotalCost = 0; - if (itemGUID) - { - sLog.outDebug("ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID)); - - Item* item = _player->GetItemByGuid(itemGUID); - - if (item) - TotalCost= _player->DurabilityRepair(item->GetPos(),true,discountMod,guildBank>0?true:false); - } - else - { - sLog.outDebug("ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID)); - - TotalCost = _player->DurabilityRepairAll(true,discountMod,guildBank>0?true:false); - } - if (guildBank) - { - uint32 GuildId = _player->GetGuildId(); - if (!GuildId) - return; - Guild *pGuild = objmgr.GetGuildById(GuildId); - if (!pGuild) - return; - pGuild->LogBankEvent(GUILD_BANK_LOG_REPAIR_MONEY, 0, _player->GetGUIDLow(), TotalCost); - pGuild->SendMoneyInfo(this, _player->GetGUIDLow()); - } -} - diff --git a/src/server/game/Entities/Creature/NPCHandler.h b/src/server/game/Entities/Creature/NPCHandler.h deleted file mode 100644 index 98e2fd218d3..00000000000 --- a/src/server/game/Entities/Creature/NPCHandler.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __NPCHANDLER_H -#define __NPCHANDLER_H - -// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform -#if defined(__GNUC__) -#pragma pack(1) -#else -#pragma pack(push,1) -#endif - -struct PageText -{ - uint32 Page_ID; - char * Text; - - uint32 Next_Page; -}; - -// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform -#if defined(__GNUC__) -#pragma pack() -#else -#pragma pack(pop) -#endif - -struct QEmote -{ - uint32 _Emote; - uint32 _Delay; -}; - -struct GossipTextOption -{ - std::string Text_0; - std::string Text_1; - uint32 Language; - float Probability; - QEmote Emotes[3]; -}; - -struct GossipText -{ - GossipTextOption Options[8]; -}; - -struct PageTextLocale -{ - std::vector Text; -}; - -struct NpcTextLocale -{ - NpcTextLocale() { Text_0.resize(8); Text_1.resize(8); } - - std::vector > Text_0; - std::vector > Text_1; -}; -#endif - diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp new file mode 100644 index 00000000000..48179190a6e --- /dev/null +++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "UpdateMask.h" +#include "Opcodes.h" +#include "World.h" +#include "ObjectAccessor.h" +#include "Database/DatabaseEnv.h" +#include "GridNotifiers.h" +#include "CellImpl.h" +#include "GridNotifiersImpl.h" + +DynamicObject::DynamicObject() : WorldObject() +{ + m_objectType |= TYPEMASK_DYNAMICOBJECT; + m_objectTypeId = TYPEID_DYNAMICOBJECT; + + m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_POSITION); + + m_valuesCount = DYNAMICOBJECT_END; + + m_aura = 0; + m_duration = 0; +} + +void DynamicObject::AddToWorld() +{ + ///- Register the dynamicObject for guid lookup + if (!IsInWorld()) + { + ObjectAccessor::Instance().AddObject(this); + WorldObject::AddToWorld(); + } +} + +void DynamicObject::RemoveFromWorld() +{ + ///- Remove the dynamicObject from the accessor + if (IsInWorld()) + { + if (m_isWorldObject) + { + if (Unit *caster = GetCaster()) + { + if (caster->GetTypeId() == TYPEID_PLAYER) + caster->ToPlayer()->SetViewpoint(this, false); + } + else + { + sLog.outCrash("DynamicObject::RemoveFromWorld cannot find viewpoint owner"); + } + } + WorldObject::RemoveFromWorld(); + ObjectAccessor::Instance().RemoveObject(this); + } +} + +bool DynamicObject::Create(uint32 guidlow, Unit *caster, uint32 spellId, const Position &pos, float radius, bool active) +{ + SetMap(caster->GetMap()); + Relocate(pos); + if (!IsPositionValid()) + { + sLog.outError("DynamicObject (spell %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)",spellId,GetPositionX(),GetPositionY()); + return false; + } + + WorldObject::_Create(guidlow, HIGHGUID_DYNAMICOBJECT, caster->GetPhaseMask()); + + SetEntry(spellId); + SetFloatValue(OBJECT_FIELD_SCALE_X, 1); + SetUInt64Value(DYNAMICOBJECT_CASTER, caster->GetGUID()); + + // The lower word of DYNAMICOBJECT_BYTES must be 0x0001. This value means that the visual radius will be overriden + // by client for most of the "ground patch" visual effect spells and a few "skyfall" ones like Hurricane. + // If any other value is used, the client will _always_ use the radius provided in DYNAMICOBJECT_RADIUS, but + // precompensation is necessary (eg radius *= 2) for many spells. Anyway, blizz sends 0x0001 for all the spells + // I saw sniffed... + SetUInt32Value(DYNAMICOBJECT_BYTES, 0x00000001); + SetUInt32Value(DYNAMICOBJECT_SPELLID, spellId); + SetFloatValue(DYNAMICOBJECT_RADIUS, radius); + SetUInt32Value(DYNAMICOBJECT_CASTTIME, getMSTime()); + + m_isWorldObject = active; + return true; +} + +Unit* DynamicObject::GetCaster() const +{ + // can be not found in some cases + return ObjectAccessor::GetUnit(*this, GetCasterGUID()); +} + +void DynamicObject::Update(uint32 p_time) +{ + // caster can be not in world at time dynamic object update, but dynamic object not yet deleted in Unit destructor + Unit* caster = GetCaster(); + if (!caster) + { + Delete(); + return; + } + + bool expired = false; + + if (m_aura) + { + if (!m_aura->IsRemoved()) + m_aura->UpdateOwner(p_time, this); + + // m_aura may be set to null in Unit::RemoveGameObject call + if (m_aura && (m_aura->IsRemoved() || m_aura->IsExpired())) + expired = true; + } + else + { + if (GetDuration() > int32(p_time)) + m_duration -= p_time; + else + expired = true; + } + + if (expired) + { + caster->RemoveDynObjectWithGUID(GetGUID()); + Delete(); + } +} + +void DynamicObject::Delete() +{ + if (m_aura) + { + // dynObj may be removed in Aura::Remove - we cannot delete there + // so recheck aura here + if (!m_aura->IsRemoved()) + m_aura->_Remove(AURA_REMOVE_BY_DEFAULT); + delete m_aura; + m_aura = NULL; + } + SendObjectDeSpawnAnim(GetGUID()); + RemoveFromWorld(); + AddObjectToRemoveList(); +} + +int32 DynamicObject::GetDuration() const +{ + if (!m_aura) + return m_duration; + else + return m_aura->GetDuration(); +} + +void DynamicObject::SetDuration(int32 newDuration) +{ + if (!m_aura) + m_duration = newDuration; + else + m_aura->SetDuration(newDuration); +} + +void DynamicObject::Delay(int32 delaytime) +{ + SetDuration(GetDuration() - delaytime); +} + +bool DynamicObject::isVisibleForInState(Player const* u, bool inVisibleList) const +{ + return IsInWorld() && u->IsInWorld() + && (IsWithinDistInMap(u->m_seer,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false)); +} diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.h b/src/server/game/Entities/DynamicObject/DynamicObject.h new file mode 100644 index 00000000000..9a70407fd2d --- /dev/null +++ b/src/server/game/Entities/DynamicObject/DynamicObject.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYCORE_DYNAMICOBJECT_H +#define TRINITYCORE_DYNAMICOBJECT_H + +#include "Object.h" + +class Unit; +class Aura; +struct SpellEntry; + +class DynamicObject : public WorldObject, public GridObject +{ + public: + explicit DynamicObject(); + + void AddToWorld(); + void RemoveFromWorld(); + + bool Create(uint32 guidlow, Unit *caster, uint32 spellId, const Position &pos, float radius, bool active); + void Update(uint32 p_time); + void Delete(); + void SetDuration(int32 newDuration); + int32 GetDuration() const; + void SetAura(Aura * aura) {assert (!m_aura && aura); m_aura = aura;} + void Delay(int32 delaytime); + uint32 GetSpellId() const { return GetUInt32Value(DYNAMICOBJECT_SPELLID); } + uint64 GetCasterGUID() const { return GetUInt64Value(DYNAMICOBJECT_CASTER); } + float GetRadius() const { return GetFloatValue(DYNAMICOBJECT_RADIUS); } + Unit* GetCaster() const; + bool isVisibleForInState(Player const* u, bool inVisibleList) const; + + void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); } + void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); } + void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); } + void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); } + void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); } + + protected: + int32 m_duration; // for non-aura dynobjects + Aura * m_aura; +}; +#endif diff --git a/src/server/game/Entities/Item/Bag.cpp b/src/server/game/Entities/Item/Bag.cpp deleted file mode 100644 index aa78126b198..00000000000 --- a/src/server/game/Entities/Item/Bag.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "ObjectMgr.h" -#include "Database/DatabaseEnv.h" - -#include "Bag.h" -#include "Log.h" -#include "UpdateData.h" - -Bag::Bag(): Item() -{ - m_objectType |= TYPEMASK_CONTAINER; - m_objectTypeId = TYPEID_CONTAINER; - - m_valuesCount = CONTAINER_END; - - memset(m_bagslot, 0, sizeof(Item *) * MAX_BAG_SIZE); -} - -Bag::~Bag() -{ - for (uint8 i = 0; i < MAX_BAG_SIZE; ++i) - if (Item *item = m_bagslot[i]) - { - if (item->IsInWorld()) - { - sLog.outCrash("Item %u (slot %u, bag slot %u) in bag %u (slot %u, bag slot %u, m_bagslot %u) is to be deleted but is still in world.", - item->GetEntry(), (uint32)item->GetSlot(), (uint32)item->GetBagSlot(), - GetEntry(), (uint32)GetSlot(), (uint32)GetBagSlot(), (uint32)i); - item->RemoveFromWorld(); - } - delete m_bagslot[i]; - } -} - -void Bag::AddToWorld() -{ - Item::AddToWorld(); - - for (uint32 i = 0; i < GetBagSize(); ++i) - if (m_bagslot[i]) - m_bagslot[i]->AddToWorld(); -} - -void Bag::RemoveFromWorld() -{ - for (uint32 i = 0; i < GetBagSize(); ++i) - if (m_bagslot[i]) - m_bagslot[i]->RemoveFromWorld(); - - Item::RemoveFromWorld(); -} - -bool Bag::Create(uint32 guidlow, uint32 itemid, Player const* owner) -{ - ItemPrototype const * itemProto = objmgr.GetItemPrototype(itemid); - - if (!itemProto || itemProto->ContainerSlots > MAX_BAG_SIZE) - return false; - - Object::_Create(guidlow, 0, HIGHGUID_CONTAINER); - - SetEntry(itemid); - SetFloatValue(OBJECT_FIELD_SCALE_X, 1.0f); - - SetUInt64Value(ITEM_FIELD_OWNER, owner ? owner->GetGUID() : 0); - SetUInt64Value(ITEM_FIELD_CONTAINED, owner ? owner->GetGUID() : 0); - - SetUInt32Value(ITEM_FIELD_MAXDURABILITY, itemProto->MaxDurability); - SetUInt32Value(ITEM_FIELD_DURABILITY, itemProto->MaxDurability); - SetUInt32Value(ITEM_FIELD_FLAGS, itemProto->Flags); - SetUInt32Value(ITEM_FIELD_STACK_COUNT, 1); - - // Setting the number of Slots the Container has - SetUInt32Value(CONTAINER_FIELD_NUM_SLOTS, itemProto->ContainerSlots); - - // Cleaning 20 slots - for (uint8 i = 0; i < MAX_BAG_SIZE; ++i) - { - SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (i*2), 0); - m_bagslot[i] = NULL; - } - - return true; -} - -void Bag::SaveToDB() -{ - Item::SaveToDB(); -} - -bool Bag::LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult_AutoPtr result) -{ - if (!Item::LoadFromDB(guid, owner_guid, result)) - return false; - - // cleanup bag content related item value fields (its will be filled correctly from `character_inventory`) - for (uint8 i = 0; i < MAX_BAG_SIZE; ++i) - { - SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (i*2), 0); - if (m_bagslot[i]) - { - delete m_bagslot[i]; - m_bagslot[i] = NULL; - } - } - - return true; -} - -void Bag::DeleteFromDB() -{ - for (uint8 i = 0; i < MAX_BAG_SIZE; ++i) - if (m_bagslot[i]) - m_bagslot[i]->DeleteFromDB(); - - Item::DeleteFromDB(); -} - -uint32 Bag::GetFreeSlots() const -{ - uint32 slots = 0; - for (uint32 i=0; i < GetBagSize(); ++i) - if (!m_bagslot[i]) - ++slots; - - return slots; -} - -void Bag::RemoveItem(uint8 slot, bool /*update*/) -{ - assert(slot < MAX_BAG_SIZE); - - if (m_bagslot[slot]) - m_bagslot[slot]->SetContainer(NULL); - - m_bagslot[slot] = NULL; - SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (slot * 2), 0); -} - -void Bag::StoreItem(uint8 slot, Item *pItem, bool /*update*/) -{ - assert(slot < MAX_BAG_SIZE); - - if (pItem && pItem->GetGUID() != this->GetGUID()) - { - m_bagslot[slot] = pItem; - SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (slot * 2), pItem->GetGUID()); - pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, GetGUID()); - pItem->SetUInt64Value(ITEM_FIELD_OWNER, GetOwnerGUID()); - pItem->SetContainer(this); - pItem->SetSlot(slot); - } -} - -void Bag::BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const -{ - Item::BuildCreateUpdateBlockForPlayer(data, target); - - for (uint32 i = 0; i < GetBagSize(); ++i) - if (m_bagslot[i]) - m_bagslot[i]->BuildCreateUpdateBlockForPlayer(data, target); -} - -// If the bag is empty returns true -bool Bag::IsEmpty() const -{ - for (uint32 i = 0; i < GetBagSize(); ++i) - if (m_bagslot[i]) - return false; - - return true; -} - -uint32 Bag::GetItemCount(uint32 item, Item* eItem) const -{ - Item *pItem; - uint32 count = 0; - for (uint32 i=0; i < GetBagSize(); ++i) - { - pItem = m_bagslot[i]; - if (pItem && pItem != eItem && pItem->GetEntry() == item) - count += pItem->GetCount(); - } - - if (eItem && eItem->GetProto()->GemProperties) - { - for (uint32 i=0; i < GetBagSize(); ++i) - { - pItem = m_bagslot[i]; - if (pItem && pItem != eItem && pItem->GetProto()->Socket[0].Color) - count += pItem->GetGemCountWithID(item); - } - } - - return count; -} - -uint8 Bag::GetSlotByItemGUID(uint64 guid) const -{ - for (uint32 i = 0; i < GetBagSize(); ++i) - if (m_bagslot[i] != 0) - if (m_bagslot[i]->GetGUID() == guid) - return i; - - return NULL_SLOT; -} - -Item* Bag::GetItemByPos(uint8 slot) const -{ - if (slot < GetBagSize()) - return m_bagslot[slot]; - - return NULL; -} - diff --git a/src/server/game/Entities/Item/Bag.h b/src/server/game/Entities/Item/Bag.h deleted file mode 100644 index 5bc2480fc47..00000000000 --- a/src/server/game/Entities/Item/Bag.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_BAG_H -#define TRINITY_BAG_H - -// Maximum 36 Slots ((CONTAINER_END - CONTAINER_FIELD_SLOT_1)/2 -#define MAX_BAG_SIZE 36 // 2.0.12 - -#include "Item.h" -#include "ItemPrototype.h" - -class Bag : public Item -{ - public: - - Bag(); - ~Bag(); - - void AddToWorld(); - void RemoveFromWorld(); - - bool Create(uint32 guidlow, uint32 itemid, Player const* owner); - - void Clear(); - void StoreItem(uint8 slot, Item *pItem, bool update); - void RemoveItem(uint8 slot, bool update); - - Item* GetItemByPos(uint8 slot) const; - uint32 GetItemCount(uint32 item, Item* eItem = NULL) const; - - uint8 GetSlotByItemGUID(uint64 guid) const; - bool IsEmpty() const; - uint32 GetFreeSlots() const; - uint32 GetBagSize() const { return GetUInt32Value(CONTAINER_FIELD_NUM_SLOTS); } - - // DB operations - // overwrite virtual Item::SaveToDB - void SaveToDB(); - // overwrite virtual Item::LoadFromDB - bool LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult_AutoPtr result); - // overwrite virtual Item::DeleteFromDB - void DeleteFromDB(); - - void BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const; - - protected: - - // Bag Storage space - Item* m_bagslot[MAX_BAG_SIZE]; -}; - -inline Item* NewItemOrBag(ItemPrototype const * proto) -{ - return (proto->InventoryType == INVTYPE_BAG) ? new Bag : new Item; -} -#endif - diff --git a/src/server/game/Entities/Item/Container/Bag.cpp b/src/server/game/Entities/Item/Container/Bag.cpp new file mode 100644 index 00000000000..aa78126b198 --- /dev/null +++ b/src/server/game/Entities/Item/Container/Bag.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "ObjectMgr.h" +#include "Database/DatabaseEnv.h" + +#include "Bag.h" +#include "Log.h" +#include "UpdateData.h" + +Bag::Bag(): Item() +{ + m_objectType |= TYPEMASK_CONTAINER; + m_objectTypeId = TYPEID_CONTAINER; + + m_valuesCount = CONTAINER_END; + + memset(m_bagslot, 0, sizeof(Item *) * MAX_BAG_SIZE); +} + +Bag::~Bag() +{ + for (uint8 i = 0; i < MAX_BAG_SIZE; ++i) + if (Item *item = m_bagslot[i]) + { + if (item->IsInWorld()) + { + sLog.outCrash("Item %u (slot %u, bag slot %u) in bag %u (slot %u, bag slot %u, m_bagslot %u) is to be deleted but is still in world.", + item->GetEntry(), (uint32)item->GetSlot(), (uint32)item->GetBagSlot(), + GetEntry(), (uint32)GetSlot(), (uint32)GetBagSlot(), (uint32)i); + item->RemoveFromWorld(); + } + delete m_bagslot[i]; + } +} + +void Bag::AddToWorld() +{ + Item::AddToWorld(); + + for (uint32 i = 0; i < GetBagSize(); ++i) + if (m_bagslot[i]) + m_bagslot[i]->AddToWorld(); +} + +void Bag::RemoveFromWorld() +{ + for (uint32 i = 0; i < GetBagSize(); ++i) + if (m_bagslot[i]) + m_bagslot[i]->RemoveFromWorld(); + + Item::RemoveFromWorld(); +} + +bool Bag::Create(uint32 guidlow, uint32 itemid, Player const* owner) +{ + ItemPrototype const * itemProto = objmgr.GetItemPrototype(itemid); + + if (!itemProto || itemProto->ContainerSlots > MAX_BAG_SIZE) + return false; + + Object::_Create(guidlow, 0, HIGHGUID_CONTAINER); + + SetEntry(itemid); + SetFloatValue(OBJECT_FIELD_SCALE_X, 1.0f); + + SetUInt64Value(ITEM_FIELD_OWNER, owner ? owner->GetGUID() : 0); + SetUInt64Value(ITEM_FIELD_CONTAINED, owner ? owner->GetGUID() : 0); + + SetUInt32Value(ITEM_FIELD_MAXDURABILITY, itemProto->MaxDurability); + SetUInt32Value(ITEM_FIELD_DURABILITY, itemProto->MaxDurability); + SetUInt32Value(ITEM_FIELD_FLAGS, itemProto->Flags); + SetUInt32Value(ITEM_FIELD_STACK_COUNT, 1); + + // Setting the number of Slots the Container has + SetUInt32Value(CONTAINER_FIELD_NUM_SLOTS, itemProto->ContainerSlots); + + // Cleaning 20 slots + for (uint8 i = 0; i < MAX_BAG_SIZE; ++i) + { + SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (i*2), 0); + m_bagslot[i] = NULL; + } + + return true; +} + +void Bag::SaveToDB() +{ + Item::SaveToDB(); +} + +bool Bag::LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult_AutoPtr result) +{ + if (!Item::LoadFromDB(guid, owner_guid, result)) + return false; + + // cleanup bag content related item value fields (its will be filled correctly from `character_inventory`) + for (uint8 i = 0; i < MAX_BAG_SIZE; ++i) + { + SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (i*2), 0); + if (m_bagslot[i]) + { + delete m_bagslot[i]; + m_bagslot[i] = NULL; + } + } + + return true; +} + +void Bag::DeleteFromDB() +{ + for (uint8 i = 0; i < MAX_BAG_SIZE; ++i) + if (m_bagslot[i]) + m_bagslot[i]->DeleteFromDB(); + + Item::DeleteFromDB(); +} + +uint32 Bag::GetFreeSlots() const +{ + uint32 slots = 0; + for (uint32 i=0; i < GetBagSize(); ++i) + if (!m_bagslot[i]) + ++slots; + + return slots; +} + +void Bag::RemoveItem(uint8 slot, bool /*update*/) +{ + assert(slot < MAX_BAG_SIZE); + + if (m_bagslot[slot]) + m_bagslot[slot]->SetContainer(NULL); + + m_bagslot[slot] = NULL; + SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (slot * 2), 0); +} + +void Bag::StoreItem(uint8 slot, Item *pItem, bool /*update*/) +{ + assert(slot < MAX_BAG_SIZE); + + if (pItem && pItem->GetGUID() != this->GetGUID()) + { + m_bagslot[slot] = pItem; + SetUInt64Value(CONTAINER_FIELD_SLOT_1 + (slot * 2), pItem->GetGUID()); + pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, GetGUID()); + pItem->SetUInt64Value(ITEM_FIELD_OWNER, GetOwnerGUID()); + pItem->SetContainer(this); + pItem->SetSlot(slot); + } +} + +void Bag::BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const +{ + Item::BuildCreateUpdateBlockForPlayer(data, target); + + for (uint32 i = 0; i < GetBagSize(); ++i) + if (m_bagslot[i]) + m_bagslot[i]->BuildCreateUpdateBlockForPlayer(data, target); +} + +// If the bag is empty returns true +bool Bag::IsEmpty() const +{ + for (uint32 i = 0; i < GetBagSize(); ++i) + if (m_bagslot[i]) + return false; + + return true; +} + +uint32 Bag::GetItemCount(uint32 item, Item* eItem) const +{ + Item *pItem; + uint32 count = 0; + for (uint32 i=0; i < GetBagSize(); ++i) + { + pItem = m_bagslot[i]; + if (pItem && pItem != eItem && pItem->GetEntry() == item) + count += pItem->GetCount(); + } + + if (eItem && eItem->GetProto()->GemProperties) + { + for (uint32 i=0; i < GetBagSize(); ++i) + { + pItem = m_bagslot[i]; + if (pItem && pItem != eItem && pItem->GetProto()->Socket[0].Color) + count += pItem->GetGemCountWithID(item); + } + } + + return count; +} + +uint8 Bag::GetSlotByItemGUID(uint64 guid) const +{ + for (uint32 i = 0; i < GetBagSize(); ++i) + if (m_bagslot[i] != 0) + if (m_bagslot[i]->GetGUID() == guid) + return i; + + return NULL_SLOT; +} + +Item* Bag::GetItemByPos(uint8 slot) const +{ + if (slot < GetBagSize()) + return m_bagslot[slot]; + + return NULL; +} + diff --git a/src/server/game/Entities/Item/Container/Bag.h b/src/server/game/Entities/Item/Container/Bag.h new file mode 100644 index 00000000000..5bc2480fc47 --- /dev/null +++ b/src/server/game/Entities/Item/Container/Bag.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_BAG_H +#define TRINITY_BAG_H + +// Maximum 36 Slots ((CONTAINER_END - CONTAINER_FIELD_SLOT_1)/2 +#define MAX_BAG_SIZE 36 // 2.0.12 + +#include "Item.h" +#include "ItemPrototype.h" + +class Bag : public Item +{ + public: + + Bag(); + ~Bag(); + + void AddToWorld(); + void RemoveFromWorld(); + + bool Create(uint32 guidlow, uint32 itemid, Player const* owner); + + void Clear(); + void StoreItem(uint8 slot, Item *pItem, bool update); + void RemoveItem(uint8 slot, bool update); + + Item* GetItemByPos(uint8 slot) const; + uint32 GetItemCount(uint32 item, Item* eItem = NULL) const; + + uint8 GetSlotByItemGUID(uint64 guid) const; + bool IsEmpty() const; + uint32 GetFreeSlots() const; + uint32 GetBagSize() const { return GetUInt32Value(CONTAINER_FIELD_NUM_SLOTS); } + + // DB operations + // overwrite virtual Item::SaveToDB + void SaveToDB(); + // overwrite virtual Item::LoadFromDB + bool LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult_AutoPtr result); + // overwrite virtual Item::DeleteFromDB + void DeleteFromDB(); + + void BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const; + + protected: + + // Bag Storage space + Item* m_bagslot[MAX_BAG_SIZE]; +}; + +inline Item* NewItemOrBag(ItemPrototype const * proto) +{ + return (proto->InventoryType == INVTYPE_BAG) ? new Bag : new Item; +} +#endif + diff --git a/src/server/game/Entities/Item/ItemHandler.cpp b/src/server/game/Entities/Item/ItemHandler.cpp deleted file mode 100644 index 53aede43492..00000000000 --- a/src/server/game/Entities/Item/ItemHandler.cpp +++ /dev/null @@ -1,1430 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "Item.h" -#include "UpdateData.h" -#include "ObjectAccessor.h" - -void WorldSession::HandleSplitItemOpcode(WorldPacket & recv_data) -{ - //sLog.outDebug("WORLD: CMSG_SPLIT_ITEM"); - uint8 srcbag, srcslot, dstbag, dstslot; - uint32 count; - - recv_data >> srcbag >> srcslot >> dstbag >> dstslot >> count; - //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u, count = %u", srcbag, srcslot, dstbag, dstslot, count); - - uint16 src = ((srcbag << 8) | srcslot); - uint16 dst = ((dstbag << 8) | dstslot); - - if (src == dst) - return; - - if (count == 0) - return; //check count - if zero it's fake packet - - if (!_player->IsValidPos(srcbag,srcslot)) - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - if (!_player->IsValidPos(dstbag,dstslot)) - { - _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); - return; - } - - _player->SplitItem(src, dst, count); -} - -void WorldSession::HandleSwapInvItemOpcode(WorldPacket & recv_data) -{ - //sLog.outDebug("WORLD: CMSG_SWAP_INV_ITEM"); - uint8 srcslot, dstslot; - - recv_data >> dstslot >> srcslot; - //sLog.outDebug("STORAGE: receive srcslot = %u, dstslot = %u", srcslot, dstslot); - - // prevent attempt swap same item to current position generated by client at special checting sequence - if (srcslot == dstslot) - return; - - if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0,srcslot)) - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0,dstslot)) - { - _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); - return; - } - - uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot); - uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot); - - _player->SwapItem(src, dst); -} - -void WorldSession::HandleAutoEquipItemSlotOpcode(WorldPacket & recv_data) -{ - uint64 itemguid; - uint8 dstslot; - recv_data >> itemguid >> dstslot; - - // cheating attempt, client should never send opcode in that case - if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, dstslot)) - return; - - Item* item = _player->GetItemByGuid(itemguid); - uint16 dstpos = dstslot | (INVENTORY_SLOT_BAG_0 << 8); - - if (!item || item->GetPos() == dstpos) - return; - - _player->SwapItem(item->GetPos(), dstpos); -} - -void WorldSession::HandleSwapItem(WorldPacket & recv_data) -{ - //sLog.outDebug("WORLD: CMSG_SWAP_ITEM"); - uint8 dstbag, dstslot, srcbag, srcslot; - - recv_data >> dstbag >> dstslot >> srcbag >> srcslot ; - //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u", srcbag, srcslot, dstbag, dstslot); - - uint16 src = ((srcbag << 8) | srcslot); - uint16 dst = ((dstbag << 8) | dstslot); - - // prevent attempt swap same item to current position generated by client at special checting sequence - if (src == dst) - return; - - if (!_player->IsValidPos(srcbag,srcslot)) - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - if (!_player->IsValidPos(dstbag,dstslot)) - { - _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); - return; - } - - _player->SwapItem(src, dst); -} - -void WorldSession::HandleAutoEquipItemOpcode(WorldPacket & recv_data) -{ - //sLog.outDebug("WORLD: CMSG_AUTOEQUIP_ITEM"); - uint8 srcbag, srcslot; - - recv_data >> srcbag >> srcslot; - //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); - - Item *pSrcItem = _player->GetItemByPos(srcbag, srcslot); - if (!pSrcItem) - return; // only at cheat - - uint16 dest; - uint8 msg = _player->CanEquipItem(NULL_SLOT, dest, pSrcItem, !pSrcItem->IsBag()); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pSrcItem, NULL); - return; - } - - uint16 src = pSrcItem->GetPos(); - if (dest == src) // prevent equip in same slot, only at cheat - return; - - Item *pDstItem = _player->GetItemByPos(dest); - if (!pDstItem) // empty slot, simple case - { - _player->RemoveItem(srcbag, srcslot, true); - _player->EquipItem(dest, pSrcItem, true); - _player->AutoUnequipOffhandIfNeed(); - } - else // have currently equipped item, not simple case - { - uint8 dstbag = pDstItem->GetBagSlot(); - uint8 dstslot = pDstItem->GetSlot(); - - msg = _player->CanUnequipItem(dest, !pSrcItem->IsBag()); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pDstItem, NULL); - return; - } - - // check dest->src move possibility - ItemPosCountVec sSrc; - uint16 eSrc = 0; - if (_player->IsInventoryPos(src)) - { - msg = _player->CanStoreItem(srcbag, srcslot, sSrc, pDstItem, true); - if (msg != EQUIP_ERR_OK) - msg = _player->CanStoreItem(srcbag, NULL_SLOT, sSrc, pDstItem, true); - if (msg != EQUIP_ERR_OK) - msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sSrc, pDstItem, true); - } - else if (_player->IsBankPos(src)) - { - msg = _player->CanBankItem(srcbag, srcslot, sSrc, pDstItem, true); - if (msg != EQUIP_ERR_OK) - msg = _player->CanBankItem(srcbag, NULL_SLOT, sSrc, pDstItem, true); - if (msg != EQUIP_ERR_OK) - msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, sSrc, pDstItem, true); - } - else if (_player->IsEquipmentPos(src)) - { - msg = _player->CanEquipItem(srcslot, eSrc, pDstItem, true); - if (msg == EQUIP_ERR_OK) - msg = _player->CanUnequipItem(eSrc, true); - } - - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pDstItem, pSrcItem); - return; - } - - // now do moves, remove... - _player->RemoveItem(dstbag, dstslot, false); - _player->RemoveItem(srcbag, srcslot, false); - - // add to dest - _player->EquipItem(dest, pSrcItem, true); - - // add to src - if (_player->IsInventoryPos(src)) - _player->StoreItem(sSrc, pDstItem, true); - else if (_player->IsBankPos(src)) - _player->BankItem(sSrc, pDstItem, true); - else if (_player->IsEquipmentPos(src)) - _player->EquipItem(eSrc, pDstItem, true); - - _player->AutoUnequipOffhandIfNeed(); - } -} - -void WorldSession::HandleDestroyItemOpcode(WorldPacket & recv_data) -{ - //sLog.outDebug("WORLD: CMSG_DESTROYITEM"); - uint8 bag, slot, count, data1, data2, data3; - - recv_data >> bag >> slot >> count >> data1 >> data2 >> data3; - //sLog.outDebug("STORAGE: receive bag = %u, slot = %u, count = %u", bag, slot, count); - - uint16 pos = (bag << 8) | slot; - - // prevent drop unequipable items (in combat, for example) and non-empty bags - if (_player->IsEquipmentPos(pos) || _player->IsBagPos(pos)) - { - uint8 msg = _player->CanUnequipItem(pos, false); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, _player->GetItemByPos(pos), NULL); - return; - } - } - - Item *pItem = _player->GetItemByPos(bag, slot); - if (!pItem) - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - if (count) - { - uint32 i_count = count; - _player->DestroyItemCount(pItem, i_count, true); - } - else - _player->DestroyItem(bag, slot, true); -} - -// Only _static_ data send in this packet !!! -void WorldSession::HandleItemQuerySingleOpcode(WorldPacket & recv_data) -{ - //sLog.outDebug("WORLD: CMSG_ITEM_QUERY_SINGLE"); - uint32 item; - recv_data >> item; - - sLog.outDetail("STORAGE: Item Query = %u", item); - - ItemPrototype const *pProto = objmgr.GetItemPrototype(item); - if (pProto) - { - std::string Name = pProto->Name1; - std::string Description = pProto->Description; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId); - if (il) - { - if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty()) - Name = il->Name[loc_idx]; - if (il->Description.size() > size_t(loc_idx) && !il->Description[loc_idx].empty()) - Description = il->Description[loc_idx]; - } - } - // guess size - WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 600); - data << pProto->ItemId; - data << pProto->Class; - data << pProto->SubClass; - data << int32(pProto->Unk0); // new 2.0.3, not exist in wdb cache? - data << Name; - data << uint8(0x00); //pProto->Name2; // blizz not send name there, just uint8(0x00); <-- \0 = empty string = empty name... - data << uint8(0x00); //pProto->Name3; // blizz not send name there, just uint8(0x00); - data << uint8(0x00); //pProto->Name4; // blizz not send name there, just uint8(0x00); - data << pProto->DisplayInfoID; - data << pProto->Quality; - data << pProto->Flags; - data << pProto->Flags2; - data << pProto->BuyPrice; - data << pProto->SellPrice; - data << pProto->InventoryType; - data << pProto->AllowableClass; - data << pProto->AllowableRace; - data << pProto->ItemLevel; - data << pProto->RequiredLevel; - data << pProto->RequiredSkill; - data << pProto->RequiredSkillRank; - data << pProto->RequiredSpell; - data << pProto->RequiredHonorRank; - data << pProto->RequiredCityRank; - data << pProto->RequiredReputationFaction; - data << pProto->RequiredReputationRank; - data << int32(pProto->MaxCount); - data << int32(pProto->Stackable); - data << pProto->ContainerSlots; - data << pProto->StatsCount; // item stats count - for (uint32 i = 0; i < pProto->StatsCount; ++i) - { - data << pProto->ItemStat[i].ItemStatType; - data << pProto->ItemStat[i].ItemStatValue; - } - data << pProto->ScalingStatDistribution; // scaling stats distribution - data << pProto->ScalingStatValue; // some kind of flags used to determine stat values column - for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) - { - data << pProto->Damage[i].DamageMin; - data << pProto->Damage[i].DamageMax; - data << pProto->Damage[i].DamageType; - } - - // resistances (7) - data << pProto->Armor; - data << pProto->HolyRes; - data << pProto->FireRes; - data << pProto->NatureRes; - data << pProto->FrostRes; - data << pProto->ShadowRes; - data << pProto->ArcaneRes; - - data << pProto->Delay; - data << pProto->AmmoType; - data << pProto->RangedModRange; - - for (int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s) - { - // send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown - // use `item_template` or if not set then only use spell cooldowns - SpellEntry const* spell = sSpellStore.LookupEntry(pProto->Spells[s].SpellId); - if (spell) - { - bool db_data = pProto->Spells[s].SpellCooldown >= 0 || pProto->Spells[s].SpellCategoryCooldown >= 0; - - data << pProto->Spells[s].SpellId; - data << pProto->Spells[s].SpellTrigger; - data << uint32(-abs(pProto->Spells[s].SpellCharges)); - - if (db_data) - { - data << uint32(pProto->Spells[s].SpellCooldown); - data << uint32(pProto->Spells[s].SpellCategory); - data << uint32(pProto->Spells[s].SpellCategoryCooldown); - } - else - { - data << uint32(spell->RecoveryTime); - data << uint32(spell->Category); - data << uint32(spell->CategoryRecoveryTime); - } - } - else - { - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(-1); - data << uint32(0); - data << uint32(-1); - } - } - data << pProto->Bonding; - data << Description; - data << pProto->PageText; - data << pProto->LanguageID; - data << pProto->PageMaterial; - data << pProto->StartQuest; - data << pProto->LockID; - data << int32(pProto->Material); - data << pProto->Sheath; - data << pProto->RandomProperty; - data << pProto->RandomSuffix; - data << pProto->Block; - data << pProto->ItemSet; - data << pProto->MaxDurability; - data << pProto->Area; - data << pProto->Map; // Added in 1.12.x & 2.0.1 client branch - data << pProto->BagFamily; - data << pProto->TotemCategory; - for (int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s) - { - data << pProto->Socket[s].Color; - data << pProto->Socket[s].Content; - } - data << pProto->socketBonus; - data << pProto->GemProperties; - data << pProto->RequiredDisenchantSkill; - data << pProto->ArmorDamageModifier; - data << abs(pProto->Duration); // added in 2.4.2.8209, duration (seconds) - data << pProto->ItemLimitCategory; // WotLK, ItemLimitCategory - data << pProto->HolidayId; // Holiday.dbc? - SendPacket(&data); - } - else - { - sLog.outDebug("WORLD: CMSG_ITEM_QUERY_SINGLE - NO item INFO! (ENTRY: %u)", item); - WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 4); - data << uint32(item | 0x80000000); - SendPacket(&data); - } -} - -void WorldSession::HandleReadItem(WorldPacket & recv_data) -{ - //sLog.outDebug("WORLD: CMSG_READ_ITEM"); - - uint8 bag, slot; - recv_data >> bag >> slot; - - //sLog.outDetail("STORAGE: Read bag = %u, slot = %u", bag, slot); - Item *pItem = _player->GetItemByPos(bag, slot); - - if (pItem && pItem->GetProto()->PageText) - { - WorldPacket data; - - uint8 msg = _player->CanUseItem(pItem); - if (msg == EQUIP_ERR_OK) - { - data.Initialize (SMSG_READ_ITEM_OK, 8); - sLog.outDetail("STORAGE: Item page sent"); - } - else - { - data.Initialize(SMSG_READ_ITEM_FAILED, 8); - sLog.outDetail("STORAGE: Unable to read item"); - _player->SendEquipError(msg, pItem, NULL); - } - data << pItem->GetGUID(); - SendPacket(&data); - } - else - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); -} - -void WorldSession::HandlePageQuerySkippedOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_PAGE_TEXT_QUERY"); - - uint32 itemid; - uint64 guid; - - recv_data >> itemid >> guid; - - sLog.outDetail("Packet Info: itemid: %u guidlow: %u guidentry: %u guidhigh: %u", - itemid, GUID_LOPART(guid), GUID_ENPART(guid), GUID_HIPART(guid)); -} - -void WorldSession::HandleSellItemOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_SELL_ITEM"); - uint64 vendorguid, itemguid; - uint32 count; - - recv_data >> vendorguid >> itemguid >> count; - - if (!itemguid) - return; - - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR); - if (!pCreature) - { - sLog.outDebug("WORLD: HandleSellItemOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid))); - _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, itemguid, 0); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - Item *pItem = _player->GetItemByGuid(itemguid); - if (pItem) - { - // prevent sell not owner item - if (_player->GetGUID() != pItem->GetOwnerGUID()) - { - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); - return; - } - - // prevent sell non empty bag by drag-and-drop at vendor's item list - if (pItem->IsBag() && !((Bag*)pItem)->IsEmpty()) - { - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); - return; - } - - // prevent sell currently looted item - if (_player->GetLootGUID() == pItem->GetGUID()) - { - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); - return; - } - - // special case at auto sell (sell all) - if (count == 0) - { - count = pItem->GetCount(); - } - else - { - // prevent sell more items that exist in stack (possible only not from client) - if (count > pItem->GetCount()) - { - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); - return; - } - } - - ItemPrototype const *pProto = pItem->GetProto(); - if (pProto) - { - if (pProto->SellPrice > 0) - { - if (count < pItem->GetCount()) // need split items - { - Item *pNewItem = pItem->CloneItem(count, _player); - if (!pNewItem) - { - sLog.outError("WORLD: HandleSellItemOpcode - could not create clone of item %u; count = %u", pItem->GetEntry(), count); - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); - return; - } - - pItem->SetCount(pItem->GetCount() - count); - _player->ItemRemovedQuestCheck(pItem->GetEntry(), count); - if (_player->IsInWorld()) - pItem->SendUpdateToPlayer(_player); - pItem->SetState(ITEM_CHANGED, _player); - - _player->AddItemToBuyBackSlot(pNewItem); - if (_player->IsInWorld()) - pNewItem->SendUpdateToPlayer(_player); - } - else - { - _player->ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount()); - _player->RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true); - pItem->RemoveFromUpdateQueueOf(_player); - _player->AddItemToBuyBackSlot(pItem); - } - - uint32 money = pProto->SellPrice * count; - _player->ModifyMoney(money); - _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS, money); - } - else - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); - return; - } - } - _player->SendSellError(SELL_ERR_CANT_FIND_ITEM, pCreature, itemguid, 0); - return; -} - -void WorldSession::HandleBuybackItem(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_BUYBACK_ITEM"); - uint64 vendorguid; - uint32 slot; - - recv_data >> vendorguid >> slot; - - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR); - if (!pCreature) - { - sLog.outDebug("WORLD: HandleBuybackItem - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid))); - _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - Item *pItem = _player->GetItemFromBuyBackSlot(slot); - if (pItem) - { - uint32 price = _player->GetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + slot - BUYBACK_SLOT_START); - if (_player->GetMoney() < price) - { - _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, pItem->GetEntry(), 0); - return; - } - - ItemPosCountVec dest; - uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false); - if (msg == EQUIP_ERR_OK) - { - _player->ModifyMoney(-(int32)price); - _player->RemoveItemFromBuyBackSlot(slot, false); - _player->ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount()); - _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, pItem->GetEntry(), pItem->GetCount()); - _player->StoreItem(dest, pItem, true); - } - else - _player->SendEquipError(msg, pItem, NULL); - return; - } - else - _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, pCreature, 0, 0); -} - -void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_BUY_ITEM_IN_SLOT"); - uint64 vendorguid, bagguid; - uint32 item, slot, count; - uint8 bagslot; - - recv_data >> vendorguid >> item >> slot >> bagguid >> bagslot >> count; - - // client expects count starting at 1, and we send vendorslot+1 to client already - if (slot > 0) - --slot; - else - return; // cheating - - uint8 bag = NULL_BAG; // init for case invalid bagGUID - - // find bag slot by bag guid - if (bagguid == _player->GetGUID()) - bag = INVENTORY_SLOT_BAG_0; - else - { - for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) - { - if (Bag *pBag = (Bag*)_player->GetItemByPos(INVENTORY_SLOT_BAG_0,i)) - { - if (bagguid == pBag->GetGUID()) - { - bag = i; - break; - } - } - } - } - - // bag not found, cheating? - if (bag == NULL_BAG) - return; - - GetPlayer()->BuyItemFromVendorSlot(vendorguid,slot,item,count,bag,bagslot); -} - -void WorldSession::HandleBuyItemOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_BUY_ITEM"); - uint64 vendorguid; - uint32 item, slot, count; - uint8 unk1; - - recv_data >> vendorguid >> item >> slot >> count >> unk1; - - // client expects count starting at 1, and we send vendorslot+1 to client already - if (slot > 0) - --slot; - else - return; // cheating - - GetPlayer()->BuyItemFromVendorSlot(vendorguid,slot,item,count,NULL_BAG,NULL_SLOT); -} - -void WorldSession::HandleListInventoryOpcode(WorldPacket & recv_data) -{ - uint64 guid; - - recv_data >> guid; - - if (!GetPlayer()->isAlive()) - return; - - sLog.outDebug("WORLD: Recvd CMSG_LIST_INVENTORY"); - - SendListInventory(guid); -} - -void WorldSession::SendListInventory(uint64 vendorguid) -{ - sLog.outDebug("WORLD: Sent SMSG_LIST_INVENTORY"); - - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR); - if (!pCreature) - { - sLog.outDebug("WORLD: SendListInventory - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid))); - _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - // Stop the npc if moving - pCreature->StopMoving(); - - VendorItemData const* vItems = pCreature->GetVendorItems(); - if (!vItems) - { - _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); - return; - } - - uint8 numitems = vItems->GetItemCount(); - uint8 count = 0; - - WorldPacket data(SMSG_LIST_INVENTORY, (8+1+numitems*8*4)); - data << uint64(vendorguid); - - size_t count_pos = data.wpos(); - data << uint8(count); - - float discountMod = _player->GetReputationPriceDiscount(pCreature); - - for (uint8 vendorslot = 0; vendorslot < numitems; ++vendorslot ) - { - if (VendorItem const* crItem = vItems->GetItem(vendorslot)) - { - if (ItemPrototype const *pProto = objmgr.GetItemPrototype(crItem->item)) - { - if ((pProto->AllowableClass & _player->getClassMask()) == 0 && pProto->Bonding == BIND_WHEN_PICKED_UP && !_player->isGameMaster()) - continue; - // Only display items in vendor lists for the team the - // player is on. If GM on, display all items. - // `item_template`.`Faction` is actually `Team`. - // 1 == Horde / 2 == Alliance. Field will be renamed in later - // patch. - if (pProto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY && _player->GetTeam() == ALLIANCE || pProto->Flags2 == ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && _player->GetTeam() == HORDE && !_player->isGameMaster()) - continue; - ++count; - - // reputation discount - int32 price = uint32(floor(pProto->BuyPrice * discountMod)); - - data << uint32(vendorslot+1); // client expects counting to start at 1 - data << uint32(crItem->item); - data << uint32(pProto->DisplayInfoID); - data << int32(crItem->maxcount <= 0 ? 0xFFFFFFFF : pCreature->GetVendorItemCurrentCount(crItem)); - data << uint32(price); - data << uint32(pProto->MaxDurability); - data << uint32(pProto->BuyCount); - data << uint32(crItem->ExtendedCost); - } - } - } - - if (count == 0 || data.size() != 8 + 1 + size_t(count) * 8 * 4) - return; - - data.put(count_pos, count); - SendPacket(&data); -} - -void WorldSession::HandleAutoStoreBagItemOpcode(WorldPacket & recv_data) -{ - //sLog.outDebug("WORLD: CMSG_AUTOSTORE_BAG_ITEM"); - uint8 srcbag, srcslot, dstbag; - - recv_data >> srcbag >> srcslot >> dstbag; - //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u", srcbag, srcslot, dstbag); - - Item *pItem = _player->GetItemByPos(srcbag, srcslot); - if (!pItem) - return; - - if (!_player->IsValidPos(dstbag,NULL_SLOT)) - { - _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); - return; - } - - uint16 src = pItem->GetPos(); - - // check unequip potability for equipped items and bank bags - if (_player->IsEquipmentPos (src) || _player->IsBagPos (src)) - { - uint8 msg = _player->CanUnequipItem(src, !_player->IsBagPos (src)); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pItem, NULL); - return; - } - } - - ItemPosCountVec dest; - uint8 msg = _player->CanStoreItem(dstbag, NULL_SLOT, dest, pItem, false); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pItem, NULL); - return; - } - - // no-op: placed in same slot - if (dest.size() == 1 && dest[0].pos == src) - { - // just remove grey item state - _player->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); - return; - } - - _player->RemoveItem(srcbag, srcslot, true); - _player->StoreItem(dest, pItem, true); -} - -void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: CMSG_BUY_BANK_SLOT"); - - uint64 guid; - recvPacket >> guid; - - // cheating protection - /* not critical if "cheated", and check skip allow by slots in bank windows open by .bank command. - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER); - if (!pCreature) - { - sLog.outDebug("WORLD: HandleBuyBankSlotOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - */ - - uint32 slot = _player->GetBankBagSlotCount(); - - // next slot - ++slot; - - sLog.outDetail("PLAYER: Buy bank bag slot, slot number = %u", slot); - - BankBagSlotPricesEntry const* slotEntry = sBankBagSlotPricesStore.LookupEntry(slot); - - WorldPacket data(SMSG_BUY_BANK_SLOT_RESULT, 4); - - if (!slotEntry) - { - data << uint32(ERR_BANKSLOT_FAILED_TOO_MANY); - SendPacket(&data); - return; - } - - uint32 price = slotEntry->price; - - if (_player->GetMoney() < price) - { - data << uint32(ERR_BANKSLOT_INSUFFICIENT_FUNDS); - SendPacket(&data); - return; - } - - _player->SetBankBagSlotCount(slot); - _player->ModifyMoney(-int32(price)); - - data << uint32(ERR_BANKSLOT_OK); - SendPacket(&data); - - _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT); -} - -void WorldSession::HandleAutoBankItemOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: CMSG_AUTOBANK_ITEM"); - uint8 srcbag, srcslot; - - recvPacket >> srcbag >> srcslot; - sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); - - Item *pItem = _player->GetItemByPos(srcbag, srcslot); - if (!pItem) - return; - - ItemPosCountVec dest; - uint8 msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, dest, pItem, false); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pItem, NULL); - return; - } - - _player->RemoveItem(srcbag, srcslot, true); - _player->BankItem(dest, pItem, true); -} - -void WorldSession::HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: CMSG_AUTOSTORE_BANK_ITEM"); - uint8 srcbag, srcslot; - - recvPacket >> srcbag >> srcslot; - sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); - - Item *pItem = _player->GetItemByPos(srcbag, srcslot); - if (!pItem) - return; - - if (_player->IsBankPos(srcbag, srcslot)) // moving from bank to inventory - { - ItemPosCountVec dest; - uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pItem, NULL); - return; - } - - _player->RemoveItem(srcbag, srcslot, true); - _player->StoreItem(dest, pItem, true); - } - else // moving from inventory to bank - { - ItemPosCountVec dest; - uint8 msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, dest, pItem, false); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pItem, NULL); - return; - } - - _player->RemoveItem(srcbag, srcslot, true); - _player->BankItem(dest, pItem, true); - } -} - -void WorldSession::HandleSetAmmoOpcode(WorldPacket & recv_data) -{ - if (!GetPlayer()->isAlive()) - { - GetPlayer()->SendEquipError(EQUIP_ERR_YOU_ARE_DEAD, NULL, NULL); - return; - } - - sLog.outDebug("WORLD: CMSG_SET_AMMO"); - uint32 item; - - recv_data >> item; - - if (!item) - GetPlayer()->RemoveAmmo(); - else - GetPlayer()->SetAmmo(item); -} - -void WorldSession::SendEnchantmentLog(uint64 Target, uint64 Caster,uint32 ItemID,uint32 SpellID) -{ - WorldPacket data(SMSG_ENCHANTMENTLOG, (8+8+4+4+1)); // last check 2.0.10 - data << uint64(Target); - data << uint64(Caster); - data << uint32(ItemID); - data << uint32(SpellID); - data << uint8(0); - SendPacket(&data); -} - -void WorldSession::SendItemEnchantTimeUpdate(uint64 Playerguid, uint64 Itemguid,uint32 slot,uint32 Duration) -{ - // last check 2.0.10 - WorldPacket data(SMSG_ITEM_ENCHANT_TIME_UPDATE, (8+4+4+8)); - data << uint64(Itemguid); - data << uint32(slot); - data << uint32(Duration); - data << uint64(Playerguid); - SendPacket(&data); -} - -void WorldSession::HandleItemNameQueryOpcode(WorldPacket & recv_data) -{ - uint32 itemid; - recv_data >> itemid; - recv_data.read_skip(); // guid - - sLog.outDebug("WORLD: CMSG_ITEM_NAME_QUERY %u", itemid); - ItemPrototype const *pProto = objmgr.GetItemPrototype(itemid); - if (pProto) - { - std::string Name; - Name = pProto->Name1; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId); - if (il) - { - if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty()) - Name = il->Name[loc_idx]; - } - } - // guess size - WorldPacket data(SMSG_ITEM_NAME_QUERY_RESPONSE, (4+10)); - data << uint32(pProto->ItemId); - data << Name; - data << uint32(pProto->InventoryType); - SendPacket(&data); - return; - } -// This is a BS check, there are lots of items listed in Item.dbc that do not even exist on official -- so we can NEVER get the data for them. -// If you *really* want to spam your error log -- uncomment this. -/* else - { - // listed in dbc or not expected to exist unknown item - if (sItemStore.LookupEntry(itemid)) - sLog.outErrorDb("WORLD: CMSG_ITEM_NAME_QUERY for item %u failed (item listed in Item.dbc but not exist in DB)", itemid); - else - sLog.outError("WORLD: CMSG_ITEM_NAME_QUERY for item %u failed (unknown item, not listed in Item.dbc)", itemid); - } */ -} - -void WorldSession::HandleWrapItemOpcode(WorldPacket& recv_data) -{ - sLog.outDebug("Received opcode CMSG_WRAP_ITEM"); - - uint8 gift_bag, gift_slot, item_bag, item_slot; - //recv_data.hexlike(); - - recv_data >> gift_bag >> gift_slot; // paper - recv_data >> item_bag >> item_slot; // item - - sLog.outDebug("WRAP: receive gift_bag = %u, gift_slot = %u, item_bag = %u, item_slot = %u", gift_bag, gift_slot, item_bag, item_slot); - - Item *gift = _player->GetItemByPos(gift_bag, gift_slot); - if (!gift) - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL); - return; - } - - if (!gift->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPER))// cheating: non-wrapper wrapper - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL); - return; - } - - Item *item = _player->GetItemByPos(item_bag, item_slot); - - if (!item) - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, item, NULL); - return; - } - - if (item == gift) // not possable with pacjket from real client - { - _player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL); - return; - } - - if (item->IsEquipped()) - { - _player->SendEquipError(EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED, item, NULL); - return; - } - - if (item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)) // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED); - { - _player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL); - return; - } - - if (item->IsBag()) - { - _player->SendEquipError(EQUIP_ERR_BAGS_CANT_BE_WRAPPED, item, NULL); - return; - } - - if (item->IsSoulBound()) - { - _player->SendEquipError(EQUIP_ERR_BOUND_CANT_BE_WRAPPED, item, NULL); - return; - } - - if (item->GetMaxStackCount() != 1) - { - _player->SendEquipError(EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED, item, NULL); - return; - } - - // maybe not correct check (it is better than nothing) - if (item->GetProto()->MaxCount>0) - { - _player->SendEquipError(EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED, item, NULL); - return; - } - - CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("INSERT INTO character_gifts VALUES ('%u', '%u', '%u', '%u')", GUID_LOPART(item->GetOwnerGUID()), item->GetGUIDLow(), item->GetEntry(), item->GetUInt32Value(ITEM_FIELD_FLAGS)); - item->SetEntry(gift->GetEntry()); - - switch (item->GetEntry()) - { - case 5042: item->SetEntry(5043); break; - case 5048: item->SetEntry(5044); break; - case 17303: item->SetEntry(17302); break; - case 17304: item->SetEntry(17305); break; - case 17307: item->SetEntry(17308); break; - case 21830: item->SetEntry(21831); break; - } - item->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); - item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED); - item->SetState(ITEM_CHANGED, _player); - - if (item->GetState() == ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance` - { - // after save it will be impossible to remove the item from the queue - item->RemoveFromUpdateQueueOf(_player); - item->SaveToDB(); // item gave inventory record unchanged and can be save standalone - } - CharacterDatabase.CommitTransaction(); - - uint32 count = 1; - _player->DestroyItemCount(gift, count, true); -} - -void WorldSession::HandleSocketOpcode(WorldPacket& recv_data) -{ - sLog.outDebug("WORLD: CMSG_SOCKET_GEMS"); - - uint64 item_guid; - uint64 gem_guids[MAX_GEM_SOCKETS]; - - recv_data >> item_guid; - if (!item_guid) - return; - - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) - recv_data >> gem_guids[i]; - - //cheat -> tried to socket same gem multiple times - if ((gem_guids[0] && (gem_guids[0] == gem_guids[1] || gem_guids[0] == gem_guids[2])) || - (gem_guids[1] && (gem_guids[1] == gem_guids[2]))) - return; - - Item *itemTarget = _player->GetItemByGuid(item_guid); - if (!itemTarget) //missing item to socket - return; - - ItemPrototype const* itemProto = itemTarget->GetProto(); - if (!itemProto) - return; - - //this slot is excepted when applying / removing meta gem bonus - uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT); - - Item *Gems[MAX_GEM_SOCKETS]; - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) - Gems[i] = gem_guids[i] ? _player->GetItemByGuid(gem_guids[i]) : NULL; - - GemPropertiesEntry const *GemProps[MAX_GEM_SOCKETS]; - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get geminfo from dbc storage - GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetProto()->GemProperties) : NULL; - - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe - { - if (!GemProps[i]) - continue; - - // tried to put gem in socket where no socket exists (take care about prismatic sockets) - if (!itemProto->Socket[i].Color) - { - // no prismatic socket - if (!itemTarget->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT)) - return; - - // not first not-colored (not normaly used) socket - if (i != 0 && !itemProto->Socket[i-1].Color && (i+1 >= MAX_GEM_SOCKETS || itemProto->Socket[i+1].Color)) - return; - - // ok, this is first not colored socket for item with prismatic socket - } - - // tried to put normal gem in meta socket - if (itemProto->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META) - return; - - // tried to put meta gem in normal socket - if (itemProto->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META) - return; - } - - uint32 GemEnchants[MAX_GEM_SOCKETS]; - uint32 OldEnchants[MAX_GEM_SOCKETS]; - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get new and old enchantments - { - GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0; - OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i)); - } - - // check unique-equipped conditions - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) - { - if (!Gems[i]) - continue; - - // continue check for case when attempt add 2 similar unique equipped gems in one item. - ItemPrototype const* iGemProto = Gems[i]->GetProto(); - - // unique item (for new and already placed bit removed enchantments - if (iGemProto->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED) - { - for (int j = 0; j < MAX_GEM_SOCKETS; ++j) - { - if (i == j) // skip self - continue; - - if (Gems[j]) - { - if (iGemProto->ItemId == Gems[j]->GetEntry()) - { - _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); - return; - } - } - else if (OldEnchants[j]) - { - if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j])) - { - if (iGemProto->ItemId == enchantEntry->GemID) - { - _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); - return; - } - } - } - - } - } - - // unique limit type item - int32 limit_newcount = 0; - if (iGemProto->ItemLimitCategory) - { - if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->ItemLimitCategory)) - { - for (int j = 0; j < MAX_GEM_SOCKETS; ++j) - { - if (Gems[j]) - { - // destroyed gem - if (OldEnchants[j]) - { - if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j])) - if (ItemPrototype const* jProto = ObjectMgr::GetItemPrototype(enchantEntry->GemID)) - if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory) - --limit_newcount; - } - - // new gem - if (iGemProto->ItemLimitCategory == Gems[j]->GetProto()->ItemLimitCategory) - ++limit_newcount; - } - // existed gem - else if (OldEnchants[j]) - { - if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j])) - if (ItemPrototype const* jProto = ObjectMgr::GetItemPrototype(enchantEntry->GemID)) - if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory) - ++limit_newcount; - } - } - - if (limit_newcount > 0 && uint32(limit_newcount) > limitEntry->maxCount) - { - _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); - return; - } - } - } - - // for equipped item check all equipment for duplicate equipped gems - if (itemTarget->IsEquipped()) - { - if (uint8 res = _player->CanEquipUniqueItem(Gems[i],slot,limit_newcount >= 0 ? limit_newcount : 0)) - { - _player->SendEquipError(res, itemTarget, NULL); - return; - } - } - } - - bool SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus - _player->ToggleMetaGemsActive(slot, false); //turn off all metagems (except for the target item) - - //if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met - - //remove ALL enchants - for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) - _player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),false); - - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) - { - if (GemEnchants[i]) - { - itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i],0,0); - if (Item* guidItem = _player->GetItemByGuid(gem_guids[i])) - _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true); - } - } - - for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) - _player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),true); - - bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state - if (SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change... - { - _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,false); - itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetProto()->socketBonus : 0), 0, 0); - _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,true); - //it is not displayed, client has an inbuilt system to determine if the bonus is activated - } - - _player->ToggleMetaGemsActive(slot, true); //turn on all metagems (except for target item) -} - -void WorldSession::HandleCancelTempEnchantmentOpcode(WorldPacket& recv_data) -{ - sLog.outDebug("WORLD: CMSG_CANCEL_TEMP_ENCHANTMENT"); - - uint32 eslot; - - recv_data >> eslot; - - // apply only to equipped item - if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0,eslot)) - return; - - Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, eslot); - - if (!item) - return; - - if (!item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) - return; - - GetPlayer()->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,false); - item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT); -} - -void WorldSession::HandleItemRefundInfoRequest(WorldPacket& recv_data) -{ - sLog.outDebug("WORLD: CMSG_ITEM_REFUND_INFO"); - - uint64 guid; - recv_data >> guid; // item guid - - Item *item = _player->GetItemByGuid(guid); - if (!item) - { - sLog.outDebug("Item refund: item not found!"); - return; - } - - GetPlayer()->SendRefundInfo(item); -} - -void WorldSession::HandleItemRefund(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: CMSG_ITEM_REFUND"); - uint64 guid; - recv_data >> guid; // item guid - - Item *item = _player->GetItemByGuid(guid); - if (!item) - { - sLog.outDebug("Item refund: item not found!"); - return; - } - - GetPlayer()->RefundItem(item); -} - -/** - * Handles the packet sent by the client when requesting information about item text. - * - * This function is called when player clicks on item which has some flag set - */ -void WorldSession::HandleItemTextQuery(WorldPacket & recv_data ) -{ - uint64 itemGuid; - recv_data >> itemGuid; - - sLog.outDebug("CMSG_ITEM_TEXT_QUERY item guid: %u", GUID_LOPART(itemGuid)); - - WorldPacket data(SMSG_ITEM_TEXT_QUERY_RESPONSE, (4+10)); // guess size - - if (Item *item = _player->GetItemByGuid(itemGuid)) - { - data << uint8(0); // has text - data << uint64(itemGuid); // item guid - data << item->GetText(); - } - else - { - data << uint8(1); // no text - } - - SendPacket(&data); -} diff --git a/src/server/game/Entities/Object/Corpse.cpp b/src/server/game/Entities/Object/Corpse.cpp deleted file mode 100644 index 510ea13e78b..00000000000 --- a/src/server/game/Entities/Object/Corpse.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Corpse.h" -#include "Player.h" -#include "UpdateMask.h" -#include "ObjectAccessor.h" -#include "Database/DatabaseEnv.h" -#include "Opcodes.h" -#include "GossipDef.h" -#include "World.h" - -Corpse::Corpse(CorpseType type) : WorldObject() -, m_type(type) -{ - m_objectType |= TYPEMASK_CORPSE; - m_objectTypeId = TYPEID_CORPSE; - - m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_POSITION); - - m_valuesCount = CORPSE_END; - - m_time = time(NULL); - - lootForBody = false; - - if (type != CORPSE_BONES) - m_isWorldObject = true; -} - -Corpse::~Corpse() -{ -} - -void Corpse::AddToWorld() -{ - ///- Register the corpse for guid lookup - if (!IsInWorld()) - ObjectAccessor::Instance().AddObject(this); - - Object::AddToWorld(); -} - -void Corpse::RemoveFromWorld() -{ - ///- Remove the corpse from the accessor - if (IsInWorld()) - ObjectAccessor::Instance().RemoveObject(this); - - Object::RemoveFromWorld(); -} - -bool Corpse::Create(uint32 guidlow, Map *map) -{ - SetMap(map); - Object::_Create(guidlow, 0, HIGHGUID_CORPSE); - return true; -} - -bool Corpse::Create(uint32 guidlow, Player *owner) -{ - ASSERT(owner); - - Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation()); - - if (!IsPositionValid()) - { - sLog.outError("Corpse (guidlow %d, owner %s) not created. Suggested coordinates isn't valid (X: %f Y: %f)", - guidlow, owner->GetName(), owner->GetPositionX(), owner->GetPositionY()); - return false; - } - - //we need to assign owner's map for corpse - //in other way we will get a crash in Corpse::SaveToDB() - SetMap(owner->GetMap()); - - WorldObject::_Create(guidlow, HIGHGUID_CORPSE, owner->GetPhaseMask()); - - SetFloatValue(OBJECT_FIELD_SCALE_X, 1); - SetUInt64Value(CORPSE_FIELD_OWNER, owner->GetGUID()); - - m_grid = Trinity::ComputeGridPair(GetPositionX(), GetPositionY()); - - return true; -} - -void Corpse::SaveToDB() -{ - // prevent DB data inconsistence problems and duplicates - CharacterDatabase.BeginTransaction(); - DeleteFromDB(); - - std::ostringstream ss; - ss << "INSERT INTO corpse (guid,player,position_x,position_y,position_z,orientation,zone,map,data,time,corpse_type,instance,phaseMask) VALUES (" - << GetGUIDLow() << ", " - << GUID_LOPART(GetOwnerGUID()) << ", " - << GetPositionX() << ", " - << GetPositionY() << ", " - << GetPositionZ() << ", " - << GetOrientation() << ", " - << GetZoneId() << ", " - << GetMapId() << ", '"; - for (uint16 i = 0; i < m_valuesCount; ++i) - ss << GetUInt32Value(i) << " "; - ss << "'," - << uint64(m_time) <<", " - << uint32(GetType()) << ", " - << int(GetInstanceId()) << ", " - << uint16(GetPhaseMask()) << ")"; // prevent out of range error - CharacterDatabase.Execute(ss.str().c_str()); - CharacterDatabase.CommitTransaction(); -} - -void Corpse::DeleteBonesFromWorld() -{ - assert(GetType() == CORPSE_BONES); - Corpse* corpse = ObjectAccessor::GetCorpse(*this, GetGUID()); - - if (!corpse) - { - sLog.outError("Bones %u not found in world.", GetGUIDLow()); - return; - } - - AddObjectToRemoveList(); -} - -void Corpse::DeleteFromDB() -{ - if (GetType() == CORPSE_BONES) - // only specific bones - CharacterDatabase.PExecute("DELETE FROM corpse WHERE guid = '%d'", GetGUIDLow()); - else - // all corpses (not bones) - CharacterDatabase.PExecute("DELETE FROM corpse WHERE player = '%d' AND corpse_type <> '0'", GUID_LOPART(GetOwnerGUID())); -} - -/* -bool Corpse::LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId) -{ - bool external = (result != NULL); - if (!external) - // 0 1 2 3 4 5 6 7 8 9 - result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,data,time,corpse_type,instance,phaseMask FROM corpse WHERE guid = '%u'",guid); - - if (!result) - { - sLog.outError("Corpse (GUID: %u) not found in table `corpse`, can't load. ",guid); - return false; - } - - Field *fields = result->Fetch(); - - if (!LoadFromDB(guid, fields)) - { - if (!external) - delete result; - - return false; - } - - if (!external) - delete result; - - return true; -}*/ - -bool Corpse::LoadFromDB(uint32 guid, Field *fields) -{ - float positionX = fields[0].GetFloat(); - float positionY = fields[1].GetFloat(); - float positionZ = fields[2].GetFloat(); - float ort = fields[3].GetFloat(); - uint32 mapid = fields[4].GetUInt32(); - - Object::_Create(guid, 0, HIGHGUID_CORPSE); - - if (!LoadValues(fields[5].GetString())) - { - sLog.outError("Corpse #%d have broken data in `data` field. Can't be loaded.",guid); - return false; - } - - m_time = time_t(fields[6].GetUInt64()); - m_type = CorpseType(fields[7].GetUInt32()); - - if (m_type >= MAX_CORPSE_TYPE) - { - sLog.outError("Corpse (guidlow %d, owner %d) have wrong corpse type, not load.",GetGUIDLow(),GUID_LOPART(GetOwnerGUID())); - return false; - } - - if (m_type != CORPSE_BONES) - m_isWorldObject = true; - - uint32 instanceid = fields[8].GetUInt32(); - - uint32 phaseMask = fields[9].GetUInt32(); - - // overwrite possible wrong/corrupted guid - SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_CORPSE)); - - // place - SetLocationInstanceId(instanceid); - SetLocationMapId(mapid); - SetPhaseMask(phaseMask, false); - Relocate(positionX, positionY, positionZ, ort); - - if (!IsPositionValid()) - { - sLog.outError("Corpse (guidlow %d, owner %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)", - GetGUIDLow(), GUID_LOPART(GetOwnerGUID()), GetPositionX(), GetPositionY()); - return false; - } - - m_grid = Trinity::ComputeGridPair(GetPositionX(), GetPositionY()); - - return true; -} - -bool Corpse::isVisibleForInState(Player const* u, bool inVisibleList) const -{ - return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u->m_seer, World::GetMaxVisibleDistanceForObject() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false); -} - diff --git a/src/server/game/Entities/Object/Corpse.h b/src/server/game/Entities/Object/Corpse.h deleted file mode 100644 index bab95e99d14..00000000000 --- a/src/server/game/Entities/Object/Corpse.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITYCORE_CORPSE_H -#define TRINITYCORE_CORPSE_H - -#include "Object.h" -#include "Database/DatabaseEnv.h" -#include "GridDefines.h" -#include "LootMgr.h" - -enum CorpseType -{ - CORPSE_BONES = 0, - CORPSE_RESURRECTABLE_PVE = 1, - CORPSE_RESURRECTABLE_PVP = 2 -}; -#define MAX_CORPSE_TYPE 3 - -// Value equal client resurrection dialog show radius. -#define CORPSE_RECLAIM_RADIUS 39 - -enum CorpseFlags -{ - CORPSE_FLAG_NONE = 0x00, - CORPSE_FLAG_BONES = 0x01, - CORPSE_FLAG_UNK1 = 0x02, - CORPSE_FLAG_UNK2 = 0x04, - CORPSE_FLAG_HIDE_HELM = 0x08, - CORPSE_FLAG_HIDE_CLOAK = 0x10, - CORPSE_FLAG_LOOTABLE = 0x20 -}; - -class Corpse : public WorldObject, public GridObject -{ - public: - explicit Corpse(CorpseType type = CORPSE_BONES); - ~Corpse(); - - void AddToWorld(); - void RemoveFromWorld(); - - bool Create(uint32 guidlow, Map *map); - bool Create(uint32 guidlow, Player *owner); - - void SaveToDB(); - //bool LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId); - bool LoadFromDB(uint32 guid, Field *fields); - - void DeleteBonesFromWorld(); - void DeleteFromDB(); - - uint64 const& GetOwnerGUID() const { return GetUInt64Value(CORPSE_FIELD_OWNER); } - - time_t const& GetGhostTime() const { return m_time; } - void ResetGhostTime() { m_time = time(NULL); } - CorpseType GetType() const { return m_type; } - - GridPair const& GetGrid() const { return m_grid; } - void SetGrid(GridPair const& grid) { m_grid = grid; } - - bool isVisibleForInState(Player const* u, bool inVisibleList) const; - - Loot loot; // remove insignia ONLY at BG - Player* lootRecipient; - bool lootForBody; - - void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); } - void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); } - void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); } - void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); } - void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); } - - private: - CorpseType m_type; - time_t m_time; - GridPair m_grid; // gride for corpse position for fast search -}; -#endif - diff --git a/src/server/game/Entities/Object/DynamicObject.cpp b/src/server/game/Entities/Object/DynamicObject.cpp deleted file mode 100644 index 48179190a6e..00000000000 --- a/src/server/game/Entities/Object/DynamicObject.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "UpdateMask.h" -#include "Opcodes.h" -#include "World.h" -#include "ObjectAccessor.h" -#include "Database/DatabaseEnv.h" -#include "GridNotifiers.h" -#include "CellImpl.h" -#include "GridNotifiersImpl.h" - -DynamicObject::DynamicObject() : WorldObject() -{ - m_objectType |= TYPEMASK_DYNAMICOBJECT; - m_objectTypeId = TYPEID_DYNAMICOBJECT; - - m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_POSITION); - - m_valuesCount = DYNAMICOBJECT_END; - - m_aura = 0; - m_duration = 0; -} - -void DynamicObject::AddToWorld() -{ - ///- Register the dynamicObject for guid lookup - if (!IsInWorld()) - { - ObjectAccessor::Instance().AddObject(this); - WorldObject::AddToWorld(); - } -} - -void DynamicObject::RemoveFromWorld() -{ - ///- Remove the dynamicObject from the accessor - if (IsInWorld()) - { - if (m_isWorldObject) - { - if (Unit *caster = GetCaster()) - { - if (caster->GetTypeId() == TYPEID_PLAYER) - caster->ToPlayer()->SetViewpoint(this, false); - } - else - { - sLog.outCrash("DynamicObject::RemoveFromWorld cannot find viewpoint owner"); - } - } - WorldObject::RemoveFromWorld(); - ObjectAccessor::Instance().RemoveObject(this); - } -} - -bool DynamicObject::Create(uint32 guidlow, Unit *caster, uint32 spellId, const Position &pos, float radius, bool active) -{ - SetMap(caster->GetMap()); - Relocate(pos); - if (!IsPositionValid()) - { - sLog.outError("DynamicObject (spell %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)",spellId,GetPositionX(),GetPositionY()); - return false; - } - - WorldObject::_Create(guidlow, HIGHGUID_DYNAMICOBJECT, caster->GetPhaseMask()); - - SetEntry(spellId); - SetFloatValue(OBJECT_FIELD_SCALE_X, 1); - SetUInt64Value(DYNAMICOBJECT_CASTER, caster->GetGUID()); - - // The lower word of DYNAMICOBJECT_BYTES must be 0x0001. This value means that the visual radius will be overriden - // by client for most of the "ground patch" visual effect spells and a few "skyfall" ones like Hurricane. - // If any other value is used, the client will _always_ use the radius provided in DYNAMICOBJECT_RADIUS, but - // precompensation is necessary (eg radius *= 2) for many spells. Anyway, blizz sends 0x0001 for all the spells - // I saw sniffed... - SetUInt32Value(DYNAMICOBJECT_BYTES, 0x00000001); - SetUInt32Value(DYNAMICOBJECT_SPELLID, spellId); - SetFloatValue(DYNAMICOBJECT_RADIUS, radius); - SetUInt32Value(DYNAMICOBJECT_CASTTIME, getMSTime()); - - m_isWorldObject = active; - return true; -} - -Unit* DynamicObject::GetCaster() const -{ - // can be not found in some cases - return ObjectAccessor::GetUnit(*this, GetCasterGUID()); -} - -void DynamicObject::Update(uint32 p_time) -{ - // caster can be not in world at time dynamic object update, but dynamic object not yet deleted in Unit destructor - Unit* caster = GetCaster(); - if (!caster) - { - Delete(); - return; - } - - bool expired = false; - - if (m_aura) - { - if (!m_aura->IsRemoved()) - m_aura->UpdateOwner(p_time, this); - - // m_aura may be set to null in Unit::RemoveGameObject call - if (m_aura && (m_aura->IsRemoved() || m_aura->IsExpired())) - expired = true; - } - else - { - if (GetDuration() > int32(p_time)) - m_duration -= p_time; - else - expired = true; - } - - if (expired) - { - caster->RemoveDynObjectWithGUID(GetGUID()); - Delete(); - } -} - -void DynamicObject::Delete() -{ - if (m_aura) - { - // dynObj may be removed in Aura::Remove - we cannot delete there - // so recheck aura here - if (!m_aura->IsRemoved()) - m_aura->_Remove(AURA_REMOVE_BY_DEFAULT); - delete m_aura; - m_aura = NULL; - } - SendObjectDeSpawnAnim(GetGUID()); - RemoveFromWorld(); - AddObjectToRemoveList(); -} - -int32 DynamicObject::GetDuration() const -{ - if (!m_aura) - return m_duration; - else - return m_aura->GetDuration(); -} - -void DynamicObject::SetDuration(int32 newDuration) -{ - if (!m_aura) - m_duration = newDuration; - else - m_aura->SetDuration(newDuration); -} - -void DynamicObject::Delay(int32 delaytime) -{ - SetDuration(GetDuration() - delaytime); -} - -bool DynamicObject::isVisibleForInState(Player const* u, bool inVisibleList) const -{ - return IsInWorld() && u->IsInWorld() - && (IsWithinDistInMap(u->m_seer,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false)); -} diff --git a/src/server/game/Entities/Object/DynamicObject.h b/src/server/game/Entities/Object/DynamicObject.h deleted file mode 100644 index 9a70407fd2d..00000000000 --- a/src/server/game/Entities/Object/DynamicObject.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITYCORE_DYNAMICOBJECT_H -#define TRINITYCORE_DYNAMICOBJECT_H - -#include "Object.h" - -class Unit; -class Aura; -struct SpellEntry; - -class DynamicObject : public WorldObject, public GridObject -{ - public: - explicit DynamicObject(); - - void AddToWorld(); - void RemoveFromWorld(); - - bool Create(uint32 guidlow, Unit *caster, uint32 spellId, const Position &pos, float radius, bool active); - void Update(uint32 p_time); - void Delete(); - void SetDuration(int32 newDuration); - int32 GetDuration() const; - void SetAura(Aura * aura) {assert (!m_aura && aura); m_aura = aura;} - void Delay(int32 delaytime); - uint32 GetSpellId() const { return GetUInt32Value(DYNAMICOBJECT_SPELLID); } - uint64 GetCasterGUID() const { return GetUInt64Value(DYNAMICOBJECT_CASTER); } - float GetRadius() const { return GetFloatValue(DYNAMICOBJECT_RADIUS); } - Unit* GetCaster() const; - bool isVisibleForInState(Player const* u, bool inVisibleList) const; - - void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); } - void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); } - void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); } - void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); } - void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); } - - protected: - int32 m_duration; // for non-aura dynobjects - Aura * m_aura; -}; -#endif diff --git a/src/server/game/Entities/Object/ObjectAccessor.cpp b/src/server/game/Entities/Object/ObjectAccessor.cpp deleted file mode 100644 index cf5bc728c6e..00000000000 --- a/src/server/game/Entities/Object/ObjectAccessor.cpp +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ObjectAccessor.h" -#include "ObjectMgr.h" -#include "Policies/SingletonImp.h" -#include "Player.h" -#include "Creature.h" -#include "GameObject.h" -#include "DynamicObject.h" -#include "Vehicle.h" -#include "WorldPacket.h" -#include "Item.h" -#include "Corpse.h" -#include "GridNotifiers.h" -#include "MapManager.h" -#include "Map.h" -#include "CellImpl.h" -#include "GridNotifiersImpl.h" -#include "Opcodes.h" -#include "ObjectDefines.h" -#include "MapInstanced.h" -#include "World.h" - -#include - -#define CLASS_LOCK Trinity::ClassLevelLockable -INSTANTIATE_SINGLETON_2(ObjectAccessor, CLASS_LOCK); -INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ACE_Thread_Mutex); - -ObjectAccessor::ObjectAccessor() -{ -} - -ObjectAccessor::~ObjectAccessor() -{ - for (Player2CorpsesMapType::const_iterator itr = i_player2corpse.begin(); itr != i_player2corpse.end(); ++itr) - { - itr->second->RemoveFromWorld(); - delete itr->second; - } -} - -Creature* ObjectAccessor::GetCreatureOrPetOrVehicle(WorldObject const& u, uint64 guid) -{ - if (IS_PLAYER_GUID(guid)) - return NULL; - - if (IS_PET_GUID(guid)) - return GetPet(guid); - - return u.IsInWorld() ? u.GetMap()->GetCreature(guid) : NULL; -} - -Corpse* ObjectAccessor::GetCorpse(WorldObject const& u, uint64 guid) -{ - Corpse* ret = GetObjectInWorld(guid, (Corpse*)NULL); - - if (!ret) - return NULL; - - if (ret->GetMapId() != u.GetMapId()) - return NULL; - - if (ret->GetInstanceId() != u.GetInstanceId()) - return NULL; - - return ret; -} - -WorldObject* ObjectAccessor::GetWorldObject(WorldObject const& p, uint64 guid) -{ - switch (GUID_HIPART(guid)) - { - case HIGHGUID_PLAYER: return FindPlayer(guid); - case HIGHGUID_GAMEOBJECT: return p.GetMap()->GetGameObject(guid); - case HIGHGUID_VEHICLE: - case HIGHGUID_UNIT: return p.GetMap()->GetCreature(guid); - case HIGHGUID_PET: return GetPet(guid); - case HIGHGUID_DYNAMICOBJECT: return p.GetMap()->GetDynamicObject(guid); - case HIGHGUID_TRANSPORT: return NULL; - case HIGHGUID_CORPSE: return GetCorpse(p,guid); - case HIGHGUID_MO_TRANSPORT: return NULL; - default: return NULL; - } -} - -Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const& p, uint64 guid, uint32 typemask) -{ - switch (GUID_HIPART(guid)) - { - case HIGHGUID_ITEM: - if (typemask & TYPEMASK_ITEM && p.GetTypeId() == TYPEID_PLAYER) - return ((Player const&)p).GetItemByGuid(guid); - break; - case HIGHGUID_PLAYER: - if (typemask & TYPEMASK_PLAYER) - return FindPlayer(guid); - break; - case HIGHGUID_GAMEOBJECT: - if (typemask & TYPEMASK_GAMEOBJECT) - return p.GetMap()->GetGameObject(guid); - break; - case HIGHGUID_UNIT: - case HIGHGUID_VEHICLE: - if (typemask & TYPEMASK_UNIT) - return p.GetMap()->GetCreature(guid); - break; - case HIGHGUID_PET: - if (typemask & TYPEMASK_UNIT) - return GetPet(guid); - break; - case HIGHGUID_DYNAMICOBJECT: - if (typemask & TYPEMASK_DYNAMICOBJECT) - return p.GetMap()->GetDynamicObject(guid); - break; - case HIGHGUID_TRANSPORT: - case HIGHGUID_CORPSE: - case HIGHGUID_MO_TRANSPORT: - break; - } - - return NULL; -} - -Player* ObjectAccessor::FindPlayer(uint64 guid) -{ - Player* plr = GetObjectInWorld(guid, (Player*)NULL); - if (!plr || !plr->IsInWorld()) - return NULL; - - return plr; -} - -Player* ObjectAccessor::FindPlayerByName(const char* name) -{ - Guard guard(*HashMapHolder::GetLock()); - HashMapHolder::MapType& m = HashMapHolder::GetContainer(); - for (HashMapHolder::MapType::iterator iter = m.begin(); iter != m.end(); ++iter) - if (iter->second->IsInWorld() && strcmp(name, iter->second->GetName()) == 0) - return iter->second; - - return NULL; -} - -void ObjectAccessor::SaveAllPlayers() -{ - Guard guard(*HashMapHolder::GetLock()); - HashMapHolder::MapType& m = HashMapHolder::GetContainer(); - for (HashMapHolder::MapType::iterator itr = m.begin(); itr != m.end(); ++itr) - itr->second->SaveToDB(); -} - -Pet* ObjectAccessor::GetPet(uint64 guid) -{ - return GetObjectInWorld(guid, (Pet*)NULL); -} - -Corpse* ObjectAccessor::GetCorpseForPlayerGUID(uint64 guid) -{ - Guard guard(i_corpseGuard); - - Player2CorpsesMapType::iterator iter = i_player2corpse.find(guid); - if (iter == i_player2corpse.end()) - return NULL; - - assert(iter->second->GetType() != CORPSE_BONES); - - return iter->second; -} - -void ObjectAccessor::RemoveCorpse(Corpse* corpse) -{ - assert(corpse && corpse->GetType() != CORPSE_BONES); - - if (corpse->FindMap()) - corpse->FindMap()->Remove(corpse, false); - else - corpse->RemoveFromWorld(); - - // Critical section - { - Guard guard(i_corpseGuard); - - Player2CorpsesMapType::iterator iter = i_player2corpse.find(corpse->GetOwnerGUID()); - if (iter == i_player2corpse.end()) // TODO: Fix this - return; - - // build mapid*cellid -> guid_set map - CellPair cell_pair = Trinity::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY()); - uint32 cell_id = (cell_pair.y_coord * TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; - - objmgr.DeleteCorpseCellData(corpse->GetMapId(), cell_id, corpse->GetOwnerGUID()); - - i_player2corpse.erase(iter); - } -} - -void ObjectAccessor::AddCorpse(Corpse* corpse) -{ - assert(corpse && corpse->GetType() != CORPSE_BONES); - - // Critical section - { - Guard guard(i_corpseGuard); - - assert(i_player2corpse.find(corpse->GetOwnerGUID()) == i_player2corpse.end()); - i_player2corpse[corpse->GetOwnerGUID()] = corpse; - - // build mapid*cellid -> guid_set map - CellPair cell_pair = Trinity::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY()); - uint32 cell_id = (cell_pair.y_coord * TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; - - objmgr.AddCorpseCellData(corpse->GetMapId(), cell_id, corpse->GetOwnerGUID(), corpse->GetInstanceId()); - } -} - -void ObjectAccessor::AddCorpsesToGrid(GridPair const& gridpair, GridType& grid, Map* map) -{ - Guard guard(i_corpseGuard); - - for (Player2CorpsesMapType::iterator iter = i_player2corpse.begin(); iter != i_player2corpse.end(); ++iter) - { - if (iter->second->GetGrid() == gridpair) - { - // verify, if the corpse in our instance (add only corpses which are) - if (map->Instanceable()) - { - if (iter->second->GetInstanceId() == map->GetInstanceId()) - grid.AddWorldObject(iter->second); - } - else - grid.AddWorldObject(iter->second); - } - } -} - -Corpse* ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool /*insignia*/) -{ - Corpse* corpse = GetCorpseForPlayerGUID(player_guid); - if (!corpse) - { - //in fact this function is called from several places - //even when player doesn't have a corpse, not an error - // TODO: really, now... - //sLog.outError("Try remove corpse that not in map for GUID %ul", player_guid); - return NULL; - } - - DEBUG_LOG("Deleting Corpse and spawned bones."); - - //Map* map = corpse->FindMap(); - - // remove corpse from player_guid -> corpse map - RemoveCorpse(corpse); - - // done in removecorpse - // remove resurrectable corpse from grid object registry (loaded state checked into call) - // do not load the map if it's not loaded - //Map *map = MapManager::Instance().FindMap(corpse->GetMapId(), corpse->GetInstanceId()); - //if (map) - // map->Remove(corpse, false); - - // remove corpse from DB - corpse->DeleteFromDB(); - - // we don't want bones to save some cpu.. :) - delete corpse; - return NULL; - - /* - Corpse* bones = NULL; - // create the bones only if the map and the grid is loaded at the corpse's location - // ignore bones creating option in case insignia - if (map && (insignia || - (map->IsBattleGroundOrArena() ? sWorld.getConfig(CONFIG_DEATH_BONES_BG_OR_ARENA) : sWorld.getConfig(CONFIG_DEATH_BONES_WORLD))) && - !map->IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY())) - { - // Create bones, don't change Corpse - bones = new Corpse; - bones->Create(corpse->GetGUIDLow(), map); - - for (int i = 3; i < CORPSE_END; ++i) // don't overwrite guid and object type - bones->SetUInt32Value(i, corpse->GetUInt32Value(i)); - - bones->SetGrid(corpse->GetGrid()); - // bones->m_time = m_time; // don't overwrite time - // bones->m_inWorld = m_inWorld; // don't overwrite in-world state - // bones->m_type = m_type; // don't overwrite type - bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation()); - bones->SetPhaseMask(corpse->GetPhaseMask(), false); - - bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES); - bones->SetUInt64Value(CORPSE_FIELD_OWNER, 0); - - for (int i = 0; i < EQUIPMENT_SLOT_END; ++i) - { - if (corpse->GetUInt32Value(CORPSE_FIELD_ITEM + i)) - bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0); - } - - // add bones in grid store if grid loaded where corpse placed - map->Add(bones); - } - - // all references to the corpse should be removed at this point - delete corpse; - - return bones; - */ -} - -void ObjectAccessor::Update(uint32 /*diff*/) -{ - UpdateDataMapType update_players; - - // Critical section - { - Guard guard(i_updateGuard); - - while (!i_objects.empty()) - { - Object* obj = *i_objects.begin(); - assert(obj && obj->IsInWorld()); - i_objects.erase(i_objects.begin()); - obj->BuildUpdate(update_players); - } - } - - WorldPacket packet; // here we allocate a std::vector with a size of 0x10000 - for (UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter) - { - iter->second.BuildPacket(&packet); - iter->first->GetSession()->SendPacket(&packet); - packet.clear(); // clean the string - } -} - -/// Define the static members of HashMapHolder - -template UNORDERED_MAP< uint64, T* > HashMapHolder::m_objectMap; -template ACE_Thread_Mutex HashMapHolder::i_lock; - -/// Global definitions for the hashmap storage - -template class HashMapHolder; -template class HashMapHolder; -template class HashMapHolder; -template class HashMapHolder; -template class HashMapHolder; -template class HashMapHolder; - -template Player* ObjectAccessor::GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, Player* /*fake*/); -template Pet* ObjectAccessor::GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, Pet* /*fake*/); -template Creature* ObjectAccessor::GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, Creature* /*fake*/); -template Corpse* ObjectAccessor::GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, Corpse* /*fake*/); -template GameObject* ObjectAccessor::GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, GameObject* /*fake*/); -template DynamicObject* ObjectAccessor::GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, DynamicObject* /*fake*/); diff --git a/src/server/game/Entities/Object/ObjectAccessor.h b/src/server/game/Entities/Object/ObjectAccessor.h deleted file mode 100644 index 8e64eb48fa0..00000000000 --- a/src/server/game/Entities/Object/ObjectAccessor.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_OBJECTACCESSOR_H -#define TRINITY_OBJECTACCESSOR_H - -#include "Platform/Define.h" -#include "Policies/Singleton.h" -#include -#include "Utilities/UnorderedMap.h" -#include "Policies/ThreadingModel.h" - -#include "UpdateData.h" - -#include "GridDefines.h" -#include "Object.h" -#include "Player.h" - -#include - -class Creature; -class Corpse; -class Unit; -class GameObject; -class DynamicObject; -class WorldObject; -class Map; - -template -class HashMapHolder -{ - public: - - typedef UNORDERED_MAP MapType; - typedef ACE_Thread_Mutex LockType; - typedef Trinity::GeneralLock Guard; - - static void Insert(T* o) - { - Guard guard(i_lock); - m_objectMap[o->GetGUID()] = o; - } - - static void Remove(T* o) - { - Guard guard(i_lock); - m_objectMap.erase(o->GetGUID()); - } - - static T* Find(uint64 guid) - { - Guard guard(i_lock); - typename MapType::iterator itr = m_objectMap.find(guid); - return (itr != m_objectMap.end()) ? itr->second : NULL; - } - - static MapType& GetContainer() { return m_objectMap; } - - static LockType* GetLock() { return &i_lock; } - - private: - - //Non instanceable only static - HashMapHolder() {} - - static LockType i_lock; - static MapType m_objectMap; -}; - -class ObjectAccessor : public Trinity::Singleton > -{ - friend class Trinity::OperatorNew; - ObjectAccessor(); - ~ObjectAccessor(); - ObjectAccessor(const ObjectAccessor&); - ObjectAccessor& operator=(const ObjectAccessor&); - - public: - - typedef UNORDERED_MAP Player2CorpsesMapType; - typedef UNORDERED_MAP::value_type UpdateDataValueType; - - template static T* GetObjectInWorld(uint64 guid, T* /*fake*/) - { - return HashMapHolder::Find(guid); - } - - static Unit* GetObjectInWorld(uint64 guid, Unit* /*fake*/) - { - if (!guid) - return NULL; - - if (IS_PLAYER_GUID(guid)) - { - Unit* u = (Unit*)HashMapHolder::Find(guid); - if (!u || !u->IsInWorld()) - return NULL; - - return u; - } - - if (IS_PET_GUID(guid)) - return (Unit*)HashMapHolder::Find(guid); - - return (Unit*)HashMapHolder::Find(guid); - } - - static Unit* GetUnitInOrOutOfWorld(uint64 guid, Unit* /*fake*/) - { - if (!guid) - return NULL; - - if (IS_PLAYER_GUID(guid)) - { - Unit* u = (Unit*)HashMapHolder::Find(guid); - if (!u) - return NULL; - - return u; - } - - // Other object types than player are unloaded while out of world - return GetObjectInWorld(guid, (Unit*)NULL); - } - - template static T* GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, T* /*fake*/) - { - T* obj = HashMapHolder::Find(guid); - if (!obj || obj->GetMapId() != mapid) - return NULL; - - CellPair p = Trinity::ComputeCellPair(x, y); - if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - { - sLog.outError("ObjectAccessor::GetObjectInWorld: invalid coordinates supplied X:%f Y:%f grid cell [%u:%u]", x, y, p.x_coord, p.y_coord); - return NULL; - } - - CellPair q = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); - if (q.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || q.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - { - sLog.outError("ObjectAccessor::GetObjecInWorld: object (GUID: %u TypeId: %u) has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUIDLow(), obj->GetTypeId(), obj->GetPositionX(), obj->GetPositionY(), q.x_coord, q.y_coord); - return NULL; - } - - int32 dx = int32(p.x_coord) - int32(q.x_coord); - int32 dy = int32(p.y_coord) - int32(q.y_coord); - - if (dx > -2 && dx < 2 && dy > -2 && dy < 2) - return obj; - else - return NULL; - } - - static WorldObject* GetWorldObject(WorldObject const&, uint64); - static Object* GetObjectByTypeMask(WorldObject const&, uint64, uint32 typemask); - static Creature* GetCreatureOrPetOrVehicle(WorldObject const&, uint64); - static Unit* GetUnit(WorldObject const&, uint64 guid) { return GetObjectInWorld(guid, (Unit*)NULL); } - static Unit* GetUnitInOrOutOfWorld(WorldObject const&, uint64 guid) { return GetUnitInOrOutOfWorld(guid, (Unit*)NULL); } - static Pet* GetPet(Unit const&, uint64 guid) { return GetPet(guid); } - static Player* GetPlayer(Unit const&, uint64 guid) { return FindPlayer(guid); } - static Corpse* GetCorpse(WorldObject const& u, uint64 guid); - static Pet* GetPet(uint64 guid); - static Player* FindPlayer(uint64); - - Player* FindPlayerByName(const char* name) ; - - // when using this, you must use the hashmapholder's lock - HashMapHolder::MapType& GetPlayers() - { - return HashMapHolder::GetContainer(); - } - - // when using this, you must use the hashmapholder's lock - HashMapHolder::MapType& GetCreatures() - { - return HashMapHolder::GetContainer(); - } - - // when using this, you must use the hashmapholder's lock - HashMapHolder::MapType& GetGameObjects() - { - return HashMapHolder::GetContainer(); - } - - template void AddObject(T* object) - { - HashMapHolder::Insert(object); - } - - template void RemoveObject(T* object) - { - HashMapHolder::Remove(object); - } - - void RemoveObject(Player* pl) - { - HashMapHolder::Remove(pl); - RemoveUpdateObject((Object*)pl); - } - - void SaveAllPlayers(); - - void AddUpdateObject(Object* obj) - { - Guard guard(i_updateGuard); - i_objects.insert(obj); - } - - void RemoveUpdateObject(Object* obj) - { - Guard guard(i_updateGuard); - i_objects.erase(obj); - } - - void Update(uint32 diff); - - Corpse* GetCorpseForPlayerGUID(uint64 guid); - void RemoveCorpse(Corpse* corpse); - void AddCorpse(Corpse* corpse); - void AddCorpsesToGrid(GridPair const& gridpair, GridType& grid, Map* map); - Corpse* ConvertCorpseForPlayer(uint64 player_guid, bool insignia = false); - - typedef ACE_Thread_Mutex LockType; - typedef Trinity::GeneralLock Guard; - - private: - - Player2CorpsesMapType i_player2corpse; - - static void _buildChangeObjectForPlayer(WorldObject*, UpdateDataMapType&); - static void _buildPacket(Player*, Object*, UpdateDataMapType&); - void _update(); - - std::set i_objects; - - LockType i_updateGuard; - LockType i_corpseGuard; -}; -#endif diff --git a/src/server/game/Entities/Object/ObjectMgr.cpp b/src/server/game/Entities/Object/ObjectMgr.cpp deleted file mode 100644 index ce86c2a4e77..00000000000 --- a/src/server/game/Entities/Object/ObjectMgr.cpp +++ /dev/null @@ -1,8724 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "Database/SQLStorage.h" -#include "Database/SQLStorageImpl.h" -#include "Policies/SingletonImp.h" - -#include "Log.h" -#include "MapManager.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "UpdateMask.h" -#include "World.h" -#include "Group.h" -#include "Guild.h" -#include "ArenaTeam.h" -#include "Transports.h" -#include "ProgressBar.h" -#include "Language.h" -#include "GameEventMgr.h" -#include "Spell.h" -#include "Chat.h" -#include "AccountMgr.h" -#include "InstanceSaveMgr.h" -#include "SpellAuras.h" -#include "Util.h" -#include "WaypointManager.h" -#include "GossipDef.h" -#include "Vehicle.h" -#include "AchievementMgr.h" - -INSTANTIATE_SINGLETON_1(ObjectMgr); - -ScriptMapMap sQuestEndScripts; -ScriptMapMap sQuestStartScripts; -ScriptMapMap sSpellScripts; -ScriptMapMap sGameObjectScripts; -ScriptMapMap sEventScripts; -ScriptMapMap sGossipScripts; -ScriptMapMap sWaypointScripts; - -bool normalizePlayerName(std::string& name) -{ - if (name.empty()) - return false; - - wchar_t wstr_buf[MAX_INTERNAL_PLAYER_NAME+1]; - size_t wstr_len = MAX_INTERNAL_PLAYER_NAME; - - if (!Utf8toWStr(name,&wstr_buf[0],wstr_len)) - return false; - - wstr_buf[0] = wcharToUpper(wstr_buf[0]); - for (size_t i = 1; i < wstr_len; ++i) - wstr_buf[i] = wcharToLower(wstr_buf[i]); - - if (!WStrToUtf8(wstr_buf,wstr_len,name)) - return false; - - return true; -} - -LanguageDesc lang_description[LANGUAGES_COUNT] = -{ - { LANG_ADDON, 0, 0 }, - { LANG_UNIVERSAL, 0, 0 }, - { LANG_ORCISH, 669, SKILL_LANG_ORCISH }, - { LANG_DARNASSIAN, 671, SKILL_LANG_DARNASSIAN }, - { LANG_TAURAHE, 670, SKILL_LANG_TAURAHE }, - { LANG_DWARVISH, 672, SKILL_LANG_DWARVEN }, - { LANG_COMMON, 668, SKILL_LANG_COMMON }, - { LANG_DEMONIC, 815, SKILL_LANG_DEMON_TONGUE }, - { LANG_TITAN, 816, SKILL_LANG_TITAN }, - { LANG_THALASSIAN, 813, SKILL_LANG_THALASSIAN }, - { LANG_DRACONIC, 814, SKILL_LANG_DRACONIC }, - { LANG_KALIMAG, 817, SKILL_LANG_OLD_TONGUE }, - { LANG_GNOMISH, 7340, SKILL_LANG_GNOMISH }, - { LANG_TROLL, 7341, SKILL_LANG_TROLL }, - { LANG_GUTTERSPEAK, 17737, SKILL_LANG_GUTTERSPEAK }, - { LANG_DRAENEI, 29932, SKILL_LANG_DRAENEI }, - { LANG_ZOMBIE, 0, 0 }, - { LANG_GNOMISH_BINARY, 0, 0 }, - { LANG_GOBLIN_BINARY, 0, 0 } -}; - -LanguageDesc const* GetLanguageDescByID(uint32 lang) -{ - for (uint8 i = 0; i < LANGUAGES_COUNT; ++i) - { - if (uint32(lang_description[i].lang_id) == lang) - return &lang_description[i]; - } - - return NULL; -} - -bool SpellClickInfo::IsFitToRequirements(Player const* player, Creature const * clickNpc) const -{ - if (questStart) - { - // not in expected required quest state - if (!player || ((!questStartCanActive || !player->IsActiveQuest(questStart)) && !player->GetQuestRewardStatus(questStart))) - return false; - } - - if (questEnd) - { - // not in expected forbidden quest state - if (!player || player->GetQuestRewardStatus(questEnd)) - return false; - } - - if (auraRequired) - if (!player->HasAura(auraRequired)) - return false; - - if (auraForbidden) - if (player->HasAura(auraForbidden)) - return false; - - Unit const * summoner = NULL; - // Check summoners for party - if (clickNpc->isSummon()) - summoner = clickNpc->ToTempSummon()->GetSummoner(); - if (!summoner) - summoner = clickNpc; - - switch (userType) - { - case SPELL_CLICK_USER_FRIEND: - if (!player->IsFriendlyTo(summoner)) - return false; - break; - case SPELL_CLICK_USER_RAID: - if (!player->IsInRaidWith(summoner)) - return false; - break; - case SPELL_CLICK_USER_PARTY: - if (!player->IsInPartyWith(summoner)) - return false; - break; - } - - return true; -} - -ObjectMgr::ObjectMgr() -{ - m_hiCharGuid = 1; - m_hiCreatureGuid = 1; - m_hiPetGuid = 1; - m_hiVehicleGuid = 1; - m_hiItemGuid = 1; - m_hiGoGuid = 1; - m_hiDoGuid = 1; - m_hiCorpseGuid = 1; - m_hiPetNumber = 1; - m_hiGroupGuid = 1; - m_ItemTextId = 1; - m_mailid = 1; - m_equipmentSetGuid = 1; - m_guildId = 1; - m_arenaTeamId = 1; - m_auctionid = 1; -} - -ObjectMgr::~ObjectMgr() -{ - for (QuestMap::iterator i = mQuestTemplates.begin(); i != mQuestTemplates.end(); ++i) - delete i->second; - - for (PetLevelInfoMap::iterator i = petInfo.begin(); i != petInfo.end(); ++i) - delete[] i->second; - - // free only if loaded - for (int class_ = 0; class_ < MAX_CLASSES; ++class_) - delete[] playerClassInfo[class_].levelInfo; - - for (int race = 0; race < MAX_RACES; ++race) - for (int class_ = 0; class_ < MAX_CLASSES; ++class_) - delete[] playerInfo[race][class_].levelInfo; - - // free group and guild objects - for (GroupSet::iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr) - delete (*itr); - - for (GuildMap::iterator itr = mGuildMap.begin(); itr != mGuildMap.end(); ++itr) - delete itr->second; - - for (ArenaTeamMap::iterator itr = mArenaTeamMap.begin(); itr != mArenaTeamMap.end(); ++itr) - delete itr->second; - - for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr) - itr->second.Clear(); - - for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr) - itr->second.Clear(); -} - -Group * ObjectMgr::GetGroupByGUID(const uint64 &guid) const -{ - for (GroupSet::const_iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr) - if ((*itr)->GetGUID() == guid) - return *itr; - - return NULL; -} - -Guild * ObjectMgr::GetGuildById(uint32 GuildId) const -{ - GuildMap::const_iterator itr = mGuildMap.find(GuildId); - if (itr != mGuildMap.end()) - return itr->second; - - return NULL; -} - -Guild * ObjectMgr::GetGuildByName(const std::string& guildname) const -{ - std::string search = guildname; - std::transform(search.begin(), search.end(), search.begin(), ::toupper); - for (GuildMap::const_iterator itr = mGuildMap.begin(); itr != mGuildMap.end(); ++itr) - { - std::string gname = itr->second->GetName(); - std::transform(gname.begin(), gname.end(), gname.begin(), ::toupper); - if (search == gname) - return itr->second; - } - return NULL; -} - -std::string ObjectMgr::GetGuildNameById(uint32 GuildId) const -{ - GuildMap::const_iterator itr = mGuildMap.find(GuildId); - if (itr != mGuildMap.end()) - return itr->second->GetName(); - - return ""; -} - -Guild* ObjectMgr::GetGuildByLeader(const uint64 &guid) const -{ - for (GuildMap::const_iterator itr = mGuildMap.begin(); itr != mGuildMap.end(); ++itr) - if (itr->second->GetLeader() == guid) - return itr->second; - - return NULL; -} - -void ObjectMgr::AddGuild(Guild* guild) -{ - mGuildMap[guild->GetId()] = guild; -} - -void ObjectMgr::RemoveGuild(uint32 Id) -{ - mGuildMap.erase(Id); -} - -ArenaTeam* ObjectMgr::GetArenaTeamById(uint32 arenateamid) const -{ - ArenaTeamMap::const_iterator itr = mArenaTeamMap.find(arenateamid); - if (itr != mArenaTeamMap.end()) - return itr->second; - - return NULL; -} - -ArenaTeam* ObjectMgr::GetArenaTeamByName(const std::string& arenateamname) const -{ - std::string search = arenateamname; - std::transform(search.begin(), search.end(), search.begin(), ::toupper); - for (ArenaTeamMap::const_iterator itr = mArenaTeamMap.begin(); itr != mArenaTeamMap.end(); ++itr) - { - std::string teamname = itr->second->GetName(); - std::transform(teamname.begin(), teamname.end(), teamname.begin(), ::toupper); - if (search == teamname) - return itr->second; - } - return NULL; -} - -ArenaTeam* ObjectMgr::GetArenaTeamByCaptain(uint64 const& guid) const -{ - for (ArenaTeamMap::const_iterator itr = mArenaTeamMap.begin(); itr != mArenaTeamMap.end(); ++itr) - if (itr->second->GetCaptain() == guid) - return itr->second; - - return NULL; -} - -void ObjectMgr::AddArenaTeam(ArenaTeam* arenaTeam) -{ - mArenaTeamMap[arenaTeam->GetId()] = arenaTeam; -} - -void ObjectMgr::RemoveArenaTeam(uint32 Id) -{ - mArenaTeamMap.erase(Id); -} - -CreatureInfo const* ObjectMgr::GetCreatureTemplate(uint32 id) -{ - return sCreatureStorage.LookupEntry(id); -} - -void ObjectMgr::LoadCreatureLocales() -{ - mCreatureLocaleMap.clear(); // need for reload case - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry,name_loc1,subname_loc1,name_loc2,subname_loc2,name_loc3,subname_loc3,name_loc4,subname_loc4,name_loc5,subname_loc5,name_loc6,subname_loc6,name_loc7,subname_loc7,name_loc8,subname_loc8 FROM locales_creature"); - - if (!result) - return; - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 entry = fields[0].GetUInt32(); - - CreatureLocale& data = mCreatureLocaleMap[entry]; - - for (uint8 i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[1+2*(i-1)].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.Name.size() <= idx) - data.Name.resize(idx+1); - - data.Name[idx] = str; - } - } - str = fields[1+2*(i-1)+1].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.SubName.size() <= idx) - data.SubName.resize(idx+1); - - data.SubName[idx] = str; - } - } - } - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %lu creature locale strings", (unsigned long)mCreatureLocaleMap.size()); -} - -void ObjectMgr::LoadGossipMenuItemsLocales() -{ - mGossipMenuItemsLocaleMap.clear(); // need for reload case - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT menu_id,id," - "option_text_loc1,box_text_loc1,option_text_loc2,box_text_loc2," - "option_text_loc3,box_text_loc3,option_text_loc4,box_text_loc4," - "option_text_loc5,box_text_loc5,option_text_loc6,box_text_loc6," - "option_text_loc7,box_text_loc7,option_text_loc8,box_text_loc8 " - "FROM locales_gossip_menu_option"); - - if (!result) - return; - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint16 menuId = fields[0].GetUInt16(); - uint16 id = fields[1].GetUInt16(); - - GossipMenuItemsLocale& data = mGossipMenuItemsLocaleMap[MAKE_PAIR32(menuId,id)]; - - for (uint8 i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[2+2*(i-1)].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.OptionText.size() <= idx) - data.OptionText.resize(idx+1); - - data.OptionText[idx] = str; - } - } - str = fields[2+2*(i-1)+1].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.BoxText.size() <= idx) - data.BoxText.resize(idx+1); - - data.BoxText[idx] = str; - } - } - } - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %lu gossip_menu_option locale strings", (unsigned long)mGossipMenuItemsLocaleMap.size()); -} - -void ObjectMgr::LoadPointOfInterestLocales() -{ - mPointOfInterestLocaleMap.clear(); // need for reload case - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry,icon_name_loc1,icon_name_loc2,icon_name_loc3,icon_name_loc4,icon_name_loc5,icon_name_loc6,icon_name_loc7,icon_name_loc8 FROM locales_points_of_interest"); - - if (!result) - return; - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 entry = fields[0].GetUInt32(); - - PointOfInterestLocale& data = mPointOfInterestLocaleMap[entry]; - - for (uint8 i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[i].GetCppString(); - if (str.empty()) - continue; - - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.IconName.size() <= idx) - data.IconName.resize(idx+1); - - data.IconName[idx] = str; - } - } - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %lu points_of_interest locale strings", (unsigned long)mPointOfInterestLocaleMap.size()); -} - -struct SQLCreatureLoader : public SQLStorageLoaderBase -{ - template - void convert_from_str(uint32 /*field_pos*/, char *src, D &dst) - { - dst = D(objmgr.GetScriptId(src)); - } -}; - -void ObjectMgr::LoadCreatureTemplates() -{ - SQLCreatureLoader loader; - loader.Load(sCreatureStorage); - - sLog.outString(">> Loaded %u creature definitions", sCreatureStorage.RecordCount); - sLog.outString(); - - // check data correctness - for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i) - { - CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i); - CheckCreatureTemplate(cInfo); - } -} - -void ObjectMgr::CheckCreatureTemplate(CreatureInfo const* cInfo) -{ - if (!cInfo) - return; - - bool ok = true; // bool to allow continue outside this loop - for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && ok; ++diff) - { - if (!cInfo->DifficultyEntry[diff]) - continue; - ok = false; // will be set to true at the end of this loop again - - CreatureInfo const* difficultyInfo = GetCreatureTemplate(cInfo->DifficultyEntry[diff]); - if (!difficultyInfo) - { - sLog.outErrorDb("Creature (Entry: %u) have `difficulty_entry_%u`=%u but creature entry %u not exist.", - cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff], cInfo->DifficultyEntry[diff]); - continue; - } - - if (difficultyEntries[diff].find(cInfo->Entry) != difficultyEntries[diff].end()) - { - sLog.outErrorDb("Creature (Entry: %u) listed as difficulty %u but have value in `difficulty_entry_1`.", cInfo->Entry, diff + 1); - continue; - } - - bool ok2 = true; - for (uint32 diff2 = 0; diff2 < MAX_DIFFICULTY - 1 && ok2; ++diff2) - { - ok2 = false; - if (difficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != difficultyEntries[diff2].end()) - { - sLog.outErrorDb("Creature (Entry: %u) already listed as difficulty %u for another entry.", cInfo->DifficultyEntry[diff], diff2 + 1); - continue; - } - - if (hasDifficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != hasDifficultyEntries[diff2].end()) - { - sLog.outErrorDb("Creature (Entry: %u) have `difficulty_entry_%u`=%u but creature entry %u have difficulty %u entry also.", - cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff], cInfo->DifficultyEntry[diff], diff2 + 1); - continue; - } - ok2 = true; - } - if (!ok2) - continue; - - if (cInfo->unit_class != difficultyInfo->unit_class) - { - sLog.outErrorDb("Creature (Entry: %u, class %u) has different `unit_class` in difficulty %u mode (Entry: %u, class %u).", - cInfo->Entry, cInfo->unit_class, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->unit_class); - continue; - } - - if (cInfo->npcflag != difficultyInfo->npcflag) - { - sLog.outErrorDb("Creature (Entry: %u) has different `npcflag` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]); - continue; - } - - if (cInfo->trainer_class != difficultyInfo->trainer_class) - { - sLog.outErrorDb("Creature (Entry: %u) has different `trainer_class` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]); - continue; - } - - if (cInfo->trainer_race != difficultyInfo->trainer_race) - { - sLog.outErrorDb("Creature (Entry: %u) has different `trainer_race` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]); - continue; - } - - if (cInfo->trainer_type != difficultyInfo->trainer_type) - { - sLog.outErrorDb("Creature (Entry: %u) has different `trainer_type` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]); - continue; - } - - if (cInfo->trainer_spell != difficultyInfo->trainer_spell) - { - sLog.outErrorDb("Creature (Entry: %u) has different `trainer_spell` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]); - continue; - } - - if (difficultyInfo->AIName && *difficultyInfo->AIName) - { - sLog.outErrorDb("Difficulty %u mode creature (Entry: %u) has `AIName`, but in any case will used difficulty 0 mode creature (Entry: %u) AIName.", - diff, cInfo->DifficultyEntry[diff], cInfo->Entry); - continue; - } - - if (difficultyInfo->ScriptID) - { - sLog.outErrorDb("Difficulty %u mode creature (Entry: %u) has `ScriptName`, but in any case will used difficulty 0 mode creature (Entry: %u) ScriptName.", - diff, cInfo->DifficultyEntry[diff], cInfo->Entry); - continue; - } - - hasDifficultyEntries[diff].insert(cInfo->Entry); - difficultyEntries[diff].insert(cInfo->DifficultyEntry[diff]); - ok = true; - } - - FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_A); - if (!factionTemplate) - sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_A template (%u)", cInfo->Entry, cInfo->faction_A); - - factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_H); - if (!factionTemplate) - sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_H template (%u)", cInfo->Entry, cInfo->faction_H); - - // used later for scale - CreatureDisplayInfoEntry const* displayScaleEntry = NULL; - - if (cInfo->Modelid1) - { - CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid1); - if (!displayEntry) - { - sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid1 id (%u), can crash client", cInfo->Entry, cInfo->Modelid1); - const_cast(cInfo)->Modelid1 = 0; - } - else if (!displayScaleEntry) - displayScaleEntry = displayEntry; - - CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry(cInfo->Modelid1); - if (!minfo) - sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid1 (%u)", cInfo->Entry, cInfo->Modelid1); - } - - if (cInfo->Modelid2) - { - CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid2); - if (!displayEntry) - { - sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid2 id (%u), can crash client", cInfo->Entry, cInfo->Modelid2); - const_cast(cInfo)->Modelid2 = 0; - } - else if (!displayScaleEntry) - displayScaleEntry = displayEntry; - - CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry(cInfo->Modelid2); - if (!minfo) - sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid2 (%u)", cInfo->Entry, cInfo->Modelid2); - } - - if (cInfo->Modelid3) - { - CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid3); - if (!displayEntry) - { - sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid3 id (%u), can crash client", cInfo->Entry, cInfo->Modelid3); - const_cast(cInfo)->Modelid3 = 0; - } - else if (!displayScaleEntry) - displayScaleEntry = displayEntry; - - CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry(cInfo->Modelid3); - if (!minfo) - sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid3 (%u)", cInfo->Entry, cInfo->Modelid3); - } - - if (cInfo->Modelid4) - { - CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid4); - if (!displayEntry) - { - sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid4 id (%u), can crash client", cInfo->Entry, cInfo->Modelid4); - const_cast(cInfo)->Modelid4 = 0; - } - else if (!displayScaleEntry) - displayScaleEntry = displayEntry; - - CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry(cInfo->Modelid4); - if (!minfo) - sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid4 (%u)", cInfo->Entry, cInfo->Modelid4); - } - - if (!displayScaleEntry) - sLog.outErrorDb("Creature (Entry: %u) not has any existed display id in Modelid1/Modelid2/Modelid3/Modelid4", cInfo->Entry); - - for (int k = 0; k < MAX_KILL_CREDIT; ++k) - { - if (cInfo->KillCredit[k]) - { - if (!GetCreatureTemplate(cInfo->KillCredit[k])) - { - sLog.outErrorDb("Creature (Entry: %u) has not existed creature entry in `KillCredit%d` (%u)",cInfo->Entry,k+1,cInfo->KillCredit[k]); - const_cast(cInfo)->KillCredit[k] = 0; - } - } - } - - if (!cInfo->unit_class || ((1 << (cInfo->unit_class-1)) & CLASSMASK_ALL_CREATURES) == 0) - { - sLog.outErrorDb("Creature (Entry: %u) has invalid unit_class(%u) for creature_template. Set to 1 (UNIT_CLASS_WARRIOR).", cInfo->Entry, cInfo->unit_class); - const_cast(cInfo)->unit_class = UNIT_CLASS_WARRIOR; - } - - if (cInfo->dmgschool >= MAX_SPELL_SCHOOL) - { - sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`",cInfo->Entry,cInfo->dmgschool); - const_cast(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL; - } - - if (cInfo->baseattacktime == 0) - const_cast(cInfo)->baseattacktime = BASE_ATTACK_TIME; - - if (cInfo->rangeattacktime == 0) - const_cast(cInfo)->rangeattacktime = BASE_ATTACK_TIME; - - if (cInfo->npcflag & UNIT_NPC_FLAG_SPELLCLICK) - { - sLog.outErrorDb("Creature (Entry: %u) has dynamic flag UNIT_NPC_FLAG_SPELLCLICK (%u) set, it expect to be set by code base at `npc_spellclick_spells` content.",cInfo->Entry,UNIT_NPC_FLAG_SPELLCLICK); - const_cast(cInfo)->npcflag &= ~UNIT_NPC_FLAG_SPELLCLICK; - } - - if ((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE) - sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u",cInfo->Entry,cInfo->trainer_type); - - if (cInfo->type && !sCreatureTypeStore.LookupEntry(cInfo->type)) - { - sLog.outErrorDb("Creature (Entry: %u) has invalid creature type (%u) in `type`",cInfo->Entry,cInfo->type); - const_cast(cInfo)->type = CREATURE_TYPE_HUMANOID; - } - - // must exist or used hidden but used in data horse case - if (cInfo->family && !sCreatureFamilyStore.LookupEntry(cInfo->family) && cInfo->family != CREATURE_FAMILY_HORSE_CUSTOM) - { - sLog.outErrorDb("Creature (Entry: %u) has invalid creature family (%u) in `family`",cInfo->Entry,cInfo->family); - const_cast(cInfo)->family = 0; - } - - if (cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE) - { - sLog.outErrorDb("Creature (Entry: %u) has wrong value (%u) in `InhabitType`, creature will not correctly walk/swim/fly",cInfo->Entry,cInfo->InhabitType); - const_cast(cInfo)->InhabitType = INHABIT_ANYWHERE; - } - - if (cInfo->VehicleId) - { - VehicleEntry const* vehId = sVehicleStore.LookupEntry(cInfo->VehicleId); - if (!vehId) - sLog.outErrorDb("Creature (Entry: %u) has a non-existing VehicleId (%u). This *WILL* cause the client to freeze!", cInfo->Entry, cInfo->VehicleId); - } - - if (cInfo->PetSpellDataId) - { - CreatureSpellDataEntry const* spellDataId = sCreatureSpellDataStore.LookupEntry(cInfo->PetSpellDataId); - if (!spellDataId) - sLog.outErrorDb("Creature (Entry: %u) has non-existing PetSpellDataId (%u)", cInfo->Entry, cInfo->PetSpellDataId); - } - - for (uint8 j = 0; j < CREATURE_MAX_SPELLS; ++j) - { - if (cInfo->spells[j] && !sSpellStore.LookupEntry(cInfo->spells[j])) - { - sLog.outErrorDb("Creature (Entry: %u) has non-existing Spell%d (%u), set to 0", cInfo->Entry, j+1,cInfo->spells[j]); - const_cast(cInfo)->spells[j] = 0; - } - } - - if (cInfo->MovementType >= MAX_DB_MOTION_TYPE) - { - sLog.outErrorDb("Creature (Entry: %u) has wrong movement generator type (%u), ignore and set to IDLE.",cInfo->Entry,cInfo->MovementType); - const_cast(cInfo)->MovementType = IDLE_MOTION_TYPE; - } - - if (cInfo->equipmentId > 0) // 0 no equipment - { - if (!GetEquipmentInfo(cInfo->equipmentId)) - { - sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", cInfo->Entry, cInfo->equipmentId); - const_cast(cInfo)->equipmentId = 0; - } - } - - /// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc - if (cInfo->scale <= 0.0f) - { - if (displayScaleEntry) - const_cast(cInfo)->scale = displayScaleEntry->scale; - else - const_cast(cInfo)->scale = 1.0f; - } - - if (cInfo->expansion > (MAX_CREATURE_BASE_HP - 1)) - { - sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with expansion %u ignore and set to NULL.", cInfo->expansion); - const_cast(cInfo)->expansion = 0; - } - - const_cast(cInfo)->dmg_multiplier *= Creature::_GetDamageMod(cInfo->rank); -} - -void ObjectMgr::ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr) -{ - // Now add the auras, format "spellid effectindex spellid effectindex..." - char *p,*s; - std::map val; - s=p=(char*)reinterpret_cast(addon->auras); - if (p) - { - uint32 currSpellId = 0; - bool spell = true; - while (p[0] != 0) - { - ++p; - if (p[0] == ' ' || p[0] == 0) - { - if (spell) - currSpellId = atoi(s); - else - { - uint8 eff = atoi(s); - if (eff >=3) - { - sLog.outErrorDb("Creature (%s: %u) has wrong `auras` data in `%s`(too high aura effect: %d for spell: %d)",guidEntryStr,addon->guidOrEntry,table,eff,currSpellId); - } - val[currSpellId] |= 1<(addon->auras); - - // wrong list - if (!spell) - { - addon->auras = NULL; - sLog.outErrorDb("Creature (%s: %u) has wrong `auras` data in `%s`.",guidEntryStr,addon->guidOrEntry,table); - return; - } - } - - // empty list - if (val.empty()) - { - addon->auras = NULL; - return; - } - - // replace by new structures array - const_cast(addon->auras) = new CreatureDataAddonAura[val.size()+1]; - - uint32 i=0; - for (std::map::iterator itr = val.begin(); itr != val.end();++itr) - { - CreatureDataAddonAura& cAura = const_cast(addon->auras[i]); - cAura.spell_id = itr->first; - cAura.effectMask = itr->second; - if (cAura.effectMask > 7 || !cAura.effectMask) - { - sLog.outErrorDb("Creature (%s: %u) has wrong effect for spell %u in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.spell_id,table); - continue; - } - SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(cAura.spell_id); - if (!AdditionalSpellInfo) - { - sLog.outErrorDb("Creature (%s: %u) has wrong spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.spell_id,table); - continue; - } - for (uint8 eff = 0; eff < MAX_SPELL_EFFECTS; ++eff) - { - if ((1<Effect[eff] || !AdditionalSpellInfo->EffectApplyAuraName[eff]) - { - sLog.outErrorDb("Creature (%s: %u) has not aura effect %u of spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,eff,cAura.spell_id,table); - continue; - } - else if (AdditionalSpellInfo->Effect[eff] == SPELL_EFFECT_PERSISTENT_AREA_AURA) - { - sLog.outErrorDb("Creature (%s: %u) has persistent area aura effect %u of spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,eff,cAura.spell_id,table); - continue; - } - } - } - - ++i; - } - - // fill terminator element (after last added) - CreatureDataAddonAura& endAura = const_cast(addon->auras[i]); - endAura.spell_id = 0; - endAura.effectMask = 0; -} - -void ObjectMgr::LoadCreatureAddons(SQLStorage& creatureaddons, char const* entryName, char const* comment) -{ - creatureaddons.Load(); - - sLog.outString(">> Loaded %u %s", creatureaddons.RecordCount, comment); - sLog.outString(); - - // check data correctness and convert 'auras' - for (uint32 i = 1; i < creatureaddons.MaxEntry; ++i) - { - CreatureDataAddon const* addon = creatureaddons.LookupEntry(i); - if (!addon) - continue; - - if (addon->mount) - { - if (!sCreatureDisplayInfoStore.LookupEntry(addon->mount)) - { - sLog.outErrorDb("Creature (%s %u) have invalid displayInfoId for mount (%u) defined in `%s`.", entryName, addon->guidOrEntry, addon->mount, creatureaddons.GetTableName()); - const_cast(addon)->mount = 0; - } - } - - if (!sEmotesStore.LookupEntry(addon->emote)) - sLog.outErrorDb("Creature (%s %u) have invalid emote (%u) defined in `%s`.", entryName, addon->guidOrEntry, addon->emote, creatureaddons.GetTableName()); - - /*if (addon->move_flags & (MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4)) - { - sLog.outErrorDb("Creature (%s %u) movement flags mask defined in `%s` include forbidden flags (" I32FMT ") that can crash client, cleanup at load.", entryName, addon->guidOrEntry, creatureaddons.GetTableName(), (MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4)); - const_cast(addon)->move_flags &= ~(MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4); - }*/ - - ConvertCreatureAddonAuras(const_cast(addon), creatureaddons.GetTableName(), entryName); - } -} - -void ObjectMgr::LoadCreatureAddons() -{ - LoadCreatureAddons(sCreatureInfoAddonStorage,"Entry","creature template addons"); - - // check entry ids - for (uint32 i = 1; i < sCreatureInfoAddonStorage.MaxEntry; ++i) - if (CreatureDataAddon const* addon = sCreatureInfoAddonStorage.LookupEntry(i)) - if (!sCreatureStorage.LookupEntry(addon->guidOrEntry)) - sLog.outErrorDb("Creature (Entry: %u) does not exist but has a record in `%s`",addon->guidOrEntry, sCreatureInfoAddonStorage.GetTableName()); - - sLog.outString("Loading Creature Addon Data..."); - LoadCreatureAddons(sCreatureDataAddonStorage,"GUID","creature addons"); - - // check entry ids - for (uint32 i = 1; i < sCreatureDataAddonStorage.MaxEntry; ++i) - if (CreatureDataAddon const* addon = sCreatureDataAddonStorage.LookupEntry(i)) - if (mCreatureDataMap.find(addon->guidOrEntry) == mCreatureDataMap.end()) - sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_addon`",addon->guidOrEntry); -} - -EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry) -{ - return sEquipmentStorage.LookupEntry(entry); -} - -void ObjectMgr::LoadEquipmentTemplates() -{ - sEquipmentStorage.Load(); - - for (uint32 i=0; i< sEquipmentStorage.MaxEntry; ++i) - { - EquipmentInfo const* eqInfo = sEquipmentStorage.LookupEntry(i); - - if (!eqInfo) - continue; - - for (uint8 j=0; j<3; j++) - { - if (!eqInfo->equipentry[j]) - continue; - - ItemEntry const *dbcitem = sItemStore.LookupEntry(eqInfo->equipentry[j]); - - if (!dbcitem) - { - sLog.outErrorDb("Unknown item (entry=%u) in creature_equip_template.equipentry%u for entry = %u, forced to 0.", eqInfo->equipentry[j], j+1, i); - const_cast(eqInfo)->equipentry[j] = 0; - continue; - } - - if (dbcitem->InventoryType != INVTYPE_WEAPON && - dbcitem->InventoryType != INVTYPE_SHIELD && - dbcitem->InventoryType != INVTYPE_RANGED && - dbcitem->InventoryType != INVTYPE_2HWEAPON && - dbcitem->InventoryType != INVTYPE_WEAPONMAINHAND && - dbcitem->InventoryType != INVTYPE_WEAPONOFFHAND && - dbcitem->InventoryType != INVTYPE_HOLDABLE && - dbcitem->InventoryType != INVTYPE_THROWN && - dbcitem->InventoryType != INVTYPE_RANGEDRIGHT) - { - sLog.outErrorDb("Item (entry=%u) in creature_equip_template.equipentry%u for entry = %u is not equipable in a hand, forced to 0.", eqInfo->equipentry[j], j+1, i); - const_cast(eqInfo)->equipentry[j] = 0; - } - } - } - sLog.outString(">> Loaded %u equipment template", sEquipmentStorage.RecordCount); - sLog.outString(); -} - -CreatureModelInfo const* ObjectMgr::GetCreatureModelInfo(uint32 modelid) -{ - return sCreatureModelStorage.LookupEntry(modelid); -} - -uint32 ObjectMgr::ChooseDisplayId(uint32 /*team*/, const CreatureInfo *cinfo, const CreatureData *data /*= NULL*/) -{ - // Load creature model (display id) - uint32 display_id = 0; - - if (!data || data->displayid == 0) - { - display_id = cinfo->GetRandomValidModelId(); - } - else - return data->displayid; - - /*if (!team) - { - switch(cinfo->Entry) - { - case 28511: // Eye of Acherus - case 33114: // Flame Leviathan Seat (model 24914 chair) - case 33167: // Salvaged Demolisher Mechanic Seat - case 33189: // Liquid Pryite - return cinfo->Modelid1; - case 33218: // Pyrite Safety Container - return cinfo->Modelid2; - case 33143: // Overload Control Device - return cinfo->Modelid3; - default: - return cinfo->GetRandomValidModelId(); - } - }*/ - - return display_id; -} - -CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(uint32 display_id) -{ - CreatureModelInfo const *minfo = GetCreatureModelInfo(display_id); - if (!minfo) - return NULL; - - // If a model for another gender exists, 50% chance to use it - if (minfo->modelid_other_gender != 0 && urand(0,1) == 0) - { - CreatureModelInfo const *minfo_tmp = GetCreatureModelInfo(minfo->modelid_other_gender); - if (!minfo_tmp) - { - sLog.outErrorDb("Model (Entry: %u) has modelid_other_gender %u not found in table `creature_model_info`. ", minfo->modelid, minfo->modelid_other_gender); - return minfo; // not fatal, just use the previous one - } - else - return minfo_tmp; - } - else - return minfo; -} - -void ObjectMgr::LoadCreatureModelInfo() -{ - sCreatureModelStorage.Load(); - - // post processing - for (uint32 i = 1; i < sCreatureModelStorage.MaxEntry; ++i) - { - CreatureModelInfo const *minfo = sCreatureModelStorage.LookupEntry(i); - if (!minfo) - continue; - - if (!sCreatureDisplayInfoStore.LookupEntry(minfo->modelid)) - sLog.outErrorDb("Table `creature_model_info` has model for not existed display id (%u).", minfo->modelid); - - if (minfo->gender > GENDER_NONE) - { - sLog.outErrorDb("Table `creature_model_info` has wrong gender (%u) for display id (%u).", uint32(minfo->gender), minfo->modelid); - const_cast(minfo)->gender = GENDER_MALE; - } - - if (minfo->modelid_other_gender && !sCreatureDisplayInfoStore.LookupEntry(minfo->modelid_other_gender)) - { - sLog.outErrorDb("Table `creature_model_info` has not existed alt.gender model (%u) for existed display id (%u).", minfo->modelid_other_gender, minfo->modelid); - const_cast(minfo)->modelid_other_gender = 0; - } - } - - sLog.outString(">> Loaded %u creature model based info", sCreatureModelStorage.RecordCount); - sLog.outString(); - - // check if combat_reach is valid - for (uint32 i = 1; i < sCreatureModelStorage.MaxEntry; ++i) - { - CreatureModelInfo const* mInfo = sCreatureModelStorage.LookupEntry(i); - if (!mInfo) - continue; - - if (mInfo->combat_reach < 0.1f) - { - //sLog.outErrorDb("Creature model (Entry: %u) has invalid combat reach (%f), setting it to 0.5", mInfo->modelid, mInfo->combat_reach); - const_cast(mInfo)->combat_reach = DEFAULT_COMBAT_REACH; - } - } -} - -bool ObjectMgr::CheckCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid) const -{ - const CreatureData* const slave = GetCreatureData(guid); - const CreatureData* const master = GetCreatureData(linkedGuid); - - if (!slave || !master) // they must have a corresponding entry in db - { - sLog.outError("LinkedRespawn: Creature '%u' linking to '%u' which doesn't exist",guid,linkedGuid); - return false; - } - - const MapEntry* const map = sMapStore.LookupEntry(master->mapid); - - if (master->mapid != slave->mapid // link only to same map - && (!map || map->Instanceable())) // or to unistanced world - { - sLog.outError("LinkedRespawn: Creature '%u' linking to '%u' on an unpermitted map",guid,linkedGuid); - return false; - } - - if (!(master->spawnMask & slave->spawnMask) // they must have a possibility to meet (normal/heroic difficulty) - && (!map || map->Instanceable())) - { - sLog.outError("LinkedRespawn: Creature '%u' linking to '%u' with not corresponding spawnMask",guid,linkedGuid); - return false; - } - - return true; -} - -void ObjectMgr::LoadCreatureLinkedRespawn() -{ - mCreatureLinkedRespawnMap.clear(); - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT guid, linkedGuid FROM creature_linked_respawn ORDER BY guid ASC"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(""); - sLog.outErrorDb(">> Loaded 0 linked respawns. DB table `creature_linked_respawn` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 guid = fields[0].GetUInt32(); - uint32 linkedGuid = fields[1].GetUInt32(); - - if (CheckCreatureLinkedRespawn(guid,linkedGuid)) - mCreatureLinkedRespawnMap[guid] = linkedGuid; - - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u linked respawns", mCreatureLinkedRespawnMap.size()); -} - -bool ObjectMgr::SetCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid) -{ - if (!guid) - return false; - - if (!linkedGuid) // we're removing the linking - { - mCreatureLinkedRespawnMap.erase(guid); - WorldDatabase.DirectPExecute("DELETE FROM creature_linked_respawn WHERE guid = '%u'",guid); - return true; - } - - if (CheckCreatureLinkedRespawn(guid,linkedGuid)) // we add/change linking - { - mCreatureLinkedRespawnMap[guid] = linkedGuid; - WorldDatabase.DirectPExecute("REPLACE INTO creature_linked_respawn (guid,linkedGuid) VALUES ('%u','%u')",guid,linkedGuid); - return true; - } - return false; -} - -void ObjectMgr::LoadCreatures() -{ - uint32 count = 0; - // 0 1 2 3 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid," - // 4 5 6 7 8 9 10 11 - "equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint," - // 12 13 14 15 16 17 18 19 - "curhealth, curmana, DeathState, MovementType, spawnMask, phaseMask, event, pool_entry " - "FROM creature LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid " - "LEFT OUTER JOIN pool_creature ON creature.guid = pool_creature.guid"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 creature. DB table `creature` is empty."); - return; - } - - // build single time for check creature data - std::set difficultyCreatures[MAX_DIFFICULTY - 1]; - for (uint32 i = 0; i < sCreatureStorage.MaxEntry; ++i) - if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i)) - for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1; ++diff) - if (cInfo->DifficultyEntry[diff]) - difficultyCreatures[diff].insert(cInfo->DifficultyEntry[diff]); - - // build single time for check spawnmask - std::map spawnMasks; - for (uint32 i = 0; i < sMapStore.GetNumRows(); ++i) - if (sMapStore.LookupEntry(i)) - for (int k = 0; k < MAX_DIFFICULTY; ++k) - if (GetMapDifficultyData(i,Difficulty(k))) - spawnMasks[i] |= (1 << k); - - //TODO: remove this - //gameeventmgr.mGameEventCreatureGuids.resize(52*2-1); - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 guid = fields[ 0].GetUInt32(); - uint32 entry = fields[ 1].GetUInt32(); - - CreatureInfo const* cInfo = GetCreatureTemplate(entry); - if (!cInfo) - { - sLog.outErrorDb("Table `creature` has creature (GUID: %u) with non existing creature entry %u, skipped.", guid, entry); - continue; - } - - CreatureData& data = mCreatureDataMap[guid]; - - data.id = entry; - data.mapid = fields[ 2].GetUInt32(); - data.displayid = fields[ 3].GetUInt32(); - data.equipmentId = fields[ 4].GetUInt32(); - data.posX = fields[ 5].GetFloat(); - data.posY = fields[ 6].GetFloat(); - data.posZ = fields[ 7].GetFloat(); - data.orientation = fields[ 8].GetFloat(); - data.spawntimesecs = fields[ 9].GetUInt32(); - data.spawndist = fields[10].GetFloat(); - data.currentwaypoint= fields[11].GetUInt32(); - data.curhealth = fields[12].GetUInt32(); - data.curmana = fields[13].GetUInt32(); - data.is_dead = fields[14].GetBool(); - data.movementType = fields[15].GetUInt8(); - data.spawnMask = fields[16].GetUInt8(); - data.phaseMask = fields[17].GetUInt16(); - int16 gameEvent = fields[18].GetInt16(); - int16 PoolId = fields[19].GetInt16(); - - MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid); - if (!mapEntry) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u) that spawned at not existed map (Id: %u), skipped.",guid, data.mapid); - continue; - } - - if (data.spawnMask & ~spawnMasks[data.mapid]) - sLog.outErrorDb("Table `creature` have creature (GUID: %u) that have wrong spawn mask %u including not supported difficulty modes for map (Id: %u).",guid, data.spawnMask, data.mapid); - - bool ok = true; - for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && ok; ++diff) - { - if (difficultyCreatures[diff].find(data.id) != difficultyCreatures[diff].end()) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u) that listed as difficulty %u template (entry: %u) in `creature_template`, skipped.", - guid, diff + 1, data.id); - ok = false; - } - } - if (!ok) - continue; - - // I do not know why but in db most display id are not zero - /*if (data.displayid == 11686 || data.displayid == 24719) - { - (const_cast(cInfo))->flags_extra |= CREATURE_FLAG_EXTRA_TRIGGER; - } - else if (data.displayid == cInfo->DisplayID_A || data.displayid == cInfo->DisplayID_A2 - || data.displayid == cInfo->DisplayID_H || data.displayid == cInfo->DisplayID_H2) - data.displayid = 0; - */ - - if (data.equipmentId > 0) // -1 no equipment, 0 use default - { - if (!GetEquipmentInfo(data.equipmentId)) - { - sLog.outErrorDb("Table `creature` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", data.id, data.equipmentId); - data.equipmentId = -1; - } - } - - if (cInfo->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND) - { - if (!mapEntry || !mapEntry->IsDungeon()) - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`flags_extra` including CREATURE_FLAG_EXTRA_INSTANCE_BIND but creature are not in instance.",guid,data.id); - } - - if (data.spawndist < 0.0f) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `spawndist`< 0, set to 0.",guid,data.id); - data.spawndist = 0.0f; - } - else if (data.movementType == RANDOM_MOTION_TYPE) - { - if (data.spawndist == 0.0f) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=1 (random movement) but with `spawndist`=0, replace by idle movement type (0).",guid,data.id); - data.movementType = IDLE_MOTION_TYPE; - } - else if (cInfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER) - data.movementType = IDLE_MOTION_TYPE; - } - else if (data.movementType == IDLE_MOTION_TYPE) - { - if (data.spawndist != 0.0f) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=0 (idle) have `spawndist`<>0, set to 0.",guid,data.id); - data.spawndist = 0.0f; - } - } - - if (data.phaseMask == 0) - { - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `phaseMask`=0 (not visible for anyone), set to 1.",guid,data.id); - data.phaseMask = 1; - } - - //if (entry == 32307 || entry == 32308) - /*if (entry == 30739 || entry == 30740) - { - gameEvent = 51; - uint32 guid2 = objmgr.GenerateLowGuid(HIGHGUID_UNIT); - CreatureData& data2 = mCreatureDataMap[guid2]; - data2 = data; -// data2.id = (entry == 32307 ? 32308 : 32307); - data2.id = (entry == 30739 ? 30740 : 30739); - data2.displayid = 0; - gameeventmgr.mGameEventCreatureGuids[51+51].push_back(guid); - gameeventmgr.mGameEventCreatureGuids[51+50].push_back(guid2); - }*/ - - if (gameEvent == 0 && PoolId == 0) // if not this is to be managed by GameEvent System or Pool system - AddCreatureToGrid(guid, &data); - - ++count; - - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %lu creatures", (unsigned long)mCreatureDataMap.size()); -} - -void ObjectMgr::AddCreatureToGrid(uint32 guid, CreatureData const* data) -{ - uint8 mask = data->spawnMask; - for (uint8 i = 0; mask != 0; i++, mask >>= 1) - { - if (mask & 1) - { - CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY); - uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; - - CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; - cell_guids.creatures.insert(guid); - } - } -} - -void ObjectMgr::RemoveCreatureFromGrid(uint32 guid, CreatureData const* data) -{ - uint8 mask = data->spawnMask; - for (uint8 i = 0; mask != 0; i++, mask >>= 1) - { - if (mask & 1) - { - CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY); - uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; - - CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; - cell_guids.creatures.erase(guid); - } - } -} - -uint32 ObjectMgr::AddGOData(uint32 entry, uint32 mapId, float x, float y, float z, float o, uint32 spawntimedelay, float rotation0, float rotation1, float rotation2, float rotation3) -{ - GameObjectInfo const* goinfo = GetGameObjectInfo(entry); - if (!goinfo) - return 0; - - Map* map = const_cast(MapManager::Instance().CreateBaseMap(mapId)); - if (!map) - return 0; - - uint32 guid = GenerateLowGuid(HIGHGUID_GAMEOBJECT); - GameObjectData& data = NewGOData(guid); - data.id = entry; - data.mapid = mapId; - data.posX = x; - data.posY = y; - data.posZ = z; - data.orientation = o; - data.rotation0 = rotation0; - data.rotation1 = rotation1; - data.rotation2 = rotation2; - data.rotation3 = rotation3; - data.spawntimesecs = spawntimedelay; - data.animprogress = 100; - data.spawnMask = 1; - data.go_state = GO_STATE_READY; - data.phaseMask = PHASEMASK_NORMAL; - data.artKit = goinfo->type == GAMEOBJECT_TYPE_CAPTURE_POINT ? 21 : 0; - data.dbData = false; - - AddGameobjectToGrid(guid, &data); - - // Spawn if necessary (loaded grids only) - // We use spawn coords to spawn - if (!map->Instanceable() && map->IsLoaded(x, y)) - { - GameObject *go = new GameObject; - if (!go->LoadFromDB(guid, map)) - { - sLog.outError("AddGOData: cannot add gameobject entry %u to map", entry); - delete go; - return 0; - } - map->Add(go); - } - - sLog.outDebug("AddGOData: dbguid %u entry %u map %u x %f y %f z %f o %f", guid, entry, mapId, x, y, z, o); - - return guid; -} - -bool ObjectMgr::MoveCreData(uint32 guid, uint32 mapId, Position pos) -{ - CreatureData& data = NewOrExistCreatureData(guid); - if (!data.id) - return false; - - RemoveCreatureFromGrid(guid, &data); - if (data.posX == pos.GetPositionX() && data.posY == pos.GetPositionY() && data.posZ == pos.GetPositionZ()) - return true; - data.posX = pos.GetPositionX(); - data.posY = pos.GetPositionY(); - data.posZ = pos.GetPositionZ(); - data.orientation = pos.GetOrientation(); - AddCreatureToGrid(guid, &data); - - // Spawn if necessary (loaded grids only) - if (Map* map = const_cast(MapManager::Instance().CreateBaseMap(mapId))) - { - // We use spawn coords to spawn - if (!map->Instanceable() && map->IsLoaded(data.posX, data.posY)) - { - Creature *creature = new Creature; - if (!creature->LoadFromDB(guid, map)) - { - sLog.outError("AddCreature: cannot add creature entry %u to map", guid); - delete creature; - return false; - } - map->Add(creature); - } - } - return true; -} - -uint32 ObjectMgr::AddCreData(uint32 entry, uint32 /*team*/, uint32 mapId, float x, float y, float z, float o, uint32 spawntimedelay) -{ - CreatureInfo const *cInfo = GetCreatureTemplate(entry); - if (!cInfo) - return 0; - - uint32 level = cInfo->minlevel == cInfo->maxlevel ? cInfo->minlevel : urand(cInfo->minlevel, cInfo->maxlevel); // Only used for extracting creature base stats - CreatureBaseStats const* stats = objmgr.GetCreatureBaseStats(level, cInfo->unit_class); - - uint32 guid = GenerateLowGuid(HIGHGUID_UNIT); - CreatureData& data = NewOrExistCreatureData(guid); - data.id = entry; - data.mapid = mapId; - data.displayid = 0; - data.equipmentId = cInfo->equipmentId; - data.posX = x; - data.posY = y; - data.posZ = z; - data.orientation = o; - data.spawntimesecs = spawntimedelay; - data.spawndist = 0; - data.currentwaypoint = 0; - data.curhealth = stats->GenerateHealth(cInfo); - data.curmana = stats->GenerateMana(cInfo); - data.is_dead = false; - data.movementType = cInfo->MovementType; - data.spawnMask = 1; - data.phaseMask = PHASEMASK_NORMAL; - data.dbData = false; - - AddCreatureToGrid(guid, &data); - - // Spawn if necessary (loaded grids only) - if (Map* map = const_cast(MapManager::Instance().CreateBaseMap(mapId))) - { - // We use spawn coords to spawn - if (!map->Instanceable() && !map->IsRemovalGrid(x, y)) - { - Creature* creature = new Creature; - if (!creature->LoadFromDB(guid, map)) - { - sLog.outError("AddCreature: cannot add creature entry %u to map", entry); - delete creature; - return 0; - } - map->Add(creature); - } - } - - return guid; -} - -void ObjectMgr::LoadGameobjects() -{ - uint32 count = 0; - - // 0 1 2 3 4 5 6 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation," - // 7 8 9 10 11 12 13 14 15 16 17 - "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, phaseMask, event, pool_entry " - "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid " - "LEFT OUTER JOIN pool_gameobject ON gameobject.guid = pool_gameobject.guid"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 gameobjects. DB table `gameobject` is empty."); - return; - } - - // build single time for check spawnmask - std::map spawnMasks; - for (uint32 i = 0; i < sMapStore.GetNumRows(); ++i) - if (sMapStore.LookupEntry(i)) - for (int k = 0; k < MAX_DIFFICULTY; ++k) - if (GetMapDifficultyData(i,Difficulty(k))) - spawnMasks[i] |= (1 << k); - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 guid = fields[ 0].GetUInt32(); - uint32 entry = fields[ 1].GetUInt32(); - - GameObjectInfo const* gInfo = GetGameObjectInfo(entry); - if (!gInfo) - { - sLog.outErrorDb("Table `gameobject` has gameobject (GUID: %u) with non existing gameobject entry %u, skipped.", guid, entry); - continue; - } - - if (!gInfo->displayId) - { - switch (gInfo->type) - { - case GAMEOBJECT_TYPE_TRAP: - case GAMEOBJECT_TYPE_SPELL_FOCUS: - break; - default: - sLog.outErrorDb("Gameobject (GUID: %u Entry %u GoType: %u) doesn't have displayId (%u), not loaded.", guid, entry, gInfo->type, gInfo->displayId); - break; - } - } - - if (gInfo->displayId && !sGameObjectDisplayInfoStore.LookupEntry(gInfo->displayId)) - { - sLog.outErrorDb("Gameobject (GUID: %u Entry %u GoType: %u) have invalid displayId (%u), not loaded.",guid, entry, gInfo->type, gInfo->displayId); - continue; - } - - GameObjectData& data = mGameObjectDataMap[guid]; - - data.id = entry; - data.mapid = fields[ 2].GetUInt32(); - data.posX = fields[ 3].GetFloat(); - data.posY = fields[ 4].GetFloat(); - data.posZ = fields[ 5].GetFloat(); - data.orientation = fields[ 6].GetFloat(); - data.rotation0 = fields[ 7].GetFloat(); - data.rotation1 = fields[ 8].GetFloat(); - data.rotation2 = fields[ 9].GetFloat(); - data.rotation3 = fields[10].GetFloat(); - data.spawntimesecs = fields[11].GetInt32(); - - MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid); - if (!mapEntry) - { - sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) that spawned at not existed map (Id: %u), skip", guid, data.id, data.mapid); - continue; - } - - if (data.spawntimesecs == 0 && gInfo->IsDespawnAtAction()) - { - sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with `spawntimesecs` (0) value, but gameobejct marked as despawnable at action.",guid,data.id); - } - - data.animprogress = fields[12].GetUInt32(); - data.artKit = 0; - - uint32 go_state = fields[13].GetUInt32(); - if (go_state >= MAX_GO_STATE) - { - sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid `state` (%u) value, skip",guid,data.id,go_state); - continue; - } - data.go_state = GOState(go_state); - - data.spawnMask = fields[14].GetUInt8(); - - if (data.spawnMask & ~spawnMasks[data.mapid]) - sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) that have wrong spawn mask %u including not supported difficulty modes for map (Id: %u), skip", guid, data.id, data.spawnMask, data.mapid); - - data.phaseMask = fields[15].GetUInt16(); - int16 gameEvent = fields[16].GetInt16(); - int16 PoolId = fields[17].GetInt16(); - - if (data.rotation2 < -1.0f || data.rotation2 > 1.0f) - { - sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid rotation2 (%f) value, skip",guid,data.id,data.rotation2); - continue; - } - - if (data.rotation3 < -1.0f || data.rotation3 > 1.0f) - { - sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid rotation3 (%f) value, skip",guid,data.id,data.rotation3); - continue; - } - - if (!MapManager::IsValidMapCoord(data.mapid,data.posX,data.posY,data.posZ,data.orientation)) - { - sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid coordinates, skip",guid,data.id); - continue; - } - - if (data.phaseMask == 0) - { - sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with `phaseMask`=0 (not visible for anyone), set to 1.",guid,data.id); - data.phaseMask = 1; - } - - if (gameEvent == 0 && PoolId == 0) // if not this is to be managed by GameEvent System or Pool system - AddGameobjectToGrid(guid, &data); - ++count; - - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %lu gameobjects", (unsigned long)mGameObjectDataMap.size()); -} - -void ObjectMgr::AddGameobjectToGrid(uint32 guid, GameObjectData const* data) -{ - uint8 mask = data->spawnMask; - for (uint8 i = 0; mask != 0; i++, mask >>= 1) - { - if (mask & 1) - { - CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY); - uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; - - CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; - cell_guids.gameobjects.insert(guid); - } - } -} - -void ObjectMgr::RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data) -{ - uint8 mask = data->spawnMask; - for (uint8 i = 0; mask != 0; i++, mask >>= 1) - { - if (mask & 1) - { - CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY); - uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; - - CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; - cell_guids.gameobjects.erase(guid); - } - } -} - -void ObjectMgr::LoadCreatureRespawnTimes() -{ - uint32 count = 0; - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM creature_respawn"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded 0 creature respawn time."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 loguid = fields[0].GetUInt32(); - uint64 respawn_time = fields[1].GetUInt64(); - uint32 instance = fields[2].GetUInt32(); - - mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = time_t(respawn_time); - - ++count; - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %lu creature respawn times", (unsigned long)mCreatureRespawnTimes.size()); -} - -void ObjectMgr::LoadGameobjectRespawnTimes() -{ - // remove outdated data - WorldDatabase.DirectExecute("DELETE FROM gameobject_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())"); - - uint32 count = 0; - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM gameobject_respawn"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded 0 gameobject respawn time."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 loguid = fields[0].GetUInt32(); - uint64 respawn_time = fields[1].GetUInt64(); - uint32 instance = fields[2].GetUInt32(); - - mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = time_t(respawn_time); - - ++count; - } while (result->NextRow()); - - sLog.outString(">> Loaded %lu gameobject respawn times", (unsigned long)mGORespawnTimes.size()); - sLog.outString(); -} - -// name must be checked to correctness (if received) before call this function -uint64 ObjectMgr::GetPlayerGUIDByName(std::string name) const -{ - uint64 guid = 0; - - CharacterDatabase.escape_string(name); - - // Player name safe to sending to DB (checked at login) and this function using - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT guid FROM characters WHERE name = '%s'", name.c_str()); - if (result) - guid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); - - return guid; -} - -bool ObjectMgr::GetPlayerNameByGUID(const uint64 &guid, std::string &name) const -{ - // prevent DB access for online player - if (Player* player = GetPlayer(guid)) - { - name = player->GetName(); - return true; - } - - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT name FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); - - if (result) - { - name = (*result)[0].GetCppString(); - return true; - } - - return false; -} - -uint32 ObjectMgr::GetPlayerTeamByGUID(const uint64 &guid) const -{ - // prevent DB access for online player - if (Player* player = GetPlayer(guid)) - { - return Player::TeamForRace(player->getRace()); - } - - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT race FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); - - if (result) - { - uint8 race = (*result)[0].GetUInt8(); - return Player::TeamForRace(race); - } - - return 0; -} - -uint32 ObjectMgr::GetPlayerAccountIdByGUID(const uint64 &guid) const -{ - // prevent DB access for online player - if (Player* player = GetPlayer(guid)) - { - return player->GetSession()->GetAccountId(); - } - - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); - if (result) - { - uint32 acc = (*result)[0].GetUInt32(); - return acc; - } - - return 0; -} - -uint32 ObjectMgr::GetPlayerAccountIdByPlayerName(const std::string& name) const -{ - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'", name.c_str()); - if (result) - { - uint32 acc = (*result)[0].GetUInt32(); - return acc; - } - - return 0; -} - -void ObjectMgr::LoadItemLocales() -{ - mItemLocaleMap.clear(); // need for reload case - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry,name_loc1,description_loc1,name_loc2,description_loc2,name_loc3,description_loc3,name_loc4,description_loc4,name_loc5,description_loc5,name_loc6,description_loc6,name_loc7,description_loc7,name_loc8,description_loc8 FROM locales_item"); - - if (!result) - return; - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 entry = fields[0].GetUInt32(); - - ItemLocale& data = mItemLocaleMap[entry]; - - for (uint8 i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[1+2*(i-1)].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.Name.size() <= idx) - data.Name.resize(idx+1); - - data.Name[idx] = str; - } - } - - str = fields[1+2*(i-1)+1].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.Description.size() <= idx) - data.Description.resize(idx+1); - - data.Description[idx] = str; - } - } - } - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %lu Item locale strings", (unsigned long)mItemLocaleMap.size()); -} - -struct SQLItemLoader : public SQLStorageLoaderBase -{ - template - void convert_from_str(uint32 /*field_pos*/, char *src, D &dst) - { - dst = D(objmgr.GetScriptId(src)); - } -}; - -void ObjectMgr::LoadItemPrototypes() -{ - SQLItemLoader loader; - loader.Load(sItemStorage); - sLog.outString(">> Loaded %u item prototypes", sItemStorage.RecordCount); - sLog.outString(); - - // check data correctness - for (uint32 i = 1; i < sItemStorage.MaxEntry; ++i) - { - ItemPrototype const* proto = sItemStorage.LookupEntry(i); - ItemEntry const *dbcitem = sItemStore.LookupEntry(i); - if (!proto) - { - /* to many errors, and possible not all items really used in game - if (dbcitem) - sLog.outErrorDb("Item (Entry: %u) doesn't exists in DB, but must exist.",i); - */ - continue; - } - - if (dbcitem) - { - if (proto->Class != dbcitem->Class) - { - sLog.outErrorDb("Item (Entry: %u) not correct class %u, must be %u (still using DB value).",i,proto->Class,dbcitem->Class); - // It safe let use Class from DB - } - /* disabled: have some strange wrong cases for Subclass values. - for enable also uncomment Subclass field in ItemEntry structure and in Itemfmt[] - if (proto->SubClass != dbcitem->SubClass) - { - sLog.outErrorDb("Item (Entry: %u) not correct (Class: %u, Sub: %u) pair, must be (Class: %u, Sub: %u) (still using DB value).",i,proto->Class,proto->SubClass,dbcitem->Class,dbcitem->SubClass); - // It safe let use Subclass from DB - } - */ - - if (proto->Unk0 != dbcitem->Unk0) - { - sLog.outErrorDb("Item (Entry: %u) not correct %i Unk0, must be %i (still using DB value).",i,proto->Unk0,dbcitem->Unk0); - // It safe let use Unk0 from DB - } - - if (proto->Material != dbcitem->Material) - { - sLog.outErrorDb("Item (Entry: %u) not correct %i material, must be %i (still using DB value).",i,proto->Material,dbcitem->Material); - // It safe let use Material from DB - } - - if (proto->InventoryType != dbcitem->InventoryType) - { - sLog.outErrorDb("Item (Entry: %u) not correct %u inventory type, must be %u (still using DB value).",i,proto->InventoryType,dbcitem->InventoryType); - // It safe let use InventoryType from DB - } - - if (proto->DisplayInfoID != dbcitem->DisplayId) - { - sLog.outErrorDb("Item (Entry: %u) not correct %u display id, must be %u (using it).",i,proto->DisplayInfoID,dbcitem->DisplayId); - const_cast(proto)->DisplayInfoID = dbcitem->DisplayId; - } - if (proto->Sheath != dbcitem->Sheath) - { - sLog.outErrorDb("Item (Entry: %u) not correct %u sheath, must be %u (using it).",i,proto->Sheath,dbcitem->Sheath); - const_cast(proto)->Sheath = dbcitem->Sheath; - } - } - else - sLog.outErrorDb("Item (Entry: %u) not correct (not listed in list of existed items).",i); - - if (proto->Class >= MAX_ITEM_CLASS) - { - sLog.outErrorDb("Item (Entry: %u) has wrong Class value (%u)",i,proto->Class); - const_cast(proto)->Class = ITEM_CLASS_MISC; - } - - if (proto->SubClass >= MaxItemSubclassValues[proto->Class]) - { - sLog.outErrorDb("Item (Entry: %u) has wrong Subclass value (%u) for class %u",i,proto->SubClass,proto->Class); - const_cast(proto)->SubClass = 0;// exist for all item classes - } - - if (proto->Quality >= MAX_ITEM_QUALITY) - { - sLog.outErrorDb("Item (Entry: %u) has wrong Quality value (%u)",i,proto->Quality); - const_cast(proto)->Quality = ITEM_QUALITY_NORMAL; - } - - if (proto->BuyCount <= 0) - { - sLog.outErrorDb("Item (Entry: %u) has wrong BuyCount value (%u), set to default(1).",i,proto->BuyCount); - const_cast(proto)->BuyCount = 1; - } - - if (proto->InventoryType >= MAX_INVTYPE) - { - sLog.outErrorDb("Item (Entry: %u) has wrong InventoryType value (%u)",i,proto->InventoryType); - const_cast(proto)->InventoryType = INVTYPE_NON_EQUIP; - } - - if (proto->RequiredSkill >= MAX_SKILL_TYPE) - { - sLog.outErrorDb("Item (Entry: %u) has wrong RequiredSkill value (%u)",i,proto->RequiredSkill); - const_cast(proto)->RequiredSkill = 0; - } - - { - // can be used in equip slot, as page read use in inventory, or spell casting at use - bool req = proto->InventoryType != INVTYPE_NON_EQUIP || proto->PageText; - if (!req) - for (uint8 j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j) - { - if (proto->Spells[j].SpellId) - { - req = true; - break; - } - } - - if (req) - { - if (!(proto->AllowableClass & CLASSMASK_ALL_PLAYABLE)) - sLog.outErrorDb("Item (Entry: %u) not have in `AllowableClass` any playable classes (%u) and can't be equipped or use.",i,proto->AllowableClass); - - if (!(proto->AllowableRace & RACEMASK_ALL_PLAYABLE)) - sLog.outErrorDb("Item (Entry: %u) not have in `AllowableRace` any playable races (%u) and can't be equipped or use.",i,proto->AllowableRace); - } - } - - if (proto->RequiredSpell && !sSpellStore.LookupEntry(proto->RequiredSpell)) - { - sLog.outErrorDb("Item (Entry: %u) have wrong (non-existed) spell in RequiredSpell (%u)",i,proto->RequiredSpell); - const_cast(proto)->RequiredSpell = 0; - } - - if (proto->RequiredReputationRank >= MAX_REPUTATION_RANK) - sLog.outErrorDb("Item (Entry: %u) has wrong reputation rank in RequiredReputationRank (%u), item can't be used.",i,proto->RequiredReputationRank); - - if (proto->RequiredReputationFaction) - { - if (!sFactionStore.LookupEntry(proto->RequiredReputationFaction)) - { - sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) faction in RequiredReputationFaction (%u)",i,proto->RequiredReputationFaction); - const_cast(proto)->RequiredReputationFaction = 0; - } - - if (proto->RequiredReputationRank == MIN_REPUTATION_RANK) - sLog.outErrorDb("Item (Entry: %u) has min. reputation rank in RequiredReputationRank (0) but RequiredReputationFaction > 0, faction setting is useless.",i); - } - - if (proto->MaxCount < -1) - { - sLog.outErrorDb("Item (Entry: %u) has too large negative in maxcount (%i), replace by value (-1) no storing limits.",i,proto->MaxCount); - const_cast(proto)->MaxCount = -1; - } - - if (proto->Stackable == 0) - { - sLog.outErrorDb("Item (Entry: %u) has wrong value in stackable (%i), replace by default 1.",i,proto->Stackable); - const_cast(proto)->Stackable = 1; - } - else if (proto->Stackable < -1) - { - sLog.outErrorDb("Item (Entry: %u) has too large negative in stackable (%i), replace by value (-1) no stacking limits.",i,proto->Stackable); - const_cast(proto)->Stackable = -1; - } - - if (proto->ContainerSlots > MAX_BAG_SIZE) - { - sLog.outErrorDb("Item (Entry: %u) has too large value in ContainerSlots (%u), replace by hardcoded limit (%u).",i,proto->ContainerSlots,MAX_BAG_SIZE); - const_cast(proto)->ContainerSlots = MAX_BAG_SIZE; - } - - if (proto->StatsCount > MAX_ITEM_PROTO_STATS) - { - sLog.outErrorDb("Item (Entry: %u) has too large value in statscount (%u), replace by hardcoded limit (%u).",i,proto->StatsCount,MAX_ITEM_PROTO_STATS); - const_cast(proto)->StatsCount = MAX_ITEM_PROTO_STATS; - } - - for (uint8 j = 0; j < MAX_ITEM_PROTO_STATS; ++j) - { - // for ItemStatValue != 0 - if (proto->ItemStat[j].ItemStatValue && proto->ItemStat[j].ItemStatType >= MAX_ITEM_MOD) - { - sLog.outErrorDb("Item (Entry: %u) has wrong stat_type%d (%u)",i,j+1,proto->ItemStat[j].ItemStatType); - const_cast(proto)->ItemStat[j].ItemStatType = 0; - } - - switch (proto->ItemStat[j].ItemStatType) - { - case ITEM_MOD_SPELL_HEALING_DONE: - case ITEM_MOD_SPELL_DAMAGE_DONE: - sLog.outErrorDb("Item (Entry: %u) has deprecated stat_type%d (%u)",i,j+1,proto->ItemStat[j].ItemStatType); - break; - default: - break; - } - } - - for (uint8 j = 0; j < MAX_ITEM_PROTO_DAMAGES; ++j) - { - if (proto->Damage[j].DamageType >= MAX_SPELL_SCHOOL) - { - sLog.outErrorDb("Item (Entry: %u) has wrong dmg_type%d (%u)",i,j+1,proto->Damage[j].DamageType); - const_cast(proto)->Damage[j].DamageType = 0; - } - } - - // special format - if ((proto->Spells[0].SpellId == 483) || (proto->Spells[0].SpellId == 55884)) - { - // spell_1 - if (proto->Spells[0].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE) - { - sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format",i,0+1,proto->Spells[0].SpellTrigger); - const_cast(proto)->Spells[0].SpellId = 0; - const_cast(proto)->Spells[0].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - const_cast(proto)->Spells[1].SpellId = 0; - const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - - // spell_2 have learning spell - if (proto->Spells[1].SpellTrigger != ITEM_SPELLTRIGGER_LEARN_SPELL_ID) - { - sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format.",i,1+1,proto->Spells[1].SpellTrigger); - const_cast(proto)->Spells[0].SpellId = 0; - const_cast(proto)->Spells[1].SpellId = 0; - const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - else if (!proto->Spells[1].SpellId) - { - sLog.outErrorDb("Item (Entry: %u) not has expected spell in spellid_%d in special learning format.",i,1+1); - const_cast(proto)->Spells[0].SpellId = 0; - const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - else if (proto->Spells[1].SpellId != -1) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[1].SpellId); - if (!spellInfo) - { - sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%d)",i,1+1,proto->Spells[1].SpellId); - const_cast(proto)->Spells[0].SpellId = 0; - const_cast(proto)->Spells[1].SpellId = 0; - const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - // allowed only in special format - else if ((proto->Spells[1].SpellId == 483) || (proto->Spells[1].SpellId == 55884)) - { - sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%d)",i,1+1,proto->Spells[1].SpellId); - const_cast(proto)->Spells[0].SpellId = 0; - const_cast(proto)->Spells[1].SpellId = 0; - const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - } - - // spell_3*,spell_4*,spell_5* is empty - for (uint8 j = 2; j < MAX_ITEM_PROTO_SPELLS; ++j) - { - if (proto->Spells[j].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE) - { - sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)",i,j+1,proto->Spells[j].SpellTrigger); - const_cast(proto)->Spells[j].SpellId = 0; - const_cast(proto)->Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - else if (proto->Spells[j].SpellId != 0) - { - sLog.outErrorDb("Item (Entry: %u) has wrong spell in spellid_%d (%d) for learning special format",i,j+1,proto->Spells[j].SpellId); - const_cast(proto)->Spells[j].SpellId = 0; - } - } - } - // normal spell list - else - { - for (uint8 j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j) - { - if (proto->Spells[j].SpellTrigger >= MAX_ITEM_SPELLTRIGGER || proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID) - { - sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)",i,j+1,proto->Spells[j].SpellTrigger); - const_cast(proto)->Spells[j].SpellId = 0; - const_cast(proto)->Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; - } - - if (proto->Spells[j].SpellId && proto->Spells[j].SpellId != -1) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[j].SpellId); - if (!spellInfo) - { - sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%d)",i,j+1,proto->Spells[j].SpellId); - const_cast(proto)->Spells[j].SpellId = 0; - } - // allowed only in special format - else if ((proto->Spells[j].SpellId == 483) || (proto->Spells[j].SpellId == 55884)) - { - sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%d)",i,j+1,proto->Spells[j].SpellId); - const_cast(proto)->Spells[j].SpellId = 0; - } - } - } - } - - if (proto->Bonding >= MAX_BIND_TYPE) - sLog.outErrorDb("Item (Entry: %u) has wrong Bonding value (%u)",i,proto->Bonding); - - if (proto->PageText && !sPageTextStore.LookupEntry(proto->PageText)) - sLog.outErrorDb("Item (Entry: %u) has non existing first page (Id:%u)", i,proto->PageText); - - if (proto->LockID && !sLockStore.LookupEntry(proto->LockID)) - sLog.outErrorDb("Item (Entry: %u) has wrong LockID (%u)",i,proto->LockID); - - if (proto->Sheath >= MAX_SHEATHETYPE) - { - sLog.outErrorDb("Item (Entry: %u) has wrong Sheath (%u)",i,proto->Sheath); - const_cast(proto)->Sheath = SHEATHETYPE_NONE; - } - - if (proto->RandomProperty && !sItemRandomPropertiesStore.LookupEntry(GetItemEnchantMod(proto->RandomProperty))) - { - sLog.outErrorDb("Item (Entry: %u) has unknown (wrong or not listed in `item_enchantment_template`) RandomProperty (%u)",i,proto->RandomProperty); - const_cast(proto)->RandomProperty = 0; - } - - if (proto->RandomSuffix && !sItemRandomSuffixStore.LookupEntry(GetItemEnchantMod(proto->RandomSuffix))) - { - sLog.outErrorDb("Item (Entry: %u) has wrong RandomSuffix (%u)",i,proto->RandomSuffix); - const_cast(proto)->RandomSuffix = 0; - } - - if (proto->ItemSet && !sItemSetStore.LookupEntry(proto->ItemSet)) - { - sLog.outErrorDb("Item (Entry: %u) have wrong ItemSet (%u)",i,proto->ItemSet); - const_cast(proto)->ItemSet = 0; - } - - if (proto->Area && !GetAreaEntryByAreaID(proto->Area)) - sLog.outErrorDb("Item (Entry: %u) has wrong Area (%u)",i,proto->Area); - - if (proto->Map && !sMapStore.LookupEntry(proto->Map)) - sLog.outErrorDb("Item (Entry: %u) has wrong Map (%u)",i,proto->Map); - - if (proto->BagFamily) - { - // check bits - for (uint32 j = 0; j < sizeof(proto->BagFamily)*8; ++j) - { - uint32 mask = 1 << j; - if ((proto->BagFamily & mask) == 0) - continue; - - ItemBagFamilyEntry const* bf = sItemBagFamilyStore.LookupEntry(j+1); - if (!bf) - { - sLog.outErrorDb("Item (Entry: %u) has bag family bit set not listed in ItemBagFamily.dbc, remove bit",i); - const_cast(proto)->BagFamily &= ~mask; - continue; - } - - if (BAG_FAMILY_MASK_CURRENCY_TOKENS & mask) - { - CurrencyTypesEntry const* ctEntry = sCurrencyTypesStore.LookupEntry(proto->ItemId); - if (!ctEntry) - { - sLog.outErrorDb("Item (Entry: %u) has currency bag family bit set in BagFamily but not listed in CurrencyTypes.dbc, remove bit",i); - const_cast(proto)->BagFamily &= ~mask; - } - } - } - } - - if (proto->TotemCategory && !sTotemCategoryStore.LookupEntry(proto->TotemCategory)) - sLog.outErrorDb("Item (Entry: %u) has wrong TotemCategory (%u)",i,proto->TotemCategory); - - for (uint8 j = 0; j < MAX_ITEM_PROTO_SOCKETS; ++j) - { - if (proto->Socket[j].Color && (proto->Socket[j].Color & SOCKET_COLOR_ALL) != proto->Socket[j].Color) - { - sLog.outErrorDb("Item (Entry: %u) has wrong socketColor_%d (%u)",i,j+1,proto->Socket[j].Color); - const_cast(proto)->Socket[j].Color = 0; - } - } - - if (proto->GemProperties && !sGemPropertiesStore.LookupEntry(proto->GemProperties)) - sLog.outErrorDb("Item (Entry: %u) has wrong GemProperties (%u)",i,proto->GemProperties); - - if (proto->FoodType >= MAX_PET_DIET) - { - sLog.outErrorDb("Item (Entry: %u) has wrong FoodType value (%u)",i,proto->FoodType); - const_cast(proto)->FoodType = 0; - } - - if (proto->ItemLimitCategory && !sItemLimitCategoryStore.LookupEntry(proto->ItemLimitCategory)) - { - sLog.outErrorDb("Item (Entry: %u) has wrong LimitCategory value (%u)",i,proto->ItemLimitCategory); - const_cast(proto)->ItemLimitCategory = 0; - } - - if (proto->HolidayId && !sHolidaysStore.LookupEntry(proto->HolidayId)) - { - sLog.outErrorDb("Item (Entry: %u) has wrong HolidayId value (%u)", i, proto->HolidayId); - const_cast(proto)->HolidayId = 0; - } - } - - // check some dbc referecned items (avoid duplicate reports) - std::set notFoundOutfit; - for (uint32 i = 1; i < sCharStartOutfitStore.GetNumRows(); ++i) - { - CharStartOutfitEntry const* entry = sCharStartOutfitStore.LookupEntry(i); - if (!entry) - continue; - - for (int j = 0; j < MAX_OUTFIT_ITEMS; ++j) - { - if (entry->ItemId[j] <= 0) - continue; - - uint32 item_id = entry->ItemId[j]; - - if (!GetItemPrototype(item_id)) - notFoundOutfit.insert(item_id); - } - } - - for (std::set::const_iterator itr = notFoundOutfit.begin(); itr != notFoundOutfit.end(); ++itr) - sLog.outErrorDb("Item (Entry: %u) not exist in `item_template` but referenced in `CharStartOutfit.dnc`", *itr); -} - -void ObjectMgr::LoadVehicleAccessories() -{ - m_VehicleAccessoryMap.clear(); // needed for reload case - - uint32 count = 0; - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT `entry`,`accessory_entry`,`seat_id`,`minion` FROM `vehicle_accessory`"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 LoadVehicleAccessor. DB table `vehicle_accessory` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 uiEntry = fields[0].GetUInt32(); - uint32 uiAccessory = fields[1].GetUInt32(); - int8 uiSeat = int8(fields[2].GetInt16()); - bool bMinion = fields[3].GetBool(); - - if (!sCreatureStorage.LookupEntry(uiEntry)) - { - sLog.outErrorDb("Table `vehicle_accessory`: creature template entry %u does not exist.", uiEntry); - continue; - } - - if (!sCreatureStorage.LookupEntry(uiAccessory)) - { - sLog.outErrorDb("Table `vehicle_accessory`: Accessory %u does not exist.", uiAccessory); - continue; - } - - m_VehicleAccessoryMap[uiEntry].push_back(VehicleAccessory(uiAccessory, uiSeat, bMinion)); - - ++count; - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u Vehicle Accessories", count); -} - -void ObjectMgr::LoadPetLevelInfo() -{ - // Loading levels data - { - // 0 1 2 3 4 5 6 7 8 9 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT creature_entry, level, hp, mana, str, agi, sta, inte, spi, armor FROM pet_levelstats"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - - sLog.outString(); - sLog.outString(">> Loaded %u level pet stats definitions", count); - sLog.outErrorDb("Error loading `pet_levelstats` table or empty table."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field* fields = result->Fetch(); - - uint32 creature_id = fields[0].GetUInt32(); - if (!sCreatureStorage.LookupEntry(creature_id)) - { - sLog.outErrorDb("Wrong creature id %u in `pet_levelstats` table, ignoring.",creature_id); - continue; - } - - uint32 current_level = fields[1].GetUInt32(); - if (current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum - sLog.outErrorDb("Wrong (> %u) level %u in `pet_levelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level); - else - { - sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `pet_levelstats` table, ignoring.",current_level); - ++count; // make result loading percent "expected" correct in case disabled detail mode for example. - } - continue; - } - else if (current_level < 1) - { - sLog.outErrorDb("Wrong (<1) level %u in `pet_levelstats` table, ignoring.",current_level); - continue; - } - - PetLevelInfo*& pInfoMapEntry = petInfo[creature_id]; - - if (pInfoMapEntry == NULL) - pInfoMapEntry = new PetLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)]; - - // data for level 1 stored in [0] array element, ... - PetLevelInfo* pLevelInfo = &pInfoMapEntry[current_level-1]; - - pLevelInfo->health = fields[2].GetUInt16(); - pLevelInfo->mana = fields[3].GetUInt16(); - pLevelInfo->armor = fields[9].GetUInt16(); - - for (int i = 0; i < MAX_STATS; i++) - { - pLevelInfo->stats[i] = fields[i+4].GetUInt16(); - } - - bar.step(); - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u level pet stats definitions", count); - } - - // Fill gaps and check integrity - for (PetLevelInfoMap::iterator itr = petInfo.begin(); itr != petInfo.end(); ++itr) - { - PetLevelInfo* pInfo = itr->second; - - // fatal error if no level 1 data - if (!pInfo || pInfo[0].health == 0) - { - sLog.outErrorDb("Creature %u does not have pet stats data for Level 1!",itr->first); - exit(1); - } - - // fill level gaps - for (uint8 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) - { - if (pInfo[level].health == 0) - { - sLog.outErrorDb("Creature %u has no data for Level %i pet stats data, using data of Level %i.",itr->first,level+1, level); - pInfo[level] = pInfo[level-1]; - } - } - } -} - -PetLevelInfo const* ObjectMgr::GetPetLevelInfo(uint32 creature_id, uint8 level) const -{ - if (level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); - - PetLevelInfoMap::const_iterator itr = petInfo.find(creature_id); - if (itr == petInfo.end()) - return NULL; - - return &itr->second[level-1]; // data for level 1 stored in [0] array element, ... -} - -void ObjectMgr::LoadPlayerInfo() -{ - // Load playercreate - { - // 0 1 2 3 4 5 6 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT race, class, map, zone, position_x, position_y, position_z FROM playercreateinfo"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - - sLog.outString(); - sLog.outString(">> Loaded %u player create definitions", count); - sLog.outErrorDb("Error loading `playercreateinfo` table or empty table."); - exit(1); - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field* fields = result->Fetch(); - - uint32 current_race = fields[0].GetUInt32(); - uint32 current_class = fields[1].GetUInt32(); - uint32 mapId = fields[2].GetUInt32(); - uint32 areaId = fields[3].GetUInt32(); - float positionX = fields[4].GetFloat(); - float positionY = fields[5].GetFloat(); - float positionZ = fields[6].GetFloat(); - - if (current_race >= MAX_RACES) - { - sLog.outErrorDb("Wrong race %u in `playercreateinfo` table, ignoring.",current_race); - continue; - } - - ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(current_race); - if (!rEntry) - { - sLog.outErrorDb("Wrong race %u in `playercreateinfo` table, ignoring.",current_race); - continue; - } - - if (current_class >= MAX_CLASSES) - { - sLog.outErrorDb("Wrong class %u in `playercreateinfo` table, ignoring.",current_class); - continue; - } - - if (!sChrClassesStore.LookupEntry(current_class)) - { - sLog.outErrorDb("Wrong class %u in `playercreateinfo` table, ignoring.",current_class); - continue; - } - - // accept DB data only for valid position (and non instanceable) - if (!MapManager::IsValidMapCoord(mapId,positionX,positionY,positionZ)) - { - sLog.outErrorDb("Wrong home position for class %u race %u pair in `playercreateinfo` table, ignoring.",current_class,current_race); - continue; - } - - if (sMapStore.LookupEntry(mapId)->Instanceable()) - { - sLog.outErrorDb("Home position in instanceable map for class %u race %u pair in `playercreateinfo` table, ignoring.",current_class,current_race); - continue; - } - - PlayerInfo* pInfo = &playerInfo[current_race][current_class]; - - pInfo->mapId = mapId; - pInfo->areaId = areaId; - pInfo->positionX = positionX; - pInfo->positionY = positionY; - pInfo->positionZ = positionZ; - - pInfo->displayId_m = rEntry->model_m; - pInfo->displayId_f = rEntry->model_f; - - bar.step(); - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u player create definitions", count); - } - - // Load playercreate items - sLog.outString("Loading Player Create Items Data..."); - { - // 0 1 2 3 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT race, class, itemid, amount FROM playercreateinfo_item"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u custom player create items", count); - } - else - { - barGoLink bar(result->GetRowCount()); - - do - { - Field* fields = result->Fetch(); - - uint32 current_race = fields[0].GetUInt32(); - if (current_race >= MAX_RACES) - { - sLog.outErrorDb("Wrong race %u in `playercreateinfo_item` table, ignoring.",current_race); - continue; - } - - uint32 current_class = fields[1].GetUInt32(); - if (current_class >= MAX_CLASSES) - { - sLog.outErrorDb("Wrong class %u in `playercreateinfo_item` table, ignoring.",current_class); - continue; - } - - PlayerInfo* pInfo = &playerInfo[current_race][current_class]; - - uint32 item_id = fields[2].GetUInt32(); - - if (!GetItemPrototype(item_id)) - { - sLog.outErrorDb("Item id %u (race %u class %u) in `playercreateinfo_item` table but not listed in `item_template`, ignoring.",item_id,current_race,current_class); - continue; - } - - uint32 amount = fields[3].GetUInt32(); - - if (!amount) - { - sLog.outErrorDb("Item id %u (class %u race %u) have amount == 0 in `playercreateinfo_item` table, ignoring.",item_id,current_race,current_class); - continue; - } - - pInfo->item.push_back(PlayerCreateInfoItem(item_id, amount)); - - bar.step(); - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u custom player create items", count); - } - } - - // Load playercreate spells - sLog.outString("Loading Player Create Spell Data..."); - { - - QueryResult_AutoPtr result = QueryResult_AutoPtr(NULL); - if (sWorld.getConfig(CONFIG_START_ALL_SPELLS)) - result = WorldDatabase.Query("SELECT race, class, Spell, Active FROM playercreateinfo_spell_custom"); - else - result = WorldDatabase.Query("SELECT race, class, Spell FROM playercreateinfo_spell"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - - sLog.outString(); - sLog.outString(">> Loaded %u player create spells", count); - sLog.outErrorDb("Error loading player starting spells or empty table."); - } - else - { - barGoLink bar(result->GetRowCount()); - - do - { - Field* fields = result->Fetch(); - - uint32 current_race = fields[0].GetUInt32(); - if (current_race >= MAX_RACES) - { - sLog.outErrorDb("Wrong race %u in `playercreateinfo_spell` table, ignoring.",current_race); - continue; - } - - uint32 current_class = fields[1].GetUInt32(); - if (current_class >= MAX_CLASSES) - { - sLog.outErrorDb("Wrong class %u in `playercreateinfo_spell` table, ignoring.",current_class); - continue; - } - - if (!current_race || !current_class) - { - uint32 min_race = current_race ? current_race : 1; - uint32 max_race = current_race ? current_race + 1 : MAX_RACES; - uint32 min_class = current_class ? current_class : 1; - uint32 max_class = current_class ? current_class + 1 : MAX_CLASSES; - for (uint32 r = min_race; r < max_race; ++r) - for (uint32 c = min_class; c < max_class; ++c) - playerInfo[r][c].spell.push_back(fields[2].GetUInt32()); - } - else - playerInfo[current_race][current_class].spell.push_back(fields[2].GetUInt32()); - - bar.step(); - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u player create spells", count); - } - } - - // Load playercreate actions - sLog.outString("Loading Player Create Action Data..."); - { - // 0 1 2 3 4 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT race, class, button, action, type FROM playercreateinfo_action"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - - sLog.outString(); - sLog.outString(">> Loaded %u player create actions", count); - sLog.outErrorDb("Error loading `playercreateinfo_action` table or empty table."); - } - else - { - barGoLink bar(result->GetRowCount()); - - do - { - Field* fields = result->Fetch(); - - uint32 current_race = fields[0].GetUInt32(); - if (current_race >= MAX_RACES) - { - sLog.outErrorDb("Wrong race %u in `playercreateinfo_action` table, ignoring.",current_race); - continue; - } - - uint32 current_class = fields[1].GetUInt32(); - if (current_class >= MAX_CLASSES) - { - sLog.outErrorDb("Wrong class %u in `playercreateinfo_action` table, ignoring.",current_class); - continue; - } - - PlayerInfo* pInfo = &playerInfo[current_race][current_class]; - pInfo->action.push_back(PlayerCreateInfoAction(fields[2].GetUInt8(),fields[3].GetUInt32(),fields[4].GetUInt8())); - - bar.step(); - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u player create actions", count); - } - } - - // Loading levels data (class only dependent) - sLog.outString("Loading Player Create Level HP/Mana Data..."); - { - // 0 1 2 3 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT class, level, basehp, basemana FROM player_classlevelstats"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - - sLog.outString(); - sLog.outString(">> Loaded %u level health/mana definitions", count); - sLog.outErrorDb("Error loading `player_classlevelstats` table or empty table."); - exit(1); - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field* fields = result->Fetch(); - - uint32 current_class = fields[0].GetUInt32(); - if (current_class >= MAX_CLASSES) - { - sLog.outErrorDb("Wrong class %u in `player_classlevelstats` table, ignoring.",current_class); - continue; - } - - uint8 current_level = fields[1].GetUInt8(); - if (current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum - sLog.outErrorDb("Wrong (> %u) level %u in `player_classlevelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level); - else - { - sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `player_classlevelstats` table, ignoring.",current_level); - ++count; // make result loading percent "expected" correct in case disabled detail mode for example. - } - continue; - } - - PlayerClassInfo* pClassInfo = &playerClassInfo[current_class]; - - if (!pClassInfo->levelInfo) - pClassInfo->levelInfo = new PlayerClassLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)]; - - PlayerClassLevelInfo* pClassLevelInfo = &pClassInfo->levelInfo[current_level-1]; - - pClassLevelInfo->basehealth = fields[2].GetUInt16(); - pClassLevelInfo->basemana = fields[3].GetUInt16(); - - bar.step(); - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u level health/mana definitions", count); - } - - // Fill gaps and check integrity - for (int class_ = 0; class_ < MAX_CLASSES; ++class_) - { - // skip non existed classes - if (!sChrClassesStore.LookupEntry(class_)) - continue; - - PlayerClassInfo* pClassInfo = &playerClassInfo[class_]; - - // fatal error if no level 1 data - if (!pClassInfo->levelInfo || pClassInfo->levelInfo[0].basehealth == 0) - { - sLog.outErrorDb("Class %i Level 1 does not have health/mana data!",class_); - exit(1); - } - - // fill level gaps - for (uint8 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) - { - if (pClassInfo->levelInfo[level].basehealth == 0) - { - sLog.outErrorDb("Class %i Level %i does not have health/mana data. Using stats data of level %i.",class_,level+1, level); - pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level-1]; - } - } - } - - // Loading levels data (class/race dependent) - sLog.outString("Loading Player Create Level Stats Data..."); - { - // 0 1 2 3 4 5 6 7 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT race, class, level, str, agi, sta, inte, spi FROM player_levelstats"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - - sLog.outString(); - sLog.outString(">> Loaded %u level stats definitions", count); - sLog.outErrorDb("Error loading `player_levelstats` table or empty table."); - exit(1); - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field* fields = result->Fetch(); - - uint32 current_race = fields[0].GetUInt32(); - if (current_race >= MAX_RACES) - { - sLog.outErrorDb("Wrong race %u in `player_levelstats` table, ignoring.",current_race); - continue; - } - - uint32 current_class = fields[1].GetUInt32(); - if (current_class >= MAX_CLASSES) - { - sLog.outErrorDb("Wrong class %u in `player_levelstats` table, ignoring.",current_class); - continue; - } - - uint32 current_level = fields[2].GetUInt32(); - if (current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum - sLog.outErrorDb("Wrong (> %u) level %u in `player_levelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level); - else - { - sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `player_levelstats` table, ignoring.",current_level); - ++count; // make result loading percent "expected" correct in case disabled detail mode for example. - } - continue; - } - - PlayerInfo* pInfo = &playerInfo[current_race][current_class]; - - if (!pInfo->levelInfo) - pInfo->levelInfo = new PlayerLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)]; - - PlayerLevelInfo* pLevelInfo = &pInfo->levelInfo[current_level-1]; - - for (int i = 0; i < MAX_STATS; i++) - { - pLevelInfo->stats[i] = fields[i+3].GetUInt8(); - } - - bar.step(); - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u level stats definitions", count); - } - - // Fill gaps and check integrity - for (int race = 0; race < MAX_RACES; ++race) - { - // skip non existed races - if (!sChrRacesStore.LookupEntry(race)) - continue; - - for (int class_ = 0; class_ < MAX_CLASSES; ++class_) - { - // skip non existed classes - if (!sChrClassesStore.LookupEntry(class_)) - continue; - - PlayerInfo* pInfo = &playerInfo[race][class_]; - - // skip non loaded combinations - if (!pInfo->displayId_m || !pInfo->displayId_f) - continue; - - // skip expansion races if not playing with expansion - if (sWorld.getConfig(CONFIG_EXPANSION) < 1 && (race == RACE_BLOODELF || race == RACE_DRAENEI)) - continue; - - // skip expansion classes if not playing with expansion - if (sWorld.getConfig(CONFIG_EXPANSION) < 2 && class_ == CLASS_DEATH_KNIGHT) - continue; - - // fatal error if no level 1 data - if (!pInfo->levelInfo || pInfo->levelInfo[0].stats[0] == 0) - { - sLog.outErrorDb("Race %i Class %i Level 1 does not have stats data!",race,class_); - exit(1); - } - - // fill level gaps - for (uint8 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) - { - if (pInfo->levelInfo[level].stats[0] == 0) - { - sLog.outErrorDb("Race %i Class %i Level %i does not have stats data. Using stats data of level %i.",race,class_,level+1, level); - pInfo->levelInfo[level] = pInfo->levelInfo[level-1]; - } - } - } - } - - // Loading xp per level data - sLog.outString("Loading Player Create XP Data..."); - { - mPlayerXPperLevel.resize(sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)); - for (uint8 level = 0; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) - mPlayerXPperLevel[level] = 0; - - // 0 1 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT lvl, xp_for_next_level FROM player_xp_for_level"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - - sLog.outString(); - sLog.outString(">> Loaded %u xp for level definitions", count); - sLog.outErrorDb("Error loading `player_xp_for_level` table or empty table."); - exit(1); - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field* fields = result->Fetch(); - - uint32 current_level = fields[0].GetUInt32(); - uint32 current_xp = fields[1].GetUInt32(); - - if (current_level >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum - sLog.outErrorDb("Wrong (> %u) level %u in `player_xp_for_level` table, ignoring.", STRONG_MAX_LEVEL,current_level); - else - { - sLog.outDetail("Unused (> MaxPlayerLevel in TrinityCore.conf) level %u in `player_xp_for_levels` table, ignoring.",current_level); - ++count; // make result loading percent "expected" correct in case disabled detail mode for example. - } - continue; - } - //PlayerXPperLevel - mPlayerXPperLevel[current_level] = current_xp; - bar.step(); - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u xp for level definitions", count); - } - - // fill level gaps - for (uint8 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) - { - if (mPlayerXPperLevel[level] == 0) - { - sLog.outErrorDb("Level %i does not have XP for level data. Using data of level [%i] + 100.",level+1, level); - mPlayerXPperLevel[level] = mPlayerXPperLevel[level-1]+100; - } - } -} - -void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint8 level, PlayerClassLevelInfo* info) const -{ - if (level < 1 || class_ >= MAX_CLASSES) - return; - - PlayerClassInfo const* pInfo = &playerClassInfo[class_]; - - if (level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); - - *info = pInfo->levelInfo[level-1]; -} - -void ObjectMgr::GetPlayerLevelInfo(uint32 race, uint32 class_, uint8 level, PlayerLevelInfo* info) const -{ - if (level < 1 || race >= MAX_RACES || class_ >= MAX_CLASSES) - return; - - PlayerInfo const* pInfo = &playerInfo[race][class_]; - if (pInfo->displayId_m == 0 || pInfo->displayId_f == 0) - return; - - if (level <= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - *info = pInfo->levelInfo[level-1]; - else - BuildPlayerLevelInfo(race,class_,level,info); -} - -void ObjectMgr::BuildPlayerLevelInfo(uint8 race, uint8 _class, uint8 level, PlayerLevelInfo* info) const -{ - // base data (last known level) - *info = playerInfo[race][_class].levelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)-1]; - - // if conversion from uint32 to uint8 causes unexpected behaviour, change lvl to uint32 - for (uint8 lvl = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)-1; lvl < level; ++lvl) - { - switch(_class) - { - case CLASS_WARRIOR: - info->stats[STAT_STRENGTH] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0)); - info->stats[STAT_STAMINA] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0)); - info->stats[STAT_AGILITY] += (lvl > 36 ? 1: (lvl > 6 && (lvl%2) ? 1: 0)); - info->stats[STAT_INTELLECT] += (lvl > 9 && !(lvl%2) ? 1: 0); - info->stats[STAT_SPIRIT] += (lvl > 9 && !(lvl%2) ? 1: 0); - break; - case CLASS_PALADIN: - info->stats[STAT_STRENGTH] += (lvl > 3 ? 1: 0); - info->stats[STAT_STAMINA] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0)); - info->stats[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 7 && !(lvl%2) ? 1: 0)); - info->stats[STAT_INTELLECT] += (lvl > 6 && (lvl%2) ? 1: 0); - info->stats[STAT_SPIRIT] += (lvl > 7 ? 1: 0); - break; - case CLASS_HUNTER: - info->stats[STAT_STRENGTH] += (lvl > 4 ? 1: 0); - info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0); - info->stats[STAT_AGILITY] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0)); - info->stats[STAT_INTELLECT] += (lvl > 8 && (lvl%2) ? 1: 0); - info->stats[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0)); - break; - case CLASS_ROGUE: - info->stats[STAT_STRENGTH] += (lvl > 5 ? 1: 0); - info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0); - info->stats[STAT_AGILITY] += (lvl > 16 ? 2: (lvl > 1 ? 1: 0)); - info->stats[STAT_INTELLECT] += (lvl > 8 && !(lvl%2) ? 1: 0); - info->stats[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0)); - break; - case CLASS_PRIEST: - info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0); - info->stats[STAT_STAMINA] += (lvl > 5 ? 1: 0); - info->stats[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 8 && (lvl%2) ? 1: 0)); - info->stats[STAT_INTELLECT] += (lvl > 22 ? 2: (lvl > 1 ? 1: 0)); - info->stats[STAT_SPIRIT] += (lvl > 3 ? 1: 0); - break; - case CLASS_SHAMAN: - info->stats[STAT_STRENGTH] += (lvl > 34 ? 1: (lvl > 6 && (lvl%2) ? 1: 0)); - info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0); - info->stats[STAT_AGILITY] += (lvl > 7 && !(lvl%2) ? 1: 0); - info->stats[STAT_INTELLECT] += (lvl > 5 ? 1: 0); - info->stats[STAT_SPIRIT] += (lvl > 4 ? 1: 0); - break; - case CLASS_MAGE: - info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0); - info->stats[STAT_STAMINA] += (lvl > 5 ? 1: 0); - info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0); - info->stats[STAT_INTELLECT] += (lvl > 24 ? 2: (lvl > 1 ? 1: 0)); - info->stats[STAT_SPIRIT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0)); - break; - case CLASS_WARLOCK: - info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0); - info->stats[STAT_STAMINA] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0)); - info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0); - info->stats[STAT_INTELLECT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0)); - info->stats[STAT_SPIRIT] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0)); - break; - case CLASS_DRUID: - info->stats[STAT_STRENGTH] += (lvl > 38 ? 2: (lvl > 6 && (lvl%2) ? 1: 0)); - info->stats[STAT_STAMINA] += (lvl > 32 ? 2: (lvl > 4 ? 1: 0)); - info->stats[STAT_AGILITY] += (lvl > 38 ? 2: (lvl > 8 && (lvl%2) ? 1: 0)); - info->stats[STAT_INTELLECT] += (lvl > 38 ? 3: (lvl > 4 ? 1: 0)); - info->stats[STAT_SPIRIT] += (lvl > 38 ? 3: (lvl > 5 ? 1: 0)); - } - } -} - -void ObjectMgr::LoadGuilds() -{ - Guild *newGuild; - uint32 count = 0; - - // 0 1 2 3 4 5 6 - QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT guild.guildid,guild.name,leaderguid,EmblemStyle,EmblemColor,BorderStyle,BorderColor," - // 7 8 9 10 11 12 - "BackgroundColor,info,motd,createdate,BankMoney,COUNT(guild_bank_tab.guildid) " - "FROM guild LEFT JOIN guild_bank_tab ON guild.guildid = guild_bank_tab.guildid GROUP BY guild.guildid ORDER BY guildid ASC"); - - if (!result) - { - - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u guild definitions", count); - return; - } - - // load guild ranks - // 0 1 2 3 4 - QueryResult_AutoPtr guildRanksResult = CharacterDatabase.Query("SELECT guildid,rid,rname,rights,BankMoneyPerDay FROM guild_rank ORDER BY guildid ASC, rid ASC"); - - // load guild members - // 0 1 2 3 4 5 6 - QueryResult_AutoPtr guildMembersResult = CharacterDatabase.Query("SELECT guildid,guild_member.guid,rank,pnote,offnote,BankResetTimeMoney,BankRemMoney," - // 7 8 9 10 11 12 - "BankResetTimeTab0,BankRemSlotsTab0,BankResetTimeTab1,BankRemSlotsTab1,BankResetTimeTab2,BankRemSlotsTab2," - // 13 14 15 16 17 18 - "BankResetTimeTab3,BankRemSlotsTab3,BankResetTimeTab4,BankRemSlotsTab4,BankResetTimeTab5,BankRemSlotsTab5," - // 19 20 21 22 23 - "characters.name, characters.level, characters.class, characters.zone, characters.logout_time " - "FROM guild_member LEFT JOIN characters ON characters.guid = guild_member.guid ORDER BY guildid ASC"); - - // load guild bank tab rights - // 0 1 2 3 4 - QueryResult_AutoPtr guildBankTabRightsResult = CharacterDatabase.Query("SELECT guildid,TabId,rid,gbright,SlotPerDay FROM guild_bank_right ORDER BY guildid ASC, TabId ASC"); - - barGoLink bar(result->GetRowCount()); - - do - { - //Field *fields = result->Fetch(); - - bar.step(); - ++count; - - newGuild = new Guild; - if (!newGuild->LoadGuildFromDB(result) || - !newGuild->LoadRanksFromDB(guildRanksResult) || - !newGuild->LoadMembersFromDB(guildMembersResult) || - !newGuild->LoadBankRightsFromDB(guildBankTabRightsResult) || - !newGuild->CheckGuildStructure() -) - { - newGuild->Disband(); - delete newGuild; - continue; - } - newGuild->LoadGuildEventLogFromDB(); - newGuild->LoadGuildBankEventLogFromDB(); - newGuild->LoadGuildBankFromDB(); - AddGuild(newGuild); - - } while (result->NextRow()); - - //delete unused LogGuid records in guild_eventlog and guild_bank_eventlog table - //you can comment these lines if you don't plan to change CONFIG_GUILD_EVENT_LOG_COUNT and CONFIG_GUILD_BANK_EVENT_LOG_COUNT - CharacterDatabase.PQuery("DELETE FROM guild_eventlog WHERE LogGuid > '%u'", sWorld.getConfig(CONFIG_GUILD_EVENT_LOG_COUNT)); - CharacterDatabase.PQuery("DELETE FROM guild_bank_eventlog WHERE LogGuid > '%u'", sWorld.getConfig(CONFIG_GUILD_BANK_EVENT_LOG_COUNT)); - - sLog.outString(); - sLog.outString(">> Loaded %u guild definitions", count); -} - -void ObjectMgr::LoadArenaTeams() -{ - uint32 count = 0; - - // 0 1 2 3 4 5 - QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT arena_team.arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle," - // 6 7 8 9 10 11 12 13 14 - "EmblemColor,BorderStyle,BorderColor, rating,games,wins,played,wins2,rank " - "FROM arena_team LEFT JOIN arena_team_stats ON arena_team.arenateamid = arena_team_stats.arenateamid ORDER BY arena_team.arenateamid ASC"); - - if (!result) - { - - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u arenateam definitions", count); - return; - } - - // load arena_team members - QueryResult_AutoPtr arenaTeamMembersResult = CharacterDatabase.Query( - // 0 1 2 3 4 5 6 7 8 - "SELECT arenateamid,member.guid,played_week,wons_week,played_season,wons_season,personal_rating,name,class " - "FROM arena_team_member member LEFT JOIN characters chars on member.guid = chars.guid ORDER BY member.arenateamid ASC"); - - barGoLink bar(result->GetRowCount()); - - do - { - //Field *fields = result->Fetch(); - - bar.step(); - ++count; - - ArenaTeam *newArenaTeam = new ArenaTeam; - if (!newArenaTeam->LoadArenaTeamFromDB(result) || - !newArenaTeam->LoadMembersFromDB(arenaTeamMembersResult)) - { - newArenaTeam->Disband(NULL); - delete newArenaTeam; - continue; - } - AddArenaTeam(newArenaTeam); - }while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u arenateam definitions", count); -} - -void ObjectMgr::LoadGroups() -{ - Group *group = NULL; - Field *fields = NULL; - uint64 groupGuid = 0; - uint32 count = 0; - - // Consistency cleaning before load to avoid having to do some checks later - // Delete all members that does not exist - CharacterDatabase.PExecute("DELETE FROM group_member WHERE NOT EXISTS (SELECT guid FROM characters WHERE guid=memberGuid)"); - // Delete all groups whose leader does not exist - CharacterDatabase.PExecute("DELETE FROM groups WHERE NOT EXISTS (SELECT guid FROM characters WHERE guid=leaderGuid)"); - // Delete all groups with less than 2 members - CharacterDatabase.PExecute("DELETE FROM groups WHERE guid NOT IN (SELECT guid FROM group_member GROUP BY guid HAVING COUNT(guid) > 1)"); - // Delete all rows from group_member or group_instance with no group - CharacterDatabase.PExecute("DELETE FROM group_member WHERE guid NOT IN (SELECT guid FROM groups)"); - CharacterDatabase.PExecute("DELETE FROM group_instance WHERE guid NOT IN (SELECT guid FROM groups)"); - - // ----------------------- Load Group definitions - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT leaderGuid, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, groupType, difficulty, raiddifficulty, guid FROM groups"); - if (!result) - { - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded 0 group definitions"); - return; - } - - barGoLink bar(result->GetRowCount()); - do - { - bar.step(); - fields = result->Fetch(); - ++count; - group = new Group; - groupGuid = MAKE_NEW_GUID(fields[15].GetUInt32(),0,HIGHGUID_GROUP); - group->LoadGroupFromDB(groupGuid, result, false); - // group load will never be false (we have run consistency sql's before loading) - AddGroup(group); - }while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u group definitions", count); - - // ----------------------- Load member - // 0 1 2 3 - result = CharacterDatabase.Query("SELECT guid, memberGuid, memberFlags, subgroup FROM group_member ORDER BY guid"); - if (!result) - { - barGoLink bar2(1); - bar2.step(); - sLog.outString(); - sLog.outString(">> Loaded 0 group members"); - return; - } - - barGoLink bar2(result->GetRowCount()); - uint32 groupLowGuid = 0; - count = 0; - do - { - bar2.step(); - fields = result->Fetch(); - - if (groupLowGuid != fields[0].GetUInt32()) - { - groupLowGuid = fields[0].GetUInt32(); - groupGuid = MAKE_NEW_GUID(groupLowGuid, 0, HIGHGUID_GROUP); - group = GetGroupByGUID(groupGuid); - // group will never be NULL (we have run consistency sql's before loading) - } - group->LoadMemberFromDB(fields[1].GetUInt32(), fields[2].GetUInt8(), fields[3].GetUInt8()); - ++count; - }while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u group members", count); - - - // ----------------------- Load instance save - // 0 1 2 3 4 5 - result = CharacterDatabase.Query("SELECT guid, map, instance, permanent, difficulty, resettime, " - // 6 - "(SELECT COUNT(1) FROM groups JOIN character_instance ON leaderGuid = groups.guid WHERE instance = group_instance.instance AND permanent = 1 LIMIT 1) " - "FROM group_instance LEFT JOIN instance ON instance = id ORDER BY guid"); - - if (!result) - { - barGoLink bar2(1); - bar2.step(); - sLog.outString(); - sLog.outString(">> Loaded 0 group-instance saves"); - return; - } - - barGoLink bar3(result->GetRowCount()); - count = 0; - do - { - bar3.step(); - fields = result->Fetch(); - groupGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_GROUP); - group = GetGroupByGUID(groupGuid); - // group will never be NULL (we have run consistency sql's before loading) - - MapEntry const* mapEntry = sMapStore.LookupEntry(fields[1].GetUInt32()); - if (!mapEntry || !mapEntry->IsDungeon()) - { - sLog.outErrorDb("Incorrect entry in group_instance table : no dungeon map %d", fields[1].GetUInt32()); - continue; - } - - uint32 diff = fields[4].GetUInt8(); - if (diff >= (mapEntry->IsRaid() ? MAX_RAID_DIFFICULTY : MAX_DUNGEON_DIFFICULTY)) - { - sLog.outErrorDb("Wrong dungeon difficulty use in group_instance table: %d", diff + 1); - diff = 0; // default for both difficaly types - } - - InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapEntry->MapID, fields[2].GetUInt32(), Difficulty(diff), time_t(fields[5].GetUInt64()), fields[6].GetBool(), true); - group->BindToInstance(save, fields[3].GetBool(), true); - ++count; - }while (result->NextRow()); - sLog.outString(); - sLog.outString(">> Loaded %u group-instance saves", count); -} - -void ObjectMgr::LoadQuests() -{ - // For reload case - for (QuestMap::const_iterator itr=mQuestTemplates.begin(); itr != mQuestTemplates.end(); ++itr) - delete itr->second; - mQuestTemplates.clear(); - - mExclusiveQuestGroups.clear(); - - // 0 1 2 3 4 5 6 7 8 9 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, Method, ZoneOrSort, SkillOrClassMask, MinLevel, MaxLevel, QuestLevel, Type, RequiredRaces, RequiredSkillValue," - // 10 11 12 13 14 15 16 17 18 19 - "RepObjectiveFaction, RepObjectiveValue, RepObjectiveFaction2, RepObjectiveValue2, RequiredMinRepFaction, RequiredMinRepValue, RequiredMaxRepFaction, RequiredMaxRepValue, SuggestedPlayers, LimitTime," - // 20 21 22 23 24 25 26 27 28 29 30 31 32 33 - "QuestFlags, SpecialFlags, CharTitleId, PlayersSlain, BonusTalents, RewardArenaPoints, PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestInChain, RewXPId, SrcItemId, SrcItemCount, SrcSpell," - // 34 35 36 37 38 39 40 41 42 43 44 - "Title, Details, Objectives, OfferRewardText, RequestItemsText, EndText, CompletedText, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4," - // 45 46 47 48 49 50 51 52 53 54 55 56 - "ReqItemId1, ReqItemId2, ReqItemId3, ReqItemId4, ReqItemId5, ReqItemId6, ReqItemCount1, ReqItemCount2, ReqItemCount3, ReqItemCount4, ReqItemCount5, ReqItemCount6," - // 57 58 59 60 61 62 63 64 - "ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4," - // 65 66 67 68 69 70 71 72 - "ReqCreatureOrGOId1, ReqCreatureOrGOId2, ReqCreatureOrGOId3, ReqCreatureOrGOId4, ReqCreatureOrGOCount1, ReqCreatureOrGOCount2, ReqCreatureOrGOCount3, ReqCreatureOrGOCount4," - // 73 74 75 76 - "ReqSpellCast1, ReqSpellCast2, ReqSpellCast3, ReqSpellCast4," - // 77 78 79 80 81 82 - "RewChoiceItemId1, RewChoiceItemId2, RewChoiceItemId3, RewChoiceItemId4, RewChoiceItemId5, RewChoiceItemId6," - // 83 84 85 86 87 88 - "RewChoiceItemCount1, RewChoiceItemCount2, RewChoiceItemCount3, RewChoiceItemCount4, RewChoiceItemCount5, RewChoiceItemCount6," - // 89 90 91 92 93 94 95 96 - "RewItemId1, RewItemId2, RewItemId3, RewItemId4, RewItemCount1, RewItemCount2, RewItemCount3, RewItemCount4," - // 97 98 99 100 101 102 103 104 105 106 - "RewRepFaction1, RewRepFaction2, RewRepFaction3, RewRepFaction4, RewRepFaction5, RewRepValueId1, RewRepValueId2, RewRepValueId3, RewRepValueId4, RewRepValueId5," - // 107 108 109 110 111 - "RewRepValue1, RewRepValue2, RewRepValue3, RewRepValue4, RewRepValue5," - // 112 113 114 115 116 117 118 119 120 121 122 123 - "RewHonorAddition, RewHonorMultiplier, RewOrReqMoney, RewMoneyMaxLevel, RewSpell, RewSpellCast, RewMailTemplateId, RewMailDelaySecs, PointMapId, PointX, PointY, PointOpt," - // 124 125 126 127 128 129 130 131 - "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, DetailsEmoteDelay1, DetailsEmoteDelay2, DetailsEmoteDelay3, DetailsEmoteDelay4," - // 132 133 134 135 136 137 - "IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4," - // 138 139 140 141 - "OfferRewardEmoteDelay1, OfferRewardEmoteDelay2, OfferRewardEmoteDelay3, OfferRewardEmoteDelay4," - // 142 143 - "StartScript, CompleteScript" - " FROM quest_template"); - if (result == NULL) - { - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded 0 quests definitions"); - sLog.outErrorDb("`quest_template` table is empty!"); - return; - } - - // create multimap previous quest for each existed quest - // some quests can have many previous maps set by NextQuestId in previous quest - // for example set of race quests can lead to single not race specific quest - barGoLink bar(result->GetRowCount()); - do - { - bar.step(); - Field *fields = result->Fetch(); - - Quest * newQuest = new Quest(fields); - mQuestTemplates[newQuest->GetQuestId()] = newQuest; - } while (result->NextRow()); - - std::map usedMailTemplates; - - // Post processing - for (QuestMap::iterator iter = mQuestTemplates.begin(); iter != mQuestTemplates.end(); ++iter) - { - Quest * qinfo = iter->second; - - // additional quest integrity checks (GO, creature_template and item_template must be loaded already) - - if (qinfo->GetQuestMethod() >= 3) - { - sLog.outErrorDb("Quest %u has `Method` = %u, expected values are 0, 1 or 2.",qinfo->GetQuestId(),qinfo->GetQuestMethod()); - } - - if (qinfo->QuestFlags & ~QUEST_TRINITY_FLAGS_DB_ALLOWED) - { - sLog.outErrorDb("Quest %u has `SpecialFlags` = %u > max allowed value. Correct `SpecialFlags` to value <= %u", - qinfo->GetQuestId(),qinfo->QuestFlags >> 20, QUEST_TRINITY_FLAGS_DB_ALLOWED >> 20); - qinfo->QuestFlags &= QUEST_TRINITY_FLAGS_DB_ALLOWED; - } - - if (qinfo->QuestFlags & QUEST_FLAGS_DAILY && qinfo->QuestFlags & QUEST_FLAGS_WEEKLY) - { - sLog.outErrorDb("Weekly Quest %u is marked as daily quest in `QuestFlags`, removed daily flag.",qinfo->GetQuestId()); - qinfo->QuestFlags &= ~QUEST_FLAGS_DAILY; - } - - if (qinfo->QuestFlags & QUEST_FLAGS_DAILY) - { - if (!(qinfo->QuestFlags & QUEST_TRINITY_FLAGS_REPEATABLE)) - { - sLog.outErrorDb("Daily Quest %u not marked as repeatable in `SpecialFlags`, added.",qinfo->GetQuestId()); - qinfo->QuestFlags |= QUEST_TRINITY_FLAGS_REPEATABLE; - } - } - - if (qinfo->QuestFlags & QUEST_FLAGS_WEEKLY) - { - if (!(qinfo->QuestFlags & QUEST_TRINITY_FLAGS_REPEATABLE)) - { - sLog.outErrorDb("Weekly Quest %u not marked as repeatable in `SpecialFlags`, added.",qinfo->GetQuestId()); - qinfo->QuestFlags |= QUEST_TRINITY_FLAGS_REPEATABLE; - } - } - - if (qinfo->QuestFlags & QUEST_FLAGS_AUTO_REWARDED) - { - // at auto-reward can be rewarded only RewChoiceItemId[0] - for (int j = 1; j < QUEST_REWARD_CHOICES_COUNT; ++j ) - { - if (uint32 id = qinfo->RewChoiceItemId[j]) - { - sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item from `RewChoiceItemId%d` can't be rewarded with quest flag QUEST_FLAGS_AUTO_REWARDED.", - qinfo->GetQuestId(),j+1,id,j+1); - // no changes, quest ignore this data - } - } - } - - // client quest log visual (area case) - if (qinfo->ZoneOrSort > 0) - { - if (!GetAreaEntryByAreaID(qinfo->ZoneOrSort)) - { - sLog.outErrorDb("Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.", - qinfo->GetQuestId(),qinfo->ZoneOrSort); - // no changes, quest not dependent from this value but can have problems at client - } - } - // client quest log visual (sort case) - if (qinfo->ZoneOrSort < 0) - { - QuestSortEntry const* qSort = sQuestSortStore.LookupEntry(-int32(qinfo->ZoneOrSort)); - if (!qSort) - { - sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (sort case) but quest sort with this id does not exist.", - qinfo->GetQuestId(),qinfo->ZoneOrSort); - // no changes, quest not dependent from this value but can have problems at client (note some may be 0, we must allow this so no check) - } - //check SkillOrClass value (class case). - if (ClassByQuestSort(-int32(qinfo->ZoneOrSort))) - { - // SkillOrClass should not have class case when class case already set in ZoneOrSort. - if (qinfo->SkillOrClassMask < 0) - { - sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (class sort case) and `SkillOrClassMask` = %i (class case), redundant.", - qinfo->GetQuestId(),qinfo->ZoneOrSort,qinfo->SkillOrClassMask); - } - } - //check for proper SkillOrClass value (skill case) - if (int32 skill_id = SkillByQuestSort(-int32(qinfo->ZoneOrSort))) - { - // skill is positive value in SkillOrClass - if (qinfo->SkillOrClassMask != skill_id) - { - sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (skill sort case) but `SkillOrClassMask` does not have a corresponding value (%i).", - qinfo->GetQuestId(),qinfo->ZoneOrSort,skill_id); - //override, and force proper value here? - } - } - } - - // SkillOrClassMask (class case) - if (qinfo->SkillOrClassMask < 0) - { - if (!(-int32(qinfo->SkillOrClassMask) & CLASSMASK_ALL_PLAYABLE)) - { - sLog.outErrorDb("Quest %u has `SkillOrClassMask` = %i (class case) but classmask does not have valid class", - qinfo->GetQuestId(),qinfo->SkillOrClassMask); - } - } - // SkillOrClassMask (skill case) - if (qinfo->SkillOrClassMask > 0) - { - if (!sSkillLineStore.LookupEntry(qinfo->SkillOrClassMask)) - { - sLog.outErrorDb("Quest %u has `SkillOrClass` = %u (skill case) but skill (%i) does not exist", - qinfo->GetQuestId(),qinfo->SkillOrClassMask,qinfo->SkillOrClassMask); - } - } - - if (qinfo->RequiredSkillValue) - { - if (qinfo->RequiredSkillValue > sWorld.GetConfigMaxSkillValue()) - { - sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but max possible skill is %u, quest can't be done.", - qinfo->GetQuestId(),qinfo->RequiredSkillValue,sWorld.GetConfigMaxSkillValue()); - // no changes, quest can't be done for this requirement - } - - if (qinfo->SkillOrClassMask <= 0) - { - sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but `SkillOrClass` = %i (class case), value ignored.", - qinfo->GetQuestId(),qinfo->RequiredSkillValue,qinfo->SkillOrClassMask); - // no changes, quest can't be done for this requirement (fail at wrong skill id) - } - } - // else Skill quests can have 0 skill level, this is ok - - if (qinfo->RepObjectiveFaction2 && !sFactionStore.LookupEntry(qinfo->RepObjectiveFaction2)) - { - sLog.outErrorDb("Quest %u has `RepObjectiveFaction2` = %u but faction template %u does not exist, quest can't be done.", - qinfo->GetQuestId(),qinfo->RepObjectiveFaction2,qinfo->RepObjectiveFaction2); - // no changes, quest can't be done for this requirement - } - - if (qinfo->RepObjectiveFaction && !sFactionStore.LookupEntry(qinfo->RepObjectiveFaction)) - { - sLog.outErrorDb("Quest %u has `RepObjectiveFaction` = %u but faction template %u does not exist, quest can't be done.", - qinfo->GetQuestId(),qinfo->RepObjectiveFaction,qinfo->RepObjectiveFaction); - // no changes, quest can't be done for this requirement - } - - if (qinfo->RequiredMinRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMinRepFaction)) - { - sLog.outErrorDb("Quest %u has `RequiredMinRepFaction` = %u but faction template %u does not exist, quest can't be done.", - qinfo->GetQuestId(),qinfo->RequiredMinRepFaction,qinfo->RequiredMinRepFaction); - // no changes, quest can't be done for this requirement - } - - if (qinfo->RequiredMaxRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMaxRepFaction)) - { - sLog.outErrorDb("Quest %u has `RequiredMaxRepFaction` = %u but faction template %u does not exist, quest can't be done.", - qinfo->GetQuestId(),qinfo->RequiredMaxRepFaction,qinfo->RequiredMaxRepFaction); - // no changes, quest can't be done for this requirement - } - - if (qinfo->RequiredMinRepValue && qinfo->RequiredMinRepValue > ReputationMgr::Reputation_Cap) - { - sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but max reputation is %u, quest can't be done.", - qinfo->GetQuestId(),qinfo->RequiredMinRepValue,ReputationMgr::Reputation_Cap); - // no changes, quest can't be done for this requirement - } - - if (qinfo->RequiredMinRepValue && qinfo->RequiredMaxRepValue && qinfo->RequiredMaxRepValue <= qinfo->RequiredMinRepValue) - { - sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d and `RequiredMinRepValue` = %d, quest can't be done.", - qinfo->GetQuestId(),qinfo->RequiredMaxRepValue,qinfo->RequiredMinRepValue); - // no changes, quest can't be done for this requirement - } - - if (!qinfo->RepObjectiveFaction && qinfo->RepObjectiveValue > 0) - { - sLog.outErrorDb("Quest %u has `RepObjectiveValue` = %d but `RepObjectiveFaction` is 0, value has no effect", - qinfo->GetQuestId(),qinfo->RepObjectiveValue); - // warning - } - - if (!qinfo->RepObjectiveFaction2 && qinfo->RepObjectiveValue2 > 0) - { - sLog.outErrorDb("Quest %u has `RepObjectiveValue2` = %d but `RepObjectiveFaction2` is 0, value has no effect", - qinfo->GetQuestId(),qinfo->RepObjectiveValue2); - // warning - } - - if (!qinfo->RequiredMinRepFaction && qinfo->RequiredMinRepValue > 0) - { - sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but `RequiredMinRepFaction` is 0, value has no effect", - qinfo->GetQuestId(),qinfo->RequiredMinRepValue); - // warning - } - - if (!qinfo->RequiredMaxRepFaction && qinfo->RequiredMaxRepValue > 0) - { - sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d but `RequiredMaxRepFaction` is 0, value has no effect", - qinfo->GetQuestId(),qinfo->RequiredMaxRepValue); - // warning - } - - if (qinfo->CharTitleId && !sCharTitlesStore.LookupEntry(qinfo->CharTitleId)) - { - sLog.outErrorDb("Quest %u has `CharTitleId` = %u but CharTitle Id %u does not exist, quest can't be rewarded with title.", - qinfo->GetQuestId(),qinfo->GetCharTitleId(),qinfo->GetCharTitleId()); - qinfo->CharTitleId = 0; - // quest can't reward this title - } - - if (qinfo->SrcItemId) - { - if (!sItemStorage.LookupEntry(qinfo->SrcItemId)) - { - sLog.outErrorDb("Quest %u has `SrcItemId` = %u but item with entry %u does not exist, quest can't be done.", - qinfo->GetQuestId(),qinfo->SrcItemId,qinfo->SrcItemId); - qinfo->SrcItemId = 0; // quest can't be done for this requirement - } - else if (qinfo->SrcItemCount == 0) - { - sLog.outErrorDb("Quest %u has `SrcItemId` = %u but `SrcItemCount` = 0, set to 1 but need fix in DB.", - qinfo->GetQuestId(),qinfo->SrcItemId); - qinfo->SrcItemCount = 1; // update to 1 for allow quest work for backward compatibility with DB - } - } - else if (qinfo->SrcItemCount>0) - { - sLog.outErrorDb("Quest %u has `SrcItemId` = 0 but `SrcItemCount` = %u, useless value.", - qinfo->GetQuestId(),qinfo->SrcItemCount); - qinfo->SrcItemCount=0; // no quest work changes in fact - } - - if (qinfo->SrcSpell) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->SrcSpell); - if (!spellInfo) - { - sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u doesn't exist, quest can't be done.", - qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell); - qinfo->SrcSpell = 0; // quest can't be done for this requirement - } - else if (!SpellMgr::IsSpellValid(spellInfo)) - { - sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u is broken, quest can't be done.", - qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell); - qinfo->SrcSpell = 0; // quest can't be done for this requirement - } - } - - for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j) - { - uint32 id = qinfo->ReqItemId[j]; - if (id) - { - if (qinfo->ReqItemCount[j] == 0) - { - sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but `ReqItemCount%d` = 0, quest can't be done.", - qinfo->GetQuestId(),j+1,id,j+1); - // no changes, quest can't be done for this requirement - } - - qinfo->SetFlag(QUEST_TRINITY_FLAGS_DELIVER); - - if (!sItemStorage.LookupEntry(id)) - { - sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but item with entry %u does not exist, quest can't be done.", - qinfo->GetQuestId(),j+1,id,id); - qinfo->ReqItemCount[j] = 0; // prevent incorrect work of quest - } - } - else if (qinfo->ReqItemCount[j]>0) - { - sLog.outErrorDb("Quest %u has `ReqItemId%d` = 0 but `ReqItemCount%d` = %u, quest can't be done.", - qinfo->GetQuestId(),j+1,j+1,qinfo->ReqItemCount[j]); - qinfo->ReqItemCount[j] = 0; // prevent incorrect work of quest - } - } - - for (uint8 j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j) - { - uint32 id = qinfo->ReqSourceId[j]; - if (id) - { - if (!sItemStorage.LookupEntry(id)) - { - sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but item with entry %u does not exist, quest can't be done.", - qinfo->GetQuestId(),j+1,id,id); - // no changes, quest can't be done for this requirement - } - } - else - { - if (qinfo->ReqSourceCount[j]>0) - { - sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceCount%d` = %u.", - qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceCount[j]); - // no changes, quest ignore this data - } - } - } - - for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j) - { - uint32 id = qinfo->ReqSpell[j]; - if (id) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(id); - if (!spellInfo) - { - sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u but spell %u does not exist, quest can't be done.", - qinfo->GetQuestId(),j+1,id,id); - continue; - } - - if (!qinfo->ReqCreatureOrGOId[j]) - { - bool found = false; - for (uint8 k = 0; k < 3; ++k) - { - if ((spellInfo->Effect[k] == SPELL_EFFECT_QUEST_COMPLETE && uint32(spellInfo->EffectMiscValue[k]) == qinfo->QuestId) || - spellInfo->Effect[k] == SPELL_EFFECT_SEND_EVENT) - { - found = true; - break; - } - } - - if (found) - { - if (!qinfo->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT)) - { - sLog.outErrorDb("Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT for quest %u and ReqCreatureOrGOId%d = 0, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Quest flags or ReqCreatureOrGOId%d must be fixed, quest modified to enable objective.",spellInfo->Id,qinfo->QuestId,j+1,j+1); - - // this will prevent quest completing without objective - const_cast(qinfo)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT); - } - } - else - { - sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u and ReqCreatureOrGOId%d = 0 but spell %u does not have SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT effect for this quest, quest can't be done.", - qinfo->GetQuestId(),j+1,id,j+1,id); - // no changes, quest can't be done for this requirement - } - } - } - } - - for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j) - { - int32 id = qinfo->ReqCreatureOrGOId[j]; - if (id < 0 && !sGOStorage.LookupEntry(-id)) - { - sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but gameobject %u does not exist, quest can't be done.", - qinfo->GetQuestId(),j+1,id,uint32(-id)); - qinfo->ReqCreatureOrGOId[j] = 0; // quest can't be done for this requirement - } - - if (id > 0 && !sCreatureStorage.LookupEntry(id)) - { - sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but creature with entry %u does not exist, quest can't be done.", - qinfo->GetQuestId(),j+1,id,uint32(id)); - qinfo->ReqCreatureOrGOId[j] = 0; // quest can't be done for this requirement - } - - if (id) - { - // In fact SpeakTo and Kill are quite same: either you can speak to mob:SpeakTo or you can't:Kill/Cast - - qinfo->SetFlag(QUEST_TRINITY_FLAGS_KILL_OR_CAST | QUEST_TRINITY_FLAGS_SPEAKTO); - - if (!qinfo->ReqCreatureOrGOCount[j]) - { - sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %u but `ReqCreatureOrGOCount%d` = 0, quest can't be done.", - qinfo->GetQuestId(),j+1,id,j+1); - // no changes, quest can be incorrectly done, but we already report this - } - } - else if (qinfo->ReqCreatureOrGOCount[j]>0) - { - sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = 0 but `ReqCreatureOrGOCount%d` = %u.", - qinfo->GetQuestId(),j+1,j+1,qinfo->ReqCreatureOrGOCount[j]); - // no changes, quest ignore this data - } - } - - for (uint8 j = 0; j < QUEST_REWARD_CHOICES_COUNT; ++j) - { - uint32 id = qinfo->RewChoiceItemId[j]; - if (id) - { - if (!sItemStorage.LookupEntry(id)) - { - sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.", - qinfo->GetQuestId(),j+1,id,id); - qinfo->RewChoiceItemId[j] = 0; // no changes, quest will not reward this - } - - if (!qinfo->RewChoiceItemCount[j]) - { - sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but `RewChoiceItemCount%d` = 0, quest can't be done.", - qinfo->GetQuestId(),j+1,id,j+1); - // no changes, quest can't be done - } - } - else if (qinfo->RewChoiceItemCount[j]>0) - { - sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = 0 but `RewChoiceItemCount%d` = %u.", - qinfo->GetQuestId(),j+1,j+1,qinfo->RewChoiceItemCount[j]); - // no changes, quest ignore this data - } - } - - for (uint8 j = 0; j < QUEST_REWARDS_COUNT; ++j) - { - uint32 id = qinfo->RewItemId[j]; - if (id) - { - if (!sItemStorage.LookupEntry(id)) - { - sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.", - qinfo->GetQuestId(),j+1,id,id); - qinfo->RewItemId[j] = 0; // no changes, quest will not reward this item - } - - if (!qinfo->RewItemCount[j]) - { - sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but `RewItemCount%d` = 0, quest will not reward this item.", - qinfo->GetQuestId(),j+1,id,j+1); - // no changes - } - } - else if (qinfo->RewItemCount[j]>0) - { - sLog.outErrorDb("Quest %u has `RewItemId%d` = 0 but `RewItemCount%d` = %u.", - qinfo->GetQuestId(),j+1,j+1,qinfo->RewItemCount[j]); - // no changes, quest ignore this data - } - } - - for (uint8 j = 0; j < QUEST_REPUTATIONS_COUNT; ++j) - { - if (qinfo->RewRepFaction[j]) - { - if (abs(qinfo->RewRepValueId[j]) > 9) - { - sLog.outErrorDb("Quest %u has RewRepValueId%d = %i. That is outside the range of valid values (-9 to 9).", qinfo->GetQuestId(), j+1, qinfo->RewRepValueId[j]); - } - if (!sFactionStore.LookupEntry(qinfo->RewRepFaction[j])) - { - sLog.outErrorDb("Quest %u has `RewRepFaction%d` = %u but raw faction (faction.dbc) %u does not exist, quest will not reward reputation for this faction.", qinfo->GetQuestId(),j+1,qinfo->RewRepFaction[j] ,qinfo->RewRepFaction[j]); - qinfo->RewRepFaction[j] = 0; // quest will not reward this - } - } - - - else if (qinfo->RewRepValue[j] != 0) - { - sLog.outErrorDb("Quest %u has `RewRepFaction%d` = 0 but `RewRepValue%d` = %i.", - qinfo->GetQuestId(),j+1,j+1,qinfo->RewRepValue[j]); - // no changes, quest ignore this data - } - } - - - if (qinfo->RewSpell) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpell); - - if (!spellInfo) - { - sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u does not exist, spell removed as display reward.", - qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell); - qinfo->RewSpell = 0; // no spell reward will display for this quest - } - - else if (!SpellMgr::IsSpellValid(spellInfo)) - { - sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is broken, quest will not have a spell reward.", - qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell); - qinfo->RewSpell = 0; // no spell reward will display for this quest - } - - else if (GetTalentSpellCost(qinfo->RewSpell)) - { - sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is talent, quest will not have a spell reward.", - qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell); - qinfo->RewSpell = 0; // no spell reward will display for this quest - } - } - - if (qinfo->RewSpellCast > 0) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpellCast); - - if (!spellInfo) - { - sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u does not exist, quest will not have a spell reward.", - qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast); - qinfo->RewSpellCast = 0; // no spell will be casted on player - } - - else if (!SpellMgr::IsSpellValid(spellInfo)) - { - sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u is broken, quest will not have a spell reward.", - qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast); - qinfo->RewSpellCast = 0; // no spell will be casted on player - } - - else if (GetTalentSpellCost(qinfo->RewSpellCast)) - { - sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is talent, quest will not have a spell reward.", - qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast); - qinfo->RewSpellCast = 0; // no spell will be casted on player - } - } - - if (qinfo->RewMailTemplateId) - { - if (!sMailTemplateStore.LookupEntry(qinfo->RewMailTemplateId)) - { - sLog.outErrorDb("Quest %u has `RewMailTemplateId` = %u but mail template %u does not exist, quest will not have a mail reward.", - qinfo->GetQuestId(),qinfo->RewMailTemplateId,qinfo->RewMailTemplateId); - qinfo->RewMailTemplateId = 0; // no mail will send to player - qinfo->RewMailDelaySecs = 0; // no mail will send to player - } - else if (usedMailTemplates.find(qinfo->RewMailTemplateId) != usedMailTemplates.end()) - { - std::map::const_iterator used_mt_itr = usedMailTemplates.find(qinfo->RewMailTemplateId); - sLog.outErrorDb("Quest %u has `RewMailTemplateId` = %u but mail template %u already used for quest %u, quest will not have a mail reward.", - qinfo->GetQuestId(),qinfo->RewMailTemplateId,qinfo->RewMailTemplateId,used_mt_itr->second); - qinfo->RewMailTemplateId = 0; // no mail will send to player - qinfo->RewMailDelaySecs = 0; // no mail will send to player - } - else - usedMailTemplates[qinfo->RewMailTemplateId] = qinfo->GetQuestId(); - } - - if (qinfo->NextQuestInChain) - { - QuestMap::iterator qNextItr = mQuestTemplates.find(qinfo->NextQuestInChain); - if (qNextItr == mQuestTemplates.end()) - { - sLog.outErrorDb("Quest %u has `NextQuestInChain` = %u but quest %u does not exist, quest chain will not work.", - qinfo->GetQuestId(),qinfo->NextQuestInChain ,qinfo->NextQuestInChain); - qinfo->NextQuestInChain = 0; - } - else - qNextItr->second->prevChainQuests.push_back(qinfo->GetQuestId()); - } - - // fill additional data stores - if (qinfo->PrevQuestId) - { - if (mQuestTemplates.find(abs(qinfo->GetPrevQuestId())) == mQuestTemplates.end()) - { - sLog.outErrorDb("Quest %d has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetPrevQuestId()); - } - else - { - qinfo->prevQuests.push_back(qinfo->PrevQuestId); - } - } - - if (qinfo->NextQuestId) - { - QuestMap::iterator qNextItr = mQuestTemplates.find(abs(qinfo->GetNextQuestId())); - if (qNextItr == mQuestTemplates.end()) - { - sLog.outErrorDb("Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId()); - } - else - { - int32 signedQuestId = qinfo->NextQuestId < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId()); - qNextItr->second->prevQuests.push_back(signedQuestId); - } - } - - if (qinfo->ExclusiveGroup) - mExclusiveQuestGroups.insert(std::pair(qinfo->ExclusiveGroup, qinfo->GetQuestId())); - if (qinfo->LimitTime) - qinfo->SetFlag(QUEST_TRINITY_FLAGS_TIMED); - } - - // check QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE - for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i) - { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(i); - if (!spellInfo) - continue; - - for (uint8 j = 0; j < 3; ++j) - { - if (spellInfo->Effect[j] != SPELL_EFFECT_QUEST_COMPLETE) - continue; - - uint32 quest_id = spellInfo->EffectMiscValue[j]; - - Quest const* quest = GetQuestTemplate(quest_id); - - // some quest referenced in spells not exist (outdated spells) - if (!quest) - continue; - - if (!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT)) - { - sLog.outErrorDb("Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE for quest %u , but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Quest flags must be fixed, quest modified to enable objective.",spellInfo->Id,quest_id); - - // this will prevent quest completing without objective - const_cast(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT); - } - } - } - - sLog.outString(); - sLog.outString(">> Loaded %lu quests definitions", (unsigned long)mQuestTemplates.size()); -} - -void ObjectMgr::LoadQuestLocales() -{ - mQuestLocaleMap.clear(); // need for reload case - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry," - "Title_loc1,Details_loc1,Objectives_loc1,OfferRewardText_loc1,RequestItemsText_loc1,EndText_loc1,CompletedText_loc1,ObjectiveText1_loc1,ObjectiveText2_loc1,ObjectiveText3_loc1,ObjectiveText4_loc1," - "Title_loc2,Details_loc2,Objectives_loc2,OfferRewardText_loc2,RequestItemsText_loc2,EndText_loc2,CompletedText_loc2,ObjectiveText1_loc2,ObjectiveText2_loc2,ObjectiveText3_loc2,ObjectiveText4_loc2," - "Title_loc3,Details_loc3,Objectives_loc3,OfferRewardText_loc3,RequestItemsText_loc3,EndText_loc3,CompletedText_loc3,ObjectiveText1_loc3,ObjectiveText2_loc3,ObjectiveText3_loc3,ObjectiveText4_loc3," - "Title_loc4,Details_loc4,Objectives_loc4,OfferRewardText_loc4,RequestItemsText_loc4,EndText_loc4,CompletedText_loc4,ObjectiveText1_loc4,ObjectiveText2_loc4,ObjectiveText3_loc4,ObjectiveText4_loc4," - "Title_loc5,Details_loc5,Objectives_loc5,OfferRewardText_loc5,RequestItemsText_loc5,EndText_loc5,CompletedText_loc5,ObjectiveText1_loc5,ObjectiveText2_loc5,ObjectiveText3_loc5,ObjectiveText4_loc5," - "Title_loc6,Details_loc6,Objectives_loc6,OfferRewardText_loc6,RequestItemsText_loc6,EndText_loc6,CompletedText_loc6,ObjectiveText1_loc6,ObjectiveText2_loc6,ObjectiveText3_loc6,ObjectiveText4_loc6," - "Title_loc7,Details_loc7,Objectives_loc7,OfferRewardText_loc7,RequestItemsText_loc7,EndText_loc7,CompletedText_loc7,ObjectiveText1_loc7,ObjectiveText2_loc7,ObjectiveText3_loc7,ObjectiveText4_loc7," - "Title_loc8,Details_loc8,Objectives_loc8,OfferRewardText_loc8,RequestItemsText_loc8,EndText_loc8,CompletedText_loc8,ObjectiveText1_loc8,ObjectiveText2_loc8,ObjectiveText3_loc8,ObjectiveText4_loc8" - " FROM locales_quest" -); - - if (!result) - return; - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 entry = fields[0].GetUInt32(); - - QuestLocale& data = mQuestLocaleMap[entry]; - - for (uint8 i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[1+11*(i-1)].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.Title.size() <= idx) - data.Title.resize(idx+1); - - data.Title[idx] = str; - } - } - str = fields[1+11*(i-1)+1].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.Details.size() <= idx) - data.Details.resize(idx+1); - - data.Details[idx] = str; - } - } - str = fields[1+11*(i-1)+2].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.Objectives.size() <= idx) - data.Objectives.resize(idx+1); - - data.Objectives[idx] = str; - } - } - str = fields[1+11*(i-1)+3].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.OfferRewardText.size() <= idx) - data.OfferRewardText.resize(idx+1); - - data.OfferRewardText[idx] = str; - } - } - str = fields[1+11*(i-1)+4].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.RequestItemsText.size() <= idx) - data.RequestItemsText.resize(idx+1); - - data.RequestItemsText[idx] = str; - } - } - str = fields[1+11*(i-1)+5].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.EndText.size() <= idx) - data.EndText.resize(idx+1); - - data.EndText[idx] = str; - } - } - str = fields[1+11*(i-1)+6].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.CompletedText.size() <= idx) - data.CompletedText.resize(idx+1); - - data.CompletedText[idx] = str; - } - } - - for (uint8 k = 0; k < 4; ++k) - { - str = fields[1+11*(i-1)+7+k].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.ObjectiveText[k].size() <= idx) - data.ObjectiveText[k].resize(idx+1); - - data.ObjectiveText[k][idx] = str; - } - } - } - } - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %lu Quest locale strings", (unsigned long)mQuestLocaleMap.size()); -} - -void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename) -{ - if (sWorld.IsScriptScheduled()) // function don't must be called in time scripts use. - return; - - sLog.outString("%s :", tablename); - - scripts.clear(); // need for reload support - - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT id,delay,command,datalong,datalong2,dataint, x, y, z, o FROM %s", tablename); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u script definitions", count); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - bar.step(); - - Field *fields = result->Fetch(); - ScriptInfo tmp; - tmp.id = fields[0].GetUInt32(); - tmp.delay = fields[1].GetUInt32(); - tmp.command = fields[2].GetUInt32(); - tmp.datalong = fields[3].GetUInt32(); - tmp.datalong2 = fields[4].GetUInt32(); - tmp.dataint = fields[5].GetInt32(); - tmp.x = fields[6].GetFloat(); - tmp.y = fields[7].GetFloat(); - tmp.z = fields[8].GetFloat(); - tmp.o = fields[9].GetFloat(); - - // generic command args check - switch (tmp.command) - { - case SCRIPT_COMMAND_TALK: - { - if (tmp.datalong > CHAT_TYPE_WHISPER) - { - sLog.outErrorDb("Table `%s` has invalid talk type (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.datalong,tmp.id); - continue; - } - if (tmp.dataint == 0) - { - sLog.outErrorDb("Table `%s` has invalid talk text id (dataint = %i) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.dataint,tmp.id); - continue; - } - if (tmp.dataint < MIN_DB_SCRIPT_STRING_ID || tmp.dataint >= MAX_DB_SCRIPT_STRING_ID) - { - sLog.outErrorDb("Table `%s` has out of range text id (dataint = %i expected %u-%u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.dataint,MIN_DB_SCRIPT_STRING_ID,MAX_DB_SCRIPT_STRING_ID,tmp.id); - continue; - } - - break; - } - - case SCRIPT_COMMAND_EMOTE: - { - if (!sEmotesStore.LookupEntry(tmp.datalong)) - { - sLog.outErrorDb("Table `%s` has invalid emote id (datalong = %u) in SCRIPT_COMMAND_EMOTE for script id %u",tablename,tmp.datalong,tmp.id); - continue; - } - break; - } - - case SCRIPT_COMMAND_TELEPORT_TO: - { - if (!sMapStore.LookupEntry(tmp.datalong)) - { - sLog.outErrorDb("Table `%s` has invalid map (Id: %u) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.datalong,tmp.id); - continue; - } - - if (!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o)) - { - sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.x,tmp.y,tmp.id); - continue; - } - break; - } - - case SCRIPT_COMMAND_KILL_CREDIT: - { - if (!GetCreatureTemplate(tmp.datalong)) - { - sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_KILL_CREDIT for script id %u",tablename,tmp.datalong,tmp.id); - continue; - } - break; - } - - case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: - { - if (!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o)) - { - sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.x,tmp.y,tmp.id); - continue; - } - - if (!GetCreatureTemplate(tmp.datalong)) - { - sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.datalong,tmp.id); - continue; - } - break; - } - - case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: - { - GameObjectData const* data = GetGOData(tmp.datalong); - if (!data) - { - sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,tmp.id); - continue; - } - - GameObjectInfo const* info = GetGameObjectInfo(data->id); - if (!info) - { - sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,data->id,tmp.id); - continue; - } - - if (info->type == GAMEOBJECT_TYPE_FISHINGNODE || - info->type == GAMEOBJECT_TYPE_FISHINGHOLE || - info->type == GAMEOBJECT_TYPE_DOOR || - info->type == GAMEOBJECT_TYPE_BUTTON || - info->type == GAMEOBJECT_TYPE_TRAP) - { - sLog.outErrorDb("Table `%s` have gameobject type (%u) unsupported by command SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,info->id,tmp.id); - continue; - } - break; - } - case SCRIPT_COMMAND_OPEN_DOOR: - case SCRIPT_COMMAND_CLOSE_DOOR: - { - GameObjectData const* data = GetGOData(tmp.datalong); - if (!data) - { - sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in %s for script id %u",tablename,tmp.datalong,(tmp.command == SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id); - continue; - } - - GameObjectInfo const* info = GetGameObjectInfo(data->id); - if (!info) - { - sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in %s for script id %u",tablename,tmp.datalong,data->id,(tmp.command == SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id); - continue; - } - - if (info->type != GAMEOBJECT_TYPE_DOOR) - { - sLog.outErrorDb("Table `%s` has gameobject type (%u) non supported by command %s for script id %u",tablename,info->id,(tmp.command == SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id); - continue; - } - - break; - } - case SCRIPT_COMMAND_QUEST_EXPLORED: - { - Quest const* quest = GetQuestTemplate(tmp.datalong); - if (!quest) - { - sLog.outErrorDb("Table `%s` has invalid quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",tablename,tmp.datalong,tmp.id); - continue; - } - - if (!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT)) - { - sLog.outErrorDb("Table `%s` has quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT in quest flags. Script command or quest flags wrong. Quest modified to require objective.",tablename,tmp.datalong,tmp.id); - - // this will prevent quest completing without objective - const_cast(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT); - - // continue; - quest objective requirement set and command can be allowed - } - - if (float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE) - { - sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u", - tablename,tmp.datalong2,tmp.id); - continue; - } - - if (tmp.datalong2 && float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE) - { - sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, max distance is %f or 0 for disable distance check", - tablename,tmp.datalong2,tmp.id,DEFAULT_VISIBILITY_DISTANCE); - continue; - } - - if (tmp.datalong2 && float(tmp.datalong2) < INTERACTION_DISTANCE) - { - sLog.outErrorDb("Table `%s` has too small distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, min distance is %f or 0 for disable distance check", - tablename,tmp.datalong2,tmp.id,INTERACTION_DISTANCE); - continue; - } - - break; - } - - case SCRIPT_COMMAND_REMOVE_AURA: - { - if (!sSpellStore.LookupEntry(tmp.datalong)) - { - sLog.outErrorDb("Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA or SCRIPT_COMMAND_CAST_SPELL for script id %u", - tablename,tmp.datalong,tmp.id); - continue; - } - if (tmp.datalong2 & ~0x1) // 1 bits (0,1) - { - sLog.outErrorDb("Table `%s` using unknown flags in datalong2 (%u)i n SCRIPT_COMMAND_CAST_SPELL for script id %u", - tablename,tmp.datalong2,tmp.id); - continue; - } - break; - } - case SCRIPT_COMMAND_CAST_SPELL: - { - if (!sSpellStore.LookupEntry(tmp.datalong)) - { - sLog.outErrorDb("Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA or SCRIPT_COMMAND_CAST_SPELL for script id %u", - tablename,tmp.datalong,tmp.id); - continue; - } - if (tmp.datalong2 & ~0x3) // 2 bits - { - sLog.outErrorDb("Table `%s` using unknown flags in datalong2 (%u)i n SCRIPT_COMMAND_CAST_SPELL for script id %u", - tablename,tmp.datalong2,tmp.id); - continue; - } - break; - } - - case SCRIPT_COMMAND_CREATE_ITEM: - { - if (!GetItemPrototype(tmp.datalong)) - { - sLog.outErrorDb("Table `%s` has nonexistent item (entry: %u) in SCRIPT_COMMAND_CREATE_ITEM for script id %u", - tablename, tmp.datalong, tmp.id); - continue; - } - if (!tmp.datalong2) - { - sLog.outErrorDb("Table `%s` SCRIPT_COMMAND_CREATE_ITEM but amount is %u for script id %u", - tablename, tmp.datalong2, tmp.id); - continue; - } - break; - } - } - - if (scripts.find(tmp.id) == scripts.end()) - { - ScriptMap emptyMap; - scripts[tmp.id] = emptyMap; - } - scripts[tmp.id].insert(std::pair(tmp.delay, tmp)); - - ++count; - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u script definitions", count); -} - -void ObjectMgr::LoadGameObjectScripts() -{ - LoadScripts(sGameObjectScripts, "gameobject_scripts"); - - // check ids - for (ScriptMapMap::const_iterator itr = sGameObjectScripts.begin(); itr != sGameObjectScripts.end(); ++itr) - { - if (!GetGOData(itr->first)) - sLog.outErrorDb("Table `gameobject_scripts` has not existing gameobject (GUID: %u) as script id",itr->first); - } -} - -void ObjectMgr::LoadQuestEndScripts() -{ - LoadScripts(sQuestEndScripts, "quest_end_scripts"); - - // check ids - for (ScriptMapMap::const_iterator itr = sQuestEndScripts.begin(); itr != sQuestEndScripts.end(); ++itr) - { - if (!GetQuestTemplate(itr->first)) - sLog.outErrorDb("Table `quest_end_scripts` has not existing quest (Id: %u) as script id",itr->first); - } -} - -void ObjectMgr::LoadQuestStartScripts() -{ - LoadScripts(sQuestStartScripts,"quest_start_scripts"); - - // check ids - for (ScriptMapMap::const_iterator itr = sQuestStartScripts.begin(); itr != sQuestStartScripts.end(); ++itr) - { - if (!GetQuestTemplate(itr->first)) - sLog.outErrorDb("Table `quest_start_scripts` has not existing quest (Id: %u) as script id",itr->first); - } -} - -void ObjectMgr::LoadSpellScripts() -{ - LoadScripts(sSpellScripts, "spell_scripts"); - - // check ids - for (ScriptMapMap::const_iterator itr = sSpellScripts.begin(); itr != sSpellScripts.end(); ++itr) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first); - - if (!spellInfo) - { - sLog.outErrorDb("Table `spell_scripts` has not existing spell (Id: %u) as script id",itr->first); - continue; - } - - //check for correct spellEffect - bool found = false; - for (uint8 i=0; i<3; ++i) - { - // skip empty effects - if (!spellInfo->Effect[i]) - continue; - - if (spellInfo->Effect[i] == SPELL_EFFECT_SCRIPT_EFFECT) - { - found = true; - break; - } - } - - if (!found) - sLog.outErrorDb("Table `spell_scripts` has unsupported spell (Id: %u) without SPELL_EFFECT_SCRIPT_EFFECT (%u) spell effect",itr->first,SPELL_EFFECT_SCRIPT_EFFECT); - } -} - -void ObjectMgr::LoadEventScripts() -{ - LoadScripts(sEventScripts, "event_scripts"); - - std::set evt_scripts; - // Load all possible script entries from gameobjects - for (uint32 i = 1; i < sGOStorage.MaxEntry; ++i) - { - GameObjectInfo const * goInfo = sGOStorage.LookupEntry(i); - if (goInfo) - { - switch(goInfo->type) - { - case GAMEOBJECT_TYPE_GOOBER: - if (goInfo->goober.eventId) - evt_scripts.insert(goInfo->goober.eventId); - break; - case GAMEOBJECT_TYPE_CHEST: - if (goInfo->chest.eventId) - evt_scripts.insert(goInfo->chest.eventId); - break; - case GAMEOBJECT_TYPE_CAMERA: - if (goInfo->camera.eventID) - evt_scripts.insert(goInfo->camera.eventID); - default: - break; - } - } - } - // Load all possible script entries from spells - for (uint32 i = 1; i < sSpellStore.GetNumRows(); ++i) - { - SpellEntry const * spell = sSpellStore.LookupEntry(i); - if (spell) - { - for (uint8 j=0; j<3; ++j) - { - if (spell->Effect[j] == SPELL_EFFECT_SEND_EVENT) - { - if (spell->EffectMiscValue[j]) - evt_scripts.insert(spell->EffectMiscValue[j]); - } - } - } - } - - // Then check if all scripts are in above list of possible script entries - for (ScriptMapMap::const_iterator itr = sEventScripts.begin(); itr != sEventScripts.end(); ++itr) - { - std::set::const_iterator itr2 = evt_scripts.find(itr->first); - if (itr2 == evt_scripts.end()) - sLog.outErrorDb("Table `event_scripts` has script (Id: %u) not referring to any gameobject_template type 10 data2 field, type 3 data6 field, type 13 data 2 field or any spell effect %u", - itr->first, SPELL_EFFECT_SEND_EVENT); - } -} - -//Load WP Scripts -void ObjectMgr::LoadWaypointScripts() -{ - LoadScripts(sWaypointScripts, "waypoint_scripts"); - - for (ScriptMapMap::const_iterator itr = sWaypointScripts.begin(); itr != sWaypointScripts.end(); ++itr) - { - QueryResult_AutoPtr query = WorldDatabase.PQuery("SELECT * FROM waypoint_scripts WHERE id = %u", itr->first); - if (!query || !query->GetRowCount()) - sLog.outErrorDb("There is no waypoint which links to the waypoint script %u", itr->first); - } -} - -void ObjectMgr::LoadGossipScripts() -{ - LoadScripts(sGossipScripts, "gossip_scripts"); - - // checks are done in LoadGossipMenuItems -} - -void ObjectMgr::LoadPageTexts() -{ - sPageTextStore.Free(); // for reload case - - sPageTextStore.Load(); - sLog.outString(">> Loaded %u page texts", sPageTextStore.RecordCount); - sLog.outString(); - - for (uint32 i = 1; i < sPageTextStore.MaxEntry; ++i) - { - // check data correctness - PageText const* page = sPageTextStore.LookupEntry(i); - if (!page) - continue; - - if (page->Next_Page && !sPageTextStore.LookupEntry(page->Next_Page)) - { - sLog.outErrorDb("Page text (Id: %u) has not existing next page (Id:%u)", i,page->Next_Page); - continue; - } - - // detect circular reference - std::set checkedPages; - for (PageText const* pageItr = page; pageItr; pageItr = sPageTextStore.LookupEntry(pageItr->Next_Page)) - { - if (!pageItr->Next_Page) - break; - checkedPages.insert(pageItr->Page_ID); - if (checkedPages.find(pageItr->Next_Page)!= checkedPages.end()) - { - std::ostringstream ss; - ss << "The text page(s) "; - for (std::set::iterator itr= checkedPages.begin(); itr != checkedPages.end(); ++itr) - ss << *itr << " "; - ss << "create(s) a circular reference, which can cause the server to freeze. Changing Next_Page of page " - << pageItr->Page_ID <<" to 0"; - sLog.outErrorDb(ss.str().c_str()); - const_cast(pageItr)->Next_Page = 0; - break; - } - } - } -} - -void ObjectMgr::LoadPageTextLocales() -{ - mPageTextLocaleMap.clear(); // need for reload case - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry,text_loc1,text_loc2,text_loc3,text_loc4,text_loc5,text_loc6,text_loc7,text_loc8 FROM locales_page_text"); - - if (!result) - return; - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 entry = fields[0].GetUInt32(); - - PageTextLocale& data = mPageTextLocaleMap[entry]; - - for (uint8 i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[i].GetCppString(); - if (str.empty()) - continue; - - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.Text.size() <= idx) - data.Text.resize(idx+1); - - data.Text[idx] = str; - } - } - - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %lu PageText locale strings", (unsigned long)mPageTextLocaleMap.size()); -} - -struct SQLInstanceLoader : public SQLStorageLoaderBase -{ - template - void convert_from_str(uint32 /*field_pos*/, char *src, D &dst) - { - dst = D(objmgr.GetScriptId(src)); - } -}; - -void ObjectMgr::LoadInstanceTemplate() -{ - SQLInstanceLoader loader; - loader.Load(sInstanceTemplate); - - for (uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++) - { - InstanceTemplate* temp = (InstanceTemplate*)GetInstanceTemplate(i); - if (!temp) - continue; - - if (!MapManager::IsValidMAP(temp->map)) - sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", temp->map); - - if (!MapManager::IsValidMapCoord(temp->parent,temp->startLocX,temp->startLocY,temp->startLocZ,temp->startLocO)) - { - sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad parent entrance coordinates for map id %d template!", temp->map); - temp->parent = 0; // will have wrong continent 0 parent, at least existed - } - } - - sLog.outString(">> Loaded %u Instance Template definitions", sInstanceTemplate.RecordCount); - sLog.outString(); -} - -GossipText const *ObjectMgr::GetGossipText(uint32 Text_ID) const -{ - GossipTextMap::const_iterator itr = mGossipText.find(Text_ID); - if (itr != mGossipText.end()) - return &itr->second; - return NULL; -} - -void ObjectMgr::LoadGossipText() -{ - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT * FROM npc_text"); - - int count = 0; - if (!result) - { - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u npc texts", count); - return; - } - - int cic; - - barGoLink bar(result->GetRowCount()); - - do - { - ++count; - cic = 0; - - Field *fields = result->Fetch(); - - bar.step(); - - uint32 Text_ID = fields[cic++].GetUInt32(); - if (!Text_ID) - { - sLog.outErrorDb("Table `npc_text` has record wit reserved id 0, ignore."); - continue; - } - - GossipText& gText = mGossipText[Text_ID]; - - for (int i=0; i< 8; i++) - { - gText.Options[i].Text_0 = fields[cic++].GetCppString(); - gText.Options[i].Text_1 = fields[cic++].GetCppString(); - - gText.Options[i].Language = fields[cic++].GetUInt32(); - gText.Options[i].Probability = fields[cic++].GetFloat(); - - for (uint8 j=0; j < 3; ++j) - { - gText.Options[i].Emotes[j]._Delay = fields[cic++].GetUInt32(); - gText.Options[i].Emotes[j]._Emote = fields[cic++].GetUInt32(); - } - } - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u npc texts", count); -} - -void ObjectMgr::LoadNpcTextLocales() -{ - mNpcTextLocaleMap.clear(); // need for reload case - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry," - "Text0_0_loc1,Text0_1_loc1,Text1_0_loc1,Text1_1_loc1,Text2_0_loc1,Text2_1_loc1,Text3_0_loc1,Text3_1_loc1,Text4_0_loc1,Text4_1_loc1,Text5_0_loc1,Text5_1_loc1,Text6_0_loc1,Text6_1_loc1,Text7_0_loc1,Text7_1_loc1," - "Text0_0_loc2,Text0_1_loc2,Text1_0_loc2,Text1_1_loc2,Text2_0_loc2,Text2_1_loc2,Text3_0_loc2,Text3_1_loc1,Text4_0_loc2,Text4_1_loc2,Text5_0_loc2,Text5_1_loc2,Text6_0_loc2,Text6_1_loc2,Text7_0_loc2,Text7_1_loc2," - "Text0_0_loc3,Text0_1_loc3,Text1_0_loc3,Text1_1_loc3,Text2_0_loc3,Text2_1_loc3,Text3_0_loc3,Text3_1_loc1,Text4_0_loc3,Text4_1_loc3,Text5_0_loc3,Text5_1_loc3,Text6_0_loc3,Text6_1_loc3,Text7_0_loc3,Text7_1_loc3," - "Text0_0_loc4,Text0_1_loc4,Text1_0_loc4,Text1_1_loc4,Text2_0_loc4,Text2_1_loc4,Text3_0_loc4,Text3_1_loc1,Text4_0_loc4,Text4_1_loc4,Text5_0_loc4,Text5_1_loc4,Text6_0_loc4,Text6_1_loc4,Text7_0_loc4,Text7_1_loc4," - "Text0_0_loc5,Text0_1_loc5,Text1_0_loc5,Text1_1_loc5,Text2_0_loc5,Text2_1_loc5,Text3_0_loc5,Text3_1_loc1,Text4_0_loc5,Text4_1_loc5,Text5_0_loc5,Text5_1_loc5,Text6_0_loc5,Text6_1_loc5,Text7_0_loc5,Text7_1_loc5," - "Text0_0_loc6,Text0_1_loc6,Text1_0_loc6,Text1_1_loc6,Text2_0_loc6,Text2_1_loc6,Text3_0_loc6,Text3_1_loc1,Text4_0_loc6,Text4_1_loc6,Text5_0_loc6,Text5_1_loc6,Text6_0_loc6,Text6_1_loc6,Text7_0_loc6,Text7_1_loc6," - "Text0_0_loc7,Text0_1_loc7,Text1_0_loc7,Text1_1_loc7,Text2_0_loc7,Text2_1_loc7,Text3_0_loc7,Text3_1_loc1,Text4_0_loc7,Text4_1_loc7,Text5_0_loc7,Text5_1_loc7,Text6_0_loc7,Text6_1_loc7,Text7_0_loc7,Text7_1_loc7, " - "Text0_0_loc8,Text0_1_loc8,Text1_0_loc8,Text1_1_loc8,Text2_0_loc8,Text2_1_loc8,Text3_0_loc8,Text3_1_loc1,Text4_0_loc8,Text4_1_loc8,Text5_0_loc8,Text5_1_loc8,Text6_0_loc8,Text6_1_loc8,Text7_0_loc8,Text7_1_loc8 " - " FROM locales_npc_text"); - - if (!result) - return; - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 entry = fields[0].GetUInt32(); - - NpcTextLocale& data = mNpcTextLocaleMap[entry]; - - for (uint8 i=1; i= 0) - { - if (data.Text_0[j].size() <= idx) - data.Text_0[j].resize(idx+1); - - data.Text_0[j][idx] = str0; - } - } - std::string str1 = fields[1+8*2*(i-1)+2*j+1].GetCppString(); - if (!str1.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.Text_1[j].size() <= idx) - data.Text_1[j].resize(idx+1); - - data.Text_1[j][idx] = str1; - } - } - } - } - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %lu NpcText locale strings", (unsigned long)mNpcTextLocaleMap.size()); -} - -//not very fast function but it is called only once a day, or on starting-up -void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp) -{ - time_t basetime = time(NULL); - sLog.outDebug("Returning mails current time: hour: %d, minute: %d, second: %d ", localtime(&basetime)->tm_hour, localtime(&basetime)->tm_min, localtime(&basetime)->tm_sec); - //delete all old mails without item and without body immediately, if starting server - if (!serverUp) - CharacterDatabase.PExecute("DELETE FROM mail WHERE expire_time < '" UI64FMTD "' AND has_items = '0' AND body = ''", (uint64)basetime); - // 0 1 2 3 4 5 6 7 8 9 - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT id,messageType,sender,receiver,has_items,expire_time,cod,checked,mailTemplateId FROM mail WHERE expire_time < '" UI64FMTD "'", (uint64)basetime); - if (!result) - { - barGoLink bar(1); - bar.step(); - sLog.outString(); - sLog.outString(">> Only expired mails (need to be return or delete) or DB table `mail` is empty."); - return; // any mails need to be returned or deleted - } - - //std::ostringstream delitems, delmails; //will be here for optimization - //bool deletemail = false, deleteitem = false; - //delitems << "DELETE FROM item_instance WHERE guid IN ("; - //delmails << "DELETE FROM mail WHERE id IN (" - - barGoLink bar(result->GetRowCount()); - uint32 count = 0; - Field *fields; - - do - { - bar.step(); - - fields = result->Fetch(); - Mail *m = new Mail; - m->messageID = fields[0].GetUInt32(); - m->messageType = fields[1].GetUInt8(); - m->sender = fields[2].GetUInt32(); - m->receiver = fields[3].GetUInt32(); - bool has_items = fields[4].GetBool(); - m->expire_time = (time_t)fields[5].GetUInt64(); - m->deliver_time = 0; - m->COD = fields[6].GetUInt32(); - m->checked = fields[7].GetUInt32(); - m->mailTemplateId = fields[8].GetInt16(); - - Player *pl = 0; - if (serverUp) - pl = GetPlayer((uint64)m->receiver); - if (pl && pl->m_mailsLoaded) - { //this code will run very improbably (the time is between 4 and 5 am, in game is online a player, who has old mail - //his in mailbox and he has already listed his mails) - delete m; - continue; - } - //delete or return mail: - if (has_items) - { - QueryResult_AutoPtr resultItems = CharacterDatabase.PQuery("SELECT item_guid,item_template FROM mail_items WHERE mail_id='%u'", m->messageID); - if (resultItems) - { - do - { - Field *fields2 = resultItems->Fetch(); - - uint32 item_guid_low = fields2[0].GetUInt32(); - uint32 item_template = fields2[1].GetUInt32(); - - m->AddItem(item_guid_low, item_template); - } - while (resultItems->NextRow()); - } - //if it is mail from AH, it shouldn't be returned, but deleted - if (m->messageType != MAIL_NORMAL || m->messageType == MAIL_AUCTION || (m->checked & (MAIL_CHECK_MASK_COD_PAYMENT | MAIL_CHECK_MASK_RETURNED))) - { - // mail open and then not returned - for (std::vector::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2) - CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", itr2->item_guid); - } - else - { - //mail will be returned: - CharacterDatabase.PExecute("UPDATE mail SET sender = '%u', receiver = '%u', expire_time = '" UI64FMTD "', deliver_time = '" UI64FMTD "',cod = '0', checked = '%u' WHERE id = '%u'", m->receiver, m->sender, (uint64)(basetime + 30*DAY), (uint64)basetime, MAIL_CHECK_MASK_RETURNED, m->messageID); - delete m; - continue; - } - } - - //deletemail = true; - //delmails << m->messageID << ", "; - CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", m->messageID); - delete m; - ++count; - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u mails", count); -} - -void ObjectMgr::LoadQuestAreaTriggers() -{ - mQuestAreaTriggerMap.clear(); // need for reload case - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id,quest FROM areatrigger_involvedrelation"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u quest trigger points", count); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - ++count; - bar.step(); - - Field *fields = result->Fetch(); - - uint32 trigger_ID = fields[0].GetUInt32(); - uint32 quest_ID = fields[1].GetUInt32(); - - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(trigger_ID); - if (!atEntry) - { - sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",trigger_ID); - continue; - } - - Quest const* quest = GetQuestTemplate(quest_ID); - - if (!quest) - { - sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not existing quest %u",trigger_ID,quest_ID); - continue; - } - - if (!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT)) - { - sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not quest %u, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Trigger or quest flags must be fixed, quest modified to require objective.",trigger_ID,quest_ID); - - // this will prevent quest completing without objective - const_cast(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT); - - // continue; - quest modified to required objective and trigger can be allowed. - } - - mQuestAreaTriggerMap[trigger_ID] = quest_ID; - - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u quest trigger points", count); -} - -void ObjectMgr::LoadTavernAreaTriggers() -{ - mTavernAreaTriggerSet.clear(); // need for reload case - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id FROM areatrigger_tavern"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u tavern triggers", count); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - ++count; - bar.step(); - - Field *fields = result->Fetch(); - - uint32 Trigger_ID = fields[0].GetUInt32(); - - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); - if (!atEntry) - { - sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID); - continue; - } - - mTavernAreaTriggerSet.insert(Trigger_ID); - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u tavern triggers", count); -} - -void ObjectMgr::LoadAreaTriggerScripts() -{ - mAreaTriggerScripts.clear(); // need for reload case - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, ScriptName FROM areatrigger_scripts"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u areatrigger scripts", count); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - ++count; - bar.step(); - - Field *fields = result->Fetch(); - - uint32 Trigger_ID = fields[0].GetUInt32(); - const char *scriptName = fields[1].GetString(); - - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); - if (!atEntry) - { - sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID); - continue; - } - mAreaTriggerScripts[Trigger_ID] = GetScriptId(scriptName); - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u areatrigger scripts", count); -} - -uint32 ObjectMgr::GetNearestTaxiNode(float x, float y, float z, uint32 mapid, uint32 team) -{ - bool found = false; - float dist = 10000; - uint32 id = 0; - - for (uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i) - { - TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i); - - if (!node || node->map_id != mapid || !node->MountCreatureID[team == ALLIANCE ? 1 : 0] && node->MountCreatureID[0] != 32981) // dk flight - continue; - - uint8 field = (uint8)((i - 1) / 32); - uint32 submask = 1<<((i-1)%32); - - // skip not taxi network nodes - if ((sTaxiNodesMask[field] & submask) == 0) - continue; - - float dist2 = (node->x - x)*(node->x - x)+(node->y - y)*(node->y - y)+(node->z - z)*(node->z - z); - if (found) - { - if (dist2 < dist) - { - dist = dist2; - id = i; - } - } - else - { - found = true; - dist = dist2; - id = i; - } - } - - return id; -} - -void ObjectMgr::GetTaxiPath(uint32 source, uint32 destination, uint32 &path, uint32 &cost) -{ - TaxiPathSetBySource::iterator src_i = sTaxiPathSetBySource.find(source); - if (src_i == sTaxiPathSetBySource.end()) - { - path = 0; - cost = 0; - return; - } - - TaxiPathSetForSource& pathSet = src_i->second; - - TaxiPathSetForSource::iterator dest_i = pathSet.find(destination); - if (dest_i == pathSet.end()) - { - path = 0; - cost = 0; - return; - } - - cost = dest_i->second.price; - path = dest_i->second.ID; -} - -uint32 ObjectMgr::GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt_team /* = false */) -{ - uint32 mount_entry = 0; - uint32 mount_id = 0; - - // select mount creature id - TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id); - if (node) - { - if (team == ALLIANCE) - mount_entry = node->MountCreatureID[1]; - else - mount_entry = node->MountCreatureID[0]; - - // Fix for Alliance not being able to use Acherus taxi - // only one mount type for both sides - if (mount_entry == 0 && allowed_alt_team) - { - // Simply reverse the selection. At least one team in theory should have a valid mount ID to choose. - mount_entry = team == ALLIANCE ? node->MountCreatureID[0] : node->MountCreatureID[1]; - } - - CreatureInfo const *mount_info = GetCreatureTemplate(mount_entry); - if (mount_info) - { - mount_id = mount_info->GetRandomValidModelId(); - if (!mount_id) - { - sLog.outErrorDb("No displayid found for the taxi mount with the entry %u! Can't load it!", mount_entry); - return false; - } - } - } - - CreatureModelInfo const *minfo = objmgr.GetCreatureModelRandomGender(mount_id); - if (minfo) - mount_id = minfo->modelid; - - return mount_id; -} - -void ObjectMgr::GetTaxiPathNodes(uint32 path, Path &pathnodes, std::vector& mapIds) -{ - if (path >= sTaxiPathNodesByPath.size()) - return; - - TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path]; - - pathnodes.Resize(nodeList.size()); - mapIds.resize(nodeList.size()); - - for (size_t i = 0; i < nodeList.size(); ++i) - { - pathnodes[ i ].x = nodeList[i].x; - pathnodes[ i ].y = nodeList[i].y; - pathnodes[ i ].z = nodeList[i].z; - - mapIds[i] = nodeList[i].mapid; - } -} - -void ObjectMgr::GetTransportPathNodes(uint32 path, TransportPath &pathnodes) -{ - if (path >= sTaxiPathNodesByPath.size()) - return; - - TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path]; - - pathnodes.Resize(nodeList.size()); - - for (size_t i = 0; i < nodeList.size(); ++i) - { - pathnodes[ i ].mapid = nodeList[i].mapid; - pathnodes[ i ].x = nodeList[i].x; - pathnodes[ i ].y = nodeList[i].y; - pathnodes[ i ].z = nodeList[i].z; - pathnodes[ i ].actionFlag = nodeList[i].actionFlag; - pathnodes[ i ].delay = nodeList[i].delay; - } -} - -void ObjectMgr::LoadGraveyardZones() -{ - mGraveYardMap.clear(); // need for reload case - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id,ghost_zone,faction FROM game_graveyard_zone"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u graveyard-zone links", count); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - ++count; - bar.step(); - - Field *fields = result->Fetch(); - - uint32 safeLocId = fields[0].GetUInt32(); - uint32 zoneId = fields[1].GetUInt32(); - uint32 team = fields[2].GetUInt32(); - - WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(safeLocId); - if (!entry) - { - sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",safeLocId); - continue; - } - - AreaTableEntry const *areaEntry = GetAreaEntryByAreaID(zoneId); - if (!areaEntry) - { - sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing zone id (%u), skipped.",zoneId); - continue; - } - - if (areaEntry->zone != 0) - { - sLog.outErrorDb("Table `game_graveyard_zone` has record subzone id (%u) instead of zone, skipped.",zoneId); - continue; - } - - if (team != 0 && team != HORDE && team != ALLIANCE) - { - sLog.outErrorDb("Table `game_graveyard_zone` has record for non player faction (%u), skipped.",team); - continue; - } - - if (!AddGraveYardLink(safeLocId,zoneId,team,false)) - sLog.outErrorDb("Table `game_graveyard_zone` has a duplicate record for Graveyard (ID: %u) and Zone (ID: %u), skipped.",safeLocId,zoneId); - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u graveyard-zone links", count); -} - -WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team) -{ - // search for zone associated closest graveyard - uint32 zoneId = MapManager::Instance().GetZoneId(MapId,x,y,z); - - // Simulate std. algorithm: - // found some graveyard associated to (ghost_zone,ghost_map) - // - // if mapId == graveyard.mapId (ghost in plain zone or city or battleground) and search graveyard at same map - // then check faction - // if mapId != graveyard.mapId (ghost in instance) and search any graveyard associated - // then check faction - GraveYardMap::const_iterator graveLow = mGraveYardMap.lower_bound(zoneId); - GraveYardMap::const_iterator graveUp = mGraveYardMap.upper_bound(zoneId); - MapEntry const* map = sMapStore.LookupEntry(MapId); - // not need to check validity of map object; MapId _MUST_ be valid here - - if (graveLow == graveUp && !map->IsBattleArena()) - { - //sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team); - return NULL; - } - - // at corpse map - bool foundNear = false; - float distNear = 10000; - WorldSafeLocsEntry const* entryNear = NULL; - - // at entrance map for corpse map - bool foundEntr = false; - float distEntr = 10000; - WorldSafeLocsEntry const* entryEntr = NULL; - - // some where other - WorldSafeLocsEntry const* entryFar = NULL; - - MapEntry const* mapEntry = sMapStore.LookupEntry(MapId); - - for (GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr) - { - GraveYardData const& data = itr->second; - - WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(data.safeLocId); - if (!entry) - { - sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",data.safeLocId); - continue; - } - - // skip enemy faction graveyard - // team == 0 case can be at call from .neargrave - if (data.team != 0 && team != 0 && data.team != team) - continue; - - // find now nearest graveyard at other map - if (MapId != entry->map_id) - { - // if find graveyard at different map from where entrance placed (or no entrance data), use any first - if (!mapEntry || - mapEntry->entrance_map < 0 || - uint32(mapEntry->entrance_map) != entry->map_id || - (mapEntry->entrance_x == 0 && mapEntry->entrance_y == 0)) - { - // not have any corrdinates for check distance anyway - entryFar = entry; - continue; - } - - // at entrance map calculate distance (2D); - float dist2 = (entry->x - mapEntry->entrance_x)*(entry->x - mapEntry->entrance_x) - +(entry->y - mapEntry->entrance_y)*(entry->y - mapEntry->entrance_y); - if (foundEntr) - { - if (dist2 < distEntr) - { - distEntr = dist2; - entryEntr = entry; - } - } - else - { - foundEntr = true; - distEntr = dist2; - entryEntr = entry; - } - } - // find now nearest graveyard at same map - else - { - float dist2 = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y)+(entry->z - z)*(entry->z - z); - if (foundNear) - { - if (dist2 < distNear) - { - distNear = dist2; - entryNear = entry; - } - } - else - { - foundNear = true; - distNear = dist2; - entryNear = entry; - } - } - } - - if (entryNear) - return entryNear; - - if (entryEntr) - return entryEntr; - - return entryFar; -} - -GraveYardData const* ObjectMgr::FindGraveYardData(uint32 id, uint32 zoneId) -{ - GraveYardMap::const_iterator graveLow = mGraveYardMap.lower_bound(zoneId); - GraveYardMap::const_iterator graveUp = mGraveYardMap.upper_bound(zoneId); - - for (GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr) - { - if (itr->second.safeLocId == id) - return &itr->second; - } - - return NULL; -} - -bool ObjectMgr::AddGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inDB) -{ - if (FindGraveYardData(id,zoneId)) - return false; - - // add link to loaded data - GraveYardData data; - data.safeLocId = id; - data.team = team; - - mGraveYardMap.insert(GraveYardMap::value_type(zoneId,data)); - - // add link to DB - if (inDB) - { - WorldDatabase.PExecuteLog("INSERT INTO game_graveyard_zone (id,ghost_zone,faction) " - "VALUES ('%u', '%u','%u')",id,zoneId,team); - } - - return true; -} - -void ObjectMgr::RemoveGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inDB) -{ - GraveYardMap::iterator graveLow = mGraveYardMap.lower_bound(zoneId); - GraveYardMap::iterator graveUp = mGraveYardMap.upper_bound(zoneId); - if (graveLow == graveUp) - { - //sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team); - return; - } - - bool found = false; - - GraveYardMap::iterator itr; - - for (itr = graveLow; itr != graveUp; ++itr) - { - GraveYardData & data = itr->second; - - // skip not matching safezone id - if (data.safeLocId != id) - continue; - - // skip enemy faction graveyard at same map (normal area, city, or battleground) - // team == 0 case can be at call from .neargrave - if (data.team != 0 && team != 0 && data.team != team) - continue; - - found = true; - break; - } - - // no match, return - if (!found) - return; - - // remove from links - mGraveYardMap.erase(itr); - - // remove link from DB - if (inDB) - { - WorldDatabase.PExecute("DELETE FROM game_graveyard_zone WHERE id = '%u' AND ghost_zone = '%u' AND faction = '%u'",id,zoneId,team); - } - - return; -} - -void ObjectMgr::LoadAreaTriggerTeleports() -{ - mAreaTriggers.clear(); // need for reload case - - uint32 count = 0; - - // 0 1 2 3 4 5 6 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id, access_id, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport"); - if (!result) - { - - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u area trigger teleport definitions", count); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - - bar.step(); - - ++count; - - uint32 Trigger_ID = fields[0].GetUInt32(); - - AreaTrigger at; - - at.access_id = fields[1].GetUInt32(); - at.target_mapId = fields[2].GetUInt32(); - at.target_X = fields[3].GetFloat(); - at.target_Y = fields[4].GetFloat(); - at.target_Z = fields[5].GetFloat(); - at.target_Orientation = fields[6].GetFloat(); - - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); - if (!atEntry) - { - sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID); - continue; - } - - MapEntry const* mapEntry = sMapStore.LookupEntry(at.target_mapId); - if (!mapEntry) - { - sLog.outErrorDb("Area trigger (ID:%u) target map (ID: %u) does not exist in `Map.dbc`.",Trigger_ID,at.target_mapId); - continue; - } - - if (at.target_X == 0 && at.target_Y == 0 && at.target_Z == 0) - { - sLog.outErrorDb("Area trigger (ID:%u) target coordinates not provided.",Trigger_ID); - continue; - } - - mAreaTriggers[Trigger_ID] = at; - - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u area trigger teleport definitions", count); -} - -void ObjectMgr::LoadAccessRequirements() -{ - mAccessRequirements.clear(); // need for reload case - - uint32 count = 0; - - // 0 1 2 3 4 5 6 7 8 9 10 11 12 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id, level_min, level_max, item, item2, heroic_key, heroic_key2, quest_done, quest_failed_text, heroic_quest_done, heroic_quest_failed_text, heroic_level_min, status FROM access_requirement"); - if (!result) - { - - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u access requirement definitions", count); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - - bar.step(); - - ++count; - - uint32 requiremt_ID = fields[0].GetUInt32(); - - AccessRequirement ar; - - ar.levelMin = fields[1].GetUInt8(); - ar.levelMax = fields[2].GetUInt8(); - ar.heroicLevelMin = fields[11].GetUInt8(); - ar.item = fields[3].GetUInt32(); - ar.item2 = fields[4].GetUInt32(); - ar.heroicKey = fields[5].GetUInt32(); - ar.heroicKey2 = fields[6].GetUInt32(); - ar.quest = fields[7].GetUInt32(); - ar.questFailedText = fields[8].GetCppString(); - ar.heroicQuest = fields[9].GetUInt32(); - ar.heroicQuestFailedText = fields[10].GetCppString(); - ar.status = fields[12].GetUInt8(); - - if (ar.item) - { - ItemPrototype const *pProto = GetItemPrototype(ar.item); - if (!pProto) - { - sLog.outError("Key item %u does not exist for requirement %u, removing key requirement.", ar.item, requiremt_ID); - ar.item = 0; - } - } - - if (ar.item2) - { - ItemPrototype const *pProto = GetItemPrototype(ar.item2); - if (!pProto) - { - sLog.outError("Second item %u does not exist for requirement %u, removing key requirement.", ar.item2, requiremt_ID); - ar.item2 = 0; - } - } - - if (ar.heroicKey) - { - ItemPrototype const *pProto = GetItemPrototype(ar.heroicKey); - if (!pProto) - { - sLog.outError("Heroic key %u not exist for trigger %u, remove key requirement.", ar.heroicKey, requiremt_ID); - ar.heroicKey = 0; - } - } - - if (ar.heroicKey2) - { - ItemPrototype const *pProto = GetItemPrototype(ar.heroicKey2); - if (!pProto) - { - sLog.outError("Second heroic key %u not exist for trigger %u, remove key requirement.", ar.heroicKey2, requiremt_ID); - ar.heroicKey2 = 0; - } - } - - if (ar.heroicQuest) - { - QuestMap::iterator qReqItr = mQuestTemplates.find(ar.heroicQuest); - if (qReqItr == mQuestTemplates.end()) - { - sLog.outErrorDb("Required Heroic Quest %u not exist for trigger %u, remove heroic quest done requirement.",ar.heroicQuest,requiremt_ID); - ar.heroicQuest = 0; - } - } - - if (ar.quest) - { - QuestMap::iterator qReqItr = mQuestTemplates.find(ar.quest); - if (qReqItr == mQuestTemplates.end()) - { - sLog.outErrorDb("Required Quest %u not exist for trigger %u, remove quest done requirement.",ar.quest,requiremt_ID); - ar.quest = 0; - } - } - - mAccessRequirements[requiremt_ID] = ar; - - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u access requirement definitions", count); -} - -/* - * Searches for the areatrigger which teleports players out of the given map with instance_template.parent field support - */ -AreaTrigger const* ObjectMgr::GetGoBackTrigger(uint32 Map) const -{ - bool useParentDbValue = false; - uint32 parentId = 0; - const MapEntry *mapEntry = sMapStore.LookupEntry(Map); - if (!mapEntry || mapEntry->entrance_map < 0) - return NULL; - - if (mapEntry->IsDungeon()) - { - const InstanceTemplate *iTemplate = objmgr.GetInstanceTemplate(Map); - - if (!iTemplate) - return NULL; - - parentId = iTemplate->parent; - useParentDbValue = true; - } - - uint32 entrance_map = uint32(mapEntry->entrance_map); - for (AreaTriggerMap::const_iterator itr = mAreaTriggers.begin(); itr != mAreaTriggers.end(); ++itr) - if ((!useParentDbValue && itr->second.target_mapId == entrance_map) || (useParentDbValue && itr->second.target_mapId == parentId)) - { - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(itr->first); - if (atEntry && atEntry->mapid == Map) - return &itr->second; - } - return NULL; -} - -/** - * Searches for the areatrigger which teleports players to the given map - */ -AreaTrigger const* ObjectMgr::GetMapEntranceTrigger(uint32 Map) const -{ - for (AreaTriggerMap::const_iterator itr = mAreaTriggers.begin(); itr != mAreaTriggers.end(); ++itr) - { - if (itr->second.target_mapId == Map) - { - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(itr->first); - if (atEntry) - return &itr->second; - } - } - return NULL; -} - -void ObjectMgr::SetHighestGuids() -{ - QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT MAX(guid) FROM characters"); - if (result) - m_hiCharGuid = (*result)[0].GetUInt32()+1; - - result = WorldDatabase.Query("SELECT MAX(guid) FROM creature"); - if (result) - m_hiCreatureGuid = (*result)[0].GetUInt32()+1; - - result = CharacterDatabase.Query("SELECT MAX(guid) FROM item_instance"); - if (result) - m_hiItemGuid = (*result)[0].GetUInt32()+1; - - // Cleanup other tables from not existed guids ( >= m_hiItemGuid) - CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item >= '%u'", m_hiItemGuid); - CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid >= '%u'", m_hiItemGuid); - CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE itemguid >= '%u'", m_hiItemGuid); - CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE item_guid >= '%u'", m_hiItemGuid); - - result = WorldDatabase.Query("SELECT MAX(guid) FROM gameobject"); - if (result) - m_hiGoGuid = (*result)[0].GetUInt32()+1; - - result = CharacterDatabase.Query("SELECT MAX(id) FROM auctionhouse"); - if (result) - m_auctionid = (*result)[0].GetUInt32()+1; - - result = CharacterDatabase.Query("SELECT MAX(id) FROM mail"); - if (result) - m_mailid = (*result)[0].GetUInt32()+1; - - result = CharacterDatabase.Query("SELECT MAX(guid) FROM corpse"); - if (result) - m_hiCorpseGuid = (*result)[0].GetUInt32()+1; - - result = CharacterDatabase.Query("SELECT MAX(arenateamid) FROM arena_team"); - if (result) - m_arenaTeamId = (*result)[0].GetUInt32()+1; - - result = CharacterDatabase.Query("SELECT MAX(setguid) FROM character_equipmentsets"); - if (result) - m_equipmentSetGuid = (*result)[0].GetUInt64()+1; - - result = CharacterDatabase.Query("SELECT MAX(guildid) FROM guild"); - if (result) - m_guildId = (*result)[0].GetUInt32()+1; - - result = CharacterDatabase.Query("SELECT MAX(guid) FROM groups"); - if (result) - m_hiGroupGuid = (*result)[0].GetUInt32()+1; -} - -uint32 ObjectMgr::GenerateArenaTeamId() -{ - if (m_arenaTeamId >= 0xFFFFFFFE) - { - sLog.outError("Arena team ids overflow!! Can't continue, shutting down server. "); - World::StopNow(ERROR_EXIT_CODE); - } - return m_arenaTeamId++; -} - -uint32 ObjectMgr::GenerateAuctionID() -{ - if (m_auctionid >= 0xFFFFFFFE) - { - sLog.outError("Auctions ids overflow!! Can't continue, shutting down server. "); - World::StopNow(ERROR_EXIT_CODE); - } - return m_auctionid++; -} - -uint64 ObjectMgr::GenerateEquipmentSetGuid() -{ - if (m_equipmentSetGuid >= 0xFFFFFFFFFFFFFFFEll) - { - sLog.outError("EquipmentSet guid overflow!! Can't continue, shutting down server. "); - World::StopNow(ERROR_EXIT_CODE); - } - return m_equipmentSetGuid++; -} - -uint32 ObjectMgr::GenerateGuildId() -{ - if (m_guildId >= 0xFFFFFFFE) - { - sLog.outError("Guild ids overflow!! Can't continue, shutting down server. "); - World::StopNow(ERROR_EXIT_CODE); - } - return m_guildId++; -} - -uint32 ObjectMgr::GenerateMailID() -{ - if (m_mailid >= 0xFFFFFFFE) - { - sLog.outError("Mail ids overflow!! Can't continue, shutting down server. "); - World::StopNow(ERROR_EXIT_CODE); - } - return m_mailid++; -} - -uint32 ObjectMgr::GenerateLowGuid(HighGuid guidhigh) -{ - switch(guidhigh) - { - case HIGHGUID_ITEM: - if (m_hiItemGuid >= 0xFFFFFFFE) - { - sLog.outError("Item guid overflow!! Can't continue, shutting down server. "); - World::StopNow(ERROR_EXIT_CODE); - } - return m_hiItemGuid++; - case HIGHGUID_UNIT: - if (m_hiCreatureGuid >= 0x00FFFFFE) - { - sLog.outError("Creature guid overflow!! Can't continue, shutting down server. "); - World::StopNow(ERROR_EXIT_CODE); - } - return m_hiCreatureGuid++; - case HIGHGUID_PET: - if (m_hiPetGuid >= 0x00FFFFFE) - { - sLog.outError("Pet guid overflow!! Can't continue, shutting down server. "); - World::StopNow(ERROR_EXIT_CODE); - } - return m_hiPetGuid++; - case HIGHGUID_VEHICLE: - if (m_hiVehicleGuid >= 0x00FFFFFF) - { - sLog.outError("Vehicle guid overflow!! Can't continue, shutting down server. "); - World::StopNow(ERROR_EXIT_CODE); - } - return m_hiVehicleGuid++; - case HIGHGUID_PLAYER: - if (m_hiCharGuid >= 0xFFFFFFFE) - { - sLog.outError("Players guid overflow!! Can't continue, shutting down server. "); - World::StopNow(ERROR_EXIT_CODE); - } - return m_hiCharGuid++; - case HIGHGUID_GAMEOBJECT: - if (m_hiGoGuid >= 0x00FFFFFE) - { - sLog.outError("Gameobject guid overflow!! Can't continue, shutting down server. "); - World::StopNow(ERROR_EXIT_CODE); - } - return m_hiGoGuid++; - case HIGHGUID_CORPSE: - if (m_hiCorpseGuid >= 0xFFFFFFFE) - { - sLog.outError("Corpse guid overflow!! Can't continue, shutting down server. "); - World::StopNow(ERROR_EXIT_CODE); - } - return m_hiCorpseGuid++; - case HIGHGUID_DYNAMICOBJECT: - if (m_hiDoGuid >= 0xFFFFFFFE) - { - sLog.outError("DynamicObject guid overflow!! Can't continue, shutting down server. "); - World::StopNow(ERROR_EXIT_CODE); - } - return m_hiDoGuid++; - case HIGHGUID_GROUP: - if (m_hiGroupGuid >= 0xFFFFFFFE) - { - sLog.outError("Group guid overflow!! Can't continue, shutting down server. "); - World::StopNow(ERROR_EXIT_CODE); - } - return m_hiGroupGuid++; - default: - ASSERT(0); - } - - ASSERT(0); - return 0; -} - -void ObjectMgr::LoadGameObjectLocales() -{ - mGameObjectLocaleMap.clear(); // need for reload case - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry," - "name_loc1,name_loc2,name_loc3,name_loc4,name_loc5,name_loc6,name_loc7,name_loc8," - "castbarcaption_loc1,castbarcaption_loc2,castbarcaption_loc3,castbarcaption_loc4," - "castbarcaption_loc5,castbarcaption_loc6,castbarcaption_loc7,castbarcaption_loc8 FROM locales_gameobject"); - - if (!result) - return; - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 entry = fields[0].GetUInt32(); - - GameObjectLocale& data = mGameObjectLocaleMap[entry]; - - for (uint8 i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[i].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.Name.size() <= idx) - data.Name.resize(idx+1); - - data.Name[idx] = str; - } - } - } - - for (uint8 i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[i+(MAX_LOCALE-1)].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - if (data.CastBarCaption.size() <= idx) - data.CastBarCaption.resize(idx+1); - - data.CastBarCaption[idx] = str; - } - } - } - - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %lu gameobject locale strings", (unsigned long)mGameObjectLocaleMap.size()); -} - -struct SQLGameObjectLoader : public SQLStorageLoaderBase -{ - template - void convert_from_str(uint32 /*field_pos*/, char *src, D &dst) - { - dst = D(objmgr.GetScriptId(src)); - } -}; - -inline void CheckGOLockId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) -{ - if (sLockStore.LookupEntry(dataN)) - return; - - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but lock (Id: %u) not found.", - goInfo->id,goInfo->type,N,goInfo->door.lockId,goInfo->door.lockId); -} - -inline void CheckGOLinkedTrapId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) -{ - if (GameObjectInfo const* trapInfo = sGOStorage.LookupEntry(dataN)) - { - if (trapInfo->type != GAMEOBJECT_TYPE_TRAP) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.", - goInfo->id,goInfo->type,N,dataN,dataN,GAMEOBJECT_TYPE_TRAP); - } - /* disable check for while (too many error reports baout not existed in trap templates - else - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but trap GO (Entry %u) not exist in `gameobject_template`.", - goInfo->id,goInfo->type,N,dataN,dataN); - */ -} - -inline void CheckGOSpellId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) -{ - if (sSpellStore.LookupEntry(dataN)) - return; - - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but Spell (Entry %u) not exist.", - goInfo->id,goInfo->type,N,dataN,dataN); -} - -inline void CheckAndFixGOChairHeightId(GameObjectInfo const* goInfo,uint32 const& dataN,uint32 N) -{ - if (dataN <= (UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR)) - return; - - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but correct chair height in range 0..%i.", - goInfo->id,goInfo->type,N,dataN,UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR); - - // prevent client and server unexpected work - const_cast(dataN) = 0; -} - -inline void CheckGONoDamageImmuneId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) -{ - // 0/1 correct values - if (dataN <= 1) - return; - - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but expected boolean (0/1) noDamageImmune field value.", - goInfo->id,goInfo->type,N,dataN); -} - -inline void CheckGOConsumable(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) -{ - // 0/1 correct values - if (dataN <= 1) - return; - - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but expected boolean (0/1) consumable field value.", - goInfo->id,goInfo->type,N,dataN); -} - -void ObjectMgr::LoadGameobjectInfo() -{ - SQLGameObjectLoader loader; - loader.Load(sGOStorage); - - // some checks - for (uint32 id = 1; id < sGOStorage.MaxEntry; id++) - { - GameObjectInfo const* goInfo = sGOStorage.LookupEntry(id); - if (!goInfo) - continue; - - // some GO types have unused go template, check goInfo->displayId at GO spawn data loading or ignore - - switch(goInfo->type) - { - case GAMEOBJECT_TYPE_DOOR: //0 - { - if (goInfo->door.lockId) - CheckGOLockId(goInfo,goInfo->door.lockId,1); - CheckGONoDamageImmuneId(goInfo,goInfo->door.noDamageImmune,3); - break; - } - case GAMEOBJECT_TYPE_BUTTON: //1 - { - if (goInfo->button.lockId) - CheckGOLockId(goInfo,goInfo->button.lockId,1); - CheckGONoDamageImmuneId(goInfo,goInfo->button.noDamageImmune,4); - break; - } - case GAMEOBJECT_TYPE_QUESTGIVER: //2 - { - if (goInfo->questgiver.lockId) - CheckGOLockId(goInfo,goInfo->questgiver.lockId,0); - CheckGONoDamageImmuneId(goInfo,goInfo->questgiver.noDamageImmune,5); - break; - } - case GAMEOBJECT_TYPE_CHEST: //3 - { - if (goInfo->chest.lockId) - CheckGOLockId(goInfo,goInfo->chest.lockId,0); - - CheckGOConsumable(goInfo,goInfo->chest.consumable,3); - - if (goInfo->chest.linkedTrapId) // linked trap - CheckGOLinkedTrapId(goInfo,goInfo->chest.linkedTrapId,7); - break; - } - case GAMEOBJECT_TYPE_TRAP: //6 - { - if (goInfo->trap.lockId) - CheckGOLockId(goInfo,goInfo->trap.lockId,0); - /* disable check for while, too many not existed spells - if (goInfo->trap.spellId) // spell - CheckGOSpellId(goInfo,goInfo->trap.spellId,3); - */ - break; - } - case GAMEOBJECT_TYPE_CHAIR: //7 - CheckAndFixGOChairHeightId(goInfo,goInfo->chair.height,1); - break; - case GAMEOBJECT_TYPE_SPELL_FOCUS: //8 - { - if (goInfo->spellFocus.focusId) - { - if (!sSpellFocusObjectStore.LookupEntry(goInfo->spellFocus.focusId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but SpellFocus (Id: %u) not exist.", - id,goInfo->type,goInfo->spellFocus.focusId,goInfo->spellFocus.focusId); - } - - if (goInfo->spellFocus.linkedTrapId) // linked trap - CheckGOLinkedTrapId(goInfo,goInfo->spellFocus.linkedTrapId,2); - break; - } - case GAMEOBJECT_TYPE_GOOBER: //10 - { - if (goInfo->goober.lockId) - CheckGOLockId(goInfo,goInfo->goober.lockId,0); - - CheckGOConsumable(goInfo,goInfo->goober.consumable,3); - - if (goInfo->goober.pageId) // pageId - { - if (!sPageTextStore.LookupEntry(goInfo->goober.pageId)) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but PageText (Entry %u) not exist.", - id,goInfo->type,goInfo->goober.pageId,goInfo->goober.pageId); - } - /* disable check for while, too many not existed spells - if (goInfo->goober.spellId) // spell - CheckGOSpellId(goInfo,goInfo->goober.spellId,10); - */ - CheckGONoDamageImmuneId(goInfo,goInfo->goober.noDamageImmune,11); - if (goInfo->goober.linkedTrapId) // linked trap - CheckGOLinkedTrapId(goInfo,goInfo->goober.linkedTrapId,12); - break; - } - case GAMEOBJECT_TYPE_AREADAMAGE: //12 - { - if (goInfo->areadamage.lockId) - CheckGOLockId(goInfo,goInfo->areadamage.lockId,0); - break; - } - case GAMEOBJECT_TYPE_CAMERA: //13 - { - if (goInfo->camera.lockId) - CheckGOLockId(goInfo,goInfo->camera.lockId,0); - break; - } - case GAMEOBJECT_TYPE_MO_TRANSPORT: //15 - { - if (goInfo->moTransport.taxiPathId) - { - if (goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[goInfo->moTransport.taxiPathId].empty()) - sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.", - id,goInfo->type,goInfo->moTransport.taxiPathId,goInfo->moTransport.taxiPathId); - } - break; - } - case GAMEOBJECT_TYPE_SUMMONING_RITUAL: //18 - { - /* disable check for while, too many not existed spells - // always must have spell - CheckGOSpellId(goInfo,goInfo->summoningRitual.spellId,1); - */ - break; - } - case GAMEOBJECT_TYPE_SPELLCASTER: //22 - { - // always must have spell - CheckGOSpellId(goInfo,goInfo->spellcaster.spellId,0); - break; - } - case GAMEOBJECT_TYPE_FLAGSTAND: //24 - { - if (goInfo->flagstand.lockId) - CheckGOLockId(goInfo,goInfo->flagstand.lockId,0); - CheckGONoDamageImmuneId(goInfo,goInfo->flagstand.noDamageImmune,5); - break; - } - case GAMEOBJECT_TYPE_FISHINGHOLE: //25 - { - if (goInfo->fishinghole.lockId) - CheckGOLockId(goInfo,goInfo->fishinghole.lockId,4); - break; - } - case GAMEOBJECT_TYPE_FLAGDROP: //26 - { - if (goInfo->flagdrop.lockId) - CheckGOLockId(goInfo,goInfo->flagdrop.lockId,0); - CheckGONoDamageImmuneId(goInfo,goInfo->flagdrop.noDamageImmune,3); - break; - } - case GAMEOBJECT_TYPE_BARBER_CHAIR: //32 - CheckAndFixGOChairHeightId(goInfo,goInfo->barberChair.chairheight,0); - break; - } - } - - sLog.outString(">> Loaded %u game object templates", sGOStorage.RecordCount); - sLog.outString(); -} - -void ObjectMgr::LoadExplorationBaseXP() -{ - uint32 count = 0; - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT level,basexp FROM exploration_basexp"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u BaseXP definitions", count); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - bar.step(); - - Field *fields = result->Fetch(); - uint8 level = fields[0].GetUInt8(); - uint32 basexp = fields[1].GetUInt32(); - mBaseXPTable[level] = basexp; - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u BaseXP definitions", count); -} - -uint32 ObjectMgr::GetBaseXP(uint8 level) -{ - return mBaseXPTable[level] ? mBaseXPTable[level] : 0; -} - -uint32 ObjectMgr::GetXPForLevel(uint8 level) -{ - if (level < mPlayerXPperLevel.size()) - return mPlayerXPperLevel[level]; - return 0; -} - -void ObjectMgr::LoadPetNames() -{ - uint32 count = 0; - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT word,entry,half FROM pet_name_generation"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u pet name parts", count); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - bar.step(); - - Field *fields = result->Fetch(); - std::string word = fields[0].GetString(); - uint32 entry = fields[1].GetUInt32(); - bool half = fields[2].GetBool(); - if (half) - PetHalfName1[entry].push_back(word); - else - PetHalfName0[entry].push_back(word); - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u pet name parts", count); -} - -void ObjectMgr::LoadPetNumber() -{ - QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT MAX(id) FROM character_pet"); - if (result) - { - Field *fields = result->Fetch(); - m_hiPetNumber = fields[0].GetUInt32()+1; - } - - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded the max pet number: %d", m_hiPetNumber-1); -} - -std::string ObjectMgr::GeneratePetName(uint32 entry) -{ - std::vector & list0 = PetHalfName0[entry]; - std::vector & list1 = PetHalfName1[entry]; - - if (list0.empty() || list1.empty()) - { - CreatureInfo const *cinfo = GetCreatureTemplate(entry); - char* petname = GetPetName(cinfo->family, sWorld.GetDefaultDbcLocale()); - if (!petname) - petname = cinfo->Name; - return std::string(petname); - } - - return *(list0.begin()+urand(0, list0.size()-1)) + *(list1.begin()+urand(0, list1.size()-1)); -} - -uint32 ObjectMgr::GeneratePetNumber() -{ - return ++m_hiPetNumber; -} - -void ObjectMgr::LoadCorpses() -{ - uint32 count = 0; - // 0 1 2 3 4 5 6 7 8 9 10 - QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT position_x, position_y, position_z, orientation, map, data, time, corpse_type, instance, phaseMask, guid FROM corpse WHERE corpse_type <> 0"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u corpses", count); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - bar.step(); - - Field *fields = result->Fetch(); - - uint32 guid = fields[result->GetFieldCount()-1].GetUInt32(); - - Corpse *corpse = new Corpse; - if (!corpse->LoadFromDB(guid,fields)) - { - delete corpse; - continue; - } - - ObjectAccessor::Instance().AddCorpse(corpse); - - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u corpses", count); -} - -void ObjectMgr::LoadReputationOnKill() -{ - uint32 count = 0; - - // 0 1 2 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT creature_id, RewOnKillRepFaction1, RewOnKillRepFaction2," - // 3 4 5 6 7 8 9 - "IsTeamAward1, MaxStanding1, RewOnKillRepValue1, IsTeamAward2, MaxStanding2, RewOnKillRepValue2, TeamDependent " - "FROM creature_onkill_reputation"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 creature award reputation definitions. DB table `creature_onkill_reputation` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 creature_id = fields[0].GetUInt32(); - - ReputationOnKillEntry repOnKill; - repOnKill.repfaction1 = fields[1].GetUInt32(); - repOnKill.repfaction2 = fields[2].GetUInt32(); - repOnKill.is_teamaward1 = fields[3].GetBool(); - repOnKill.reputation_max_cap1 = fields[4].GetUInt32(); - repOnKill.repvalue1 = fields[5].GetInt32(); - repOnKill.is_teamaward2 = fields[6].GetBool(); - repOnKill.reputation_max_cap2 = fields[7].GetUInt32(); - repOnKill.repvalue2 = fields[8].GetInt32(); - repOnKill.team_dependent = fields[9].GetUInt8(); - - if (!GetCreatureTemplate(creature_id)) - { - sLog.outErrorDb("Table `creature_onkill_reputation` have data for not existed creature entry (%u), skipped",creature_id); - continue; - } - - if (repOnKill.repfaction1) - { - FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(repOnKill.repfaction1); - if (!factionEntry1) - { - sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction1); - continue; - } - } - - if (repOnKill.repfaction2) - { - FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(repOnKill.repfaction2); - if (!factionEntry2) - { - sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction2); - continue; - } - } - - mRepOnKill[creature_id] = repOnKill; - - ++count; - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u creature award reputation definitions", count); -} - -void ObjectMgr::LoadPointsOfInterest() -{ - uint32 count = 0; - - // 0 1 2 3 4 5 6 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, x, y, icon, flags, data, icon_name FROM points_of_interest"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 Points of Interest definitions. DB table `points_of_interest` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 point_id = fields[0].GetUInt32(); - - PointOfInterest POI; - POI.x = fields[1].GetFloat(); - POI.y = fields[2].GetFloat(); - POI.icon = fields[3].GetUInt32(); - POI.flags = fields[4].GetUInt32(); - POI.data = fields[5].GetUInt32(); - POI.icon_name = fields[6].GetCppString(); - - if (!Trinity::IsValidMapCoord(POI.x,POI.y)) - { - sLog.outErrorDb("Table `points_of_interest` (Entry: %u) have invalid coordinates (X: %f Y: %f), ignored.",point_id,POI.x,POI.y); - continue; - } - - mPointsOfInterest[point_id] = POI; - - ++count; - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u Points of Interest definitions", count); -} - -void ObjectMgr::LoadQuestPOI() -{ - uint32 count = 0; - - // 0 1 2 3 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT questId, id, objIndex, mapid, WorldMapAreaId, FloorId, unk3, unk4 FROM quest_poi order by questId"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 quest POI definitions. DB table `quest_poi` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 questId = fields[0].GetUInt32(); - uint32 id = fields[1].GetUInt32(); - int32 objIndex = fields[2].GetInt32(); - uint32 mapId = fields[3].GetUInt32(); - uint32 WorldMapAreaId = fields[4].GetUInt32(); - uint32 FloorId = fields[5].GetUInt32(); - uint32 unk3 = fields[6].GetUInt32(); - uint32 unk4 = fields[7].GetUInt32(); - - QuestPOI POI(id, objIndex, mapId, WorldMapAreaId, FloorId, unk3, unk4); - - QueryResult_AutoPtr points = WorldDatabase.PQuery("SELECT x, y FROM quest_poi_points WHERE questId='%u' AND id='%i'", questId, id); - - if (points) - { - do - { - Field *pointFields = points->Fetch(); - int32 x = pointFields[0].GetInt32(); - int32 y = pointFields[1].GetInt32(); - QuestPOIPoint point(x, y); - POI.points.push_back(point); - } while (points->NextRow()); - } - - mQuestPOIMap[questId].push_back(POI); - - ++count; - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u quest POI definitions", count); -} - -void ObjectMgr::LoadNPCSpellClickSpells() -{ - uint32 count = 0; - - mSpellClickInfoMap.clear(); - // 0 1 2 3 4 5 6 7 8 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT npc_entry, spell_id, quest_start, quest_start_active, quest_end, cast_flags, aura_required, aura_forbidden, user_type FROM npc_spellclick_spells"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 spellclick spells. DB table `npc_spellclick_spells` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 npc_entry = fields[0].GetUInt32(); - CreatureInfo const* cInfo = GetCreatureTemplate(npc_entry); - if (!cInfo) - { - sLog.outErrorDb("Table npc_spellclick_spells references unknown creature_template %u. Skipping entry.", npc_entry); - continue; - } - - if (!(cInfo->npcflag & UNIT_NPC_FLAG_SPELLCLICK)) - const_cast(cInfo)->npcflag |= UNIT_NPC_FLAG_SPELLCLICK; - - uint32 spellid = fields[1].GetUInt32(); - SpellEntry const *spellinfo = sSpellStore.LookupEntry(spellid); - if (!spellinfo) - { - sLog.outErrorDb("Table npc_spellclick_spells references unknown spellid %u. Skipping entry.", spellid); - continue; - } - - uint32 auraRequired = fields[6].GetUInt32(); - if (auraRequired) - { - SpellEntry const *aurReqInfo = sSpellStore.LookupEntry(auraRequired); - if (!aurReqInfo) - { - sLog.outErrorDb("Table npc_spellclick_spells references unknown aura required %u. Skipping entry.", auraRequired); - continue; - } - } - - uint32 auraForbidden = fields[7].GetUInt32(); - if (auraForbidden) - { - SpellEntry const *aurForInfo = sSpellStore.LookupEntry(auraForbidden); - if (!aurForInfo) - { - sLog.outErrorDb("Table npc_spellclick_spells references unknown aura forbidden %u. Skipping entry.", auraForbidden); - continue; - } - } - - uint32 quest_start = fields[2].GetUInt32(); - - // quest might be 0 to enable spellclick independent of any quest - if (quest_start) - { - if (mQuestTemplates.find(quest_start) == mQuestTemplates.end()) - { - sLog.outErrorDb("Table npc_spellclick_spells references unknown start quest %u. Skipping entry.", quest_start); - continue; - } - } - - bool quest_start_active = fields[3].GetBool(); - - uint32 quest_end = fields[4].GetUInt32(); - // quest might be 0 to enable spellclick active infinity after start quest - if (quest_end) - { - if (mQuestTemplates.find(quest_end) == mQuestTemplates.end()) - { - sLog.outErrorDb("Table npc_spellclick_spells references unknown end quest %u. Skipping entry.", quest_end); - continue; - } - } - - uint8 userType = fields[8].GetUInt8(); - if (userType >= SPELL_CLICK_USER_MAX) - sLog.outErrorDb("Table npc_spellclick_spells references unknown user type %u. Skipping entry.", uint32(userType)); - - uint8 castFlags = fields[5].GetUInt8(); - SpellClickInfo info; - info.spellId = spellid; - info.questStart = quest_start; - info.questStartCanActive = quest_start_active; - info.questEnd = quest_end; - info.castFlags = castFlags; - info.auraRequired = auraRequired; - info.auraForbidden = auraForbidden; - info.userType = SpellClickUserTypes(userType); - mSpellClickInfoMap.insert(SpellClickInfoMap::value_type(npc_entry, info)); - - // mark creature template as spell clickable - const_cast(cInfo)->npcflag |= UNIT_NPC_FLAG_SPELLCLICK; - - ++count; - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u spellclick definitions", count); -} - -void ObjectMgr::LoadWeatherZoneChances() -{ - uint32 count = 0; - - // 0 1 2 3 4 5 6 7 8 9 10 11 12 - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT zone, spring_rain_chance, spring_snow_chance, spring_storm_chance, summer_rain_chance, summer_snow_chance, summer_storm_chance, fall_rain_chance, fall_snow_chance, fall_storm_chance, winter_rain_chance, winter_snow_chance, winter_storm_chance FROM game_weather"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 weather definitions. DB table `game_weather` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 zone_id = fields[0].GetUInt32(); - - WeatherZoneChances& wzc = mWeatherZoneMap[zone_id]; - - for (uint8 season = 0; season < WEATHER_SEASONS; ++season) - { - wzc.data[season].rainChance = fields[season * (MAX_WEATHER_TYPE-1) + 1].GetUInt32(); - wzc.data[season].snowChance = fields[season * (MAX_WEATHER_TYPE-1) + 2].GetUInt32(); - wzc.data[season].stormChance = fields[season * (MAX_WEATHER_TYPE-1) + 3].GetUInt32(); - - if (wzc.data[season].rainChance > 100) - { - wzc.data[season].rainChance = 25; - sLog.outErrorDb("Weather for zone %u season %u has wrong rain chance > 100%%",zone_id,season); - } - - if (wzc.data[season].snowChance > 100) - { - wzc.data[season].snowChance = 25; - sLog.outErrorDb("Weather for zone %u season %u has wrong snow chance > 100%%",zone_id,season); - } - - if (wzc.data[season].stormChance > 100) - { - wzc.data[season].stormChance = 25; - sLog.outErrorDb("Weather for zone %u season %u has wrong storm chance > 100%%",zone_id,season); - } - } - - ++count; - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u weather definitions", count); -} - -void ObjectMgr::SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t) -{ - mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = t; - WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance); - if (t) - WorldDatabase.PExecute("INSERT INTO creature_respawn VALUES ('%u', '" UI64FMTD "', '%u')", loguid, uint64(t), instance); -} - -void ObjectMgr::DeleteCreatureData(uint32 guid) -{ - // remove mapid*cellid -> guid_set map - CreatureData const* data = GetCreatureData(guid); - if (data) - RemoveCreatureFromGrid(guid, data); - - mCreatureDataMap.erase(guid); -} - -void ObjectMgr::SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t) -{ - mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = t; - WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance); - if (t) - WorldDatabase.PExecute("INSERT INTO gameobject_respawn VALUES ('%u', '" UI64FMTD "', '%u')", loguid, uint64(t), instance); -} - -void ObjectMgr::DeleteRespawnTimeForInstance(uint32 instance) -{ - RespawnTimes::iterator next; - - for (RespawnTimes::iterator itr = mGORespawnTimes.begin(); itr != mGORespawnTimes.end(); itr = next) - { - next = itr; - ++next; - - if (GUID_HIPART(itr->first) == instance) - mGORespawnTimes.erase(itr); - } - - for (RespawnTimes::iterator itr = mCreatureRespawnTimes.begin(); itr != mCreatureRespawnTimes.end(); itr = next) - { - next = itr; - ++next; - - if (GUID_HIPART(itr->first) == instance) - mCreatureRespawnTimes.erase(itr); - } - - WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'", instance); - WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'", instance); -} - -void ObjectMgr::DeleteGOData(uint32 guid) -{ - // remove mapid*cellid -> guid_set map - GameObjectData const* data = GetGOData(guid); - if (data) - RemoveGameobjectFromGrid(guid, data); - - mGameObjectDataMap.erase(guid); -} - -void ObjectMgr::AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance) -{ - // corpses are always added to spawn mode 0 and they are spawned by their instance id - CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid]; - cell_guids.corpses[player_guid] = instance; -} - -void ObjectMgr::DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid) -{ - // corpses are always added to spawn mode 0 and they are spawned by their instance id - CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid]; - cell_guids.corpses.erase(player_guid); -} - -void ObjectMgr::LoadQuestRelationsHelper(QuestRelations& map,char const* table) -{ - map.clear(); // need for reload case - - uint32 count = 0; - - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT id,quest FROM %s",table); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded 0 quest relations from %s. DB table `%s` is empty.",table,table); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - uint32 id = fields[0].GetUInt32(); - uint32 quest = fields[1].GetUInt32(); - - if (mQuestTemplates.find(quest) == mQuestTemplates.end()) - { - sLog.outErrorDb("Table `%s: Quest %u listed for entry %u does not exist.",table,quest,id); - continue; - } - - map.insert(QuestRelations::value_type(id,quest)); - - ++count; - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u quest relations from %s", count,table); -} - -void ObjectMgr::LoadGameobjectQuestRelations() -{ - LoadQuestRelationsHelper(mGOQuestRelations,"gameobject_questrelation"); - - for (QuestRelations::iterator itr = mGOQuestRelations.begin(); itr != mGOQuestRelations.end(); ++itr) - { - GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first); - if (!goInfo) - sLog.outErrorDb("Table `gameobject_questrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second); - else if (goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER) - sLog.outErrorDb("Table `gameobject_questrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second); - } -} - -void ObjectMgr::LoadGameobjectInvolvedRelations() -{ - LoadQuestRelationsHelper(mGOQuestInvolvedRelations,"gameobject_involvedrelation"); - - for (QuestRelations::iterator itr = mGOQuestInvolvedRelations.begin(); itr != mGOQuestInvolvedRelations.end(); ++itr) - { - GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first); - if (!goInfo) - sLog.outErrorDb("Table `gameobject_involvedrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second); - else if (goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER) - sLog.outErrorDb("Table `gameobject_involvedrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second); - } -} - -void ObjectMgr::LoadCreatureQuestRelations() -{ - LoadQuestRelationsHelper(mCreatureQuestRelations,"creature_questrelation"); - - for (QuestRelations::iterator itr = mCreatureQuestRelations.begin(); itr != mCreatureQuestRelations.end(); ++itr) - { - CreatureInfo const* cInfo = GetCreatureTemplate(itr->first); - if (!cInfo) - sLog.outErrorDb("Table `creature_questrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second); - else if (!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER)) - sLog.outErrorDb("Table `creature_questrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER",itr->first,itr->second); - } -} - -void ObjectMgr::LoadCreatureInvolvedRelations() -{ - LoadQuestRelationsHelper(mCreatureQuestInvolvedRelations,"creature_involvedrelation"); - - for (QuestRelations::iterator itr = mCreatureQuestInvolvedRelations.begin(); itr != mCreatureQuestInvolvedRelations.end(); ++itr) - { - CreatureInfo const* cInfo = GetCreatureTemplate(itr->first); - if (!cInfo) - sLog.outErrorDb("Table `creature_involvedrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second); - else if (!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER)) - sLog.outErrorDb("Table `creature_involvedrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER",itr->first,itr->second); - } -} - -void ObjectMgr::LoadReservedPlayersNames() -{ - m_ReservedNames.clear(); // need for reload case - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT name FROM reserved_name"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u reserved player names", count); - return; - } - - barGoLink bar(result->GetRowCount()); - - Field* fields; - do - { - bar.step(); - fields = result->Fetch(); - std::string name= fields[0].GetCppString(); - - std::wstring wstr; - if (!Utf8toWStr (name,wstr)) - { - sLog.outError("Table `reserved_name` have invalid name: %s", name.c_str()); - continue; - } - - wstrToLower(wstr); - - m_ReservedNames.insert(wstr); - ++count; - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u reserved player names", count); -} - -bool ObjectMgr::IsReservedName(const std::string& name) const -{ - std::wstring wstr; - if (!Utf8toWStr (name,wstr)) - return false; - - wstrToLower(wstr); - - return m_ReservedNames.find(wstr) != m_ReservedNames.end(); -} - -enum LanguageType -{ - LT_BASIC_LATIN = 0x0000, - LT_EXTENDEN_LATIN = 0x0001, - LT_CYRILLIC = 0x0002, - LT_EAST_ASIA = 0x0004, - LT_ANY = 0xFFFF -}; - -static LanguageType GetRealmLanguageType(bool create) -{ - switch(sWorld.getConfig(CONFIG_REALM_ZONE)) - { - case REALM_ZONE_UNKNOWN: // any language - case REALM_ZONE_DEVELOPMENT: - case REALM_ZONE_TEST_SERVER: - case REALM_ZONE_QA_SERVER: - return LT_ANY; - case REALM_ZONE_UNITED_STATES: // extended-Latin - case REALM_ZONE_OCEANIC: - case REALM_ZONE_LATIN_AMERICA: - case REALM_ZONE_ENGLISH: - case REALM_ZONE_GERMAN: - case REALM_ZONE_FRENCH: - case REALM_ZONE_SPANISH: - return LT_EXTENDEN_LATIN; - case REALM_ZONE_KOREA: // East-Asian - case REALM_ZONE_TAIWAN: - case REALM_ZONE_CHINA: - return LT_EAST_ASIA; - case REALM_ZONE_RUSSIAN: // Cyrillic - return LT_CYRILLIC; - default: - return create ? LT_BASIC_LATIN : LT_ANY; // basic-Latin at create, any at login - } -} - -bool isValidString(std::wstring wstr, uint32 strictMask, bool numericOrSpace, bool create = false) -{ - if (strictMask == 0) // any language, ignore realm - { - if (isExtendedLatinString(wstr,numericOrSpace)) - return true; - if (isCyrillicString(wstr,numericOrSpace)) - return true; - if (isEastAsianString(wstr,numericOrSpace)) - return true; - return false; - } - - if (strictMask & 0x2) // realm zone specific - { - LanguageType lt = GetRealmLanguageType(create); - if (lt & LT_EXTENDEN_LATIN) - if (isExtendedLatinString(wstr,numericOrSpace)) - return true; - if (lt & LT_CYRILLIC) - if (isCyrillicString(wstr,numericOrSpace)) - return true; - if (lt & LT_EAST_ASIA) - if (isEastAsianString(wstr,numericOrSpace)) - return true; - } - - if (strictMask & 0x1) // basic Latin - { - if (isBasicLatinString(wstr,numericOrSpace)) - return true; - } - - return false; -} - -uint8 ObjectMgr::CheckPlayerName(const std::string& name, bool create) -{ - std::wstring wname; - if (!Utf8toWStr(name,wname)) - return CHAR_NAME_INVALID_CHARACTER; - - if (wname.size() > MAX_PLAYER_NAME) - return CHAR_NAME_TOO_LONG; - - uint32 minName = sWorld.getConfig(CONFIG_MIN_PLAYER_NAME); - if (wname.size() < minName) - return CHAR_NAME_TOO_SHORT; - - uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PLAYER_NAMES); - if (!isValidString(wname,strictMask,false,create)) - return CHAR_NAME_MIXED_LANGUAGES; - - return CHAR_NAME_SUCCESS; -} - -bool ObjectMgr::IsValidCharterName(const std::string& name) -{ - std::wstring wname; - if (!Utf8toWStr(name,wname)) - return false; - - if (wname.size() > MAX_CHARTER_NAME) - return false; - - uint32 minName = sWorld.getConfig(CONFIG_MIN_CHARTER_NAME); - if (wname.size() < minName) - return false; - - uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_CHARTER_NAMES); - - return isValidString(wname,strictMask,true); -} - -PetNameInvalidReason ObjectMgr::CheckPetName(const std::string& name) -{ - std::wstring wname; - if (!Utf8toWStr(name,wname)) - return PET_NAME_INVALID; - - if (wname.size() > MAX_PET_NAME) - return PET_NAME_TOO_LONG; - - uint32 minName = sWorld.getConfig(CONFIG_MIN_PET_NAME); - if (wname.size() < minName) - return PET_NAME_TOO_SHORT; - - uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PET_NAMES); - if (!isValidString(wname,strictMask,false)) - return PET_NAME_MIXED_LANGUAGES; - - return PET_NAME_SUCCESS; -} - -int ObjectMgr::GetIndexForLocale(LocaleConstant loc) -{ - if (loc == LOCALE_enUS) - return -1; - - for (size_t i=0; i < m_LocalForIndex.size(); ++i) - if (m_LocalForIndex[i] == loc) - return i; - - return -1; -} - -LocaleConstant ObjectMgr::GetLocaleForIndex(int i) -{ - if (i<0 || i >= m_LocalForIndex.size()) - return LOCALE_enUS; - - return m_LocalForIndex[i]; -} - -int ObjectMgr::GetOrNewIndexForLocale(LocaleConstant loc) -{ - if (loc == LOCALE_enUS) - return -1; - - for (size_t i=0; i < m_LocalForIndex.size(); ++i) - if (m_LocalForIndex[i] == loc) - return i; - - m_LocalForIndex.push_back(loc); - return m_LocalForIndex.size()-1; -} - -void ObjectMgr::LoadGameObjectForQuests() -{ - mGameObjectForQuestSet.clear(); // need for reload case - - if (!sGOStorage.MaxEntry) - { - barGoLink bar(1); - bar.step(); - sLog.outString(); - sLog.outString(">> Loaded 0 GameObjects for quests"); - return; - } - - barGoLink bar(sGOStorage.MaxEntry - 1); - uint32 count = 0; - - // collect GO entries for GO that must activated - for (uint32 go_entry = 1; go_entry < sGOStorage.MaxEntry; ++go_entry) - { - bar.step(); - GameObjectInfo const* goInfo = sGOStorage.LookupEntry(go_entry); - if (!goInfo) - continue; - - switch(goInfo->type) - { - // scan GO chest with loot including quest items - case GAMEOBJECT_TYPE_CHEST: - { - uint32 loot_id = goInfo->GetLootId(); - - // find quest loot for GO - if (LootTemplates_Gameobject.HaveQuestLootFor(loot_id)) - { - mGameObjectForQuestSet.insert(go_entry); - ++count; - } - break; - } - case GAMEOBJECT_TYPE_GOOBER: - { - if (goInfo->goober.questId) //quests objects - { - mGameObjectForQuestSet.insert(go_entry); - count++; - } - break; - } - default: - break; - } - } - - sLog.outString(); - sLog.outString(">> Loaded %u GameObjects for quests", count); -} - -bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value) -{ - int32 start_value = min_value; - int32 end_value = max_value; - // some string can have negative indexes range - if (start_value < 0) - { - if (end_value >= start_value) - { - sLog.outErrorDb("Table '%s' attempt loaded with invalid range (%d - %d), strings not loaded.",table,min_value,max_value); - return false; - } - - // real range (max+1,min+1) exaple: (-10,-1000) -> -999...-10+1 - std::swap(start_value,end_value); - ++start_value; - ++end_value; - } - else - { - if (start_value >= end_value) - { - sLog.outErrorDb("Table '%s' attempt loaded with invalid range (%d - %d), strings not loaded.",table,min_value,max_value); - return false; - } - } - - // cleanup affected map part for reloading case - for (TrinityStringLocaleMap::iterator itr = mTrinityStringLocaleMap.begin(); itr != mTrinityStringLocaleMap.end();) - { - if (itr->first >= start_value && itr->first < end_value) - mTrinityStringLocaleMap.erase(itr++); - else - ++itr; - } - - QueryResult_AutoPtr result = db.PQuery("SELECT entry,content_default,content_loc1,content_loc2,content_loc3,content_loc4,content_loc5,content_loc6,content_loc7,content_loc8 FROM %s",table); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - if (min_value == MIN_TRINITY_STRING_ID) // error only in case internal strings - sLog.outErrorDb(">> Loaded 0 trinity strings. DB table `%s` is empty. Cannot continue.",table); - else - sLog.outString(">> Loaded 0 string templates. DB table `%s` is empty.",table); - return false; - } - - uint32 count = 0; - - barGoLink bar(result->GetRowCount()); - - do - { - Field *fields = result->Fetch(); - bar.step(); - - int32 entry = fields[0].GetInt32(); - - if (entry == 0) - { - sLog.outErrorDb("Table `%s` contain reserved entry 0, ignored.",table); - continue; - } - else if (entry < start_value || entry >= end_value) - { - sLog.outErrorDb("Table `%s` contain entry %i out of allowed range (%d - %d), ignored.",table,entry,min_value,max_value); - continue; - } - - TrinityStringLocale& data = mTrinityStringLocaleMap[entry]; - - if (data.Content.size() > 0) - { - sLog.outErrorDb("Table `%s` contain data for already loaded entry %i (from another table?), ignored.",table,entry); - continue; - } - - data.Content.resize(1); - ++count; - - // 0 -> default, idx in to idx+1 - data.Content[0] = fields[1].GetCppString(); - - for (uint8 i = 1; i < MAX_LOCALE; ++i) - { - std::string str = fields[i+1].GetCppString(); - if (!str.empty()) - { - int idx = GetOrNewIndexForLocale(LocaleConstant(i)); - if (idx >= 0) - { - // 0 -> default, idx in to idx+1 - if (data.Content.size() <= idx+1) - data.Content.resize(idx+2); - - data.Content[idx+1] = str; - } - } - } - } while (result->NextRow()); - - sLog.outString(); - if (min_value == MIN_TRINITY_STRING_ID) - sLog.outString(">> Loaded %u Trinity strings from table %s", count,table); - else - sLog.outString(">> Loaded %u string templates from %s", count,table); - - return true; -} - -const char *ObjectMgr::GetTrinityString(int32 entry, int locale_idx) const -{ - // locale_idx == -1 -> default, locale_idx >= 0 in to idx+1 - // Content[0] always exist if exist TrinityStringLocale - if (TrinityStringLocale const *msl = GetTrinityStringLocale(entry)) - { - if (msl->Content.size() > locale_idx+1 && !msl->Content[locale_idx+1].empty()) - return msl->Content[locale_idx+1].c_str(); - else - return msl->Content[0].c_str(); - } - - if (entry > 0) - sLog.outErrorDb("Entry %i not found in `trinity_string` table.",entry); - else - sLog.outErrorDb("Trinity string entry %i not found in DB.",entry); - return ""; -} - -void ObjectMgr::LoadSpellDisabledEntrys() -{ - m_DisabledPlayerSpells.clear(); // need for reload case - m_DisabledCreatureSpells.clear(); - m_DisabledPetSpells.clear(); - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, disable_mask FROM spell_disabled"); - - uint32 total_count = 0; - - if (!result) - { - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u disabled spells", total_count); - return; - } - - barGoLink bar(result->GetRowCount()); - - Field* fields; - do - { - bar.step(); - fields = result->Fetch(); - uint32 spellid = fields[0].GetUInt32(); - if (!sSpellStore.LookupEntry(spellid)) - { - sLog.outErrorDb("Spell entry %u from `spell_disabled` doesn't exist in dbc, ignoring.",spellid); - continue; - } - uint32 disable_mask = fields[1].GetUInt32(); - if (disable_mask & SPELL_DISABLE_PLAYER) - m_DisabledPlayerSpells.insert(spellid); - if (disable_mask & SPELL_DISABLE_CREATURE) - m_DisabledCreatureSpells.insert(spellid); - if (disable_mask & SPELL_DISABLE_PET) - m_DisabledPetSpells.insert(spellid); - ++total_count; - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u disabled spells from `spell_disabled`", total_count); -} - -void ObjectMgr::LoadFishingBaseSkillLevel() -{ - mFishingBaseForArea.clear(); // for reload case - - uint32 count = 0; - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry,skill FROM skill_fishing_base_level"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded `skill_fishing_base_level`, table is empty!"); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - bar.step(); - - Field *fields = result->Fetch(); - uint32 entry = fields[0].GetUInt32(); - int32 skill = fields[1].GetInt32(); - - AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry); - if (!fArea) - { - sLog.outErrorDb("AreaId %u defined in `skill_fishing_base_level` does not exist",entry); - continue; - } - - mFishingBaseForArea[entry] = skill; - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u areas for fishing base skill level", count); -} - -bool ObjectMgr::CheckDeclinedNames(std::wstring mainpart, DeclinedName const& names) -{ - for (uint8 i =0; i < MAX_DECLINED_NAME_CASES; ++i) - { - std::wstring wname; - if (!Utf8toWStr(names.name[i],wname)) - return false; - - if (mainpart != GetMainPartOfName(wname,i+1)) - return false; - } - return true; -} - -uint32 ObjectMgr::GetAreaTriggerScriptId(uint32 trigger_id) -{ - AreaTriggerScriptMap::const_iterator i = mAreaTriggerScripts.find(trigger_id); - if (i!= mAreaTriggerScripts.end()) - return i->second; - return 0; -} - -SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial) -{ - switch(pSkill->categoryId) - { - case SKILL_CATEGORY_LANGUAGES: return SKILL_RANGE_LANGUAGE; - case SKILL_CATEGORY_WEAPON: - if (pSkill->id != SKILL_FIST_WEAPONS) - return SKILL_RANGE_LEVEL; - else - return SKILL_RANGE_MONO; - case SKILL_CATEGORY_ARMOR: - case SKILL_CATEGORY_CLASS: - if (pSkill->id != SKILL_LOCKPICKING) - return SKILL_RANGE_MONO; - else - return SKILL_RANGE_LEVEL; - case SKILL_CATEGORY_SECONDARY: - case SKILL_CATEGORY_PROFESSION: - // not set skills for professions and racial abilities - if (IsProfessionSkill(pSkill->id)) - return SKILL_RANGE_RANK; - else if (racial) - return SKILL_RANGE_NONE; - else - return SKILL_RANGE_MONO; - default: - case SKILL_CATEGORY_ATTRIBUTES: //not found in dbc - case SKILL_CATEGORY_GENERIC: //only GENERIC(DND) - return SKILL_RANGE_NONE; - } -} - -void ObjectMgr::LoadGameTele() -{ - m_GameTeleMap.clear(); // for reload case - - uint32 count = 0; - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id, position_x, position_y, position_z, orientation, map, name FROM game_tele"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded `game_tele`, table is empty!"); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - bar.step(); - - Field *fields = result->Fetch(); - - uint32 id = fields[0].GetUInt32(); - - GameTele gt; - - gt.position_x = fields[1].GetFloat(); - gt.position_y = fields[2].GetFloat(); - gt.position_z = fields[3].GetFloat(); - gt.orientation = fields[4].GetFloat(); - gt.mapId = fields[5].GetUInt32(); - gt.name = fields[6].GetCppString(); - - if (!MapManager::IsValidMapCoord(gt.mapId,gt.position_x,gt.position_y,gt.position_z,gt.orientation)) - { - sLog.outErrorDb("Wrong position for id %u (name: %s) in `game_tele` table, ignoring.",id,gt.name.c_str()); - continue; - } - - if (!Utf8toWStr(gt.name,gt.wnameLow)) - { - sLog.outErrorDb("Wrong UTF8 name for id %u in `game_tele` table, ignoring.",id); - continue; - } - - wstrToLower(gt.wnameLow); - - m_GameTeleMap[id] = gt; - - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u GameTeleports", count); -} - -GameTele const* ObjectMgr::GetGameTele(const std::string& name) const -{ - // explicit name case - std::wstring wname; - if (!Utf8toWStr(name,wname)) - return false; - - // converting string that we try to find to lower case - wstrToLower(wname); - - // Alternative first GameTele what contains wnameLow as substring in case no GameTele location found - const GameTele* alt = NULL; - for (GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr) - { - if (itr->second.wnameLow == wname) - return &itr->second; - else if (alt == NULL && itr->second.wnameLow.find(wname) != std::wstring::npos) - alt = &itr->second; - } - - return alt; -} - -bool ObjectMgr::AddGameTele(GameTele& tele) -{ - // find max id - uint32 new_id = 0; - for (GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr) - if (itr->first > new_id) - new_id = itr->first; - - // use next - ++new_id; - - if (!Utf8toWStr(tele.name,tele.wnameLow)) - return false; - - wstrToLower(tele.wnameLow); - - m_GameTeleMap[new_id] = tele; - - return WorldDatabase.PExecuteLog("INSERT INTO game_tele (id,position_x,position_y,position_z,orientation,map,name) VALUES (%u,%f,%f,%f,%f,%d,'%s')", - new_id,tele.position_x,tele.position_y,tele.position_z,tele.orientation,tele.mapId,tele.name.c_str()); -} - -bool ObjectMgr::DeleteGameTele(const std::string& name) -{ - // explicit name case - std::wstring wname; - if (!Utf8toWStr(name,wname)) - return false; - - // converting string that we try to find to lower case - wstrToLower(wname); - - for (GameTeleMap::iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr) - { - if (itr->second.wnameLow == wname) - { - WorldDatabase.PExecuteLog("DELETE FROM game_tele WHERE name = '%s'",itr->second.name.c_str()); - m_GameTeleMap.erase(itr); - return true; - } - } - - return false; -} - -void ObjectMgr::LoadMailLevelRewards() -{ - m_mailLevelRewardMap.clear(); // for reload case - - uint32 count = 0; - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT level, raceMask, mailTemplateId, senderEntry FROM mail_level_reward"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded `mail_level_reward`, table is empty!"); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - bar.step(); - - Field *fields = result->Fetch(); - - uint8 level = fields[0].GetUInt8(); - uint32 raceMask = fields[1].GetUInt32(); - uint32 mailTemplateId = fields[2].GetUInt32(); - uint32 senderEntry = fields[3].GetUInt32(); - - if (level > MAX_LEVEL) - { - sLog.outErrorDb("Table `mail_level_reward` have data for level %u that more supported by client (%u), ignoring.",level,MAX_LEVEL); - continue; - } - - if (!(raceMask & RACEMASK_ALL_PLAYABLE)) - { - sLog.outErrorDb("Table `mail_level_reward` have raceMask (%u) for level %u that not include any player races, ignoring.",raceMask,level); - continue; - } - - if (!sMailTemplateStore.LookupEntry(mailTemplateId)) - { - sLog.outErrorDb("Table `mail_level_reward` have invalid mailTemplateId (%u) for level %u that invalid not include any player races, ignoring.",mailTemplateId,level); - continue; - } - - if (!GetCreatureTemplateStore(senderEntry)) - { - sLog.outErrorDb("Table `mail_level_reward` have not existed sender creature entry (%u) for level %u that invalid not include any player races, ignoring.",senderEntry,level); - continue; - } - - m_mailLevelRewardMap[level].push_back(MailLevelReward(raceMask,mailTemplateId,senderEntry)); - - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u level dependent mail rewards,", count); -} - -bool ObjectMgr::AddSpellToTrainer(uint32 entry, uint32 spell, Field *fields, std::set *skip_trainers, std::set *talentIds) -{ - if (entry >= TRINITY_TRAINER_START_REF) - return false; - - CreatureInfo const* cInfo = GetCreatureTemplate(entry); - if (!cInfo) - { - sLog.outErrorDb("Table `npc_trainer` have entry for not existed creature template (Entry: %u), ignore", entry); - return false; - } - - if (!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER)) - { - if (skip_trainers->find(entry) == skip_trainers->end()) - { - sLog.outErrorDb("Table `npc_trainer` have data for not creature template (Entry: %u) without trainer flag, ignore", entry); - skip_trainers->insert(entry); - } - return false; - } - - SpellEntry const *spellinfo = sSpellStore.LookupEntry(spell); - if (!spellinfo) - { - sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u) has non existing spell %u, ignore", entry,spell); - return false; - } - - if (!SpellMgr::IsSpellValid(spellinfo)) - { - sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u) has broken learning spell %u, ignore", entry, spell); - return false; - } - - if (GetTalentSpellCost(spell)) - { - if (talentIds->count(spell) == 0) - { - sLog.outErrorDb("Table `npc_trainer` has talent as learning spell %u, ignore", spell); - talentIds->insert(spell); - } - return false; - } - - TrainerSpellData& data = m_mCacheTrainerSpellMap[entry]; - - TrainerSpell& trainerSpell = data.spellList[spell]; - trainerSpell.spell = spell; - trainerSpell.spellCost = fields[2].GetUInt32(); - trainerSpell.reqSkill = fields[3].GetUInt32(); - trainerSpell.reqSkillValue = fields[4].GetUInt32(); - trainerSpell.reqLevel = fields[5].GetUInt32(); - - if (!trainerSpell.reqLevel) - trainerSpell.reqLevel = spellinfo->spellLevel; - - // calculate learned spell for profession case when stored cast-spell - trainerSpell.learnedSpell[0] = spell; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (spellinfo->Effect[i] != SPELL_EFFECT_LEARN_SPELL) - continue; - if (trainerSpell.learnedSpell[0] == spell) - trainerSpell.learnedSpell[0] = 0; - // player must be able to cast spell on himself - if (spellinfo->EffectImplicitTargetA[i] != 0 && spellinfo->EffectImplicitTargetA[i] != TARGET_UNIT_TARGET_ALLY - && spellinfo->EffectImplicitTargetA[i] != TARGET_UNIT_TARGET_ANY && spellinfo->EffectImplicitTargetA[i] != TARGET_UNIT_CASTER) - { - sLog.outErrorDb("Table `npc_trainer` has spell %u for trainer entry %u with learn effect which has incorrect target type, ignoring learn effect!", spell, entry); - continue; - } - - trainerSpell.learnedSpell[i] = spellinfo->EffectTriggerSpell[i]; - } - - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (!trainerSpell.learnedSpell[i]) - continue; - if (SpellMgr::IsProfessionSpell(trainerSpell.learnedSpell[i])) - { - data.trainerType = 2; - break; - } - } - return true; -} -int ObjectMgr::LoadReferenceTrainer(uint32 trainer, int32 spell, std::set *skip_trainers, std::set *talentIds) -{ - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT entry, spell,spellcost,reqskill,reqskillvalue,reqlevel FROM npc_trainer WHERE entry='%d'", spell); - if (!result) - return 0; - - uint32 count = 0; - do - { - - Field* fields = result->Fetch(); - - int32 spell = fields[1].GetInt32(); - if (spell < 0) - count += this->LoadReferenceTrainer(trainer, -spell, skip_trainers, talentIds); - else if (this->AddSpellToTrainer(trainer, uint32(spell), fields, skip_trainers, talentIds)) - ++count; - } while (result->NextRow()); - - return count; -} - -void ObjectMgr::LoadTrainerSpell() -{ - // For reload case - for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr) - itr->second.Clear(); - m_mCacheTrainerSpellMap.clear(); - - std::set skip_trainers; - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, spell,spellcost,reqskill,reqskillvalue,reqlevel FROM npc_trainer"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded `npc_trainer`, table is empty!"); - return; - } - - barGoLink bar(result->GetRowCount()); - - std::set talentIds; - - uint32 count = 0; - do - { - bar.step(); - - Field* fields = result->Fetch(); - - uint32 entry = fields[0].GetUInt32(); - int32 spell = fields[1].GetInt32(); - if (spell < 0) - count += this->LoadReferenceTrainer(entry, -spell, &skip_trainers, &talentIds); - else if (this->AddSpellToTrainer(entry, uint32(spell), fields, &skip_trainers, &talentIds)) - ++count; - - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %d Trainers", count); -} - -int ObjectMgr::LoadReferenceVendor(int32 vendor, int32 item, std::set *skip_vendors) -{ - // find all items from the reference vendor - QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT item, maxcount, incrtime, ExtendedCost FROM npc_vendor WHERE entry='%d' ORDER BY slot ASC", item); - if (!result) - return 0; - - uint32 count = 0; - do - { - Field* fields = result->Fetch(); - - int32 item_id = fields[0].GetInt32(); - - // if item is a negative, its a reference - if (item_id < 0) - count += LoadReferenceVendor(vendor, -item_id, skip_vendors); - else - { - int32 maxcount = fields[1].GetInt32(); - uint32 incrtime = fields[2].GetUInt32(); - uint32 ExtendedCost = fields[3].GetUInt32(); - - if (!IsVendorItemValid(vendor,item_id,maxcount,incrtime,ExtendedCost,NULL,skip_vendors)) - continue; - - VendorItemData& vList = m_mCacheVendorItemMap[vendor]; - - vList.AddItem(item_id,maxcount,incrtime,ExtendedCost); - ++count; - } - - } while (result->NextRow()); - - return count; -} - -void ObjectMgr::LoadVendors() -{ - // For reload case - for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr) - itr->second.Clear(); - m_mCacheVendorItemMap.clear(); - - std::set skip_vendors; - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, item, maxcount, incrtime, ExtendedCost FROM npc_vendor ORDER BY entry, slot ASC"); - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded `npc_vendor`, table is empty!"); - return; - } - - barGoLink bar(result->GetRowCount()); - - uint32 count = 0; - do - { - bar.step(); - Field* fields = result->Fetch(); - - uint32 entry = fields[0].GetUInt32(); - int32 item_id = fields[1].GetInt32(); - - // if item is a negative, its a reference - if (item_id < 0) - count += LoadReferenceVendor(entry, -item_id, &skip_vendors); - else - { - int32 maxcount = fields[2].GetInt32(); - uint32 incrtime = fields[3].GetUInt32(); - uint32 ExtendedCost = fields[4].GetUInt32(); - - if (!IsVendorItemValid(entry,item_id,maxcount,incrtime,ExtendedCost,NULL,&skip_vendors)) - continue; - - VendorItemData& vList = m_mCacheVendorItemMap[entry]; - - vList.AddItem(item_id,maxcount,incrtime,ExtendedCost); - ++count; - } - - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %d Vendors ", count); -} - -void ObjectMgr::LoadNpcTextId() -{ - - m_mCacheNpcTextIdMap.clear(); - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT npc_guid, textid FROM npc_gossip"); - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded `npc_gossip`, table is empty!"); - return; - } - - barGoLink bar(result->GetRowCount()); - - uint32 count = 0; - uint32 guid,textid; - do - { - bar.step(); - - Field* fields = result->Fetch(); - - guid = fields[0].GetUInt32(); - textid = fields[1].GetUInt32(); - - if (!GetCreatureData(guid)) - { - sLog.outErrorDb("Table `npc_gossip` have not existed creature (GUID: %u) entry, ignore. ",guid); - continue; - } - if (!GetGossipText(textid)) - { - sLog.outErrorDb("Table `npc_gossip` for creature (GUID: %u) have wrong Textid (%u), ignore. ", guid, textid); - continue; - } - - m_mCacheNpcTextIdMap[guid] = textid ; - ++count; - - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %d NpcTextId ", count); -} - -void ObjectMgr::LoadGossipMenu() -{ - m_mGossipMenusMap.clear(); - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, text_id FROM gossip_menu"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded `gossip_menu`, table is empty!"); - return; - } - - barGoLink bar(result->GetRowCount()); - - uint32 count = 0; - - do - { - bar.step(); - - Field* fields = result->Fetch(); - - GossipMenus gMenu; - - gMenu.entry = fields[0].GetUInt32(); - gMenu.text_id = fields[1].GetUInt32(); - - if (!GetGossipText(gMenu.text_id)) - { - sLog.outErrorDb("Table gossip_menu entry %u are using non-existing text_id %u", gMenu.entry, gMenu.text_id); - continue; - } - - m_mGossipMenusMap.insert(GossipMenusMap::value_type(gMenu.entry, gMenu)); - - ++count; - } - while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u gossip_menu entries", count); -} - -void ObjectMgr::LoadGossipMenuItems() -{ - m_mGossipMenuItemsMap.clear(); - - QueryResult_AutoPtr result = WorldDatabase.Query( - "SELECT menu_id, id, option_icon, option_text, option_id, npc_option_npcflag, " - "action_menu_id, action_poi_id, action_script_id, box_coded, box_money, box_text " - "FROM gossip_menu_option"); - - if (!result) - { - barGoLink bar(1); - - bar.step(); - - sLog.outString(); - sLog.outErrorDb(">> Loaded gossip_menu_option, table is empty!"); - return; - } - - barGoLink bar(result->GetRowCount()); - - uint32 count = 0; - - std::set gossipScriptSet; - - for (ScriptMapMap::const_iterator itr = sGossipScripts.begin(); itr != sGossipScripts.end(); ++itr) - gossipScriptSet.insert(itr->first); - - do - { - bar.step(); - - Field* fields = result->Fetch(); - - GossipMenuItems gMenuItem; - - gMenuItem.menu_id = fields[0].GetUInt32(); - gMenuItem.id = fields[1].GetUInt32(); - gMenuItem.option_icon = fields[2].GetUInt8(); - gMenuItem.option_text = fields[3].GetCppString(); - gMenuItem.option_id = fields[4].GetUInt32(); - gMenuItem.npc_option_npcflag = fields[5].GetUInt32(); - gMenuItem.action_menu_id = fields[6].GetUInt32(); - gMenuItem.action_poi_id = fields[7].GetUInt32(); - gMenuItem.action_script_id = fields[8].GetUInt32(); - gMenuItem.box_coded = fields[9].GetUInt8() != 0; - gMenuItem.box_money = fields[10].GetUInt32(); - gMenuItem.box_text = fields[11].GetCppString(); - - if (gMenuItem.option_icon >= GOSSIP_ICON_MAX) - { - sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has unknown icon id %u. Replacing with GOSSIP_ICON_CHAT", gMenuItem.menu_id, gMenuItem.id, gMenuItem.option_icon); - gMenuItem.option_icon = GOSSIP_ICON_CHAT; - } - - if (gMenuItem.option_id >= GOSSIP_OPTION_MAX) - sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has unknown option id %u. Option will not be used", gMenuItem.menu_id, gMenuItem.id, gMenuItem.option_id); - - if (gMenuItem.action_poi_id && !GetPointOfInterest(gMenuItem.action_poi_id)) - { - sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u use non-existing action_poi_id %u, ignoring", gMenuItem.menu_id, gMenuItem.id, gMenuItem.action_poi_id); - gMenuItem.action_poi_id = 0; - } - - if (gMenuItem.action_script_id) - { - if (gMenuItem.option_id != GOSSIP_OPTION_GOSSIP) - { - sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u have action_script_id %u but option_id is not GOSSIP_OPTION_GOSSIP, ignoring", gMenuItem.menu_id, gMenuItem.id, gMenuItem.action_script_id); - continue; - } - - if (sGossipScripts.find(gMenuItem.action_script_id) == sGossipScripts.end()) - { - sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u have action_script_id %u that does not exist in `gossip_scripts`, ignoring", gMenuItem.menu_id, gMenuItem.id, gMenuItem.action_script_id); - continue; - } - - gossipScriptSet.erase(gMenuItem.action_script_id); - } - - m_mGossipMenuItemsMap.insert(GossipMenuItemsMap::value_type(gMenuItem.menu_id, gMenuItem)); - - ++count; - - } - while (result->NextRow()); - - if (!gossipScriptSet.empty()) - { - for (std::set::const_iterator itr = gossipScriptSet.begin(); itr != gossipScriptSet.end(); ++itr) - sLog.outErrorDb("Table `gossip_scripts` contain unused script, id %u.", *itr); - } - - sLog.outString(); - sLog.outString(">> Loaded %u gossip_menu_option entries", count); -} - -void ObjectMgr::AddVendorItem(uint32 entry,uint32 item, int32 maxcount, uint32 incrtime, uint32 extendedcost, bool savetodb) -{ - VendorItemData& vList = m_mCacheVendorItemMap[entry]; - vList.AddItem(item,maxcount,incrtime,extendedcost); - - if (savetodb) WorldDatabase.PExecuteLog("INSERT INTO npc_vendor (entry,item,maxcount,incrtime,extendedcost) VALUES('%u','%u','%u','%u','%u')",entry, item, maxcount,incrtime,extendedcost); -} - -bool ObjectMgr::RemoveVendorItem(uint32 entry,uint32 item, bool savetodb) -{ - CacheVendorItemMap::iterator iter = m_mCacheVendorItemMap.find(entry); - if (iter == m_mCacheVendorItemMap.end()) - return false; - - if(!iter->second.RemoveItem(item)) - return false; - - if (savetodb) WorldDatabase.PExecuteLog("DELETE FROM npc_vendor WHERE entry='%u' AND item='%u'",entry, item); - return true; -} - -bool ObjectMgr::IsVendorItemValid(uint32 vendor_entry, uint32 item_id, int32 maxcount, uint32 incrtime, uint32 ExtendedCost, Player* pl, std::set* skip_vendors, uint32 ORnpcflag) const -{ - CreatureInfo const* cInfo = GetCreatureTemplate(vendor_entry); - if (!cInfo) - { - if (pl) - ChatHandler(pl).SendSysMessage(LANG_COMMAND_VENDORSELECTION); - else - sLog.outErrorDb("Table `(game_event_)npc_vendor` have data for not existed creature template (Entry: %u), ignore", vendor_entry); - return false; - } - - if (!((cInfo->npcflag | ORnpcflag) & UNIT_NPC_FLAG_VENDOR)) - { - if (!skip_vendors || skip_vendors->count(vendor_entry) == 0) - { - if (pl) - ChatHandler(pl).SendSysMessage(LANG_COMMAND_VENDORSELECTION); - else - sLog.outErrorDb("Table `(game_event_)npc_vendor` have data for not creature template (Entry: %u) without vendor flag, ignore", vendor_entry); - - if (skip_vendors) - skip_vendors->insert(vendor_entry); - } - return false; - } - - if (!GetItemPrototype(item_id)) - { - if (pl) - ChatHandler(pl).PSendSysMessage(LANG_ITEM_NOT_FOUND, item_id); - else - sLog.outErrorDb("Table `(game_event_)npc_vendor` for Vendor (Entry: %u) have in item list non-existed item (%u), ignore",vendor_entry,item_id); - return false; - } - - if (ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost)) - { - if (pl) - ChatHandler(pl).PSendSysMessage(LANG_EXTENDED_COST_NOT_EXIST,ExtendedCost); - else - sLog.outErrorDb("Table `(game_event_)npc_vendor` have Item (Entry: %u) with wrong ExtendedCost (%u) for vendor (%u), ignore",item_id,ExtendedCost,vendor_entry); - return false; - } - - if (maxcount > 0 && incrtime == 0) - { - if (pl) - ChatHandler(pl).PSendSysMessage("MaxCount != 0 (%u) but IncrTime == 0", maxcount); - else - sLog.outErrorDb("Table `(game_event_)npc_vendor` has `maxcount` (%u) for item %u of vendor (Entry: %u) but `incrtime`=0, ignore", maxcount, item_id, vendor_entry); - return false; - } - else if (maxcount == 0 && incrtime > 0) - { - if (pl) - ChatHandler(pl).PSendSysMessage("MaxCount == 0 but IncrTime<>= 0"); - else - sLog.outErrorDb("Table `(game_event_)npc_vendor` has `maxcount`=0 for item %u of vendor (Entry: %u) but `incrtime`<>0, ignore", item_id, vendor_entry); - return false; - } - - VendorItemData const* vItems = GetNpcVendorItemList(vendor_entry); - if (!vItems) - return true; // later checks for non-empty lists - - if(vItems->FindItemCostPair(item_id,ExtendedCost)) - { - if (pl) - ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST, item_id, ExtendedCost); - else - sLog.outErrorDb( "Table `npc_vendor` has duplicate items %u (with extended cost %u) for vendor (Entry: %u), ignoring", item_id, ExtendedCost, vendor_entry); - return false; - } - - if (vItems->GetItemCount() >= MAX_VENDOR_ITEMS) - { - if (pl) - ChatHandler(pl).SendSysMessage(LANG_COMMAND_ADDVENDORITEMITEMS); - else - sLog.outErrorDb("Table `npc_vendor` has too many items (%u >= %i) for vendor (Entry: %u), ignore", vItems->GetItemCount(), MAX_VENDOR_ITEMS, vendor_entry); - return false; - } - - return true; -} - -void ObjectMgr::LoadScriptNames() -{ - m_scriptNames.push_back(""); - QueryResult_AutoPtr result = WorldDatabase.Query( - "SELECT DISTINCT(ScriptName) FROM creature_template WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM item_template WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM areatrigger_scripts WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(script) FROM instance_template WHERE script <> ''"); - - if (!result) - { - barGoLink bar(1); - bar.step(); - sLog.outString(); - sLog.outErrorDb(">> Loaded empty set of Script Names!"); - return; - } - - barGoLink bar(result->GetRowCount()); - - //OnEvent Changes - m_scriptNames.push_back("scripted_on_events"); - uint32 count = 1; - - do - { - bar.step(); - m_scriptNames.push_back((*result)[0].GetString()); - ++count; - } while (result->NextRow()); - - std::sort(m_scriptNames.begin(), m_scriptNames.end()); - sLog.outString(); - sLog.outString(">> Loaded %d Script Names", count); -} - -uint32 ObjectMgr::GetScriptId(const char *name) -{ - // use binary search to find the script name in the sorted vector - // assume "" is the first element - if (!name) return 0; - ScriptNameMap::const_iterator itr = - std::lower_bound(m_scriptNames.begin(), m_scriptNames.end(), name); - if (itr == m_scriptNames.end() || *itr != name) return 0; - return itr - m_scriptNames.begin(); -} - -void ObjectMgr::CheckScripts(ScriptMapMap const& scripts,std::set& ids) -{ - for (ScriptMapMap::const_iterator itrMM = scripts.begin(); itrMM != scripts.end(); ++itrMM) - { - for (ScriptMap::const_iterator itrM = itrMM->second.begin(); itrM != itrMM->second.end(); ++itrM) - { - switch(itrM->second.command) - { - case SCRIPT_COMMAND_TALK: - { - if (!GetTrinityStringLocale (itrM->second.dataint)) - sLog.outErrorDb("Table `db_script_string` not has string id %u used db script (ID: %u)", itrM->second.dataint, itrMM->first); - - if (ids.find(itrM->second.dataint) != ids.end()) - ids.erase(itrM->second.dataint); - } - } - } - } -} - -void ObjectMgr::LoadDbScriptStrings() -{ - LoadTrinityStrings(WorldDatabase,"db_script_string",MIN_DB_SCRIPT_STRING_ID,MAX_DB_SCRIPT_STRING_ID); - - std::set ids; - - for (int32 i = MIN_DB_SCRIPT_STRING_ID; i < MAX_DB_SCRIPT_STRING_ID; ++i) - if (GetTrinityStringLocale(i)) - ids.insert(i); - - CheckScripts(sQuestEndScripts,ids); - CheckScripts(sQuestStartScripts,ids); - CheckScripts(sSpellScripts,ids); - CheckScripts(sGameObjectScripts,ids); - CheckScripts(sEventScripts,ids); - - CheckScripts(sWaypointScripts,ids); - - for (std::set::const_iterator itr = ids.begin(); itr != ids.end(); ++itr) - sLog.outErrorDb("Table `db_script_string` has unused string id %u", *itr); -} - -// Functions for scripting access -uint32 GetAreaTriggerScriptId(uint32 trigger_id) -{ - return objmgr.GetAreaTriggerScriptId(trigger_id); -} - -bool LoadTrinityStrings(DatabaseType& db, char const* table,int32 start_value, int32 end_value) -{ - // MAX_DB_SCRIPT_STRING_ID is max allowed negative value for scripts (scrpts can use only more deep negative values - // start/end reversed for negative values - if (start_value > MAX_DB_SCRIPT_STRING_ID || end_value >= start_value) - { - sLog.outErrorDb("Table '%s' load attempted with range (%d - %d) reserved by Trinity, strings not loaded.",table,start_value,end_value+1); - return false; - } - - return objmgr.LoadTrinityStrings(db,table,start_value,end_value); -} - -uint32 GetScriptId(const char *name) -{ - return objmgr.GetScriptId(name); -} - -ObjectMgr::ScriptNameMap & GetScriptNames() -{ - return objmgr.GetScriptNames(); -} - -GameObjectInfo const *GetGameObjectInfo(uint32 id) -{ - return objmgr.GetGameObjectInfo(id); -} - -CreatureInfo const *GetCreatureInfo(uint32 id) -{ - return objmgr.GetCreatureTemplate(id); -} - -void ObjectMgr::LoadTransportEvents() -{ - - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, waypoint_id, event_id FROM transport_events"); - - if (!result) - { - barGoLink bar1(1); - bar1.step(); - sLog.outString("\n>> Transport events table is empty \n"); - return; - } - - barGoLink bar1(result->GetRowCount()); - - do - { - bar1.step(); - - Field *fields = result->Fetch(); - - //Load event values - uint32 entry = fields[0].GetUInt32(); - uint32 waypoint_id = fields[1].GetUInt32(); - uint32 event_id = fields[2].GetUInt32(); - - uint32 event_count = (entry*100)+waypoint_id; - TransportEventMap[event_count] = event_id; - } - while (result->NextRow()); - - sLog.outString("\n>> Loaded %u transport events \n", result->GetRowCount()); -} - -CreatureInfo const* GetCreatureTemplateStore(uint32 entry) -{ - return sCreatureStorage.LookupEntry(entry); -} - -Quest const* GetQuestTemplateStore(uint32 entry) -{ - return objmgr.GetQuestTemplate(entry); -} - -uint64 ObjectMgr::GenerateGMTicketId() -{ - return ++m_GMticketid; -} - -void ObjectMgr::LoadGMTickets() -{ - if (!m_GMTicketList.empty()) - { - for (GmTicketList::const_iterator itr = m_GMTicketList.begin(); itr != m_GMTicketList.end(); ++itr) - delete *itr; - } - m_GMTicketList.clear(); - m_GMticketid = 0; - - QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT guid, playerGuid, name, message, createtime, map, posX, posY, posZ, timestamp, closed, assignedto, comment FROM gm_tickets"); - - if (!result) - { - barGoLink bar(1); - bar.step(); - sLog.outString(); - sLog.outString(">> GM Tickets table is empty, no tickets were loaded."); - return; - } - - uint16 count = 0; - barGoLink bar ((*result).GetRowCount()); - GM_Ticket *ticket; - do - { - Field *fields = result->Fetch(); - ticket = new GM_Ticket; - ticket->guid = fields[0].GetUInt64(); - ticket->playerGuid = fields[1].GetUInt64(); - ticket->name = fields[2].GetCppString(); - ticket->message = fields[3].GetCppString(); - ticket->createtime = fields[4].GetUInt64(); - ticket->map = fields[5].GetUInt32(); - ticket->pos_x = fields[6].GetFloat(); - ticket->pos_y = fields[7].GetFloat(); - ticket->pos_z = fields[8].GetFloat(); - ticket->timestamp = fields[9].GetUInt64(); - ticket->closed = fields[10].GetUInt64(); - ticket->assignedToGM = fields[11].GetUInt64(); - ticket->comment = fields[12].GetCppString(); - ++count; - bar.step(); - - m_GMTicketList.push_back(ticket); - - } while (result->NextRow()); - - result = CharacterDatabase.Query("SELECT MAX(guid) from gm_tickets"); - - if (result) - { - Field *fields = result->Fetch(); - m_GMticketid = fields[0].GetUInt64(); - } - - sLog.outString(">> Loaded %u GM Tickets from the database.", count); -} - -void ObjectMgr::AddOrUpdateGMTicket(GM_Ticket &ticket, bool create) -{ - if (create) - m_GMTicketList.push_back(&ticket); - - _AddOrUpdateGMTicket(ticket); -} - -void ObjectMgr::_AddOrUpdateGMTicket(GM_Ticket &ticket) -{ - std::string msg(ticket.message), name(ticket.name), comment(ticket.comment); - CharacterDatabase.escape_string(msg); - CharacterDatabase.escape_string(name); - CharacterDatabase.escape_string(comment); - std::ostringstream ss; - ss << "REPLACE INTO gm_tickets (guid, playerGuid, name, message, createtime, map, posX, posY, posZ, timestamp, closed, assignedto, comment) VALUES('"; - ss << ticket.guid << "', '"; - ss << ticket.playerGuid << "', '"; - ss << name << "', '"; - ss << msg << "', '" ; - ss << ticket.createtime << "', '"; - ss << ticket.map << "', '"; - ss << ticket.pos_x << "', '"; - ss << ticket.pos_y << "', '"; - ss << ticket.pos_z << "', '"; - ss << ticket.timestamp << "', '"; - ss << ticket.closed << "', '"; - ss << ticket.assignedToGM << "', '"; - ss << comment << "');"; - CharacterDatabase.BeginTransaction(); - CharacterDatabase.Execute(ss.str().c_str()); - CharacterDatabase.CommitTransaction(); -} - -void ObjectMgr::RemoveGMTicket(GM_Ticket *ticket, int64 source, bool permanently) -{ - for (GmTicketList::iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i) - if ((*i)->guid == ticket->guid) - { - if (permanently) - { - CharacterDatabase.PExecute("DELETE FROM gm_tickets WHERE guid = '%u'", ticket->guid); - i = m_GMTicketList.erase(i); - ticket = NULL; - return; - } - (*i)->closed = source; - _AddOrUpdateGMTicket(*(*i)); - } -} - -void ObjectMgr::RemoveGMTicket(uint64 ticketGuid, int64 source, bool permanently) -{ - GM_Ticket *ticket = GetGMTicket(ticketGuid); - assert(ticket); - RemoveGMTicket(ticket, source, permanently); -} - -CreatureBaseStats const* ObjectMgr::GetCreatureBaseStats(uint8 level, uint8 unitClass) -{ - CreatureBaseStatsMap::const_iterator it = m_creatureBaseStatsMap.find(MAKE_PAIR16(level,unitClass)); - - if (it != m_creatureBaseStatsMap.end()) - return &(it->second); - - struct DefaultCreatureBaseStats : public CreatureBaseStats - { - DefaultCreatureBaseStats() - { - BaseArmor = 1; - for (uint8 j = 0; j < MAX_CREATURE_BASE_HP; ++j) - BaseHealth[j] = 1; - BaseMana = 0; - } - }; - static const DefaultCreatureBaseStats def_stats; - return &def_stats; -} - -void ObjectMgr::LoadCreatureClassLevelStats() -{ - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT level, class, basehp0, basehp1, basehp2, basemana, basearmor FROM creature_classlevelstats"); - - if (!result) - { - barGoLink bar(1); - bar.step(); - sLog.outString(); - sLog.outString(">> Loaded 0 creature base stats. DB table `creature_classlevelstats` is empty."); - return; - } - - barGoLink bar(result->GetRowCount()); - uint32 counter = 0; - - do - { - Field *fields = result->Fetch(); - - uint8 Level = fields[0].GetUInt32(); - uint8 Class = fields[1].GetUInt8(); - - CreatureBaseStats stats; - for (uint8 i = 0; i < MAX_CREATURE_BASE_HP; ++i) - stats.BaseHealth[i] = fields[i + 2].GetUInt32(); - stats.BaseMana = fields[5].GetUInt32(); - stats.BaseArmor = fields[6].GetUInt32(); - - if (Level > STRONG_MAX_LEVEL) - { - sLog.outErrorDb("Creature base stats for class %u has invalid level %u (max is %u) - set to %u", - Class, Level, STRONG_MAX_LEVEL, STRONG_MAX_LEVEL); - Level = STRONG_MAX_LEVEL; - } - - if (!Class || ((1 << (Class - 1)) & CLASSMASK_ALL_CREATURES) == 0) - sLog.outErrorDb("Creature base stats for level %u has invalid class %u", - Level, Class); - - for (uint8 i = 0; i < MAX_CREATURE_BASE_HP; ++i) - { - if (stats.BaseHealth[i] < 1) - { - sLog.outErrorDb("Creature base stats for class %u, level %u has invalid zero base HP[%u] - set to 1", - Class, Level, i); - stats.BaseHealth[i] = 1; - } - } - - m_creatureBaseStatsMap[MAKE_PAIR16(Level, Class)] = stats; - - bar.step(); - ++counter; - } - while (result->NextRow()); - - for (uint32 i = 0; i < sCreatureStorage.MaxEntry; ++i) - { - CreatureInfo const* info = sCreatureStorage.LookupEntry(i); - if (!info) - continue; - - for (uint16 lvl = info->minlevel; lvl <= info->maxlevel; ++lvl) - { - if (m_creatureBaseStatsMap.find(MAKE_PAIR16(lvl, info->unit_class)) == m_creatureBaseStatsMap.end()) - sLog.outErrorDb("Missing base stats for creature class %u level %u", info->unit_class, lvl); - } - } - - sLog.outString(); - sLog.outString(">> Loaded %u creature base stats.", counter); -} diff --git a/src/server/game/Entities/Object/ObjectMgr.h b/src/server/game/Entities/Object/ObjectMgr.h deleted file mode 100644 index 79b6ffdd0eb..00000000000 --- a/src/server/game/Entities/Object/ObjectMgr.h +++ /dev/null @@ -1,1085 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _OBJECTMGR_H -#define _OBJECTMGR_H - -#include "Log.h" -#include "Object.h" -#include "Bag.h" -#include "Creature.h" -#include "Player.h" -#include "DynamicObject.h" -#include "GameObject.h" -#include "Corpse.h" -#include "QuestDef.h" -#include "Path.h" -#include "ItemPrototype.h" -#include "NPCHandler.h" -#include "Database/DatabaseEnv.h" -#include "Mail.h" -#include "Map.h" -#include "ObjectAccessor.h" -#include "ObjectDefines.h" -#include "Policies/Singleton.h" -#include "Database/SQLStorage.h" -#include "Vehicle.h" -#include "ObjectMgr.h" -#include -#include -#include -#include "ConditionMgr.h" - -extern SQLStorage sCreatureStorage; -extern SQLStorage sCreatureDataAddonStorage; -extern SQLStorage sCreatureInfoAddonStorage; -extern SQLStorage sCreatureModelStorage; -extern SQLStorage sEquipmentStorage; -extern SQLStorage sGOStorage; -extern SQLStorage sPageTextStore; -extern SQLStorage sItemStorage; -extern SQLStorage sInstanceTemplate; - -class Group; -class Guild; -class ArenaTeam; -class Path; -class TransportPath; -class Item; - -struct GameTele -{ - float position_x; - float position_y; - float position_z; - float orientation; - uint32 mapId; - std::string name; - std::wstring wnameLow; -}; - -typedef UNORDERED_MAP GameTeleMap; - -struct ScriptInfo -{ - uint32 id; - uint32 delay; - uint32 command; - uint32 datalong; - uint32 datalong2; - int32 dataint; - float x; - float y; - float z; - float o; -}; - -typedef std::multimap ScriptMap; -typedef std::map ScriptMapMap; -extern ScriptMapMap sQuestEndScripts; -extern ScriptMapMap sQuestStartScripts; -extern ScriptMapMap sSpellScripts; -extern ScriptMapMap sGameObjectScripts; -extern ScriptMapMap sEventScripts; -extern ScriptMapMap sGossipScripts; -extern ScriptMapMap sWaypointScripts; - -struct SpellClickInfo -{ - uint32 spellId; - uint32 questStart; // quest start (quest must be active or rewarded for spell apply) - uint32 questEnd; // quest end (quest don't must be rewarded for spell apply) - bool questStartCanActive; // if true then quest start can be active (not only rewarded) - uint8 castFlags; - uint32 auraRequired; - uint32 auraForbidden; - SpellClickUserTypes userType; - - // helpers - bool IsFitToRequirements(Player const* player, Creature const * clickNpc) const; -}; - -typedef std::multimap SpellClickInfoMap; -typedef std::pair SpellClickInfoMapBounds; - -struct AreaTrigger -{ - uint32 access_id; - uint32 target_mapId; - float target_X; - float target_Y; - float target_Z; - float target_Orientation; -}; - -typedef std::set CellGuidSet; -typedef std::map CellCorpseSet; -struct CellObjectGuids -{ - CellGuidSet creatures; - CellGuidSet gameobjects; - CellCorpseSet corpses; -}; -typedef UNORDERED_MAP CellObjectGuidsMap; -typedef UNORDERED_MAP MapObjectGuids; - -typedef UNORDERED_MAP RespawnTimes; - -// Trinity string ranges -#define MIN_TRINITY_STRING_ID 1 // 'trinity_string' -#define MAX_TRINITY_STRING_ID 2000000000 -#define MIN_DB_SCRIPT_STRING_ID MAX_TRINITY_STRING_ID // 'db_script_string' -#define MAX_DB_SCRIPT_STRING_ID 2000010000 -#define MIN_CREATURE_AI_TEXT_STRING_ID (-1) // 'creature_ai_texts' -#define MAX_CREATURE_AI_TEXT_STRING_ID (-1000000) - -// Trinity Trainer Reference start range -#define TRINITY_TRAINER_START_REF 200000 - -struct TrinityStringLocale -{ - std::vector Content; // 0 -> default, i -> i-1 locale index -}; - -typedef std::map CreatureLinkedRespawnMap; -typedef UNORDERED_MAP CreatureDataMap; -typedef UNORDERED_MAP GameObjectDataMap; -typedef UNORDERED_MAP CreatureLocaleMap; -typedef UNORDERED_MAP GameObjectLocaleMap; -typedef UNORDERED_MAP ItemLocaleMap; -typedef UNORDERED_MAP QuestLocaleMap; -typedef UNORDERED_MAP NpcTextLocaleMap; -typedef UNORDERED_MAP PageTextLocaleMap; -typedef UNORDERED_MAP TrinityStringLocaleMap; -typedef UNORDERED_MAP GossipMenuItemsLocaleMap; -typedef UNORDERED_MAP PointOfInterestLocaleMap; - -typedef std::multimap QuestRelations; -typedef std::multimap ItemRequiredTargetMap; -typedef std::pair ItemRequiredTargetMapBounds; - -struct PetLevelInfo -{ - PetLevelInfo() : health(0), mana(0) { for (uint8 i=0; i < MAX_STATS; ++i) stats[i] = 0; } - - uint16 stats[MAX_STATS]; - uint16 health; - uint16 mana; - uint16 armor; -}; - -struct MailLevelReward -{ - MailLevelReward() : raceMask(0), mailTemplateId(0), senderEntry(0) {} - MailLevelReward(uint32 _raceMask, uint32 _mailTemplateId, uint32 _senderEntry) : raceMask(_raceMask), mailTemplateId(_mailTemplateId), senderEntry(_senderEntry) {} - - uint32 raceMask; - uint32 mailTemplateId; - uint32 senderEntry; -}; - -typedef std::list MailLevelRewardList; -typedef UNORDERED_MAP MailLevelRewardMap; - -struct ReputationOnKillEntry -{ - uint32 repfaction1; - uint32 repfaction2; - bool is_teamaward1; - uint32 reputation_max_cap1; - int32 repvalue1; - bool is_teamaward2; - uint32 reputation_max_cap2; - int32 repvalue2; - bool team_dependent; -}; - -struct PointOfInterest -{ - uint32 entry; - float x; - float y; - uint32 icon; - uint32 flags; - uint32 data; - std::string icon_name; -}; - -struct GossipMenuItems -{ - uint32 menu_id; - uint32 id; - uint8 option_icon; - std::string option_text; - uint32 option_id; - uint32 npc_option_npcflag; - uint32 action_menu_id; - uint32 action_poi_id; - uint32 action_script_id; - bool box_coded; - uint32 box_money; - std::string box_text; - ConditionList conditions; -}; - -struct GossipMenus -{ - uint32 entry; - uint32 text_id; - ConditionList conditions; -}; - -typedef std::multimap GossipMenusMap; -typedef std::pair GossipMenusMapBounds; -typedef std::pair GossipMenusMapBoundsNonConst; -typedef std::multimap GossipMenuItemsMap; -typedef std::pair GossipMenuItemsMapBounds; -typedef std::pair GossipMenuItemsMapBoundsNonConst; - -struct QuestPOIPoint -{ - int32 x; - int32 y; - - QuestPOIPoint() : x(0), y(0) {} - QuestPOIPoint(int32 _x, int32 _y) : x(_x), y(_y) {} -}; - -struct QuestPOI -{ - uint32 Id; - int32 ObjectiveIndex; - uint32 MapId; - uint32 AreaId; - uint32 Unk2; - uint32 Unk3; - uint32 Unk4; - std::vector points; - - QuestPOI() : Id(0), ObjectiveIndex(0), MapId(0), AreaId(0), Unk2(0), Unk3(0), Unk4(0) {} - QuestPOI(uint32 id, int32 objIndex, uint32 mapId, uint32 areaId, uint32 unk2, uint32 unk3, uint32 unk4) : Id(id), ObjectiveIndex(objIndex), MapId(mapId), AreaId(areaId), Unk2(unk2), Unk3(unk3), Unk4(unk4) {} -}; - -typedef std::vector QuestPOIVector; -typedef UNORDERED_MAP QuestPOIMap; - -#define WEATHER_SEASONS 4 -struct WeatherSeasonChances -{ - uint32 rainChance; - uint32 snowChance; - uint32 stormChance; -}; - -struct WeatherZoneChances -{ - WeatherSeasonChances data[WEATHER_SEASONS]; -}; - -struct GraveYardData -{ - uint32 safeLocId; - uint32 team; -}; -typedef std::multimap GraveYardMap; - -// NPC gossip text id -typedef UNORDERED_MAP CacheNpcTextIdMap; - -typedef UNORDERED_MAP CacheVendorItemMap; -typedef UNORDERED_MAP CacheTrainerSpellMap; - -enum SkillRangeType -{ - SKILL_RANGE_LANGUAGE, // 300..300 - SKILL_RANGE_LEVEL, // 1..max skill for level - SKILL_RANGE_MONO, // 1..1, grey monolite bar - SKILL_RANGE_RANK, // 1..skill for known rank - SKILL_RANGE_NONE, // 0..0 always -}; - -struct GM_Ticket -{ - uint64 guid; - uint64 playerGuid; - std::string name; - float pos_x; - float pos_y; - float pos_z; - uint32 map; - std::string message; - uint64 createtime; - uint64 timestamp; - int64 closed; // 0 = Open, -1 = Console, playerGuid = player abandoned ticket, other = GM who closed it. - uint64 assignedToGM; - std::string comment; -}; -typedef std::list GmTicketList; -SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial); - -#define MAX_PLAYER_NAME 12 // max allowed by client name length -#define MAX_INTERNAL_PLAYER_NAME 15 // max server internal player name length (> MAX_PLAYER_NAME for support declined names) -#define MAX_PET_NAME 12 // max allowed by client name length -#define MAX_CHARTER_NAME 24 // max allowed by client name length - -bool normalizePlayerName(std::string& name); - -struct LanguageDesc -{ - Language lang_id; - uint32 spell_id; - uint32 skill_id; -}; - -extern LanguageDesc lang_description[LANGUAGES_COUNT]; - LanguageDesc const* GetLanguageDescByID(uint32 lang); - -class PlayerDumpReader; - -class ObjectMgr -{ - friend class PlayerDumpReader; - - public: - ObjectMgr(); - ~ObjectMgr(); - - typedef UNORDERED_MAP ItemMap; - - typedef std::set< Group * > GroupSet; - - typedef UNORDERED_MAP GuildMap; - - typedef UNORDERED_MAP ArenaTeamMap; - - typedef UNORDERED_MAP QuestMap; - - typedef UNORDERED_MAP AreaTriggerMap; - - typedef UNORDERED_MAP AreaTriggerScriptMap; - - typedef UNORDERED_MAP AccessRequirementMap; - - typedef UNORDERED_MAP RepOnKillMap; - typedef UNORDERED_MAP PointOfInterestMap; - - typedef UNORDERED_MAP WeatherZoneMap; - - typedef std::vector ScriptNameMap; - - UNORDERED_MAP TransportEventMap; - - Player* GetPlayer(const char* name) const { return ObjectAccessor::Instance().FindPlayerByName(name);} - Player* GetPlayer(uint64 guid) const { return ObjectAccessor::FindPlayer(guid); } - - static GameObjectInfo const *GetGameObjectInfo(uint32 id) { return sGOStorage.LookupEntry(id); } - int LoadReferenceVendor(int32 vendor, int32 item_id, std::set *skip_vendors); - - void LoadGameobjectInfo(); - void AddGameobjectInfo(GameObjectInfo *goinfo); - - Group * GetGroupByGUID(const uint64 &guid) const; - void AddGroup(Group* group) { mGroupSet.insert(group); } - void RemoveGroup(Group* group) { mGroupSet.erase(group); } - - Guild* GetGuildByLeader(uint64 const&guid) const; - Guild* GetGuildById(uint32 GuildId) const; - Guild* GetGuildByName(const std::string& guildname) const; - std::string GetGuildNameById(uint32 GuildId) const; - void AddGuild(Guild* guild); - void RemoveGuild(uint32 Id); - - ArenaTeam* GetArenaTeamById(uint32 arenateamid) const; - ArenaTeam* GetArenaTeamByName(const std::string& arenateamname) const; - ArenaTeam* GetArenaTeamByCaptain(uint64 const& guid) const; - void AddArenaTeam(ArenaTeam* arenaTeam); - void RemoveArenaTeam(uint32 Id); - ArenaTeamMap::iterator GetArenaTeamMapBegin() { return mArenaTeamMap.begin(); } - ArenaTeamMap::iterator GetArenaTeamMapEnd() { return mArenaTeamMap.end(); } - - static CreatureInfo const *GetCreatureTemplate(uint32 id); - CreatureModelInfo const *GetCreatureModelInfo(uint32 modelid); - CreatureModelInfo const* GetCreatureModelRandomGender(uint32 display_id); - uint32 ChooseDisplayId(uint32 team, const CreatureInfo *cinfo, const CreatureData *data = NULL); - EquipmentInfo const *GetEquipmentInfo(uint32 entry); - static CreatureDataAddon const *GetCreatureAddon(uint32 lowguid) - { - return sCreatureDataAddonStorage.LookupEntry(lowguid); - } - - static CreatureDataAddon const *GetCreatureTemplateAddon(uint32 entry) - { - return sCreatureInfoAddonStorage.LookupEntry(entry); - } - - static ItemPrototype const* GetItemPrototype(uint32 id) { return sItemStorage.LookupEntry(id); } - - static InstanceTemplate const* GetInstanceTemplate(uint32 map) - { - return sInstanceTemplate.LookupEntry(map); - } - - PetLevelInfo const* GetPetLevelInfo(uint32 creature_id, uint8 level) const; - - PlayerClassInfo const* GetPlayerClassInfo(uint32 class_) const - { - if (class_ >= MAX_CLASSES) return NULL; - return &playerClassInfo[class_]; - } - void GetPlayerClassLevelInfo(uint32 class_,uint8 level, PlayerClassLevelInfo* info) const; - - PlayerInfo const* GetPlayerInfo(uint32 race, uint32 class_) const - { - if (race >= MAX_RACES) return NULL; - if (class_ >= MAX_CLASSES) return NULL; - PlayerInfo const* info = &playerInfo[race][class_]; - if (info->displayId_m == 0 || info->displayId_f == 0) return NULL; - return info; - } - void GetPlayerLevelInfo(uint32 race, uint32 class_, uint8 level, PlayerLevelInfo* info) const; - - uint64 GetPlayerGUIDByName(std::string name) const; - bool GetPlayerNameByGUID(const uint64 &guid, std::string &name) const; - uint32 GetPlayerTeamByGUID(const uint64 &guid) const; - uint32 GetPlayerAccountIdByGUID(const uint64 &guid) const; - uint32 GetPlayerAccountIdByPlayerName(const std::string& name) const; - - uint32 GetNearestTaxiNode(float x, float y, float z, uint32 mapid, uint32 team); - void GetTaxiPath(uint32 source, uint32 destination, uint32 &path, uint32 &cost); - uint32 GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt_team = false); - void GetTaxiPathNodes(uint32 path, Path &pathnodes, std::vector& mapIds); - void GetTransportPathNodes(uint32 path, TransportPath &pathnodes); - - Quest const* GetQuestTemplate(uint32 quest_id) const - { - QuestMap::const_iterator itr = mQuestTemplates.find(quest_id); - return itr != mQuestTemplates.end() ? itr->second : NULL; - } - QuestMap const& GetQuestTemplates() const { return mQuestTemplates; } - - uint32 GetQuestForAreaTrigger(uint32 Trigger_ID) const - { - QuestAreaTriggerMap::const_iterator itr = mQuestAreaTriggerMap.find(Trigger_ID); - if (itr != mQuestAreaTriggerMap.end()) - return itr->second; - return 0; - } - bool IsTavernAreaTrigger(uint32 Trigger_ID) const - { - return mTavernAreaTriggerSet.find(Trigger_ID) != mTavernAreaTriggerSet.end(); - } - - bool IsGameObjectForQuests(uint32 entry) const - { - return mGameObjectForQuestSet.find(entry) != mGameObjectForQuestSet.end(); - } - - GossipText const* GetGossipText(uint32 Text_ID) const; - - WorldSafeLocsEntry const *GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team); - bool AddGraveYardLink(uint32 id, uint32 zone, uint32 team, bool inDB = true); - void RemoveGraveYardLink(uint32 id, uint32 zone, uint32 team, bool inDB = false); - void LoadGraveyardZones(); - GraveYardData const* FindGraveYardData(uint32 id, uint32 zone); - - AreaTrigger const* GetAreaTrigger(uint32 trigger) const - { - AreaTriggerMap::const_iterator itr = mAreaTriggers.find(trigger); - if (itr != mAreaTriggers.end()) - return &itr->second; - return NULL; - } - - AccessRequirement const* GetAccessRequirement(uint32 requirement) const - { - AccessRequirementMap::const_iterator itr = mAccessRequirements.find(requirement); - if (itr != mAccessRequirements.end()) - return &itr->second; - return NULL; - } - - AreaTrigger const* GetGoBackTrigger(uint32 Map) const; - AreaTrigger const* GetMapEntranceTrigger(uint32 Map) const; - - uint32 GetAreaTriggerScriptId(uint32 trigger_id); - - ReputationOnKillEntry const* GetReputationOnKilEntry(uint32 id) const - { - RepOnKillMap::const_iterator itr = mRepOnKill.find(id); - if (itr != mRepOnKill.end()) - return &itr->second; - return NULL; - } - - PointOfInterest const* GetPointOfInterest(uint32 id) const - { - PointOfInterestMap::const_iterator itr = mPointsOfInterest.find(id); - if (itr != mPointsOfInterest.end()) - return &itr->second; - return NULL; - } - - QuestPOIVector const* GetQuestPOIVector(uint32 questId) - { - QuestPOIMap::const_iterator itr = mQuestPOIMap.find(questId); - if (itr != mQuestPOIMap.end()) - return &itr->second; - return NULL; - } - - VehicleAccessoryList const* GetVehicleAccessoryList(uint32 uiEntry) const - { - VehicleAccessoryMap::const_iterator itr = m_VehicleAccessoryMap.find(uiEntry); - if (itr != m_VehicleAccessoryMap.end()) - return &itr->second; - return NULL; - } - - void LoadGuilds(); - void LoadArenaTeams(); - void LoadGroups(); - void LoadQuests(); - void LoadQuestRelations() - { - sLog.outString("Loading GO Start Quest Data..."); - LoadGameobjectQuestRelations(); - sLog.outString("Loading GO End Quest Data..."); - LoadGameobjectInvolvedRelations(); - sLog.outString("Loading Creature Start Quest Data..."); - LoadCreatureQuestRelations(); - sLog.outString("Loading Creature End Quest Data..."); - LoadCreatureInvolvedRelations(); - } - void LoadGameobjectQuestRelations(); - void LoadGameobjectInvolvedRelations(); - void LoadCreatureQuestRelations(); - void LoadCreatureInvolvedRelations(); - - QuestRelations mGOQuestRelations; - QuestRelations mGOQuestInvolvedRelations; - QuestRelations mCreatureQuestRelations; - QuestRelations mCreatureQuestInvolvedRelations; - - void LoadGameObjectScripts(); - void LoadQuestEndScripts(); - void LoadQuestStartScripts(); - void LoadEventScripts(); - void LoadSpellScripts(); - void LoadGossipScripts(); - void LoadWaypointScripts(); - - void LoadTransportEvents(); - - bool LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value); - bool LoadTrinityStrings() { return LoadTrinityStrings(WorldDatabase,"trinity_string",MIN_TRINITY_STRING_ID,MAX_TRINITY_STRING_ID); } - void LoadDbScriptStrings(); - void LoadCreatureClassLevelStats(); - void LoadCreatureLocales(); - void LoadCreatureTemplates(); - void CheckCreatureTemplate(CreatureInfo const* cInfo); - void LoadCreatures(); - void LoadCreatureLinkedRespawn(); - bool CheckCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid) const; - bool SetCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid); - void LoadCreatureRespawnTimes(); - void LoadCreatureAddons(); - void LoadCreatureModelInfo(); - void LoadEquipmentTemplates(); - void LoadGameObjectLocales(); - void LoadGameobjects(); - void LoadGameobjectRespawnTimes(); - void LoadItemPrototypes(); - void LoadItemLocales(); - void LoadQuestLocales(); - void LoadNpcTextLocales(); - void LoadPageTextLocales(); - void LoadGossipMenuItemsLocales(); - void LoadPointOfInterestLocales(); - void LoadInstanceTemplate(); - void LoadMailLevelRewards(); - void LoadVehicleAccessories(); - - void LoadGossipText(); - - void LoadAreaTriggerTeleports(); - void LoadAccessRequirements(); - void LoadQuestAreaTriggers(); - void LoadAreaTriggerScripts(); - void LoadTavernAreaTriggers(); - void LoadGameObjectForQuests(); - - void LoadPageTexts(); - - void LoadPlayerInfo(); - void LoadPetLevelInfo(); - void LoadExplorationBaseXP(); - void LoadPetNames(); - void LoadPetNumber(); - void LoadCorpses(); - void LoadFishingBaseSkillLevel(); - - void LoadReputationOnKill(); - void LoadPointsOfInterest(); - void LoadQuestPOI(); - - void LoadNPCSpellClickSpells(); - - void LoadWeatherZoneChances(); - void LoadGameTele(); - - void LoadNpcTextId(); - - void LoadGossipMenu(); - void LoadGossipMenuItems(); - - void LoadVendors(); - void LoadTrainerSpell(); - bool AddSpellToTrainer(uint32 entry, uint32 spell, Field *fields, std::set *skip_trainers, std::set *talentIds); - int LoadReferenceTrainer(uint32 trainer, int32 spell, std::set *skip_trainers, std::set *talentIds); - void LoadGMTickets(); - - std::string GeneratePetName(uint32 entry); - uint32 GetBaseXP(uint8 level); - uint32 GetXPForLevel(uint8 level); - - int32 GetFishingBaseSkillLevel(uint32 entry) const - { - FishingBaseSkillMap::const_iterator itr = mFishingBaseForArea.find(entry); - return itr != mFishingBaseForArea.end() ? itr->second : 0; - } - - void ReturnOrDeleteOldMails(bool serverUp); - - CreatureBaseStats const* GetCreatureBaseStats(uint8 level, uint8 unitClass); - - void SetHighestGuids(); - uint32 GenerateLowGuid(HighGuid guidhigh); - uint32 GenerateArenaTeamId(); - uint32 GenerateAuctionID(); - uint64 GenerateEquipmentSetGuid(); - uint32 GenerateGuildId(); - uint32 GenerateMailID(); - uint32 GeneratePetNumber(); - - typedef std::multimap ExclusiveQuestGroups; - ExclusiveQuestGroups mExclusiveQuestGroups; - - MailLevelReward const* GetMailLevelReward(uint32 level,uint32 raceMask) - { - MailLevelRewardMap::const_iterator map_itr = m_mailLevelRewardMap.find(level); - if (map_itr == m_mailLevelRewardMap.end()) - return NULL; - - for (MailLevelRewardList::const_iterator set_itr = map_itr->second.begin(); set_itr != map_itr->second.end(); ++set_itr) - if (set_itr->raceMask & raceMask) - return &*set_itr; - - return NULL; - } - - WeatherZoneChances const* GetWeatherChances(uint32 zone_id) const - { - WeatherZoneMap::const_iterator itr = mWeatherZoneMap.find(zone_id); - if (itr != mWeatherZoneMap.end()) - return &itr->second; - else - return NULL; - } - - CellObjectGuids const& GetCellObjectGuids(uint16 mapid, uint8 spawnMode, uint32 cell_id) - { - return mMapObjectGuids[MAKE_PAIR32(mapid,spawnMode)][cell_id]; - } - - CreatureData const* GetCreatureData(uint32 guid) const - { - CreatureDataMap::const_iterator itr = mCreatureDataMap.find(guid); - if (itr == mCreatureDataMap.end()) return NULL; - return &itr->second; - } - CreatureData& NewOrExistCreatureData(uint32 guid) { return mCreatureDataMap[guid]; } - void DeleteCreatureData(uint32 guid); - uint32 GetLinkedRespawnGuid(uint32 guid) const - { - CreatureLinkedRespawnMap::const_iterator itr = mCreatureLinkedRespawnMap.find(guid); - if (itr == mCreatureLinkedRespawnMap.end()) return 0; - return itr->second; - } - CreatureLocale const* GetCreatureLocale(uint32 entry) const - { - CreatureLocaleMap::const_iterator itr = mCreatureLocaleMap.find(entry); - if (itr == mCreatureLocaleMap.end()) return NULL; - return &itr->second; - } - GameObjectLocale const* GetGameObjectLocale(uint32 entry) const - { - GameObjectLocaleMap::const_iterator itr = mGameObjectLocaleMap.find(entry); - if (itr == mGameObjectLocaleMap.end()) return NULL; - return &itr->second; - } - ItemLocale const* GetItemLocale(uint32 entry) const - { - ItemLocaleMap::const_iterator itr = mItemLocaleMap.find(entry); - if (itr == mItemLocaleMap.end()) return NULL; - return &itr->second; - } - QuestLocale const* GetQuestLocale(uint32 entry) const - { - QuestLocaleMap::const_iterator itr = mQuestLocaleMap.find(entry); - if (itr == mQuestLocaleMap.end()) return NULL; - return &itr->second; - } - NpcTextLocale const* GetNpcTextLocale(uint32 entry) const - { - NpcTextLocaleMap::const_iterator itr = mNpcTextLocaleMap.find(entry); - if (itr == mNpcTextLocaleMap.end()) return NULL; - return &itr->second; - } - PageTextLocale const* GetPageTextLocale(uint32 entry) const - { - PageTextLocaleMap::const_iterator itr = mPageTextLocaleMap.find(entry); - if (itr == mPageTextLocaleMap.end()) return NULL; - return &itr->second; - } - GossipMenuItemsLocale const* GetGossipMenuItemsLocale(uint32 entry) const - { - GossipMenuItemsLocaleMap::const_iterator itr = mGossipMenuItemsLocaleMap.find(entry); - if (itr == mGossipMenuItemsLocaleMap.end()) return NULL; - return &itr->second; - } - PointOfInterestLocale const* GetPointOfInterestLocale(uint32 poi_id) const - { - PointOfInterestLocaleMap::const_iterator itr = mPointOfInterestLocaleMap.find(poi_id); - if (itr == mPointOfInterestLocaleMap.end()) return NULL; - return &itr->second; - } - - bool IsGoOfSpecificEntrySpawned(uint32 entry) const - { - for (GameObjectDataMap::const_iterator it = mGameObjectDataMap.begin(); it != mGameObjectDataMap.end(); ++it) - if (it->second.id == entry) - return true; - - return false; - } - - GameObjectData const* GetGOData(uint32 guid) const - { - GameObjectDataMap::const_iterator itr = mGameObjectDataMap.find(guid); - if (itr == mGameObjectDataMap.end()) return NULL; - return &itr->second; - } - GameObjectData& NewGOData(uint32 guid) { return mGameObjectDataMap[guid]; } - void DeleteGOData(uint32 guid); - - TrinityStringLocale const* GetTrinityStringLocale(int32 entry) const - { - TrinityStringLocaleMap::const_iterator itr = mTrinityStringLocaleMap.find(entry); - if (itr == mTrinityStringLocaleMap.end()) return NULL; - return &itr->second; - } - const char *GetTrinityString(int32 entry, int locale_idx) const; - const char *GetTrinityStringForDBCLocale(int32 entry) const { return GetTrinityString(entry,DBCLocaleIndex); } - int32 GetDBCLocaleIndex() const { return DBCLocaleIndex; } - void SetDBCLocaleIndex(uint32 lang) { DBCLocaleIndex = GetIndexForLocale(LocaleConstant(lang)); } - - void AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance); - void DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid); - - time_t GetCreatureRespawnTime(uint32 loguid, uint32 instance) { return mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)]; } - void SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t); - time_t GetGORespawnTime(uint32 loguid, uint32 instance) { return mGORespawnTimes[MAKE_PAIR64(loguid,instance)]; } - void SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t); - void DeleteRespawnTimeForInstance(uint32 instance); - - // grid objects - void AddCreatureToGrid(uint32 guid, CreatureData const* data); - void RemoveCreatureFromGrid(uint32 guid, CreatureData const* data); - void AddGameobjectToGrid(uint32 guid, GameObjectData const* data); - void RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data); - uint32 AddGOData(uint32 entry, uint32 map, float x, float y, float z, float o, uint32 spawntimedelay = 0, float rotation0 = 0, float rotation1 = 0, float rotation2 = 0, float rotation3 = 0); - uint32 AddCreData(uint32 entry, uint32 team, uint32 map, float x, float y, float z, float o, uint32 spawntimedelay = 0); - bool MoveCreData(uint32 guid, uint32 map, Position pos); - - // reserved names - void LoadReservedPlayersNames(); - bool IsReservedName(const std::string& name) const; - - // name with valid structure and symbols - static uint8 CheckPlayerName(const std::string& name, bool create = false); - static PetNameInvalidReason CheckPetName(const std::string& name); - static bool IsValidCharterName(const std::string& name); - - static bool CheckDeclinedNames(std::wstring mainpart, DeclinedName const& names); - - void LoadSpellDisabledEntrys(); - bool IsPlayerSpellDisabled(uint32 spellid) { return (m_DisabledPlayerSpells.count(spellid) != 0); } - bool IsCreatureSpellDisabled(uint32 spellid) { return (m_DisabledCreatureSpells.count(spellid) != 0); } - bool IsPetSpellDisabled(uint32 spellid) { return (m_DisabledPetSpells.count(spellid) != 0); } - - int GetIndexForLocale(LocaleConstant loc); - LocaleConstant GetLocaleForIndex(int i); - - GameTele const* GetGameTele(uint32 id) const - { - GameTeleMap::const_iterator itr = m_GameTeleMap.find(id); - if (itr == m_GameTeleMap.end()) return NULL; - return &itr->second; - } - GameTele const* GetGameTele(const std::string& name) const; - GameTeleMap const& GetGameTeleMap() const { return m_GameTeleMap; } - bool AddGameTele(GameTele& data); - bool DeleteGameTele(const std::string& name); - - uint32 GetNpcGossip(uint32 entry) const - { - CacheNpcTextIdMap::const_iterator iter = m_mCacheNpcTextIdMap.find(entry); - if (iter == m_mCacheNpcTextIdMap.end()) - return 0; - - return iter->second; - } - - TrainerSpellData const* GetNpcTrainerSpells(uint32 entry) const - { - CacheTrainerSpellMap::const_iterator iter = m_mCacheTrainerSpellMap.find(entry); - if (iter == m_mCacheTrainerSpellMap.end()) - return NULL; - - return &iter->second; - } - - VendorItemData const* GetNpcVendorItemList(uint32 entry) const - { - CacheVendorItemMap::const_iterator iter = m_mCacheVendorItemMap.find(entry); - if (iter == m_mCacheVendorItemMap.end()) - return NULL; - - return &iter->second; - } - void AddVendorItem(uint32 entry,uint32 item, int32 maxcount, uint32 incrtime, uint32 ExtendedCost, bool savetodb = true); // for event - bool RemoveVendorItem(uint32 entry,uint32 item, bool savetodb = true); // for event - bool IsVendorItemValid(uint32 vendor_entry, uint32 item, int32 maxcount, uint32 ptime, uint32 ExtendedCost, Player* pl = NULL, std::set* skip_vendors = NULL, uint32 ORnpcflag = 0) const; - - void LoadScriptNames(); - ScriptNameMap &GetScriptNames() { return m_scriptNames; } - const char * GetScriptName(uint32 id) { return id < m_scriptNames.size() ? m_scriptNames[id].c_str() : ""; } - uint32 GetScriptId(const char *name); - - int GetOrNewIndexForLocale(LocaleConstant loc); - - SpellClickInfoMapBounds GetSpellClickInfoMapBounds(uint32 creature_id) const - { - return SpellClickInfoMapBounds(mSpellClickInfoMap.lower_bound(creature_id),mSpellClickInfoMap.upper_bound(creature_id)); - } - - GM_Ticket *GetGMTicket(uint64 ticketGuid) - { - for (GmTicketList::const_iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i) - if ((*i) && (*i)->guid == ticketGuid) - return (*i); - - return NULL; - } - GM_Ticket *GetGMTicketByPlayer(uint64 playerGuid) - { - for (GmTicketList::const_iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i) - if ((*i) && (*i)->playerGuid == playerGuid && (*i)->closed == 0) - return (*i); - - return NULL; - } - - GossipMenusMapBounds GetGossipMenusMapBounds(uint32 uiMenuId) const - { - return GossipMenusMapBounds(m_mGossipMenusMap.lower_bound(uiMenuId),m_mGossipMenusMap.upper_bound(uiMenuId)); - } - - GossipMenusMapBoundsNonConst GetGossipMenusMapBoundsNonConst(uint32 uiMenuId) - { - return GossipMenusMapBoundsNonConst(m_mGossipMenusMap.lower_bound(uiMenuId),m_mGossipMenusMap.upper_bound(uiMenuId)); - } - - GossipMenuItemsMapBounds GetGossipMenuItemsMapBounds(uint32 uiMenuId) const - { - return GossipMenuItemsMapBounds(m_mGossipMenuItemsMap.lower_bound(uiMenuId),m_mGossipMenuItemsMap.upper_bound(uiMenuId)); - } - GossipMenuItemsMapBoundsNonConst GetGossipMenuItemsMapBoundsNonConst(uint32 uiMenuId) - { - return GossipMenuItemsMapBoundsNonConst(m_mGossipMenuItemsMap.lower_bound(uiMenuId),m_mGossipMenuItemsMap.upper_bound(uiMenuId)); - } - - void AddOrUpdateGMTicket(GM_Ticket &ticket, bool create = false); - void _AddOrUpdateGMTicket(GM_Ticket &ticket); - void RemoveGMTicket(uint64 ticketGuid, int64 source = -1, bool permanently = false); - void RemoveGMTicket(GM_Ticket *ticket, int64 source = -1, bool permanently = false); - GmTicketList m_GMTicketList; - uint64 GenerateGMTicketId(); - - // for wintergrasp only - GraveYardMap mGraveYardMap; - protected: - - // first free id for selected id type - uint32 m_arenaTeamId; - uint32 m_auctionid; - uint64 m_equipmentSetGuid; - uint32 m_guildId; - uint32 m_ItemTextId; - uint32 m_mailid; - uint32 m_hiPetNumber; - uint64 m_GMticketid; - - // first free low guid for seelcted guid type - uint32 m_hiCharGuid; - uint32 m_hiCreatureGuid; - uint32 m_hiPetGuid; - uint32 m_hiVehicleGuid; - uint32 m_hiItemGuid; - uint32 m_hiGoGuid; - uint32 m_hiDoGuid; - uint32 m_hiCorpseGuid; - uint32 m_hiGroupGuid; - - QuestMap mQuestTemplates; - - typedef UNORDERED_MAP GossipTextMap; - typedef UNORDERED_MAP QuestAreaTriggerMap; - typedef std::set TavernAreaTriggerSet; - typedef std::set GameObjectForQuestSet; - - GroupSet mGroupSet; - GuildMap mGuildMap; - ArenaTeamMap mArenaTeamMap; - - QuestAreaTriggerMap mQuestAreaTriggerMap; - TavernAreaTriggerSet mTavernAreaTriggerSet; - GameObjectForQuestSet mGameObjectForQuestSet; - GossipTextMap mGossipText; - AreaTriggerMap mAreaTriggers; - AreaTriggerScriptMap mAreaTriggerScripts; - AccessRequirementMap mAccessRequirements; - - RepOnKillMap mRepOnKill; - - GossipMenusMap m_mGossipMenusMap; - GossipMenuItemsMap m_mGossipMenuItemsMap; - PointOfInterestMap mPointsOfInterest; - - QuestPOIMap mQuestPOIMap; - - WeatherZoneMap mWeatherZoneMap; - - //character reserved names - typedef std::set ReservedNamesMap; - ReservedNamesMap m_ReservedNames; - - std::set m_DisabledPlayerSpells; - std::set m_DisabledCreatureSpells; - std::set m_DisabledPetSpells; - -// GraveYardMap mGraveYardMap; - - GameTeleMap m_GameTeleMap; - - ScriptNameMap m_scriptNames; - - SpellClickInfoMap mSpellClickInfoMap; - - ItemRequiredTargetMap m_ItemRequiredTarget; - - VehicleAccessoryMap m_VehicleAccessoryMap; - - typedef std::vector LocalForIndex; - LocalForIndex m_LocalForIndex; - - int DBCLocaleIndex; - - private: - void LoadScripts(ScriptMapMap& scripts, char const* tablename); - void CheckScripts(ScriptMapMap const& scripts,std::set& ids); - void LoadCreatureAddons(SQLStorage& creatureaddons, char const* entryName, char const* comment); - void ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr); - void LoadQuestRelationsHelper(QuestRelations& map,char const* table); - - MailLevelRewardMap m_mailLevelRewardMap; - - CreatureBaseStatsMap m_creatureBaseStatsMap; - - typedef std::map PetLevelInfoMap; - // PetLevelInfoMap[creature_id][level] - PetLevelInfoMap petInfo; // [creature_id][level] - - PlayerClassInfo playerClassInfo[MAX_CLASSES]; - - void BuildPlayerLevelInfo(uint8 race, uint8 class_, uint8 level, PlayerLevelInfo* plinfo) const; - PlayerInfo playerInfo[MAX_RACES][MAX_CLASSES]; - - typedef std::vector PlayerXPperLevel; // [level] - PlayerXPperLevel mPlayerXPperLevel; - - typedef std::map BaseXPMap; // [area level][base xp] - BaseXPMap mBaseXPTable; - - typedef std::map FishingBaseSkillMap; // [areaId][base skill level] - FishingBaseSkillMap mFishingBaseForArea; - - typedef std::map > HalfNameMap; - HalfNameMap PetHalfName0; - HalfNameMap PetHalfName1; - - MapObjectGuids mMapObjectGuids; - CreatureDataMap mCreatureDataMap; - CreatureLinkedRespawnMap mCreatureLinkedRespawnMap; - CreatureLocaleMap mCreatureLocaleMap; - GameObjectDataMap mGameObjectDataMap; - GameObjectLocaleMap mGameObjectLocaleMap; - ItemLocaleMap mItemLocaleMap; - QuestLocaleMap mQuestLocaleMap; - NpcTextLocaleMap mNpcTextLocaleMap; - PageTextLocaleMap mPageTextLocaleMap; - TrinityStringLocaleMap mTrinityStringLocaleMap; - GossipMenuItemsLocaleMap mGossipMenuItemsLocaleMap; - PointOfInterestLocaleMap mPointOfInterestLocaleMap; - RespawnTimes mCreatureRespawnTimes; - RespawnTimes mGORespawnTimes; - - CacheNpcTextIdMap m_mCacheNpcTextIdMap; - CacheVendorItemMap m_mCacheVendorItemMap; - CacheTrainerSpellMap m_mCacheTrainerSpellMap; - - std::set difficultyEntries[MAX_DIFFICULTY - 1]; // already loaded difficulty 1 value in creatures, used in CheckCreatureTemplate - std::set hasDifficultyEntries[MAX_DIFFICULTY - 1]; // already loaded creatures with difficulty 1 values, used in CheckCreatureTemplate - -}; - -#define objmgr Trinity::Singleton::Instance() - -// scripting access functions - bool LoadTrinityStrings(DatabaseType& db, char const* table,int32 start_value = MAX_CREATURE_AI_TEXT_STRING_ID, int32 end_value = std::numeric_limits::min()); - uint32 GetAreaTriggerScriptId(uint32 trigger_id); - uint32 GetScriptId(const char *name); - ObjectMgr::ScriptNameMap& GetScriptNames(); - GameObjectInfo const *GetGameObjectInfo(uint32 id); - CreatureInfo const *GetCreatureInfo(uint32 id); - CreatureInfo const* GetCreatureTemplateStore(uint32 entry); - Quest const* GetQuestTemplateStore(uint32 entry); - -#endif diff --git a/src/server/game/Entities/Object/ObjectPosSelector.cpp b/src/server/game/Entities/Object/ObjectPosSelector.cpp new file mode 100644 index 00000000000..899dfec3fdb --- /dev/null +++ b/src/server/game/Entities/Object/ObjectPosSelector.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ObjectPosSelector.h" + +ObjectPosSelector::ObjectPosSelector(float x,float y,float size,float dist) +: m_center_x(x),m_center_y(y),m_size(size),m_dist(dist) +{ + m_anglestep = acos(m_dist/(m_dist+2*m_size)); + + m_nextUsedPos[USED_POS_PLUS] = m_UsedPosLists[USED_POS_PLUS].end(); + m_nextUsedPos[USED_POS_MINUS] = m_UsedPosLists[USED_POS_MINUS].end(); + + m_smallStepAngle[USED_POS_PLUS] = 0; + m_smallStepAngle[USED_POS_MINUS] = 0; + + m_smallStepOk[USED_POS_PLUS] = false; + m_smallStepOk[USED_POS_MINUS] = false; + + m_smallStepNextUsedPos[USED_POS_PLUS] = NULL; + m_smallStepNextUsedPos[USED_POS_MINUS] = NULL; +} + +ObjectPosSelector::UsedPosList::value_type const* ObjectPosSelector::nextUsedPos(UsedPosType uptype) +{ + UsedPosList::const_iterator itr = m_nextUsedPos[uptype]; + if(itr!=m_UsedPosLists[uptype].end()) + ++itr; + + if(itr==m_UsedPosLists[uptype].end()) + { + if(!m_UsedPosLists[~uptype].empty()) + return &*m_UsedPosLists[~uptype].rbegin(); + else + return NULL; + } + else + return &*itr; +} + +void ObjectPosSelector::AddUsedPos(float size,float angle,float dist) +{ + if(angle>=0) + m_UsedPosLists[USED_POS_PLUS].insert(UsedPosList::value_type(angle,UsedPos(1.0,size,dist))); + else + m_UsedPosLists[USED_POS_MINUS].insert(UsedPosList::value_type(-angle,UsedPos(-1.0,size,dist))); +} + +void ObjectPosSelector::InitializeAngle() +{ + m_nextUsedPos[USED_POS_PLUS] = m_UsedPosLists[USED_POS_PLUS].begin(); + m_nextUsedPos[USED_POS_MINUS] = m_UsedPosLists[USED_POS_MINUS].begin(); + + m_smallStepAngle[USED_POS_PLUS] = 0; + m_smallStepAngle[USED_POS_MINUS] = 0; + + m_smallStepOk[USED_POS_PLUS] = true; + m_smallStepOk[USED_POS_MINUS] = true; +} + +bool ObjectPosSelector::FirstAngle(float& angle) +{ + if(m_UsedPosLists[USED_POS_PLUS].empty() && !m_UsedPosLists[USED_POS_MINUS].empty() ) + return NextAngleFor(*m_UsedPosLists[USED_POS_MINUS].begin(),1.0,USED_POS_PLUS,angle); + else if(m_UsedPosLists[USED_POS_MINUS].empty() && !m_UsedPosLists[USED_POS_PLUS].empty() ) + return NextAngleFor(*m_UsedPosLists[USED_POS_PLUS].begin(),-1.0,USED_POS_MINUS,angle); + + return false; +} + +bool ObjectPosSelector::NextAngle(float& angle) +{ + while(m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() || + m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end() || + m_smallStepOk[USED_POS_PLUS] || m_smallStepOk[USED_POS_MINUS] ) + { + // calculate next possible angle + if(NextPosibleAngle(angle)) + return true; + } + + return false; +} + +bool ObjectPosSelector::NextUsedAngle(float& angle) +{ + while(m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() || + m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end() ) + { + // calculate next possible angle + if(!NextPosibleAngle(angle)) + return true; + } + + return false; +} + +bool ObjectPosSelector::NextPosibleAngle( float& angle ) +{ + // ++ direction less updated + if( m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() && + (m_nextUsedPos[USED_POS_MINUS]==m_UsedPosLists[USED_POS_MINUS].end() || m_nextUsedPos[USED_POS_PLUS]->first <= m_nextUsedPos[USED_POS_MINUS]->first) ) + { + bool ok; + if(m_smallStepOk[USED_POS_PLUS]) + ok = NextSmallStepAngle(1.0,USED_POS_PLUS,angle); + else + ok = NextAngleFor(*m_nextUsedPos[USED_POS_PLUS],1.0,USED_POS_PLUS,angle); + + if(!ok) + ++m_nextUsedPos[USED_POS_PLUS]; // increase. only at fail (original or checked) + return ok; + } + // -- direction less updated + else if( m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end()) + { + bool ok; + if(m_smallStepOk[USED_POS_MINUS]) + ok = NextSmallStepAngle(-1.0,USED_POS_MINUS,angle); + else + ok = NextAngleFor(*m_nextUsedPos[USED_POS_MINUS],-1.0,USED_POS_MINUS,angle); + + if(!ok) + ++m_nextUsedPos[USED_POS_MINUS]; + return ok; + } + else // both list empty + { + if( m_smallStepOk[USED_POS_PLUS] && (!m_smallStepOk[USED_POS_MINUS] || m_smallStepAngle[USED_POS_PLUS] <= m_smallStepAngle[USED_POS_MINUS]) ) + { + return NextSmallStepAngle(1.0,USED_POS_PLUS,angle); + } + // -- direction less updated + else if( m_smallStepOk[USED_POS_MINUS] ) + { + return NextSmallStepAngle(-1.0,USED_POS_MINUS,angle); + } + } + + // no angles + return false; +} diff --git a/src/server/game/Entities/Object/ObjectPosSelector.h b/src/server/game/Entities/Object/ObjectPosSelector.h new file mode 100644 index 00000000000..84050611121 --- /dev/null +++ b/src/server/game/Entities/Object/ObjectPosSelector.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _OBJECT_POS_SELECTOR_H +#define _OBJECT_POS_SELECTOR_H + +#include + +#include + +enum UsedPosType { USED_POS_PLUS, USED_POS_MINUS }; + +inline UsedPosType operator ~(UsedPosType uptype) +{ + return uptype==USED_POS_PLUS ? USED_POS_MINUS : USED_POS_PLUS; +} + +struct ObjectPosSelector +{ + struct UsedPos + { + UsedPos(float sign_, float size_,float dist_) : sign(sign_), size(size_),dist(dist_) {} + + float sign; + + float size; // size of point + float dist; // dist to central point (including central point size) + }; + + typedef std::multimap UsedPosList; // abs(angle)->Node + + ObjectPosSelector(float x,float y,float size,float dist); + + void AddUsedPos(float size,float angle,float dist); + void InitializeAngle(); + + bool FirstAngle(float& angle); + bool NextAngle(float& angle); + bool NextUsedAngle(float& angle); + + bool NextPosibleAngle( float& angle ); + + bool CheckAngle(UsedPosList::value_type const& nextUsedPos, float sign, float angle ) const + { + float angle_step2 = GetAngle(nextUsedPos.second); + + float next_angle = nextUsedPos.first; + if(nextUsedPos.second.sign * sign < 0) // last node from diff. list (-pi+alpha) + next_angle = 2*M_PI-next_angle; // move to positive + + return fabs(angle)+angle_step2 <= next_angle; + } + + bool CheckOriginal() const + { + return (m_UsedPosLists[USED_POS_PLUS].empty() || CheckAngle( *m_UsedPosLists[USED_POS_PLUS].begin(),1.0,0)) && + (m_UsedPosLists[USED_POS_MINUS].empty() || CheckAngle( *m_UsedPosLists[USED_POS_MINUS].begin(),-1.0,0)); + } + + bool IsNonBalanced() const { return m_UsedPosLists[USED_POS_PLUS].empty() != m_UsedPosLists[USED_POS_MINUS].empty(); } + + bool NextAngleFor( UsedPosList::value_type const& usedPos, float sign, UsedPosType uptype, float &angle ) + { + float angle_step = GetAngle(usedPos.second); + + // next possible angle + angle = usedPos.first * usedPos.second.sign + angle_step * sign; + + UsedPosList::value_type const* nextNode = nextUsedPos(uptype); + if(nextNode) + { + // if next node permit use selected angle, then do it + if(!CheckAngle(*nextNode, sign, angle)) + { + m_smallStepOk[uptype] = false; + return false; + } + } + + // possible more points + m_smallStepOk[uptype] = true; + m_smallStepAngle[uptype] = angle; + m_smallStepNextUsedPos[uptype] = nextNode; + + return true; + } + + bool NextSmallStepAngle( float sign, UsedPosType uptype, float &angle ) + { + // next possible angle + angle = m_smallStepAngle[uptype] + m_anglestep * sign; + + if(fabs(angle) > M_PI) + { + m_smallStepOk[uptype] = false; + return false; + } + + if(m_smallStepNextUsedPos[uptype]) + { + if(fabs(angle) >= m_smallStepNextUsedPos[uptype]->first) + { + m_smallStepOk[uptype] = false; + return false; + } + + // if next node permit use selected angle, then do it + if(!CheckAngle(*m_smallStepNextUsedPos[uptype], sign, angle)) + { + m_smallStepOk[uptype] = false; + return false; + } + } + + // possible more points + m_smallStepAngle[uptype] = angle; + return true; + } + + // next used post for m_nextUsedPos[uptype] + UsedPosList::value_type const* nextUsedPos(UsedPosType uptype); + + // angle from used pos to next possible free pos + float GetAngle(UsedPos const& usedPos) const { return acos(m_dist/(usedPos.dist+usedPos.size+m_size)); } + + float m_center_x; + float m_center_y; + float m_size; // size of object in center + float m_dist; // distance for searching pos (including central object size) + float m_anglestep; + + UsedPosList m_UsedPosLists[2]; + UsedPosList::const_iterator m_nextUsedPos[2]; + + // field for small step from first after next used pos until next pos + float m_smallStepAngle[2]; + bool m_smallStepOk[2]; + UsedPosList::value_type const* m_smallStepNextUsedPos[2]; +}; +#endif diff --git a/src/server/game/Entities/Object/UpdateData.cpp b/src/server/game/Entities/Object/UpdateData.cpp deleted file mode 100644 index 68f0501f304..00000000000 --- a/src/server/game/Entities/Object/UpdateData.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "ByteBuffer.h" -#include "WorldPacket.h" -#include "UpdateData.h" -#include "Log.h" -#include "Opcodes.h" -#include "World.h" -#include - -UpdateData::UpdateData() : m_blockCount(0) -{ -} - -void UpdateData::AddOutOfRangeGUID(std::set& guids) -{ - m_outOfRangeGUIDs.insert(guids.begin(),guids.end()); -} - -void UpdateData::AddOutOfRangeGUID(const uint64 &guid) -{ - m_outOfRangeGUIDs.insert(guid); -} - -void UpdateData::AddUpdateBlock(const ByteBuffer &block) -{ - m_data.append(block); - ++m_blockCount; -} - -void UpdateData::Compress(void* dst, uint32 *dst_size, void* src, int src_size) -{ - z_stream c_stream; - - c_stream.zalloc = (alloc_func)0; - c_stream.zfree = (free_func)0; - c_stream.opaque = (voidpf)0; - - // default Z_BEST_SPEED (1) - int z_res = deflateInit(&c_stream, sWorld.getConfig(CONFIG_COMPRESSION)); - if (z_res != Z_OK) - { - sLog.outError("Can't compress update packet (zlib: deflateInit) Error code: %i (%s)",z_res,zError(z_res)); - *dst_size = 0; - return; - } - - c_stream.next_out = (Bytef*)dst; - c_stream.avail_out = *dst_size; - c_stream.next_in = (Bytef*)src; - c_stream.avail_in = (uInt)src_size; - - z_res = deflate(&c_stream, Z_NO_FLUSH); - if (z_res != Z_OK) - { - sLog.outError("Can't compress update packet (zlib: deflate) Error code: %i (%s)",z_res,zError(z_res)); - *dst_size = 0; - return; - } - - if (c_stream.avail_in != 0) - { - sLog.outError("Can't compress update packet (zlib: deflate not greedy)"); - *dst_size = 0; - return; - } - - z_res = deflate(&c_stream, Z_FINISH); - if (z_res != Z_STREAM_END) - { - sLog.outError("Can't compress update packet (zlib: deflate should report Z_STREAM_END instead %i (%s)",z_res,zError(z_res)); - *dst_size = 0; - return; - } - - z_res = deflateEnd(&c_stream); - if (z_res != Z_OK) - { - sLog.outError("Can't compress update packet (zlib: deflateEnd) Error code: %i (%s)",z_res,zError(z_res)); - *dst_size = 0; - return; - } - - *dst_size = c_stream.total_out; -} - -bool UpdateData::BuildPacket(WorldPacket *packet) -{ - ASSERT(packet->empty()); // shouldn't happen - - ByteBuffer buf(4 + (m_outOfRangeGUIDs.empty() ? 0 : 1 + 4 + 9 * m_outOfRangeGUIDs.size()) + m_data.wpos()); - - buf << (uint32) (!m_outOfRangeGUIDs.empty() ? m_blockCount + 1 : m_blockCount); - - if (!m_outOfRangeGUIDs.empty()) - { - buf << (uint8) UPDATETYPE_OUT_OF_RANGE_OBJECTS; - buf << (uint32) m_outOfRangeGUIDs.size(); - - for (std::set::const_iterator i = m_outOfRangeGUIDs.begin(); i != m_outOfRangeGUIDs.end(); ++i) - { - buf.appendPackGUID(*i); - } - } - - buf.append(m_data); - - size_t pSize = buf.wpos(); // use real used data size - - if (pSize > 100) // compress large packets - { - uint32 destsize = compressBound(pSize); - packet->resize(destsize + sizeof(uint32)); - - packet->put(0, pSize); - Compress(const_cast(packet->contents()) + sizeof(uint32), &destsize, (void*)buf.contents(), pSize); - if (destsize == 0) - return false; - - packet->resize(destsize + sizeof(uint32)); - packet->SetOpcode(SMSG_COMPRESSED_UPDATE_OBJECT); - } - else // send small packets without compression - { - packet->append(buf); - packet->SetOpcode(SMSG_UPDATE_OBJECT); - } - - return true; -} - -void UpdateData::Clear() -{ - m_data.clear(); - m_outOfRangeGUIDs.clear(); - m_blockCount = 0; -} - diff --git a/src/server/game/Entities/Object/UpdateData.h b/src/server/game/Entities/Object/UpdateData.h deleted file mode 100644 index e560db842f5..00000000000 --- a/src/server/game/Entities/Object/UpdateData.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __UPDATEDATA_H -#define __UPDATEDATA_H - -#include "ByteBuffer.h" -class WorldPacket; - -enum OBJECT_UPDATE_TYPE -{ - UPDATETYPE_VALUES = 0, - UPDATETYPE_MOVEMENT = 1, - UPDATETYPE_CREATE_OBJECT = 2, - UPDATETYPE_CREATE_OBJECT2 = 3, - UPDATETYPE_OUT_OF_RANGE_OBJECTS = 4, - UPDATETYPE_NEAR_OBJECTS = 5 -}; - -enum OBJECT_UPDATE_FLAGS -{ - UPDATEFLAG_NONE = 0x0000, - UPDATEFLAG_SELF = 0x0001, - UPDATEFLAG_TRANSPORT = 0x0002, - UPDATEFLAG_HAS_TARGET = 0x0004, - UPDATEFLAG_LOWGUID = 0x0008, - UPDATEFLAG_HIGHGUID = 0x0010, - UPDATEFLAG_LIVING = 0x0020, - UPDATEFLAG_HAS_POSITION = 0x0040, - UPDATEFLAG_VEHICLE = 0x0080, - UPDATEFLAG_POSITION = 0x0100, - UPDATEFLAG_ROTATION = 0x0200 -}; - -class UpdateData -{ - public: - UpdateData(); - - void AddOutOfRangeGUID(std::set& guids); - void AddOutOfRangeGUID(const uint64 &guid); - void AddUpdateBlock(const ByteBuffer &block); - bool BuildPacket(WorldPacket *packet); - bool HasData() { return m_blockCount > 0 || !m_outOfRangeGUIDs.empty(); } - void Clear(); - - std::set const& GetOutOfRangeGUIDs() const { return m_outOfRangeGUIDs; } - - protected: - uint32 m_blockCount; - std::set m_outOfRangeGUIDs; - ByteBuffer m_data; - - void Compress(void* dst, uint32 *dst_size, void* src, int src_size); -}; -#endif - diff --git a/src/server/game/Entities/Object/UpdateFields.h b/src/server/game/Entities/Object/UpdateFields.h deleted file mode 100644 index 5f819375677..00000000000 --- a/src/server/game/Entities/Object/UpdateFields.h +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _UPDATEFIELDS_AUTO_H -#define _UPDATEFIELDS_AUTO_H - -// Auto generated for version 3, 3, 3, 11723 - -enum EObjectFields -{ - OBJECT_FIELD_GUID = 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC - OBJECT_FIELD_TYPE = 0x0002, // Size: 1, Type: INT, Flags: PUBLIC - OBJECT_FIELD_ENTRY = 0x0003, // Size: 1, Type: INT, Flags: PUBLIC - OBJECT_FIELD_SCALE_X = 0x0004, // Size: 1, Type: FLOAT, Flags: PUBLIC - OBJECT_FIELD_PADDING = 0x0005, // Size: 1, Type: INT, Flags: NONE - OBJECT_END = 0x0006, -}; - -enum EItemFields -{ - ITEM_FIELD_OWNER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC - ITEM_FIELD_CONTAINED = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC - ITEM_FIELD_CREATOR = OBJECT_END + 0x0004, // Size: 2, Type: LONG, Flags: PUBLIC - ITEM_FIELD_GIFTCREATOR = OBJECT_END + 0x0006, // Size: 2, Type: LONG, Flags: PUBLIC - ITEM_FIELD_STACK_COUNT = OBJECT_END + 0x0008, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER - ITEM_FIELD_DURATION = OBJECT_END + 0x0009, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER - ITEM_FIELD_SPELL_CHARGES = OBJECT_END + 0x000A, // Size: 5, Type: INT, Flags: OWNER, ITEM_OWNER - ITEM_FIELD_FLAGS = OBJECT_END + 0x000F, // Size: 1, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_1_1 = OBJECT_END + 0x0010, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_1_3 = OBJECT_END + 0x0012, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_2_1 = OBJECT_END + 0x0013, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_2_3 = OBJECT_END + 0x0015, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_3_1 = OBJECT_END + 0x0016, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_3_3 = OBJECT_END + 0x0018, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_4_1 = OBJECT_END + 0x0019, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_4_3 = OBJECT_END + 0x001B, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_5_1 = OBJECT_END + 0x001C, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_5_3 = OBJECT_END + 0x001E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_6_1 = OBJECT_END + 0x001F, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_6_3 = OBJECT_END + 0x0021, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_7_1 = OBJECT_END + 0x0022, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_7_3 = OBJECT_END + 0x0024, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_8_1 = OBJECT_END + 0x0025, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_8_3 = OBJECT_END + 0x0027, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_9_1 = OBJECT_END + 0x0028, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_9_3 = OBJECT_END + 0x002A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_10_1 = OBJECT_END + 0x002B, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_10_3 = OBJECT_END + 0x002D, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_11_1 = OBJECT_END + 0x002E, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_11_3 = OBJECT_END + 0x0030, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_12_1 = OBJECT_END + 0x0031, // Size: 2, Type: INT, Flags: PUBLIC - ITEM_FIELD_ENCHANTMENT_12_3 = OBJECT_END + 0x0033, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - ITEM_FIELD_PROPERTY_SEED = OBJECT_END + 0x0034, // Size: 1, Type: INT, Flags: PUBLIC - ITEM_FIELD_RANDOM_PROPERTIES_ID = OBJECT_END + 0x0035, // Size: 1, Type: INT, Flags: PUBLIC - ITEM_FIELD_DURABILITY = OBJECT_END + 0x0036, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER - ITEM_FIELD_MAXDURABILITY = OBJECT_END + 0x0037, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER - ITEM_FIELD_CREATE_PLAYED_TIME = OBJECT_END + 0x0038, // Size: 1, Type: INT, Flags: PUBLIC - ITEM_FIELD_PAD = OBJECT_END + 0x0039, // Size: 1, Type: INT, Flags: NONE - ITEM_END = OBJECT_END + 0x003A, -}; - -enum EContainerFields -{ - CONTAINER_FIELD_NUM_SLOTS = ITEM_END + 0x0000, // Size: 1, Type: INT, Flags: PUBLIC - CONTAINER_ALIGN_PAD = ITEM_END + 0x0001, // Size: 1, Type: BYTES, Flags: NONE - CONTAINER_FIELD_SLOT_1 = ITEM_END + 0x0002, // Size: 72, Type: LONG, Flags: PUBLIC - CONTAINER_END = ITEM_END + 0x004A, -}; - -enum EUnitFields -{ - UNIT_FIELD_CHARM = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC - UNIT_FIELD_SUMMON = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC - UNIT_FIELD_CRITTER = OBJECT_END + 0x0004, // Size: 2, Type: LONG, Flags: PRIVATE - UNIT_FIELD_CHARMEDBY = OBJECT_END + 0x0006, // Size: 2, Type: LONG, Flags: PUBLIC - UNIT_FIELD_SUMMONEDBY = OBJECT_END + 0x0008, // Size: 2, Type: LONG, Flags: PUBLIC - UNIT_FIELD_CREATEDBY = OBJECT_END + 0x000A, // Size: 2, Type: LONG, Flags: PUBLIC - UNIT_FIELD_TARGET = OBJECT_END + 0x000C, // Size: 2, Type: LONG, Flags: PUBLIC - UNIT_FIELD_CHANNEL_OBJECT = OBJECT_END + 0x000E, // Size: 2, Type: LONG, Flags: PUBLIC - UNIT_CHANNEL_SPELL = OBJECT_END + 0x0010, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_BYTES_0 = OBJECT_END + 0x0011, // Size: 1, Type: BYTES, Flags: PUBLIC - UNIT_FIELD_HEALTH = OBJECT_END + 0x0012, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER1 = OBJECT_END + 0x0013, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER2 = OBJECT_END + 0x0014, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER3 = OBJECT_END + 0x0015, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER4 = OBJECT_END + 0x0016, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER5 = OBJECT_END + 0x0017, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER6 = OBJECT_END + 0x0018, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER7 = OBJECT_END + 0x0019, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXHEALTH = OBJECT_END + 0x001A, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXPOWER1 = OBJECT_END + 0x001B, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXPOWER2 = OBJECT_END + 0x001C, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXPOWER3 = OBJECT_END + 0x001D, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXPOWER4 = OBJECT_END + 0x001E, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXPOWER5 = OBJECT_END + 0x001F, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXPOWER6 = OBJECT_END + 0x0020, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MAXPOWER7 = OBJECT_END + 0x0021, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER = OBJECT_END + 0x0022, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER = OBJECT_END + 0x0029, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_LEVEL = OBJECT_END + 0x0030, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_FACTIONTEMPLATE = OBJECT_END + 0x0031, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_VIRTUAL_ITEM_SLOT_ID = OBJECT_END + 0x0032, // Size: 3, Type: INT, Flags: PUBLIC - UNIT_FIELD_FLAGS = OBJECT_END + 0x0035, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_FLAGS_2 = OBJECT_END + 0x0036, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_AURASTATE = OBJECT_END + 0x0037, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_BASEATTACKTIME = OBJECT_END + 0x0038, // Size: 2, Type: INT, Flags: PUBLIC - UNIT_FIELD_RANGEDATTACKTIME = OBJECT_END + 0x003A, // Size: 1, Type: INT, Flags: PRIVATE - UNIT_FIELD_BOUNDINGRADIUS = OBJECT_END + 0x003B, // Size: 1, Type: FLOAT, Flags: PUBLIC - UNIT_FIELD_COMBATREACH = OBJECT_END + 0x003C, // Size: 1, Type: FLOAT, Flags: PUBLIC - UNIT_FIELD_DISPLAYID = OBJECT_END + 0x003D, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_NATIVEDISPLAYID = OBJECT_END + 0x003E, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MOUNTDISPLAYID = OBJECT_END + 0x003F, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_MINDAMAGE = OBJECT_END + 0x0040, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER - UNIT_FIELD_MAXDAMAGE = OBJECT_END + 0x0041, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER - UNIT_FIELD_MINOFFHANDDAMAGE = OBJECT_END + 0x0042, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER - UNIT_FIELD_MAXOFFHANDDAMAGE = OBJECT_END + 0x0043, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER - UNIT_FIELD_BYTES_1 = OBJECT_END + 0x0044, // Size: 1, Type: BYTES, Flags: PUBLIC - UNIT_FIELD_PETNUMBER = OBJECT_END + 0x0045, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_PET_NAME_TIMESTAMP = OBJECT_END + 0x0046, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_PETEXPERIENCE = OBJECT_END + 0x0047, // Size: 1, Type: INT, Flags: OWNER - UNIT_FIELD_PETNEXTLEVELEXP = OBJECT_END + 0x0048, // Size: 1, Type: INT, Flags: OWNER - UNIT_DYNAMIC_FLAGS = OBJECT_END + 0x0049, // Size: 1, Type: INT, Flags: DYNAMIC - UNIT_MOD_CAST_SPEED = OBJECT_END + 0x004A, // Size: 1, Type: FLOAT, Flags: PUBLIC - UNIT_CREATED_BY_SPELL = OBJECT_END + 0x004B, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_NPC_FLAGS = OBJECT_END + 0x004C, // Size: 1, Type: INT, Flags: DYNAMIC - UNIT_NPC_EMOTESTATE = OBJECT_END + 0x004D, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_STAT0 = OBJECT_END + 0x004E, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_STAT1 = OBJECT_END + 0x004F, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_STAT2 = OBJECT_END + 0x0050, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_STAT3 = OBJECT_END + 0x0051, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_STAT4 = OBJECT_END + 0x0052, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_POSSTAT0 = OBJECT_END + 0x0053, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_POSSTAT1 = OBJECT_END + 0x0054, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_POSSTAT2 = OBJECT_END + 0x0055, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_POSSTAT3 = OBJECT_END + 0x0056, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_POSSTAT4 = OBJECT_END + 0x0057, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_NEGSTAT0 = OBJECT_END + 0x0058, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_NEGSTAT1 = OBJECT_END + 0x0059, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_NEGSTAT2 = OBJECT_END + 0x005A, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_NEGSTAT3 = OBJECT_END + 0x005B, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_NEGSTAT4 = OBJECT_END + 0x005C, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_RESISTANCES = OBJECT_END + 0x005D, // Size: 7, Type: INT, Flags: PRIVATE, OWNER, PARTY_LEADER - UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE = OBJECT_END + 0x0064, // Size: 7, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE = OBJECT_END + 0x006B, // Size: 7, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_BASE_MANA = OBJECT_END + 0x0072, // Size: 1, Type: INT, Flags: PUBLIC - UNIT_FIELD_BASE_HEALTH = OBJECT_END + 0x0073, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_BYTES_2 = OBJECT_END + 0x0074, // Size: 1, Type: BYTES, Flags: PUBLIC - UNIT_FIELD_ATTACK_POWER = OBJECT_END + 0x0075, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_ATTACK_POWER_MODS = OBJECT_END + 0x0076, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE, OWNER - UNIT_FIELD_ATTACK_POWER_MULTIPLIER = OBJECT_END + 0x0077, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_RANGED_ATTACK_POWER = OBJECT_END + 0x0078, // Size: 1, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_RANGED_ATTACK_POWER_MODS = OBJECT_END + 0x0079, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE, OWNER - UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = OBJECT_END + 0x007A, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_MINRANGEDDAMAGE = OBJECT_END + 0x007B, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_MAXRANGEDDAMAGE = OBJECT_END + 0x007C, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_POWER_COST_MODIFIER = OBJECT_END + 0x007D, // Size: 7, Type: INT, Flags: PRIVATE, OWNER - UNIT_FIELD_POWER_COST_MULTIPLIER = OBJECT_END + 0x0084, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_MAXHEALTHMODIFIER = OBJECT_END + 0x008B, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER - UNIT_FIELD_HOVERHEIGHT = OBJECT_END + 0x008C, // Size: 1, Type: FLOAT, Flags: PUBLIC - UNIT_FIELD_PADDING = OBJECT_END + 0x008D, // Size: 1, Type: INT, Flags: NONE - UNIT_END = OBJECT_END + 0x008E, - - PLAYER_DUEL_ARBITER = UNIT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC - PLAYER_FLAGS = UNIT_END + 0x0002, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_GUILDID = UNIT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_GUILDRANK = UNIT_END + 0x0004, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_BYTES = UNIT_END + 0x0005, // Size: 1, Type: BYTES, Flags: PUBLIC - PLAYER_BYTES_2 = UNIT_END + 0x0006, // Size: 1, Type: BYTES, Flags: PUBLIC - PLAYER_BYTES_3 = UNIT_END + 0x0007, // Size: 1, Type: BYTES, Flags: PUBLIC - PLAYER_DUEL_TEAM = UNIT_END + 0x0008, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_GUILD_TIMESTAMP = UNIT_END + 0x0009, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_QUEST_LOG_1_1 = UNIT_END + 0x000A, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_1_2 = UNIT_END + 0x000B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_1_3 = UNIT_END + 0x000C, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_1_4 = UNIT_END + 0x000E, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_2_1 = UNIT_END + 0x000F, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_2_2 = UNIT_END + 0x0010, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_2_3 = UNIT_END + 0x0011, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_2_5 = UNIT_END + 0x0013, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_3_1 = UNIT_END + 0x0014, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_3_2 = UNIT_END + 0x0015, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_3_3 = UNIT_END + 0x0016, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_3_5 = UNIT_END + 0x0018, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_4_1 = UNIT_END + 0x0019, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_4_2 = UNIT_END + 0x001A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_4_3 = UNIT_END + 0x001B, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_4_5 = UNIT_END + 0x001D, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_5_1 = UNIT_END + 0x001E, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_5_2 = UNIT_END + 0x001F, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_5_3 = UNIT_END + 0x0020, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_5_5 = UNIT_END + 0x0022, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_6_1 = UNIT_END + 0x0023, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_6_2 = UNIT_END + 0x0024, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_6_3 = UNIT_END + 0x0025, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_6_5 = UNIT_END + 0x0027, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_7_1 = UNIT_END + 0x0028, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_7_2 = UNIT_END + 0x0029, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_7_3 = UNIT_END + 0x002A, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_7_5 = UNIT_END + 0x002C, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_8_1 = UNIT_END + 0x002D, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_8_2 = UNIT_END + 0x002E, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_8_3 = UNIT_END + 0x002F, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_8_5 = UNIT_END + 0x0031, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_9_1 = UNIT_END + 0x0032, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_9_2 = UNIT_END + 0x0033, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_9_3 = UNIT_END + 0x0034, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_9_5 = UNIT_END + 0x0036, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_10_1 = UNIT_END + 0x0037, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_10_2 = UNIT_END + 0x0038, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_10_3 = UNIT_END + 0x0039, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_10_5 = UNIT_END + 0x003B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_11_1 = UNIT_END + 0x003C, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_11_2 = UNIT_END + 0x003D, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_11_3 = UNIT_END + 0x003E, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_11_5 = UNIT_END + 0x0040, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_12_1 = UNIT_END + 0x0041, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_12_2 = UNIT_END + 0x0042, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_12_3 = UNIT_END + 0x0043, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_12_5 = UNIT_END + 0x0045, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_13_1 = UNIT_END + 0x0046, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_13_2 = UNIT_END + 0x0047, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_13_3 = UNIT_END + 0x0048, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_13_5 = UNIT_END + 0x004A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_14_1 = UNIT_END + 0x004B, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_14_2 = UNIT_END + 0x004C, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_14_3 = UNIT_END + 0x004D, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_14_5 = UNIT_END + 0x004F, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_15_1 = UNIT_END + 0x0050, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_15_2 = UNIT_END + 0x0051, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_15_3 = UNIT_END + 0x0052, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_15_5 = UNIT_END + 0x0054, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_16_1 = UNIT_END + 0x0055, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_16_2 = UNIT_END + 0x0056, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_16_3 = UNIT_END + 0x0057, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_16_5 = UNIT_END + 0x0059, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_17_1 = UNIT_END + 0x005A, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_17_2 = UNIT_END + 0x005B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_17_3 = UNIT_END + 0x005C, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_17_5 = UNIT_END + 0x005E, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_18_1 = UNIT_END + 0x005F, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_18_2 = UNIT_END + 0x0060, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_18_3 = UNIT_END + 0x0061, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_18_5 = UNIT_END + 0x0063, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_19_1 = UNIT_END + 0x0064, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_19_2 = UNIT_END + 0x0065, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_19_3 = UNIT_END + 0x0066, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_19_5 = UNIT_END + 0x0068, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_20_1 = UNIT_END + 0x0069, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_20_2 = UNIT_END + 0x006A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_20_3 = UNIT_END + 0x006B, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_20_5 = UNIT_END + 0x006D, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_21_1 = UNIT_END + 0x006E, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_21_2 = UNIT_END + 0x006F, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_21_3 = UNIT_END + 0x0070, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_21_5 = UNIT_END + 0x0072, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_22_1 = UNIT_END + 0x0073, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_22_2 = UNIT_END + 0x0074, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_22_3 = UNIT_END + 0x0075, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_22_5 = UNIT_END + 0x0077, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_23_1 = UNIT_END + 0x0078, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_23_2 = UNIT_END + 0x0079, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_23_3 = UNIT_END + 0x007A, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_23_5 = UNIT_END + 0x007C, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_24_1 = UNIT_END + 0x007D, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_24_2 = UNIT_END + 0x007E, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_24_3 = UNIT_END + 0x007F, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_24_5 = UNIT_END + 0x0081, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_25_1 = UNIT_END + 0x0082, // Size: 1, Type: INT, Flags: PARTY_MEMBER - PLAYER_QUEST_LOG_25_2 = UNIT_END + 0x0083, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_QUEST_LOG_25_3 = UNIT_END + 0x0084, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_QUEST_LOG_25_5 = UNIT_END + 0x0086, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_VISIBLE_ITEM_1_ENTRYID = UNIT_END + 0x0087, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_1_ENCHANTMENT = UNIT_END + 0x0088, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_2_ENTRYID = UNIT_END + 0x0089, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_2_ENCHANTMENT = UNIT_END + 0x008A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_3_ENTRYID = UNIT_END + 0x008B, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_3_ENCHANTMENT = UNIT_END + 0x008C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_4_ENTRYID = UNIT_END + 0x008D, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_4_ENCHANTMENT = UNIT_END + 0x008E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_5_ENTRYID = UNIT_END + 0x008F, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_5_ENCHANTMENT = UNIT_END + 0x0090, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_6_ENTRYID = UNIT_END + 0x0091, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_6_ENCHANTMENT = UNIT_END + 0x0092, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_7_ENTRYID = UNIT_END + 0x0093, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_7_ENCHANTMENT = UNIT_END + 0x0094, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_8_ENTRYID = UNIT_END + 0x0095, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_8_ENCHANTMENT = UNIT_END + 0x0096, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_9_ENTRYID = UNIT_END + 0x0097, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_9_ENCHANTMENT = UNIT_END + 0x0098, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_10_ENTRYID = UNIT_END + 0x0099, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_10_ENCHANTMENT = UNIT_END + 0x009A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_11_ENTRYID = UNIT_END + 0x009B, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_11_ENCHANTMENT = UNIT_END + 0x009C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_12_ENTRYID = UNIT_END + 0x009D, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_12_ENCHANTMENT = UNIT_END + 0x009E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_13_ENTRYID = UNIT_END + 0x009F, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_13_ENCHANTMENT = UNIT_END + 0x00A0, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_14_ENTRYID = UNIT_END + 0x00A1, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_14_ENCHANTMENT = UNIT_END + 0x00A2, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_15_ENTRYID = UNIT_END + 0x00A3, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_15_ENCHANTMENT = UNIT_END + 0x00A4, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_16_ENTRYID = UNIT_END + 0x00A5, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_16_ENCHANTMENT = UNIT_END + 0x00A6, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_17_ENTRYID = UNIT_END + 0x00A7, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_17_ENCHANTMENT = UNIT_END + 0x00A8, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_18_ENTRYID = UNIT_END + 0x00A9, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_18_ENCHANTMENT = UNIT_END + 0x00AA, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_19_ENTRYID = UNIT_END + 0x00AB, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_VISIBLE_ITEM_19_ENCHANTMENT = UNIT_END + 0x00AC, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC - PLAYER_CHOSEN_TITLE = UNIT_END + 0x00AD, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_FAKE_INEBRIATION = UNIT_END + 0x00AE, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_FIELD_PAD_0 = UNIT_END + 0x00AF, // Size: 1, Type: INT, Flags: NONE - PLAYER_FIELD_INV_SLOT_HEAD = UNIT_END + 0x00B0, // Size: 46, Type: LONG, Flags: PRIVATE - PLAYER_FIELD_PACK_SLOT_1 = UNIT_END + 0x00DE, // Size: 32, Type: LONG, Flags: PRIVATE - PLAYER_FIELD_BANK_SLOT_1 = UNIT_END + 0x00FE, // Size: 56, Type: LONG, Flags: PRIVATE - PLAYER_FIELD_BANKBAG_SLOT_1 = UNIT_END + 0x0136, // Size: 14, Type: LONG, Flags: PRIVATE - PLAYER_FIELD_VENDORBUYBACK_SLOT_1 = UNIT_END + 0x0144, // Size: 24, Type: LONG, Flags: PRIVATE - PLAYER_FIELD_KEYRING_SLOT_1 = UNIT_END + 0x015C, // Size: 64, Type: LONG, Flags: PRIVATE - PLAYER_FIELD_CURRENCYTOKEN_SLOT_1 = UNIT_END + 0x019C, // Size: 64, Type: LONG, Flags: PRIVATE - PLAYER_FARSIGHT = UNIT_END + 0x01DC, // Size: 2, Type: LONG, Flags: PRIVATE - PLAYER__FIELD_KNOWN_TITLES = UNIT_END + 0x01DE, // Size: 2, Type: LONG, Flags: PRIVATE - PLAYER__FIELD_KNOWN_TITLES1 = UNIT_END + 0x01E0, // Size: 2, Type: LONG, Flags: PRIVATE - PLAYER__FIELD_KNOWN_TITLES2 = UNIT_END + 0x01E2, // Size: 2, Type: LONG, Flags: PRIVATE - PLAYER_FIELD_KNOWN_CURRENCIES = UNIT_END + 0x01E4, // Size: 2, Type: LONG, Flags: PRIVATE - PLAYER_XP = UNIT_END + 0x01E6, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_NEXT_LEVEL_XP = UNIT_END + 0x01E7, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_SKILL_INFO_1_1 = UNIT_END + 0x01E8, // Size: 384, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_CHARACTER_POINTS1 = UNIT_END + 0x0368, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_CHARACTER_POINTS2 = UNIT_END + 0x0369, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_TRACK_CREATURES = UNIT_END + 0x036A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_TRACK_RESOURCES = UNIT_END + 0x036B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_BLOCK_PERCENTAGE = UNIT_END + 0x036C, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_DODGE_PERCENTAGE = UNIT_END + 0x036D, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_PARRY_PERCENTAGE = UNIT_END + 0x036E, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_EXPERTISE = UNIT_END + 0x036F, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_OFFHAND_EXPERTISE = UNIT_END + 0x0370, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_CRIT_PERCENTAGE = UNIT_END + 0x0371, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_RANGED_CRIT_PERCENTAGE = UNIT_END + 0x0372, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_OFFHAND_CRIT_PERCENTAGE = UNIT_END + 0x0373, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_SPELL_CRIT_PERCENTAGE1 = UNIT_END + 0x0374, // Size: 7, Type: FLOAT, Flags: PRIVATE - PLAYER_SHIELD_BLOCK = UNIT_END + 0x037B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_SHIELD_BLOCK_CRIT_PERCENTAGE = UNIT_END + 0x037C, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_EXPLORED_ZONES_1 = UNIT_END + 0x037D, // Size: 128, Type: BYTES, Flags: PRIVATE - PLAYER_REST_STATE_EXPERIENCE = UNIT_END + 0x03FD, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_COINAGE = UNIT_END + 0x03FE, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MOD_DAMAGE_DONE_POS = UNIT_END + 0x03FF, // Size: 7, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MOD_DAMAGE_DONE_NEG = UNIT_END + 0x0406, // Size: 7, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MOD_DAMAGE_DONE_PCT = UNIT_END + 0x040D, // Size: 7, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MOD_HEALING_DONE_POS = UNIT_END + 0x0414, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MOD_HEALING_PCT = UNIT_END + 0x0415, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_FIELD_MOD_HEALING_DONE_PCT = UNIT_END + 0x0416, // Size: 1, Type: FLOAT, Flags: PRIVATE - PLAYER_FIELD_MOD_TARGET_RESISTANCE = UNIT_END + 0x0417, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE = UNIT_END + 0x0418, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_BYTES = UNIT_END + 0x0419, // Size: 1, Type: BYTES, Flags: PRIVATE - PLAYER_AMMO_ID = UNIT_END + 0x041A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_SELF_RES_SPELL = UNIT_END + 0x041B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_PVP_MEDALS = UNIT_END + 0x041C, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_BUYBACK_PRICE_1 = UNIT_END + 0x041D, // Size: 12, Type: INT, Flags: PRIVATE - PLAYER_FIELD_BUYBACK_TIMESTAMP_1 = UNIT_END + 0x0429, // Size: 12, Type: INT, Flags: PRIVATE - PLAYER_FIELD_KILLS = UNIT_END + 0x0435, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_FIELD_TODAY_CONTRIBUTION = UNIT_END + 0x0436, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_YESTERDAY_CONTRIBUTION = UNIT_END + 0x0437, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_LIFETIME_HONORABLE_KILLS = UNIT_END + 0x0438, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_BYTES2 = UNIT_END + 0x0439, // Size: 1, Type: 6, Flags: PRIVATE - PLAYER_FIELD_WATCHED_FACTION_INDEX = UNIT_END + 0x043A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_COMBAT_RATING_1 = UNIT_END + 0x043B, // Size: 25, Type: INT, Flags: PRIVATE - PLAYER_FIELD_ARENA_TEAM_INFO_1_1 = UNIT_END + 0x0454, // Size: 21, Type: INT, Flags: PRIVATE - PLAYER_FIELD_HONOR_CURRENCY = UNIT_END + 0x0469, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_ARENA_CURRENCY = UNIT_END + 0x046A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MAX_LEVEL = UNIT_END + 0x046B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_DAILY_QUESTS_1 = UNIT_END + 0x046C, // Size: 25, Type: INT, Flags: PRIVATE - PLAYER_RUNE_REGEN_1 = UNIT_END + 0x0485, // Size: 4, Type: FLOAT, Flags: PRIVATE - PLAYER_NO_REAGENT_COST_1 = UNIT_END + 0x0489, // Size: 3, Type: INT, Flags: PRIVATE - PLAYER_FIELD_GLYPH_SLOTS_1 = UNIT_END + 0x048C, // Size: 6, Type: INT, Flags: PRIVATE - PLAYER_FIELD_GLYPHS_1 = UNIT_END + 0x0492, // Size: 6, Type: INT, Flags: PRIVATE - PLAYER_GLYPHS_ENABLED = UNIT_END + 0x0498, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_PET_SPELL_POWER = UNIT_END + 0x0499, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_END = UNIT_END + 0x049A, -}; - -enum EGameObjectFields -{ - OBJECT_FIELD_CREATED_BY = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC - GAMEOBJECT_DISPLAYID = OBJECT_END + 0x0002, // Size: 1, Type: INT, Flags: PUBLIC - GAMEOBJECT_FLAGS = OBJECT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC - GAMEOBJECT_PARENTROTATION = OBJECT_END + 0x0004, // Size: 4, Type: FLOAT, Flags: PUBLIC - GAMEOBJECT_DYNAMIC = OBJECT_END + 0x0008, // Size: 1, Type: TWO_SHORT, Flags: DYNAMIC - GAMEOBJECT_FACTION = OBJECT_END + 0x0009, // Size: 1, Type: INT, Flags: PUBLIC - GAMEOBJECT_LEVEL = OBJECT_END + 0x000A, // Size: 1, Type: INT, Flags: PUBLIC - GAMEOBJECT_BYTES_1 = OBJECT_END + 0x000B, // Size: 1, Type: BYTES, Flags: PUBLIC - GAMEOBJECT_END = OBJECT_END + 0x000C, -}; - -enum EDynamicObjectFields -{ - DYNAMICOBJECT_CASTER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC - DYNAMICOBJECT_BYTES = OBJECT_END + 0x0002, // Size: 1, Type: BYTES, Flags: PUBLIC - DYNAMICOBJECT_SPELLID = OBJECT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC - DYNAMICOBJECT_RADIUS = OBJECT_END + 0x0004, // Size: 1, Type: FLOAT, Flags: PUBLIC - DYNAMICOBJECT_CASTTIME = OBJECT_END + 0x0005, // Size: 1, Type: INT, Flags: PUBLIC - DYNAMICOBJECT_END = OBJECT_END + 0x0006, -}; - -enum ECorpseFields -{ - CORPSE_FIELD_OWNER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC - CORPSE_FIELD_PARTY = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC - CORPSE_FIELD_DISPLAY_ID = OBJECT_END + 0x0004, // Size: 1, Type: INT, Flags: PUBLIC - CORPSE_FIELD_ITEM = OBJECT_END + 0x0005, // Size: 19, Type: INT, Flags: PUBLIC - CORPSE_FIELD_BYTES_1 = OBJECT_END + 0x0018, // Size: 1, Type: BYTES, Flags: PUBLIC - CORPSE_FIELD_BYTES_2 = OBJECT_END + 0x0019, // Size: 1, Type: BYTES, Flags: PUBLIC - CORPSE_FIELD_GUILD = OBJECT_END + 0x001A, // Size: 1, Type: INT, Flags: PUBLIC - CORPSE_FIELD_FLAGS = OBJECT_END + 0x001B, // Size: 1, Type: INT, Flags: PUBLIC - CORPSE_FIELD_DYNAMIC_FLAGS = OBJECT_END + 0x001C, // Size: 1, Type: INT, Flags: DYNAMIC - CORPSE_FIELD_PAD = OBJECT_END + 0x001D, // Size: 1, Type: INT, Flags: NONE - CORPSE_END = OBJECT_END + 0x001E, -}; -#endif diff --git a/src/server/game/Entities/Object/UpdateMask.h b/src/server/game/Entities/Object/UpdateMask.h deleted file mode 100644 index 527bec42aa7..00000000000 --- a/src/server/game/Entities/Object/UpdateMask.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __UPDATEMASK_H -#define __UPDATEMASK_H - -#include "UpdateFields.h" -#include "Errors.h" - -class UpdateMask -{ - public: - UpdateMask() : mCount(0), mBlocks(0), mUpdateMask(0) { } - UpdateMask(const UpdateMask& mask) : mUpdateMask(0) { *this = mask; } - - ~UpdateMask() - { - if (mUpdateMask) - delete [] mUpdateMask; - } - - void SetBit (uint32 index) - { - ((uint8 *)mUpdateMask)[ index >> 3 ] |= 1 << (index & 0x7); - } - - void UnsetBit (uint32 index) - { - ((uint8 *)mUpdateMask)[ index >> 3 ] &= (0xff ^ (1 << (index & 0x7))); - } - - bool GetBit (uint32 index) const - { - return (((uint8 *)mUpdateMask)[ index >> 3 ] & (1 << (index & 0x7))) != 0; - } - - uint32 GetBlockCount() const { return mBlocks; } - uint32 GetLength() const { return mBlocks << 2; } - uint32 GetCount() const { return mCount; } - uint8* GetMask() { return (uint8*)mUpdateMask; } - - void SetCount (uint32 valuesCount) - { - if (mUpdateMask) - delete [] mUpdateMask; - - mCount = valuesCount; - mBlocks = (valuesCount + 31) / 32; - - mUpdateMask = new uint32[mBlocks]; - memset(mUpdateMask, 0, mBlocks << 2); - } - - void Clear() - { - if (mUpdateMask) - memset(mUpdateMask, 0, mBlocks << 2); - } - - UpdateMask& operator = (const UpdateMask& mask) - { - SetCount(mask.mCount); - memcpy(mUpdateMask, mask.mUpdateMask, mBlocks << 2); - - return *this; - } - - void operator &= (const UpdateMask& mask) - { - ASSERT(mask.mCount <= mCount); - for (uint32 i = 0; i < mBlocks; ++i) - mUpdateMask[i] &= mask.mUpdateMask[i]; - } - - void operator |= (const UpdateMask& mask) - { - ASSERT(mask.mCount <= mCount); - for (uint32 i = 0; i < mBlocks; ++i) - mUpdateMask[i] |= mask.mUpdateMask[i]; - } - - UpdateMask operator & (const UpdateMask& mask) const - { - ASSERT(mask.mCount <= mCount); - - UpdateMask newmask; - newmask = *this; - newmask &= mask; - - return newmask; - } - - UpdateMask operator | (const UpdateMask& mask) const - { - ASSERT(mask.mCount <= mCount); - - UpdateMask newmask; - newmask = *this; - newmask |= mask; - - return newmask; - } - - private: - uint32 mCount; - uint32 mBlocks; - uint32 *mUpdateMask; -}; -#endif - diff --git a/src/server/game/Entities/Object/Updates/UpdateData.cpp b/src/server/game/Entities/Object/Updates/UpdateData.cpp new file mode 100644 index 00000000000..68f0501f304 --- /dev/null +++ b/src/server/game/Entities/Object/Updates/UpdateData.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "ByteBuffer.h" +#include "WorldPacket.h" +#include "UpdateData.h" +#include "Log.h" +#include "Opcodes.h" +#include "World.h" +#include + +UpdateData::UpdateData() : m_blockCount(0) +{ +} + +void UpdateData::AddOutOfRangeGUID(std::set& guids) +{ + m_outOfRangeGUIDs.insert(guids.begin(),guids.end()); +} + +void UpdateData::AddOutOfRangeGUID(const uint64 &guid) +{ + m_outOfRangeGUIDs.insert(guid); +} + +void UpdateData::AddUpdateBlock(const ByteBuffer &block) +{ + m_data.append(block); + ++m_blockCount; +} + +void UpdateData::Compress(void* dst, uint32 *dst_size, void* src, int src_size) +{ + z_stream c_stream; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + // default Z_BEST_SPEED (1) + int z_res = deflateInit(&c_stream, sWorld.getConfig(CONFIG_COMPRESSION)); + if (z_res != Z_OK) + { + sLog.outError("Can't compress update packet (zlib: deflateInit) Error code: %i (%s)",z_res,zError(z_res)); + *dst_size = 0; + return; + } + + c_stream.next_out = (Bytef*)dst; + c_stream.avail_out = *dst_size; + c_stream.next_in = (Bytef*)src; + c_stream.avail_in = (uInt)src_size; + + z_res = deflate(&c_stream, Z_NO_FLUSH); + if (z_res != Z_OK) + { + sLog.outError("Can't compress update packet (zlib: deflate) Error code: %i (%s)",z_res,zError(z_res)); + *dst_size = 0; + return; + } + + if (c_stream.avail_in != 0) + { + sLog.outError("Can't compress update packet (zlib: deflate not greedy)"); + *dst_size = 0; + return; + } + + z_res = deflate(&c_stream, Z_FINISH); + if (z_res != Z_STREAM_END) + { + sLog.outError("Can't compress update packet (zlib: deflate should report Z_STREAM_END instead %i (%s)",z_res,zError(z_res)); + *dst_size = 0; + return; + } + + z_res = deflateEnd(&c_stream); + if (z_res != Z_OK) + { + sLog.outError("Can't compress update packet (zlib: deflateEnd) Error code: %i (%s)",z_res,zError(z_res)); + *dst_size = 0; + return; + } + + *dst_size = c_stream.total_out; +} + +bool UpdateData::BuildPacket(WorldPacket *packet) +{ + ASSERT(packet->empty()); // shouldn't happen + + ByteBuffer buf(4 + (m_outOfRangeGUIDs.empty() ? 0 : 1 + 4 + 9 * m_outOfRangeGUIDs.size()) + m_data.wpos()); + + buf << (uint32) (!m_outOfRangeGUIDs.empty() ? m_blockCount + 1 : m_blockCount); + + if (!m_outOfRangeGUIDs.empty()) + { + buf << (uint8) UPDATETYPE_OUT_OF_RANGE_OBJECTS; + buf << (uint32) m_outOfRangeGUIDs.size(); + + for (std::set::const_iterator i = m_outOfRangeGUIDs.begin(); i != m_outOfRangeGUIDs.end(); ++i) + { + buf.appendPackGUID(*i); + } + } + + buf.append(m_data); + + size_t pSize = buf.wpos(); // use real used data size + + if (pSize > 100) // compress large packets + { + uint32 destsize = compressBound(pSize); + packet->resize(destsize + sizeof(uint32)); + + packet->put(0, pSize); + Compress(const_cast(packet->contents()) + sizeof(uint32), &destsize, (void*)buf.contents(), pSize); + if (destsize == 0) + return false; + + packet->resize(destsize + sizeof(uint32)); + packet->SetOpcode(SMSG_COMPRESSED_UPDATE_OBJECT); + } + else // send small packets without compression + { + packet->append(buf); + packet->SetOpcode(SMSG_UPDATE_OBJECT); + } + + return true; +} + +void UpdateData::Clear() +{ + m_data.clear(); + m_outOfRangeGUIDs.clear(); + m_blockCount = 0; +} + diff --git a/src/server/game/Entities/Object/Updates/UpdateData.h b/src/server/game/Entities/Object/Updates/UpdateData.h new file mode 100644 index 00000000000..e560db842f5 --- /dev/null +++ b/src/server/game/Entities/Object/Updates/UpdateData.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __UPDATEDATA_H +#define __UPDATEDATA_H + +#include "ByteBuffer.h" +class WorldPacket; + +enum OBJECT_UPDATE_TYPE +{ + UPDATETYPE_VALUES = 0, + UPDATETYPE_MOVEMENT = 1, + UPDATETYPE_CREATE_OBJECT = 2, + UPDATETYPE_CREATE_OBJECT2 = 3, + UPDATETYPE_OUT_OF_RANGE_OBJECTS = 4, + UPDATETYPE_NEAR_OBJECTS = 5 +}; + +enum OBJECT_UPDATE_FLAGS +{ + UPDATEFLAG_NONE = 0x0000, + UPDATEFLAG_SELF = 0x0001, + UPDATEFLAG_TRANSPORT = 0x0002, + UPDATEFLAG_HAS_TARGET = 0x0004, + UPDATEFLAG_LOWGUID = 0x0008, + UPDATEFLAG_HIGHGUID = 0x0010, + UPDATEFLAG_LIVING = 0x0020, + UPDATEFLAG_HAS_POSITION = 0x0040, + UPDATEFLAG_VEHICLE = 0x0080, + UPDATEFLAG_POSITION = 0x0100, + UPDATEFLAG_ROTATION = 0x0200 +}; + +class UpdateData +{ + public: + UpdateData(); + + void AddOutOfRangeGUID(std::set& guids); + void AddOutOfRangeGUID(const uint64 &guid); + void AddUpdateBlock(const ByteBuffer &block); + bool BuildPacket(WorldPacket *packet); + bool HasData() { return m_blockCount > 0 || !m_outOfRangeGUIDs.empty(); } + void Clear(); + + std::set const& GetOutOfRangeGUIDs() const { return m_outOfRangeGUIDs; } + + protected: + uint32 m_blockCount; + std::set m_outOfRangeGUIDs; + ByteBuffer m_data; + + void Compress(void* dst, uint32 *dst_size, void* src, int src_size); +}; +#endif + diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.h b/src/server/game/Entities/Object/Updates/UpdateFields.h new file mode 100644 index 00000000000..5f819375677 --- /dev/null +++ b/src/server/game/Entities/Object/Updates/UpdateFields.h @@ -0,0 +1,435 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _UPDATEFIELDS_AUTO_H +#define _UPDATEFIELDS_AUTO_H + +// Auto generated for version 3, 3, 3, 11723 + +enum EObjectFields +{ + OBJECT_FIELD_GUID = 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC + OBJECT_FIELD_TYPE = 0x0002, // Size: 1, Type: INT, Flags: PUBLIC + OBJECT_FIELD_ENTRY = 0x0003, // Size: 1, Type: INT, Flags: PUBLIC + OBJECT_FIELD_SCALE_X = 0x0004, // Size: 1, Type: FLOAT, Flags: PUBLIC + OBJECT_FIELD_PADDING = 0x0005, // Size: 1, Type: INT, Flags: NONE + OBJECT_END = 0x0006, +}; + +enum EItemFields +{ + ITEM_FIELD_OWNER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC + ITEM_FIELD_CONTAINED = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC + ITEM_FIELD_CREATOR = OBJECT_END + 0x0004, // Size: 2, Type: LONG, Flags: PUBLIC + ITEM_FIELD_GIFTCREATOR = OBJECT_END + 0x0006, // Size: 2, Type: LONG, Flags: PUBLIC + ITEM_FIELD_STACK_COUNT = OBJECT_END + 0x0008, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER + ITEM_FIELD_DURATION = OBJECT_END + 0x0009, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER + ITEM_FIELD_SPELL_CHARGES = OBJECT_END + 0x000A, // Size: 5, Type: INT, Flags: OWNER, ITEM_OWNER + ITEM_FIELD_FLAGS = OBJECT_END + 0x000F, // Size: 1, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_1_1 = OBJECT_END + 0x0010, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_1_3 = OBJECT_END + 0x0012, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_2_1 = OBJECT_END + 0x0013, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_2_3 = OBJECT_END + 0x0015, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_3_1 = OBJECT_END + 0x0016, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_3_3 = OBJECT_END + 0x0018, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_4_1 = OBJECT_END + 0x0019, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_4_3 = OBJECT_END + 0x001B, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_5_1 = OBJECT_END + 0x001C, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_5_3 = OBJECT_END + 0x001E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_6_1 = OBJECT_END + 0x001F, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_6_3 = OBJECT_END + 0x0021, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_7_1 = OBJECT_END + 0x0022, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_7_3 = OBJECT_END + 0x0024, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_8_1 = OBJECT_END + 0x0025, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_8_3 = OBJECT_END + 0x0027, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_9_1 = OBJECT_END + 0x0028, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_9_3 = OBJECT_END + 0x002A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_10_1 = OBJECT_END + 0x002B, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_10_3 = OBJECT_END + 0x002D, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_11_1 = OBJECT_END + 0x002E, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_11_3 = OBJECT_END + 0x0030, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_12_1 = OBJECT_END + 0x0031, // Size: 2, Type: INT, Flags: PUBLIC + ITEM_FIELD_ENCHANTMENT_12_3 = OBJECT_END + 0x0033, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + ITEM_FIELD_PROPERTY_SEED = OBJECT_END + 0x0034, // Size: 1, Type: INT, Flags: PUBLIC + ITEM_FIELD_RANDOM_PROPERTIES_ID = OBJECT_END + 0x0035, // Size: 1, Type: INT, Flags: PUBLIC + ITEM_FIELD_DURABILITY = OBJECT_END + 0x0036, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER + ITEM_FIELD_MAXDURABILITY = OBJECT_END + 0x0037, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER + ITEM_FIELD_CREATE_PLAYED_TIME = OBJECT_END + 0x0038, // Size: 1, Type: INT, Flags: PUBLIC + ITEM_FIELD_PAD = OBJECT_END + 0x0039, // Size: 1, Type: INT, Flags: NONE + ITEM_END = OBJECT_END + 0x003A, +}; + +enum EContainerFields +{ + CONTAINER_FIELD_NUM_SLOTS = ITEM_END + 0x0000, // Size: 1, Type: INT, Flags: PUBLIC + CONTAINER_ALIGN_PAD = ITEM_END + 0x0001, // Size: 1, Type: BYTES, Flags: NONE + CONTAINER_FIELD_SLOT_1 = ITEM_END + 0x0002, // Size: 72, Type: LONG, Flags: PUBLIC + CONTAINER_END = ITEM_END + 0x004A, +}; + +enum EUnitFields +{ + UNIT_FIELD_CHARM = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC + UNIT_FIELD_SUMMON = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC + UNIT_FIELD_CRITTER = OBJECT_END + 0x0004, // Size: 2, Type: LONG, Flags: PRIVATE + UNIT_FIELD_CHARMEDBY = OBJECT_END + 0x0006, // Size: 2, Type: LONG, Flags: PUBLIC + UNIT_FIELD_SUMMONEDBY = OBJECT_END + 0x0008, // Size: 2, Type: LONG, Flags: PUBLIC + UNIT_FIELD_CREATEDBY = OBJECT_END + 0x000A, // Size: 2, Type: LONG, Flags: PUBLIC + UNIT_FIELD_TARGET = OBJECT_END + 0x000C, // Size: 2, Type: LONG, Flags: PUBLIC + UNIT_FIELD_CHANNEL_OBJECT = OBJECT_END + 0x000E, // Size: 2, Type: LONG, Flags: PUBLIC + UNIT_CHANNEL_SPELL = OBJECT_END + 0x0010, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_BYTES_0 = OBJECT_END + 0x0011, // Size: 1, Type: BYTES, Flags: PUBLIC + UNIT_FIELD_HEALTH = OBJECT_END + 0x0012, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_POWER1 = OBJECT_END + 0x0013, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_POWER2 = OBJECT_END + 0x0014, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_POWER3 = OBJECT_END + 0x0015, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_POWER4 = OBJECT_END + 0x0016, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_POWER5 = OBJECT_END + 0x0017, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_POWER6 = OBJECT_END + 0x0018, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_POWER7 = OBJECT_END + 0x0019, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MAXHEALTH = OBJECT_END + 0x001A, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MAXPOWER1 = OBJECT_END + 0x001B, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MAXPOWER2 = OBJECT_END + 0x001C, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MAXPOWER3 = OBJECT_END + 0x001D, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MAXPOWER4 = OBJECT_END + 0x001E, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MAXPOWER5 = OBJECT_END + 0x001F, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MAXPOWER6 = OBJECT_END + 0x0020, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MAXPOWER7 = OBJECT_END + 0x0021, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER = OBJECT_END + 0x0022, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER + UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER = OBJECT_END + 0x0029, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER + UNIT_FIELD_LEVEL = OBJECT_END + 0x0030, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_FACTIONTEMPLATE = OBJECT_END + 0x0031, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_VIRTUAL_ITEM_SLOT_ID = OBJECT_END + 0x0032, // Size: 3, Type: INT, Flags: PUBLIC + UNIT_FIELD_FLAGS = OBJECT_END + 0x0035, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_FLAGS_2 = OBJECT_END + 0x0036, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_AURASTATE = OBJECT_END + 0x0037, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_BASEATTACKTIME = OBJECT_END + 0x0038, // Size: 2, Type: INT, Flags: PUBLIC + UNIT_FIELD_RANGEDATTACKTIME = OBJECT_END + 0x003A, // Size: 1, Type: INT, Flags: PRIVATE + UNIT_FIELD_BOUNDINGRADIUS = OBJECT_END + 0x003B, // Size: 1, Type: FLOAT, Flags: PUBLIC + UNIT_FIELD_COMBATREACH = OBJECT_END + 0x003C, // Size: 1, Type: FLOAT, Flags: PUBLIC + UNIT_FIELD_DISPLAYID = OBJECT_END + 0x003D, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_NATIVEDISPLAYID = OBJECT_END + 0x003E, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MOUNTDISPLAYID = OBJECT_END + 0x003F, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_MINDAMAGE = OBJECT_END + 0x0040, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER + UNIT_FIELD_MAXDAMAGE = OBJECT_END + 0x0041, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER + UNIT_FIELD_MINOFFHANDDAMAGE = OBJECT_END + 0x0042, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER + UNIT_FIELD_MAXOFFHANDDAMAGE = OBJECT_END + 0x0043, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER, PARTY_LEADER + UNIT_FIELD_BYTES_1 = OBJECT_END + 0x0044, // Size: 1, Type: BYTES, Flags: PUBLIC + UNIT_FIELD_PETNUMBER = OBJECT_END + 0x0045, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_PET_NAME_TIMESTAMP = OBJECT_END + 0x0046, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_PETEXPERIENCE = OBJECT_END + 0x0047, // Size: 1, Type: INT, Flags: OWNER + UNIT_FIELD_PETNEXTLEVELEXP = OBJECT_END + 0x0048, // Size: 1, Type: INT, Flags: OWNER + UNIT_DYNAMIC_FLAGS = OBJECT_END + 0x0049, // Size: 1, Type: INT, Flags: DYNAMIC + UNIT_MOD_CAST_SPEED = OBJECT_END + 0x004A, // Size: 1, Type: FLOAT, Flags: PUBLIC + UNIT_CREATED_BY_SPELL = OBJECT_END + 0x004B, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_NPC_FLAGS = OBJECT_END + 0x004C, // Size: 1, Type: INT, Flags: DYNAMIC + UNIT_NPC_EMOTESTATE = OBJECT_END + 0x004D, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_STAT0 = OBJECT_END + 0x004E, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_STAT1 = OBJECT_END + 0x004F, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_STAT2 = OBJECT_END + 0x0050, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_STAT3 = OBJECT_END + 0x0051, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_STAT4 = OBJECT_END + 0x0052, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_POSSTAT0 = OBJECT_END + 0x0053, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_POSSTAT1 = OBJECT_END + 0x0054, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_POSSTAT2 = OBJECT_END + 0x0055, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_POSSTAT3 = OBJECT_END + 0x0056, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_POSSTAT4 = OBJECT_END + 0x0057, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_NEGSTAT0 = OBJECT_END + 0x0058, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_NEGSTAT1 = OBJECT_END + 0x0059, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_NEGSTAT2 = OBJECT_END + 0x005A, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_NEGSTAT3 = OBJECT_END + 0x005B, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_NEGSTAT4 = OBJECT_END + 0x005C, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_RESISTANCES = OBJECT_END + 0x005D, // Size: 7, Type: INT, Flags: PRIVATE, OWNER, PARTY_LEADER + UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE = OBJECT_END + 0x0064, // Size: 7, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE = OBJECT_END + 0x006B, // Size: 7, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_BASE_MANA = OBJECT_END + 0x0072, // Size: 1, Type: INT, Flags: PUBLIC + UNIT_FIELD_BASE_HEALTH = OBJECT_END + 0x0073, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_BYTES_2 = OBJECT_END + 0x0074, // Size: 1, Type: BYTES, Flags: PUBLIC + UNIT_FIELD_ATTACK_POWER = OBJECT_END + 0x0075, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_ATTACK_POWER_MODS = OBJECT_END + 0x0076, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE, OWNER + UNIT_FIELD_ATTACK_POWER_MULTIPLIER = OBJECT_END + 0x0077, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER + UNIT_FIELD_RANGED_ATTACK_POWER = OBJECT_END + 0x0078, // Size: 1, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_RANGED_ATTACK_POWER_MODS = OBJECT_END + 0x0079, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE, OWNER + UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = OBJECT_END + 0x007A, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER + UNIT_FIELD_MINRANGEDDAMAGE = OBJECT_END + 0x007B, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER + UNIT_FIELD_MAXRANGEDDAMAGE = OBJECT_END + 0x007C, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER + UNIT_FIELD_POWER_COST_MODIFIER = OBJECT_END + 0x007D, // Size: 7, Type: INT, Flags: PRIVATE, OWNER + UNIT_FIELD_POWER_COST_MULTIPLIER = OBJECT_END + 0x0084, // Size: 7, Type: FLOAT, Flags: PRIVATE, OWNER + UNIT_FIELD_MAXHEALTHMODIFIER = OBJECT_END + 0x008B, // Size: 1, Type: FLOAT, Flags: PRIVATE, OWNER + UNIT_FIELD_HOVERHEIGHT = OBJECT_END + 0x008C, // Size: 1, Type: FLOAT, Flags: PUBLIC + UNIT_FIELD_PADDING = OBJECT_END + 0x008D, // Size: 1, Type: INT, Flags: NONE + UNIT_END = OBJECT_END + 0x008E, + + PLAYER_DUEL_ARBITER = UNIT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC + PLAYER_FLAGS = UNIT_END + 0x0002, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_GUILDID = UNIT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_GUILDRANK = UNIT_END + 0x0004, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_BYTES = UNIT_END + 0x0005, // Size: 1, Type: BYTES, Flags: PUBLIC + PLAYER_BYTES_2 = UNIT_END + 0x0006, // Size: 1, Type: BYTES, Flags: PUBLIC + PLAYER_BYTES_3 = UNIT_END + 0x0007, // Size: 1, Type: BYTES, Flags: PUBLIC + PLAYER_DUEL_TEAM = UNIT_END + 0x0008, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_GUILD_TIMESTAMP = UNIT_END + 0x0009, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_QUEST_LOG_1_1 = UNIT_END + 0x000A, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_1_2 = UNIT_END + 0x000B, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_1_3 = UNIT_END + 0x000C, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_1_4 = UNIT_END + 0x000E, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_2_1 = UNIT_END + 0x000F, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_2_2 = UNIT_END + 0x0010, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_2_3 = UNIT_END + 0x0011, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_2_5 = UNIT_END + 0x0013, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_3_1 = UNIT_END + 0x0014, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_3_2 = UNIT_END + 0x0015, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_3_3 = UNIT_END + 0x0016, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_3_5 = UNIT_END + 0x0018, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_4_1 = UNIT_END + 0x0019, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_4_2 = UNIT_END + 0x001A, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_4_3 = UNIT_END + 0x001B, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_4_5 = UNIT_END + 0x001D, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_5_1 = UNIT_END + 0x001E, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_5_2 = UNIT_END + 0x001F, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_5_3 = UNIT_END + 0x0020, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_5_5 = UNIT_END + 0x0022, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_6_1 = UNIT_END + 0x0023, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_6_2 = UNIT_END + 0x0024, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_6_3 = UNIT_END + 0x0025, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_6_5 = UNIT_END + 0x0027, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_7_1 = UNIT_END + 0x0028, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_7_2 = UNIT_END + 0x0029, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_7_3 = UNIT_END + 0x002A, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_7_5 = UNIT_END + 0x002C, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_8_1 = UNIT_END + 0x002D, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_8_2 = UNIT_END + 0x002E, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_8_3 = UNIT_END + 0x002F, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_8_5 = UNIT_END + 0x0031, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_9_1 = UNIT_END + 0x0032, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_9_2 = UNIT_END + 0x0033, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_9_3 = UNIT_END + 0x0034, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_9_5 = UNIT_END + 0x0036, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_10_1 = UNIT_END + 0x0037, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_10_2 = UNIT_END + 0x0038, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_10_3 = UNIT_END + 0x0039, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_10_5 = UNIT_END + 0x003B, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_11_1 = UNIT_END + 0x003C, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_11_2 = UNIT_END + 0x003D, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_11_3 = UNIT_END + 0x003E, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_11_5 = UNIT_END + 0x0040, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_12_1 = UNIT_END + 0x0041, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_12_2 = UNIT_END + 0x0042, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_12_3 = UNIT_END + 0x0043, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_12_5 = UNIT_END + 0x0045, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_13_1 = UNIT_END + 0x0046, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_13_2 = UNIT_END + 0x0047, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_13_3 = UNIT_END + 0x0048, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_13_5 = UNIT_END + 0x004A, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_14_1 = UNIT_END + 0x004B, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_14_2 = UNIT_END + 0x004C, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_14_3 = UNIT_END + 0x004D, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_14_5 = UNIT_END + 0x004F, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_15_1 = UNIT_END + 0x0050, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_15_2 = UNIT_END + 0x0051, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_15_3 = UNIT_END + 0x0052, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_15_5 = UNIT_END + 0x0054, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_16_1 = UNIT_END + 0x0055, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_16_2 = UNIT_END + 0x0056, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_16_3 = UNIT_END + 0x0057, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_16_5 = UNIT_END + 0x0059, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_17_1 = UNIT_END + 0x005A, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_17_2 = UNIT_END + 0x005B, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_17_3 = UNIT_END + 0x005C, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_17_5 = UNIT_END + 0x005E, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_18_1 = UNIT_END + 0x005F, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_18_2 = UNIT_END + 0x0060, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_18_3 = UNIT_END + 0x0061, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_18_5 = UNIT_END + 0x0063, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_19_1 = UNIT_END + 0x0064, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_19_2 = UNIT_END + 0x0065, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_19_3 = UNIT_END + 0x0066, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_19_5 = UNIT_END + 0x0068, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_20_1 = UNIT_END + 0x0069, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_20_2 = UNIT_END + 0x006A, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_20_3 = UNIT_END + 0x006B, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_20_5 = UNIT_END + 0x006D, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_21_1 = UNIT_END + 0x006E, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_21_2 = UNIT_END + 0x006F, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_21_3 = UNIT_END + 0x0070, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_21_5 = UNIT_END + 0x0072, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_22_1 = UNIT_END + 0x0073, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_22_2 = UNIT_END + 0x0074, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_22_3 = UNIT_END + 0x0075, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_22_5 = UNIT_END + 0x0077, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_23_1 = UNIT_END + 0x0078, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_23_2 = UNIT_END + 0x0079, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_23_3 = UNIT_END + 0x007A, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_23_5 = UNIT_END + 0x007C, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_24_1 = UNIT_END + 0x007D, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_24_2 = UNIT_END + 0x007E, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_24_3 = UNIT_END + 0x007F, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_24_5 = UNIT_END + 0x0081, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_25_1 = UNIT_END + 0x0082, // Size: 1, Type: INT, Flags: PARTY_MEMBER + PLAYER_QUEST_LOG_25_2 = UNIT_END + 0x0083, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_QUEST_LOG_25_3 = UNIT_END + 0x0084, // Size: 2, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_QUEST_LOG_25_5 = UNIT_END + 0x0086, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_VISIBLE_ITEM_1_ENTRYID = UNIT_END + 0x0087, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_1_ENCHANTMENT = UNIT_END + 0x0088, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_2_ENTRYID = UNIT_END + 0x0089, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_2_ENCHANTMENT = UNIT_END + 0x008A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_3_ENTRYID = UNIT_END + 0x008B, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_3_ENCHANTMENT = UNIT_END + 0x008C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_4_ENTRYID = UNIT_END + 0x008D, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_4_ENCHANTMENT = UNIT_END + 0x008E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_5_ENTRYID = UNIT_END + 0x008F, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_5_ENCHANTMENT = UNIT_END + 0x0090, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_6_ENTRYID = UNIT_END + 0x0091, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_6_ENCHANTMENT = UNIT_END + 0x0092, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_7_ENTRYID = UNIT_END + 0x0093, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_7_ENCHANTMENT = UNIT_END + 0x0094, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_8_ENTRYID = UNIT_END + 0x0095, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_8_ENCHANTMENT = UNIT_END + 0x0096, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_9_ENTRYID = UNIT_END + 0x0097, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_9_ENCHANTMENT = UNIT_END + 0x0098, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_10_ENTRYID = UNIT_END + 0x0099, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_10_ENCHANTMENT = UNIT_END + 0x009A, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_11_ENTRYID = UNIT_END + 0x009B, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_11_ENCHANTMENT = UNIT_END + 0x009C, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_12_ENTRYID = UNIT_END + 0x009D, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_12_ENCHANTMENT = UNIT_END + 0x009E, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_13_ENTRYID = UNIT_END + 0x009F, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_13_ENCHANTMENT = UNIT_END + 0x00A0, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_14_ENTRYID = UNIT_END + 0x00A1, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_14_ENCHANTMENT = UNIT_END + 0x00A2, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_15_ENTRYID = UNIT_END + 0x00A3, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_15_ENCHANTMENT = UNIT_END + 0x00A4, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_16_ENTRYID = UNIT_END + 0x00A5, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_16_ENCHANTMENT = UNIT_END + 0x00A6, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_17_ENTRYID = UNIT_END + 0x00A7, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_17_ENCHANTMENT = UNIT_END + 0x00A8, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_18_ENTRYID = UNIT_END + 0x00A9, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_18_ENCHANTMENT = UNIT_END + 0x00AA, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_19_ENTRYID = UNIT_END + 0x00AB, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_VISIBLE_ITEM_19_ENCHANTMENT = UNIT_END + 0x00AC, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC + PLAYER_CHOSEN_TITLE = UNIT_END + 0x00AD, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_FAKE_INEBRIATION = UNIT_END + 0x00AE, // Size: 1, Type: INT, Flags: PUBLIC + PLAYER_FIELD_PAD_0 = UNIT_END + 0x00AF, // Size: 1, Type: INT, Flags: NONE + PLAYER_FIELD_INV_SLOT_HEAD = UNIT_END + 0x00B0, // Size: 46, Type: LONG, Flags: PRIVATE + PLAYER_FIELD_PACK_SLOT_1 = UNIT_END + 0x00DE, // Size: 32, Type: LONG, Flags: PRIVATE + PLAYER_FIELD_BANK_SLOT_1 = UNIT_END + 0x00FE, // Size: 56, Type: LONG, Flags: PRIVATE + PLAYER_FIELD_BANKBAG_SLOT_1 = UNIT_END + 0x0136, // Size: 14, Type: LONG, Flags: PRIVATE + PLAYER_FIELD_VENDORBUYBACK_SLOT_1 = UNIT_END + 0x0144, // Size: 24, Type: LONG, Flags: PRIVATE + PLAYER_FIELD_KEYRING_SLOT_1 = UNIT_END + 0x015C, // Size: 64, Type: LONG, Flags: PRIVATE + PLAYER_FIELD_CURRENCYTOKEN_SLOT_1 = UNIT_END + 0x019C, // Size: 64, Type: LONG, Flags: PRIVATE + PLAYER_FARSIGHT = UNIT_END + 0x01DC, // Size: 2, Type: LONG, Flags: PRIVATE + PLAYER__FIELD_KNOWN_TITLES = UNIT_END + 0x01DE, // Size: 2, Type: LONG, Flags: PRIVATE + PLAYER__FIELD_KNOWN_TITLES1 = UNIT_END + 0x01E0, // Size: 2, Type: LONG, Flags: PRIVATE + PLAYER__FIELD_KNOWN_TITLES2 = UNIT_END + 0x01E2, // Size: 2, Type: LONG, Flags: PRIVATE + PLAYER_FIELD_KNOWN_CURRENCIES = UNIT_END + 0x01E4, // Size: 2, Type: LONG, Flags: PRIVATE + PLAYER_XP = UNIT_END + 0x01E6, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_NEXT_LEVEL_XP = UNIT_END + 0x01E7, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_SKILL_INFO_1_1 = UNIT_END + 0x01E8, // Size: 384, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_CHARACTER_POINTS1 = UNIT_END + 0x0368, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_CHARACTER_POINTS2 = UNIT_END + 0x0369, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_TRACK_CREATURES = UNIT_END + 0x036A, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_TRACK_RESOURCES = UNIT_END + 0x036B, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_BLOCK_PERCENTAGE = UNIT_END + 0x036C, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_DODGE_PERCENTAGE = UNIT_END + 0x036D, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_PARRY_PERCENTAGE = UNIT_END + 0x036E, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_EXPERTISE = UNIT_END + 0x036F, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_OFFHAND_EXPERTISE = UNIT_END + 0x0370, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_CRIT_PERCENTAGE = UNIT_END + 0x0371, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_RANGED_CRIT_PERCENTAGE = UNIT_END + 0x0372, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_OFFHAND_CRIT_PERCENTAGE = UNIT_END + 0x0373, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_SPELL_CRIT_PERCENTAGE1 = UNIT_END + 0x0374, // Size: 7, Type: FLOAT, Flags: PRIVATE + PLAYER_SHIELD_BLOCK = UNIT_END + 0x037B, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_SHIELD_BLOCK_CRIT_PERCENTAGE = UNIT_END + 0x037C, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_EXPLORED_ZONES_1 = UNIT_END + 0x037D, // Size: 128, Type: BYTES, Flags: PRIVATE + PLAYER_REST_STATE_EXPERIENCE = UNIT_END + 0x03FD, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_COINAGE = UNIT_END + 0x03FE, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MOD_DAMAGE_DONE_POS = UNIT_END + 0x03FF, // Size: 7, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MOD_DAMAGE_DONE_NEG = UNIT_END + 0x0406, // Size: 7, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MOD_DAMAGE_DONE_PCT = UNIT_END + 0x040D, // Size: 7, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MOD_HEALING_DONE_POS = UNIT_END + 0x0414, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MOD_HEALING_PCT = UNIT_END + 0x0415, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_FIELD_MOD_HEALING_DONE_PCT = UNIT_END + 0x0416, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_FIELD_MOD_TARGET_RESISTANCE = UNIT_END + 0x0417, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE = UNIT_END + 0x0418, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_BYTES = UNIT_END + 0x0419, // Size: 1, Type: BYTES, Flags: PRIVATE + PLAYER_AMMO_ID = UNIT_END + 0x041A, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_SELF_RES_SPELL = UNIT_END + 0x041B, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_PVP_MEDALS = UNIT_END + 0x041C, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_BUYBACK_PRICE_1 = UNIT_END + 0x041D, // Size: 12, Type: INT, Flags: PRIVATE + PLAYER_FIELD_BUYBACK_TIMESTAMP_1 = UNIT_END + 0x0429, // Size: 12, Type: INT, Flags: PRIVATE + PLAYER_FIELD_KILLS = UNIT_END + 0x0435, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_FIELD_TODAY_CONTRIBUTION = UNIT_END + 0x0436, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_YESTERDAY_CONTRIBUTION = UNIT_END + 0x0437, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_LIFETIME_HONORABLE_KILLS = UNIT_END + 0x0438, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_BYTES2 = UNIT_END + 0x0439, // Size: 1, Type: 6, Flags: PRIVATE + PLAYER_FIELD_WATCHED_FACTION_INDEX = UNIT_END + 0x043A, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_COMBAT_RATING_1 = UNIT_END + 0x043B, // Size: 25, Type: INT, Flags: PRIVATE + PLAYER_FIELD_ARENA_TEAM_INFO_1_1 = UNIT_END + 0x0454, // Size: 21, Type: INT, Flags: PRIVATE + PLAYER_FIELD_HONOR_CURRENCY = UNIT_END + 0x0469, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_ARENA_CURRENCY = UNIT_END + 0x046A, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MAX_LEVEL = UNIT_END + 0x046B, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_DAILY_QUESTS_1 = UNIT_END + 0x046C, // Size: 25, Type: INT, Flags: PRIVATE + PLAYER_RUNE_REGEN_1 = UNIT_END + 0x0485, // Size: 4, Type: FLOAT, Flags: PRIVATE + PLAYER_NO_REAGENT_COST_1 = UNIT_END + 0x0489, // Size: 3, Type: INT, Flags: PRIVATE + PLAYER_FIELD_GLYPH_SLOTS_1 = UNIT_END + 0x048C, // Size: 6, Type: INT, Flags: PRIVATE + PLAYER_FIELD_GLYPHS_1 = UNIT_END + 0x0492, // Size: 6, Type: INT, Flags: PRIVATE + PLAYER_GLYPHS_ENABLED = UNIT_END + 0x0498, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_PET_SPELL_POWER = UNIT_END + 0x0499, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_END = UNIT_END + 0x049A, +}; + +enum EGameObjectFields +{ + OBJECT_FIELD_CREATED_BY = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC + GAMEOBJECT_DISPLAYID = OBJECT_END + 0x0002, // Size: 1, Type: INT, Flags: PUBLIC + GAMEOBJECT_FLAGS = OBJECT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC + GAMEOBJECT_PARENTROTATION = OBJECT_END + 0x0004, // Size: 4, Type: FLOAT, Flags: PUBLIC + GAMEOBJECT_DYNAMIC = OBJECT_END + 0x0008, // Size: 1, Type: TWO_SHORT, Flags: DYNAMIC + GAMEOBJECT_FACTION = OBJECT_END + 0x0009, // Size: 1, Type: INT, Flags: PUBLIC + GAMEOBJECT_LEVEL = OBJECT_END + 0x000A, // Size: 1, Type: INT, Flags: PUBLIC + GAMEOBJECT_BYTES_1 = OBJECT_END + 0x000B, // Size: 1, Type: BYTES, Flags: PUBLIC + GAMEOBJECT_END = OBJECT_END + 0x000C, +}; + +enum EDynamicObjectFields +{ + DYNAMICOBJECT_CASTER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC + DYNAMICOBJECT_BYTES = OBJECT_END + 0x0002, // Size: 1, Type: BYTES, Flags: PUBLIC + DYNAMICOBJECT_SPELLID = OBJECT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC + DYNAMICOBJECT_RADIUS = OBJECT_END + 0x0004, // Size: 1, Type: FLOAT, Flags: PUBLIC + DYNAMICOBJECT_CASTTIME = OBJECT_END + 0x0005, // Size: 1, Type: INT, Flags: PUBLIC + DYNAMICOBJECT_END = OBJECT_END + 0x0006, +}; + +enum ECorpseFields +{ + CORPSE_FIELD_OWNER = OBJECT_END + 0x0000, // Size: 2, Type: LONG, Flags: PUBLIC + CORPSE_FIELD_PARTY = OBJECT_END + 0x0002, // Size: 2, Type: LONG, Flags: PUBLIC + CORPSE_FIELD_DISPLAY_ID = OBJECT_END + 0x0004, // Size: 1, Type: INT, Flags: PUBLIC + CORPSE_FIELD_ITEM = OBJECT_END + 0x0005, // Size: 19, Type: INT, Flags: PUBLIC + CORPSE_FIELD_BYTES_1 = OBJECT_END + 0x0018, // Size: 1, Type: BYTES, Flags: PUBLIC + CORPSE_FIELD_BYTES_2 = OBJECT_END + 0x0019, // Size: 1, Type: BYTES, Flags: PUBLIC + CORPSE_FIELD_GUILD = OBJECT_END + 0x001A, // Size: 1, Type: INT, Flags: PUBLIC + CORPSE_FIELD_FLAGS = OBJECT_END + 0x001B, // Size: 1, Type: INT, Flags: PUBLIC + CORPSE_FIELD_DYNAMIC_FLAGS = OBJECT_END + 0x001C, // Size: 1, Type: INT, Flags: DYNAMIC + CORPSE_FIELD_PAD = OBJECT_END + 0x001D, // Size: 1, Type: INT, Flags: NONE + CORPSE_END = OBJECT_END + 0x001E, +}; +#endif diff --git a/src/server/game/Entities/Object/Updates/UpdateMask.h b/src/server/game/Entities/Object/Updates/UpdateMask.h new file mode 100644 index 00000000000..527bec42aa7 --- /dev/null +++ b/src/server/game/Entities/Object/Updates/UpdateMask.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __UPDATEMASK_H +#define __UPDATEMASK_H + +#include "UpdateFields.h" +#include "Errors.h" + +class UpdateMask +{ + public: + UpdateMask() : mCount(0), mBlocks(0), mUpdateMask(0) { } + UpdateMask(const UpdateMask& mask) : mUpdateMask(0) { *this = mask; } + + ~UpdateMask() + { + if (mUpdateMask) + delete [] mUpdateMask; + } + + void SetBit (uint32 index) + { + ((uint8 *)mUpdateMask)[ index >> 3 ] |= 1 << (index & 0x7); + } + + void UnsetBit (uint32 index) + { + ((uint8 *)mUpdateMask)[ index >> 3 ] &= (0xff ^ (1 << (index & 0x7))); + } + + bool GetBit (uint32 index) const + { + return (((uint8 *)mUpdateMask)[ index >> 3 ] & (1 << (index & 0x7))) != 0; + } + + uint32 GetBlockCount() const { return mBlocks; } + uint32 GetLength() const { return mBlocks << 2; } + uint32 GetCount() const { return mCount; } + uint8* GetMask() { return (uint8*)mUpdateMask; } + + void SetCount (uint32 valuesCount) + { + if (mUpdateMask) + delete [] mUpdateMask; + + mCount = valuesCount; + mBlocks = (valuesCount + 31) / 32; + + mUpdateMask = new uint32[mBlocks]; + memset(mUpdateMask, 0, mBlocks << 2); + } + + void Clear() + { + if (mUpdateMask) + memset(mUpdateMask, 0, mBlocks << 2); + } + + UpdateMask& operator = (const UpdateMask& mask) + { + SetCount(mask.mCount); + memcpy(mUpdateMask, mask.mUpdateMask, mBlocks << 2); + + return *this; + } + + void operator &= (const UpdateMask& mask) + { + ASSERT(mask.mCount <= mCount); + for (uint32 i = 0; i < mBlocks; ++i) + mUpdateMask[i] &= mask.mUpdateMask[i]; + } + + void operator |= (const UpdateMask& mask) + { + ASSERT(mask.mCount <= mCount); + for (uint32 i = 0; i < mBlocks; ++i) + mUpdateMask[i] |= mask.mUpdateMask[i]; + } + + UpdateMask operator & (const UpdateMask& mask) const + { + ASSERT(mask.mCount <= mCount); + + UpdateMask newmask; + newmask = *this; + newmask &= mask; + + return newmask; + } + + UpdateMask operator | (const UpdateMask& mask) const + { + ASSERT(mask.mCount <= mCount); + + UpdateMask newmask; + newmask = *this; + newmask |= mask; + + return newmask; + } + + private: + uint32 mCount; + uint32 mBlocks; + uint32 *mUpdateMask; +}; +#endif + diff --git a/src/server/game/Entities/Pet/PetHandler.cpp b/src/server/game/Entities/Pet/PetHandler.cpp deleted file mode 100644 index 34e6845762b..00000000000 --- a/src/server/game/Entities/Pet/PetHandler.cpp +++ /dev/null @@ -1,813 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "Log.h" -#include "Opcodes.h" -#include "Spell.h" -#include "ObjectAccessor.h" -#include "CreatureAI.h" -#include "Util.h" -#include "Pet.h" -#include "World.h" - -void WorldSession::HandleDismissCritter(WorldPacket &recv_data) -{ - uint64 guid; - recv_data >> guid; - - sLog.outDebug("WORLD: Received CMSG_DISMISS_CRITTER for GUID %u", guid); - - Unit* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); - - if (!pet) - { - sLog.outError("Vanitypet %u does not exist", uint32(GUID_LOPART(guid))); - return; - } - - if (_player->GetCritterGUID() == pet->GetGUID()) - { - if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isSummon()) - pet->ToTempSummon()->UnSummon(); - } -} - -void WorldSession::HandlePetAction(WorldPacket & recv_data) -{ - uint64 guid1; - uint32 data; - uint64 guid2; - recv_data >> guid1; //pet guid - recv_data >> data; - recv_data >> guid2; //tag guid - - uint32 spellid = UNIT_ACTION_BUTTON_ACTION(data); - uint8 flag = UNIT_ACTION_BUTTON_TYPE(data); //delete = 0x07 CastSpell = C1 - - // used also for charmed creature - Unit* pet= ObjectAccessor::GetUnit(*_player, guid1); - sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.", uint32(GUID_LOPART(guid1)), uint32(flag), spellid, uint32(GUID_LOPART(guid2))); - if (!pet) - { - sLog.outError("Pet %u not exist.", uint32(GUID_LOPART(guid1))); - return; - } - - if (pet != GetPlayer()->GetFirstControlled()) - { - sLog.outError("HandlePetAction.Pet %u isn't pet of player %s.", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName()); - return; - } - - if (!pet->isAlive()) - return; - - //TODO: allow control charmed player? - if (pet->GetTypeId() == TYPEID_PLAYER && !(flag == ACT_COMMAND && spellid == COMMAND_ATTACK)) - return; - - if (GetPlayer()->m_Controlled.size() == 1) - HandlePetActionHelper(pet, guid1, spellid, flag, guid2); - else - { - //If a pet is dismissed, m_Controlled will change - std::vector controlled; - for (Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr) - if ((*itr)->GetEntry() == pet->GetEntry() && (*itr)->isAlive()) - controlled.push_back(*itr); - for (std::vector::iterator itr = controlled.begin(); itr != controlled.end(); ++itr) - HandlePetActionHelper(*itr, guid1, spellid, flag, guid2); - } -} - -void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid, uint16 flag, uint64 guid2) -{ - CharmInfo *charmInfo = pet->GetCharmInfo(); - if (!charmInfo) - { - sLog.outError("WorldSession::HandlePetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId()); - return; - } - - switch(flag) - { - case ACT_COMMAND: //0x07 - switch(spellid) - { - case COMMAND_STAY: //flat=1792 //STAY - pet->AttackStop(); - pet->InterruptNonMeleeSpells(false); - pet->GetMotionMaster()->MoveIdle(); - charmInfo->SetCommandState(COMMAND_STAY); - - charmInfo->SetIsCommandAttack(false); - charmInfo->SetIsAtStay(true); - charmInfo->SetIsFollowing(false); - charmInfo->SetIsReturning(false); - charmInfo->SaveStayPosition(); - break; - case COMMAND_FOLLOW: //spellid=1792 //FOLLOW - pet->AttackStop(); - pet->InterruptNonMeleeSpells(false); - pet->GetMotionMaster()->MoveFollow(_player,PET_FOLLOW_DIST,pet->GetFollowAngle()); - charmInfo->SetCommandState(COMMAND_FOLLOW); - - charmInfo->SetIsCommandAttack(false); - charmInfo->SetIsAtStay(false); - charmInfo->SetIsReturning(true); - charmInfo->SetIsFollowing(false); - break; - case COMMAND_ATTACK: //spellid=1792 //ATTACK - { - // Can't attack if owner is pacified - if (_player->HasAuraType(SPELL_AURA_MOD_PACIFY)) - { - //pet->SendPetCastFail(spellid, SPELL_FAILED_PACIFIED); - //TODO: Send proper error message to client - return; - } - - // only place where pet can be player - Unit *TargetUnit = ObjectAccessor::GetUnit(*_player, guid2); - if (!TargetUnit) - return; - - if (!pet->canAttack(TargetUnit)) - return; - - // Not let attack through obstructions - if (sWorld.getConfig(CONFIG_PET_LOS)) - { - - if (!pet->IsWithinLOSInMap(TargetUnit)) - return; - - } - - pet->clearUnitState(UNIT_STAT_FOLLOW); - // This is true if pet has no target or has target but targets differs. - if (pet->getVictim() != TargetUnit || (pet->getVictim() == TargetUnit && !pet->GetCharmInfo()->IsCommandAttack())) - { - if (pet->getVictim()) - pet->AttackStop(); - - if (pet->GetTypeId() != TYPEID_PLAYER && pet->ToCreature()->IsAIEnabled) - { - charmInfo->SetIsCommandAttack(true); - charmInfo->SetIsAtStay(false); - charmInfo->SetIsFollowing(false); - charmInfo->SetIsReturning(false); - - pet->ToCreature()->AI()->AttackStart(TargetUnit); - - //10% chance to play special pet attack talk, else growl - if (pet->ToCreature()->isPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10) - pet->SendPetTalk((uint32)PET_TALK_ATTACK); - else - { - // 90% chance for pet and 100% chance for charmed creature - pet->SendPetAIReaction(guid1); - } - } - else // charmed player - { - if (pet->getVictim() && pet->getVictim() != TargetUnit) - pet->AttackStop(); - - charmInfo->SetIsCommandAttack(true); - charmInfo->SetIsAtStay(false); - charmInfo->SetIsFollowing(false); - charmInfo->SetIsReturning(false); - - pet->Attack(TargetUnit,true); - pet->SendPetAIReaction(guid1); - } - } - break; - } - case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet) - if (pet->GetCharmerGUID() == GetPlayer()->GetGUID()) - _player->StopCastingCharm(); - else if (pet->GetOwnerGUID() == GetPlayer()->GetGUID()) - { - assert(pet->GetTypeId() == TYPEID_UNIT); - if (pet->isPet()) - { - if (((Pet*)pet)->getPetType() == HUNTER_PET) - GetPlayer()->RemovePet((Pet*)pet, PET_SAVE_AS_DELETED); - else - //dismissing a summoned pet is like killing them (this prevents returning a soulshard...) - pet->setDeathState(CORPSE); - } - else if (pet->HasUnitTypeMask(UNIT_MASK_MINION)) - { - ((Minion*)pet)->UnSummon(); - } - } - break; - default: - sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); - } - break; - case ACT_REACTION: // 0x6 - switch(spellid) - { - case REACT_PASSIVE: //passive - pet->AttackStop(); - - case REACT_DEFENSIVE: //recovery - case REACT_AGGRESSIVE: //activete - if (pet->GetTypeId() == TYPEID_UNIT) - pet->ToCreature()->SetReactState(ReactStates(spellid)); - break; - } - break; - case ACT_DISABLED: // 0x81 spell (disabled), ignore - case ACT_PASSIVE: // 0x01 - case ACT_ENABLED: // 0xC1 spell - { - Unit* unit_target = NULL; - - if (guid2) - unit_target = ObjectAccessor::GetUnit(*_player,guid2); - - // do not cast unknown spells - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid); - if (!spellInfo) - { - sLog.outError("WORLD: unknown PET spell id %i", spellid); - return; - } - - if (spellInfo->StartRecoveryCategory > 0) - if (pet->ToCreature()->GetGlobalCooldown() > 0) - return; - - for (uint32 i = 0; i < 3; ++i) - { - if (spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENEMY_SRC || spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENEMY_DST || spellInfo->EffectImplicitTargetA[i] == TARGET_DEST_DYNOBJ_ENEMY) - return; - } - - // do not cast not learned spells - if (!pet->HasSpell(spellid) || IsPassiveSpell(spellid)) - return; - - // Clear the flags as if owner clicked 'attack'. AI will reset them - // after AttackStart, even if spell failed - if (pet->GetCharmInfo()) - { - pet->GetCharmInfo()->SetIsAtStay(false); - pet->GetCharmInfo()->SetIsCommandAttack(true); - pet->GetCharmInfo()->SetIsReturning(false); - pet->GetCharmInfo()->SetIsFollowing(false); - } - - Spell *spell = new Spell(pet, spellInfo, false); - - SpellCastResult result = spell->CheckPetCast(unit_target); - - //auto turn to target unless possessed - if (result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->isPossessed() && !pet->IsVehicle()) - { - if (unit_target) - { - pet->SetInFront(unit_target); - if (unit_target->GetTypeId() == TYPEID_PLAYER) - pet->SendUpdateToPlayer((Player*)unit_target); - } - else if (Unit *unit_target2 = spell->m_targets.getUnitTarget()) - { - pet->SetInFront(unit_target2); - if (unit_target2->GetTypeId() == TYPEID_PLAYER) - pet->SendUpdateToPlayer((Player*)unit_target2); - } - if (Unit* powner = pet->GetCharmerOrOwner()) - if (powner->GetTypeId() == TYPEID_PLAYER) - pet->SendUpdateToPlayer(powner->ToPlayer()); - result = SPELL_CAST_OK; - } - - if (result == SPELL_CAST_OK) - { - pet->ToCreature()->AddCreatureSpellCooldown(spellid); - - unit_target = spell->m_targets.getUnitTarget(); - - //10% chance to play special pet attack talk, else growl - //actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell - if (pet->ToCreature()->isPet() && (((Pet*)pet)->getPetType() == SUMMON_PET) && (pet != unit_target) && (urand(0, 100) < 10)) - pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); - else - { - pet->SendPetAIReaction(guid1); - } - - if (unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->isPossessed() && !pet->IsVehicle()) - { - // This is true if pet has no target or has target but targets differs. - if (pet->getVictim() != unit_target) - { - if (pet->getVictim()) - pet->AttackStop(); - pet->GetMotionMaster()->Clear(); - if (pet->ToCreature()->IsAIEnabled) - pet->ToCreature()->AI()->AttackStart(unit_target); - } - } - - spell->prepare(&(spell->m_targets)); - } - else - { - if (pet->isPossessed() || pet->IsVehicle()) - Spell::SendCastResult(GetPlayer(),spellInfo,0,result); - else - pet->SendPetCastFail(spellid, result); - - if (!pet->ToCreature()->HasSpellCooldown(spellid)) - GetPlayer()->SendClearCooldown(spellid, pet); - - spell->finish(false); - delete spell; - - // reset specific flags in case of spell fail. AI will reset other flags - if (pet->GetCharmInfo()) - pet->GetCharmInfo()->SetIsCommandAttack(false); - } - break; - } - default: - sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); - } -} - -void WorldSession::HandlePetNameQuery(WorldPacket & recv_data) -{ - sLog.outDetail("HandlePetNameQuery. CMSG_PET_NAME_QUERY"); - - uint32 petnumber; - uint64 petguid; - - recv_data >> petnumber; - recv_data >> petguid; - - SendPetNameQuery(petguid,petnumber); -} - -void WorldSession::SendPetNameQuery(uint64 petguid, uint32 petnumber) -{ - Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, petguid); - if (!pet) - { - WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4+4+7+1)); - data << uint32(petnumber); - data << "Unknown"; - data << uint32(0); - data << uint8(0); - _player->GetSession()->SendPacket(&data); - return; - } - - std::string name = pet->GetName(); - - WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4+4+name.size()+1)); - data << uint32(petnumber); - data << name.c_str(); - data << uint32(pet->GetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP)); - - if (pet->isPet() && ((Pet*)pet)->GetDeclinedNames()) - { - data << uint8(1); - for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - data << ((Pet*)pet)->GetDeclinedNames()->name[i]; - } - else - data << uint8(0); - - _player->GetSession()->SendPacket(&data); -} - -void WorldSession::HandlePetSetAction(WorldPacket & recv_data) -{ - sLog.outDetail("HandlePetSetAction. CMSG_PET_SET_ACTION"); - - uint64 petguid; - uint8 count; - - recv_data >> petguid; - - Unit* pet = ObjectAccessor::GetUnit(*_player, petguid); - - if (!pet || pet != _player->GetFirstControlled()) - { - sLog.outError("HandlePetSetAction: Unknown pet or pet owner."); - return; - } - - CharmInfo *charmInfo = pet->GetCharmInfo(); - if (!charmInfo) - { - sLog.outError("WorldSession::HandlePetSetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId()); - return; - } - - count = (recv_data.size() == 24) ? 2 : 1; - - uint32 position[2]; - uint32 data[2]; - bool move_command = false; - - for (uint8 i = 0; i < count; ++i) - { - recv_data >> position[i]; - recv_data >> data[i]; - - uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]); - - //ignore invalid position - if (position[i] >= MAX_UNIT_ACTION_BAR_INDEX) - return; - - // in the normal case, command and reaction buttons can only be moved, not removed - // at moving count == 2, at removing count == 1 - // ignore attempt to remove command|reaction buttons (not possible at normal case) - if (act_state == ACT_COMMAND || act_state == ACT_REACTION) - { - if (count == 1) - return; - - move_command = true; - } - } - - // check swap (at command->spell swap client remove spell first in another packet, so check only command move correctness) - if (move_command) - { - uint8 act_state_0 = UNIT_ACTION_BUTTON_TYPE(data[0]); - if (act_state_0 == ACT_COMMAND || act_state_0 == ACT_REACTION) - { - uint32 spell_id_0 = UNIT_ACTION_BUTTON_ACTION(data[0]); - UnitActionBarEntry const* actionEntry_1 = charmInfo->GetActionBarEntry(position[1]); - if (!actionEntry_1 || spell_id_0 != actionEntry_1->GetAction() || - act_state_0 != actionEntry_1->GetType()) - return; - } - - uint8 act_state_1 = UNIT_ACTION_BUTTON_TYPE(data[1]); - if (act_state_1 == ACT_COMMAND || act_state_1 == ACT_REACTION) - { - uint32 spell_id_1 = UNIT_ACTION_BUTTON_ACTION(data[1]); - UnitActionBarEntry const* actionEntry_0 = charmInfo->GetActionBarEntry(position[0]); - if (!actionEntry_0 || spell_id_1 != actionEntry_0->GetAction() || - act_state_1 != actionEntry_0->GetType()) - return; - } - } - - for (uint8 i = 0; i < count; ++i) - { - uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(data[i]); - uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]); - - sLog.outDetail("Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), 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 - if (!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id))) - { - //sign for autocast - if (act_state == ACT_ENABLED && spell_id) - { - if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isPet()) - ((Pet*)pet)->ToggleAutocast(spell_id, true); - else - charmInfo->ToggleCreatureAutocast(spell_id, true); - } - //sign for no/turn off autocast - else if (act_state == ACT_DISABLED && spell_id) - { - if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isPet()) - ((Pet*)pet)->ToggleAutocast(spell_id, false); - else - charmInfo->ToggleCreatureAutocast(spell_id, false); - - } - - charmInfo->SetActionBar(position[i],spell_id,ActiveStates(act_state)); - } - } -} - -void WorldSession::HandlePetRename(WorldPacket & recv_data) -{ - sLog.outDetail("HandlePetRename. CMSG_PET_RENAME"); - - uint64 petguid; - uint8 isdeclined; - - std::string name; - DeclinedName declinedname; - - recv_data >> petguid; - recv_data >> name; - recv_data >> isdeclined; - - Pet* pet = ObjectAccessor::GetPet(petguid); - // check it! - if (!pet || !pet->isPet() || ((Pet*)pet)->getPetType()!= HUNTER_PET || - !pet->HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) || - pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo()) - return; - - PetNameInvalidReason res = ObjectMgr::CheckPetName(name); - if (res != PET_NAME_SUCCESS) - { - SendPetNameInvalid(res, name, NULL); - return; - } - - if (objmgr.IsReservedName(name)) - { - SendPetNameInvalid(PET_NAME_RESERVED, name, NULL); - return; - } - - pet->SetName(name); - - Unit *owner = pet->GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) - owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_NAME); - - pet->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED); - - if (isdeclined) - { - for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - { - recv_data >> declinedname.name[i]; - } - - std::wstring wname; - Utf8toWStr(name, wname); - if (!ObjectMgr::CheckDeclinedNames(GetMainPartOfName(wname,0),declinedname)) - { - SendPetNameInvalid(PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME, name, &declinedname); - return; - } - } - - CharacterDatabase.BeginTransaction(); - if (isdeclined) - { - for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - CharacterDatabase.escape_string(declinedname.name[i]); - CharacterDatabase.PExecute("DELETE FROM character_pet_declinedname WHERE owner = '%u' AND id = '%u'", _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber()); - CharacterDatabase.PExecute("INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u','%u','%s','%s','%s','%s','%s')", - pet->GetCharmInfo()->GetPetNumber(), _player->GetGUIDLow(), declinedname.name[0].c_str(), declinedname.name[1].c_str(), declinedname.name[2].c_str(), declinedname.name[3].c_str(), declinedname.name[4].c_str()); - } - - CharacterDatabase.escape_string(name); - CharacterDatabase.PExecute("UPDATE character_pet SET name = '%s', renamed = '1' WHERE owner = '%u' AND id = '%u'", name.c_str(), _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber()); - CharacterDatabase.CommitTransaction(); - - pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL)); -} - -void WorldSession::HandlePetAbandon(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; //pet guid - sLog.outDetail("HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(guid)); - - if (!_player->IsInWorld()) - return; - - // pet/charmed - Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); - if (pet) - { - if (pet->isPet()) - { - if (pet->GetGUID() == _player->GetPetGUID()) - { - uint32 feelty = pet->GetPower(POWER_HAPPINESS); - pet->SetPower(POWER_HAPPINESS ,(feelty-50000) > 0 ?(feelty-50000) : 0); - } - - _player->RemovePet((Pet*)pet,PET_SAVE_AS_DELETED); - } - else if (pet->GetGUID() == _player->GetCharmGUID()) - _player->StopCastingCharm(); - } -} - -void WorldSession::HandlePetSpellAutocastOpcode(WorldPacket& recvPacket) -{ - sLog.outDetail("CMSG_PET_SPELL_AUTOCAST"); - uint64 guid; - uint32 spellid; - uint8 state; //1 for on, 0 for off - recvPacket >> guid >> spellid >> state; - - if (!_player->GetGuardianPet() && !_player->GetCharm()) - return; - - if (ObjectAccessor::FindPlayer(guid)) - return; - - Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player,guid); - - if (!pet || (pet != _player->GetGuardianPet() && pet != _player->GetCharm())) - { - sLog.outError("HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName()); - return; - } - - // do not add not learned spells/ passive spells - if (!pet->HasSpell(spellid) || IsAutocastableSpell(spellid)) - return; - - CharmInfo *charmInfo = pet->GetCharmInfo(); - if (!charmInfo) - { - sLog.outError("WorldSession::HandlePetSpellAutocastOpcod: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId()); - return; - } - - if (pet->isPet()) - ((Pet*)pet)->ToggleAutocast(spellid, state); - else - pet->GetCharmInfo()->ToggleCreatureAutocast(spellid, state); - - charmInfo->SetSpellAutocast(spellid,state); -} - -void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) -{ - sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL"); - - uint64 guid; - uint32 spellid; - uint8 cast_count; - uint8 unk_flags; // flags (if 0x02 - some additional data are received) - - recvPacket >> guid >> cast_count >> spellid >> unk_flags; - - sLog.outDebug("WORLD: CMSG_PET_CAST_SPELL, cast_count: %u, spellid %u, unk_flags %u", cast_count, spellid, unk_flags); - - // This opcode is also sent from charmed and possessed units (players and creatures) - if (!_player->GetGuardianPet() && !_player->GetCharm()) - return; - - Unit* caster = ObjectAccessor::GetUnit(*_player, guid); - - if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm())) - { - sLog.outError("HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName()); - return; - } - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid); - if (!spellInfo) - { - sLog.outError("WORLD: unknown PET spell id %i", spellid); - return; - } - - if (spellInfo->StartRecoveryCategory > 0) //Check if spell is affected by GCD - if (caster->GetTypeId() == TYPEID_UNIT && caster->ToCreature()->GetGlobalCooldown() > 0) - { - caster->SendPetCastFail(spellid, SPELL_FAILED_NOT_READY); - return; - } - - // do not cast not learned spells - if (!caster->HasSpell(spellid) || IsPassiveSpell(spellid)) - return; - - SpellCastTargets targets; - if (!targets.read(&recvPacket,caster)) - return; - - caster->clearUnitState(UNIT_STAT_FOLLOW); - - Spell *spell = new Spell(caster, spellInfo, spellid == 33395); // water elemental can cast freeze as triggered - spell->m_cast_count = spellid == 33395 ? 0 : cast_count; // probably pending spell cast - spell->m_targets = targets; - - // TODO: need to check victim? - SpellCastResult result; - if (caster->m_movedPlayer) - result = spell->CheckPetCast(caster->m_movedPlayer->GetSelectedUnit()); - else - result = spell->CheckPetCast(NULL); - if (result == SPELL_CAST_OK) - { - if (caster->GetTypeId() == TYPEID_UNIT) - { - Creature* pet = caster->ToCreature(); - pet->AddCreatureSpellCooldown(spellid); - if (pet->isPet()) - { - Pet* p = (Pet*)pet; - // 10% chance to play special pet attack talk, else growl - // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell - if (p->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) - pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); - else - pet->SendPetAIReaction(guid); - } - } - - spell->prepare(&(spell->m_targets)); - } - else - { - caster->SendPetCastFail(spellid, result); - if (caster->GetTypeId() == TYPEID_PLAYER) - { - if (!caster->ToPlayer()->HasSpellCooldown(spellid)) - GetPlayer()->SendClearCooldown(spellid, caster); - } - else - { - if (!caster->ToCreature()->HasSpellCooldown(spellid)) - GetPlayer()->SendClearCooldown(spellid, caster); - } - - spell->finish(false); - delete spell; - } -} - -void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName *declinedName) -{ - WorldPacket data(SMSG_PET_NAME_INVALID, 4 + name.size() + 1 + 1); - data << uint32(error); - data << name; - if (declinedName) - { - data << uint8(1); - for (uint32 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - data << declinedName->name[i]; - } - else - data << uint8(0); - SendPacket(&data); -} - -void WorldSession::HandlePetLearnTalent(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_PET_LEARN_TALENT"); - - uint64 guid; - uint32 talent_id, requested_rank; - recv_data >> guid >> talent_id >> requested_rank; - - _player->LearnPetTalent(guid, talent_id, requested_rank); - _player->SendTalentsInfoData(true); -} - -void WorldSession::HandleLearnPreviewTalentsPet(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_LEARN_PREVIEW_TALENTS_PET"); - - uint64 guid; - recv_data >> guid; - - uint32 talentsCount; - recv_data >> talentsCount; - - uint32 talentId, talentRank; - - for (uint32 i = 0; i < talentsCount; ++i) - { - recv_data >> talentId >> talentRank; - - _player->LearnPetTalent(guid, talentId, talentRank); - } - - _player->SendTalentsInfoData(true); -} diff --git a/src/server/game/Entities/Player/CharacterHandler.cpp b/src/server/game/Entities/Player/CharacterHandler.cpp deleted file mode 100644 index 416827d73ea..00000000000 --- a/src/server/game/Entities/Player/CharacterHandler.cpp +++ /dev/null @@ -1,1406 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "ObjectAccessor.h" -#include "ObjectMgr.h" -#include "SystemConfig.h" -#include "World.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Auth/md5.h" -#include "Database/DatabaseEnv.h" -#include "Database/DatabaseImpl.h" - -#include "ArenaTeam.h" -#include "Chat.h" -#include "Group.h" -#include "Guild.h" -#include "Language.h" -#include "Log.h" -#include "Opcodes.h" -#include "Player.h" -#include "PlayerDump.h" -#include "SharedDefines.h" -#include "SocialMgr.h" -#include "UpdateMask.h" -#include "Util.h" -#include "ScriptMgr.h" - -class LoginQueryHolder : public SqlQueryHolder -{ - private: - uint32 m_accountId; - uint64 m_guid; - public: - LoginQueryHolder(uint32 accountId, uint64 guid) - : m_accountId(accountId), m_guid(guid) { } - uint64 GetGuid() const { return m_guid; } - uint32 GetAccountId() const { return m_accountId; } - bool Initialize(); -}; - -bool LoginQueryHolder::Initialize() -{ - SetSize(MAX_PLAYER_LOGIN_QUERY); - - bool res = true; - - // NOTE: all fields in `characters` must be read to prevent lost character data at next save in case wrong DB structure. - // !!! NOTE: including unused `zone`,`online` - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags," - "position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost," - "resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty," - "arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, todayKills, yesterdayKills, chosenTitle, knownCurrencies, watchedFaction, drunk," - "health, power1, power2, power3, power4, power5, power6, power7, instance_id, speccount, activespec, exploredZones, equipmentCache, ammoId, knownTitles, actionBars FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT guid FROM group_member WHERE memberGuid =%u", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_mask,recalculate_mask,stackcount,amount0,amount1,amount2,base_amount0,base_amount1,base_amount2,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLS, "SELECT spell,active,disabled FROM character_spell WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS, "SELECT quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4 FROM character_queststatus WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS,"SELECT quest,time FROM character_queststatus_daily WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADWEKLYQUESTSTATUS,"SELECT quest FROM character_queststatus_weekly WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADREPUTATION, "SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, "SELECT data,text,bag,slot,item,item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag,slot", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, "SELECT a.button,a.action,a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activespec AND a.guid = '%u' ORDER BY button", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = '%u' AND (checked & 1)=0 AND deliver_time <= '" UI64FMTD "'", GUID_LOPART(m_guid),(uint64)time(NULL)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = '%u' AND (checked & 1)=0", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSOCIALLIST, "SELECT friend,flags,note FROM character_social WHERE guid = '%u' LIMIT 255", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADHOMEBIND, "SELECT map,zone,position_x,position_y,position_z FROM character_homebind WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS, "SELECT spell,item,time FROM character_spell_cooldown WHERE guid = '%u'", GUID_LOPART(m_guid)); - if (sWorld.getConfig(CONFIG_DECLINED_NAMES_USED)) - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = '%u'",GUID_LOPART(m_guid)); - // in other case still be dummy query - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGUILD, "SELECT guildid,rank FROM guild_member WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADARENAINFO, "SELECT arenateamid, played_week, played_season, wons_season, personal_rating FROM arena_team_member WHERE guid='%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS, "SELECT achievement, date FROM character_achievement WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS,"SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, item0, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE guid = '%u' ORDER BY setindex", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBGDATA, "SELECT instance_id, team, join_x, join_y, join_z, join_o, join_map, taxi_start, taxi_end, mount_spell FROM character_battleground_data WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGLYPHS, "SELECT spec, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6 FROM character_glyphs WHERE guid='%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADTALENTS, "SELECT spell, spec FROM character_talent WHERE guid='%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA, "SELECT type, time, data FROM character_account_data WHERE guid='%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADRANDOMBG, "SELECT guid FROM character_battleground_random WHERE guid = '%u'", GUID_LOPART(m_guid)); - - return res; -} - -// don't call WorldSession directly -// it may get deleted before the query callbacks get executed -// instead pass an account id to this handler -class CharacterHandler -{ - - public: - void HandleCharEnumCallback(QueryResult_AutoPtr result, uint32 account) - { - WorldSession * session = sWorld.FindSession(account); - if (!session) - return; - session->HandleCharEnum(result); - } - void HandlePlayerLoginCallback(QueryResult_AutoPtr /*dummy*/, SqlQueryHolder * holder) - { - if (!holder) return; - WorldSession *session = sWorld.FindSession(((LoginQueryHolder*)holder)->GetAccountId()); - if (!session) - { - delete holder; - return; - } - session->HandlePlayerLogin((LoginQueryHolder*)holder); - } -} chrHandler; - -void WorldSession::HandleCharEnum(QueryResult_AutoPtr result) -{ - WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size - - uint8 num = 0; - - data << num; - - if (result) - { - do - { - uint32 guidlow = (*result)[0].GetUInt32(); - sLog.outDetail("Loading char guid %u from account %u.",guidlow,GetAccountId()); - if (Player::BuildEnumData(result, &data)) - ++num; - } - while (result->NextRow()); - } - - data.put(0, num); - - SendPacket(&data); -} - -void WorldSession::HandleCharEnumOpcode(WorldPacket & /*recv_data*/) -{ - /// get all the data necessary for loading all characters (along with their pets) on the account - CharacterDatabase.AsyncPQuery(&chrHandler, &CharacterHandler::HandleCharEnumCallback, GetAccountId(), - !sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) ? - // ------- Query Without Declined Names -------- - // 0 1 2 3 4 5 6 7 - "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, " - // 8 9 10 11 12 13 14 - "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, " - // 15 16 17 18 19 - "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.equipmentCache " - "FROM characters LEFT JOIN character_pet ON characters.guid=character_pet.owner AND character_pet.slot='%u' " - "LEFT JOIN guild_member ON characters.guid = guild_member.guid " - "WHERE characters.account = '%u' ORDER BY characters.guid" - : - // --------- Query With Declined Names --------- - // 0 1 2 3 4 5 6 7 - "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, " - // 8 9 10 11 12 13 14 - "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, " - // 15 16 17 18 19 20 - "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.equipmentCache, character_declinedname.genitive " - "FROM characters LEFT JOIN character_pet ON characters.guid = character_pet.owner AND character_pet.slot='%u' " - "LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid " - "LEFT JOIN guild_member ON characters.guid = guild_member.guid " - "WHERE characters.account = '%u' ORDER BY characters.guid", - PET_SAVE_AS_CURRENT,GetAccountId()); -} - -void WorldSession::HandleCharCreateOpcode(WorldPacket & recv_data) -{ - std::string name; - uint8 race_,class_; - - recv_data >> name; - - recv_data >> race_; - recv_data >> class_; - - WorldPacket data(SMSG_CHAR_CREATE, 1); // returned with diff.values in all cases - - if (GetSecurity() == SEC_PLAYER) - { - if (uint32 mask = sWorld.getConfig(CONFIG_CHARACTERS_CREATING_DISABLED)) - { - bool disabled = false; - - uint32 team = Player::TeamForRace(race_); - switch(team) - { - case ALLIANCE: disabled = mask & (1<<0); break; - case HORDE: disabled = mask & (1<<1); break; - } - - if (disabled) - { - data << (uint8)CHAR_CREATE_DISABLED; - SendPacket(&data); - return; - } - } - } - - ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(class_); - ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race_); - - if (!classEntry || !raceEntry) - { - data << (uint8)CHAR_CREATE_FAILED; - SendPacket(&data); - sLog.outError("Class: %u or Race %u not found in DBC (Wrong DBC files?) or Cheater?", class_, race_); - return; - } - - // prevent character creating Expansion race without Expansion account - if (raceEntry->expansion > Expansion()) - { - data << (uint8)CHAR_CREATE_EXPANSION; - sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u race (%u)",Expansion(),GetAccountId(),raceEntry->expansion,race_); - SendPacket(&data); - return; - } - - // prevent character creating Expansion class without Expansion account - if (classEntry->expansion > Expansion()) - { - data << (uint8)CHAR_CREATE_EXPANSION_CLASS; - sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u class (%u)",Expansion(),GetAccountId(),classEntry->expansion,class_); - SendPacket(&data); - return; - } - - // prevent character creating with invalid name - if (!normalizePlayerName(name)) - { - data << (uint8)CHAR_NAME_NO_NAME; - SendPacket(&data); - sLog.outError("Account:[%d] but tried to Create character with empty [name] ",GetAccountId()); - return; - } - - // check name limitations - uint8 res = ObjectMgr::CheckPlayerName(name,true); - if (res != CHAR_NAME_SUCCESS) - { - data << uint8(res); - SendPacket(&data); - return; - } - - if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(name)) - { - data << (uint8)CHAR_NAME_RESERVED; - SendPacket(&data); - return; - } - - if (objmgr.GetPlayerGUIDByName(name)) - { - data << (uint8)CHAR_CREATE_NAME_IN_USE; - SendPacket(&data); - return; - } - - QueryResult_AutoPtr resultacct = LoginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'", GetAccountId()); - if (resultacct) - { - Field *fields=resultacct->Fetch(); - uint32 acctcharcount = fields[0].GetUInt32(); - - if (acctcharcount >= sWorld.getConfig(CONFIG_CHARACTERS_PER_ACCOUNT)) - { - data << (uint8)CHAR_CREATE_ACCOUNT_LIMIT; - SendPacket(&data); - return; - } - } - - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE account = '%d'", GetAccountId()); - uint8 charcount = 0; - if (result) - { - Field *fields=result->Fetch(); - charcount = fields[0].GetUInt8(); - - if (charcount >= sWorld.getConfig(CONFIG_CHARACTERS_PER_REALM)) - { - data << (uint8)CHAR_CREATE_SERVER_LIMIT; - SendPacket(&data); - return; - } - } - - // speedup check for heroic class disabled case - uint32 heroic_free_slots = sWorld.getConfig(CONFIG_HEROIC_CHARACTERS_PER_REALM); - if (heroic_free_slots == 0 && GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT) - { - data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT; - SendPacket(&data); - return; - } - - // speedup check for heroic class disabled case - uint32 req_level_for_heroic = sWorld.getConfig(CONFIG_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING); - if (GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && req_level_for_heroic > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT; - SendPacket(&data); - return; - } - - bool AllowTwoSideAccounts = !sWorld.IsPvPRealm() || sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || GetSecurity() > SEC_PLAYER; - uint32 skipCinematics = sWorld.getConfig(CONFIG_SKIP_CINEMATICS); - - bool have_same_race = false; - - // if 0 then allowed creating without any characters - bool have_req_level_for_heroic = (req_level_for_heroic == 0); - - if (!AllowTwoSideAccounts || skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT) - { - QueryResult_AutoPtr result2 = CharacterDatabase.PQuery("SELECT level,race,class FROM characters WHERE account = '%u' %s", - GetAccountId(), (skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT) ? "" : "LIMIT 1"); - if (result2) - { - uint32 team_= Player::TeamForRace(race_); - - Field* field = result2->Fetch(); - uint8 acc_race = field[1].GetUInt32(); - - if (GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT) - { - uint8 acc_class = field[2].GetUInt32(); - if (acc_class == CLASS_DEATH_KNIGHT) - { - if (heroic_free_slots > 0) - --heroic_free_slots; - - if (heroic_free_slots == 0) - { - data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT; - SendPacket(&data); - return; - } - } - - if (!have_req_level_for_heroic) - { - uint32 acc_level = field[0].GetUInt32(); - if (acc_level >= req_level_for_heroic) - have_req_level_for_heroic = true; - } - } - - // need to check team only for first character - // TODO: what to if account already has characters of both races? - if (!AllowTwoSideAccounts) - { - uint32 acc_team=0; - if (acc_race > 0) - acc_team = Player::TeamForRace(acc_race); - - if (acc_team != team_) - { - data << (uint8)CHAR_CREATE_PVP_TEAMS_VIOLATION; - SendPacket(&data); - return; - } - } - - // search same race for cinematic or same class if need - // TODO: check if cinematic already shown? (already logged in?; cinematic field) - while ((skipCinematics == 1 && !have_same_race) || class_ == CLASS_DEATH_KNIGHT) - { - if (!result2->NextRow()) - break; - - field = result2->Fetch(); - acc_race = field[1].GetUInt32(); - - if (!have_same_race) - have_same_race = race_ == acc_race; - - if (GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT) - { - uint8 acc_class = field[2].GetUInt32(); - if (acc_class == CLASS_DEATH_KNIGHT) - { - if (heroic_free_slots > 0) - --heroic_free_slots; - - if (heroic_free_slots == 0) - { - data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT; - SendPacket(&data); - return; - } - } - - if (!have_req_level_for_heroic) - { - uint32 acc_level = field[0].GetUInt32(); - if (acc_level >= req_level_for_heroic) - have_req_level_for_heroic = true; - } - } - } - } - } - - if (GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && !have_req_level_for_heroic) - { - data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT; - SendPacket(&data); - return; - } - - // extract other data required for player creating - uint8 gender, skin, face, hairStyle, hairColor, facialHair, outfitId; - recv_data >> gender >> skin >> face; - recv_data >> hairStyle >> hairColor >> facialHair >> outfitId; - - if (recv_data.rpos() < recv_data.wpos()) - { - uint8 unk; - recv_data >> unk; - sLog.outDebug("Character creation %s (account %u) has unhandled tail data: [%u]", name.c_str(), GetAccountId(), unk); - } - - Player * pNewChar = new Player(this); - if (!pNewChar->Create(objmgr.GenerateLowGuid(HIGHGUID_PLAYER), name, race_, class_, gender, skin, face, hairStyle, hairColor, facialHair, outfitId)) - { - // Player not create (race/class problem?) - pNewChar->CleanupsBeforeDelete(); - delete pNewChar; - - data << (uint8)CHAR_CREATE_ERROR; - SendPacket(&data); - - return; - } - - if ((have_same_race && skipCinematics == 1) || skipCinematics == 2) - pNewChar->setCinematic(1); // not show intro - - pNewChar->SetAtLoginFlag(AT_LOGIN_FIRST); // First login - - // Player created, save it now - pNewChar->SaveToDB(); - charcount+=1; - - LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", GetAccountId(), realmID); - LoginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charcount, GetAccountId(), realmID); - - pNewChar->CleanupsBeforeDelete(); - - data << (uint8)CHAR_CREATE_SUCCESS; - SendPacket(&data); - - std::string IP_str = GetRemoteAddress(); - sLog.outBasic("Account: %d (IP: %s) Create Character:[%s] (GUID: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), pNewChar->GetGUIDLow()); - sLog.outChar("Account: %d (IP: %s) Create Character:[%s] (GUID: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), pNewChar->GetGUIDLow()); - delete pNewChar; // created only to call SaveToDB() - -} - -void WorldSession::HandleCharDeleteOpcode(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - - // can't delete loaded character - if (objmgr.GetPlayer(guid)) - return; - - uint32 accountId = 0; - std::string name; - - // is guild leader - if (objmgr.GetGuildByLeader(guid)) - { - WorldPacket data(SMSG_CHAR_DELETE, 1); - data << (uint8)CHAR_DELETE_FAILED_GUILD_LEADER; - SendPacket(&data); - return; - } - - // is arena team captain - if (objmgr.GetArenaTeamByCaptain(guid)) - { - WorldPacket data(SMSG_CHAR_DELETE, 1); - data << (uint8)CHAR_DELETE_FAILED_ARENA_CAPTAIN; - SendPacket(&data); - return; - } - - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT account,name FROM characters WHERE guid='%u'", GUID_LOPART(guid)); - if (result) - { - Field *fields = result->Fetch(); - accountId = fields[0].GetUInt32(); - name = fields[1].GetCppString(); - } - - // prevent deleting other players' characters using cheating tools - if (accountId != GetAccountId()) - return; - - std::string IP_str = GetRemoteAddress(); - sLog.outDetail("Account: %d (IP: %s) Delete Character:[%s] (GUID: %u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid)); - sLog.outChar("Account: %d (IP: %s) Delete Character:[%s] (GUID: %u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid)); - - if (sLog.IsOutCharDump()) // optimize GetPlayerDump call - { - std::string dump = PlayerDumpWriter().GetDump(GUID_LOPART(guid)); - sLog.outCharDump(dump.c_str(),GetAccountId(),GUID_LOPART(guid),name.c_str()); - } - - Player::DeleteFromDB(guid, GetAccountId()); - - WorldPacket data(SMSG_CHAR_DELETE, 1); - data << (uint8)CHAR_DELETE_SUCCESS; - SendPacket(&data); -} - -void WorldSession::HandlePlayerLoginOpcode(WorldPacket & recv_data) -{ - if (PlayerLoading() || GetPlayer() != NULL) - { - sLog.outError("Player tryes to login again, AccountId = %d",GetAccountId()); - return; - } - - m_playerLoading = true; - uint64 playerGuid = 0; - - DEBUG_LOG("WORLD: Recvd Player Logon Message"); - - recv_data >> playerGuid; - - LoginQueryHolder *holder = new LoginQueryHolder(GetAccountId(), playerGuid); - if (!holder->Initialize()) - { - delete holder; // delete all unprocessed queries - m_playerLoading = false; - return; - } - - CharacterDatabase.DelayQueryHolder(&chrHandler, &CharacterHandler::HandlePlayerLoginCallback, holder); -} - -void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) -{ - uint64 playerGuid = holder->GetGuid(); - - Player* pCurrChar = new Player(this); - // for send server info and strings (config) - ChatHandler chH = ChatHandler(pCurrChar); - - // "GetAccountId() == db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools) - if (!pCurrChar->LoadFromDB(GUID_LOPART(playerGuid), holder)) - { - KickPlayer(); // disconnect client, player no set to session and it will not deleted or saved at kick - delete pCurrChar; // delete it manually - delete holder; // delete all unprocessed queries - m_playerLoading = false; - return; - } - - pCurrChar->GetMotionMaster()->Initialize(); - - SetPlayer(pCurrChar); - - pCurrChar->SendDungeonDifficulty(false); - - WorldPacket data(SMSG_LOGIN_VERIFY_WORLD, 20); - data << pCurrChar->GetMapId(); - data << pCurrChar->GetPositionX(); - data << pCurrChar->GetPositionY(); - data << pCurrChar->GetPositionZ(); - data << pCurrChar->GetOrientation(); - SendPacket(&data); - - // load player specific part before send times - LoadAccountData(holder->GetResult(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA),PER_CHARACTER_CACHE_MASK); - SendAccountDataTimes(PER_CHARACTER_CACHE_MASK); - - data.Initialize(SMSG_FEATURE_SYSTEM_STATUS, 2); // added in 2.2.0 - data << uint8(2); // unknown value - data << uint8(0); // enable(1)/disable(0) voice chat interface in client - SendPacket(&data); - - // Send MOTD - { - data.Initialize(SMSG_MOTD, 50); // new in 2.0.1 - data << (uint32)0; - - uint32 linecount=0; - std::string str_motd = sWorld.GetMotd(); - std::string::size_type pos, nextpos; - - pos = 0; - while ((nextpos= str_motd.find('@',pos)) != std::string::npos) - { - if (nextpos != pos) - { - data << str_motd.substr(pos,nextpos-pos); - ++linecount; - } - pos = nextpos+1; - } - - if (posGetGUIDLow()); - QueryResult_AutoPtr resultGuild = holder->GetResult(PLAYER_LOGIN_QUERY_LOADGUILD); - - if (resultGuild) - { - Field *fields = resultGuild->Fetch(); - pCurrChar->SetInGuild(fields[0].GetUInt32()); - pCurrChar->SetRank(fields[1].GetUInt32()); - } - else if (pCurrChar->GetGuildId()) // clear guild related fields in case wrong data about non existed membership - { - pCurrChar->SetInGuild(0); - pCurrChar->SetRank(0); - } - - if (pCurrChar->GetGuildId() != 0) - { - Guild* guild = objmgr.GetGuildById(pCurrChar->GetGuildId()); - if (guild) - { - data.Initialize(SMSG_GUILD_EVENT, (1+1+guild->GetMOTD().size()+1)); - data << uint8(GE_MOTD); - data << uint8(1); - data << guild->GetMOTD(); - SendPacket(&data); - DEBUG_LOG("WORLD: Sent guild-motd (SMSG_GUILD_EVENT)"); - - guild->DisplayGuildBankTabsInfo(this); - - guild->BroadcastEvent(GE_SIGNED_ON, pCurrChar->GetGUID(), 1, pCurrChar->GetName(), "", ""); - } - else - { - // remove wrong guild data - sLog.outError("Player %s (GUID: %u) marked as member not existed guild (id: %u), removing guild membership for player.",pCurrChar->GetName(),pCurrChar->GetGUIDLow(),pCurrChar->GetGuildId()); - pCurrChar->SetInGuild(0); - } - } - - data.Initialize(SMSG_LEARNED_DANCE_MOVES, 4+4); - data << uint32(0); - data << uint32(0); - SendPacket(&data); - - pCurrChar->SendInitialPacketsBeforeAddToMap(); - - //Show cinematic at the first time that player login - if (!pCurrChar->getCinematic()) - { - pCurrChar->setCinematic(1); - - if (ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(pCurrChar->getClass())) - { - if (cEntry->CinematicSequence) - pCurrChar->SendCinematicStart(cEntry->CinematicSequence); - else if (ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(pCurrChar->getRace())) - pCurrChar->SendCinematicStart(rEntry->CinematicSequence); - - // send new char string if not empty - if (!sWorld.GetNewCharString().empty()) - chH.PSendSysMessage(sWorld.GetNewCharString().c_str()); - } - } - - if (!pCurrChar->GetMap()->Add(pCurrChar) || !pCurrChar->CheckInstanceLoginValid()) - { - AreaTrigger const* at = objmgr.GetGoBackTrigger(pCurrChar->GetMapId()); - if (at) - pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation()); - else - pCurrChar->TeleportTo(pCurrChar->m_homebindMapId, pCurrChar->m_homebindX, pCurrChar->m_homebindY, pCurrChar->m_homebindZ, pCurrChar->GetOrientation()); - } - - ObjectAccessor::Instance().AddObject(pCurrChar); - //sLog.outDebug("Player %s added to Map.",pCurrChar->GetName()); - - pCurrChar->SendInitialPacketsAfterAddToMap(); - - CharacterDatabase.PExecute("UPDATE characters SET online = 1 WHERE guid = '%u'", pCurrChar->GetGUIDLow()); - LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = '%u'", GetAccountId()); - pCurrChar->SetInGameTime(getMSTime()); - - // announce group about member online (must be after add to player list to receive announce to self) - if (Group *group = pCurrChar->GetGroup()) - { - //pCurrChar->groupInfo.group->SendInit(this); // useless - group->SendUpdate(); - group->ResetMaxEnchantingLevel(); - } - - // friend status - sSocialMgr.SendFriendStatus(pCurrChar, FRIEND_ONLINE, pCurrChar->GetGUIDLow(), true); - - // Place character in world (and load zone) before some object loading - pCurrChar->LoadCorpse(); - - // setting Ghost+speed if dead - if (pCurrChar->m_deathState != ALIVE) - { - // not blizz like, we must correctly save and load player instead... - if (pCurrChar->getRace() == RACE_NIGHTELF) - pCurrChar->CastSpell(pCurrChar, 20584, true, 0);// auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form) - pCurrChar->CastSpell(pCurrChar, 8326, true, 0); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?) - - pCurrChar->SetMovement(MOVE_WATER_WALK); - } - - pCurrChar->ContinueTaxiFlight(); - - // reset for all pets before pet loading - if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) - Pet::resetTalentsForAllPetsOf(pCurrChar); - - // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned) - pCurrChar->LoadPet(); - - // Set FFA PvP for non GM in non-rest mode - if (sWorld.IsFFAPvPRealm() && !pCurrChar->isGameMaster() && !pCurrChar->HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_RESTING)) - pCurrChar->SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); - - if (pCurrChar->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP)) - pCurrChar->SetContestedPvP(); - - // Apply at_login requests - if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_SPELLS)) - { - pCurrChar->resetSpells(); - SendNotification(LANG_RESET_SPELLS); - } - - if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS)) - { - pCurrChar->resetTalents(true); - pCurrChar->SendTalentsInfoData(false); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state - SendNotification(LANG_RESET_TALENTS); - } - - if (pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST)) - pCurrChar->RemoveAtLoginFlag(AT_LOGIN_FIRST); - - // show time before shutdown if shutdown planned. - if (sWorld.IsShutdowning()) - sWorld.ShutdownMsg(true,pCurrChar); - - if (sWorld.getConfig(CONFIG_ALL_TAXI_PATHS)) - pCurrChar->SetTaxiCheater(true); - - if (pCurrChar->isGameMaster()) - SendNotification(LANG_GM_ON); - - std::string IP_str = GetRemoteAddress(); - sLog.outChar("Account: %d (IP: %s) Login Character:[%s] (GUID: %u)", - GetAccountId(),IP_str.c_str(),pCurrChar->GetName() ,pCurrChar->GetGUIDLow()); - - if (!pCurrChar->IsStandState() && !pCurrChar->hasUnitState(UNIT_STAT_STUNNED)) - pCurrChar->SetStandState(UNIT_STAND_STATE_STAND); - - m_playerLoading = false; - - //Hook for OnLogin Event - sScriptMgr.OnLogin(pCurrChar); - delete holder; -} - -void WorldSession::HandleSetFactionAtWar(WorldPacket & recv_data) -{ - DEBUG_LOG("WORLD: Received CMSG_SET_FACTION_ATWAR"); - - uint32 repListID; - uint8 flag; - - recv_data >> repListID; - recv_data >> flag; - - GetPlayer()->GetReputationMgr().SetAtWar(repListID,flag); -} - -//I think this function is never used :/ I dunno, but i guess this opcode not exists -void WorldSession::HandleSetFactionCheat(WorldPacket & /*recv_data*/) -{ - sLog.outError("WORLD SESSION: HandleSetFactionCheat, not expected call, please report."); - /* - uint32 FactionID; - uint32 Standing; - - recv_data >> FactionID; - recv_data >> Standing; - - std::list::iterator itr; - - for (itr = GetPlayer()->factions.begin(); itr != GetPlayer()->factions.end(); ++itr) - { - if (itr->ReputationListID == FactionID) - { - itr->Standing += Standing; - itr->Flags = (itr->Flags | 1); - break; - } - } - */ - GetPlayer()->GetReputationMgr().SendStates(); -} - -void WorldSession::HandleMeetingStoneInfo(WorldPacket & /*recv_data*/) -{ - DEBUG_LOG("WORLD: Received CMSG_MEETING_STONE_INFO"); - - //SendLfgUpdate(0, 0, 0); -} - -void WorldSession::HandleTutorialFlag(WorldPacket & recv_data) -{ - uint32 iFlag; - recv_data >> iFlag; - - uint32 wInt = (iFlag / 32); - if (wInt >= 8) - { - //sLog.outError("CHEATER? Account:[%d] Guid[%u] tried to send wrong CMSG_TUTORIAL_FLAG", GetAccountId(),GetGUID()); - return; - } - uint32 rInt = (iFlag % 32); - - uint32 tutflag = GetTutorialInt(wInt); - tutflag |= (1 << rInt); - SetTutorialInt(wInt, tutflag); - - //sLog.outDebug("Received Tutorial Flag Set {%u}.", iFlag); -} - -void WorldSession::HandleTutorialClear(WorldPacket & /*recv_data*/) -{ - for (int i = 0; i < 8; ++i) - SetTutorialInt(i, 0xFFFFFFFF); -} - -void WorldSession::HandleTutorialReset(WorldPacket & /*recv_data*/) -{ - for (int i = 0; i < 8; ++i) - SetTutorialInt(i, 0x00000000); -} - -void WorldSession::HandleSetWatchedFactionOpcode(WorldPacket & recv_data) -{ - DEBUG_LOG("WORLD: Received CMSG_SET_WATCHED_FACTION"); - uint32 fact; - recv_data >> fact; - GetPlayer()->SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fact); -} - -void WorldSession::HandleSetFactionInactiveOpcode(WorldPacket & recv_data) -{ - DEBUG_LOG("WORLD: Received CMSG_SET_FACTION_INACTIVE"); - uint32 replistid; - uint8 inactive; - recv_data >> replistid >> inactive; - - _player->GetReputationMgr().SetInactive(replistid, inactive); -} - -void WorldSession::HandleShowingHelmOpcode(WorldPacket & /*recv_data*/) -{ - DEBUG_LOG("CMSG_SHOWING_HELM for %s", _player->GetName()); - _player->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM); -} - -void WorldSession::HandleShowingCloakOpcode(WorldPacket & /*recv_data*/) -{ - DEBUG_LOG("CMSG_SHOWING_CLOAK for %s", _player->GetName()); - _player->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK); -} - -void WorldSession::HandleCharRenameOpcode(WorldPacket& recv_data) -{ - uint64 guid; - std::string newname; - - recv_data >> guid; - recv_data >> newname; - - // prevent character rename to invalid name - if (!normalizePlayerName(newname)) - { - WorldPacket data(SMSG_CHAR_RENAME, 1); - data << uint8(CHAR_NAME_NO_NAME); - SendPacket(&data); - return; - } - - uint8 res = ObjectMgr::CheckPlayerName(newname,true); - if (res != CHAR_NAME_SUCCESS) - { - WorldPacket data(SMSG_CHAR_RENAME, 1); - data << uint8(res); - SendPacket(&data); - return; - } - - // check name limitations - if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname)) - { - WorldPacket data(SMSG_CHAR_RENAME, 1); - data << uint8(CHAR_NAME_RESERVED); - SendPacket(&data); - return; - } - - std::string escaped_newname = newname; - CharacterDatabase.escape_string(escaped_newname); - - // make sure that the character belongs to the current account, that rename at login is enabled - // and that there is no character with the desired new name - CharacterDatabase.AsyncPQuery(&WorldSession::HandleChangePlayerNameOpcodeCallBack, - GetAccountId(), newname, - "SELECT guid, name FROM characters WHERE guid = %d AND account = %d AND (at_login & %d) = %d AND NOT EXISTS (SELECT NULL FROM characters WHERE name = '%s')", - GUID_LOPART(guid), GetAccountId(), AT_LOGIN_RENAME, AT_LOGIN_RENAME, escaped_newname.c_str() -); -} - -void WorldSession::HandleChangePlayerNameOpcodeCallBack(QueryResult_AutoPtr result, uint32 accountId, std::string newname) -{ - WorldSession * session = sWorld.FindSession(accountId); - if (!session) - return; - - if (!result) - { - WorldPacket data(SMSG_CHAR_RENAME, 1); - data << uint8(CHAR_CREATE_ERROR); - session->SendPacket(&data); - return; - } - - uint32 guidLow = result->Fetch()[0].GetUInt32(); - uint64 guid = MAKE_NEW_GUID(guidLow, 0, HIGHGUID_PLAYER); - std::string oldname = result->Fetch()[1].GetCppString(); - - CharacterDatabase.PExecute("UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'", newname.c_str(), uint32(AT_LOGIN_RENAME), guidLow); - CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid ='%u'", guidLow); - - sLog.outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s", session->GetAccountId(), session->GetRemoteAddress().c_str(), oldname.c_str(), guidLow, newname.c_str()); - - WorldPacket data(SMSG_CHAR_RENAME, 1+8+(newname.size()+1)); - data << uint8(RESPONSE_SUCCESS); - data << uint64(guid); - data << newname; - session->SendPacket(&data); -} - -void WorldSession::HandleSetPlayerDeclinedNames(WorldPacket& recv_data) -{ - uint64 guid; - - recv_data >> guid; - - // not accept declined names for unsupported languages - std::string name; - if (!objmgr.GetPlayerNameByGUID(guid, name)) - { - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); - data << uint32(1); - data << uint64(guid); - SendPacket(&data); - return; - } - - std::wstring wname; - if (!Utf8toWStr(name, wname)) - { - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); - data << uint32(1); - data << uint64(guid); - SendPacket(&data); - return; - } - - if (!isCyrillicCharacter(wname[0])) // name already stored as only single alphabet using - { - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); - data << uint32(1); - data << uint64(guid); - SendPacket(&data); - return; - } - - std::string name2; - DeclinedName declinedname; - - recv_data >> name2; - - if (name2 != name) // character have different name - { - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); - data << uint32(1); - data << uint64(guid); - SendPacket(&data); - return; - } - - for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - { - recv_data >> declinedname.name[i]; - if (!normalizePlayerName(declinedname.name[i])) - { - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); - data << uint32(1); - data << uint64(guid); - SendPacket(&data); - return; - } - } - - if (!ObjectMgr::CheckDeclinedNames(GetMainPartOfName(wname, 0), declinedname)) - { - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); - data << uint32(1); - data << uint64(guid); - SendPacket(&data); - return; - } - - for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - CharacterDatabase.escape_string(declinedname.name[i]); - - CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid = '%u'", GUID_LOPART(guid)); - CharacterDatabase.PExecute("INSERT INTO character_declinedname (guid, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u','%s','%s','%s','%s','%s')", - GUID_LOPART(guid), declinedname.name[0].c_str(), declinedname.name[1].c_str(), declinedname.name[2].c_str(), declinedname.name[3].c_str(), declinedname.name[4].c_str()); - CharacterDatabase.CommitTransaction(); - - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); - data << uint32(0); // OK - data << uint64(guid); - SendPacket(&data); -} - -void WorldSession::HandleAlterAppearance(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_ALTER_APPEARANCE"); - - uint32 Hair, Color, FacialHair, SkinColor; - recv_data >> Hair >> Color >> FacialHair >> SkinColor; - - BarberShopStyleEntry const* bs_hair = sBarberShopStyleStore.LookupEntry(Hair); - - if (!bs_hair || bs_hair->type != 0 || bs_hair->race != _player->getRace() || bs_hair->gender != _player->getGender()) - return; - - BarberShopStyleEntry const* bs_facialHair = sBarberShopStyleStore.LookupEntry(FacialHair); - - if (!bs_facialHair || bs_facialHair->type != 2 || bs_facialHair->race != _player->getRace() || bs_facialHair->gender != _player->getGender()) - return; - - BarberShopStyleEntry const* bs_skinColor = sBarberShopStyleStore.LookupEntry(SkinColor); - - if (bs_skinColor && (bs_skinColor->type != 3 || bs_skinColor->race != _player->getRace() || bs_skinColor->gender != _player->getGender())) - return; - - uint32 Cost = _player->GetBarberShopCost(bs_hair->hair_id, Color, bs_facialHair->hair_id, bs_skinColor); - - // 0 - ok - // 1,3 - not enough money - // 2 - you have to seat on barber chair - if (_player->GetMoney() < Cost) - { - WorldPacket data(SMSG_BARBER_SHOP_RESULT, 4); - data << uint32(1); // no money - SendPacket(&data); - return; - } - else - { - WorldPacket data(SMSG_BARBER_SHOP_RESULT, 4); - data << uint32(0); // ok - SendPacket(&data); - } - - _player->ModifyMoney(-int32(Cost)); // it isn't free - _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER, Cost); - - _player->SetByteValue(PLAYER_BYTES, 2, uint8(bs_hair->hair_id)); - _player->SetByteValue(PLAYER_BYTES, 3, uint8(Color)); - _player->SetByteValue(PLAYER_BYTES_2, 0, uint8(bs_facialHair->hair_id)); - if (bs_skinColor) - _player->SetByteValue(PLAYER_BYTES, 0, uint8(bs_skinColor->hair_id)); - - _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP, 1); - - _player->SetStandState(0); // stand up -} - -void WorldSession::HandleRemoveGlyph(WorldPacket & recv_data) -{ - uint32 slot; - recv_data >> slot; - - if (slot >= MAX_GLYPH_SLOT_INDEX) - { - sLog.outDebug("Client sent wrong glyph slot number in opcode CMSG_REMOVE_GLYPH %u", slot); - return; - } - - if (uint32 glyph = _player->GetGlyph(slot)) - { - if (GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph)) - { - _player->RemoveAurasDueToSpell(gp->SpellId); - _player->SetGlyph(slot, 0); - _player->SendTalentsInfoData(false); - } - } -} - -void WorldSession::HandleCharCustomize(WorldPacket& recv_data) -{ - uint64 guid; - std::string newname; - - recv_data >> guid; - recv_data >> newname; - - uint8 gender, skin, face, hairStyle, hairColor, facialHair; - recv_data >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face; - - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT at_login FROM characters WHERE guid ='%u'", GUID_LOPART(guid)); - if (!result) - { - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); - data << uint8(CHAR_CREATE_ERROR); - SendPacket(&data); - return; - } - - Field *fields = result->Fetch(); - uint32 at_loginFlags = fields[0].GetUInt32(); - - if (!(at_loginFlags & AT_LOGIN_CUSTOMIZE)) - { - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); - data << uint8(CHAR_CREATE_ERROR); - SendPacket(&data); - return; - } - - // prevent character rename to invalid name - if (!normalizePlayerName(newname)) - { - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); - data << uint8(CHAR_NAME_NO_NAME); - SendPacket(&data); - return; - } - - uint8 res = ObjectMgr::CheckPlayerName(newname,true); - if (res != CHAR_NAME_SUCCESS) - { - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); - data << uint8(res); - SendPacket(&data); - return; - } - - // check name limitations - if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname)) - { - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); - data << uint8(CHAR_NAME_RESERVED); - SendPacket(&data); - return; - } - - // character with this name already exist - if (uint64 newguid = objmgr.GetPlayerGUIDByName(newname)) - { - if (newguid != guid) - { - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); - data << uint8(CHAR_CREATE_NAME_IN_USE); - SendPacket(&data); - return; - } - } - - CharacterDatabase.escape_string(newname); - if (QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT name FROM characters WHERE guid ='%u'", GUID_LOPART(guid))) - { - std::string oldname = result->Fetch()[0].GetCppString(); - std::string IP_str = GetRemoteAddress(); - sLog.outChar("Account: %d (IP: %s), Character[%s] (guid:%u) Customized to: %s", GetAccountId(), IP_str.c_str(), oldname.c_str(), GUID_LOPART(guid), newname.c_str()); - } - Player::Customize(guid, gender, skin, face, hairStyle, hairColor, facialHair); - CharacterDatabase.PExecute("UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'", newname.c_str(), uint32(AT_LOGIN_CUSTOMIZE), GUID_LOPART(guid)); - CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid ='%u'", GUID_LOPART(guid)); - - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1+8+(newname.size()+1)+6); - data << uint8(RESPONSE_SUCCESS); - data << uint64(guid); - data << newname; - data << uint8(gender); - data << uint8(skin); - data << uint8(face); - data << uint8(hairStyle); - data << uint8(hairColor); - data << uint8(facialHair); - SendPacket(&data); -} - -void WorldSession::HandleEquipmentSetSave(WorldPacket &recv_data) -{ - sLog.outDebug("CMSG_EQUIPMENT_SET_SAVE"); - - uint64 setGuid; - if (!recv_data.readPackGUID(setGuid)) - return; - - uint32 index; - recv_data >> index; - if (index >= MAX_EQUIPMENT_SET_INDEX) // client set slots amount - return; - - std::string name; - recv_data >> name; - - std::string iconName; - recv_data >> iconName; - - EquipmentSet eqSet; - - eqSet.Guid = setGuid; - eqSet.Name = name; - eqSet.IconName = iconName; - eqSet.state = EQUIPMENT_SET_NEW; - - for (uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) - { - uint64 itemGuid; - if (!recv_data.readPackGUID(itemGuid)) - return; - - Item *item = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); - - if (!item && itemGuid) // cheating check 1 - return; - - if (item && item->GetGUID() != itemGuid) // cheating check 2 - return; - - eqSet.Items[i] = GUID_LOPART(itemGuid); - } - - _player->SetEquipmentSet(index, eqSet); -} - -void WorldSession::HandleEquipmentSetDelete(WorldPacket &recv_data) -{ - sLog.outDebug("CMSG_EQUIPMENT_SET_DELETE"); - - uint64 setGuid; - if (!recv_data.readPackGUID(setGuid)) - return; - - _player->DeleteEquipmentSet(setGuid); -} - -void WorldSession::HandleEquipmentSetUse(WorldPacket &recv_data) -{ - sLog.outDebug("CMSG_EQUIPMENT_SET_USE"); - recv_data.hexlike(); - - for (uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) - { - uint64 itemGuid; - if (!recv_data.readPackGUID(itemGuid)) - return; - - uint8 srcbag, srcslot; - recv_data >> srcbag >> srcslot; - - sLog.outDebug("Item " UI64FMTD ": srcbag %u, srcslot %u", itemGuid, srcbag, srcslot); - - Item *item = _player->GetItemByGuid(itemGuid); - - uint16 dstpos = i | (INVENTORY_SLOT_BAG_0 << 8); - - if (!item) - { - Item *uItem = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); - if (!uItem) - continue; - - ItemPosCountVec sDest; - uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sDest, uItem, false); - if (msg == EQUIP_ERR_OK) - { - _player->RemoveItem(INVENTORY_SLOT_BAG_0, i, true); - _player->StoreItem(sDest, uItem, true); - } - else - _player->SendEquipError(msg, uItem, NULL); - - continue; - } - - if (item->GetPos() == dstpos) - continue; - - _player->SwapItem(item->GetPos(), dstpos); - } - - WorldPacket data(SMSG_EQUIPMENT_SET_USE_RESULT, 1); - data << uint8(0); // 4 - equipment swap failed - inventory is full - SendPacket(&data); -} - -void WorldSession::HandleOnPVPKill(Player *killed) -{ - sScriptMgr.OnPVPKill(GetPlayer(), killed); -} - -bool WorldSession::HandleOnPlayerChat(const char *text) -{ - return sScriptMgr.OnPlayerChat(GetPlayer(), text); -} - -uint32 WorldSession::HandleOnGetXP(uint32 amount) -{ - return sScriptMgr.OnGetXP(GetPlayer(), amount); -} - -int32 WorldSession::HandleOnGetMoney(int32 amount) -{ - return sScriptMgr.OnGetMoney(GetPlayer(), amount); -} - -void WorldSession::HandleOnAreaChange(AreaTableEntry const *pArea) -{ - sScriptMgr.OnAreaChange(GetPlayer(), pArea); -} - -bool WorldSession::HandleOnItemClick(Item *pItem) -{ - return sScriptMgr.OnItemClick(GetPlayer(), pItem); -} - -bool WorldSession::HandleOnItemOpen(Item *pItem) -{ - return sScriptMgr.OnItemOpen(GetPlayer(), pItem); -} - -bool WorldSession::HandleOnGoClick(GameObject *pGameObject) -{ - return sScriptMgr.OnGoClick(GetPlayer(), pGameObject); -} - -void WorldSession::HandleOnCreatureKill(Creature *pCreature) -{ - sScriptMgr.OnCreatureKill(GetPlayer(), pCreature); -} diff --git a/src/server/game/Entities/Player/DuelHandler.cpp b/src/server/game/Entities/Player/DuelHandler.cpp deleted file mode 100644 index 99c8a774b03..00000000000 --- a/src/server/game/Entities/Player/DuelHandler.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Log.h" -#include "Opcodes.h" -#include "UpdateData.h" -#include "Player.h" - -void WorldSession::HandleDuelAcceptedOpcode(WorldPacket& recvPacket) -{ - uint64 guid; - Player *pl; - Player *plTarget; - - if (!GetPlayer()->duel) // ignore accept from duel-sender - return; - - recvPacket >> guid; - - pl = GetPlayer(); - plTarget = pl->duel->opponent; - - if (pl == pl->duel->initiator || !plTarget || pl == plTarget || pl->duel->startTime != 0 || plTarget->duel->startTime != 0) - return; - - //sLog.outDebug("WORLD: received CMSG_DUEL_ACCEPTED"); - DEBUG_LOG("Player 1 is: %u (%s)", pl->GetGUIDLow(),pl->GetName()); - DEBUG_LOG("Player 2 is: %u (%s)", plTarget->GetGUIDLow(),plTarget->GetName()); - - time_t now = time(NULL); - pl->duel->startTimer = now; - plTarget->duel->startTimer = now; - - pl->SendDuelCountdown(3000); - plTarget->SendDuelCountdown(3000); -} - -void WorldSession::HandleDuelCancelledOpcode(WorldPacket& recvPacket) -{ - //sLog.outDebug("WORLD: received CMSG_DUEL_CANCELLED"); - - // no duel requested - if (!GetPlayer()->duel) - return; - - // player surrendered in a duel using /forfeit - if (GetPlayer()->duel->startTime != 0) - { - GetPlayer()->CombatStopWithPets(true); - if (GetPlayer()->duel->opponent) - GetPlayer()->duel->opponent->CombatStopWithPets(true); - - GetPlayer()->CastSpell(GetPlayer(), 7267, true); // beg - GetPlayer()->DuelComplete(DUEL_WON); - return; - } - - // player either discarded the duel using the "discard button" - // or used "/forfeit" before countdown reached 0 - uint64 guid; - recvPacket >> guid; - - GetPlayer()->DuelComplete(DUEL_INTERUPTED); -} diff --git a/src/server/game/Entities/Player/MiscHandler.cpp b/src/server/game/Entities/Player/MiscHandler.cpp deleted file mode 100644 index ea6f892c126..00000000000 --- a/src/server/game/Entities/Player/MiscHandler.cpp +++ /dev/null @@ -1,1721 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Language.h" -#include "Database/DatabaseEnv.h" -#include "Database/DatabaseImpl.h" -#include "WorldPacket.h" -#include "Opcodes.h" -#include "Log.h" -#include "Player.h" -#include "GossipDef.h" -#include "World.h" -#include "ObjectMgr.h" -#include "WorldSession.h" -#include "Auth/BigNumber.h" -#include "Auth/Sha1.h" -#include "UpdateData.h" -#include "LootMgr.h" -#include "Chat.h" -#include -#include "ObjectAccessor.h" -#include "Object.h" -#include "BattleGround.h" -#include "OutdoorPvP.h" -#include "Pet.h" -#include "SocialMgr.h" -#include "CellImpl.h" -#include "AccountMgr.h" -#include "Vehicle.h" -#include "CreatureAI.h" -#include "DBCEnums.h" -#include "ScriptMgr.h" -#include "MapManager.h" -#include "InstanceData.h" - -void WorldSession::HandleRepopRequestOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Recvd CMSG_REPOP_REQUEST Message"); - - recv_data.read_skip(); - - if (GetPlayer()->isAlive()||GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) - return; - - // the world update order is sessions, players, creatures - // the netcode runs in parallel with all of these - // creatures can kill players - // so if the server is lagging enough the player can - // release spirit after he's killed but before he is updated - if (GetPlayer()->getDeathState() == JUST_DIED) - { - sLog.outDebug("HandleRepopRequestOpcode: got request after player %s(%d) was killed and before he was updated", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); - GetPlayer()->KillPlayer(); - } - - //this is spirit release confirm? - GetPlayer()->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT, true); - GetPlayer()->BuildPlayerRepop(); - GetPlayer()->RepopAtGraveyard(); -} - -void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION"); - - uint32 gossipListId; - uint32 menuId; - uint64 guid; - std::string code = ""; - - recv_data >> guid >> menuId >> gossipListId; - - if (_player->PlayerTalkClass->GossipOptionCoded(gossipListId)) - { - // recheck - sLog.outBasic("reading string"); - recv_data >> code; - sLog.outBasic("string read: %s", code.c_str()); - } - - Creature *unit = NULL; - GameObject *go = NULL; - if (IS_CRE_OR_VEH_GUID(guid)) - { - unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); - if (!unit) - { - sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - } - else if (IS_GAMEOBJECT_GUID(guid)) - { - go = _player->GetMap()->GetGameObject(guid); - if (!go) - { - sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - GameObject (GUID: %u) not found.", uint32(GUID_LOPART(guid))); - return; - } - } - else - { - sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - unsupported GUID type for highguid %u. lowpart %u.", uint32(GUID_HIPART(guid)), uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - if ((unit && unit->GetCreatureInfo()->ScriptID != unit->LastUsedScriptID) || (go && go->GetGOInfo()->ScriptId != go->LastUsedScriptID)) - { - sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - Script reloaded while in use, ignoring and set new scipt id"); - if (unit) - unit->LastUsedScriptID = unit->GetCreatureInfo()->ScriptID; - if (go) - go->LastUsedScriptID = go->GetGOInfo()->ScriptId; - _player->PlayerTalkClass->CloseGossip(); - return; - } - if (!code.empty()) - { - if (unit) - { - if (!sScriptMgr.GossipSelectWithCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str())) - _player->OnGossipSelect(unit, gossipListId, menuId); - } - else - sScriptMgr.GOSelectWithCode(_player, go, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str()); - } - else - { - if (unit) - { - if (!sScriptMgr.GossipSelect(_player, unit, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId))) - _player->OnGossipSelect(unit, gossipListId, menuId); - } - else - sScriptMgr.GOSelect(_player, go, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId)); - } -} - -void WorldSession::HandleWhoOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Recvd CMSG_WHO Message"); - //recv_data.hexlike(); - - uint32 clientcount = 0; - - uint32 level_min, level_max, racemask, classmask, zones_count, str_count; - uint32 zoneids[10]; // 10 is client limit - std::string player_name, guild_name; - - recv_data >> level_min; // maximal player level, default 0 - recv_data >> level_max; // minimal player level, default 100 (MAX_LEVEL) - recv_data >> player_name; // player name, case sensitive... - - recv_data >> guild_name; // guild name, case sensitive... - - recv_data >> racemask; // race mask - recv_data >> classmask; // class mask - recv_data >> zones_count; // zones count, client limit = 10 (2.0.10) - - if (zones_count > 10) - return; // can't be received from real client or broken packet - - for (uint32 i = 0; i < zones_count; ++i) - { - uint32 temp; - recv_data >> temp; // zone id, 0 if zone is unknown... - zoneids[i] = temp; - sLog.outDebug("Zone %u: %u", i, zoneids[i]); - } - - recv_data >> str_count; // user entered strings count, client limit=4 (checked on 2.0.10) - - if (str_count > 4) - return; // can't be received from real client or broken packet - - sLog.outDebug("Minlvl %u, maxlvl %u, name %s, guild %s, racemask %u, classmask %u, zones %u, strings %u", level_min, level_max, player_name.c_str(), guild_name.c_str(), racemask, classmask, zones_count, str_count); - - std::wstring str[4]; // 4 is client limit - for (uint32 i = 0; i < str_count; ++i) - { - std::string temp; - recv_data >> temp; // user entered string, it used as universal search pattern(guild+player name)? - - if (!Utf8toWStr(temp,str[i])) - continue; - - wstrToLower(str[i]); - - sLog.outDebug("String %u: %s", i, temp.c_str()); - } - - std::wstring wplayer_name; - std::wstring wguild_name; - if (!(Utf8toWStr(player_name, wplayer_name) && Utf8toWStr(guild_name, wguild_name))) - return; - wstrToLower(wplayer_name); - wstrToLower(wguild_name); - - // client send in case not set max level value 100 but Trinity supports 255 max level, - // update it to show GMs with characters after 100 level - if (level_max >= MAX_LEVEL) - level_max = STRONG_MAX_LEVEL; - - uint32 team = _player->GetTeam(); - uint32 security = GetSecurity(); - bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); - uint32 gmLevelInWhoList = sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST); - - WorldPacket data(SMSG_WHO, 50); // guess size - data << uint32(clientcount); // clientcount place holder, listed count - data << uint32(clientcount); // clientcount place holder, online count - - ObjectAccessor::Guard guard(*HashMapHolder::GetLock()); - HashMapHolder::MapType& m = ObjectAccessor::Instance().GetPlayers(); - for (HashMapHolder::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) - { - if (security == SEC_PLAYER) - { - // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST - if (itr->second->GetTeam() != team && !allowTwoSideWhoList) - continue; - - // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST - if ((itr->second->GetSession()->GetSecurity() > gmLevelInWhoList)) - continue; - } - - //do not process players which are not in world - if (!(itr->second->IsInWorld())) - continue; - - // check if target is globally visible for player - if (!(itr->second->IsVisibleGloballyFor(_player))) - continue; - - // check if target's level is in level range - uint8 lvl = itr->second->getLevel(); - if (lvl < level_min || lvl > level_max) - continue; - - // check if class matches classmask - uint32 class_ = itr->second->getClass(); - if (!(classmask & (1 << class_))) - continue; - - // check if race matches racemask - uint32 race = itr->second->getRace(); - if (!(racemask & (1 << race))) - continue; - - uint32 pzoneid = itr->second->GetZoneId(); - - bool z_show = true; - for (uint32 i = 0; i < zones_count; ++i) - { - if (zoneids[i] == pzoneid) - { - z_show = true; - break; - } - - z_show = false; - } - if (!z_show) - continue; - - std::string pname = itr->second->GetName(); - std::wstring wpname; - if (!Utf8toWStr(pname,wpname)) - continue; - wstrToLower(wpname); - - if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos)) - continue; - - std::string gname = objmgr.GetGuildNameById(itr->second->GetGuildId()); - std::wstring wgname; - if (!Utf8toWStr(gname,wgname)) - continue; - wstrToLower(wgname); - - if (!(wguild_name.empty() || wgname.find(wguild_name) != std::wstring::npos)) - continue; - - std::string aname; - if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId())) - aname = areaEntry->area_name[GetSessionDbcLocale()]; - - bool s_show = true; - for (uint32 i = 0; i < str_count; ++i) - { - if (!str[i].empty()) - { - if (wgname.find(str[i]) != std::wstring::npos || - wpname.find(str[i]) != std::wstring::npos || - Utf8FitTo(aname, str[i])) - { - s_show = true; - break; - } - s_show = false; - } - } - if (!s_show) - continue; - - data << pname; // player name - data << gname; // guild name - data << uint32(lvl); // player level - data << uint32(class_); // player class - data << uint32(race); // player race - data << uint8(0); // new 2.4.0 - data << uint32(pzoneid); // player zone id - - // 49 is maximum player count sent to client - can be overridden - // through config, but is unstable - if ((++clientcount) == sWorld.getConfig(CONFIG_MAX_WHO)) - break; - } - - uint32 count = m.size(); - data.put( 0, clientcount ); // insert right count, listed count - data.put( 4, count > 50 ? count : clientcount ); // insert right count, online count - - SendPacket(&data); - sLog.outDebug("WORLD: Send SMSG_WHO Message"); -} - -void WorldSession::HandleLogoutRequestOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("WORLD: Recvd CMSG_LOGOUT_REQUEST Message, security - %u", GetSecurity()); - - if (uint64 lguid = GetPlayer()->GetLootGUID()) - DoLootRelease(lguid); - - uint8 reason = 0; - - if (GetPlayer()->isInCombat()) - reason = 1; - else if (GetPlayer()->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_JUMPING | MOVEMENTFLAG_FALLING)) - reason = 3; // is jumping or falling - else if (GetPlayer()->duel || GetPlayer()->HasAura(9454)) // is dueling or frozen by GM via freeze command - reason = 2; // FIXME - Need the correct value - - if (reason) - { - WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); - data << uint8(reason); - data << uint32(0); - SendPacket(&data); - LogoutRequest(0); - return; - } - - //instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in TrinityCore.conf - if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->isInFlight() || - GetSecurity() >= sWorld.getConfig(CONFIG_INSTANT_LOGOUT)) - { - WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); - data << uint8(0); - data << uint32(16777216); - SendPacket(&data); - LogoutPlayer(true); - return; - } - - // not set flags if player can't free move to prevent lost state at logout cancel - if (GetPlayer()->CanFreeMove()) - { - GetPlayer()->SetStandState(UNIT_STAND_STATE_SIT); - - WorldPacket data(SMSG_FORCE_MOVE_ROOT, (8+4)); // guess size - data.append(GetPlayer()->GetPackGUID()); - data << (uint32)2; - SendPacket(&data); - GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); - } - - WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); - data << uint8(0); - data << uint32(0); - SendPacket(&data); - LogoutRequest(time(NULL)); -} - -void WorldSession::HandlePlayerLogoutOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("WORLD: Recvd CMSG_PLAYER_LOGOUT Message"); -} - -void WorldSession::HandleLogoutCancelOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("WORLD: Recvd CMSG_LOGOUT_CANCEL Message"); - - LogoutRequest(0); - - WorldPacket data(SMSG_LOGOUT_CANCEL_ACK, 0); - SendPacket(&data); - - // not remove flags if can't free move - its not set in Logout request code. - if (GetPlayer()->CanFreeMove()) - { - //!we can move again - data.Initialize(SMSG_FORCE_MOVE_UNROOT, 8); // guess size - data.append(GetPlayer()->GetPackGUID()); - data << uint32(0); - SendPacket(&data); - - //! Stand Up - GetPlayer()->SetStandState(UNIT_STAND_STATE_STAND); - - //! DISABLE_ROTATE - GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); - } - - sLog.outDebug("WORLD: sent SMSG_LOGOUT_CANCEL_ACK Message"); -} - -void WorldSession::HandleTogglePvP(WorldPacket & recv_data) -{ - // this opcode can be used in two ways: Either set explicit new status or toggle old status - if (recv_data.size() == 1) - { - bool newPvPStatus; - recv_data >> newPvPStatus; - GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP, newPvPStatus); - GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER, !newPvPStatus); - } - else - { - GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); - GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER); - } - - if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP)) - { - if (!GetPlayer()->IsPvP() || GetPlayer()->pvpInfo.endTimer != 0) - GetPlayer()->UpdatePvP(true, true); - } - else - { - if (!GetPlayer()->pvpInfo.inHostileArea && GetPlayer()->IsPvP()) - GetPlayer()->pvpInfo.endTimer = time(NULL); // start toggle-off - } - - //if (OutdoorPvP * pvp = _player->GetOutdoorPvP()) - // pvp->HandlePlayerActivityChanged(_player); -} - -void WorldSession::HandleZoneUpdateOpcode(WorldPacket & recv_data) -{ - uint32 newZone; - recv_data >> newZone; - - sLog.outDetail("WORLD: Recvd ZONE_UPDATE: %u", newZone); - - // use server size data - uint32 newzone, newarea; - GetPlayer()->GetZoneAndAreaId(newzone,newarea); - GetPlayer()->UpdateZone(newzone,newarea); - //GetPlayer()->SendInitWorldStates(true,newZone); -} - -void WorldSession::HandleSetTargetOpcode(WorldPacket & recv_data) -{ - // When this packet send? - uint64 guid ; - recv_data >> guid; - - _player->SetUInt32Value(UNIT_FIELD_TARGET, guid); - - // update reputation list if need - Unit* unit = ObjectAccessor::GetUnit(*_player, guid); - if (!unit) - return; - - if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction())) - _player->GetReputationMgr().SetVisible(factionTemplateEntry); -} - -void WorldSession::HandleSetSelectionOpcode(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - - _player->SetSelection(guid); - - // update reputation list if need - Unit* unit = ObjectAccessor::GetUnit(*_player, guid); - if (!unit) - return; - - if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction())) - _player->GetReputationMgr().SetVisible(factionTemplateEntry); -} - -void WorldSession::HandleStandStateChangeOpcode(WorldPacket & recv_data) -{ - // sLog.outDebug("WORLD: Received CMSG_STANDSTATECHANGE"); -- too many spam in log at lags/debug stop - uint32 animstate; - recv_data >> animstate; - - _player->SetStandState(animstate); -} - -void WorldSession::HandleContactListOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_CONTACT_LIST"); - uint32 unk; - recv_data >> unk; - sLog.outDebug("unk value is %u", unk); - _player->GetSocial()->SendSocialList(); -} - -void WorldSession::HandleAddFriendOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_ADD_FRIEND"); - - std::string friendName = GetTrinityString(LANG_FRIEND_IGNORE_UNKNOWN); - std::string friendNote; - - recv_data >> friendName; - - recv_data >> friendNote; - - if (!normalizePlayerName(friendName)) - return; - - CharacterDatabase.escape_string(friendName); // prevent SQL injection - normal name don't must changed by this call - - sLog.outDebug("WORLD: %s asked to add friend : '%s'", - GetPlayer()->GetName(), friendName.c_str()); - - CharacterDatabase.AsyncPQuery(&WorldSession::HandleAddFriendOpcodeCallBack, GetAccountId(), friendNote, "SELECT guid, race, account FROM characters WHERE name = '%s'", friendName.c_str()); -} - -void WorldSession::HandleAddFriendOpcodeCallBack(QueryResult_AutoPtr result, uint32 accountId, std::string friendNote) -{ - uint64 friendGuid; - uint64 friendAcctid; - uint32 team; - FriendsResult friendResult; - - WorldSession * session = sWorld.FindSession(accountId); - - if (!session || !session->GetPlayer()) - return; - - friendResult = FRIEND_NOT_FOUND; - friendGuid = 0; - - if (result) - { - friendGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); - team = Player::TeamForRace((*result)[1].GetUInt8()); - friendAcctid = (*result)[2].GetUInt32(); - - if (session->GetSecurity() >= SEC_MODERATOR || sWorld.getConfig(CONFIG_ALLOW_GM_FRIEND) || accmgr.GetSecurity(friendAcctid) < SEC_MODERATOR) - { - if (friendGuid) - { - if (friendGuid == session->GetPlayer()->GetGUID()) - friendResult = FRIEND_SELF; - else if (session->GetPlayer()->GetTeam() != team && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && session->GetSecurity() < SEC_MODERATOR) - friendResult = FRIEND_ENEMY; - else if (session->GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid))) - friendResult = FRIEND_ALREADY; - else - { - Player* pFriend = ObjectAccessor::FindPlayer(friendGuid); - if (pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(session->GetPlayer())) - friendResult = FRIEND_ADDED_ONLINE; - else - friendResult = FRIEND_ADDED_OFFLINE; - if (!session->GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false)) - { - friendResult = FRIEND_LIST_FULL; - sLog.outDebug("WORLD: %s's friend list is full.", session->GetPlayer()->GetName()); - } - } - session->GetPlayer()->GetSocial()->SetFriendNote(GUID_LOPART(friendGuid), friendNote); - } - } - } - - sSocialMgr.SendFriendStatus(session->GetPlayer(), friendResult, GUID_LOPART(friendGuid), false); - - sLog.outDebug("WORLD: Sent (SMSG_FRIEND_STATUS)"); -} - -void WorldSession::HandleDelFriendOpcode(WorldPacket & recv_data) -{ - uint64 FriendGUID; - - sLog.outDebug("WORLD: Received CMSG_DEL_FRIEND"); - - recv_data >> FriendGUID; - - _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(FriendGUID), false); - - sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_REMOVED, GUID_LOPART(FriendGUID), false); - - sLog.outDebug("WORLD: Sent motd (SMSG_FRIEND_STATUS)"); -} - -void WorldSession::HandleAddIgnoreOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_ADD_IGNORE"); - - std::string IgnoreName = GetTrinityString(LANG_FRIEND_IGNORE_UNKNOWN); - - recv_data >> IgnoreName; - - if (!normalizePlayerName(IgnoreName)) - return; - - CharacterDatabase.escape_string(IgnoreName); // prevent SQL injection - normal name don't must changed by this call - - sLog.outDebug("WORLD: %s asked to Ignore: '%s'", - GetPlayer()->GetName(), IgnoreName.c_str()); - - CharacterDatabase.AsyncPQuery(&WorldSession::HandleAddIgnoreOpcodeCallBack, GetAccountId(), "SELECT guid FROM characters WHERE name = '%s'", IgnoreName.c_str()); -} - -void WorldSession::HandleAddIgnoreOpcodeCallBack(QueryResult_AutoPtr result, uint32 accountId) -{ - uint64 IgnoreGuid; - FriendsResult ignoreResult; - - WorldSession * session = sWorld.FindSession(accountId); - - if (!session || !session->GetPlayer()) - return; - - ignoreResult = FRIEND_IGNORE_NOT_FOUND; - IgnoreGuid = 0; - - if (result) - { - IgnoreGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); - - if (IgnoreGuid) - { - if (IgnoreGuid == session->GetPlayer()->GetGUID()) //not add yourself - ignoreResult = FRIEND_IGNORE_SELF; - else if (session->GetPlayer()->GetSocial()->HasIgnore(GUID_LOPART(IgnoreGuid))) - ignoreResult = FRIEND_IGNORE_ALREADY; - else - { - ignoreResult = FRIEND_IGNORE_ADDED; - - // ignore list full - if (!session->GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(IgnoreGuid), true)) - ignoreResult = FRIEND_IGNORE_FULL; - } - } - } - - sSocialMgr.SendFriendStatus(session->GetPlayer(), ignoreResult, GUID_LOPART(IgnoreGuid), false); - - sLog.outDebug("WORLD: Sent (SMSG_FRIEND_STATUS)"); -} - -void WorldSession::HandleDelIgnoreOpcode(WorldPacket & recv_data) -{ - uint64 IgnoreGUID; - - sLog.outDebug("WORLD: Received CMSG_DEL_IGNORE"); - - recv_data >> IgnoreGUID; - - _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(IgnoreGUID), true); - - sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_IGNORE_REMOVED, GUID_LOPART(IgnoreGUID), false); - - sLog.outDebug("WORLD: Sent motd (SMSG_FRIEND_STATUS)"); -} - -void WorldSession::HandleSetContactNotesOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_SET_CONTACT_NOTES"); - uint64 guid; - std::string note; - recv_data >> guid >> note; - _player->GetSocial()->SetFriendNote(guid, note); -} - -void WorldSession::HandleBugOpcode(WorldPacket & recv_data) -{ - uint32 suggestion, contentlen, typelen; - std::string content, type; - - recv_data >> suggestion >> contentlen >> content; - - recv_data >> typelen >> type; - - if (suggestion == 0) - sLog.outDebug("WORLD: Received CMSG_BUG [Bug Report]"); - else - sLog.outDebug("WORLD: Received CMSG_BUG [Suggestion]"); - - sLog.outDebug("%s", type.c_str()); - sLog.outDebug("%s", content.c_str()); - - CharacterDatabase.escape_string(type); - CharacterDatabase.escape_string(content); - CharacterDatabase.PExecute ("INSERT INTO bugreport (type,content) VALUES('%s', '%s')", type.c_str(), content.c_str()); -} - -void WorldSession::HandleReclaimCorpseOpcode(WorldPacket &recv_data) -{ - sLog.outDetail("WORLD: Received CMSG_RECLAIM_CORPSE"); - - uint64 guid; - recv_data >> guid; - - if (GetPlayer()->isAlive()) - return; - - // do not allow corpse reclaim in arena - if (GetPlayer()->InArena()) - return; - - // body not released yet - if (!GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) - return; - - Corpse *corpse = GetPlayer()->GetCorpse(); - - if (!corpse) - return; - - // prevent resurrect before 30-sec delay after body release not finished - if (corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType() == CORPSE_RESURRECTABLE_PVP) > time(NULL)) - return; - - if (!corpse->IsWithinDistInMap(GetPlayer(), CORPSE_RECLAIM_RADIUS, true)) - return; - - // resurrect - GetPlayer()->ResurrectPlayer(GetPlayer()->InBattleGround() ? 1.0f : 0.5f); - - // spawn bones - GetPlayer()->SpawnCorpseBones(); -} - -void WorldSession::HandleResurrectResponseOpcode(WorldPacket & recv_data) -{ - sLog.outDetail("WORLD: Received CMSG_RESURRECT_RESPONSE"); - - uint64 guid; - uint8 status; - recv_data >> guid; - recv_data >> status; - - if (GetPlayer()->isAlive()) - return; - - if (status == 0) - { - GetPlayer()->clearResurrectRequestData(); // reject - return; - } - - if (!GetPlayer()->isRessurectRequestedBy(guid)) - return; - - GetPlayer()->ResurectUsingRequestData(); -} - -void WorldSession::SendAreaTriggerMessage(const char* Text, ...) -{ - va_list ap; - char szStr [1024]; - szStr[0] = '\0'; - - va_start(ap, Text); - vsnprintf(szStr, 1024, Text, ap); - va_end(ap); - - uint32 length = strlen(szStr)+1; - WorldPacket data(SMSG_AREA_TRIGGER_MESSAGE, 4+length); - data << length; - data << szStr; - SendPacket(&data); -} - -void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_AREATRIGGER"); - - uint32 Trigger_ID; - - recv_data >> Trigger_ID; - sLog.outDebug("Trigger ID:%u",Trigger_ID); - - if (GetPlayer()->isInFlight()) - { - sLog.outDebug("Player '%s' (GUID: %u) in flight, ignore Area Trigger ID:%u",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow(), Trigger_ID); - return; - } - - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); - if (!atEntry) - { - sLog.outDebug("Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID:%u",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow(), Trigger_ID); - return; - } - - if (GetPlayer()->GetMapId() != atEntry->mapid) - { - sLog.outDebug("Player '%s' (GUID: %u) too far (trigger map: %u player map: %u), ignore Area Trigger ID: %u", GetPlayer()->GetName(), atEntry->mapid, GetPlayer()->GetMapId(), GetPlayer()->GetGUIDLow(), Trigger_ID); - return; - } - - // delta is safe radius - const float delta = 5.0f; - // check if player in the range of areatrigger - Player* pl = GetPlayer(); - - if (atEntry->radius > 0) - { - // if we have radius check it - float dist = pl->GetDistance(atEntry->x,atEntry->y,atEntry->z); - if (dist > atEntry->radius + delta) - { - sLog.outDebug("Player '%s' (GUID: %u) too far (radius: %f distance: %f), ignore Area Trigger ID: %u", - pl->GetName(), pl->GetGUIDLow(), atEntry->radius, dist, Trigger_ID); - return; - } - } - else - { - // we have only extent - - // rotate the players position instead of rotating the whole cube, that way we can make a simplified - // is-in-cube check and we have to calculate only one point instead of 4 - - // 2PI = 360°, keep in mind that ingame orientation is counter-clockwise - double rotation = 2*M_PI-atEntry->box_orientation; - double sinVal = sin(rotation); - double cosVal = cos(rotation); - - float playerBoxDistX = pl->GetPositionX() - atEntry->x; - float playerBoxDistY = pl->GetPositionY() - atEntry->y; - - float rotPlayerX = atEntry->x + playerBoxDistX * cosVal - playerBoxDistY*sinVal; - float rotPlayerY = atEntry->y + playerBoxDistY * cosVal + playerBoxDistX*sinVal; - - // box edges are parallel to coordiante axis, so we can treat every dimension independently :D - float dz = pl->GetPositionZ() - atEntry->z; - float dx = rotPlayerX - atEntry->x; - float dy = rotPlayerY - atEntry->y; - if ((fabs(dx) > atEntry->box_x/2 + delta) || - (fabs(dy) > atEntry->box_y/2 + delta) || - (fabs(dz) > atEntry->box_z/2 + delta)) - { - sLog.outDebug("Player '%s' (GUID: %u) too far (1/2 box X: %f 1/2 box Y: %f 1/2 box Z: %f rotatedPlayerX: %f rotatedPlayerY: %f dZ:%f), ignore Area Trigger ID: %u", - pl->GetName(), pl->GetGUIDLow(), atEntry->box_x/2, atEntry->box_y/2, atEntry->box_z/2, rotPlayerX, rotPlayerY, dz, Trigger_ID); - return; - } - } - - if (sScriptMgr.AreaTrigger(GetPlayer(), atEntry)) - return; - - uint32 quest_id = objmgr.GetQuestForAreaTrigger(Trigger_ID); - if (quest_id && GetPlayer()->isAlive() && GetPlayer()->IsActiveQuest(quest_id)) - { - Quest const* pQuest = objmgr.GetQuestTemplate(quest_id); - if (pQuest) - { - if (GetPlayer()->GetQuestStatus(quest_id) == QUEST_STATUS_INCOMPLETE) - GetPlayer()->AreaExploredOrEventHappens(quest_id); - } - } - - if (objmgr.IsTavernAreaTrigger(Trigger_ID)) - { - // set resting flag we are in the inn - GetPlayer()->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); - GetPlayer()->InnEnter(time(NULL), atEntry->mapid, atEntry->x, atEntry->y, atEntry->z); - GetPlayer()->SetRestType(REST_TYPE_IN_TAVERN); - - if (sWorld.IsFFAPvPRealm()) - GetPlayer()->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); - - return; - } - - if (GetPlayer()->InBattleGround()) - { - BattleGround* bg = GetPlayer()->GetBattleGround(); - if (bg) - if (bg->GetStatus() == STATUS_IN_PROGRESS) - bg->HandleAreaTrigger(GetPlayer(), Trigger_ID); - - return; - } - - if (OutdoorPvP * pvp = GetPlayer()->GetOutdoorPvP()) - { - if (pvp->HandleAreaTrigger(_player, Trigger_ID)) - return; - } - - // NULL if all values default (non teleport trigger) - AreaTrigger const* at = objmgr.GetAreaTrigger(Trigger_ID); - if (!at) - return; - - if (!GetPlayer()->Satisfy(objmgr.GetAccessRequirement(at->access_id), at->target_mapId, true)) - return; - - // check if player can enter instance : instance not full, and raid instance not in encounter fight - if (!MapManager::Instance().CanPlayerEnter(at->target_mapId, GetPlayer(), false)) - return; - - GetPlayer()->TeleportTo(at->target_mapId,at->target_X,at->target_Y,at->target_Z,at->target_Orientation,TELE_TO_NOT_LEAVE_TRANSPORT); -} - -void WorldSession::HandleUpdateAccountData(WorldPacket &recv_data) -{ - sLog.outDetail("WORLD: Received CMSG_UPDATE_ACCOUNT_DATA"); - - uint32 type, timestamp, decompressedSize; - recv_data >> type >> timestamp >> decompressedSize; - - sLog.outDebug("UAD: type %u, time %u, decompressedSize %u", type, timestamp, decompressedSize); - - if (type > NUM_ACCOUNT_DATA_TYPES) - return; - - if (decompressedSize == 0) // erase - { - SetAccountData(AccountDataType(type), 0, ""); - - WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4+4); - data << uint32(type); - data << uint32(0); - SendPacket(&data); - - return; - } - - if (decompressedSize > 0xFFFF) - { - recv_data.rpos(recv_data.wpos()); // unnneded warning spam in this case - sLog.outError("UAD: Account data packet too big, size %u", decompressedSize); - return; - } - - ByteBuffer dest; - dest.resize(decompressedSize); - - uLongf realSize = decompressedSize; - if (uncompress(const_cast(dest.contents()), &realSize, const_cast(recv_data.contents() + recv_data.rpos()), recv_data.size() - recv_data.rpos()) != Z_OK) - { - recv_data.rpos(recv_data.wpos()); // unnneded warning spam in this case - sLog.outError("UAD: Failed to decompress account data"); - return; - } - - recv_data.rpos(recv_data.wpos()); // uncompress read (recv_data.size() - recv_data.rpos()) - - std::string adata; - dest >> adata; - - SetAccountData(AccountDataType(type), timestamp, adata); - - WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4+4); - data << uint32(type); - data << uint32(0); - SendPacket(&data); -} - -void WorldSession::HandleRequestAccountData(WorldPacket& recv_data) -{ - sLog.outDetail("WORLD: Received CMSG_REQUEST_ACCOUNT_DATA"); - - uint32 type; - recv_data >> type; - - sLog.outDebug("RAD: type %u", type); - - if (type > NUM_ACCOUNT_DATA_TYPES) - return; - - AccountData *adata = GetAccountData(AccountDataType(type)); - - uint32 size = adata->Data.size(); - - uLongf destSize = compressBound(size); - - ByteBuffer dest; - dest.resize(destSize); - - if (size && compress(const_cast(dest.contents()), &destSize, (uint8*)adata->Data.c_str(), size) != Z_OK) - { - sLog.outDebug("RAD: Failed to compress account data"); - return; - } - - dest.resize(destSize); - - WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA, 8+4+4+4+destSize); - data << uint64(_player ? _player->GetGUID() : 0); // player guid - data << uint32(type); // type (0-7) - data << uint32(adata->Time); // unix time - data << uint32(size); // decompressed length - data.append(dest); // compressed data - SendPacket(&data); -} - -void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_SET_ACTION_BUTTON"); - uint8 button; - uint32 packetData; - recv_data >> button >> packetData; - - uint32 action = ACTION_BUTTON_ACTION(packetData); - uint8 type = ACTION_BUTTON_TYPE(packetData); - - sLog.outDetail("BUTTON: %u ACTION: %u TYPE: %u", button, action, type); - if (!packetData) - { - sLog.outDetail("MISC: Remove action from button %u", button); - GetPlayer()->removeActionButton(button); - } - else - { - switch(type) - { - case ACTION_BUTTON_MACRO: - case ACTION_BUTTON_CMACRO: - sLog.outDetail("MISC: Added Macro %u into button %u", action, button); - break; - case ACTION_BUTTON_EQSET: - sLog.outDetail("MISC: Added EquipmentSet %u into button %u", action, button); - break; - case ACTION_BUTTON_SPELL: - sLog.outDetail("MISC: Added Spell %u into button %u", action, button); - break; - case ACTION_BUTTON_ITEM: - sLog.outDetail("MISC: Added Item %u into button %u", action, button); - break; - default: - sLog.outError("MISC: Unknown action button type %u for action %u into button %u", type, action, button); - return; - } - GetPlayer()->addActionButton(button, action, type); - } -} - -void WorldSession::HandleCompleteCinematic(WorldPacket & /*recv_data*/) -{ - DEBUG_LOG("WORLD: Player is watching cinema"); -} - -void WorldSession::HandleNextCinematicCamera(WorldPacket & /*recv_data*/) -{ - DEBUG_LOG("WORLD: Which movie to play"); -} - -void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket & recv_data) -{ - /* WorldSession::Update(getMSTime());*/ - DEBUG_LOG("WORLD: Time Lag/Synchronization Resent/Update"); - - uint64 guid; - if (!recv_data.readPackGUID(guid)) - { - recv_data.rpos(recv_data.wpos()); - return; - } - recv_data.read_skip(); - /* - uint64 guid; - uint32 time_skipped; - recv_data >> guid; - recv_data >> time_skipped; - sLog.outDebug("WORLD: CMSG_MOVE_TIME_SKIPPED"); - - /// TODO - must be need use in Trinity - We substract server Lags to move time (AntiLags) - for exmaple - GetPlayer()->ModifyLastMoveTime(-int32(time_skipped)); - */ -} - -void WorldSession::HandleFeatherFallAck(WorldPacket &recv_data) -{ - DEBUG_LOG("WORLD: CMSG_MOVE_FEATHER_FALL_ACK"); - - // no used - recv_data.rpos(recv_data.wpos()); // prevent warnings spam -} - -void WorldSession::HandleMoveUnRootAck(WorldPacket& recv_data) -{ - // no used - recv_data.rpos(recv_data.wpos()); // prevent warnings spam -/* - uint64 guid; - recv_data >> guid; - - // now can skip not our packet - if (_player->GetGUID() != guid) - { - recv_data.rpos(recv_data.wpos()); // prevent warnings spam - return; - } - - sLog.outDebug("WORLD: CMSG_FORCE_MOVE_UNROOT_ACK"); - - recv_data.read_skip(); // unk - - MovementInfo movementInfo; - movementInfo.guid = guid; - ReadMovementInfo(recv_data, &movementInfo); - recv_data.read_skip(); // unk2 -*/ -} - -void WorldSession::HandleMoveRootAck(WorldPacket& recv_data) -{ - // no used - recv_data.rpos(recv_data.wpos()); // prevent warnings spam -/* - uint64 guid; - recv_data >> guid; - - // now can skip not our packet - if (_player->GetGUID() != guid) - { - recv_data.rpos(recv_data.wpos()); // prevent warnings spam - return; - } - - sLog.outDebug("WORLD: CMSG_FORCE_MOVE_ROOT_ACK"); - - recv_data.read_skip(); // unk - - MovementInfo movementInfo; - ReadMovementInfo(recv_data, &movementInfo); -*/ -} - -void WorldSession::HandleSetActionBarToggles(WorldPacket& recv_data) -{ - uint8 ActionBar; - - recv_data >> ActionBar; - - if (!GetPlayer()) // ignore until not logged (check needed because STATUS_AUTHED) - { - if (ActionBar != 0) - sLog.outError("WorldSession::HandleSetActionBarToggles in not logged state with value: %u, ignored",uint32(ActionBar)); - return; - } - - GetPlayer()->SetByteValue(PLAYER_FIELD_BYTES, 2, ActionBar); -} - -void WorldSession::HandleWardenDataOpcode(WorldPacket& recv_data) -{ - recv_data.read_skip(); - /* - uint8 tmp; - recv_data >> tmp; - sLog.outDebug("Received opcode CMSG_WARDEN_DATA, not resolve.uint8 = %u",tmp); - */ -} - -void WorldSession::HandlePlayedTime(WorldPacket& recv_data) -{ - uint8 unk1; - recv_data >> unk1; // 0 or 1 expected - - WorldPacket data(SMSG_PLAYED_TIME, 4 + 4 + 1); - data << uint32(_player->GetTotalPlayedTime()); - data << uint32(_player->GetLevelPlayedTime()); - data << uint8(unk1); // 0 - will not show in chat frame - SendPacket(&data); -} - -void WorldSession::HandleInspectOpcode(WorldPacket& recv_data) -{ - uint64 guid; - recv_data >> guid; - DEBUG_LOG("Inspected guid is " UI64FMTD, guid); - - _player->SetSelection(guid); - - Player *plr = objmgr.GetPlayer(guid); - if (!plr) // wrong player - return; - - uint32 talent_points = 0x47; - uint32 guid_size = plr->GetPackGUID().wpos(); - WorldPacket data(SMSG_INSPECT_TALENT, guid_size+4+talent_points); - data.append(plr->GetPackGUID()); - - if (sWorld.getConfig(CONFIG_TALENTS_INSPECTING) || _player->isGameMaster()) - { - plr->BuildPlayerTalentsInfoData(&data); - } - else - { - data << uint32(0); // unspentTalentPoints - data << uint8(0); // talentGroupCount - data << uint8(0); // talentGroupIndex - } - - plr->BuildEnchantmentsInfoData(&data); - SendPacket(&data); -} - -void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket& recv_data) -{ - uint64 guid; - recv_data >> guid; - - Player *player = objmgr.GetPlayer(guid); - - if (!player) - { - sLog.outError("InspectHonorStats: WTF, player not found..."); - return; - } - - WorldPacket data(MSG_INSPECT_HONOR_STATS, 8+1+4*4); - data << uint64(player->GetGUID()); - data << uint8(player->GetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY)); - data << uint32(player->GetUInt32Value(PLAYER_FIELD_KILLS)); - data << uint32(player->GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION)); - data << uint32(player->GetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION)); - data << uint32(player->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS)); - SendPacket(&data); -} - -void WorldSession::HandleWorldTeleportOpcode(WorldPacket& recv_data) -{ - // write in client console: worldport 469 452 6454 2536 180 or /console worldport 469 452 6454 2536 180 - // Received opcode CMSG_WORLD_TELEPORT - // Time is ***, map=469, x=452.000000, y=6454.000000, z=2536.000000, orient=3.141593 - - uint32 time; - uint32 mapid; - float PositionX; - float PositionY; - float PositionZ; - float Orientation; - - recv_data >> time; // time in m.sec. - recv_data >> mapid; - recv_data >> PositionX; - recv_data >> PositionY; - recv_data >> PositionZ; - recv_data >> Orientation; // o (3.141593 = 180 degrees) - - //sLog.outDebug("Received opcode CMSG_WORLD_TELEPORT"); - if (GetPlayer()->isInFlight()) - { - sLog.outDebug("Player '%s' (GUID: %u) in flight, ignore worldport command.",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow()); - return; - } - - DEBUG_LOG("Time %u sec, map=%u, x=%f, y=%f, z=%f, orient=%f", time/1000, mapid, PositionX, PositionY, PositionZ, Orientation); - - if (GetSecurity() >= SEC_ADMINISTRATOR) - GetPlayer()->TeleportTo(mapid,PositionX,PositionY,PositionZ,Orientation); - else - SendNotification(LANG_YOU_NOT_HAVE_PERMISSION); - sLog.outDebug("Received worldport command from player %s", GetPlayer()->GetName()); -} - -void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data) -{ - sLog.outDebug("Received opcode CMSG_WHOIS"); - std::string charname; - recv_data >> charname; - - if (GetSecurity() < SEC_ADMINISTRATOR) - { - SendNotification(LANG_YOU_NOT_HAVE_PERMISSION); - return; - } - - if (charname.empty() || !normalizePlayerName (charname)) - { - SendNotification(LANG_NEED_CHARACTER_NAME); - return; - } - - Player *plr = objmgr.GetPlayer(charname.c_str()); - - if (!plr) - { - SendNotification(LANG_PLAYER_NOT_EXIST_OR_OFFLINE, charname.c_str()); - return; - } - - uint32 accid = plr->GetSession()->GetAccountId(); - - QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid); - if (!result) - { - SendNotification(LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND, charname.c_str()); - return; - } - - Field *fields = result->Fetch(); - std::string acc = fields[0].GetCppString(); - if (acc.empty()) - acc = "Unknown"; - std::string email = fields[1].GetCppString(); - if (email.empty()) - email = "Unknown"; - std::string lastip = fields[2].GetCppString(); - if (lastip.empty()) - lastip = "Unknown"; - - std::string msg = charname + "'s " + "account is " + acc + ", e-mail: " + email + ", last ip: " + lastip; - - WorldPacket data(SMSG_WHOIS, msg.size()+1); - data << msg; - _player->GetSession()->SendPacket(&data); - - sLog.outDebug("Received whois command from player %s for character %s", GetPlayer()->GetName(), charname.c_str()); -} - -void WorldSession::HandleComplainOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_COMPLAIN"); - recv_data.hexlike(); - - uint8 spam_type; // 0 - mail, 1 - chat - uint64 spammer_guid; - uint32 unk1 = 0; - uint32 unk2 = 0; - uint32 unk3 = 0; - uint32 unk4 = 0; - std::string description = ""; - recv_data >> spam_type; // unk 0x01 const, may be spam type (mail/chat) - recv_data >> spammer_guid; // player guid - switch(spam_type) - { - case 0: - recv_data >> unk1; // const 0 - recv_data >> unk2; // probably mail id - recv_data >> unk3; // const 0 - break; - case 1: - recv_data >> unk1; // probably language - recv_data >> unk2; // message type? - recv_data >> unk3; // probably channel id - recv_data >> unk4; // unk random value - recv_data >> description; // spam description string (messagetype, channel name, player name, message) - break; - } - - // NOTE: all chat messages from this spammer automatically ignored by spam reporter until logout in case chat spam. - // if it's mail spam - ALL mails from this spammer automatically removed by client - - // Complaint Received message - WorldPacket data(SMSG_COMPLAIN_RESULT, 1); - data << uint8(0); - SendPacket(&data); - - sLog.outDebug("REPORT SPAM: type %u, guid %u, unk1 %u, unk2 %u, unk3 %u, unk4 %u, message %s", spam_type, GUID_LOPART(spammer_guid), unk1, unk2, unk3, unk4, description.c_str()); -} - -void WorldSession::HandleRealmSplitOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_REALM_SPLIT"); - - uint32 unk; - std::string split_date = "01/01/01"; - recv_data >> unk; - - WorldPacket data(SMSG_REALM_SPLIT, 4+4+split_date.size()+1); - data << unk; - data << uint32(0x00000000); // realm split state - // split states: - // 0x0 realm normal - // 0x1 realm split - // 0x2 realm split pending - data << split_date; - SendPacket(&data); - //sLog.outDebug("response sent %u", unk); -} - -void WorldSession::HandleFarSightOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_FAR_SIGHT"); - //recv_data.hexlike(); - - uint8 apply; - recv_data >> apply; - - switch(apply) - { - case 0: - sLog.outDebug("Player %u set vision to self", _player->GetGUIDLow()); - _player->SetSeer(_player); - break; - case 1: - sLog.outDebug("Added FarSight " I64FMT " to player %u", _player->GetUInt64Value(PLAYER_FARSIGHT), _player->GetGUIDLow()); - if (WorldObject *target = _player->GetViewpoint()) - _player->SetSeer(target); - else - sLog.outError("Player %s requests non-existing seer", _player->GetName()); - break; - default: - sLog.outDebug("Unhandled mode in CMSG_FAR_SIGHT: %u", apply); - return; - } - - GetPlayer()->UpdateVisibilityForPlayer(); -} - -void WorldSession::HandleSetTitleOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_SET_TITLE"); - - int32 title; - recv_data >> title; - - // -1 at none - if (title > 0 && title < MAX_TITLE_INDEX) - { - if (!GetPlayer()->HasTitle(title)) - return; - } - else - title = 0; - - GetPlayer()->SetUInt32Value(PLAYER_CHOSEN_TITLE, title); -} - -void WorldSession::HandleTimeSyncResp(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_TIME_SYNC_RESP"); - - uint32 counter, clientTicks; - recv_data >> counter >> clientTicks; - - if (counter != _player->m_timeSyncCounter - 1) - sLog.outDebug("Wrong time sync counter from player %s (cheater?)", _player->GetName()); - - sLog.outDebug("Time sync received: counter %u, client ticks %u, time since last sync %u", counter, clientTicks, clientTicks - _player->m_timeSyncClient); - - uint32 ourTicks = clientTicks + (getMSTime() - _player->m_timeSyncServer); - - // diff should be small - sLog.outDebug("Our ticks: %u, diff %u, latency %u", ourTicks, ourTicks - clientTicks, GetLatency()); - - _player->m_timeSyncClient = clientTicks; -} - -void WorldSession::HandleResetInstancesOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("WORLD: CMSG_RESET_INSTANCES"); - Group *pGroup = _player->GetGroup(); - if (pGroup) - { - if (pGroup->IsLeader(_player->GetGUID())) - { - pGroup->ResetInstances(INSTANCE_RESET_ALL, false, _player); - pGroup->ResetInstances(INSTANCE_RESET_ALL, true,_player); - } - } - else - { - _player->ResetInstances(INSTANCE_RESET_ALL, false); - _player->ResetInstances(INSTANCE_RESET_ALL, true); - } -} - -void WorldSession::HandleSetDungeonDifficultyOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("MSG_SET_DUNGEON_DIFFICULTY"); - - uint32 mode; - recv_data >> mode; - - if (mode >= MAX_DUNGEON_DIFFICULTY) - { - sLog.outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode); - return; - } - - if (Difficulty(mode) == _player->GetDungeonDifficulty()) - return; - - // cannot reset while in an instance - Map *map = _player->GetMap(); - if (map && map->IsDungeon()) - { - sLog.outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); - return; - } - - if (_player->getLevel() < LEVELREQUIREMENT_HEROIC) - return; - - Group *pGroup = _player->GetGroup(); - if (pGroup) - { - if (pGroup->IsLeader(_player->GetGUID())) - { - for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* pGroupGuy = itr->getSource(); - if (!pGroupGuy) - continue; - - if (!pGroupGuy->IsInMap(pGroupGuy)) - return; - - map = pGroupGuy->GetMap(); - if (map && map->IsNonRaidDungeon()) - { - sLog.outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); - return; - } - } - // the difficulty is set even if the instances can't be reset - //_player->SendDungeonDifficulty(true); - pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false, _player); - pGroup->SetDungeonDifficulty(Difficulty(mode)); - } - } - else - { - _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false); - _player->SetDungeonDifficulty(Difficulty(mode)); - } -} - -void WorldSession::HandleSetRaidDifficultyOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("MSG_SET_RAID_DIFFICULTY"); - - uint32 mode; - recv_data >> mode; - - if (mode >= MAX_RAID_DIFFICULTY) - { - sLog.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode); - return; - } - - // cannot reset while in an instance - Map *map = _player->GetMap(); - if (map && map->IsDungeon()) - { - sLog.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); - return; - } - - if (Difficulty(mode) == _player->GetRaidDifficulty()) - return; - - if (_player->getLevel() < LEVELREQUIREMENT_HEROIC) - return; - - Group *pGroup = _player->GetGroup(); - if (pGroup) - { - if (pGroup->IsLeader(_player->GetGUID())) - { - for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* pGroupGuy = itr->getSource(); - if (!pGroupGuy) - continue; - - if (!pGroupGuy->IsInMap(pGroupGuy)) - return; - - map = pGroupGuy->GetMap(); - if (map && map->IsRaid()) - { - sLog.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); - return; - } - } - // the difficulty is set even if the instances can't be reset - //_player->SendDungeonDifficulty(true); - pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true, _player); - pGroup->SetRaidDifficulty(Difficulty(mode)); - } - } - else - { - _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true); - _player->SetRaidDifficulty(Difficulty(mode)); - } -} - -void WorldSession::HandleCancelMountAuraOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("WORLD: CMSG_CANCEL_MOUNT_AURA"); - - //If player is not mounted, so go out :) - if (!_player->IsMounted()) // not blizz like; no any messages on blizz - { - ChatHandler(this).SendSysMessage(LANG_CHAR_NON_MOUNTED); - return; - } - - if (_player->isInFlight()) // not blizz like; no any messages on blizz - { - ChatHandler(this).SendSysMessage(LANG_YOU_IN_FLIGHT); - return; - } - - _player->Unmount(); - _player->RemoveAurasByType(SPELL_AURA_MOUNTED); -} - -void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket & recv_data) -{ - // fly mode on/off - sLog.outDebug("WORLD: CMSG_MOVE_SET_CAN_FLY_ACK"); - //recv_data.hexlike(); - - uint64 guid; // guid - unused - if (!recv_data.readPackGUID(guid)) - return; - - recv_data.read_skip(); // unk - - MovementInfo movementInfo; - movementInfo.guid = guid; - ReadMovementInfo(recv_data, &movementInfo); - - recv_data.read_skip(); // unk2 - - _player->m_mover->m_movementInfo.flags = movementInfo.GetMovementFlags(); -} - -void WorldSession::HandleRequestPetInfoOpcode(WorldPacket & /*recv_data */) -{ - /* - sLog.outDebug("WORLD: CMSG_REQUEST_PET_INFO"); - recv_data.hexlike(); - */ -} - -void WorldSession::HandleSetTaxiBenchmarkOpcode(WorldPacket & recv_data) -{ - uint8 mode; - recv_data >> mode; - - sLog.outDebug("Client used \"/timetest %d\" command", mode); -} - -void WorldSession::HandleQueryInspectAchievements(WorldPacket & recv_data) -{ - uint64 guid; - if (!recv_data.readPackGUID(guid)) - return; - - Player *player = objmgr.GetPlayer(guid); - if (!player) - return; - - player->GetAchievementMgr().SendRespondInspectAchievements(_player); -} - -void WorldSession::HandleWorldStateUITimerUpdate(WorldPacket& /*recv_data*/) -{ - // empty opcode - sLog.outDebug("WORLD: CMSG_WORLD_STATE_UI_TIMER_UPDATE"); - - WorldPacket data(SMSG_WORLD_STATE_UI_TIMER_UPDATE, 4); - data << uint32(time(NULL)); - SendPacket(&data); -} - -void WorldSession::HandleReadyForAccountDataTimes(WorldPacket& /*recv_data*/) -{ - // empty opcode - sLog.outDebug("WORLD: CMSG_READY_FOR_ACCOUNT_DATA_TIMES"); - - SendAccountDataTimes(GLOBAL_CACHE_MASK); -} - -void WorldSession::SendSetPhaseShift(uint32 PhaseShift) -{ - WorldPacket data(SMSG_SET_PHASE_SHIFT, 4); - data << uint32(PhaseShift); - SendPacket(&data); -} diff --git a/src/server/game/Entities/Player/PetitionsHandler.cpp b/src/server/game/Entities/Player/PetitionsHandler.cpp deleted file mode 100644 index 7f578c22656..00000000000 --- a/src/server/game/Entities/Player/PetitionsHandler.cpp +++ /dev/null @@ -1,938 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Language.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectMgr.h" -#include "Log.h" -#include "Opcodes.h" -#include "Guild.h" -#include "ArenaTeam.h" -#include "GossipDef.h" -#include "SocialMgr.h" - -/*enum PetitionType // dbc data -{ - PETITION_TYPE_GUILD = 1, - PETITION_TYPE_ARENA_TEAM = 3 -};*/ - -// Charters ID in item_template -#define GUILD_CHARTER 5863 -#define GUILD_CHARTER_COST 1000 // 10 S -#define ARENA_TEAM_CHARTER_2v2 23560 -#define ARENA_TEAM_CHARTER_2v2_COST 800000 // 80 G -#define ARENA_TEAM_CHARTER_3v3 23561 -#define ARENA_TEAM_CHARTER_3v3_COST 1200000 // 120 G -#define ARENA_TEAM_CHARTER_5v5 23562 -#define ARENA_TEAM_CHARTER_5v5_COST 2000000 // 200 G - -void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("Received opcode CMSG_PETITION_BUY"); - recv_data.hexlike(); - - uint64 guidNPC; - uint32 clientIndex; // 1 for guild and arenaslot+1 for arenas in client - std::string name; - - recv_data >> guidNPC; // NPC GUID - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data >> name; // name - recv_data.read_skip(); // some string - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - - for (int i = 0; i < 10; ++i) - recv_data.read_skip(); - - recv_data >> clientIndex; // index - recv_data.read_skip(); // 0 - - sLog.outDebug("Petitioner with GUID %u tried sell petition: name %s", GUID_LOPART(guidNPC), name.c_str()); - - // prevent cheating - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guidNPC,UNIT_NPC_FLAG_PETITIONER); - if (!pCreature) - { - sLog.outDebug("WORLD: HandlePetitionBuyOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(guidNPC)); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - uint32 charterid = 0; - uint32 cost = 0; - uint32 type = 0; - if (pCreature->isTabardDesigner()) - { - // if tabard designer, then trying to buy a guild charter. - // do not let if already in guild. - if (_player->GetGuildId()) - return; - - charterid = GUILD_CHARTER; - cost = GUILD_CHARTER_COST; - type = 9; - } - else - { - // TODO: find correct opcode - if (_player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - SendNotification(LANG_ARENA_ONE_TOOLOW, sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)); - return; - } - - switch(clientIndex) // arenaSlot+1 as received from client (1 from 3 case) - { - case 1: - charterid = ARENA_TEAM_CHARTER_2v2; - cost = ARENA_TEAM_CHARTER_2v2_COST; - type = 2; // 2v2 - break; - case 2: - charterid = ARENA_TEAM_CHARTER_3v3; - cost = ARENA_TEAM_CHARTER_3v3_COST; - type = 3; // 3v3 - break; - case 3: - charterid = ARENA_TEAM_CHARTER_5v5; - cost = ARENA_TEAM_CHARTER_5v5_COST; - type = 5; // 5v5 - break; - default: - sLog.outDebug("unknown selection at buy arena petition: %u", clientIndex); - return; - } - - if (_player->GetArenaTeamId(clientIndex - 1)) // arenaSlot+1 as received from client - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM); - return; - } - } - - if (type == 9) - { - if (objmgr.GetGuildByName(name)) - { - SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_EXISTS_S); - return; - } - if (objmgr.IsReservedName(name) || !ObjectMgr::IsValidCharterName(name)) - { - SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_INVALID); - return; - } - } - else - { - if (objmgr.GetArenaTeamByName(name)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S); - return; - } - if (objmgr.IsReservedName(name) || !ObjectMgr::IsValidCharterName(name)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID); - return; - } - } - - ItemPrototype const *pProto = objmgr.GetItemPrototype(charterid); - if (!pProto) - { - _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, charterid, 0); - return; - } - - if (_player->GetMoney() < cost) - { //player hasn't got enough money - _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, charterid, 0); - return; - } - - ItemPosCountVec dest; - uint8 msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterid, pProto->BuyCount); - if (msg != EQUIP_ERR_OK) - { - _player->SendBuyError(msg, pCreature, charterid, 0); - return; - } - - _player->ModifyMoney(-(int32)cost); - Item *charter = _player->StoreNewItem(dest, charterid, true); - if (!charter) - return; - - charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1, charter->GetGUIDLow()); - // ITEM_FIELD_ENCHANTMENT_1_1 is guild/arenateam id - // ITEM_FIELD_ENCHANTMENT_1_1+1 is current signatures count (showed on item) - charter->SetState(ITEM_CHANGED, _player); - _player->SendNewItem(charter, 1, true, false); - - // a petition is invalid, if both the owner and the type matches - // we checked above, if this player is in an arenateam, so this must be - // datacorruption - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE ownerguid = '%u' AND type = '%u'", _player->GetGUIDLow(), type); - - std::ostringstream ssInvalidPetitionGUIDs; - - if (result) - { - do - { - Field *fields = result->Fetch(); - ssInvalidPetitionGUIDs << "'" << fields[0].GetUInt32() << "' , "; - } while (result->NextRow()); - } - - // delete petitions with the same guid as this one - ssInvalidPetitionGUIDs << "'" << charter->GetGUIDLow() << "'"; - - sLog.outDebug("Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str()); - CharacterDatabase.escape_string(name); - CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); - CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); - CharacterDatabase.PExecute("INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES ('%u', '%u', '%s', '%u')", - _player->GetGUIDLow(), charter->GetGUIDLow(), name.c_str(), type); - CharacterDatabase.CommitTransaction(); -} - -void WorldSession::HandlePetitionShowSignOpcode(WorldPacket & recv_data) -{ - // ok - sLog.outDebug("Received opcode CMSG_PETITION_SHOW_SIGNATURES"); - //recv_data.hexlike(); - - uint8 signs = 0; - uint64 petitionguid; - recv_data >> petitionguid; // petition guid - - // solve (possible) some strange compile problems with explicit use GUID_LOPART(petitionguid) at some GCC versions (wrong code optimization in compiler?) - uint32 petitionguid_low = GUID_LOPART(petitionguid); - - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", petitionguid_low); - if (!result) - { - sLog.outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName()); - return; - } - Field *fields = result->Fetch(); - uint32 type = fields[0].GetUInt32(); - - // if guild petition and has guild => error, return; - if (type == 9 && _player->GetGuildId()) - return; - - result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", petitionguid_low); - - // result == NULL also correct in case no sign yet - if (result) - signs = result->GetRowCount(); - - sLog.outDebug("CMSG_PETITION_SHOW_SIGNATURES petition entry: '%u'", petitionguid_low); - - WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+1+signs*12)); - data << uint64(petitionguid); // petition guid - data << uint64(_player->GetGUID()); // owner guid - data << uint32(petitionguid_low); // guild guid (in mangos always same as GUID_LOPART(petitionguid) - data << uint8(signs); // sign's count - - for (uint8 i = 1; i <= signs; ++i) - { - Field *fields2 = result->Fetch(); - uint64 plguid = fields2[0].GetUInt64(); - - data << uint64(plguid); // Player GUID - data << (uint32)0; // there 0 ... - - result->NextRow(); - } - SendPacket(&data); -} - -void WorldSession::HandlePetitionQueryOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("Received opcode CMSG_PETITION_QUERY"); // ok - //recv_data.hexlike(); - - uint32 guildguid; - uint64 petitionguid; - recv_data >> guildguid; // in Trinity always same as GUID_LOPART(petitionguid) - recv_data >> petitionguid; // petition guid - sLog.outDebug("CMSG_PETITION_QUERY Petition GUID %u Guild GUID %u", GUID_LOPART(petitionguid), guildguid); - - SendPetitionQueryOpcode(petitionguid); -} - -void WorldSession::SendPetitionQueryOpcode(uint64 petitionguid) -{ - uint64 ownerguid = 0; - uint32 type; - std::string name = "NO_NAME_FOR_GUID"; - uint8 signs = 0; - - QueryResult_AutoPtr result = CharacterDatabase.PQuery( - "SELECT ownerguid, name, " - " (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs, " - " type " - "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid)); - - if (result) - { - Field* fields = result->Fetch(); - ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); - name = fields[1].GetCppString(); - signs = fields[2].GetUInt8(); - type = fields[3].GetUInt32(); - } - else - { - sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid)); - return; - } - - WorldPacket data(SMSG_PETITION_QUERY_RESPONSE, (4+8+name.size()+1+1+4*12+2+10)); - data << uint32(GUID_LOPART(petitionguid)); // guild/team guid (in Trinity always same as GUID_LOPART(petition guid) - data << uint64(ownerguid); // charter owner guid - data << name; // name (guild/arena team) - data << uint8(0); // some string - if (type == 9) - { - data << uint32(9); - data << uint32(9); - data << uint32(0); // bypass client - side limitation, a different value is needed here for each petition - } - else - { - data << uint32(type-1); - data << uint32(type-1); - data << uint32(type); // bypass client - side limitation, a different value is needed here for each petition - } - data << uint32(0); // 5 - data << uint32(0); // 6 - data << uint32(0); // 7 - data << uint32(0); // 8 - data << uint16(0); // 9 2 bytes field - data << uint32(0); // 10 - data << uint32(0); // 11 - data << uint32(0); // 13 count of next strings? - - for (int i = 0; i < 10; ++i) - data << uint8(0); // some string - - data << uint32(0); // 14 - - if (type == 9) - data << uint32(0); // 15 0 - guild, 1 - arena team - else - data << uint32(1); - - SendPacket(&data); -} - -void WorldSession::HandlePetitionRenameOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("Received opcode MSG_PETITION_RENAME"); // ok - //recv_data.hexlike(); - - uint64 petitionguid; - uint32 type; - std::string newname; - - recv_data >> petitionguid; // guid - recv_data >> newname; // new name - - Item *item = _player->GetItemByGuid(petitionguid); - if (!item) - return; - - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); - - if (result) - { - Field* fields = result->Fetch(); - type = fields[0].GetUInt32(); - } - else - { - sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid)); - return; - } - - if (type == 9) - { - if (objmgr.GetGuildByName(newname)) - { - SendGuildCommandResult(GUILD_CREATE_S, newname, ERR_GUILD_NAME_EXISTS_S); - return; - } - if (objmgr.IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname)) - { - SendGuildCommandResult(GUILD_CREATE_S, newname, ERR_GUILD_NAME_INVALID); - return; - } - } - else - { - if (objmgr.GetArenaTeamByName(newname)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_EXISTS_S); - return; - } - if (objmgr.IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_INVALID); - return; - } - } - - std::string db_newname = newname; - CharacterDatabase.escape_string(db_newname); - CharacterDatabase.PExecute("UPDATE petition SET name = '%s' WHERE petitionguid = '%u'", - db_newname.c_str(), GUID_LOPART(petitionguid)); - - sLog.outDebug("Petition (GUID: %u) renamed to '%s'", GUID_LOPART(petitionguid), newname.c_str()); - WorldPacket data(MSG_PETITION_RENAME, (8+newname.size()+1)); - data << uint64(petitionguid); - data << newname; - SendPacket(&data); -} - -void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("Received opcode CMSG_PETITION_SIGN"); // ok - //recv_data.hexlike(); - - Field *fields; - uint64 petitionguid; - uint8 unk; - recv_data >> petitionguid; // petition guid - recv_data >> unk; - - QueryResult_AutoPtr result = CharacterDatabase.PQuery( - "SELECT ownerguid, " - " (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs, " - " type " - "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid)); - - if (!result) - { - sLog.outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName()); - return; - } - - fields = result->Fetch(); - uint64 ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); - uint8 signs = fields[1].GetUInt8(); - uint32 type = fields[2].GetUInt32(); - - uint32 plguidlo = _player->GetGUIDLow(); - if (GUID_LOPART(ownerguid) == plguidlo) - return; - - // not let enemies sign guild charter - if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != objmgr.GetPlayerTeamByGUID(ownerguid)) - { - if (type != 9) - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); - else - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_NOT_ALLIED); - return; - } - - if (type != 9) - { - if (_player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", _player->GetName(), ERR_ARENA_TEAM_TARGET_TOO_LOW_S); - return; - } - - uint8 slot = ArenaTeam::GetSlotByType(type); - if (slot >= MAX_ARENA_SLOT) - return; - - if (_player->GetArenaTeamId(slot)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_IN_ARENA_TEAM_S); - return; - } - - if (_player->GetArenaTeamIdInvited()) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S); - return; - } - } - else - { - if (_player->GetGuildId()) - { - SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_IN_GUILD_S); - return; - } - if (_player->GetGuildIdInvited()) - { - SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_INVITED_TO_GUILD_S); - return; - } - } - - if (++signs > type) // client signs maximum - return; - - //client doesn't allow to sign petition two times by one character, but not check sign by another character from same account - //not allow sign another player from already sign player account - result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u' AND petitionguid = '%u'", GetAccountId(), GUID_LOPART(petitionguid)); - - if (result) - { - WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4)); - data << uint64(petitionguid); - data << uint64(_player->GetGUID()); - data << (uint32)PETITION_SIGN_ALREADY_SIGNED; - - // close at signer side - SendPacket(&data); - - // update for owner if online - if (Player *owner = objmgr.GetPlayer(ownerguid)) - owner->GetSession()->SendPacket(&data); - return; - } - - CharacterDatabase.PExecute("INSERT INTO petition_sign (ownerguid,petitionguid, playerguid, player_account) VALUES ('%u', '%u', '%u','%u')", GUID_LOPART(ownerguid),GUID_LOPART(petitionguid), plguidlo,GetAccountId()); - - sLog.outDebug("PETITION SIGN: GUID %u by player: %s (GUID: %u Account: %u)", GUID_LOPART(petitionguid), _player->GetName(),plguidlo,GetAccountId()); - - WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4)); - data << uint64(petitionguid); - data << uint64(_player->GetGUID()); - data << uint32(PETITION_SIGN_OK); - - // close at signer side - SendPacket(&data); - - // update signs count on charter, required testing... - //Item *item = _player->GetItemByGuid(petitionguid)); - //if (item) - // item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1+1, signs); - - // update for owner if online - if (Player *owner = objmgr.GetPlayer(ownerguid)) - owner->GetSession()->SendPacket(&data); -} - -void WorldSession::HandlePetitionDeclineOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("Received opcode MSG_PETITION_DECLINE"); // ok - //recv_data.hexlike(); - - uint64 petitionguid; - uint64 ownerguid; - recv_data >> petitionguid; // petition guid - sLog.outDebug("Petition %u declined by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow()); - - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT ownerguid FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); - if (!result) - return; - - Field *fields = result->Fetch(); - ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); - - Player *owner = objmgr.GetPlayer(ownerguid); - if (owner) // petition owner online - { - WorldPacket data(MSG_PETITION_DECLINE, 8); - data << uint64(_player->GetGUID()); - owner->GetSession()->SendPacket(&data); - } -} - -void WorldSession::HandleOfferPetitionOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("Received opcode CMSG_OFFER_PETITION"); // ok - //recv_data.hexlike(); - - uint8 signs = 0; - uint64 petitionguid, plguid; - uint32 type, junk; - Player *player; - recv_data >> junk; // this is not petition type! - recv_data >> petitionguid; // petition guid - recv_data >> plguid; // player guid - - player = ObjectAccessor::FindPlayer(plguid); - if (!player) - return; - - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); - if (!result) - return; - - Field *fields = result->Fetch(); - type = fields[0].GetUInt32(); - - sLog.outDebug("OFFER PETITION: type %u, GUID1 %u, to player id: %u", type, GUID_LOPART(petitionguid), GUID_LOPART(plguid)); - - if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam()) - { - if (type != 9) - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); - else - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_NOT_ALLIED); - return; - } - - if (type != 9) - { - if (player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - // player is too low level to join an arena team - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ARENA_TEAM_TARGET_TOO_LOW_S); - return; - } - - uint8 slot = ArenaTeam::GetSlotByType(type); - if (slot >= MAX_ARENA_SLOT) - return; - - if (player->GetArenaTeamId(slot)) - { - // player is already in an arena team - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ALREADY_IN_ARENA_TEAM_S); - return; - } - - if (player->GetArenaTeamIdInvited()) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S); - return; - } - } - else - { - if (player->GetGuildId()) - { - SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_IN_GUILD_S); - return; - } - - if (player->GetGuildIdInvited()) - { - SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_INVITED_TO_GUILD_S); - return; - } - } - - result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); - // result == NULL also correct charter without signs - if (result) - signs = result->GetRowCount(); - - WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+signs+signs*12)); - data << uint64(petitionguid); // petition guid - data << uint64(_player->GetGUID()); // owner guid - data << uint32(GUID_LOPART(petitionguid)); // guild guid (in mangos always same as GUID_LOPART(petition guid) - data << uint8(signs); // sign's count - - for (uint8 i = 1; i <= signs; ++i) - { - Field *fields2 = result->Fetch(); - plguid = fields2[0].GetUInt64(); - - data << uint64(plguid); // Player GUID - data << (uint32)0; // there 0 ... - - result->NextRow(); - } - - player->GetSession()->SendPacket(&data); -} - -void WorldSession::HandleTurnInPetitionOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("Received opcode CMSG_TURN_IN_PETITION"); // ok - //recv_data.hexlike(); - - WorldPacket data; - uint64 petitionguid; - - uint32 ownerguidlo; - uint32 type; - std::string name; - - recv_data >> petitionguid; - - sLog.outDebug("Petition %u turned in by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow()); - - // data - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT ownerguid, name, type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); - if (result) - { - Field *fields = result->Fetch(); - ownerguidlo = fields[0].GetUInt32(); - name = fields[1].GetCppString(); - type = fields[2].GetUInt32(); - } - else - { - sLog.outError("petition table has broken data!"); - return; - } - - if (type == 9) - { - if (_player->GetGuildId()) - { - data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); - data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild - _player->GetSession()->SendPacket(&data); - return; - } - } - else - { - uint8 slot = ArenaTeam::GetSlotByType(type); - if (slot >= MAX_ARENA_SLOT) - return; - - if (_player->GetArenaTeamId(slot)) - { - //data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); - //data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild - //_player->GetSession()->SendPacket(&data); - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM); - return; - } - } - - if (_player->GetGUIDLow() != ownerguidlo) - return; - - // signs - uint8 signs; - result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); - if (result) - signs = result->GetRowCount(); - else - signs = 0; - - uint32 count; - //if (signs < sWorld.getConfig(CONFIG_MIN_PETITION_SIGNS)) - if (type == 9) - count = sWorld.getConfig(CONFIG_MIN_PETITION_SIGNS); - else - count = type-1; - if (signs < count) - { - data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); - data << (uint32)PETITION_TURN_NEED_MORE_SIGNATURES; // need more signatures... - SendPacket(&data); - return; - } - - if (type == 9) - { - if (objmgr.GetGuildByName(name)) - { - SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_EXISTS_S); - return; - } - } - else - { - if (objmgr.GetArenaTeamByName(name)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S); - return; - } - } - - // and at last charter item check - Item *item = _player->GetItemByGuid(petitionguid); - if (!item) - return; - - // OK! - - // delete charter item - _player->DestroyItem(item->GetBagSlot(),item->GetSlot(), true); - - if (type == 9) // create guild - { - Guild* guild = new Guild; - if (!guild->Create(_player, name)) - { - delete guild; - return; - } - - // register guild and add guildmaster - objmgr.AddGuild(guild); - - // add members - for (uint8 i = 0; i < signs; ++i) - { - Field* fields = result->Fetch(); - guild->AddMember(fields[0].GetUInt64(), guild->GetLowestRank()); - result->NextRow(); - } - } - else // or arena team - { - ArenaTeam* at = new ArenaTeam; - if (!at->Create(_player->GetGUID(), type, name)) - { - sLog.outError("PetitionsHandler: arena team create failed."); - delete at; - return; - } - - uint32 icon, iconcolor, border, bordercolor, backgroud; - recv_data >> backgroud >> icon >> iconcolor >> border >> bordercolor; - - at->SetEmblem(backgroud, icon, iconcolor, border, bordercolor); - - // register team and add captain - objmgr.AddArenaTeam(at); - sLog.outDebug("PetitonsHandler: arena team added to objmrg"); - - // add members - for (uint8 i = 0; i < signs; ++i) - { - Field* fields = result->Fetch(); - uint64 memberGUID = fields[0].GetUInt64(); - sLog.outDebug("PetitionsHandler: adding arena member %u", GUID_LOPART(memberGUID)); - at->AddMember(memberGUID); - result->NextRow(); - } - } - - CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); - CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); - CharacterDatabase.CommitTransaction(); - - // created - sLog.outDebug("TURN IN PETITION GUID %u", GUID_LOPART(petitionguid)); - - data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); - data << (uint32)PETITION_TURN_OK; - SendPacket(&data); -} - -void WorldSession::HandlePetitionShowListOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("Received CMSG_PETITION_SHOWLIST"); // ok - //recv_data.hexlike(); - - uint64 guid; - recv_data >> guid; - - SendPetitionShowList(guid); -} - -void WorldSession::SendPetitionShowList(uint64 guid) -{ - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_PETITIONER); - if (!pCreature) - { - sLog.outDebug("WORLD: HandlePetitionShowListOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - uint8 count = 0; - if (pCreature->isTabardDesigner()) - count = 1; - else - count = 3; - - WorldPacket data(SMSG_PETITION_SHOWLIST, 8+1+4*6); - data << guid; // npc guid - data << count; // count - if (count == 1) - { - data << uint32(1); // index - data << uint32(GUILD_CHARTER); // charter entry - data << uint32(16161); // charter display id - data << uint32(GUILD_CHARTER_COST); // charter cost - data << uint32(0); // unknown - data << uint32(9); // required signs? - } - else - { - // 2v2 - data << uint32(1); // index - data << uint32(ARENA_TEAM_CHARTER_2v2); // charter entry - data << uint32(16161); // charter display id - data << uint32(ARENA_TEAM_CHARTER_2v2_COST); // charter cost - data << uint32(2); // unknown - data << uint32(2); // required signs? - // 3v3 - data << uint32(2); // index - data << uint32(ARENA_TEAM_CHARTER_3v3); // charter entry - data << uint32(16161); // charter display id - data << uint32(ARENA_TEAM_CHARTER_3v3_COST); // charter cost - data << uint32(3); // unknown - data << uint32(3); // required signs? - // 5v5 - data << uint32(3); // index - data << uint32(ARENA_TEAM_CHARTER_5v5); // charter entry - data << uint32(16161); // charter display id - data << uint32(ARENA_TEAM_CHARTER_5v5_COST); // charter cost - data << uint32(5); // unknown - data << uint32(5); // required signs? - } - //for (uint8 i = 0; i < count; ++i) - //{ - // data << uint32(i); // index - // data << uint32(GUILD_CHARTER); // charter entry - // data << uint32(16161); // charter display id - // data << uint32(GUILD_CHARTER_COST+i); // charter cost - // data << uint32(0); // unknown - // data << uint32(9); // required signs? - //} - SendPacket(&data); - sLog.outDebug("Sent SMSG_PETITION_SHOWLIST"); -} diff --git a/src/server/game/Entities/Player/TicketHandler.cpp b/src/server/game/Entities/Player/TicketHandler.cpp deleted file mode 100644 index 72ed25adbca..00000000000 --- a/src/server/game/Entities/Player/TicketHandler.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Language.h" -#include "WorldPacket.h" -#include "Common.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "World.h" - -void WorldSession::HandleGMTicketCreateOpcode(WorldPacket & recv_data) -{ - if (GetPlayer()->getLevel() < sWorld.getConfig(CONFIG_TICKET_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_TICKET_REQ), sWorld.getConfig(CONFIG_TICKET_LEVEL_REQ)); - return; - } - - if (GM_Ticket *ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID())) - { - WorldPacket data(SMSG_GMTICKET_CREATE, 4); - data << uint32(1); // 1 - You already have GM ticket - SendPacket(&data); - return; - } - - uint32 map; - float x, y, z; - std::string ticketText, ticketText2; - - SendQueryTimeResponse(); - - WorldPacket data(SMSG_GMTICKET_CREATE, 4); - recv_data >> map; - recv_data >> x; - recv_data >> y; - recv_data >> z; - recv_data >> ticketText; - recv_data >> ticketText2; - - GM_Ticket *ticket = new GM_Ticket; - ticket->name = GetPlayer()->GetName(); - ticket->guid = objmgr.GenerateGMTicketId(); - ticket->playerGuid = GetPlayer()->GetGUID(); - ticket->message = ticketText; - ticket->createtime = time(NULL); - ticket->map = map; - ticket->pos_x = x; - ticket->pos_y = y; - ticket->pos_z = z; - ticket->timestamp = time(NULL); - ticket->closed = 0; - ticket->assignedToGM = 0; - ticket->comment = ""; - - objmgr.AddOrUpdateGMTicket(*ticket, true); - - data << uint32(2); - SendPacket(&data); - - sWorld.SendGMText(LANG_COMMAND_TICKETNEW, GetPlayer()->GetName(), ticket->guid); - -} - -void WorldSession::HandleGMTicketUpdateOpcode(WorldPacket & recv_data) -{ - WorldPacket data(SMSG_GMTICKET_UPDATETEXT, 4); - - std::string message; - recv_data >> message; - - GM_Ticket *ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); - if (!ticket) - { - data << uint32(1); - SendPacket(&data); - return; - } - - ticket->message = message; - ticket->timestamp = time(NULL); - - objmgr.AddOrUpdateGMTicket(*ticket); - - data << uint32(2); - SendPacket(&data); - - sWorld.SendGMText(LANG_COMMAND_TICKETUPDATED, GetPlayer()->GetName(), ticket->guid); - -} - -void WorldSession::HandleGMTicketDeleteOpcode(WorldPacket & /*recv_data*/) -{ - GM_Ticket* ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); - - if (ticket) - { - WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4); - data << uint32(9); - SendPacket(&data); - - sWorld.SendGMText(LANG_COMMAND_TICKETPLAYERABANDON, GetPlayer()->GetName(), ticket->guid); - objmgr.RemoveGMTicket(ticket, GetPlayer()->GetGUID(), false); - SendGMTicketGetTicket(0x0A, 0); - } -} - -void WorldSession::HandleGMTicketGetTicketOpcode(WorldPacket & /*recv_data*/) -{ - SendQueryTimeResponse(); - - GM_Ticket *ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); - if (ticket) - SendGMTicketGetTicket(0x06, ticket->message.c_str()); - else - SendGMTicketGetTicket(0x0A, 0); - -} - -void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPacket & /*recv_data*/) -{ - WorldPacket data(SMSG_GMTICKET_SYSTEMSTATUS, 4); - data << uint32(1); - SendPacket(&data); -} - -void WorldSession::SendGMTicketGetTicket(uint32 status, char const* text) -{ - int len = text ? strlen(text) : 0; - WorldPacket data(SMSG_GMTICKET_GETTICKET, (4+len+1+4+2+4+4)); - data << uint32(status); // standard 0x0A, 0x06 if text present - data << uint32(1); // unk flags, if 0, can't edit the ticket - if (status == 6) - { - data << text; // ticket text - data << uint8(0x7); // ticket category - data << float(0); // tickets in queue? - data << float(0); // if > "tickets in queue" then "We are currently experiencing a high volume of petitions." - data << float(0); // 0 - "Your ticket will be serviced soon", 1 - "Wait time currently unavailable" - data << uint8(0); // if == 2 and next field == 1 then "Your ticket has been escalated" - data << uint8(0); // const - } - SendPacket(&data); -} diff --git a/src/server/game/Entities/Player/TradeHandler.cpp b/src/server/game/Entities/Player/TradeHandler.cpp deleted file mode 100644 index 448a6e0520d..00000000000 --- a/src/server/game/Entities/Player/TradeHandler.cpp +++ /dev/null @@ -1,656 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectAccessor.h" -#include "Log.h" -#include "Opcodes.h" -#include "Player.h" -#include "Item.h" -#include "SocialMgr.h" -#include "Language.h" - -enum TradeStatus -{ - TRADE_STATUS_BUSY = 0, - TRADE_STATUS_BEGIN_TRADE = 1, - TRADE_STATUS_OPEN_WINDOW = 2, - TRADE_STATUS_TRADE_CANCELED = 3, - TRADE_STATUS_TRADE_ACCEPT = 4, - TRADE_STATUS_BUSY_2 = 5, - TRADE_STATUS_NO_TARGET = 6, - TRADE_STATUS_BACK_TO_TRADE = 7, - TRADE_STATUS_TRADE_COMPLETE = 8, - // 9? - TRADE_STATUS_TARGET_TO_FAR = 10, - TRADE_STATUS_WRONG_FACTION = 11, - TRADE_STATUS_CLOSE_WINDOW = 12, - // 13? - TRADE_STATUS_IGNORE_YOU = 14, - TRADE_STATUS_YOU_STUNNED = 15, - TRADE_STATUS_TARGET_STUNNED = 16, - TRADE_STATUS_YOU_DEAD = 17, - TRADE_STATUS_TARGET_DEAD = 18, - TRADE_STATUS_YOU_LOGOUT = 19, - TRADE_STATUS_TARGET_LOGOUT = 20, - TRADE_STATUS_TRIAL_ACCOUNT = 21, // Trial accounts can not perform that action - TRADE_STATUS_ONLY_CONJURED = 22 // You can only trade conjured items... (cross realm BG related). -}; - -void WorldSession::SendTradeStatus(uint32 status) -{ - WorldPacket data; - - switch(status) - { - case TRADE_STATUS_BEGIN_TRADE: - data.Initialize(SMSG_TRADE_STATUS, 4+8); - data << uint32(status); - data << uint64(0); - break; - case TRADE_STATUS_OPEN_WINDOW: - data.Initialize(SMSG_TRADE_STATUS, 4+4); - data << uint32(status); - data << uint32(0); // added in 2.4.0 - break; - case TRADE_STATUS_CLOSE_WINDOW: - data.Initialize(SMSG_TRADE_STATUS, 4+4+1+4); - data << uint32(status); - data << uint32(0); - data << uint8(0); - data << uint32(0); - break; - case TRADE_STATUS_ONLY_CONJURED: - data.Initialize(SMSG_TRADE_STATUS, 4+1); - data << uint32(status); - data << uint8(0); - break; - default: - data.Initialize(SMSG_TRADE_STATUS, 4); - data << uint32(status); - break; - } - - SendPacket(&data); -} - -void WorldSession::HandleIgnoreTradeOpcode(WorldPacket& /*recvPacket*/) -{ - sLog.outDebug("WORLD: Ignore Trade %u",_player->GetGUIDLow()); - // recvPacket.print_storage(); -} - -void WorldSession::HandleBusyTradeOpcode(WorldPacket& /*recvPacket*/) -{ - sLog.outDebug("WORLD: Busy Trade %u",_player->GetGUIDLow()); - // recvPacket.print_storage(); -} - -void WorldSession::SendUpdateTrade() -{ - Item *item = NULL; - - if (!_player || !_player->pTrader) - return; - - // reset trade status - if (_player->acceptTrade) - { - _player->acceptTrade = false; - SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); - } - - if (_player->pTrader->acceptTrade) - { - _player->pTrader->acceptTrade = false; - _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); - } - - WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, (100)); // guess size - data << (uint8) 1; // can be different (only seen 0 and 1) - data << (uint32) 0; // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) - data << (uint32) TRADE_SLOT_COUNT; // trade slots count/number?, = next field in most cases - data << (uint32) TRADE_SLOT_COUNT; // trade slots count/number?, = prev field in most cases - data << (uint32) _player->pTrader->tradeGold; // trader gold - data << (uint32) 0; // spell casted on lowest slot item - - for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) - { - item = (_player->pTrader->tradeItems[i] != 0 ? _player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]) : NULL); - - data << (uint8) i; // trade slot number, if not specified, then end of packet - - if (item) - { - data << (uint32) item->GetProto()->ItemId; // entry - // display id - data << (uint32) item->GetProto()->DisplayInfoID; - // stack count - data << (uint32) item->GetUInt32Value(ITEM_FIELD_STACK_COUNT); - data << (uint32) 0; // probably gift=1, created_by=0? - // gift creator - data << (uint64) item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR); - data << (uint32) item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT); - for (uint8 j = 0; j < 3; ++j) - data << (uint32) 0; // enchantment id (permanent/gems?) - // creator - data << (uint64) item->GetUInt64Value(ITEM_FIELD_CREATOR); - data << (uint32) item->GetSpellCharges(); // charges - data << (uint32) item->GetItemSuffixFactor(); // SuffixFactor - // random properties id - data << (int32) item->GetItemRandomPropertyId(); - data << (uint32) item->GetProto()->LockID; // lock id - // max durability - data << (uint32) item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); - // durability - data << (uint32) item->GetUInt32Value(ITEM_FIELD_DURABILITY); - } - else - { - for (uint8 j = 0; j < 18; j++) - data << uint32(0); - } - } - SendPacket(&data); -} - -//============================================================== -// transfer the items to the players - -void WorldSession::moveItems(Item* myItems[], Item* hisItems[]) -{ - for (int i=0; ipTrader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, myItems[i], false) == EQUIP_ERR_OK); - bool playerCanTrade = (hisItems[i] == NULL || _player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, hisItems[i], false) == EQUIP_ERR_OK); - if (traderCanTrade && playerCanTrade) - { - // Ok, if trade item exists and can be stored - // If we trade in both directions we had to check, if the trade will work before we actually do it - // A roll back is not possible after we stored it - if (myItems[i]) - { - // logging - sLog.outDebug("partner storing: %u",myItems[i]->GetGUIDLow()); - if (_player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) - { - sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)", - _player->GetName(),_player->GetSession()->GetAccountId(), - myItems[i]->GetProto()->Name1,myItems[i]->GetEntry(),myItems[i]->GetCount(), - _player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId()); - } - - // store - _player->pTrader->MoveItemToInventory(traderDst, myItems[i], true, true); - } - if (hisItems[i]) - { - // logging - sLog.outDebug("player storing: %u",hisItems[i]->GetGUIDLow()); - if (_player->pTrader->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) - { - sLog.outCommand(_player->pTrader->GetSession()->GetAccountId(),"GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)", - _player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId(), - hisItems[i]->GetProto()->Name1,hisItems[i]->GetEntry(),hisItems[i]->GetCount(), - _player->GetName(),_player->GetSession()->GetAccountId()); - } - - // store - _player->MoveItemToInventory(playerDst, hisItems[i], true, true); - } - } - else - { - // in case of fatal error log error message - // return the already removed items to the original owner - if (myItems[i]) - { - if (!traderCanTrade) - sLog.outError("trader can't store item: %u",myItems[i]->GetGUIDLow()); - if (_player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, myItems[i], false) == EQUIP_ERR_OK) - _player->MoveItemToInventory(playerDst, myItems[i], true, true); - else - sLog.outError("player can't take item back: %u",myItems[i]->GetGUIDLow()); - } - // return the already removed items to the original owner - if (hisItems[i]) - { - if (!playerCanTrade) - sLog.outError("player can't store item: %u",hisItems[i]->GetGUIDLow()); - if (_player->pTrader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, hisItems[i], false) == EQUIP_ERR_OK) - _player->pTrader->MoveItemToInventory(traderDst, hisItems[i], true, true); - else - sLog.outError("trader can't take item back: %u",hisItems[i]->GetGUIDLow()); - } - } - } -} - -//============================================================== - -void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) -{ - Item *myItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; - Item *hisItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; - bool myCanCompleteTrade=true,hisCanCompleteTrade=true; - - if (!GetPlayer()->pTrader) - return; - - // not accept case incorrect money amount - if (_player->tradeGold > _player->GetMoney()) - { - SendNotification(LANG_NOT_ENOUGH_GOLD); - _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); - _player->acceptTrade = false; - return; - } - - // not accept case incorrect money amount - if (_player->pTrader->tradeGold > _player->pTrader->GetMoney()) - { - _player->pTrader->GetSession()->SendNotification(LANG_NOT_ENOUGH_GOLD); - SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); - _player->pTrader->acceptTrade = false; - return; - } - - // not accept if some items now can't be trade (cheating) - for (int i=0; itradeItems[i] != 0) - { - if (Item* item =_player->GetItemByGuid(_player->tradeItems[i])) - { - if (!item->CanBeTraded()) - { - SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); - return; - } - } - } - if (_player->pTrader->tradeItems[i] != 0) - { - if (Item* item =_player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i])) - { - if (!item->CanBeTraded()) - { - SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); - return; - } - } - } - } - - _player->acceptTrade = true; - if (_player->pTrader->acceptTrade) - { - // inform partner client - _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); - - // store items in local list and set 'in-trade' flag - for (int i=0; itradeItems[i] != 0) - { - //Can return NULL - myItems[i] = _player->GetItemByGuid(_player->tradeItems[i]); - if (myItems[i]) - { - myItems[i]->SetInTrade(); - sLog.outDebug("Player trade item bag: %u slot: %u", myItems[i]->GetBagSlot(), myItems[i]->GetSlot()); - } - } - if (_player->pTrader->tradeItems[i] != 0) - { - //Can return NULL - hisItems[i]=_player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]); - if (hisItems[i]) - { - hisItems[i]->SetInTrade(); - sLog.outDebug("Player trade item bag: %u slot: %u", hisItems[i]->GetBagSlot(), hisItems[i]->GetSlot()); - } - } - } - - // test if item will fit in each inventory - hisCanCompleteTrade = (_player->pTrader->CanStoreItems(myItems,TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK); - myCanCompleteTrade = (_player->CanStoreItems(hisItems,TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK); - - // clear 'in-trade' flag - for (int i=0; iSetInTrade(false); - if (hisItems[i]) hisItems[i]->SetInTrade(false); - } - - // in case of missing space report error - if (!myCanCompleteTrade) - { - SendNotification(LANG_NOT_FREE_TRADE_SLOTS); - GetPlayer()->pTrader->GetSession()->SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); - SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); - _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); - return; - } - else if (!hisCanCompleteTrade) - { - SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); - GetPlayer()->pTrader->GetSession()->SendNotification(LANG_NOT_FREE_TRADE_SLOTS); - SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); - _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); - return; - } - - // execute trade: 1. remove - for (int i=0; iSetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); - iPtr = _player->GetItemByGuid(_player->tradeItems[i]); - _player->MoveItemFromInventory(iPtr->GetBagSlot(), iPtr->GetSlot(), true); - } - if (hisItems[i]) - { - hisItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR,_player->pTrader->GetGUID()); - iPtr = _player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]); - _player->pTrader->MoveItemFromInventory(iPtr->GetBagSlot(), iPtr->GetSlot(), true); - } - } - - // execute trade: 2. store - moveItems(myItems, hisItems); - - // logging money - if (sWorld.getConfig(CONFIG_GM_LOG_TRADE)) - { - if (_player->GetSession()->GetSecurity() > SEC_PLAYER && _player->tradeGold > 0) - { - sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", - _player->GetName(),_player->GetSession()->GetAccountId(), - _player->tradeGold, - _player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId()); - } - if (_player->pTrader->GetSession()->GetSecurity() > SEC_PLAYER && _player->pTrader->tradeGold > 0) - { - sLog.outCommand(_player->pTrader->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", - _player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId(), - _player->pTrader->tradeGold, - _player->GetName(),_player->GetSession()->GetAccountId()); - } - } - - // update money - _player->ModifyMoney(-int32(_player->tradeGold)); - _player->ModifyMoney(_player->pTrader->tradeGold); - _player->pTrader->ModifyMoney(-int32(_player->pTrader->tradeGold)); - _player->pTrader->ModifyMoney(_player->tradeGold); - - _player->ClearTrade(); - _player->pTrader->ClearTrade(); - - // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards) - CharacterDatabase.BeginTransaction(); - _player->SaveInventoryAndGoldToDB(); - _player->pTrader->SaveInventoryAndGoldToDB(); - CharacterDatabase.CommitTransaction(); - - _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); - SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); - - _player->pTrader->pTrader = NULL; - _player->pTrader = NULL; - } - else - { - _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); - } -} - -void WorldSession::HandleUnacceptTradeOpcode(WorldPacket& /*recvPacket*/) -{ - if (!GetPlayer()->pTrader) - return; - - _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); - _player->acceptTrade = false; -} - -void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/) -{ - if (!_player->pTrader) - return; - - _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_OPEN_WINDOW); - _player->pTrader->ClearTrade(); - - SendTradeStatus(TRADE_STATUS_OPEN_WINDOW); - _player->ClearTrade(); -} - -void WorldSession::SendCancelTrade() -{ - SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); -} - -void WorldSession::HandleCancelTradeOpcode(WorldPacket& /*recvPacket*/) -{ - // sended also after LOGOUT COMPLETE - if (_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT - _player->TradeCancel(true); -} - -void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) -{ - if (GetPlayer()->pTrader) - return; - - uint64 ID; - - if (!GetPlayer()->isAlive()) - { - SendTradeStatus(TRADE_STATUS_YOU_DEAD); - return; - } - - if (GetPlayer()->hasUnitState(UNIT_STAT_STUNNED)) - { - SendTradeStatus(TRADE_STATUS_YOU_STUNNED); - return; - } - - if (isLogingOut()) - { - SendTradeStatus(TRADE_STATUS_YOU_LOGOUT); - return; - } - - if (GetPlayer()->isInFlight()) - { - SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); - return; - } - - if (GetPlayer()->getLevel() < sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_TRADE_REQ), sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ)); - return; - } - - recvPacket >> ID; - - Player* pOther = ObjectAccessor::FindPlayer(ID); - - if (!pOther) - { - SendTradeStatus(TRADE_STATUS_NO_TARGET); - return; - } - - if (pOther == GetPlayer() || pOther->pTrader) - { - SendTradeStatus(TRADE_STATUS_BUSY); - return; - } - - if (!pOther->isAlive()) - { - SendTradeStatus(TRADE_STATUS_TARGET_DEAD); - return; - } - - if (pOther->isInFlight()) - { - SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); - return; - } - - if (pOther->hasUnitState(UNIT_STAT_STUNNED)) - { - SendTradeStatus(TRADE_STATUS_TARGET_STUNNED); - return; - } - - if (pOther->GetSession()->isLogingOut()) - { - SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT); - return; - } - - if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) - { - SendTradeStatus(TRADE_STATUS_IGNORE_YOU); - return; - } - - if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && pOther->GetTeam() !=_player->GetTeam()) - { - SendTradeStatus(TRADE_STATUS_WRONG_FACTION); - return; - } - - if (!pOther->IsWithinDistInMap(_player,10.0f,false)) - { - SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); - return; - } - - if (pOther->getLevel() < sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_TRADE_OTHER_REQ), sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ)); - return; - } - - // OK start trade - _player->pTrader = pOther; - pOther->pTrader =_player; - - WorldPacket data(SMSG_TRADE_STATUS, 12); - data << (uint32) TRADE_STATUS_BEGIN_TRADE; - data << (uint64)_player->GetGUID(); - _player->pTrader->GetSession()->SendPacket(&data); -} - -void WorldSession::HandleSetTradeGoldOpcode(WorldPacket& recvPacket) -{ - if (!_player->pTrader) - return; - - uint32 gold; - - recvPacket >> gold; - - // gold can be incorrect, but this is checked at trade finished. - _player->tradeGold = gold; - - _player->pTrader->GetSession()->SendUpdateTrade(); -} - -void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket) -{ - if (!_player->pTrader) - return; - - // send update - uint8 tradeSlot; - uint8 bag; - uint8 slot; - - recvPacket >> tradeSlot; - recvPacket >> bag; - recvPacket >> slot; - - // invalid slot number - if (tradeSlot >= TRADE_SLOT_COUNT) - { - SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); - return; - } - - // check cheating, can't fail with correct client operations - Item* item = _player->GetItemByPos(bag,slot); - if (!item || (tradeSlot != TRADE_SLOT_NONTRADED && !item->CanBeTraded())) - { - SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); - return; - } - - uint64 iGUID = item->GetGUID(); - - // prevent place single item into many trade slots using cheating and client bugs - for (int i = 0; i < TRADE_SLOT_COUNT; ++i) - { - if (_player->tradeItems[i] == iGUID) - { - // cheating attempt - SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); - return; - } - } - - _player->tradeItems[tradeSlot] = iGUID; - - _player->pTrader->GetSession()->SendUpdateTrade(); -} - -void WorldSession::HandleClearTradeItemOpcode(WorldPacket& recvPacket) -{ - if (!_player->pTrader) - return; - - uint8 tradeSlot; - recvPacket >> tradeSlot; - - // invalid slot number - if (tradeSlot >= TRADE_SLOT_COUNT) - return; - - _player->tradeItems[tradeSlot] = 0; - - _player->pTrader->GetSession()->SendUpdateTrade(); -} - diff --git a/src/server/game/Entities/Player/VoiceChatHandler.cpp b/src/server/game/Entities/Player/VoiceChatHandler.cpp deleted file mode 100644 index 78aafe1999b..00000000000 --- a/src/server/game/Entities/Player/VoiceChatHandler.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" - -void WorldSession::HandleVoiceSessionEnableOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_VOICE_SESSION_ENABLE"); - // uint8 isVoiceEnabled, uint8 isMicrophoneEnabled - recv_data.read_skip(); - recv_data.read_skip(); - recv_data.hexlike(); -} - -void WorldSession::HandleChannelVoiceOnOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_CHANNEL_VOICE_ON"); - // Enable Voice button in channel context menu - recv_data.hexlike(); -} - -void WorldSession::HandleSetActiveVoiceChannel(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_SET_ACTIVE_VOICE_CHANNEL"); - recv_data.read_skip(); - recv_data.read_skip(); - recv_data.hexlike(); -} - diff --git a/src/server/game/Entities/Transport/Transports.cpp b/src/server/game/Entities/Transport/Transports.cpp new file mode 100644 index 00000000000..444e115f8b9 --- /dev/null +++ b/src/server/game/Entities/Transport/Transports.cpp @@ -0,0 +1,589 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" + +#include "Transports.h" +#include "MapManager.h" +#include "ObjectMgr.h" +#include "Path.h" + +#include "WorldPacket.h" +#include "DBCStores.h" +#include "ProgressBar.h" + +#include "World.h" + +void MapManager::LoadTransports() +{ + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, name, period FROM transports"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u transports", count); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + bar.step(); + + Transport *t = new Transport; + + Field *fields = result->Fetch(); + + uint32 entry = fields[0].GetUInt32(); + std::string name = fields[1].GetCppString(); + t->m_period = fields[2].GetUInt32(); + + const GameObjectInfo *goinfo = objmgr.GetGameObjectInfo(entry); + + if (!goinfo) + { + sLog.outErrorDb("Transport ID:%u, Name: %s, will not be loaded, gameobject_template missing", entry, name.c_str()); + delete t; + continue; + } + + if (goinfo->type != GAMEOBJECT_TYPE_MO_TRANSPORT) + { + sLog.outErrorDb("Transport ID:%u, Name: %s, will not be loaded, gameobject_template type wrong", entry, name.c_str()); + delete t; + continue; + } + + // sLog.outString("Loading transport %d between %s, %s", entry, name.c_str(), goinfo->name); + + std::set mapsUsed; + + if (!t->GenerateWaypoints(goinfo->moTransport.taxiPathId, mapsUsed)) + // skip transports with empty waypoints list + { + sLog.outErrorDb("Transport (path id %u) path size = 0. Transport ignored, check DBC files or transport GO data0 field.",goinfo->moTransport.taxiPathId); + delete t; + continue; + } + + float x, y, z, o; + uint32 mapid; + x = t->m_WayPoints[0].x; y = t->m_WayPoints[0].y; z = t->m_WayPoints[0].z; mapid = t->m_WayPoints[0].mapid; o = 1; + + // creates the Gameobject + if (!t->Create(entry, mapid, x, y, z, o, 100, 0)) + { + delete t; + continue; + } + + m_Transports.insert(t); + + for (std::set::const_iterator i = mapsUsed.begin(); i != mapsUsed.end(); ++i) + m_TransportsByMap[*i].insert(t); + + //If we someday decide to use the grid to track transports, here: + t->SetMap(MapManager::Instance().CreateMap(mapid, t, 0)); + + //t->GetMap()->Add((GameObject *)t); + ++count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u transports", count); + + // check transport data DB integrity + result = WorldDatabase.Query("SELECT gameobject.guid,gameobject.id,transports.name FROM gameobject,transports WHERE gameobject.id = transports.entry"); + if (result) // wrong data found + { + do + { + Field *fields = result->Fetch(); + + uint32 guid = fields[0].GetUInt32(); + uint32 entry = fields[1].GetUInt32(); + std::string name = fields[2].GetCppString(); + sLog.outErrorDb("Transport %u '%s' have record (GUID: %u) in `gameobject`. Transports DON'T must have any records in `gameobject` or its behavior will be unpredictable/bugged.",entry,name.c_str(),guid); + } + while (result->NextRow()); + } +} + +Transport::Transport() : GameObject() +{ + m_updateFlag = (UPDATEFLAG_TRANSPORT | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_ROTATION); +} + +bool Transport::Create(uint32 guidlow, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags) +{ + Relocate(x,y,z,ang); + // instance id and phaseMask isn't set to values different from std. + + if (!IsPositionValid()) + { + sLog.outError("Transport (GUID: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", + guidlow,x,y); + return false; + } + + Object::_Create(guidlow, 0, HIGHGUID_MO_TRANSPORT); + + GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(guidlow); + + if (!goinfo) + { + sLog.outErrorDb("Transport not created: entry in `gameobject_template` not found, guidlow: %u map: %u (X: %f Y: %f Z: %f) ang: %f",guidlow, mapid, x, y, z, ang); + return false; + } + + m_goInfo = goinfo; + + SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size); + + SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction); + //SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags); + SetUInt32Value(GAMEOBJECT_FLAGS, MAKE_PAIR32(0x28, 0x64)); + SetUInt32Value(GAMEOBJECT_LEVEL, m_period); + SetEntry(goinfo->id); + + SetUInt32Value(GAMEOBJECT_DISPLAYID, goinfo->displayId); + + SetGoState(GO_STATE_READY); + SetGoType(GameobjectTypes(goinfo->type)); + + SetGoAnimProgress(animprogress); + if (dynflags) + SetUInt32Value(GAMEOBJECT_DYNAMIC, MAKE_PAIR32(0, dynflags)); + + SetName(goinfo->name); + + return true; +} + +struct keyFrame +{ + keyFrame(float _x, float _y, float _z, uint32 _mapid, int _actionflag, int _delay) + { + x = _x; y = _y; z = _z; mapid = _mapid; actionflag = _actionflag; delay = _delay; distFromPrev = -1; distSinceStop = -1; distUntilStop = -1; + tFrom = 0; tTo = 0; + } + + float x; + float y; + float z; + uint32 mapid; + int actionflag; + int delay; + float distSinceStop; + float distUntilStop; + float distFromPrev; + float tFrom, tTo; +}; + +bool Transport::GenerateWaypoints(uint32 pathid, std::set &mapids) +{ + TransportPath path; + objmgr.GetTransportPathNodes(pathid, path); + + if (path.Empty()) + return false; + + std::vector keyFrames; + int mapChange = 0; + mapids.clear(); + for (size_t i = 1; i < path.Size() - 1; ++i) + { + if (mapChange == 0) + { + if ((path[i].mapid == path[i+1].mapid)) + { + keyFrame k(path[i].x, path[i].y, path[i].z, path[i].mapid, path[i].actionFlag, path[i].delay); + keyFrames.push_back(k); + mapids.insert(k.mapid); + } + else + { + mapChange = 1; + } + } + else + { + --mapChange; + } + } + + int lastStop = -1; + int firstStop = -1; + + // first cell is arrived at by teleportation :S + keyFrames[0].distFromPrev = 0; + if (keyFrames[0].actionflag == 2) + { + lastStop = 0; + } + + // find the rest of the distances between key points + for (size_t i = 1; i < keyFrames.size(); ++i) + { + if ((keyFrames[i].actionflag == 1) || (keyFrames[i].mapid != keyFrames[i-1].mapid)) + { + keyFrames[i].distFromPrev = 0; + } + else + { + keyFrames[i].distFromPrev = + sqrt(pow(keyFrames[i].x - keyFrames[i - 1].x, 2) + + pow(keyFrames[i].y - keyFrames[i - 1].y, 2) + + pow(keyFrames[i].z - keyFrames[i - 1].z, 2)); + } + if (keyFrames[i].actionflag == 2) + { + // remember first stop frame + if (firstStop == -1) + firstStop = i; + lastStop = i; + } + } + + float tmpDist = 0; + for (size_t i = 0; i < keyFrames.size(); ++i) + { + int j = (i + lastStop) % keyFrames.size(); + if (keyFrames[j].actionflag == 2) + tmpDist = 0; + else + tmpDist += keyFrames[j].distFromPrev; + keyFrames[j].distSinceStop = tmpDist; + } + + for (int i = int(keyFrames.size()) - 1; i >= 0; i--) + { + int j = (i + (firstStop+1)) % keyFrames.size(); + tmpDist += keyFrames[(j + 1) % keyFrames.size()].distFromPrev; + keyFrames[j].distUntilStop = tmpDist; + if (keyFrames[j].actionflag == 2) + tmpDist = 0; + } + + for (size_t i = 0; i < keyFrames.size(); ++i) + { + if (keyFrames[i].distSinceStop < (30 * 30 * 0.5f)) + keyFrames[i].tFrom = sqrt(2 * keyFrames[i].distSinceStop); + else + keyFrames[i].tFrom = ((keyFrames[i].distSinceStop - (30 * 30 * 0.5f)) / 30) + 30; + + if (keyFrames[i].distUntilStop < (30 * 30 * 0.5f)) + keyFrames[i].tTo = sqrt(2 * keyFrames[i].distUntilStop); + else + keyFrames[i].tTo = ((keyFrames[i].distUntilStop - (30 * 30 * 0.5f)) / 30) + 30; + + keyFrames[i].tFrom *= 1000; + keyFrames[i].tTo *= 1000; + } + + // for (int i = 0; i < keyFrames.size(); ++i) { + // sLog.outString("%f, %f, %f, %f, %f, %f, %f", keyFrames[i].x, keyFrames[i].y, keyFrames[i].distUntilStop, keyFrames[i].distSinceStop, keyFrames[i].distFromPrev, keyFrames[i].tFrom, keyFrames[i].tTo); + // } + + // Now we're completely set up; we can move along the length of each waypoint at 100 ms intervals + // speed = max(30, t) (remember x = 0.5s^2, and when accelerating, a = 1 unit/s^2 + int t = 0; + bool teleport = false; + if (keyFrames[keyFrames.size() - 1].mapid != keyFrames[0].mapid) + teleport = true; + + WayPoint pos(keyFrames[0].mapid, keyFrames[0].x, keyFrames[0].y, keyFrames[0].z, teleport, 0); + m_WayPoints[0] = pos; + t += keyFrames[0].delay * 1000; + + uint32 cM = keyFrames[0].mapid; + for (size_t i = 0; i < keyFrames.size() - 1; ++i) + { + float d = 0; + float tFrom = keyFrames[i].tFrom; + float tTo = keyFrames[i].tTo; + + // keep the generation of all these points; we use only a few now, but may need the others later + if (((d < keyFrames[i + 1].distFromPrev) && (tTo > 0))) + { + while ((d < keyFrames[i + 1].distFromPrev) && (tTo > 0)) + { + tFrom += 100; + tTo -= 100; + + if (d > 0) + { + float newX, newY, newZ; + newX = keyFrames[i].x + (keyFrames[i + 1].x - keyFrames[i].x) * d / keyFrames[i + 1].distFromPrev; + newY = keyFrames[i].y + (keyFrames[i + 1].y - keyFrames[i].y) * d / keyFrames[i + 1].distFromPrev; + newZ = keyFrames[i].z + (keyFrames[i + 1].z - keyFrames[i].z) * d / keyFrames[i + 1].distFromPrev; + + bool teleport = false; + if (keyFrames[i].mapid != cM) + { + teleport = true; + cM = keyFrames[i].mapid; + } + + // sLog.outString("T: %d, D: %f, x: %f, y: %f, z: %f", t, d, newX, newY, newZ); + WayPoint pos(keyFrames[i].mapid, newX, newY, newZ, teleport, i); + if (teleport) + m_WayPoints[t] = pos; + } + + if (tFrom < tTo) // caught in tFrom dock's "gravitational pull" + { + if (tFrom <= 30000) + { + d = 0.5f * (tFrom / 1000) * (tFrom / 1000); + } + else + { + d = 0.5f * 30 * 30 + 30 * ((tFrom - 30000) / 1000); + } + d = d - keyFrames[i].distSinceStop; + } + else + { + if (tTo <= 30000) + { + d = 0.5f * (tTo / 1000) * (tTo / 1000); + } + else + { + d = 0.5f * 30 * 30 + 30 * ((tTo - 30000) / 1000); + } + d = keyFrames[i].distUntilStop - d; + } + t += 100; + } + t -= 100; + } + + if (keyFrames[i + 1].tFrom > keyFrames[i + 1].tTo) + t += 100 - ((long)keyFrames[i + 1].tTo % 100); + else + t += (long)keyFrames[i + 1].tTo % 100; + + bool teleport = false; + if ((keyFrames[i + 1].actionflag == 1) || (keyFrames[i + 1].mapid != keyFrames[i].mapid)) + { + teleport = true; + cM = keyFrames[i + 1].mapid; + } + + WayPoint pos(keyFrames[i + 1].mapid, keyFrames[i + 1].x, keyFrames[i + 1].y, keyFrames[i + 1].z, teleport, i); + + // sLog.outString("T: %d, x: %f, y: %f, z: %f, t:%d", t, pos.x, pos.y, pos.z, teleport); +/* + if (keyFrames[i+1].delay > 5) + pos.delayed = true; +*/ + //if (teleport) + m_WayPoints[t] = pos; + + t += keyFrames[i + 1].delay * 1000; + // sLog.outString("------"); + } + + uint32 timer = t; + + // sLog.outDetail(" Generated %lu waypoints, total time %u.", (unsigned long)m_WayPoints.size(), timer); + + m_curr = m_WayPoints.begin(); + m_curr = GetNextWayPoint(); + m_next = GetNextWayPoint(); + m_pathTime = timer; + + m_nextNodeTime = m_curr->first; + + return true; +} + +Transport::WayPointMap::const_iterator Transport::GetNextWayPoint() +{ + WayPointMap::const_iterator iter = m_curr; + ++iter; + if (iter == m_WayPoints.end()) + iter = m_WayPoints.begin(); + return iter; +} + +void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z) +{ + Map const* oldMap = GetMap(); + Relocate(x, y, z); + + for (PlayerSet::const_iterator itr = m_passengers.begin(); itr != m_passengers.end();) + { + Player *plr = *itr; + ++itr; + + if (plr->isDead() && !plr->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) + { + plr->ResurrectPlayer(1.0); + } + plr->TeleportTo(newMapid, x, y, z, GetOrientation(), TELE_TO_NOT_LEAVE_TRANSPORT); + + //WorldPacket data(SMSG_811, 4); + //data << uint32(0); + //plr->GetSession()->SendPacket(&data); + } + + //we need to create and save new Map object with 'newMapid' because if not done -> lead to invalid Map object reference... + //player far teleport would try to create same instance, but we need it NOW for transport... + //correct me if I'm wrong O.o + //yes, you're right + + ResetMap(); + Map * newMap = MapManager::Instance().CreateMap(newMapid, this, 0); + SetMap(newMap); + assert (GetMap()); + + if (oldMap != newMap) + { + UpdateForMap(oldMap); + UpdateForMap(newMap); + } +} + +bool Transport::AddPassenger(Player* passenger) +{ + if (m_passengers.insert(passenger).second) + sLog.outDetail("Player %s boarded transport %s.", passenger->GetName(), GetName()); + return true; +} + +bool Transport::RemovePassenger(Player* passenger) +{ + if (m_passengers.erase(passenger)) + sLog.outDetail("Player %s removed from transport %s.", passenger->GetName(), GetName()); + return true; +} + +void Transport::CheckForEvent(uint32 entry, uint32 wp_id) +{ + uint32 key = entry*100+wp_id; + if (objmgr.TransportEventMap.find(key) != objmgr.TransportEventMap.end()) + GetMap()->ScriptsStart(sEventScripts, objmgr.TransportEventMap[key], this, NULL); +} + +void Transport::Update(uint32 /*p_time*/) +{ + if (m_WayPoints.size() <= 1) + return; + + m_timer = getMSTime() % m_period; + while (((m_timer - m_curr->first) % m_pathTime) > ((m_next->first - m_curr->first) % m_pathTime)) + { + m_curr = GetNextWayPoint(); + m_next = GetNextWayPoint(); + + // first check help in case client-server transport coordinates de-synchronization + if (m_curr->second.mapid != GetMapId() || m_curr->second.teleport) + { + TeleportTransport(m_curr->second.mapid, m_curr->second.x, m_curr->second.y, m_curr->second.z); + } + else + { + Relocate(m_curr->second.x, m_curr->second.y, m_curr->second.z); + } +/* + if (m_curr->second.delayed) + { + switch (GetEntry()) + { + case 176495: + case 164871: + case 175080: + SendPlaySound(11804, false); break; // ZeppelinDocked + case 20808: + case 181646: + case 176231: + case 176244: + case 176310: + case 177233: + SendPlaySound(5495, false);break; // BoatDockingWarning + default: + SendPlaySound(5154, false); break; // ShipDocked + } + } +*/ + /* + for (PlayerSet::const_iterator itr = m_passengers.begin(); itr != m_passengers.end();) + { + PlayerSet::const_iterator it2 = itr; + ++itr; + //(*it2)->SetPosition(m_curr->second.x + (*it2)->GetTransOffsetX(), m_curr->second.y + (*it2)->GetTransOffsetY(), m_curr->second.z + (*it2)->GetTransOffsetZ(), (*it2)->GetTransOffsetO()); + } + */ + + m_nextNodeTime = m_curr->first; + + if (m_curr == m_WayPoints.begin() && (sLog.getLogFilter() & LOG_FILTER_TRANSPORT_MOVES) == 0) + sLog.outDetail(" ************ BEGIN ************** %s", this->m_name.c_str()); + + if ((sLog.getLogFilter() & LOG_FILTER_TRANSPORT_MOVES) == 0) + sLog.outDetail("%s moved to %d %f %f %f %d", this->m_name.c_str(), m_curr->second.id, m_curr->second.x, m_curr->second.y, m_curr->second.z, m_curr->second.mapid); + + //Transport Event System + CheckForEvent(this->GetEntry(), m_curr->second.id); + } +} + +void Transport::UpdateForMap(Map const* targetMap) +{ + Map::PlayerList const& pl = targetMap->GetPlayers(); + if (pl.isEmpty()) + return; + + if (GetMapId() == targetMap->GetId()) + { + for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) + { + if (this != itr->getSource()->GetTransport()) + { + UpdateData transData; + BuildCreateUpdateBlockForPlayer(&transData, itr->getSource()); + WorldPacket packet; + transData.BuildPacket(&packet); + itr->getSource()->SendDirectMessage(&packet); + } + } + } + else + { + UpdateData transData; + BuildOutOfRangeUpdateBlock(&transData); + WorldPacket out_packet; + transData.BuildPacket(&out_packet); + + for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) + if (this != itr->getSource()->GetTransport()) + itr->getSource()->SendDirectMessage(&out_packet); + } +} + diff --git a/src/server/game/Entities/Transport/Transports.h b/src/server/game/Entities/Transport/Transports.h new file mode 100644 index 00000000000..25b9ade1461 --- /dev/null +++ b/src/server/game/Entities/Transport/Transports.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRANSPORTS_H +#define TRANSPORTS_H + +#include "GameObject.h" + +#include +#include +#include + +class TransportPath +{ + public: + struct PathNode + { + uint32 mapid; + float x,y,z; + uint32 actionFlag; + uint32 delay; + }; + + void SetLength(const unsigned int sz) + { + i_nodes.resize(sz); + } + + unsigned int Size(void) const { return i_nodes.size(); } + bool Empty(void) const { return i_nodes.empty(); } + void Resize(unsigned int sz) { i_nodes.resize(sz); } + void Clear(void) { i_nodes.clear(); } + PathNode* GetNodes(void) { return static_cast(&i_nodes[0]); } + + PathNode& operator[](const unsigned int idx) { return i_nodes[idx]; } + const PathNode& operator()(const unsigned int idx) const { return i_nodes[idx]; } + + protected: + std::vector i_nodes; +}; + +class Transport : public GameObject +{ + public: + explicit Transport(); + + bool Create(uint32 guidlow, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags); + bool GenerateWaypoints(uint32 pathid, std::set &mapids); + void Update(uint32 p_time); + bool AddPassenger(Player* passenger); + bool RemovePassenger(Player* passenger); + void CheckForEvent(uint32 entry, uint32 wp_id); + + typedef std::set PlayerSet; + PlayerSet const& GetPassengers() const { return m_passengers; } + + private: + struct WayPoint + { + WayPoint() : mapid(0), x(0), y(0), z(0), teleport(false), id(0) {} + WayPoint(uint32 _mapid, float _x, float _y, float _z, bool _teleport, uint32 _id) : + mapid(_mapid), x(_x), y(_y), z(_z), teleport(_teleport), id(_id) {} + uint32 mapid; + float x; + float y; + float z; + bool teleport; + uint32 id; + }; + + typedef std::map WayPointMap; + + WayPointMap::const_iterator m_curr; + WayPointMap::const_iterator m_next; + uint32 m_pathTime; + uint32 m_timer; + + PlayerSet m_passengers; + + public: + WayPointMap m_WayPoints; + uint32 m_nextNodeTime; + uint32 m_period; + + private: + void TeleportTransport(uint32 newMapid, float x, float y, float z); + void UpdateForMap(Map const* map); + WayPointMap::const_iterator GetNextWayPoint(); +}; +#endif + diff --git a/src/server/game/Events/GlobalEvents.cpp b/src/server/game/Events/GlobalEvents.cpp deleted file mode 100644 index 300527aad73..00000000000 --- a/src/server/game/Events/GlobalEvents.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** \file - \ingroup world -*/ - -#include "Log.h" -#include "Database/DatabaseEnv.h" -#include "Database/DatabaseImpl.h" -#include "Platform/Define.h" -#include "MapManager.h" -#include "ObjectAccessor.h" -#include "GlobalEvents.h" -#include "ObjectDefines.h" -#include "Corpse.h" - -static void CorpsesEraseCallBack(QueryResult_AutoPtr result, bool bones) -{ - if (!result) - return; - - do - { - Field *fields = result->Fetch(); - uint32 guidlow = fields[0].GetUInt32(); - float positionX = fields[1].GetFloat(); - float positionY = fields[2].GetFloat(); - uint32 mapid = fields[3].GetUInt32(); - uint64 player_guid = MAKE_NEW_GUID(fields[4].GetUInt32(), 0, HIGHGUID_PLAYER); - - uint64 guid = MAKE_NEW_GUID(guidlow, 0, HIGHGUID_CORPSE); - - sLog.outDebug("[Global event] Removing %s %u (X:%f Y:%f Map:%u).",(bones?"bones":"corpse"),guidlow,positionX,positionY,mapid); - - /// Resurrectable - convert corpses to bones - if (!bones) - { - if (!ObjectAccessor::Instance().ConvertCorpseForPlayer(player_guid)) - { - sLog.outDebug("Corpse %u not found in world or bones creating forbidden. Delete from DB.",guidlow); - CharacterDatabase.PExecute("DELETE FROM corpse WHERE guid = '%u'",guidlow); - } - } - else - ///- or delete bones - { - MapManager::Instance().RemoveBonesFromMap(mapid, guid, positionX, positionY); - - ///- remove bones from the database - CharacterDatabase.PExecute("DELETE FROM corpse WHERE guid = '%u'",guidlow); - } - } while (result->NextRow()); -} - -/// Handle periodic erase of corpses and bones -static void CorpsesErase(bool bones,uint32 delay) -{ - ///- Get the list of eligible corpses/bones to be removed - //No SQL injection (uint32 and enum) - CharacterDatabase.AsyncPQuery(&CorpsesEraseCallBack, bones, "SELECT guid,position_x,position_y,map,player FROM corpse WHERE time < (UNIX_TIMESTAMP()+'%u') AND corpse_type %s '0'", delay, (bones ? "=" : "<>")); -} - -/// not thread guarded variant for call from other thread -void CorpsesErase() -{ - CorpsesErase(true, 20*MINUTE); - CorpsesErase(false,3*DAY); -} - diff --git a/src/server/game/Events/GlobalEvents.h b/src/server/game/Events/GlobalEvents.h deleted file mode 100644 index 6af63bf4429..00000000000 --- a/src/server/game/Events/GlobalEvents.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/// \addtogroup world -/// @{ -/// \file - -#ifndef __GLOBALEVENTS_H -#define __GLOBALEVENTS_H - -void CorpsesErase(); -void HandleCorpsesErase(void*); -#endif -/// @} - diff --git a/src/server/game/Events/UnitEvents.h b/src/server/game/Events/UnitEvents.h deleted file mode 100644 index a218e0dd34d..00000000000 --- a/src/server/game/Events/UnitEvents.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _UNITEVENTS -#define _UNITEVENTS - -#include "Common.h" - -class ThreatContainer; -class ThreatManager; -class HostileReference; - -//============================================================== -//============================================================== - -enum UNIT_EVENT_TYPE -{ - // Player/Pet changed on/offline status - UEV_THREAT_REF_ONLINE_STATUS = 1<<0, - - // Threat for Player/Pet changed - UEV_THREAT_REF_THREAT_CHANGE = 1<<1, - - // Player/Pet will be removed from list (dead) [for internal use] - UEV_THREAT_REF_REMOVE_FROM_LIST = 1<<2, - - // Player/Pet entered/left water or some other place where it is/was not accessible for the creature - UEV_THREAT_REF_ASSECCIBLE_STATUS = 1<<3, - - // Threat list is going to be sorted (if dirty flag is set) - UEV_THREAT_SORT_LIST = 1<<4, - - // New target should be fetched, could tbe the current target as well - UEV_THREAT_SET_NEXT_TARGET = 1<<5, - - // A new victim (target) was set. Could be NULL - UEV_THREAT_VICTIM_CHANGED = 1<<6, - - // Future use - //UEV_UNIT_KILLED = 1<<7, - - //Future use - //UEV_UNIT_HEALTH_CHANGE = 1<<8, -}; - -#define UEV_THREAT_REF_EVENT_MASK (UEV_THREAT_REF_ONLINE_STATUS | UEV_THREAT_REF_THREAT_CHANGE | UEV_THREAT_REF_REMOVE_FROM_LIST | UEV_THREAT_REF_ASSECCIBLE_STATUS) -#define UEV_THREAT_MANAGER_EVENT_MASK (UEV_THREAT_SORT_LIST | UEV_THREAT_SET_NEXT_TARGET | UEV_THREAT_VICTIM_CHANGED) -#define UEV_ALL_EVENT_MASK (0xffffffff) - -// Future use -//#define UEV_UNIT_EVENT_MASK (UEV_UNIT_KILLED | UEV_UNIT_HEALTH_CHANGE) - -//============================================================== - -class UnitBaseEvent -{ - private: - uint32 iType; - public: - UnitBaseEvent(uint32 pType) { iType = pType; } - uint32 getType() const { return iType; } - bool matchesTypeMask(uint32 pMask) const { return iType & pMask; } - - void setType(uint32 pType) { iType = pType; } - -}; - -//============================================================== - -class ThreatRefStatusChangeEvent : public UnitBaseEvent -{ - private: - HostileReference* iHostileReference; - union - { - float iFValue; - int32 iIValue; - bool iBValue; - }; - ThreatManager* iThreatManager; - public: - ThreatRefStatusChangeEvent(uint32 pType) : UnitBaseEvent(pType) { iHostileReference = NULL; } - - ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference) : UnitBaseEvent(pType) { iHostileReference = pHostileReference; } - - ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference, float pValue) : UnitBaseEvent(pType) { iHostileReference = pHostileReference; iFValue = pValue; } - - ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference, bool pValue) : UnitBaseEvent(pType) { iHostileReference = pHostileReference; iBValue = pValue; } - - int32 getIValue() const { return iIValue; } - - float getFValue() const { return iFValue; } - - bool getBValue() const { return iBValue; } - - void setBValue(bool pValue) { iBValue = pValue; } - - HostileReference* getReference() const { return iHostileReference; } - - void setThreatManager(ThreatManager* pThreatManager) { iThreatManager = pThreatManager; } - - ThreatManager* getThreatManager() const { return iThreatManager; } -}; - -//============================================================== - -class ThreatManagerEvent : public ThreatRefStatusChangeEvent -{ - private: - ThreatContainer* iThreatContainer; - public: - ThreatManagerEvent(uint32 pType) : ThreatRefStatusChangeEvent(pType) {} - ThreatManagerEvent(uint32 pType, HostileReference* pHostileReference) : ThreatRefStatusChangeEvent(pType, pHostileReference) {} - - void setThreatContainer(ThreatContainer* pThreatContainer) { iThreatContainer = pThreatContainer; } - - ThreatContainer* getThreatContainer() const { return iThreatContainer; } -}; - -//============================================================== -#endif - diff --git a/src/server/game/Globals/Formulas.h b/src/server/game/Globals/Formulas.h deleted file mode 100644 index e5961834a78..00000000000 --- a/src/server/game/Globals/Formulas.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_FORMULAS_H -#define TRINITY_FORMULAS_H - -#include "World.h" - -namespace Trinity -{ - namespace Honor - { - inline uint32 hk_honor_at_level(uint8 level, uint32 count = 1) - { - return uint32(ceil(count * (33.333f * ((float)level) / 21.50537f))); - } - } - namespace XP - { - enum XPColorChar { RED, ORANGE, YELLOW, GREEN, GRAY }; - - inline uint8 GetGrayLevel(uint8 pl_level) - { - if (pl_level <= 5) - return 0; - else if (pl_level <= 39) - return pl_level - 5 - pl_level/10; - else if (pl_level <= 59) - return pl_level - 1 - pl_level/5; - else - return pl_level - 9; - } - - inline XPColorChar GetColorCode(uint8 pl_level, uint8 mob_level) - { - if (mob_level >= pl_level + 5) - return RED; - else if (mob_level >= pl_level + 3) - return ORANGE; - else if (mob_level >= pl_level - 2) - return YELLOW; - else if (mob_level > GetGrayLevel(pl_level)) - return GREEN; - else - return GRAY; - } - - inline uint8 GetZeroDifference(uint8 pl_level) - { - if (pl_level < 8) return 5; - if (pl_level < 10) return 6; - if (pl_level < 12) return 7; - if (pl_level < 16) return 8; - if (pl_level < 20) return 9; - if (pl_level < 30) return 11; - if (pl_level < 40) return 12; - if (pl_level < 45) return 13; - if (pl_level < 50) return 14; - if (pl_level < 55) return 15; - if (pl_level < 60) return 16; - return 17; - } - - inline uint32 BaseGain(uint8 pl_level, uint8 mob_level, ContentLevels content) - { - uint32 nBaseExp; - switch (content) - { - case CONTENT_1_60: nBaseExp = 45; break; - case CONTENT_61_70: nBaseExp = 235; break; - case CONTENT_71_80: nBaseExp = 580; break; - default: - sLog.outError("BaseGain: Unsupported content level %u",content); - nBaseExp = 45; break; - } - - if (mob_level >= pl_level) - { - uint8 nLevelDiff = mob_level - pl_level; - if (nLevelDiff > 4) - nLevelDiff = 4; - return ((pl_level*5 + nBaseExp) * (20 + nLevelDiff)/10 + 1)/2; - } - else - { - uint8 gray_level = GetGrayLevel(pl_level); - if (mob_level > gray_level) - { - uint8 ZD = GetZeroDifference(pl_level); - return (pl_level*5 + nBaseExp) * (ZD + mob_level - pl_level)/ZD; - } - return 0; - } - } - - inline uint32 Gain(Player *pl, Unit *u) - { - if (u->GetTypeId() == TYPEID_UNIT && ( - ((Creature*)u)->isTotem() || ((Creature*)u)->isPet() || - (((Creature*)u)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL))) - return 0; - - uint32 xp_gain = BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(u->GetMapId(),u->GetZoneId())); - if (xp_gain == 0) - return 0; - - //elites in instances have a 2.75x xp bonus instead of the regular 2x world bonus - if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->isElite()) - { - if(u->GetMap() && u->GetMap()->IsDungeon()) - xp_gain *= 2.75; - else - xp_gain *= 2; - } - - return uint32(xp_gain*sWorld.getRate(RATE_XP_KILL)); - } - - inline float xp_in_group_rate(uint32 count, bool isRaid) - { - if (isRaid) - { - // FIX ME: must apply decrease modifiers dependent from raid size - return 1.0f; - } - else - { - switch (count) - { - case 0: - case 1: - case 2: - return 1.0f; - case 3: - return 1.166f; - case 4: - return 1.3f; - case 5: - default: - return 1.4f; - } - } - } - } -} -#endif - diff --git a/src/server/game/Globals/GlobalEvents.cpp b/src/server/game/Globals/GlobalEvents.cpp new file mode 100644 index 00000000000..300527aad73 --- /dev/null +++ b/src/server/game/Globals/GlobalEvents.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** \file + \ingroup world +*/ + +#include "Log.h" +#include "Database/DatabaseEnv.h" +#include "Database/DatabaseImpl.h" +#include "Platform/Define.h" +#include "MapManager.h" +#include "ObjectAccessor.h" +#include "GlobalEvents.h" +#include "ObjectDefines.h" +#include "Corpse.h" + +static void CorpsesEraseCallBack(QueryResult_AutoPtr result, bool bones) +{ + if (!result) + return; + + do + { + Field *fields = result->Fetch(); + uint32 guidlow = fields[0].GetUInt32(); + float positionX = fields[1].GetFloat(); + float positionY = fields[2].GetFloat(); + uint32 mapid = fields[3].GetUInt32(); + uint64 player_guid = MAKE_NEW_GUID(fields[4].GetUInt32(), 0, HIGHGUID_PLAYER); + + uint64 guid = MAKE_NEW_GUID(guidlow, 0, HIGHGUID_CORPSE); + + sLog.outDebug("[Global event] Removing %s %u (X:%f Y:%f Map:%u).",(bones?"bones":"corpse"),guidlow,positionX,positionY,mapid); + + /// Resurrectable - convert corpses to bones + if (!bones) + { + if (!ObjectAccessor::Instance().ConvertCorpseForPlayer(player_guid)) + { + sLog.outDebug("Corpse %u not found in world or bones creating forbidden. Delete from DB.",guidlow); + CharacterDatabase.PExecute("DELETE FROM corpse WHERE guid = '%u'",guidlow); + } + } + else + ///- or delete bones + { + MapManager::Instance().RemoveBonesFromMap(mapid, guid, positionX, positionY); + + ///- remove bones from the database + CharacterDatabase.PExecute("DELETE FROM corpse WHERE guid = '%u'",guidlow); + } + } while (result->NextRow()); +} + +/// Handle periodic erase of corpses and bones +static void CorpsesErase(bool bones,uint32 delay) +{ + ///- Get the list of eligible corpses/bones to be removed + //No SQL injection (uint32 and enum) + CharacterDatabase.AsyncPQuery(&CorpsesEraseCallBack, bones, "SELECT guid,position_x,position_y,map,player FROM corpse WHERE time < (UNIX_TIMESTAMP()+'%u') AND corpse_type %s '0'", delay, (bones ? "=" : "<>")); +} + +/// not thread guarded variant for call from other thread +void CorpsesErase() +{ + CorpsesErase(true, 20*MINUTE); + CorpsesErase(false,3*DAY); +} + diff --git a/src/server/game/Globals/GlobalEvents.h b/src/server/game/Globals/GlobalEvents.h new file mode 100644 index 00000000000..6af63bf4429 --- /dev/null +++ b/src/server/game/Globals/GlobalEvents.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/// \addtogroup world +/// @{ +/// \file + +#ifndef __GLOBALEVENTS_H +#define __GLOBALEVENTS_H + +void CorpsesErase(); +void HandleCorpsesErase(void*); +#endif +/// @} + diff --git a/src/server/game/Globals/Language.h b/src/server/game/Globals/Language.h deleted file mode 100644 index c0c8fc486f3..00000000000 --- a/src/server/game/Globals/Language.h +++ /dev/null @@ -1,1007 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __TRINITY_LANGUAGE_H -#define __TRINITY_LANGUAGE_H - -enum TrinityStrings -{ - // for chat commands - LANG_SELECT_CHAR_OR_CREATURE = 1, - LANG_SELECT_CREATURE = 2, - - // level 0 chat - LANG_SYSTEMMESSAGE = 3, - LANG_EVENTMESSAGE = 4, - LANG_NO_HELP_CMD = 5, - LANG_NO_CMD = 6, - LANG_NO_SUBCMD = 7, - LANG_SUBCMDS_LIST = 8, - LANG_AVIABLE_CMD = 9, - LANG_CMD_SYNTAX = 10, - LANG_ACCOUNT_LEVEL = 11, - LANG_CONNECTED_USERS = 12, - LANG_UPTIME = 13, - LANG_PLAYER_SAVED = 14, - LANG_PLAYERS_SAVED = 15, - LANG_GMS_ON_SRV = 16, - LANG_GMS_NOT_LOGGED = 17, - LANG_YOU_IN_FLIGHT = 18, - //LANG_YOU_IN_BATTLEGROUND = 19, not used - //LANG_TARGET_IN_FLIGHT = 20, not used - LANG_CHAR_IN_FLIGHT = 21, - LANG_CHAR_NON_MOUNTED = 22, - LANG_YOU_IN_COMBAT = 23, - LANG_YOU_USED_IT_RECENTLY = 24, - LANG_COMMAND_NOTCHANGEPASSWORD = 25, - LANG_COMMAND_PASSWORD = 26, - LANG_COMMAND_WRONGOLDPASSWORD = 27, - LANG_COMMAND_ACCLOCKLOCKED = 28, - LANG_COMMAND_ACCLOCKUNLOCKED = 29, - LANG_SPELL_RANK = 30, - LANG_KNOWN = 31, - LANG_LEARN = 32, - LANG_PASSIVE = 33, - LANG_TALENT = 34, - LANG_ACTIVE = 35, - LANG_COMPLETE = 36, - LANG_OFFLINE = 37, - LANG_ON = 38, - LANG_OFF = 39, - LANG_YOU_ARE = 40, - LANG_VISIBLE = 41, - LANG_INVISIBLE = 42, - LANG_DONE = 43, - LANG_YOU = 44, - LANG_UNKNOWN = 45, - LANG_ERROR = 46, - LANG_NON_EXIST_CHARACTER = 47, - LANG_FRIEND_IGNORE_UNKNOWN = 48, - LANG_LEVEL_MINREQUIRED = 49, - LANG_LEVEL_MINREQUIRED_AND_ITEM = 50, - LANG_NPC_TAINER_HELLO = 51, - LANG_COMMAND_INVALID_ITEM_COUNT = 52, - LANG_COMMAND_MAIL_ITEMS_LIMIT = 53, - LANG_NEW_PASSWORDS_NOT_MATCH = 54, - LANG_PASSWORD_TOO_LONG = 55, - LANG_MOTD_CURRENT = 56, - LANG_USING_WORLD_DB = 57, - LANG_USING_SCRIPT_LIB = 58, - LANG_USING_EVENT_AI = 59, - LANG_CONNECTED_PLAYERS = 60, - LANG_ACCOUNT_ADDON = 61, - // Room for more level 0 62-99 not used - - // level 1 chat - LANG_GLOBAL_NOTIFY = 100, - LANG_MAP_POSITION = 101, - LANG_IS_TELEPORTED = 102, - LANG_CANNOT_SUMMON_TO_INST = 103, - LANG_CANNOT_GO_TO_INST_PARTY = 104, - LANG_CANNOT_GO_TO_INST_GM = 105, - LANG_CANNOT_GO_INST_INST = 106, - LANG_CANNOT_SUMMON_INST_INST = 107, - LANG_SUMMONING = 108, - LANG_SUMMONED_BY = 109, - LANG_TELEPORTING_TO = 110, - LANG_TELEPORTED_TO_BY = 111, - LANG_NO_PLAYER = 112, - LANG_APPEARING_AT = 113, - LANG_APPEARING_TO = 114, - LANG_BAD_VALUE = 115, - LANG_NO_CHAR_SELECTED = 116, - LANG_NOT_IN_GROUP = 117, - - LANG_YOU_CHANGE_HP = 118, - LANG_YOURS_HP_CHANGED = 119, - LANG_YOU_CHANGE_MANA = 120, - LANG_YOURS_MANA_CHANGED = 121, - LANG_YOU_CHANGE_ENERGY = 122, - LANG_YOURS_ENERGY_CHANGED = 123, - - LANG_CURRENT_ENERGY = 124, //log - LANG_YOU_CHANGE_RAGE = 125, - LANG_YOURS_RAGE_CHANGED = 126, - LANG_YOU_CHANGE_LVL = 127, - LANG_CURRENT_FACTION = 128, - LANG_WRONG_FACTION = 129, - LANG_YOU_CHANGE_FACTION = 130, - LANG_YOU_CHANGE_SPELLFLATID = 131, - LANG_YOURS_SPELLFLATID_CHANGED = 132, - LANG_YOU_GIVE_TAXIS = 133, - LANG_YOU_REMOVE_TAXIS = 134, - LANG_YOURS_TAXIS_ADDED = 135, - LANG_YOURS_TAXIS_REMOVED = 136, - - LANG_YOU_CHANGE_ASPEED = 137, - LANG_YOURS_ASPEED_CHANGED = 138, - LANG_YOU_CHANGE_SPEED = 139, - LANG_YOURS_SPEED_CHANGED = 140, - LANG_YOU_CHANGE_SWIM_SPEED = 141, - LANG_YOURS_SWIM_SPEED_CHANGED = 142, - LANG_YOU_CHANGE_BACK_SPEED = 143, - LANG_YOURS_BACK_SPEED_CHANGED = 144, - LANG_YOU_CHANGE_FLY_SPEED = 145, - LANG_YOURS_FLY_SPEED_CHANGED = 146, - - LANG_YOU_CHANGE_SIZE = 147, - LANG_YOURS_SIZE_CHANGED = 148, - LANG_NO_MOUNT = 149, - LANG_YOU_GIVE_MOUNT = 150, - LANG_MOUNT_GIVED = 151, - - LANG_CURRENT_MONEY = 152, - LANG_YOU_TAKE_ALL_MONEY = 153, - LANG_YOURS_ALL_MONEY_GONE = 154, - LANG_YOU_TAKE_MONEY = 155, - LANG_YOURS_MONEY_TAKEN = 156, - LANG_YOU_GIVE_MONEY = 157, - LANG_YOURS_MONEY_GIVEN = 158, - LANG_YOU_HEAR_SOUND = 159, - - LANG_NEW_MONEY = 160, // Log - - LANG_REMOVE_BIT = 161, - LANG_SET_BIT = 162, - LANG_COMMAND_TELE_TABLEEMPTY = 163, - LANG_COMMAND_TELE_NOTFOUND = 164, - LANG_COMMAND_TELE_PARAMETER = 165, - LANG_COMMAND_TELE_NOLOCATION = 166, - // 167 // not used - LANG_COMMAND_TELE_LOCATION = 168, - - LANG_MAIL_SENT = 169, - LANG_SOUND_NOT_EXIST = 170, - LANG_CANT_TELEPORT_SELF = 171, - LANG_CONSOLE_COMMAND = 172, - LANG_YOU_CHANGE_RUNIC_POWER = 173, - LANG_YOURS_RUNIC_POWER_CHANGED = 174, - LANG_LIQUID_STATUS = 175, - // Room for more level 1 176-199 not used - - // level 2 chat - LANG_NO_SELECTION = 200, - LANG_OBJECT_GUID = 201, - LANG_TOO_LONG_NAME = 202, - LANG_CHARS_ONLY = 203, - LANG_TOO_LONG_SUBNAME = 204, - LANG_NOT_IMPLEMENTED = 205, - - LANG_ITEM_ADDED_TO_LIST = 206, - LANG_ITEM_NOT_FOUND = 207, - LANG_ITEM_DELETED_FROM_LIST = 208, - LANG_ITEM_NOT_IN_LIST = 209, - LANG_ITEM_ALREADY_IN_LIST = 210, - - LANG_RESET_SPELLS_ONLINE = 211, - LANG_RESET_SPELLS_OFFLINE = 212, - LANG_RESET_TALENTS_ONLINE = 213, - LANG_RESET_TALENTS_OFFLINE = 214, - LANG_RESET_SPELLS = 215, - LANG_RESET_TALENTS = 216, - - LANG_RESETALL_UNKNOWN_CASE = 217, - LANG_RESETALL_SPELLS = 218, - LANG_RESETALL_TALENTS = 219, - - LANG_WAYPOINT_NOTFOUND = 220, - LANG_WAYPOINT_NOTFOUNDLAST = 221, - LANG_WAYPOINT_NOTFOUNDSEARCH = 222, - LANG_WAYPOINT_NOTFOUNDDBPROBLEM = 223, - LANG_WAYPOINT_CREATSELECTED = 224, - LANG_WAYPOINT_CREATNOTFOUND = 225, - LANG_WAYPOINT_VP_SELECT = 226, - LANG_WAYPOINT_VP_NOTFOUND = 227, - LANG_WAYPOINT_VP_NOTCREATED = 228, - LANG_WAYPOINT_VP_ALLREMOVED = 229, - LANG_WAYPOINT_NOTCREATED = 230, - LANG_WAYPOINT_NOGUID = 231, - LANG_WAYPOINT_NOWAYPOINTGIVEN = 232, - LANG_WAYPOINT_ARGUMENTREQ = 233, - LANG_WAYPOINT_ADDED = 234, - LANG_WAYPOINT_ADDED_NO = 235, - LANG_WAYPOINT_CHANGED = 236, - LANG_WAYPOINT_CHANGED_NO = 237, - LANG_WAYPOINT_EXPORTED = 238, - LANG_WAYPOINT_NOTHINGTOEXPORT = 239, - LANG_WAYPOINT_IMPORTED = 240, - LANG_WAYPOINT_REMOVED = 241, - LANG_WAYPOINT_NOTREMOVED = 242, - LANG_WAYPOINT_TOOFAR1 = 243, - LANG_WAYPOINT_TOOFAR2 = 244, - LANG_WAYPOINT_TOOFAR3 = 245, - LANG_WAYPOINT_INFO_TITLE = 246, - LANG_WAYPOINT_INFO_WAITTIME = 247, - LANG_WAYPOINT_INFO_MODEL = 248, - LANG_WAYPOINT_INFO_EMOTE = 249, - LANG_WAYPOINT_INFO_SPELL = 250, - LANG_WAYPOINT_INFO_TEXT = 251, - LANG_WAYPOINT_INFO_AISCRIPT = 252, - - LANG_RENAME_PLAYER = 253, - LANG_RENAME_PLAYER_GUID = 254, - - LANG_WAYPOINT_WPCREATNOTFOUND = 255, - LANG_WAYPOINT_NPCNOTFOUND = 256, - - LANG_MOVE_TYPE_SET = 257, - LANG_MOVE_TYPE_SET_NODEL = 258, - LANG_USE_BOL = 259, - LANG_VALUE_SAVED = 260, - LANG_VALUE_SAVED_REJOIN = 261, - - LANG_COMMAND_GOAREATRNOTFOUND = 262, - LANG_INVALID_TARGET_COORD = 263, - LANG_INVALID_ZONE_COORD = 264, - LANG_INVALID_ZONE_MAP = 265, - LANG_COMMAND_TARGETOBJNOTFOUND = 266, - LANG_COMMAND_GOOBJNOTFOUND = 267, - LANG_COMMAND_GOCREATNOTFOUND = 268, - LANG_COMMAND_GOCREATMULTIPLE = 269, - LANG_COMMAND_DELCREATMESSAGE = 270, - LANG_COMMAND_CREATUREMOVED = 271, - LANG_COMMAND_CREATUREATSAMEMAP = 272, - LANG_COMMAND_OBJNOTFOUND = 273, - LANG_COMMAND_DELOBJREFERCREATURE = 274, - LANG_COMMAND_DELOBJMESSAGE = 275, - LANG_COMMAND_TURNOBJMESSAGE = 276, - LANG_COMMAND_MOVEOBJMESSAGE = 277, - LANG_COMMAND_VENDORSELECTION = 278, - LANG_COMMAND_NEEDITEMSEND = 279, - LANG_COMMAND_ADDVENDORITEMITEMS = 280, - LANG_COMMAND_KICKSELF = 281, - LANG_COMMAND_KICKMESSAGE = 282, - // 283, not used - LANG_COMMAND_WHISPERACCEPTING = 284, - LANG_COMMAND_WHISPERON = 285, - LANG_COMMAND_WHISPEROFF = 286, - LANG_COMMAND_CREATGUIDNOTFOUND = 287, - // TICKET STRINGS NEED REWRITE // 288-296 FREE - - // END - LANG_COMMAND_SPAWNDIST = 297, - LANG_COMMAND_SPAWNTIME = 298, - LANG_COMMAND_MODIFY_HONOR = 299, - - LANG_YOUR_CHAT_DISABLED = 300, - LANG_YOU_DISABLE_CHAT = 301, - LANG_CHAT_ALREADY_ENABLED = 302, - LANG_YOUR_CHAT_ENABLED = 303, - LANG_YOU_ENABLE_CHAT = 304, - - LANG_COMMAND_MODIFY_REP = 305, - LANG_COMMAND_MODIFY_ARENA = 306, - LANG_COMMAND_FACTION_NOTFOUND = 307, - LANG_COMMAND_FACTION_UNKNOWN = 308, - LANG_COMMAND_FACTION_INVPARAM = 309, - LANG_COMMAND_FACTION_DELTA = 310, - LANG_FACTION_LIST = 311, - LANG_FACTION_VISIBLE = 312, - LANG_FACTION_ATWAR = 313, - LANG_FACTION_PEACE_FORCED = 314, - LANG_FACTION_HIDDEN = 315, - LANG_FACTION_INVISIBLE_FORCED = 316, - LANG_FACTION_INACTIVE = 317, - LANG_REP_HATED = 318, - LANG_REP_HOSTILE = 319, - LANG_REP_UNFRIENDLY = 320, - LANG_REP_NEUTRAL = 321, - LANG_REP_FRIENDLY = 322, - LANG_REP_HONORED = 323, - LANG_REP_REVERED = 324, - LANG_REP_EXALTED = 325, - LANG_COMMAND_FACTION_NOREP_ERROR = 326, - LANG_FACTION_NOREPUTATION = 327, - LANG_LOOKUP_PLAYER_ACCOUNT = 328, - LANG_LOOKUP_PLAYER_CHARACTER = 329, - LANG_NO_PLAYERS_FOUND = 330, - LANG_EXTENDED_COST_NOT_EXIST = 331, - LANG_GM_ON = 332, - LANG_GM_OFF = 333, - LANG_GM_CHAT_ON = 334, - LANG_GM_CHAT_OFF = 335, - LANG_YOU_REPAIR_ITEMS = 336, - LANG_YOUR_ITEMS_REPAIRED = 337, - LANG_YOU_SET_WATERWALK = 338, - LANG_YOUR_WATERWALK_SET = 339, - LANG_CREATURE_FOLLOW_YOU_NOW = 340, - LANG_CREATURE_NOT_FOLLOW_YOU = 341, - LANG_CREATURE_NOT_FOLLOW_YOU_NOW = 342, - LANG_CREATURE_NON_TAMEABLE = 343, - LANG_YOU_ALREADY_HAVE_PET = 344, - LANG_CUSTOMIZE_PLAYER = 345, - LANG_CUSTOMIZE_PLAYER_GUID = 346, - LANG_COMMAND_GOTAXINODENOTFOUND = 347, - LANG_GAMEOBJECT_HAVE_INVALID_DATA = 348, - LANG_TITLE_LIST_CHAT = 349, - LANG_TITLE_LIST_CONSOLE = 350, - LANG_COMMAND_NOTITLEFOUND = 351, - LANG_INVALID_TITLE_ID = 352, - LANG_TITLE_ADD_RES = 353, - LANG_TITLE_REMOVE_RES = 354, - LANG_TITLE_CURRENT_RES = 355, - LANG_CURRENT_TITLE_RESET = 356, - // Room for more level 2 357-399 not used - - // level 3 chat - LANG_SCRIPTS_RELOADED = 400, - LANG_YOU_CHANGE_SECURITY = 401, - LANG_YOURS_SECURITY_CHANGED = 402, - LANG_YOURS_SECURITY_IS_LOW = 403, - LANG_CREATURE_MOVE_DISABLED = 404, - LANG_CREATURE_MOVE_ENABLED = 405, - LANG_NO_WEATHER = 406, - LANG_WEATHER_DISABLED = 407, - - LANG_BAN_YOUBANNED = 408, - LANG_BAN_YOUPERMBANNED = 409, - LANG_BAN_NOTFOUND = 410, - - LANG_UNBAN_UNBANNED = 411, - LANG_UNBAN_ERROR = 412, - - LANG_ACCOUNT_NOT_EXIST = 413, - - LANG_BANINFO_NOCHARACTER = 414, - LANG_BANINFO_NOIP = 415, - LANG_BANINFO_NOACCOUNTBAN = 416, - LANG_BANINFO_BANHISTORY = 417, - LANG_BANINFO_HISTORYENTRY = 418, - LANG_BANINFO_INFINITE = 419, - LANG_BANINFO_NEVER = 420, - LANG_BANINFO_YES = 421, - LANG_BANINFO_NO = 422, - LANG_BANINFO_IPENTRY = 423, - - LANG_BANLIST_NOIP = 424, - LANG_BANLIST_NOACCOUNT = 425, - LANG_BANLIST_NOCHARACTER = 426, - LANG_BANLIST_MATCHINGIP = 427, - LANG_BANLIST_MATCHINGACCOUNT = 428, - - LANG_COMMAND_LEARN_MANY_SPELLS = 429, - LANG_COMMAND_LEARN_CLASS_SPELLS = 430, - LANG_COMMAND_LEARN_CLASS_TALENTS = 431, - LANG_COMMAND_LEARN_ALL_LANG = 432, - LANG_COMMAND_LEARN_ALL_CRAFT = 433, - LANG_COMMAND_COULDNOTFIND = 434, - LANG_COMMAND_ITEMIDINVALID = 435, - LANG_COMMAND_NOITEMFOUND = 436, - LANG_COMMAND_LISTOBJINVALIDID = 437, - LANG_COMMAND_LISTITEMMESSAGE = 438, - LANG_COMMAND_LISTOBJMESSAGE = 439, - LANG_COMMAND_INVALIDCREATUREID = 440, - LANG_COMMAND_LISTCREATUREMESSAGE = 441, - LANG_COMMAND_NOAREAFOUND = 442, - LANG_COMMAND_NOITEMSETFOUND = 443, - LANG_COMMAND_NOSKILLFOUND = 444, - LANG_COMMAND_NOSPELLFOUND = 445, - LANG_COMMAND_NOQUESTFOUND = 446, - LANG_COMMAND_NOCREATUREFOUND = 447, - LANG_COMMAND_NOGAMEOBJECTFOUND = 448, - LANG_COMMAND_GRAVEYARDNOEXIST = 449, - LANG_COMMAND_GRAVEYARDALRLINKED = 450, - LANG_COMMAND_GRAVEYARDLINKED = 451, - LANG_COMMAND_GRAVEYARDWRONGZONE = 452, - // = 453, - LANG_COMMAND_GRAVEYARDERROR = 454, - LANG_COMMAND_GRAVEYARD_NOTEAM = 455, - LANG_COMMAND_GRAVEYARD_ANY = 456, - LANG_COMMAND_GRAVEYARD_ALLIANCE = 457, - LANG_COMMAND_GRAVEYARD_HORDE = 458, - LANG_COMMAND_GRAVEYARDNEAREST = 459, - LANG_COMMAND_ZONENOGRAVEYARDS = 460, - LANG_COMMAND_ZONENOGRAFACTION = 461, - LANG_COMMAND_TP_ALREADYEXIST = 462, - LANG_COMMAND_TP_ADDED = 463, - LANG_COMMAND_TP_ADDEDERR = 464, - LANG_COMMAND_TP_DELETED = 465, - LANG_COMMAND_NOTAXINODEFOUND = 466, - LANG_COMMAND_TARGET_LISTAURAS = 467, - LANG_COMMAND_TARGET_AURADETAIL = 468, - LANG_COMMAND_TARGET_LISTAURATYPE = 469, - LANG_COMMAND_TARGET_AURASIMPLE = 470, - - LANG_COMMAND_QUEST_NOTFOUND = 471, - LANG_COMMAND_QUEST_STARTFROMITEM = 472, - LANG_COMMAND_QUEST_REMOVED = 473, - LANG_COMMAND_QUEST_REWARDED = 474, - LANG_COMMAND_QUEST_COMPLETE = 475, - LANG_COMMAND_QUEST_ACTIVE = 476, - - LANG_COMMAND_FLYMODE_STATUS = 477, - - LANG_COMMAND_OPCODESENT = 478, - - LANG_COMMAND_IMPORT_SUCCESS = 479, - LANG_COMMAND_IMPORT_FAILED = 480, - LANG_COMMAND_EXPORT_SUCCESS = 481, - LANG_COMMAND_EXPORT_FAILED = 482, - - LANG_COMMAND_SPELL_BROKEN = 483, - - LANG_SET_SKILL = 484, - LANG_SET_SKILL_ERROR = 485, - - LANG_INVALID_SKILL_ID = 486, - LANG_LEARNING_GM_SKILLS = 487, - LANG_YOU_KNOWN_SPELL = 488, - LANG_TARGET_KNOWN_SPELL = 489, - LANG_UNKNOWN_SPELL = 490, - LANG_FORGET_SPELL = 491, - LANG_REMOVEALL_COOLDOWN = 492, - LANG_REMOVE_COOLDOWN = 493, - - LANG_ADDITEM = 494, //log - LANG_ADDITEMSET = 495, //log - LANG_REMOVEITEM = 496, - LANG_ITEM_CANNOT_CREATE = 497, - LANG_INSERT_GUILD_NAME = 498, - LANG_PLAYER_NOT_FOUND = 499, - LANG_PLAYER_IN_GUILD = 500, - LANG_GUILD_NOT_CREATED = 501, - LANG_NO_ITEMS_FROM_ITEMSET_FOUND = 502, - - LANG_DISTANCE = 503, - - LANG_ITEM_SLOT = 504, - LANG_ITEM_SLOT_NOT_EXIST = 505, - LANG_ITEM_ADDED_TO_SLOT = 506, - LANG_ITEM_SAVE_FAILED = 507, - LANG_ITEMLIST_SLOT = 508, - LANG_ITEMLIST_MAIL = 509, - LANG_ITEMLIST_AUCTION = 510, - - LANG_WRONG_LINK_TYPE = 511, - LANG_ITEM_LIST_CHAT = 512, - LANG_QUEST_LIST_CHAT = 513, - LANG_CREATURE_ENTRY_LIST_CHAT = 514, - LANG_CREATURE_LIST_CHAT = 515, - LANG_GO_ENTRY_LIST_CHAT = 516, - LANG_GO_LIST_CHAT = 517, - LANG_ITEMSET_LIST_CHAT = 518, - LANG_TELE_LIST = 519, - LANG_SPELL_LIST = 520, - LANG_SKILL_LIST_CHAT = 521, - - LANG_GAMEOBJECT_NOT_EXIST = 522, - - LANG_GAMEOBJECT_CURRENT = 523, //log - LANG_GAMEOBJECT_DETAIL = 524, - LANG_GAMEOBJECT_ADD = 525, - - LANG_MOVEGENS_LIST = 526, - LANG_MOVEGENS_IDLE = 527, - LANG_MOVEGENS_RANDOM = 528, - LANG_MOVEGENS_WAYPOINT = 529, - LANG_MOVEGENS_ANIMAL_RANDOM = 530, - LANG_MOVEGENS_CONFUSED = 531, - LANG_MOVEGENS_TARGETED_PLAYER = 532, - LANG_MOVEGENS_TARGETED_CREATURE = 533, - LANG_MOVEGENS_TARGETED_NULL = 534, - LANG_MOVEGENS_HOME_CREATURE = 535, - LANG_MOVEGENS_HOME_PLAYER = 536, - LANG_MOVEGENS_FLIGHT = 537, - LANG_MOVEGENS_UNKNOWN = 538, - - LANG_NPCINFO_CHAR = 539, - LANG_NPCINFO_LEVEL = 540, - LANG_NPCINFO_HEALTH = 541, - LANG_NPCINFO_FLAGS = 542, - LANG_NPCINFO_LOOT = 543, - LANG_NPCINFO_POSITION = 544, - LANG_NPCINFO_VENDOR = 545, - LANG_NPCINFO_TRAINER = 546, - LANG_NPCINFO_DUNGEON_ID = 547, - - LANG_PINFO_ACCOUNT = 548, - LANG_PINFO_LEVEL = 549, - LANG_PINFO_NO_REP = 550, - - LANG_YOU_SET_EXPLORE_ALL = 551, - LANG_YOU_SET_EXPLORE_NOTHING = 552, - LANG_YOURS_EXPLORE_SET_ALL = 553, - LANG_YOURS_EXPLORE_SET_NOTHING = 554, - - LANG_HOVER_ENABLED = 555, - LANG_HOVER_DISABLED = 556, - LANG_YOURS_LEVEL_UP = 557, - LANG_YOURS_LEVEL_DOWN = 558, - LANG_YOURS_LEVEL_PROGRESS_RESET = 559, - LANG_EXPLORE_AREA = 560, - LANG_UNEXPLORE_AREA = 561, - - LANG_UPDATE = 562, - LANG_UPDATE_CHANGE = 563, - LANG_TOO_BIG_INDEX = 564, - LANG_SET_UINT = 565, //log - LANG_SET_UINT_FIELD = 566, - LANG_SET_FLOAT = 567, //log - LANG_SET_FLOAT_FIELD = 568, - LANG_GET_UINT = 569, //log - LANG_GET_UINT_FIELD = 570, - LANG_GET_FLOAT = 571, //log - LANG_GET_FLOAT_FIELD = 572, - LANG_SET_32BIT = 573, //log - LANG_SET_32BIT_FIELD = 574, - LANG_CHANGE_32BIT = 575, //log - LANG_CHANGE_32BIT_FIELD = 576, - - LANG_INVISIBLE_INVISIBLE = 577, - LANG_INVISIBLE_VISIBLE = 578, - LANG_SELECTED_TARGET_NOT_HAVE_VICTIM = 579, - - LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST = 580, - LANG_COMMAND_NEAROBJMESSAGE = 581, - LANG_COMMAND_RAWPAWNTIMES = 582, - - LANG_EVENT_ENTRY_LIST_CHAT = 583, - LANG_NOEVENTFOUND = 584, - LANG_EVENT_NOT_EXIST = 585, - LANG_EVENT_INFO = 586, - LANG_EVENT_ALREADY_ACTIVE = 587, - LANG_EVENT_NOT_ACTIVE = 588, - - LANG_MOVEGENS_POINT = 589, - LANG_MOVEGENS_FEAR = 590, - LANG_MOVEGENS_DISTRACT = 591, - - LANG_COMMAND_LEARN_ALL_RECIPES = 592, - LANG_BANLIST_ACCOUNTS = 593, - LANG_BANLIST_ACCOUNTS_HEADER = 594, - LANG_BANLIST_IPS = 595, - LANG_BANLIST_IPS_HEADER = 596, - LANG_GMLIST = 597, - LANG_GMLIST_HEADER = 598, - LANG_GMLIST_EMPTY = 599, - // End Level 3 list, continued at 1100 - - // Battleground - LANG_BG_A_WINS = 600, - LANG_BG_H_WINS = 601, - - LANG_BG_WS_START_TWO_MINUTES = 753, - LANG_BG_WS_START_ONE_MINUTE = 602, - LANG_BG_WS_START_HALF_MINUTE = 603, - LANG_BG_WS_HAS_BEGUN = 604, - - LANG_BG_WS_CAPTURED_HF = 605, - LANG_BG_WS_CAPTURED_AF = 606, - LANG_BG_WS_DROPPED_HF = 607, - LANG_BG_WS_DROPPED_AF = 608, - LANG_BG_WS_RETURNED_AF = 609, - LANG_BG_WS_RETURNED_HF = 610, - LANG_BG_WS_PICKEDUP_HF = 611, - LANG_BG_WS_PICKEDUP_AF = 612, - LANG_BG_WS_F_PLACED = 613, - LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED = 614, - LANG_BG_WS_HORDE_FLAG_RESPAWNED = 615, - - LANG_BG_EY_START_TWO_MINUTES = 755, - LANG_BG_EY_START_ONE_MINUTE = 636, - LANG_BG_EY_START_HALF_MINUTE = 637, - LANG_BG_EY_HAS_BEGUN = 638, - - LANG_BG_AB_ALLY = 650, - LANG_BG_AB_HORDE = 651, - LANG_BG_AB_NODE_STABLES = 652, - LANG_BG_AB_NODE_BLACKSMITH = 653, - LANG_BG_AB_NODE_FARM = 654, - LANG_BG_AB_NODE_LUMBER_MILL = 655, - LANG_BG_AB_NODE_GOLD_MINE = 656, - LANG_BG_AB_NODE_TAKEN = 657, - LANG_BG_AB_NODE_DEFENDED = 658, - LANG_BG_AB_NODE_ASSAULTED = 659, - LANG_BG_AB_NODE_CLAIMED = 660, - - LANG_BG_AB_START_TWO_MINUTES = 754, - LANG_BG_AB_START_ONE_MINUTE = 661, - LANG_BG_AB_START_HALF_MINUTE = 662, - LANG_BG_AB_HAS_BEGUN = 663, - LANG_BG_AB_A_NEAR_VICTORY = 664, - LANG_BG_AB_H_NEAR_VICTORY = 665, - LANG_BG_MARK_BY_MAIL = 666, - - LANG_BG_EY_HAS_TAKEN_A_M_TOWER = 667, - LANG_BG_EY_HAS_TAKEN_H_M_TOWER = 668, - LANG_BG_EY_HAS_TAKEN_A_D_RUINS = 669, - LANG_BG_EY_HAS_TAKEN_H_D_RUINS = 670, - LANG_BG_EY_HAS_TAKEN_A_B_TOWER = 671, - LANG_BG_EY_HAS_TAKEN_H_B_TOWER = 672, - LANG_BG_EY_HAS_TAKEN_A_F_RUINS = 673, - LANG_BG_EY_HAS_TAKEN_H_F_RUINS = 674, - LANG_BG_EY_HAS_LOST_A_M_TOWER = 675, - LANG_BG_EY_HAS_LOST_H_M_TOWER = 676, - LANG_BG_EY_HAS_LOST_A_D_RUINS = 677, - LANG_BG_EY_HAS_LOST_H_D_RUINS = 678, - LANG_BG_EY_HAS_LOST_A_B_TOWER = 679, - LANG_BG_EY_HAS_LOST_H_B_TOWER = 680, - LANG_BG_EY_HAS_LOST_A_F_RUINS = 681, - LANG_BG_EY_HAS_LOST_H_F_RUINS = 682, - LANG_BG_EY_HAS_TAKEN_FLAG = 683, - LANG_BG_EY_CAPTURED_FLAG_A = 684, - LANG_BG_EY_CAPTURED_FLAG_H = 685, - LANG_BG_EY_DROPPED_FLAG = 686, - LANG_BG_EY_RESETED_FLAG = 687, - - LANG_ARENA_ONE_TOOLOW = 700, - LANG_ARENA_ONE_MINUTE = 701, - LANG_ARENA_THIRTY_SECONDS = 702, - LANG_ARENA_FIFTEEN_SECONDS = 703, - LANG_ARENA_HAS_BEGUN = 704, - - LANG_WAIT_BEFORE_SPEAKING = 705, - LANG_NOT_EQUIPPED_ITEM = 706, - LANG_PLAYER_DND = 707, - LANG_PLAYER_AFK = 708, - LANG_PLAYER_DND_DEFAULT = 709, - LANG_PLAYER_AFK_DEFAULT = 710, - - LANG_BG_QUEUE_ANNOUNCE_SELF = 711, - LANG_BG_QUEUE_ANNOUNCE_WORLD = 712, - LANG_YOUR_ARENA_LEVEL_REQ_ERROR = 713, -// = 714, not used - LANG_YOUR_BG_LEVEL_REQ_ERROR = 715, -// = 716, not used - LANG_BG_STARTED_ANNOUNCE_WORLD = 717, - LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN= 718, - LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT= 719, - - LANG_BG_GROUP_TOO_LARGE = 720, // "Your group is too large for this battleground. Please regroup to join." - LANG_ARENA_GROUP_TOO_LARGE = 721, // "Your group is too large for this arena. Please regroup to join." - LANG_ARENA_YOUR_TEAM_ONLY = 722, // "Your group has members not in your arena team. Please regroup to join." - LANG_ARENA_NOT_ENOUGH_PLAYERS = 723, // "Your group does not have enough players to join this match." - LANG_ARENA_GOLD_WINS = 724, // "The Gold Team wins!" - LANG_ARENA_GREEN_WINS = 725, // "The Green Team wins!" -// = 726, not used - LANG_BG_GROUP_OFFLINE_MEMBER = 727, // "Your group has an offline member. Please remove him before joining." - LANG_BG_GROUP_MIXED_FACTION = 728, // "Your group has players from the opposing faction. You can't join the battleground as a group." - LANG_BG_GROUP_MIXED_LEVELS = 729, // "Your group has players from different battleground brakets. You can't join as group." - LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE = 730, // "Someone in your party is already in this battleground queue. (S)he must leave it before joining as group." - LANG_BG_GROUP_MEMBER_DESERTER = 731, // "Someone in your party is Deserter. You can't join as group." - LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS = 732, // "Someone in your party is already in three battleground queues. You cannot join as group." - - LANG_CANNOT_TELE_TO_BG = 733, // "You cannot teleport to a battleground or arena map." - LANG_CANNOT_SUMMON_TO_BG = 734, // "You cannot summon players to a battleground or arena map." - LANG_CANNOT_GO_TO_BG_GM = 735, // "You must be in GM mode to teleport to a player in a battleground." - LANG_CANNOT_GO_TO_BG_FROM_BG = 736, // "You cannot teleport to a battleground from another battleground. Please leave the current battleground first." - LANG_DEBUG_ARENA_ON = 737, - LANG_DEBUG_ARENA_OFF = 738, - LANG_DEBUG_BG_ON = 739, - LANG_DEBUG_BG_OFF = 740, - LANG_DIST_ARENA_POINTS_START = 741, - LANG_DIST_ARENA_POINTS_ONLINE_START = 742, - LANG_DIST_ARENA_POINTS_ONLINE_END = 743, - LANG_DIST_ARENA_POINTS_TEAM_START = 744, - LANG_DIST_ARENA_POINTS_TEAM_END = 745, - LANG_DIST_ARENA_POINTS_END = 746, - LANG_BG_DISABLED = 747, - LANG_ARENA_DISABLED = 748, -// = 749, not used - LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 750, // "Not enough players. This game will close in %u mins." - LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS = 751, // "Not enough players. This game will close in %u seconds." -// = 752, not used -// LANG_BG_WS_START_TWO_MINUTES = 753, - defined above -// LANG_BG_AB_START_TWO_MINUTES = 754, - defined above -// LANG_BG_EY_START_TWO_MINUTES = 755, - defined above - - // Room for BG/ARENA = 773-784, 788-799 not used - LANG_ARENA_TESTING = 785, - LANG_AUTO_ANN = 786, - LANG_ANNOUNCE_COLOR = 787, - - // in game strings - LANG_PET_INVALID_NAME = 800, - LANG_NOT_ENOUGH_GOLD = 801, - LANG_NOT_FREE_TRADE_SLOTS = 802, - LANG_NOT_PARTNER_FREE_TRADE_SLOTS = 803, - LANG_YOU_NOT_HAVE_PERMISSION = 804, - LANG_UNKNOWN_LANGUAGE = 805, - LANG_NOT_LEARNED_LANGUAGE = 806, - LANG_NEED_CHARACTER_NAME = 807, - LANG_PLAYER_NOT_EXIST_OR_OFFLINE = 808, - LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND = 809, - LANG_ACHIEVEMENT_EARNED = 810, - LANG_GUILD_MASTER = 811, - LANG_GUILD_OFFICER = 812, - LANG_GUILD_VETERAN = 813, - LANG_GUILD_MEMBER = 814, - LANG_GUILD_INITIATE = 815, - LANG_ZONE_NOFLYZONE = 816, - - LANG_COMMAND_CREATURETEMPLATE_NOTFOUND = 817, - LANG_COMMAND_CREATURESTORAGE_NOTFOUND = 818, - // Room for in-game strings 819-999 not used - - // Level 4 (CLI only commands) - LANG_COMMAND_EXIT = 1000, - LANG_ACCOUNT_DELETED = 1001, - LANG_ACCOUNT_NOT_DELETED_SQL_ERROR = 1002, - LANG_ACCOUNT_NOT_DELETED = 1003, - LANG_ACCOUNT_CREATED = 1004, - LANG_ACCOUNT_TOO_LONG = 1005, - LANG_ACCOUNT_ALREADY_EXIST = 1006, - LANG_ACCOUNT_NOT_CREATED_SQL_ERROR = 1007, - LANG_ACCOUNT_NOT_CREATED = 1008, - LANG_CHARACTER_DELETED = 1009, - LANG_ACCOUNT_LIST_HEADER = 1010, - LANG_ACCOUNT_LIST_ERROR = 1011, - LANG_ACCOUNT_LIST_BAR = 1012, - LANG_ACCOUNT_LIST_LINE = 1013, - LANG_ACCOUNT_LIST_EMPTY = 1014, - LANG_ACCOUNT_LIST_BAR_HEADER = 1015, - // Room for more level 4 1016-1099 not used - - // Level 3 (continue) - LANG_ACCOUNT_SETADDON = 1100, - LANG_MOTD_NEW = 1101, - LANG_SENDMESSAGE = 1102, - LANG_EVENT_ENTRY_LIST_CONSOLE = 1103, - LANG_CREATURE_ENTRY_LIST_CONSOLE = 1104, - LANG_ITEM_LIST_CONSOLE = 1105, - LANG_ITEMSET_LIST_CONSOLE = 1106, - LANG_GO_ENTRY_LIST_CONSOLE = 1107, - LANG_QUEST_LIST_CONSOLE = 1108, - LANG_SKILL_LIST_CONSOLE = 1109, - LANG_CREATURE_LIST_CONSOLE = 1110, - LANG_GO_LIST_CONSOLE = 1111, - LANG_FILE_OPEN_FAIL = 1112, - LANG_ACCOUNT_CHARACTER_LIST_FULL = 1113, - LANG_DUMP_BROKEN = 1114, - LANG_INVALID_CHARACTER_NAME = 1115, - LANG_INVALID_CHARACTER_GUID = 1116, - LANG_CHARACTER_GUID_IN_USE = 1117, - LANG_ITEMLIST_GUILD = 1118, - LANG_MUST_MALE_OR_FEMALE = 1119, - LANG_YOU_CHANGE_GENDER = 1120, - LANG_YOUR_GENDER_CHANGED = 1121, - LANG_SKILL_VALUES = 1122, - LANG_NO_PET_FOUND = 1123, - LANG_WRONG_PET_TYPE = 1124, - LANG_COMMAND_LEARN_PET_TALENTS = 1125, - LANG_RESET_PET_TALENTS = 1126, - LANG_RESET_PET_TALENTS_ONLINE = 1127, - LANG_TAXINODE_ENTRY_LIST_CHAT = 1128, - LANG_TAXINODE_ENTRY_LIST_CONSOLE = 1129, - // Room for more level 3 1130-1199 not used - - // Debug commands - LANG_CINEMATIC_NOT_EXIST = 1200, - LANG_MOVIE_NOT_EXIST = 1201, - // Room for more debug 1202-1299 not used - - // FREE IDS 1300-9999 - - // AV - LANG_BG_AV_ALLY = 1300, - LANG_BG_AV_HORDE = 1301, - LANG_BG_AV_TOWER_TAKEN = 1302, - LANG_BG_AV_TOWER_ASSAULTED = 1303, - LANG_BG_AV_TOWER_DEFENDED = 1304, - LANG_BG_AV_GRAVE_TAKEN = 1305, - LANG_BG_AV_GRAVE_DEFENDED = 1306, - LANG_BG_AV_GRAVE_ASSAULTED = 1307, - - LANG_BG_AV_MINE_TAKEN = 1308, - LANG_BG_AV_MINE_NORTH = 1309, - LANG_BG_AV_MINE_SOUTH = 1310, - - LANG_BG_AV_NODE_GRAVE_STORM_AID = 1311, - LANG_BG_AV_NODE_TOWER_DUN_S = 1312, - LANG_BG_AV_NODE_TOWER_DUN_N = 1313, - LANG_BG_AV_NODE_GRAVE_STORMPIKE = 1314, - LANG_BG_AV_NODE_TOWER_ICEWING = 1315, - LANG_BG_AV_NODE_GRAVE_STONE = 1316, - LANG_BG_AV_NODE_TOWER_STONE = 1317, - LANG_BG_AV_NODE_GRAVE_SNOW = 1318, - LANG_BG_AV_NODE_TOWER_ICE = 1319, - LANG_BG_AV_NODE_GRAVE_ICE = 1320, - LANG_BG_AV_NODE_TOWER_POINT = 1321, - LANG_BG_AV_NODE_GRAVE_FROST = 1322, - LANG_BG_AV_NODE_TOWER_FROST_E = 1323, - LANG_BG_AV_NODE_TOWER_FROST_W = 1324, - LANG_BG_AV_NODE_GRAVE_FROST_HUT = 1325, - - LANG_BG_AV_START_ONE_MINUTE = 1326, - LANG_BG_AV_START_HALF_MINUTE = 1327, - LANG_BG_AV_HAS_BEGUN = 1328, - LANG_BG_AV_A_NEAR_LOSE = 1329, - LANG_BG_AV_H_NEAR_LOSE = 1330, - LANG_BG_AV_H_CAPTAIN_DEAD = 1331, - LANG_BG_AV_A_CAPTAIN_DEAD = 1332, - LANG_BG_AV_START_TWO_MINUTES = 1333, - // FREE IDS 1334-1999 - - // Ticket Strings 2000-2029 - LANG_COMMAND_TICKETNEW = 2000, - LANG_COMMAND_TICKETUPDATED = 2001, - LANG_COMMAND_TICKETPLAYERABANDON = 2002, - LANG_COMMAND_TICKETCLOSED = 2003, - LANG_COMMAND_TICKETDELETED = 2004, - LANG_COMMAND_TICKETNOTEXIST = 2005, - LANG_COMMAND_TICKETCLOSEFIRST = 2006, - LANG_COMMAND_TICKETALREADYASSIGNED = 2007, - LANG_COMMAND_TICKETRELOAD = 2008, - LANG_COMMAND_TICKETSHOWLIST = 2009, - LANG_COMMAND_TICKETSHOWONLINELIST = 2010, - LANG_COMMAND_TICKETSHOWCLOSEDLIST = 2011, - LANG_COMMAND_TICKETASSIGNERROR_A = 2012, - LANG_COMMAND_TICKETASSIGNERROR_B = 2013, - LANG_COMMAND_TICKETNOTASSIGNED = 2014, - LANG_COMMAND_TICKETUNASSIGNSECURITY = 2015, - LANG_COMMAND_TICKETCANNOTCLOSE = 2016, - LANG_COMMAND_TICKETLISTGUID = 2017, - LANG_COMMAND_TICKETLISTNAME = 2018, - LANG_COMMAND_TICKETLISTAGE = 2019, - LANG_COMMAND_TICKETLISTASSIGNEDTO = 2020, - LANG_COMMAND_TICKETLISTUNASSIGNED = 2021, - LANG_COMMAND_TICKETLISTMESSAGE = 2022, - LANG_COMMAND_TICKETLISTCOMMENT = 2023, - LANG_COMMAND_TICKETLISTADDCOMMENT = 2024, - LANG_COMMAND_TICKETLISTAGECREATE = 2025, - - // Trinity strings 5000-9999 - LANG_COMMAND_FREEZE = 5000, - LANG_COMMAND_FREEZE_ERROR = 5001, - LANG_COMMAND_FREEZE_WRONG = 5002, - LANG_COMMAND_UNFREEZE = 5003, - LANG_COMMAND_NO_FROZEN_PLAYERS = 5004, - LANG_COMMAND_LIST_FREEZE = 5005, - LANG_COMMAND_FROZEN_PLAYERS = 5006, - LANG_INSTANCE_RAID_GROUP_ONLY = 5007, - LANG_INSTANCE_CLOSED = 5008, - LANG_COMMAND_PLAYED_TO_ALL = 5009, - LANG_NPCINFO_LINKGUID = 5010, - LANG_TELEPORTED_TO_BY_CONSOLE = 5011, - // for command lookup map - LANG_COMMAND_NOMAPFOUND = 5012, - LANG_CONTINENT = 5013, - LANG_INSTANCE = 5014, - LANG_BATTLEGROUND = 5015, - LANG_ARENA = 5016, - LANG_RAID = 5017, - LANG_HEROIC = 5018, - LANG_MOUNTABLE = 5019, - LANG_NPCINFO_PHASEMASK = 5020, - LANG_NPCINFO_ARMOR = 5021, - LANG_CHANNEL_NOT_PUBLIC = 5022, - LANG_CHANNEL_PUBLIC_CHANGED = 5023, - LANG_GOINFO_ENTRY = 5024, - LANG_GOINFO_TYPE = 5025, - LANG_GOINFO_DISPLAYID = 5026, - LANG_GOINFO_NAME = 5027, - // Room for more Trinity strings 5028-9999 - - // Level requirement notifications - LANG_SAY_REQ = 6604, - LANG_WHISPER_REQ = 6605, - LANG_CHANNEL_REQ = 6606, - LANG_AUCTION_REQ = 6607, - LANG_TICKET_REQ = 6608, - LANG_TRADE_REQ = 6609, - LANG_TRADE_OTHER_REQ = 6610, - LANG_MAIL_SENDER_REQ = 6611, - LANG_MAIL_RECEIVER_REQ = 6612, - - - // Used for GM Announcements - LANG_GM_BROADCAST = 6613, - LANG_GM_NOTIFY = 6614, - LANG_GM_ANNOUNCE_COLOR = 6615, - - LANG_GM_SILENCE = 6616, // "Silence is ON for %s" - Spell 1852 - - LANG_WORLD_CLOSED = 7523, - LANG_WORLD_OPENED = 7524, - - // Use for not-in-offcial-sources patches - // 10000-10999 - // opvp hp - LANG_OPVP_HP_CAPTURE_OVERLOOK_H = 10001, - LANG_OPVP_HP_CAPTURE_OVERLOOK_A = 10002, - LANG_OPVP_HP_CAPTURE_STADIUM_H = 10003, - LANG_OPVP_HP_CAPTURE_STADIUM_A = 10004, - LANG_OPVP_HP_CAPTURE_BROKENHILL_H = 10005, - LANG_OPVP_HP_CAPTURE_BROKENHILL_A = 10006, - LANG_OPVP_HP_LOOSE_OVERLOOK_H = 10007, - LANG_OPVP_HP_LOOSE_OVERLOOK_A = 10008, - LANG_OPVP_HP_LOOSE_STADIUM_H = 10009, - LANG_OPVP_HP_LOOSE_STADIUM_A = 10010, - LANG_OPVP_HP_LOOSE_BROKENHILL_H = 10011, - LANG_OPVP_HP_LOOSE_BROKENHILL_A = 10012, - // opvp zm - LANG_OPVP_ZM_CAPTURE_WEST_H = 10013, - LANG_OPVP_ZM_CAPTURE_WEST_A = 10014, - LANG_OPVP_ZM_CAPTURE_EAST_H = 10015, - LANG_OPVP_ZM_CAPTURE_EAST_A = 10016, - LANG_OPVP_ZM_CAPTURE_GY_H = 10017, - LANG_OPVP_ZM_CAPTURE_GY_A = 10018, - LANG_OPVP_ZM_LOOSE_WEST_H = 10019, - LANG_OPVP_ZM_LOOSE_WEST_A = 10020, - LANG_OPVP_ZM_LOOSE_EAST_H = 10021, - LANG_OPVP_ZM_LOOSE_EAST_A = 10022, - LANG_OPVP_ZM_LOOSE_GY_H = 10023, - LANG_OPVP_ZM_LOOSE_GY_A = 10024, - // opvp na - LANG_OPVP_NA_CAPTURE_H = 10025, - LANG_OPVP_NA_CAPTURE_A = 10026, - LANG_OPVP_NA_LOOSE_H = 10027, - LANG_OPVP_NA_LOOSE_A = 10028, - // opvp tf - LANG_OPVP_TF_CAPTURE_H = 10029, - LANG_OPVP_TF_CAPTURE_A = 10030, - LANG_OPVP_TF_LOOSE_H = 10031, - LANG_OPVP_TF_LOOSE_A = 10032, - // opvp ep - LANG_OPVP_EP_CAPTURE_NPT_H = 10033, - LANG_OPVP_EP_CAPTURE_NPT_A = 10034, - LANG_OPVP_EP_CAPTURE_EWT_H = 10035, - LANG_OPVP_EP_CAPTURE_EWT_A = 10036, - LANG_OPVP_EP_CAPTURE_CGT_H = 10037, - LANG_OPVP_EP_CAPTURE_CGT_A = 10038, - LANG_OPVP_EP_CAPTURE_PWT_H = 10039, - LANG_OPVP_EP_CAPTURE_PWT_A = 10040, - LANG_OPVP_EP_LOOSE_NPT_H = 10041, - LANG_OPVP_EP_LOOSE_NPT_A = 10042, - LANG_OPVP_EP_LOOSE_EWT_H = 10043, - LANG_OPVP_EP_LOOSE_EWT_A = 10044, - LANG_OPVP_EP_LOOSE_CGT_H = 10045, - LANG_OPVP_EP_LOOSE_CGT_A = 10046, - LANG_OPVP_EP_LOOSE_PWT_H = 10047, - LANG_OPVP_EP_LOOSE_PWT_A = 10048, - // opvp si - LANG_OPVP_SI_CAPTURE_H = 10049, - LANG_OPVP_SI_CAPTURE_A = 10050, - // opvp gossips - LANG_OPVP_EP_FLIGHT_NPT = 10051, - LANG_OPVP_EP_FLIGHT_EWT = 10052, - LANG_OPVP_EP_FLIGHT_CGT = 10053, - LANG_OPVP_ZM_GOSSIP_ALLIANCE = 10054, - LANG_OPVP_ZM_GOSSIP_HORDE = 10055, - - LANG_BG_SA_START_TWO_MINUTES = 10056, - LANG_BG_SA_START_ONE_MINUTE = 10057, - LANG_BG_SA_START_HALF_MINUTE = 10058, - LANG_BG_SA_HAS_BEGUN = 10059, - LANG_BG_SA_IS_UNDER_ATTACK = 10060,//The %s is under attack! - LANG_BG_SA_WAS_DESTROYED = 10061,//The %s was destroyed! - LANG_BG_SA_ROUND_ONE_END = 10062,//Round 1 - finished! - LANG_BG_SA_ALLIANCE_CAPTURED_RELIC = 10063,//The Alliance captured the titan portal! - LANG_BG_SA_HORDE_CAPTURED_RELIC = 10064,//The Horde captured the titan portal! - LANG_BG_SA_ROUND_TWO_ONE_MINUTE = 10065,//Round 2 of the Battle for the Strand of the Ancients begins in 1 minute. - LANG_BG_SA_ROUND_TWO_START_HALF_MINUTE = 10066,//Round 2 begins in 30 seconds. Prepare yourselves! - LANG_BG_SA_CHAMBER_BREACHED = 10067,//The chamber has been breached! The titan relic is vulnerable! - LANG_BG_SA_A_GY_SOUTH = 10068,//The Alliance captured the South Graveyard! - LANG_BG_SA_A_GY_WEST = 10069,//The Alliance captured the West Graveyard! - LANG_BG_SA_A_GY_EAST = 10070,//The Alliance captured the East Graveyard! - LANG_BG_SA_H_GY_SOUTH = 10071,//The Horde captured the South Graveyard! - LANG_BG_SA_H_GY_WEST = 10072,//The Horde captured the West Graveyard! - LANG_BG_SA_H_GY_EAST = 10073,//The Horde captured the East Graveyard! - - // Use for custom patches 11000-11999 - LANG_AUTO_BROADCAST = 11000, - LANG_INVALID_REALMID = 11001, - - // NOT RESERVED IDS 12000-1999999999 - // `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID) - // For other tables maybe 2000010000-2147483647 (max index) -}; -#endif - diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp new file mode 100644 index 00000000000..cf5bc728c6e --- /dev/null +++ b/src/server/game/Globals/ObjectAccessor.cpp @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "Policies/SingletonImp.h" +#include "Player.h" +#include "Creature.h" +#include "GameObject.h" +#include "DynamicObject.h" +#include "Vehicle.h" +#include "WorldPacket.h" +#include "Item.h" +#include "Corpse.h" +#include "GridNotifiers.h" +#include "MapManager.h" +#include "Map.h" +#include "CellImpl.h" +#include "GridNotifiersImpl.h" +#include "Opcodes.h" +#include "ObjectDefines.h" +#include "MapInstanced.h" +#include "World.h" + +#include + +#define CLASS_LOCK Trinity::ClassLevelLockable +INSTANTIATE_SINGLETON_2(ObjectAccessor, CLASS_LOCK); +INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ACE_Thread_Mutex); + +ObjectAccessor::ObjectAccessor() +{ +} + +ObjectAccessor::~ObjectAccessor() +{ + for (Player2CorpsesMapType::const_iterator itr = i_player2corpse.begin(); itr != i_player2corpse.end(); ++itr) + { + itr->second->RemoveFromWorld(); + delete itr->second; + } +} + +Creature* ObjectAccessor::GetCreatureOrPetOrVehicle(WorldObject const& u, uint64 guid) +{ + if (IS_PLAYER_GUID(guid)) + return NULL; + + if (IS_PET_GUID(guid)) + return GetPet(guid); + + return u.IsInWorld() ? u.GetMap()->GetCreature(guid) : NULL; +} + +Corpse* ObjectAccessor::GetCorpse(WorldObject const& u, uint64 guid) +{ + Corpse* ret = GetObjectInWorld(guid, (Corpse*)NULL); + + if (!ret) + return NULL; + + if (ret->GetMapId() != u.GetMapId()) + return NULL; + + if (ret->GetInstanceId() != u.GetInstanceId()) + return NULL; + + return ret; +} + +WorldObject* ObjectAccessor::GetWorldObject(WorldObject const& p, uint64 guid) +{ + switch (GUID_HIPART(guid)) + { + case HIGHGUID_PLAYER: return FindPlayer(guid); + case HIGHGUID_GAMEOBJECT: return p.GetMap()->GetGameObject(guid); + case HIGHGUID_VEHICLE: + case HIGHGUID_UNIT: return p.GetMap()->GetCreature(guid); + case HIGHGUID_PET: return GetPet(guid); + case HIGHGUID_DYNAMICOBJECT: return p.GetMap()->GetDynamicObject(guid); + case HIGHGUID_TRANSPORT: return NULL; + case HIGHGUID_CORPSE: return GetCorpse(p,guid); + case HIGHGUID_MO_TRANSPORT: return NULL; + default: return NULL; + } +} + +Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const& p, uint64 guid, uint32 typemask) +{ + switch (GUID_HIPART(guid)) + { + case HIGHGUID_ITEM: + if (typemask & TYPEMASK_ITEM && p.GetTypeId() == TYPEID_PLAYER) + return ((Player const&)p).GetItemByGuid(guid); + break; + case HIGHGUID_PLAYER: + if (typemask & TYPEMASK_PLAYER) + return FindPlayer(guid); + break; + case HIGHGUID_GAMEOBJECT: + if (typemask & TYPEMASK_GAMEOBJECT) + return p.GetMap()->GetGameObject(guid); + break; + case HIGHGUID_UNIT: + case HIGHGUID_VEHICLE: + if (typemask & TYPEMASK_UNIT) + return p.GetMap()->GetCreature(guid); + break; + case HIGHGUID_PET: + if (typemask & TYPEMASK_UNIT) + return GetPet(guid); + break; + case HIGHGUID_DYNAMICOBJECT: + if (typemask & TYPEMASK_DYNAMICOBJECT) + return p.GetMap()->GetDynamicObject(guid); + break; + case HIGHGUID_TRANSPORT: + case HIGHGUID_CORPSE: + case HIGHGUID_MO_TRANSPORT: + break; + } + + return NULL; +} + +Player* ObjectAccessor::FindPlayer(uint64 guid) +{ + Player* plr = GetObjectInWorld(guid, (Player*)NULL); + if (!plr || !plr->IsInWorld()) + return NULL; + + return plr; +} + +Player* ObjectAccessor::FindPlayerByName(const char* name) +{ + Guard guard(*HashMapHolder::GetLock()); + HashMapHolder::MapType& m = HashMapHolder::GetContainer(); + for (HashMapHolder::MapType::iterator iter = m.begin(); iter != m.end(); ++iter) + if (iter->second->IsInWorld() && strcmp(name, iter->second->GetName()) == 0) + return iter->second; + + return NULL; +} + +void ObjectAccessor::SaveAllPlayers() +{ + Guard guard(*HashMapHolder::GetLock()); + HashMapHolder::MapType& m = HashMapHolder::GetContainer(); + for (HashMapHolder::MapType::iterator itr = m.begin(); itr != m.end(); ++itr) + itr->second->SaveToDB(); +} + +Pet* ObjectAccessor::GetPet(uint64 guid) +{ + return GetObjectInWorld(guid, (Pet*)NULL); +} + +Corpse* ObjectAccessor::GetCorpseForPlayerGUID(uint64 guid) +{ + Guard guard(i_corpseGuard); + + Player2CorpsesMapType::iterator iter = i_player2corpse.find(guid); + if (iter == i_player2corpse.end()) + return NULL; + + assert(iter->second->GetType() != CORPSE_BONES); + + return iter->second; +} + +void ObjectAccessor::RemoveCorpse(Corpse* corpse) +{ + assert(corpse && corpse->GetType() != CORPSE_BONES); + + if (corpse->FindMap()) + corpse->FindMap()->Remove(corpse, false); + else + corpse->RemoveFromWorld(); + + // Critical section + { + Guard guard(i_corpseGuard); + + Player2CorpsesMapType::iterator iter = i_player2corpse.find(corpse->GetOwnerGUID()); + if (iter == i_player2corpse.end()) // TODO: Fix this + return; + + // build mapid*cellid -> guid_set map + CellPair cell_pair = Trinity::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY()); + uint32 cell_id = (cell_pair.y_coord * TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; + + objmgr.DeleteCorpseCellData(corpse->GetMapId(), cell_id, corpse->GetOwnerGUID()); + + i_player2corpse.erase(iter); + } +} + +void ObjectAccessor::AddCorpse(Corpse* corpse) +{ + assert(corpse && corpse->GetType() != CORPSE_BONES); + + // Critical section + { + Guard guard(i_corpseGuard); + + assert(i_player2corpse.find(corpse->GetOwnerGUID()) == i_player2corpse.end()); + i_player2corpse[corpse->GetOwnerGUID()] = corpse; + + // build mapid*cellid -> guid_set map + CellPair cell_pair = Trinity::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY()); + uint32 cell_id = (cell_pair.y_coord * TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; + + objmgr.AddCorpseCellData(corpse->GetMapId(), cell_id, corpse->GetOwnerGUID(), corpse->GetInstanceId()); + } +} + +void ObjectAccessor::AddCorpsesToGrid(GridPair const& gridpair, GridType& grid, Map* map) +{ + Guard guard(i_corpseGuard); + + for (Player2CorpsesMapType::iterator iter = i_player2corpse.begin(); iter != i_player2corpse.end(); ++iter) + { + if (iter->second->GetGrid() == gridpair) + { + // verify, if the corpse in our instance (add only corpses which are) + if (map->Instanceable()) + { + if (iter->second->GetInstanceId() == map->GetInstanceId()) + grid.AddWorldObject(iter->second); + } + else + grid.AddWorldObject(iter->second); + } + } +} + +Corpse* ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool /*insignia*/) +{ + Corpse* corpse = GetCorpseForPlayerGUID(player_guid); + if (!corpse) + { + //in fact this function is called from several places + //even when player doesn't have a corpse, not an error + // TODO: really, now... + //sLog.outError("Try remove corpse that not in map for GUID %ul", player_guid); + return NULL; + } + + DEBUG_LOG("Deleting Corpse and spawned bones."); + + //Map* map = corpse->FindMap(); + + // remove corpse from player_guid -> corpse map + RemoveCorpse(corpse); + + // done in removecorpse + // remove resurrectable corpse from grid object registry (loaded state checked into call) + // do not load the map if it's not loaded + //Map *map = MapManager::Instance().FindMap(corpse->GetMapId(), corpse->GetInstanceId()); + //if (map) + // map->Remove(corpse, false); + + // remove corpse from DB + corpse->DeleteFromDB(); + + // we don't want bones to save some cpu.. :) + delete corpse; + return NULL; + + /* + Corpse* bones = NULL; + // create the bones only if the map and the grid is loaded at the corpse's location + // ignore bones creating option in case insignia + if (map && (insignia || + (map->IsBattleGroundOrArena() ? sWorld.getConfig(CONFIG_DEATH_BONES_BG_OR_ARENA) : sWorld.getConfig(CONFIG_DEATH_BONES_WORLD))) && + !map->IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY())) + { + // Create bones, don't change Corpse + bones = new Corpse; + bones->Create(corpse->GetGUIDLow(), map); + + for (int i = 3; i < CORPSE_END; ++i) // don't overwrite guid and object type + bones->SetUInt32Value(i, corpse->GetUInt32Value(i)); + + bones->SetGrid(corpse->GetGrid()); + // bones->m_time = m_time; // don't overwrite time + // bones->m_inWorld = m_inWorld; // don't overwrite in-world state + // bones->m_type = m_type; // don't overwrite type + bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation()); + bones->SetPhaseMask(corpse->GetPhaseMask(), false); + + bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES); + bones->SetUInt64Value(CORPSE_FIELD_OWNER, 0); + + for (int i = 0; i < EQUIPMENT_SLOT_END; ++i) + { + if (corpse->GetUInt32Value(CORPSE_FIELD_ITEM + i)) + bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0); + } + + // add bones in grid store if grid loaded where corpse placed + map->Add(bones); + } + + // all references to the corpse should be removed at this point + delete corpse; + + return bones; + */ +} + +void ObjectAccessor::Update(uint32 /*diff*/) +{ + UpdateDataMapType update_players; + + // Critical section + { + Guard guard(i_updateGuard); + + while (!i_objects.empty()) + { + Object* obj = *i_objects.begin(); + assert(obj && obj->IsInWorld()); + i_objects.erase(i_objects.begin()); + obj->BuildUpdate(update_players); + } + } + + WorldPacket packet; // here we allocate a std::vector with a size of 0x10000 + for (UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter) + { + iter->second.BuildPacket(&packet); + iter->first->GetSession()->SendPacket(&packet); + packet.clear(); // clean the string + } +} + +/// Define the static members of HashMapHolder + +template UNORDERED_MAP< uint64, T* > HashMapHolder::m_objectMap; +template ACE_Thread_Mutex HashMapHolder::i_lock; + +/// Global definitions for the hashmap storage + +template class HashMapHolder; +template class HashMapHolder; +template class HashMapHolder; +template class HashMapHolder; +template class HashMapHolder; +template class HashMapHolder; + +template Player* ObjectAccessor::GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, Player* /*fake*/); +template Pet* ObjectAccessor::GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, Pet* /*fake*/); +template Creature* ObjectAccessor::GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, Creature* /*fake*/); +template Corpse* ObjectAccessor::GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, Corpse* /*fake*/); +template GameObject* ObjectAccessor::GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, GameObject* /*fake*/); +template DynamicObject* ObjectAccessor::GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, DynamicObject* /*fake*/); diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h new file mode 100644 index 00000000000..8e64eb48fa0 --- /dev/null +++ b/src/server/game/Globals/ObjectAccessor.h @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_OBJECTACCESSOR_H +#define TRINITY_OBJECTACCESSOR_H + +#include "Platform/Define.h" +#include "Policies/Singleton.h" +#include +#include "Utilities/UnorderedMap.h" +#include "Policies/ThreadingModel.h" + +#include "UpdateData.h" + +#include "GridDefines.h" +#include "Object.h" +#include "Player.h" + +#include + +class Creature; +class Corpse; +class Unit; +class GameObject; +class DynamicObject; +class WorldObject; +class Map; + +template +class HashMapHolder +{ + public: + + typedef UNORDERED_MAP MapType; + typedef ACE_Thread_Mutex LockType; + typedef Trinity::GeneralLock Guard; + + static void Insert(T* o) + { + Guard guard(i_lock); + m_objectMap[o->GetGUID()] = o; + } + + static void Remove(T* o) + { + Guard guard(i_lock); + m_objectMap.erase(o->GetGUID()); + } + + static T* Find(uint64 guid) + { + Guard guard(i_lock); + typename MapType::iterator itr = m_objectMap.find(guid); + return (itr != m_objectMap.end()) ? itr->second : NULL; + } + + static MapType& GetContainer() { return m_objectMap; } + + static LockType* GetLock() { return &i_lock; } + + private: + + //Non instanceable only static + HashMapHolder() {} + + static LockType i_lock; + static MapType m_objectMap; +}; + +class ObjectAccessor : public Trinity::Singleton > +{ + friend class Trinity::OperatorNew; + ObjectAccessor(); + ~ObjectAccessor(); + ObjectAccessor(const ObjectAccessor&); + ObjectAccessor& operator=(const ObjectAccessor&); + + public: + + typedef UNORDERED_MAP Player2CorpsesMapType; + typedef UNORDERED_MAP::value_type UpdateDataValueType; + + template static T* GetObjectInWorld(uint64 guid, T* /*fake*/) + { + return HashMapHolder::Find(guid); + } + + static Unit* GetObjectInWorld(uint64 guid, Unit* /*fake*/) + { + if (!guid) + return NULL; + + if (IS_PLAYER_GUID(guid)) + { + Unit* u = (Unit*)HashMapHolder::Find(guid); + if (!u || !u->IsInWorld()) + return NULL; + + return u; + } + + if (IS_PET_GUID(guid)) + return (Unit*)HashMapHolder::Find(guid); + + return (Unit*)HashMapHolder::Find(guid); + } + + static Unit* GetUnitInOrOutOfWorld(uint64 guid, Unit* /*fake*/) + { + if (!guid) + return NULL; + + if (IS_PLAYER_GUID(guid)) + { + Unit* u = (Unit*)HashMapHolder::Find(guid); + if (!u) + return NULL; + + return u; + } + + // Other object types than player are unloaded while out of world + return GetObjectInWorld(guid, (Unit*)NULL); + } + + template static T* GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, T* /*fake*/) + { + T* obj = HashMapHolder::Find(guid); + if (!obj || obj->GetMapId() != mapid) + return NULL; + + CellPair p = Trinity::ComputeCellPair(x, y); + if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + { + sLog.outError("ObjectAccessor::GetObjectInWorld: invalid coordinates supplied X:%f Y:%f grid cell [%u:%u]", x, y, p.x_coord, p.y_coord); + return NULL; + } + + CellPair q = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); + if (q.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || q.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + { + sLog.outError("ObjectAccessor::GetObjecInWorld: object (GUID: %u TypeId: %u) has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUIDLow(), obj->GetTypeId(), obj->GetPositionX(), obj->GetPositionY(), q.x_coord, q.y_coord); + return NULL; + } + + int32 dx = int32(p.x_coord) - int32(q.x_coord); + int32 dy = int32(p.y_coord) - int32(q.y_coord); + + if (dx > -2 && dx < 2 && dy > -2 && dy < 2) + return obj; + else + return NULL; + } + + static WorldObject* GetWorldObject(WorldObject const&, uint64); + static Object* GetObjectByTypeMask(WorldObject const&, uint64, uint32 typemask); + static Creature* GetCreatureOrPetOrVehicle(WorldObject const&, uint64); + static Unit* GetUnit(WorldObject const&, uint64 guid) { return GetObjectInWorld(guid, (Unit*)NULL); } + static Unit* GetUnitInOrOutOfWorld(WorldObject const&, uint64 guid) { return GetUnitInOrOutOfWorld(guid, (Unit*)NULL); } + static Pet* GetPet(Unit const&, uint64 guid) { return GetPet(guid); } + static Player* GetPlayer(Unit const&, uint64 guid) { return FindPlayer(guid); } + static Corpse* GetCorpse(WorldObject const& u, uint64 guid); + static Pet* GetPet(uint64 guid); + static Player* FindPlayer(uint64); + + Player* FindPlayerByName(const char* name) ; + + // when using this, you must use the hashmapholder's lock + HashMapHolder::MapType& GetPlayers() + { + return HashMapHolder::GetContainer(); + } + + // when using this, you must use the hashmapholder's lock + HashMapHolder::MapType& GetCreatures() + { + return HashMapHolder::GetContainer(); + } + + // when using this, you must use the hashmapholder's lock + HashMapHolder::MapType& GetGameObjects() + { + return HashMapHolder::GetContainer(); + } + + template void AddObject(T* object) + { + HashMapHolder::Insert(object); + } + + template void RemoveObject(T* object) + { + HashMapHolder::Remove(object); + } + + void RemoveObject(Player* pl) + { + HashMapHolder::Remove(pl); + RemoveUpdateObject((Object*)pl); + } + + void SaveAllPlayers(); + + void AddUpdateObject(Object* obj) + { + Guard guard(i_updateGuard); + i_objects.insert(obj); + } + + void RemoveUpdateObject(Object* obj) + { + Guard guard(i_updateGuard); + i_objects.erase(obj); + } + + void Update(uint32 diff); + + Corpse* GetCorpseForPlayerGUID(uint64 guid); + void RemoveCorpse(Corpse* corpse); + void AddCorpse(Corpse* corpse); + void AddCorpsesToGrid(GridPair const& gridpair, GridType& grid, Map* map); + Corpse* ConvertCorpseForPlayer(uint64 player_guid, bool insignia = false); + + typedef ACE_Thread_Mutex LockType; + typedef Trinity::GeneralLock Guard; + + private: + + Player2CorpsesMapType i_player2corpse; + + static void _buildChangeObjectForPlayer(WorldObject*, UpdateDataMapType&); + static void _buildPacket(Player*, Object*, UpdateDataMapType&); + void _update(); + + std::set i_objects; + + LockType i_updateGuard; + LockType i_corpseGuard; +}; +#endif diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp new file mode 100644 index 00000000000..ce86c2a4e77 --- /dev/null +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -0,0 +1,8724 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "Database/SQLStorage.h" +#include "Database/SQLStorageImpl.h" +#include "Policies/SingletonImp.h" + +#include "Log.h" +#include "MapManager.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "UpdateMask.h" +#include "World.h" +#include "Group.h" +#include "Guild.h" +#include "ArenaTeam.h" +#include "Transports.h" +#include "ProgressBar.h" +#include "Language.h" +#include "GameEventMgr.h" +#include "Spell.h" +#include "Chat.h" +#include "AccountMgr.h" +#include "InstanceSaveMgr.h" +#include "SpellAuras.h" +#include "Util.h" +#include "WaypointManager.h" +#include "GossipDef.h" +#include "Vehicle.h" +#include "AchievementMgr.h" + +INSTANTIATE_SINGLETON_1(ObjectMgr); + +ScriptMapMap sQuestEndScripts; +ScriptMapMap sQuestStartScripts; +ScriptMapMap sSpellScripts; +ScriptMapMap sGameObjectScripts; +ScriptMapMap sEventScripts; +ScriptMapMap sGossipScripts; +ScriptMapMap sWaypointScripts; + +bool normalizePlayerName(std::string& name) +{ + if (name.empty()) + return false; + + wchar_t wstr_buf[MAX_INTERNAL_PLAYER_NAME+1]; + size_t wstr_len = MAX_INTERNAL_PLAYER_NAME; + + if (!Utf8toWStr(name,&wstr_buf[0],wstr_len)) + return false; + + wstr_buf[0] = wcharToUpper(wstr_buf[0]); + for (size_t i = 1; i < wstr_len; ++i) + wstr_buf[i] = wcharToLower(wstr_buf[i]); + + if (!WStrToUtf8(wstr_buf,wstr_len,name)) + return false; + + return true; +} + +LanguageDesc lang_description[LANGUAGES_COUNT] = +{ + { LANG_ADDON, 0, 0 }, + { LANG_UNIVERSAL, 0, 0 }, + { LANG_ORCISH, 669, SKILL_LANG_ORCISH }, + { LANG_DARNASSIAN, 671, SKILL_LANG_DARNASSIAN }, + { LANG_TAURAHE, 670, SKILL_LANG_TAURAHE }, + { LANG_DWARVISH, 672, SKILL_LANG_DWARVEN }, + { LANG_COMMON, 668, SKILL_LANG_COMMON }, + { LANG_DEMONIC, 815, SKILL_LANG_DEMON_TONGUE }, + { LANG_TITAN, 816, SKILL_LANG_TITAN }, + { LANG_THALASSIAN, 813, SKILL_LANG_THALASSIAN }, + { LANG_DRACONIC, 814, SKILL_LANG_DRACONIC }, + { LANG_KALIMAG, 817, SKILL_LANG_OLD_TONGUE }, + { LANG_GNOMISH, 7340, SKILL_LANG_GNOMISH }, + { LANG_TROLL, 7341, SKILL_LANG_TROLL }, + { LANG_GUTTERSPEAK, 17737, SKILL_LANG_GUTTERSPEAK }, + { LANG_DRAENEI, 29932, SKILL_LANG_DRAENEI }, + { LANG_ZOMBIE, 0, 0 }, + { LANG_GNOMISH_BINARY, 0, 0 }, + { LANG_GOBLIN_BINARY, 0, 0 } +}; + +LanguageDesc const* GetLanguageDescByID(uint32 lang) +{ + for (uint8 i = 0; i < LANGUAGES_COUNT; ++i) + { + if (uint32(lang_description[i].lang_id) == lang) + return &lang_description[i]; + } + + return NULL; +} + +bool SpellClickInfo::IsFitToRequirements(Player const* player, Creature const * clickNpc) const +{ + if (questStart) + { + // not in expected required quest state + if (!player || ((!questStartCanActive || !player->IsActiveQuest(questStart)) && !player->GetQuestRewardStatus(questStart))) + return false; + } + + if (questEnd) + { + // not in expected forbidden quest state + if (!player || player->GetQuestRewardStatus(questEnd)) + return false; + } + + if (auraRequired) + if (!player->HasAura(auraRequired)) + return false; + + if (auraForbidden) + if (player->HasAura(auraForbidden)) + return false; + + Unit const * summoner = NULL; + // Check summoners for party + if (clickNpc->isSummon()) + summoner = clickNpc->ToTempSummon()->GetSummoner(); + if (!summoner) + summoner = clickNpc; + + switch (userType) + { + case SPELL_CLICK_USER_FRIEND: + if (!player->IsFriendlyTo(summoner)) + return false; + break; + case SPELL_CLICK_USER_RAID: + if (!player->IsInRaidWith(summoner)) + return false; + break; + case SPELL_CLICK_USER_PARTY: + if (!player->IsInPartyWith(summoner)) + return false; + break; + } + + return true; +} + +ObjectMgr::ObjectMgr() +{ + m_hiCharGuid = 1; + m_hiCreatureGuid = 1; + m_hiPetGuid = 1; + m_hiVehicleGuid = 1; + m_hiItemGuid = 1; + m_hiGoGuid = 1; + m_hiDoGuid = 1; + m_hiCorpseGuid = 1; + m_hiPetNumber = 1; + m_hiGroupGuid = 1; + m_ItemTextId = 1; + m_mailid = 1; + m_equipmentSetGuid = 1; + m_guildId = 1; + m_arenaTeamId = 1; + m_auctionid = 1; +} + +ObjectMgr::~ObjectMgr() +{ + for (QuestMap::iterator i = mQuestTemplates.begin(); i != mQuestTemplates.end(); ++i) + delete i->second; + + for (PetLevelInfoMap::iterator i = petInfo.begin(); i != petInfo.end(); ++i) + delete[] i->second; + + // free only if loaded + for (int class_ = 0; class_ < MAX_CLASSES; ++class_) + delete[] playerClassInfo[class_].levelInfo; + + for (int race = 0; race < MAX_RACES; ++race) + for (int class_ = 0; class_ < MAX_CLASSES; ++class_) + delete[] playerInfo[race][class_].levelInfo; + + // free group and guild objects + for (GroupSet::iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr) + delete (*itr); + + for (GuildMap::iterator itr = mGuildMap.begin(); itr != mGuildMap.end(); ++itr) + delete itr->second; + + for (ArenaTeamMap::iterator itr = mArenaTeamMap.begin(); itr != mArenaTeamMap.end(); ++itr) + delete itr->second; + + for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr) + itr->second.Clear(); + + for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr) + itr->second.Clear(); +} + +Group * ObjectMgr::GetGroupByGUID(const uint64 &guid) const +{ + for (GroupSet::const_iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr) + if ((*itr)->GetGUID() == guid) + return *itr; + + return NULL; +} + +Guild * ObjectMgr::GetGuildById(uint32 GuildId) const +{ + GuildMap::const_iterator itr = mGuildMap.find(GuildId); + if (itr != mGuildMap.end()) + return itr->second; + + return NULL; +} + +Guild * ObjectMgr::GetGuildByName(const std::string& guildname) const +{ + std::string search = guildname; + std::transform(search.begin(), search.end(), search.begin(), ::toupper); + for (GuildMap::const_iterator itr = mGuildMap.begin(); itr != mGuildMap.end(); ++itr) + { + std::string gname = itr->second->GetName(); + std::transform(gname.begin(), gname.end(), gname.begin(), ::toupper); + if (search == gname) + return itr->second; + } + return NULL; +} + +std::string ObjectMgr::GetGuildNameById(uint32 GuildId) const +{ + GuildMap::const_iterator itr = mGuildMap.find(GuildId); + if (itr != mGuildMap.end()) + return itr->second->GetName(); + + return ""; +} + +Guild* ObjectMgr::GetGuildByLeader(const uint64 &guid) const +{ + for (GuildMap::const_iterator itr = mGuildMap.begin(); itr != mGuildMap.end(); ++itr) + if (itr->second->GetLeader() == guid) + return itr->second; + + return NULL; +} + +void ObjectMgr::AddGuild(Guild* guild) +{ + mGuildMap[guild->GetId()] = guild; +} + +void ObjectMgr::RemoveGuild(uint32 Id) +{ + mGuildMap.erase(Id); +} + +ArenaTeam* ObjectMgr::GetArenaTeamById(uint32 arenateamid) const +{ + ArenaTeamMap::const_iterator itr = mArenaTeamMap.find(arenateamid); + if (itr != mArenaTeamMap.end()) + return itr->second; + + return NULL; +} + +ArenaTeam* ObjectMgr::GetArenaTeamByName(const std::string& arenateamname) const +{ + std::string search = arenateamname; + std::transform(search.begin(), search.end(), search.begin(), ::toupper); + for (ArenaTeamMap::const_iterator itr = mArenaTeamMap.begin(); itr != mArenaTeamMap.end(); ++itr) + { + std::string teamname = itr->second->GetName(); + std::transform(teamname.begin(), teamname.end(), teamname.begin(), ::toupper); + if (search == teamname) + return itr->second; + } + return NULL; +} + +ArenaTeam* ObjectMgr::GetArenaTeamByCaptain(uint64 const& guid) const +{ + for (ArenaTeamMap::const_iterator itr = mArenaTeamMap.begin(); itr != mArenaTeamMap.end(); ++itr) + if (itr->second->GetCaptain() == guid) + return itr->second; + + return NULL; +} + +void ObjectMgr::AddArenaTeam(ArenaTeam* arenaTeam) +{ + mArenaTeamMap[arenaTeam->GetId()] = arenaTeam; +} + +void ObjectMgr::RemoveArenaTeam(uint32 Id) +{ + mArenaTeamMap.erase(Id); +} + +CreatureInfo const* ObjectMgr::GetCreatureTemplate(uint32 id) +{ + return sCreatureStorage.LookupEntry(id); +} + +void ObjectMgr::LoadCreatureLocales() +{ + mCreatureLocaleMap.clear(); // need for reload case + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry,name_loc1,subname_loc1,name_loc2,subname_loc2,name_loc3,subname_loc3,name_loc4,subname_loc4,name_loc5,subname_loc5,name_loc6,subname_loc6,name_loc7,subname_loc7,name_loc8,subname_loc8 FROM locales_creature"); + + if (!result) + return; + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + + CreatureLocale& data = mCreatureLocaleMap[entry]; + + for (uint8 i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[1+2*(i-1)].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.Name.size() <= idx) + data.Name.resize(idx+1); + + data.Name[idx] = str; + } + } + str = fields[1+2*(i-1)+1].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.SubName.size() <= idx) + data.SubName.resize(idx+1); + + data.SubName[idx] = str; + } + } + } + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %lu creature locale strings", (unsigned long)mCreatureLocaleMap.size()); +} + +void ObjectMgr::LoadGossipMenuItemsLocales() +{ + mGossipMenuItemsLocaleMap.clear(); // need for reload case + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT menu_id,id," + "option_text_loc1,box_text_loc1,option_text_loc2,box_text_loc2," + "option_text_loc3,box_text_loc3,option_text_loc4,box_text_loc4," + "option_text_loc5,box_text_loc5,option_text_loc6,box_text_loc6," + "option_text_loc7,box_text_loc7,option_text_loc8,box_text_loc8 " + "FROM locales_gossip_menu_option"); + + if (!result) + return; + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint16 menuId = fields[0].GetUInt16(); + uint16 id = fields[1].GetUInt16(); + + GossipMenuItemsLocale& data = mGossipMenuItemsLocaleMap[MAKE_PAIR32(menuId,id)]; + + for (uint8 i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[2+2*(i-1)].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.OptionText.size() <= idx) + data.OptionText.resize(idx+1); + + data.OptionText[idx] = str; + } + } + str = fields[2+2*(i-1)+1].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.BoxText.size() <= idx) + data.BoxText.resize(idx+1); + + data.BoxText[idx] = str; + } + } + } + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %lu gossip_menu_option locale strings", (unsigned long)mGossipMenuItemsLocaleMap.size()); +} + +void ObjectMgr::LoadPointOfInterestLocales() +{ + mPointOfInterestLocaleMap.clear(); // need for reload case + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry,icon_name_loc1,icon_name_loc2,icon_name_loc3,icon_name_loc4,icon_name_loc5,icon_name_loc6,icon_name_loc7,icon_name_loc8 FROM locales_points_of_interest"); + + if (!result) + return; + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + + PointOfInterestLocale& data = mPointOfInterestLocaleMap[entry]; + + for (uint8 i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[i].GetCppString(); + if (str.empty()) + continue; + + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.IconName.size() <= idx) + data.IconName.resize(idx+1); + + data.IconName[idx] = str; + } + } + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %lu points_of_interest locale strings", (unsigned long)mPointOfInterestLocaleMap.size()); +} + +struct SQLCreatureLoader : public SQLStorageLoaderBase +{ + template + void convert_from_str(uint32 /*field_pos*/, char *src, D &dst) + { + dst = D(objmgr.GetScriptId(src)); + } +}; + +void ObjectMgr::LoadCreatureTemplates() +{ + SQLCreatureLoader loader; + loader.Load(sCreatureStorage); + + sLog.outString(">> Loaded %u creature definitions", sCreatureStorage.RecordCount); + sLog.outString(); + + // check data correctness + for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i) + { + CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i); + CheckCreatureTemplate(cInfo); + } +} + +void ObjectMgr::CheckCreatureTemplate(CreatureInfo const* cInfo) +{ + if (!cInfo) + return; + + bool ok = true; // bool to allow continue outside this loop + for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && ok; ++diff) + { + if (!cInfo->DifficultyEntry[diff]) + continue; + ok = false; // will be set to true at the end of this loop again + + CreatureInfo const* difficultyInfo = GetCreatureTemplate(cInfo->DifficultyEntry[diff]); + if (!difficultyInfo) + { + sLog.outErrorDb("Creature (Entry: %u) have `difficulty_entry_%u`=%u but creature entry %u not exist.", + cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff], cInfo->DifficultyEntry[diff]); + continue; + } + + if (difficultyEntries[diff].find(cInfo->Entry) != difficultyEntries[diff].end()) + { + sLog.outErrorDb("Creature (Entry: %u) listed as difficulty %u but have value in `difficulty_entry_1`.", cInfo->Entry, diff + 1); + continue; + } + + bool ok2 = true; + for (uint32 diff2 = 0; diff2 < MAX_DIFFICULTY - 1 && ok2; ++diff2) + { + ok2 = false; + if (difficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != difficultyEntries[diff2].end()) + { + sLog.outErrorDb("Creature (Entry: %u) already listed as difficulty %u for another entry.", cInfo->DifficultyEntry[diff], diff2 + 1); + continue; + } + + if (hasDifficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != hasDifficultyEntries[diff2].end()) + { + sLog.outErrorDb("Creature (Entry: %u) have `difficulty_entry_%u`=%u but creature entry %u have difficulty %u entry also.", + cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff], cInfo->DifficultyEntry[diff], diff2 + 1); + continue; + } + ok2 = true; + } + if (!ok2) + continue; + + if (cInfo->unit_class != difficultyInfo->unit_class) + { + sLog.outErrorDb("Creature (Entry: %u, class %u) has different `unit_class` in difficulty %u mode (Entry: %u, class %u).", + cInfo->Entry, cInfo->unit_class, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->unit_class); + continue; + } + + if (cInfo->npcflag != difficultyInfo->npcflag) + { + sLog.outErrorDb("Creature (Entry: %u) has different `npcflag` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]); + continue; + } + + if (cInfo->trainer_class != difficultyInfo->trainer_class) + { + sLog.outErrorDb("Creature (Entry: %u) has different `trainer_class` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]); + continue; + } + + if (cInfo->trainer_race != difficultyInfo->trainer_race) + { + sLog.outErrorDb("Creature (Entry: %u) has different `trainer_race` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]); + continue; + } + + if (cInfo->trainer_type != difficultyInfo->trainer_type) + { + sLog.outErrorDb("Creature (Entry: %u) has different `trainer_type` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]); + continue; + } + + if (cInfo->trainer_spell != difficultyInfo->trainer_spell) + { + sLog.outErrorDb("Creature (Entry: %u) has different `trainer_spell` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]); + continue; + } + + if (difficultyInfo->AIName && *difficultyInfo->AIName) + { + sLog.outErrorDb("Difficulty %u mode creature (Entry: %u) has `AIName`, but in any case will used difficulty 0 mode creature (Entry: %u) AIName.", + diff, cInfo->DifficultyEntry[diff], cInfo->Entry); + continue; + } + + if (difficultyInfo->ScriptID) + { + sLog.outErrorDb("Difficulty %u mode creature (Entry: %u) has `ScriptName`, but in any case will used difficulty 0 mode creature (Entry: %u) ScriptName.", + diff, cInfo->DifficultyEntry[diff], cInfo->Entry); + continue; + } + + hasDifficultyEntries[diff].insert(cInfo->Entry); + difficultyEntries[diff].insert(cInfo->DifficultyEntry[diff]); + ok = true; + } + + FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_A); + if (!factionTemplate) + sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_A template (%u)", cInfo->Entry, cInfo->faction_A); + + factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_H); + if (!factionTemplate) + sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_H template (%u)", cInfo->Entry, cInfo->faction_H); + + // used later for scale + CreatureDisplayInfoEntry const* displayScaleEntry = NULL; + + if (cInfo->Modelid1) + { + CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid1); + if (!displayEntry) + { + sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid1 id (%u), can crash client", cInfo->Entry, cInfo->Modelid1); + const_cast(cInfo)->Modelid1 = 0; + } + else if (!displayScaleEntry) + displayScaleEntry = displayEntry; + + CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry(cInfo->Modelid1); + if (!minfo) + sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid1 (%u)", cInfo->Entry, cInfo->Modelid1); + } + + if (cInfo->Modelid2) + { + CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid2); + if (!displayEntry) + { + sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid2 id (%u), can crash client", cInfo->Entry, cInfo->Modelid2); + const_cast(cInfo)->Modelid2 = 0; + } + else if (!displayScaleEntry) + displayScaleEntry = displayEntry; + + CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry(cInfo->Modelid2); + if (!minfo) + sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid2 (%u)", cInfo->Entry, cInfo->Modelid2); + } + + if (cInfo->Modelid3) + { + CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid3); + if (!displayEntry) + { + sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid3 id (%u), can crash client", cInfo->Entry, cInfo->Modelid3); + const_cast(cInfo)->Modelid3 = 0; + } + else if (!displayScaleEntry) + displayScaleEntry = displayEntry; + + CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry(cInfo->Modelid3); + if (!minfo) + sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid3 (%u)", cInfo->Entry, cInfo->Modelid3); + } + + if (cInfo->Modelid4) + { + CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid4); + if (!displayEntry) + { + sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid4 id (%u), can crash client", cInfo->Entry, cInfo->Modelid4); + const_cast(cInfo)->Modelid4 = 0; + } + else if (!displayScaleEntry) + displayScaleEntry = displayEntry; + + CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry(cInfo->Modelid4); + if (!minfo) + sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid4 (%u)", cInfo->Entry, cInfo->Modelid4); + } + + if (!displayScaleEntry) + sLog.outErrorDb("Creature (Entry: %u) not has any existed display id in Modelid1/Modelid2/Modelid3/Modelid4", cInfo->Entry); + + for (int k = 0; k < MAX_KILL_CREDIT; ++k) + { + if (cInfo->KillCredit[k]) + { + if (!GetCreatureTemplate(cInfo->KillCredit[k])) + { + sLog.outErrorDb("Creature (Entry: %u) has not existed creature entry in `KillCredit%d` (%u)",cInfo->Entry,k+1,cInfo->KillCredit[k]); + const_cast(cInfo)->KillCredit[k] = 0; + } + } + } + + if (!cInfo->unit_class || ((1 << (cInfo->unit_class-1)) & CLASSMASK_ALL_CREATURES) == 0) + { + sLog.outErrorDb("Creature (Entry: %u) has invalid unit_class(%u) for creature_template. Set to 1 (UNIT_CLASS_WARRIOR).", cInfo->Entry, cInfo->unit_class); + const_cast(cInfo)->unit_class = UNIT_CLASS_WARRIOR; + } + + if (cInfo->dmgschool >= MAX_SPELL_SCHOOL) + { + sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`",cInfo->Entry,cInfo->dmgschool); + const_cast(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL; + } + + if (cInfo->baseattacktime == 0) + const_cast(cInfo)->baseattacktime = BASE_ATTACK_TIME; + + if (cInfo->rangeattacktime == 0) + const_cast(cInfo)->rangeattacktime = BASE_ATTACK_TIME; + + if (cInfo->npcflag & UNIT_NPC_FLAG_SPELLCLICK) + { + sLog.outErrorDb("Creature (Entry: %u) has dynamic flag UNIT_NPC_FLAG_SPELLCLICK (%u) set, it expect to be set by code base at `npc_spellclick_spells` content.",cInfo->Entry,UNIT_NPC_FLAG_SPELLCLICK); + const_cast(cInfo)->npcflag &= ~UNIT_NPC_FLAG_SPELLCLICK; + } + + if ((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE) + sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u",cInfo->Entry,cInfo->trainer_type); + + if (cInfo->type && !sCreatureTypeStore.LookupEntry(cInfo->type)) + { + sLog.outErrorDb("Creature (Entry: %u) has invalid creature type (%u) in `type`",cInfo->Entry,cInfo->type); + const_cast(cInfo)->type = CREATURE_TYPE_HUMANOID; + } + + // must exist or used hidden but used in data horse case + if (cInfo->family && !sCreatureFamilyStore.LookupEntry(cInfo->family) && cInfo->family != CREATURE_FAMILY_HORSE_CUSTOM) + { + sLog.outErrorDb("Creature (Entry: %u) has invalid creature family (%u) in `family`",cInfo->Entry,cInfo->family); + const_cast(cInfo)->family = 0; + } + + if (cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE) + { + sLog.outErrorDb("Creature (Entry: %u) has wrong value (%u) in `InhabitType`, creature will not correctly walk/swim/fly",cInfo->Entry,cInfo->InhabitType); + const_cast(cInfo)->InhabitType = INHABIT_ANYWHERE; + } + + if (cInfo->VehicleId) + { + VehicleEntry const* vehId = sVehicleStore.LookupEntry(cInfo->VehicleId); + if (!vehId) + sLog.outErrorDb("Creature (Entry: %u) has a non-existing VehicleId (%u). This *WILL* cause the client to freeze!", cInfo->Entry, cInfo->VehicleId); + } + + if (cInfo->PetSpellDataId) + { + CreatureSpellDataEntry const* spellDataId = sCreatureSpellDataStore.LookupEntry(cInfo->PetSpellDataId); + if (!spellDataId) + sLog.outErrorDb("Creature (Entry: %u) has non-existing PetSpellDataId (%u)", cInfo->Entry, cInfo->PetSpellDataId); + } + + for (uint8 j = 0; j < CREATURE_MAX_SPELLS; ++j) + { + if (cInfo->spells[j] && !sSpellStore.LookupEntry(cInfo->spells[j])) + { + sLog.outErrorDb("Creature (Entry: %u) has non-existing Spell%d (%u), set to 0", cInfo->Entry, j+1,cInfo->spells[j]); + const_cast(cInfo)->spells[j] = 0; + } + } + + if (cInfo->MovementType >= MAX_DB_MOTION_TYPE) + { + sLog.outErrorDb("Creature (Entry: %u) has wrong movement generator type (%u), ignore and set to IDLE.",cInfo->Entry,cInfo->MovementType); + const_cast(cInfo)->MovementType = IDLE_MOTION_TYPE; + } + + if (cInfo->equipmentId > 0) // 0 no equipment + { + if (!GetEquipmentInfo(cInfo->equipmentId)) + { + sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", cInfo->Entry, cInfo->equipmentId); + const_cast(cInfo)->equipmentId = 0; + } + } + + /// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc + if (cInfo->scale <= 0.0f) + { + if (displayScaleEntry) + const_cast(cInfo)->scale = displayScaleEntry->scale; + else + const_cast(cInfo)->scale = 1.0f; + } + + if (cInfo->expansion > (MAX_CREATURE_BASE_HP - 1)) + { + sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with expansion %u ignore and set to NULL.", cInfo->expansion); + const_cast(cInfo)->expansion = 0; + } + + const_cast(cInfo)->dmg_multiplier *= Creature::_GetDamageMod(cInfo->rank); +} + +void ObjectMgr::ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr) +{ + // Now add the auras, format "spellid effectindex spellid effectindex..." + char *p,*s; + std::map val; + s=p=(char*)reinterpret_cast(addon->auras); + if (p) + { + uint32 currSpellId = 0; + bool spell = true; + while (p[0] != 0) + { + ++p; + if (p[0] == ' ' || p[0] == 0) + { + if (spell) + currSpellId = atoi(s); + else + { + uint8 eff = atoi(s); + if (eff >=3) + { + sLog.outErrorDb("Creature (%s: %u) has wrong `auras` data in `%s`(too high aura effect: %d for spell: %d)",guidEntryStr,addon->guidOrEntry,table,eff,currSpellId); + } + val[currSpellId] |= 1<(addon->auras); + + // wrong list + if (!spell) + { + addon->auras = NULL; + sLog.outErrorDb("Creature (%s: %u) has wrong `auras` data in `%s`.",guidEntryStr,addon->guidOrEntry,table); + return; + } + } + + // empty list + if (val.empty()) + { + addon->auras = NULL; + return; + } + + // replace by new structures array + const_cast(addon->auras) = new CreatureDataAddonAura[val.size()+1]; + + uint32 i=0; + for (std::map::iterator itr = val.begin(); itr != val.end();++itr) + { + CreatureDataAddonAura& cAura = const_cast(addon->auras[i]); + cAura.spell_id = itr->first; + cAura.effectMask = itr->second; + if (cAura.effectMask > 7 || !cAura.effectMask) + { + sLog.outErrorDb("Creature (%s: %u) has wrong effect for spell %u in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.spell_id,table); + continue; + } + SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(cAura.spell_id); + if (!AdditionalSpellInfo) + { + sLog.outErrorDb("Creature (%s: %u) has wrong spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.spell_id,table); + continue; + } + for (uint8 eff = 0; eff < MAX_SPELL_EFFECTS; ++eff) + { + if ((1<Effect[eff] || !AdditionalSpellInfo->EffectApplyAuraName[eff]) + { + sLog.outErrorDb("Creature (%s: %u) has not aura effect %u of spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,eff,cAura.spell_id,table); + continue; + } + else if (AdditionalSpellInfo->Effect[eff] == SPELL_EFFECT_PERSISTENT_AREA_AURA) + { + sLog.outErrorDb("Creature (%s: %u) has persistent area aura effect %u of spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,eff,cAura.spell_id,table); + continue; + } + } + } + + ++i; + } + + // fill terminator element (after last added) + CreatureDataAddonAura& endAura = const_cast(addon->auras[i]); + endAura.spell_id = 0; + endAura.effectMask = 0; +} + +void ObjectMgr::LoadCreatureAddons(SQLStorage& creatureaddons, char const* entryName, char const* comment) +{ + creatureaddons.Load(); + + sLog.outString(">> Loaded %u %s", creatureaddons.RecordCount, comment); + sLog.outString(); + + // check data correctness and convert 'auras' + for (uint32 i = 1; i < creatureaddons.MaxEntry; ++i) + { + CreatureDataAddon const* addon = creatureaddons.LookupEntry(i); + if (!addon) + continue; + + if (addon->mount) + { + if (!sCreatureDisplayInfoStore.LookupEntry(addon->mount)) + { + sLog.outErrorDb("Creature (%s %u) have invalid displayInfoId for mount (%u) defined in `%s`.", entryName, addon->guidOrEntry, addon->mount, creatureaddons.GetTableName()); + const_cast(addon)->mount = 0; + } + } + + if (!sEmotesStore.LookupEntry(addon->emote)) + sLog.outErrorDb("Creature (%s %u) have invalid emote (%u) defined in `%s`.", entryName, addon->guidOrEntry, addon->emote, creatureaddons.GetTableName()); + + /*if (addon->move_flags & (MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4)) + { + sLog.outErrorDb("Creature (%s %u) movement flags mask defined in `%s` include forbidden flags (" I32FMT ") that can crash client, cleanup at load.", entryName, addon->guidOrEntry, creatureaddons.GetTableName(), (MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4)); + const_cast(addon)->move_flags &= ~(MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4); + }*/ + + ConvertCreatureAddonAuras(const_cast(addon), creatureaddons.GetTableName(), entryName); + } +} + +void ObjectMgr::LoadCreatureAddons() +{ + LoadCreatureAddons(sCreatureInfoAddonStorage,"Entry","creature template addons"); + + // check entry ids + for (uint32 i = 1; i < sCreatureInfoAddonStorage.MaxEntry; ++i) + if (CreatureDataAddon const* addon = sCreatureInfoAddonStorage.LookupEntry(i)) + if (!sCreatureStorage.LookupEntry(addon->guidOrEntry)) + sLog.outErrorDb("Creature (Entry: %u) does not exist but has a record in `%s`",addon->guidOrEntry, sCreatureInfoAddonStorage.GetTableName()); + + sLog.outString("Loading Creature Addon Data..."); + LoadCreatureAddons(sCreatureDataAddonStorage,"GUID","creature addons"); + + // check entry ids + for (uint32 i = 1; i < sCreatureDataAddonStorage.MaxEntry; ++i) + if (CreatureDataAddon const* addon = sCreatureDataAddonStorage.LookupEntry(i)) + if (mCreatureDataMap.find(addon->guidOrEntry) == mCreatureDataMap.end()) + sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_addon`",addon->guidOrEntry); +} + +EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry) +{ + return sEquipmentStorage.LookupEntry(entry); +} + +void ObjectMgr::LoadEquipmentTemplates() +{ + sEquipmentStorage.Load(); + + for (uint32 i=0; i< sEquipmentStorage.MaxEntry; ++i) + { + EquipmentInfo const* eqInfo = sEquipmentStorage.LookupEntry(i); + + if (!eqInfo) + continue; + + for (uint8 j=0; j<3; j++) + { + if (!eqInfo->equipentry[j]) + continue; + + ItemEntry const *dbcitem = sItemStore.LookupEntry(eqInfo->equipentry[j]); + + if (!dbcitem) + { + sLog.outErrorDb("Unknown item (entry=%u) in creature_equip_template.equipentry%u for entry = %u, forced to 0.", eqInfo->equipentry[j], j+1, i); + const_cast(eqInfo)->equipentry[j] = 0; + continue; + } + + if (dbcitem->InventoryType != INVTYPE_WEAPON && + dbcitem->InventoryType != INVTYPE_SHIELD && + dbcitem->InventoryType != INVTYPE_RANGED && + dbcitem->InventoryType != INVTYPE_2HWEAPON && + dbcitem->InventoryType != INVTYPE_WEAPONMAINHAND && + dbcitem->InventoryType != INVTYPE_WEAPONOFFHAND && + dbcitem->InventoryType != INVTYPE_HOLDABLE && + dbcitem->InventoryType != INVTYPE_THROWN && + dbcitem->InventoryType != INVTYPE_RANGEDRIGHT) + { + sLog.outErrorDb("Item (entry=%u) in creature_equip_template.equipentry%u for entry = %u is not equipable in a hand, forced to 0.", eqInfo->equipentry[j], j+1, i); + const_cast(eqInfo)->equipentry[j] = 0; + } + } + } + sLog.outString(">> Loaded %u equipment template", sEquipmentStorage.RecordCount); + sLog.outString(); +} + +CreatureModelInfo const* ObjectMgr::GetCreatureModelInfo(uint32 modelid) +{ + return sCreatureModelStorage.LookupEntry(modelid); +} + +uint32 ObjectMgr::ChooseDisplayId(uint32 /*team*/, const CreatureInfo *cinfo, const CreatureData *data /*= NULL*/) +{ + // Load creature model (display id) + uint32 display_id = 0; + + if (!data || data->displayid == 0) + { + display_id = cinfo->GetRandomValidModelId(); + } + else + return data->displayid; + + /*if (!team) + { + switch(cinfo->Entry) + { + case 28511: // Eye of Acherus + case 33114: // Flame Leviathan Seat (model 24914 chair) + case 33167: // Salvaged Demolisher Mechanic Seat + case 33189: // Liquid Pryite + return cinfo->Modelid1; + case 33218: // Pyrite Safety Container + return cinfo->Modelid2; + case 33143: // Overload Control Device + return cinfo->Modelid3; + default: + return cinfo->GetRandomValidModelId(); + } + }*/ + + return display_id; +} + +CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(uint32 display_id) +{ + CreatureModelInfo const *minfo = GetCreatureModelInfo(display_id); + if (!minfo) + return NULL; + + // If a model for another gender exists, 50% chance to use it + if (minfo->modelid_other_gender != 0 && urand(0,1) == 0) + { + CreatureModelInfo const *minfo_tmp = GetCreatureModelInfo(minfo->modelid_other_gender); + if (!minfo_tmp) + { + sLog.outErrorDb("Model (Entry: %u) has modelid_other_gender %u not found in table `creature_model_info`. ", minfo->modelid, minfo->modelid_other_gender); + return minfo; // not fatal, just use the previous one + } + else + return minfo_tmp; + } + else + return minfo; +} + +void ObjectMgr::LoadCreatureModelInfo() +{ + sCreatureModelStorage.Load(); + + // post processing + for (uint32 i = 1; i < sCreatureModelStorage.MaxEntry; ++i) + { + CreatureModelInfo const *minfo = sCreatureModelStorage.LookupEntry(i); + if (!minfo) + continue; + + if (!sCreatureDisplayInfoStore.LookupEntry(minfo->modelid)) + sLog.outErrorDb("Table `creature_model_info` has model for not existed display id (%u).", minfo->modelid); + + if (minfo->gender > GENDER_NONE) + { + sLog.outErrorDb("Table `creature_model_info` has wrong gender (%u) for display id (%u).", uint32(minfo->gender), minfo->modelid); + const_cast(minfo)->gender = GENDER_MALE; + } + + if (minfo->modelid_other_gender && !sCreatureDisplayInfoStore.LookupEntry(minfo->modelid_other_gender)) + { + sLog.outErrorDb("Table `creature_model_info` has not existed alt.gender model (%u) for existed display id (%u).", minfo->modelid_other_gender, minfo->modelid); + const_cast(minfo)->modelid_other_gender = 0; + } + } + + sLog.outString(">> Loaded %u creature model based info", sCreatureModelStorage.RecordCount); + sLog.outString(); + + // check if combat_reach is valid + for (uint32 i = 1; i < sCreatureModelStorage.MaxEntry; ++i) + { + CreatureModelInfo const* mInfo = sCreatureModelStorage.LookupEntry(i); + if (!mInfo) + continue; + + if (mInfo->combat_reach < 0.1f) + { + //sLog.outErrorDb("Creature model (Entry: %u) has invalid combat reach (%f), setting it to 0.5", mInfo->modelid, mInfo->combat_reach); + const_cast(mInfo)->combat_reach = DEFAULT_COMBAT_REACH; + } + } +} + +bool ObjectMgr::CheckCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid) const +{ + const CreatureData* const slave = GetCreatureData(guid); + const CreatureData* const master = GetCreatureData(linkedGuid); + + if (!slave || !master) // they must have a corresponding entry in db + { + sLog.outError("LinkedRespawn: Creature '%u' linking to '%u' which doesn't exist",guid,linkedGuid); + return false; + } + + const MapEntry* const map = sMapStore.LookupEntry(master->mapid); + + if (master->mapid != slave->mapid // link only to same map + && (!map || map->Instanceable())) // or to unistanced world + { + sLog.outError("LinkedRespawn: Creature '%u' linking to '%u' on an unpermitted map",guid,linkedGuid); + return false; + } + + if (!(master->spawnMask & slave->spawnMask) // they must have a possibility to meet (normal/heroic difficulty) + && (!map || map->Instanceable())) + { + sLog.outError("LinkedRespawn: Creature '%u' linking to '%u' with not corresponding spawnMask",guid,linkedGuid); + return false; + } + + return true; +} + +void ObjectMgr::LoadCreatureLinkedRespawn() +{ + mCreatureLinkedRespawnMap.clear(); + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT guid, linkedGuid FROM creature_linked_respawn ORDER BY guid ASC"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(""); + sLog.outErrorDb(">> Loaded 0 linked respawns. DB table `creature_linked_respawn` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 guid = fields[0].GetUInt32(); + uint32 linkedGuid = fields[1].GetUInt32(); + + if (CheckCreatureLinkedRespawn(guid,linkedGuid)) + mCreatureLinkedRespawnMap[guid] = linkedGuid; + + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u linked respawns", mCreatureLinkedRespawnMap.size()); +} + +bool ObjectMgr::SetCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid) +{ + if (!guid) + return false; + + if (!linkedGuid) // we're removing the linking + { + mCreatureLinkedRespawnMap.erase(guid); + WorldDatabase.DirectPExecute("DELETE FROM creature_linked_respawn WHERE guid = '%u'",guid); + return true; + } + + if (CheckCreatureLinkedRespawn(guid,linkedGuid)) // we add/change linking + { + mCreatureLinkedRespawnMap[guid] = linkedGuid; + WorldDatabase.DirectPExecute("REPLACE INTO creature_linked_respawn (guid,linkedGuid) VALUES ('%u','%u')",guid,linkedGuid); + return true; + } + return false; +} + +void ObjectMgr::LoadCreatures() +{ + uint32 count = 0; + // 0 1 2 3 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid," + // 4 5 6 7 8 9 10 11 + "equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint," + // 12 13 14 15 16 17 18 19 + "curhealth, curmana, DeathState, MovementType, spawnMask, phaseMask, event, pool_entry " + "FROM creature LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid " + "LEFT OUTER JOIN pool_creature ON creature.guid = pool_creature.guid"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 creature. DB table `creature` is empty."); + return; + } + + // build single time for check creature data + std::set difficultyCreatures[MAX_DIFFICULTY - 1]; + for (uint32 i = 0; i < sCreatureStorage.MaxEntry; ++i) + if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i)) + for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1; ++diff) + if (cInfo->DifficultyEntry[diff]) + difficultyCreatures[diff].insert(cInfo->DifficultyEntry[diff]); + + // build single time for check spawnmask + std::map spawnMasks; + for (uint32 i = 0; i < sMapStore.GetNumRows(); ++i) + if (sMapStore.LookupEntry(i)) + for (int k = 0; k < MAX_DIFFICULTY; ++k) + if (GetMapDifficultyData(i,Difficulty(k))) + spawnMasks[i] |= (1 << k); + + //TODO: remove this + //gameeventmgr.mGameEventCreatureGuids.resize(52*2-1); + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 guid = fields[ 0].GetUInt32(); + uint32 entry = fields[ 1].GetUInt32(); + + CreatureInfo const* cInfo = GetCreatureTemplate(entry); + if (!cInfo) + { + sLog.outErrorDb("Table `creature` has creature (GUID: %u) with non existing creature entry %u, skipped.", guid, entry); + continue; + } + + CreatureData& data = mCreatureDataMap[guid]; + + data.id = entry; + data.mapid = fields[ 2].GetUInt32(); + data.displayid = fields[ 3].GetUInt32(); + data.equipmentId = fields[ 4].GetUInt32(); + data.posX = fields[ 5].GetFloat(); + data.posY = fields[ 6].GetFloat(); + data.posZ = fields[ 7].GetFloat(); + data.orientation = fields[ 8].GetFloat(); + data.spawntimesecs = fields[ 9].GetUInt32(); + data.spawndist = fields[10].GetFloat(); + data.currentwaypoint= fields[11].GetUInt32(); + data.curhealth = fields[12].GetUInt32(); + data.curmana = fields[13].GetUInt32(); + data.is_dead = fields[14].GetBool(); + data.movementType = fields[15].GetUInt8(); + data.spawnMask = fields[16].GetUInt8(); + data.phaseMask = fields[17].GetUInt16(); + int16 gameEvent = fields[18].GetInt16(); + int16 PoolId = fields[19].GetInt16(); + + MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid); + if (!mapEntry) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u) that spawned at not existed map (Id: %u), skipped.",guid, data.mapid); + continue; + } + + if (data.spawnMask & ~spawnMasks[data.mapid]) + sLog.outErrorDb("Table `creature` have creature (GUID: %u) that have wrong spawn mask %u including not supported difficulty modes for map (Id: %u).",guid, data.spawnMask, data.mapid); + + bool ok = true; + for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && ok; ++diff) + { + if (difficultyCreatures[diff].find(data.id) != difficultyCreatures[diff].end()) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u) that listed as difficulty %u template (entry: %u) in `creature_template`, skipped.", + guid, diff + 1, data.id); + ok = false; + } + } + if (!ok) + continue; + + // I do not know why but in db most display id are not zero + /*if (data.displayid == 11686 || data.displayid == 24719) + { + (const_cast(cInfo))->flags_extra |= CREATURE_FLAG_EXTRA_TRIGGER; + } + else if (data.displayid == cInfo->DisplayID_A || data.displayid == cInfo->DisplayID_A2 + || data.displayid == cInfo->DisplayID_H || data.displayid == cInfo->DisplayID_H2) + data.displayid = 0; + */ + + if (data.equipmentId > 0) // -1 no equipment, 0 use default + { + if (!GetEquipmentInfo(data.equipmentId)) + { + sLog.outErrorDb("Table `creature` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", data.id, data.equipmentId); + data.equipmentId = -1; + } + } + + if (cInfo->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND) + { + if (!mapEntry || !mapEntry->IsDungeon()) + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`flags_extra` including CREATURE_FLAG_EXTRA_INSTANCE_BIND but creature are not in instance.",guid,data.id); + } + + if (data.spawndist < 0.0f) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `spawndist`< 0, set to 0.",guid,data.id); + data.spawndist = 0.0f; + } + else if (data.movementType == RANDOM_MOTION_TYPE) + { + if (data.spawndist == 0.0f) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=1 (random movement) but with `spawndist`=0, replace by idle movement type (0).",guid,data.id); + data.movementType = IDLE_MOTION_TYPE; + } + else if (cInfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER) + data.movementType = IDLE_MOTION_TYPE; + } + else if (data.movementType == IDLE_MOTION_TYPE) + { + if (data.spawndist != 0.0f) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=0 (idle) have `spawndist`<>0, set to 0.",guid,data.id); + data.spawndist = 0.0f; + } + } + + if (data.phaseMask == 0) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `phaseMask`=0 (not visible for anyone), set to 1.",guid,data.id); + data.phaseMask = 1; + } + + //if (entry == 32307 || entry == 32308) + /*if (entry == 30739 || entry == 30740) + { + gameEvent = 51; + uint32 guid2 = objmgr.GenerateLowGuid(HIGHGUID_UNIT); + CreatureData& data2 = mCreatureDataMap[guid2]; + data2 = data; +// data2.id = (entry == 32307 ? 32308 : 32307); + data2.id = (entry == 30739 ? 30740 : 30739); + data2.displayid = 0; + gameeventmgr.mGameEventCreatureGuids[51+51].push_back(guid); + gameeventmgr.mGameEventCreatureGuids[51+50].push_back(guid2); + }*/ + + if (gameEvent == 0 && PoolId == 0) // if not this is to be managed by GameEvent System or Pool system + AddCreatureToGrid(guid, &data); + + ++count; + + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %lu creatures", (unsigned long)mCreatureDataMap.size()); +} + +void ObjectMgr::AddCreatureToGrid(uint32 guid, CreatureData const* data) +{ + uint8 mask = data->spawnMask; + for (uint8 i = 0; mask != 0; i++, mask >>= 1) + { + if (mask & 1) + { + CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY); + uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; + + CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; + cell_guids.creatures.insert(guid); + } + } +} + +void ObjectMgr::RemoveCreatureFromGrid(uint32 guid, CreatureData const* data) +{ + uint8 mask = data->spawnMask; + for (uint8 i = 0; mask != 0; i++, mask >>= 1) + { + if (mask & 1) + { + CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY); + uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; + + CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; + cell_guids.creatures.erase(guid); + } + } +} + +uint32 ObjectMgr::AddGOData(uint32 entry, uint32 mapId, float x, float y, float z, float o, uint32 spawntimedelay, float rotation0, float rotation1, float rotation2, float rotation3) +{ + GameObjectInfo const* goinfo = GetGameObjectInfo(entry); + if (!goinfo) + return 0; + + Map* map = const_cast(MapManager::Instance().CreateBaseMap(mapId)); + if (!map) + return 0; + + uint32 guid = GenerateLowGuid(HIGHGUID_GAMEOBJECT); + GameObjectData& data = NewGOData(guid); + data.id = entry; + data.mapid = mapId; + data.posX = x; + data.posY = y; + data.posZ = z; + data.orientation = o; + data.rotation0 = rotation0; + data.rotation1 = rotation1; + data.rotation2 = rotation2; + data.rotation3 = rotation3; + data.spawntimesecs = spawntimedelay; + data.animprogress = 100; + data.spawnMask = 1; + data.go_state = GO_STATE_READY; + data.phaseMask = PHASEMASK_NORMAL; + data.artKit = goinfo->type == GAMEOBJECT_TYPE_CAPTURE_POINT ? 21 : 0; + data.dbData = false; + + AddGameobjectToGrid(guid, &data); + + // Spawn if necessary (loaded grids only) + // We use spawn coords to spawn + if (!map->Instanceable() && map->IsLoaded(x, y)) + { + GameObject *go = new GameObject; + if (!go->LoadFromDB(guid, map)) + { + sLog.outError("AddGOData: cannot add gameobject entry %u to map", entry); + delete go; + return 0; + } + map->Add(go); + } + + sLog.outDebug("AddGOData: dbguid %u entry %u map %u x %f y %f z %f o %f", guid, entry, mapId, x, y, z, o); + + return guid; +} + +bool ObjectMgr::MoveCreData(uint32 guid, uint32 mapId, Position pos) +{ + CreatureData& data = NewOrExistCreatureData(guid); + if (!data.id) + return false; + + RemoveCreatureFromGrid(guid, &data); + if (data.posX == pos.GetPositionX() && data.posY == pos.GetPositionY() && data.posZ == pos.GetPositionZ()) + return true; + data.posX = pos.GetPositionX(); + data.posY = pos.GetPositionY(); + data.posZ = pos.GetPositionZ(); + data.orientation = pos.GetOrientation(); + AddCreatureToGrid(guid, &data); + + // Spawn if necessary (loaded grids only) + if (Map* map = const_cast(MapManager::Instance().CreateBaseMap(mapId))) + { + // We use spawn coords to spawn + if (!map->Instanceable() && map->IsLoaded(data.posX, data.posY)) + { + Creature *creature = new Creature; + if (!creature->LoadFromDB(guid, map)) + { + sLog.outError("AddCreature: cannot add creature entry %u to map", guid); + delete creature; + return false; + } + map->Add(creature); + } + } + return true; +} + +uint32 ObjectMgr::AddCreData(uint32 entry, uint32 /*team*/, uint32 mapId, float x, float y, float z, float o, uint32 spawntimedelay) +{ + CreatureInfo const *cInfo = GetCreatureTemplate(entry); + if (!cInfo) + return 0; + + uint32 level = cInfo->minlevel == cInfo->maxlevel ? cInfo->minlevel : urand(cInfo->minlevel, cInfo->maxlevel); // Only used for extracting creature base stats + CreatureBaseStats const* stats = objmgr.GetCreatureBaseStats(level, cInfo->unit_class); + + uint32 guid = GenerateLowGuid(HIGHGUID_UNIT); + CreatureData& data = NewOrExistCreatureData(guid); + data.id = entry; + data.mapid = mapId; + data.displayid = 0; + data.equipmentId = cInfo->equipmentId; + data.posX = x; + data.posY = y; + data.posZ = z; + data.orientation = o; + data.spawntimesecs = spawntimedelay; + data.spawndist = 0; + data.currentwaypoint = 0; + data.curhealth = stats->GenerateHealth(cInfo); + data.curmana = stats->GenerateMana(cInfo); + data.is_dead = false; + data.movementType = cInfo->MovementType; + data.spawnMask = 1; + data.phaseMask = PHASEMASK_NORMAL; + data.dbData = false; + + AddCreatureToGrid(guid, &data); + + // Spawn if necessary (loaded grids only) + if (Map* map = const_cast(MapManager::Instance().CreateBaseMap(mapId))) + { + // We use spawn coords to spawn + if (!map->Instanceable() && !map->IsRemovalGrid(x, y)) + { + Creature* creature = new Creature; + if (!creature->LoadFromDB(guid, map)) + { + sLog.outError("AddCreature: cannot add creature entry %u to map", entry); + delete creature; + return 0; + } + map->Add(creature); + } + } + + return guid; +} + +void ObjectMgr::LoadGameobjects() +{ + uint32 count = 0; + + // 0 1 2 3 4 5 6 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation," + // 7 8 9 10 11 12 13 14 15 16 17 + "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, phaseMask, event, pool_entry " + "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid " + "LEFT OUTER JOIN pool_gameobject ON gameobject.guid = pool_gameobject.guid"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 gameobjects. DB table `gameobject` is empty."); + return; + } + + // build single time for check spawnmask + std::map spawnMasks; + for (uint32 i = 0; i < sMapStore.GetNumRows(); ++i) + if (sMapStore.LookupEntry(i)) + for (int k = 0; k < MAX_DIFFICULTY; ++k) + if (GetMapDifficultyData(i,Difficulty(k))) + spawnMasks[i] |= (1 << k); + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 guid = fields[ 0].GetUInt32(); + uint32 entry = fields[ 1].GetUInt32(); + + GameObjectInfo const* gInfo = GetGameObjectInfo(entry); + if (!gInfo) + { + sLog.outErrorDb("Table `gameobject` has gameobject (GUID: %u) with non existing gameobject entry %u, skipped.", guid, entry); + continue; + } + + if (!gInfo->displayId) + { + switch (gInfo->type) + { + case GAMEOBJECT_TYPE_TRAP: + case GAMEOBJECT_TYPE_SPELL_FOCUS: + break; + default: + sLog.outErrorDb("Gameobject (GUID: %u Entry %u GoType: %u) doesn't have displayId (%u), not loaded.", guid, entry, gInfo->type, gInfo->displayId); + break; + } + } + + if (gInfo->displayId && !sGameObjectDisplayInfoStore.LookupEntry(gInfo->displayId)) + { + sLog.outErrorDb("Gameobject (GUID: %u Entry %u GoType: %u) have invalid displayId (%u), not loaded.",guid, entry, gInfo->type, gInfo->displayId); + continue; + } + + GameObjectData& data = mGameObjectDataMap[guid]; + + data.id = entry; + data.mapid = fields[ 2].GetUInt32(); + data.posX = fields[ 3].GetFloat(); + data.posY = fields[ 4].GetFloat(); + data.posZ = fields[ 5].GetFloat(); + data.orientation = fields[ 6].GetFloat(); + data.rotation0 = fields[ 7].GetFloat(); + data.rotation1 = fields[ 8].GetFloat(); + data.rotation2 = fields[ 9].GetFloat(); + data.rotation3 = fields[10].GetFloat(); + data.spawntimesecs = fields[11].GetInt32(); + + MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid); + if (!mapEntry) + { + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) that spawned at not existed map (Id: %u), skip", guid, data.id, data.mapid); + continue; + } + + if (data.spawntimesecs == 0 && gInfo->IsDespawnAtAction()) + { + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with `spawntimesecs` (0) value, but gameobejct marked as despawnable at action.",guid,data.id); + } + + data.animprogress = fields[12].GetUInt32(); + data.artKit = 0; + + uint32 go_state = fields[13].GetUInt32(); + if (go_state >= MAX_GO_STATE) + { + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid `state` (%u) value, skip",guid,data.id,go_state); + continue; + } + data.go_state = GOState(go_state); + + data.spawnMask = fields[14].GetUInt8(); + + if (data.spawnMask & ~spawnMasks[data.mapid]) + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) that have wrong spawn mask %u including not supported difficulty modes for map (Id: %u), skip", guid, data.id, data.spawnMask, data.mapid); + + data.phaseMask = fields[15].GetUInt16(); + int16 gameEvent = fields[16].GetInt16(); + int16 PoolId = fields[17].GetInt16(); + + if (data.rotation2 < -1.0f || data.rotation2 > 1.0f) + { + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid rotation2 (%f) value, skip",guid,data.id,data.rotation2); + continue; + } + + if (data.rotation3 < -1.0f || data.rotation3 > 1.0f) + { + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid rotation3 (%f) value, skip",guid,data.id,data.rotation3); + continue; + } + + if (!MapManager::IsValidMapCoord(data.mapid,data.posX,data.posY,data.posZ,data.orientation)) + { + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid coordinates, skip",guid,data.id); + continue; + } + + if (data.phaseMask == 0) + { + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with `phaseMask`=0 (not visible for anyone), set to 1.",guid,data.id); + data.phaseMask = 1; + } + + if (gameEvent == 0 && PoolId == 0) // if not this is to be managed by GameEvent System or Pool system + AddGameobjectToGrid(guid, &data); + ++count; + + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %lu gameobjects", (unsigned long)mGameObjectDataMap.size()); +} + +void ObjectMgr::AddGameobjectToGrid(uint32 guid, GameObjectData const* data) +{ + uint8 mask = data->spawnMask; + for (uint8 i = 0; mask != 0; i++, mask >>= 1) + { + if (mask & 1) + { + CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY); + uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; + + CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; + cell_guids.gameobjects.insert(guid); + } + } +} + +void ObjectMgr::RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data) +{ + uint8 mask = data->spawnMask; + for (uint8 i = 0; mask != 0; i++, mask >>= 1) + { + if (mask & 1) + { + CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY); + uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; + + CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id]; + cell_guids.gameobjects.erase(guid); + } + } +} + +void ObjectMgr::LoadCreatureRespawnTimes() +{ + uint32 count = 0; + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM creature_respawn"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded 0 creature respawn time."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 loguid = fields[0].GetUInt32(); + uint64 respawn_time = fields[1].GetUInt64(); + uint32 instance = fields[2].GetUInt32(); + + mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = time_t(respawn_time); + + ++count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %lu creature respawn times", (unsigned long)mCreatureRespawnTimes.size()); +} + +void ObjectMgr::LoadGameobjectRespawnTimes() +{ + // remove outdated data + WorldDatabase.DirectExecute("DELETE FROM gameobject_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())"); + + uint32 count = 0; + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM gameobject_respawn"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded 0 gameobject respawn time."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 loguid = fields[0].GetUInt32(); + uint64 respawn_time = fields[1].GetUInt64(); + uint32 instance = fields[2].GetUInt32(); + + mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = time_t(respawn_time); + + ++count; + } while (result->NextRow()); + + sLog.outString(">> Loaded %lu gameobject respawn times", (unsigned long)mGORespawnTimes.size()); + sLog.outString(); +} + +// name must be checked to correctness (if received) before call this function +uint64 ObjectMgr::GetPlayerGUIDByName(std::string name) const +{ + uint64 guid = 0; + + CharacterDatabase.escape_string(name); + + // Player name safe to sending to DB (checked at login) and this function using + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT guid FROM characters WHERE name = '%s'", name.c_str()); + if (result) + guid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); + + return guid; +} + +bool ObjectMgr::GetPlayerNameByGUID(const uint64 &guid, std::string &name) const +{ + // prevent DB access for online player + if (Player* player = GetPlayer(guid)) + { + name = player->GetName(); + return true; + } + + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT name FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); + + if (result) + { + name = (*result)[0].GetCppString(); + return true; + } + + return false; +} + +uint32 ObjectMgr::GetPlayerTeamByGUID(const uint64 &guid) const +{ + // prevent DB access for online player + if (Player* player = GetPlayer(guid)) + { + return Player::TeamForRace(player->getRace()); + } + + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT race FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); + + if (result) + { + uint8 race = (*result)[0].GetUInt8(); + return Player::TeamForRace(race); + } + + return 0; +} + +uint32 ObjectMgr::GetPlayerAccountIdByGUID(const uint64 &guid) const +{ + // prevent DB access for online player + if (Player* player = GetPlayer(guid)) + { + return player->GetSession()->GetAccountId(); + } + + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); + if (result) + { + uint32 acc = (*result)[0].GetUInt32(); + return acc; + } + + return 0; +} + +uint32 ObjectMgr::GetPlayerAccountIdByPlayerName(const std::string& name) const +{ + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'", name.c_str()); + if (result) + { + uint32 acc = (*result)[0].GetUInt32(); + return acc; + } + + return 0; +} + +void ObjectMgr::LoadItemLocales() +{ + mItemLocaleMap.clear(); // need for reload case + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry,name_loc1,description_loc1,name_loc2,description_loc2,name_loc3,description_loc3,name_loc4,description_loc4,name_loc5,description_loc5,name_loc6,description_loc6,name_loc7,description_loc7,name_loc8,description_loc8 FROM locales_item"); + + if (!result) + return; + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + + ItemLocale& data = mItemLocaleMap[entry]; + + for (uint8 i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[1+2*(i-1)].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.Name.size() <= idx) + data.Name.resize(idx+1); + + data.Name[idx] = str; + } + } + + str = fields[1+2*(i-1)+1].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.Description.size() <= idx) + data.Description.resize(idx+1); + + data.Description[idx] = str; + } + } + } + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %lu Item locale strings", (unsigned long)mItemLocaleMap.size()); +} + +struct SQLItemLoader : public SQLStorageLoaderBase +{ + template + void convert_from_str(uint32 /*field_pos*/, char *src, D &dst) + { + dst = D(objmgr.GetScriptId(src)); + } +}; + +void ObjectMgr::LoadItemPrototypes() +{ + SQLItemLoader loader; + loader.Load(sItemStorage); + sLog.outString(">> Loaded %u item prototypes", sItemStorage.RecordCount); + sLog.outString(); + + // check data correctness + for (uint32 i = 1; i < sItemStorage.MaxEntry; ++i) + { + ItemPrototype const* proto = sItemStorage.LookupEntry(i); + ItemEntry const *dbcitem = sItemStore.LookupEntry(i); + if (!proto) + { + /* to many errors, and possible not all items really used in game + if (dbcitem) + sLog.outErrorDb("Item (Entry: %u) doesn't exists in DB, but must exist.",i); + */ + continue; + } + + if (dbcitem) + { + if (proto->Class != dbcitem->Class) + { + sLog.outErrorDb("Item (Entry: %u) not correct class %u, must be %u (still using DB value).",i,proto->Class,dbcitem->Class); + // It safe let use Class from DB + } + /* disabled: have some strange wrong cases for Subclass values. + for enable also uncomment Subclass field in ItemEntry structure and in Itemfmt[] + if (proto->SubClass != dbcitem->SubClass) + { + sLog.outErrorDb("Item (Entry: %u) not correct (Class: %u, Sub: %u) pair, must be (Class: %u, Sub: %u) (still using DB value).",i,proto->Class,proto->SubClass,dbcitem->Class,dbcitem->SubClass); + // It safe let use Subclass from DB + } + */ + + if (proto->Unk0 != dbcitem->Unk0) + { + sLog.outErrorDb("Item (Entry: %u) not correct %i Unk0, must be %i (still using DB value).",i,proto->Unk0,dbcitem->Unk0); + // It safe let use Unk0 from DB + } + + if (proto->Material != dbcitem->Material) + { + sLog.outErrorDb("Item (Entry: %u) not correct %i material, must be %i (still using DB value).",i,proto->Material,dbcitem->Material); + // It safe let use Material from DB + } + + if (proto->InventoryType != dbcitem->InventoryType) + { + sLog.outErrorDb("Item (Entry: %u) not correct %u inventory type, must be %u (still using DB value).",i,proto->InventoryType,dbcitem->InventoryType); + // It safe let use InventoryType from DB + } + + if (proto->DisplayInfoID != dbcitem->DisplayId) + { + sLog.outErrorDb("Item (Entry: %u) not correct %u display id, must be %u (using it).",i,proto->DisplayInfoID,dbcitem->DisplayId); + const_cast(proto)->DisplayInfoID = dbcitem->DisplayId; + } + if (proto->Sheath != dbcitem->Sheath) + { + sLog.outErrorDb("Item (Entry: %u) not correct %u sheath, must be %u (using it).",i,proto->Sheath,dbcitem->Sheath); + const_cast(proto)->Sheath = dbcitem->Sheath; + } + } + else + sLog.outErrorDb("Item (Entry: %u) not correct (not listed in list of existed items).",i); + + if (proto->Class >= MAX_ITEM_CLASS) + { + sLog.outErrorDb("Item (Entry: %u) has wrong Class value (%u)",i,proto->Class); + const_cast(proto)->Class = ITEM_CLASS_MISC; + } + + if (proto->SubClass >= MaxItemSubclassValues[proto->Class]) + { + sLog.outErrorDb("Item (Entry: %u) has wrong Subclass value (%u) for class %u",i,proto->SubClass,proto->Class); + const_cast(proto)->SubClass = 0;// exist for all item classes + } + + if (proto->Quality >= MAX_ITEM_QUALITY) + { + sLog.outErrorDb("Item (Entry: %u) has wrong Quality value (%u)",i,proto->Quality); + const_cast(proto)->Quality = ITEM_QUALITY_NORMAL; + } + + if (proto->BuyCount <= 0) + { + sLog.outErrorDb("Item (Entry: %u) has wrong BuyCount value (%u), set to default(1).",i,proto->BuyCount); + const_cast(proto)->BuyCount = 1; + } + + if (proto->InventoryType >= MAX_INVTYPE) + { + sLog.outErrorDb("Item (Entry: %u) has wrong InventoryType value (%u)",i,proto->InventoryType); + const_cast(proto)->InventoryType = INVTYPE_NON_EQUIP; + } + + if (proto->RequiredSkill >= MAX_SKILL_TYPE) + { + sLog.outErrorDb("Item (Entry: %u) has wrong RequiredSkill value (%u)",i,proto->RequiredSkill); + const_cast(proto)->RequiredSkill = 0; + } + + { + // can be used in equip slot, as page read use in inventory, or spell casting at use + bool req = proto->InventoryType != INVTYPE_NON_EQUIP || proto->PageText; + if (!req) + for (uint8 j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j) + { + if (proto->Spells[j].SpellId) + { + req = true; + break; + } + } + + if (req) + { + if (!(proto->AllowableClass & CLASSMASK_ALL_PLAYABLE)) + sLog.outErrorDb("Item (Entry: %u) not have in `AllowableClass` any playable classes (%u) and can't be equipped or use.",i,proto->AllowableClass); + + if (!(proto->AllowableRace & RACEMASK_ALL_PLAYABLE)) + sLog.outErrorDb("Item (Entry: %u) not have in `AllowableRace` any playable races (%u) and can't be equipped or use.",i,proto->AllowableRace); + } + } + + if (proto->RequiredSpell && !sSpellStore.LookupEntry(proto->RequiredSpell)) + { + sLog.outErrorDb("Item (Entry: %u) have wrong (non-existed) spell in RequiredSpell (%u)",i,proto->RequiredSpell); + const_cast(proto)->RequiredSpell = 0; + } + + if (proto->RequiredReputationRank >= MAX_REPUTATION_RANK) + sLog.outErrorDb("Item (Entry: %u) has wrong reputation rank in RequiredReputationRank (%u), item can't be used.",i,proto->RequiredReputationRank); + + if (proto->RequiredReputationFaction) + { + if (!sFactionStore.LookupEntry(proto->RequiredReputationFaction)) + { + sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) faction in RequiredReputationFaction (%u)",i,proto->RequiredReputationFaction); + const_cast(proto)->RequiredReputationFaction = 0; + } + + if (proto->RequiredReputationRank == MIN_REPUTATION_RANK) + sLog.outErrorDb("Item (Entry: %u) has min. reputation rank in RequiredReputationRank (0) but RequiredReputationFaction > 0, faction setting is useless.",i); + } + + if (proto->MaxCount < -1) + { + sLog.outErrorDb("Item (Entry: %u) has too large negative in maxcount (%i), replace by value (-1) no storing limits.",i,proto->MaxCount); + const_cast(proto)->MaxCount = -1; + } + + if (proto->Stackable == 0) + { + sLog.outErrorDb("Item (Entry: %u) has wrong value in stackable (%i), replace by default 1.",i,proto->Stackable); + const_cast(proto)->Stackable = 1; + } + else if (proto->Stackable < -1) + { + sLog.outErrorDb("Item (Entry: %u) has too large negative in stackable (%i), replace by value (-1) no stacking limits.",i,proto->Stackable); + const_cast(proto)->Stackable = -1; + } + + if (proto->ContainerSlots > MAX_BAG_SIZE) + { + sLog.outErrorDb("Item (Entry: %u) has too large value in ContainerSlots (%u), replace by hardcoded limit (%u).",i,proto->ContainerSlots,MAX_BAG_SIZE); + const_cast(proto)->ContainerSlots = MAX_BAG_SIZE; + } + + if (proto->StatsCount > MAX_ITEM_PROTO_STATS) + { + sLog.outErrorDb("Item (Entry: %u) has too large value in statscount (%u), replace by hardcoded limit (%u).",i,proto->StatsCount,MAX_ITEM_PROTO_STATS); + const_cast(proto)->StatsCount = MAX_ITEM_PROTO_STATS; + } + + for (uint8 j = 0; j < MAX_ITEM_PROTO_STATS; ++j) + { + // for ItemStatValue != 0 + if (proto->ItemStat[j].ItemStatValue && proto->ItemStat[j].ItemStatType >= MAX_ITEM_MOD) + { + sLog.outErrorDb("Item (Entry: %u) has wrong stat_type%d (%u)",i,j+1,proto->ItemStat[j].ItemStatType); + const_cast(proto)->ItemStat[j].ItemStatType = 0; + } + + switch (proto->ItemStat[j].ItemStatType) + { + case ITEM_MOD_SPELL_HEALING_DONE: + case ITEM_MOD_SPELL_DAMAGE_DONE: + sLog.outErrorDb("Item (Entry: %u) has deprecated stat_type%d (%u)",i,j+1,proto->ItemStat[j].ItemStatType); + break; + default: + break; + } + } + + for (uint8 j = 0; j < MAX_ITEM_PROTO_DAMAGES; ++j) + { + if (proto->Damage[j].DamageType >= MAX_SPELL_SCHOOL) + { + sLog.outErrorDb("Item (Entry: %u) has wrong dmg_type%d (%u)",i,j+1,proto->Damage[j].DamageType); + const_cast(proto)->Damage[j].DamageType = 0; + } + } + + // special format + if ((proto->Spells[0].SpellId == 483) || (proto->Spells[0].SpellId == 55884)) + { + // spell_1 + if (proto->Spells[0].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE) + { + sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format",i,0+1,proto->Spells[0].SpellTrigger); + const_cast(proto)->Spells[0].SpellId = 0; + const_cast(proto)->Spells[0].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + const_cast(proto)->Spells[1].SpellId = 0; + const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + } + + // spell_2 have learning spell + if (proto->Spells[1].SpellTrigger != ITEM_SPELLTRIGGER_LEARN_SPELL_ID) + { + sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format.",i,1+1,proto->Spells[1].SpellTrigger); + const_cast(proto)->Spells[0].SpellId = 0; + const_cast(proto)->Spells[1].SpellId = 0; + const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + } + else if (!proto->Spells[1].SpellId) + { + sLog.outErrorDb("Item (Entry: %u) not has expected spell in spellid_%d in special learning format.",i,1+1); + const_cast(proto)->Spells[0].SpellId = 0; + const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + } + else if (proto->Spells[1].SpellId != -1) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[1].SpellId); + if (!spellInfo) + { + sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%d)",i,1+1,proto->Spells[1].SpellId); + const_cast(proto)->Spells[0].SpellId = 0; + const_cast(proto)->Spells[1].SpellId = 0; + const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + } + // allowed only in special format + else if ((proto->Spells[1].SpellId == 483) || (proto->Spells[1].SpellId == 55884)) + { + sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%d)",i,1+1,proto->Spells[1].SpellId); + const_cast(proto)->Spells[0].SpellId = 0; + const_cast(proto)->Spells[1].SpellId = 0; + const_cast(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + } + } + + // spell_3*,spell_4*,spell_5* is empty + for (uint8 j = 2; j < MAX_ITEM_PROTO_SPELLS; ++j) + { + if (proto->Spells[j].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE) + { + sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)",i,j+1,proto->Spells[j].SpellTrigger); + const_cast(proto)->Spells[j].SpellId = 0; + const_cast(proto)->Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + } + else if (proto->Spells[j].SpellId != 0) + { + sLog.outErrorDb("Item (Entry: %u) has wrong spell in spellid_%d (%d) for learning special format",i,j+1,proto->Spells[j].SpellId); + const_cast(proto)->Spells[j].SpellId = 0; + } + } + } + // normal spell list + else + { + for (uint8 j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j) + { + if (proto->Spells[j].SpellTrigger >= MAX_ITEM_SPELLTRIGGER || proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID) + { + sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)",i,j+1,proto->Spells[j].SpellTrigger); + const_cast(proto)->Spells[j].SpellId = 0; + const_cast(proto)->Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE; + } + + if (proto->Spells[j].SpellId && proto->Spells[j].SpellId != -1) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[j].SpellId); + if (!spellInfo) + { + sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%d)",i,j+1,proto->Spells[j].SpellId); + const_cast(proto)->Spells[j].SpellId = 0; + } + // allowed only in special format + else if ((proto->Spells[j].SpellId == 483) || (proto->Spells[j].SpellId == 55884)) + { + sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%d)",i,j+1,proto->Spells[j].SpellId); + const_cast(proto)->Spells[j].SpellId = 0; + } + } + } + } + + if (proto->Bonding >= MAX_BIND_TYPE) + sLog.outErrorDb("Item (Entry: %u) has wrong Bonding value (%u)",i,proto->Bonding); + + if (proto->PageText && !sPageTextStore.LookupEntry(proto->PageText)) + sLog.outErrorDb("Item (Entry: %u) has non existing first page (Id:%u)", i,proto->PageText); + + if (proto->LockID && !sLockStore.LookupEntry(proto->LockID)) + sLog.outErrorDb("Item (Entry: %u) has wrong LockID (%u)",i,proto->LockID); + + if (proto->Sheath >= MAX_SHEATHETYPE) + { + sLog.outErrorDb("Item (Entry: %u) has wrong Sheath (%u)",i,proto->Sheath); + const_cast(proto)->Sheath = SHEATHETYPE_NONE; + } + + if (proto->RandomProperty && !sItemRandomPropertiesStore.LookupEntry(GetItemEnchantMod(proto->RandomProperty))) + { + sLog.outErrorDb("Item (Entry: %u) has unknown (wrong or not listed in `item_enchantment_template`) RandomProperty (%u)",i,proto->RandomProperty); + const_cast(proto)->RandomProperty = 0; + } + + if (proto->RandomSuffix && !sItemRandomSuffixStore.LookupEntry(GetItemEnchantMod(proto->RandomSuffix))) + { + sLog.outErrorDb("Item (Entry: %u) has wrong RandomSuffix (%u)",i,proto->RandomSuffix); + const_cast(proto)->RandomSuffix = 0; + } + + if (proto->ItemSet && !sItemSetStore.LookupEntry(proto->ItemSet)) + { + sLog.outErrorDb("Item (Entry: %u) have wrong ItemSet (%u)",i,proto->ItemSet); + const_cast(proto)->ItemSet = 0; + } + + if (proto->Area && !GetAreaEntryByAreaID(proto->Area)) + sLog.outErrorDb("Item (Entry: %u) has wrong Area (%u)",i,proto->Area); + + if (proto->Map && !sMapStore.LookupEntry(proto->Map)) + sLog.outErrorDb("Item (Entry: %u) has wrong Map (%u)",i,proto->Map); + + if (proto->BagFamily) + { + // check bits + for (uint32 j = 0; j < sizeof(proto->BagFamily)*8; ++j) + { + uint32 mask = 1 << j; + if ((proto->BagFamily & mask) == 0) + continue; + + ItemBagFamilyEntry const* bf = sItemBagFamilyStore.LookupEntry(j+1); + if (!bf) + { + sLog.outErrorDb("Item (Entry: %u) has bag family bit set not listed in ItemBagFamily.dbc, remove bit",i); + const_cast(proto)->BagFamily &= ~mask; + continue; + } + + if (BAG_FAMILY_MASK_CURRENCY_TOKENS & mask) + { + CurrencyTypesEntry const* ctEntry = sCurrencyTypesStore.LookupEntry(proto->ItemId); + if (!ctEntry) + { + sLog.outErrorDb("Item (Entry: %u) has currency bag family bit set in BagFamily but not listed in CurrencyTypes.dbc, remove bit",i); + const_cast(proto)->BagFamily &= ~mask; + } + } + } + } + + if (proto->TotemCategory && !sTotemCategoryStore.LookupEntry(proto->TotemCategory)) + sLog.outErrorDb("Item (Entry: %u) has wrong TotemCategory (%u)",i,proto->TotemCategory); + + for (uint8 j = 0; j < MAX_ITEM_PROTO_SOCKETS; ++j) + { + if (proto->Socket[j].Color && (proto->Socket[j].Color & SOCKET_COLOR_ALL) != proto->Socket[j].Color) + { + sLog.outErrorDb("Item (Entry: %u) has wrong socketColor_%d (%u)",i,j+1,proto->Socket[j].Color); + const_cast(proto)->Socket[j].Color = 0; + } + } + + if (proto->GemProperties && !sGemPropertiesStore.LookupEntry(proto->GemProperties)) + sLog.outErrorDb("Item (Entry: %u) has wrong GemProperties (%u)",i,proto->GemProperties); + + if (proto->FoodType >= MAX_PET_DIET) + { + sLog.outErrorDb("Item (Entry: %u) has wrong FoodType value (%u)",i,proto->FoodType); + const_cast(proto)->FoodType = 0; + } + + if (proto->ItemLimitCategory && !sItemLimitCategoryStore.LookupEntry(proto->ItemLimitCategory)) + { + sLog.outErrorDb("Item (Entry: %u) has wrong LimitCategory value (%u)",i,proto->ItemLimitCategory); + const_cast(proto)->ItemLimitCategory = 0; + } + + if (proto->HolidayId && !sHolidaysStore.LookupEntry(proto->HolidayId)) + { + sLog.outErrorDb("Item (Entry: %u) has wrong HolidayId value (%u)", i, proto->HolidayId); + const_cast(proto)->HolidayId = 0; + } + } + + // check some dbc referecned items (avoid duplicate reports) + std::set notFoundOutfit; + for (uint32 i = 1; i < sCharStartOutfitStore.GetNumRows(); ++i) + { + CharStartOutfitEntry const* entry = sCharStartOutfitStore.LookupEntry(i); + if (!entry) + continue; + + for (int j = 0; j < MAX_OUTFIT_ITEMS; ++j) + { + if (entry->ItemId[j] <= 0) + continue; + + uint32 item_id = entry->ItemId[j]; + + if (!GetItemPrototype(item_id)) + notFoundOutfit.insert(item_id); + } + } + + for (std::set::const_iterator itr = notFoundOutfit.begin(); itr != notFoundOutfit.end(); ++itr) + sLog.outErrorDb("Item (Entry: %u) not exist in `item_template` but referenced in `CharStartOutfit.dnc`", *itr); +} + +void ObjectMgr::LoadVehicleAccessories() +{ + m_VehicleAccessoryMap.clear(); // needed for reload case + + uint32 count = 0; + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT `entry`,`accessory_entry`,`seat_id`,`minion` FROM `vehicle_accessory`"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 LoadVehicleAccessor. DB table `vehicle_accessory` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 uiEntry = fields[0].GetUInt32(); + uint32 uiAccessory = fields[1].GetUInt32(); + int8 uiSeat = int8(fields[2].GetInt16()); + bool bMinion = fields[3].GetBool(); + + if (!sCreatureStorage.LookupEntry(uiEntry)) + { + sLog.outErrorDb("Table `vehicle_accessory`: creature template entry %u does not exist.", uiEntry); + continue; + } + + if (!sCreatureStorage.LookupEntry(uiAccessory)) + { + sLog.outErrorDb("Table `vehicle_accessory`: Accessory %u does not exist.", uiAccessory); + continue; + } + + m_VehicleAccessoryMap[uiEntry].push_back(VehicleAccessory(uiAccessory, uiSeat, bMinion)); + + ++count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u Vehicle Accessories", count); +} + +void ObjectMgr::LoadPetLevelInfo() +{ + // Loading levels data + { + // 0 1 2 3 4 5 6 7 8 9 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT creature_entry, level, hp, mana, str, agi, sta, inte, spi, armor FROM pet_levelstats"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + + sLog.outString(); + sLog.outString(">> Loaded %u level pet stats definitions", count); + sLog.outErrorDb("Error loading `pet_levelstats` table or empty table."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field* fields = result->Fetch(); + + uint32 creature_id = fields[0].GetUInt32(); + if (!sCreatureStorage.LookupEntry(creature_id)) + { + sLog.outErrorDb("Wrong creature id %u in `pet_levelstats` table, ignoring.",creature_id); + continue; + } + + uint32 current_level = fields[1].GetUInt32(); + if (current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum + sLog.outErrorDb("Wrong (> %u) level %u in `pet_levelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level); + else + { + sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `pet_levelstats` table, ignoring.",current_level); + ++count; // make result loading percent "expected" correct in case disabled detail mode for example. + } + continue; + } + else if (current_level < 1) + { + sLog.outErrorDb("Wrong (<1) level %u in `pet_levelstats` table, ignoring.",current_level); + continue; + } + + PetLevelInfo*& pInfoMapEntry = petInfo[creature_id]; + + if (pInfoMapEntry == NULL) + pInfoMapEntry = new PetLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)]; + + // data for level 1 stored in [0] array element, ... + PetLevelInfo* pLevelInfo = &pInfoMapEntry[current_level-1]; + + pLevelInfo->health = fields[2].GetUInt16(); + pLevelInfo->mana = fields[3].GetUInt16(); + pLevelInfo->armor = fields[9].GetUInt16(); + + for (int i = 0; i < MAX_STATS; i++) + { + pLevelInfo->stats[i] = fields[i+4].GetUInt16(); + } + + bar.step(); + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u level pet stats definitions", count); + } + + // Fill gaps and check integrity + for (PetLevelInfoMap::iterator itr = petInfo.begin(); itr != petInfo.end(); ++itr) + { + PetLevelInfo* pInfo = itr->second; + + // fatal error if no level 1 data + if (!pInfo || pInfo[0].health == 0) + { + sLog.outErrorDb("Creature %u does not have pet stats data for Level 1!",itr->first); + exit(1); + } + + // fill level gaps + for (uint8 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) + { + if (pInfo[level].health == 0) + { + sLog.outErrorDb("Creature %u has no data for Level %i pet stats data, using data of Level %i.",itr->first,level+1, level); + pInfo[level] = pInfo[level-1]; + } + } + } +} + +PetLevelInfo const* ObjectMgr::GetPetLevelInfo(uint32 creature_id, uint8 level) const +{ + if (level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); + + PetLevelInfoMap::const_iterator itr = petInfo.find(creature_id); + if (itr == petInfo.end()) + return NULL; + + return &itr->second[level-1]; // data for level 1 stored in [0] array element, ... +} + +void ObjectMgr::LoadPlayerInfo() +{ + // Load playercreate + { + // 0 1 2 3 4 5 6 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT race, class, map, zone, position_x, position_y, position_z FROM playercreateinfo"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + + sLog.outString(); + sLog.outString(">> Loaded %u player create definitions", count); + sLog.outErrorDb("Error loading `playercreateinfo` table or empty table."); + exit(1); + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field* fields = result->Fetch(); + + uint32 current_race = fields[0].GetUInt32(); + uint32 current_class = fields[1].GetUInt32(); + uint32 mapId = fields[2].GetUInt32(); + uint32 areaId = fields[3].GetUInt32(); + float positionX = fields[4].GetFloat(); + float positionY = fields[5].GetFloat(); + float positionZ = fields[6].GetFloat(); + + if (current_race >= MAX_RACES) + { + sLog.outErrorDb("Wrong race %u in `playercreateinfo` table, ignoring.",current_race); + continue; + } + + ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(current_race); + if (!rEntry) + { + sLog.outErrorDb("Wrong race %u in `playercreateinfo` table, ignoring.",current_race); + continue; + } + + if (current_class >= MAX_CLASSES) + { + sLog.outErrorDb("Wrong class %u in `playercreateinfo` table, ignoring.",current_class); + continue; + } + + if (!sChrClassesStore.LookupEntry(current_class)) + { + sLog.outErrorDb("Wrong class %u in `playercreateinfo` table, ignoring.",current_class); + continue; + } + + // accept DB data only for valid position (and non instanceable) + if (!MapManager::IsValidMapCoord(mapId,positionX,positionY,positionZ)) + { + sLog.outErrorDb("Wrong home position for class %u race %u pair in `playercreateinfo` table, ignoring.",current_class,current_race); + continue; + } + + if (sMapStore.LookupEntry(mapId)->Instanceable()) + { + sLog.outErrorDb("Home position in instanceable map for class %u race %u pair in `playercreateinfo` table, ignoring.",current_class,current_race); + continue; + } + + PlayerInfo* pInfo = &playerInfo[current_race][current_class]; + + pInfo->mapId = mapId; + pInfo->areaId = areaId; + pInfo->positionX = positionX; + pInfo->positionY = positionY; + pInfo->positionZ = positionZ; + + pInfo->displayId_m = rEntry->model_m; + pInfo->displayId_f = rEntry->model_f; + + bar.step(); + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u player create definitions", count); + } + + // Load playercreate items + sLog.outString("Loading Player Create Items Data..."); + { + // 0 1 2 3 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT race, class, itemid, amount FROM playercreateinfo_item"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u custom player create items", count); + } + else + { + barGoLink bar(result->GetRowCount()); + + do + { + Field* fields = result->Fetch(); + + uint32 current_race = fields[0].GetUInt32(); + if (current_race >= MAX_RACES) + { + sLog.outErrorDb("Wrong race %u in `playercreateinfo_item` table, ignoring.",current_race); + continue; + } + + uint32 current_class = fields[1].GetUInt32(); + if (current_class >= MAX_CLASSES) + { + sLog.outErrorDb("Wrong class %u in `playercreateinfo_item` table, ignoring.",current_class); + continue; + } + + PlayerInfo* pInfo = &playerInfo[current_race][current_class]; + + uint32 item_id = fields[2].GetUInt32(); + + if (!GetItemPrototype(item_id)) + { + sLog.outErrorDb("Item id %u (race %u class %u) in `playercreateinfo_item` table but not listed in `item_template`, ignoring.",item_id,current_race,current_class); + continue; + } + + uint32 amount = fields[3].GetUInt32(); + + if (!amount) + { + sLog.outErrorDb("Item id %u (class %u race %u) have amount == 0 in `playercreateinfo_item` table, ignoring.",item_id,current_race,current_class); + continue; + } + + pInfo->item.push_back(PlayerCreateInfoItem(item_id, amount)); + + bar.step(); + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u custom player create items", count); + } + } + + // Load playercreate spells + sLog.outString("Loading Player Create Spell Data..."); + { + + QueryResult_AutoPtr result = QueryResult_AutoPtr(NULL); + if (sWorld.getConfig(CONFIG_START_ALL_SPELLS)) + result = WorldDatabase.Query("SELECT race, class, Spell, Active FROM playercreateinfo_spell_custom"); + else + result = WorldDatabase.Query("SELECT race, class, Spell FROM playercreateinfo_spell"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + + sLog.outString(); + sLog.outString(">> Loaded %u player create spells", count); + sLog.outErrorDb("Error loading player starting spells or empty table."); + } + else + { + barGoLink bar(result->GetRowCount()); + + do + { + Field* fields = result->Fetch(); + + uint32 current_race = fields[0].GetUInt32(); + if (current_race >= MAX_RACES) + { + sLog.outErrorDb("Wrong race %u in `playercreateinfo_spell` table, ignoring.",current_race); + continue; + } + + uint32 current_class = fields[1].GetUInt32(); + if (current_class >= MAX_CLASSES) + { + sLog.outErrorDb("Wrong class %u in `playercreateinfo_spell` table, ignoring.",current_class); + continue; + } + + if (!current_race || !current_class) + { + uint32 min_race = current_race ? current_race : 1; + uint32 max_race = current_race ? current_race + 1 : MAX_RACES; + uint32 min_class = current_class ? current_class : 1; + uint32 max_class = current_class ? current_class + 1 : MAX_CLASSES; + for (uint32 r = min_race; r < max_race; ++r) + for (uint32 c = min_class; c < max_class; ++c) + playerInfo[r][c].spell.push_back(fields[2].GetUInt32()); + } + else + playerInfo[current_race][current_class].spell.push_back(fields[2].GetUInt32()); + + bar.step(); + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u player create spells", count); + } + } + + // Load playercreate actions + sLog.outString("Loading Player Create Action Data..."); + { + // 0 1 2 3 4 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT race, class, button, action, type FROM playercreateinfo_action"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + + sLog.outString(); + sLog.outString(">> Loaded %u player create actions", count); + sLog.outErrorDb("Error loading `playercreateinfo_action` table or empty table."); + } + else + { + barGoLink bar(result->GetRowCount()); + + do + { + Field* fields = result->Fetch(); + + uint32 current_race = fields[0].GetUInt32(); + if (current_race >= MAX_RACES) + { + sLog.outErrorDb("Wrong race %u in `playercreateinfo_action` table, ignoring.",current_race); + continue; + } + + uint32 current_class = fields[1].GetUInt32(); + if (current_class >= MAX_CLASSES) + { + sLog.outErrorDb("Wrong class %u in `playercreateinfo_action` table, ignoring.",current_class); + continue; + } + + PlayerInfo* pInfo = &playerInfo[current_race][current_class]; + pInfo->action.push_back(PlayerCreateInfoAction(fields[2].GetUInt8(),fields[3].GetUInt32(),fields[4].GetUInt8())); + + bar.step(); + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u player create actions", count); + } + } + + // Loading levels data (class only dependent) + sLog.outString("Loading Player Create Level HP/Mana Data..."); + { + // 0 1 2 3 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT class, level, basehp, basemana FROM player_classlevelstats"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + + sLog.outString(); + sLog.outString(">> Loaded %u level health/mana definitions", count); + sLog.outErrorDb("Error loading `player_classlevelstats` table or empty table."); + exit(1); + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field* fields = result->Fetch(); + + uint32 current_class = fields[0].GetUInt32(); + if (current_class >= MAX_CLASSES) + { + sLog.outErrorDb("Wrong class %u in `player_classlevelstats` table, ignoring.",current_class); + continue; + } + + uint8 current_level = fields[1].GetUInt8(); + if (current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum + sLog.outErrorDb("Wrong (> %u) level %u in `player_classlevelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level); + else + { + sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `player_classlevelstats` table, ignoring.",current_level); + ++count; // make result loading percent "expected" correct in case disabled detail mode for example. + } + continue; + } + + PlayerClassInfo* pClassInfo = &playerClassInfo[current_class]; + + if (!pClassInfo->levelInfo) + pClassInfo->levelInfo = new PlayerClassLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)]; + + PlayerClassLevelInfo* pClassLevelInfo = &pClassInfo->levelInfo[current_level-1]; + + pClassLevelInfo->basehealth = fields[2].GetUInt16(); + pClassLevelInfo->basemana = fields[3].GetUInt16(); + + bar.step(); + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u level health/mana definitions", count); + } + + // Fill gaps and check integrity + for (int class_ = 0; class_ < MAX_CLASSES; ++class_) + { + // skip non existed classes + if (!sChrClassesStore.LookupEntry(class_)) + continue; + + PlayerClassInfo* pClassInfo = &playerClassInfo[class_]; + + // fatal error if no level 1 data + if (!pClassInfo->levelInfo || pClassInfo->levelInfo[0].basehealth == 0) + { + sLog.outErrorDb("Class %i Level 1 does not have health/mana data!",class_); + exit(1); + } + + // fill level gaps + for (uint8 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) + { + if (pClassInfo->levelInfo[level].basehealth == 0) + { + sLog.outErrorDb("Class %i Level %i does not have health/mana data. Using stats data of level %i.",class_,level+1, level); + pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level-1]; + } + } + } + + // Loading levels data (class/race dependent) + sLog.outString("Loading Player Create Level Stats Data..."); + { + // 0 1 2 3 4 5 6 7 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT race, class, level, str, agi, sta, inte, spi FROM player_levelstats"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + + sLog.outString(); + sLog.outString(">> Loaded %u level stats definitions", count); + sLog.outErrorDb("Error loading `player_levelstats` table or empty table."); + exit(1); + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field* fields = result->Fetch(); + + uint32 current_race = fields[0].GetUInt32(); + if (current_race >= MAX_RACES) + { + sLog.outErrorDb("Wrong race %u in `player_levelstats` table, ignoring.",current_race); + continue; + } + + uint32 current_class = fields[1].GetUInt32(); + if (current_class >= MAX_CLASSES) + { + sLog.outErrorDb("Wrong class %u in `player_levelstats` table, ignoring.",current_class); + continue; + } + + uint32 current_level = fields[2].GetUInt32(); + if (current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum + sLog.outErrorDb("Wrong (> %u) level %u in `player_levelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level); + else + { + sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `player_levelstats` table, ignoring.",current_level); + ++count; // make result loading percent "expected" correct in case disabled detail mode for example. + } + continue; + } + + PlayerInfo* pInfo = &playerInfo[current_race][current_class]; + + if (!pInfo->levelInfo) + pInfo->levelInfo = new PlayerLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)]; + + PlayerLevelInfo* pLevelInfo = &pInfo->levelInfo[current_level-1]; + + for (int i = 0; i < MAX_STATS; i++) + { + pLevelInfo->stats[i] = fields[i+3].GetUInt8(); + } + + bar.step(); + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u level stats definitions", count); + } + + // Fill gaps and check integrity + for (int race = 0; race < MAX_RACES; ++race) + { + // skip non existed races + if (!sChrRacesStore.LookupEntry(race)) + continue; + + for (int class_ = 0; class_ < MAX_CLASSES; ++class_) + { + // skip non existed classes + if (!sChrClassesStore.LookupEntry(class_)) + continue; + + PlayerInfo* pInfo = &playerInfo[race][class_]; + + // skip non loaded combinations + if (!pInfo->displayId_m || !pInfo->displayId_f) + continue; + + // skip expansion races if not playing with expansion + if (sWorld.getConfig(CONFIG_EXPANSION) < 1 && (race == RACE_BLOODELF || race == RACE_DRAENEI)) + continue; + + // skip expansion classes if not playing with expansion + if (sWorld.getConfig(CONFIG_EXPANSION) < 2 && class_ == CLASS_DEATH_KNIGHT) + continue; + + // fatal error if no level 1 data + if (!pInfo->levelInfo || pInfo->levelInfo[0].stats[0] == 0) + { + sLog.outErrorDb("Race %i Class %i Level 1 does not have stats data!",race,class_); + exit(1); + } + + // fill level gaps + for (uint8 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) + { + if (pInfo->levelInfo[level].stats[0] == 0) + { + sLog.outErrorDb("Race %i Class %i Level %i does not have stats data. Using stats data of level %i.",race,class_,level+1, level); + pInfo->levelInfo[level] = pInfo->levelInfo[level-1]; + } + } + } + } + + // Loading xp per level data + sLog.outString("Loading Player Create XP Data..."); + { + mPlayerXPperLevel.resize(sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)); + for (uint8 level = 0; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) + mPlayerXPperLevel[level] = 0; + + // 0 1 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT lvl, xp_for_next_level FROM player_xp_for_level"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + + sLog.outString(); + sLog.outString(">> Loaded %u xp for level definitions", count); + sLog.outErrorDb("Error loading `player_xp_for_level` table or empty table."); + exit(1); + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field* fields = result->Fetch(); + + uint32 current_level = fields[0].GetUInt32(); + uint32 current_xp = fields[1].GetUInt32(); + + if (current_level >= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum + sLog.outErrorDb("Wrong (> %u) level %u in `player_xp_for_level` table, ignoring.", STRONG_MAX_LEVEL,current_level); + else + { + sLog.outDetail("Unused (> MaxPlayerLevel in TrinityCore.conf) level %u in `player_xp_for_levels` table, ignoring.",current_level); + ++count; // make result loading percent "expected" correct in case disabled detail mode for example. + } + continue; + } + //PlayerXPperLevel + mPlayerXPperLevel[current_level] = current_xp; + bar.step(); + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u xp for level definitions", count); + } + + // fill level gaps + for (uint8 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level) + { + if (mPlayerXPperLevel[level] == 0) + { + sLog.outErrorDb("Level %i does not have XP for level data. Using data of level [%i] + 100.",level+1, level); + mPlayerXPperLevel[level] = mPlayerXPperLevel[level-1]+100; + } + } +} + +void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint8 level, PlayerClassLevelInfo* info) const +{ + if (level < 1 || class_ >= MAX_CLASSES) + return; + + PlayerClassInfo const* pInfo = &playerClassInfo[class_]; + + if (level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); + + *info = pInfo->levelInfo[level-1]; +} + +void ObjectMgr::GetPlayerLevelInfo(uint32 race, uint32 class_, uint8 level, PlayerLevelInfo* info) const +{ + if (level < 1 || race >= MAX_RACES || class_ >= MAX_CLASSES) + return; + + PlayerInfo const* pInfo = &playerInfo[race][class_]; + if (pInfo->displayId_m == 0 || pInfo->displayId_f == 0) + return; + + if (level <= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + *info = pInfo->levelInfo[level-1]; + else + BuildPlayerLevelInfo(race,class_,level,info); +} + +void ObjectMgr::BuildPlayerLevelInfo(uint8 race, uint8 _class, uint8 level, PlayerLevelInfo* info) const +{ + // base data (last known level) + *info = playerInfo[race][_class].levelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)-1]; + + // if conversion from uint32 to uint8 causes unexpected behaviour, change lvl to uint32 + for (uint8 lvl = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)-1; lvl < level; ++lvl) + { + switch(_class) + { + case CLASS_WARRIOR: + info->stats[STAT_STRENGTH] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0)); + info->stats[STAT_STAMINA] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0)); + info->stats[STAT_AGILITY] += (lvl > 36 ? 1: (lvl > 6 && (lvl%2) ? 1: 0)); + info->stats[STAT_INTELLECT] += (lvl > 9 && !(lvl%2) ? 1: 0); + info->stats[STAT_SPIRIT] += (lvl > 9 && !(lvl%2) ? 1: 0); + break; + case CLASS_PALADIN: + info->stats[STAT_STRENGTH] += (lvl > 3 ? 1: 0); + info->stats[STAT_STAMINA] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0)); + info->stats[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 7 && !(lvl%2) ? 1: 0)); + info->stats[STAT_INTELLECT] += (lvl > 6 && (lvl%2) ? 1: 0); + info->stats[STAT_SPIRIT] += (lvl > 7 ? 1: 0); + break; + case CLASS_HUNTER: + info->stats[STAT_STRENGTH] += (lvl > 4 ? 1: 0); + info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0); + info->stats[STAT_AGILITY] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0)); + info->stats[STAT_INTELLECT] += (lvl > 8 && (lvl%2) ? 1: 0); + info->stats[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0)); + break; + case CLASS_ROGUE: + info->stats[STAT_STRENGTH] += (lvl > 5 ? 1: 0); + info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0); + info->stats[STAT_AGILITY] += (lvl > 16 ? 2: (lvl > 1 ? 1: 0)); + info->stats[STAT_INTELLECT] += (lvl > 8 && !(lvl%2) ? 1: 0); + info->stats[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0)); + break; + case CLASS_PRIEST: + info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0); + info->stats[STAT_STAMINA] += (lvl > 5 ? 1: 0); + info->stats[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 8 && (lvl%2) ? 1: 0)); + info->stats[STAT_INTELLECT] += (lvl > 22 ? 2: (lvl > 1 ? 1: 0)); + info->stats[STAT_SPIRIT] += (lvl > 3 ? 1: 0); + break; + case CLASS_SHAMAN: + info->stats[STAT_STRENGTH] += (lvl > 34 ? 1: (lvl > 6 && (lvl%2) ? 1: 0)); + info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0); + info->stats[STAT_AGILITY] += (lvl > 7 && !(lvl%2) ? 1: 0); + info->stats[STAT_INTELLECT] += (lvl > 5 ? 1: 0); + info->stats[STAT_SPIRIT] += (lvl > 4 ? 1: 0); + break; + case CLASS_MAGE: + info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0); + info->stats[STAT_STAMINA] += (lvl > 5 ? 1: 0); + info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0); + info->stats[STAT_INTELLECT] += (lvl > 24 ? 2: (lvl > 1 ? 1: 0)); + info->stats[STAT_SPIRIT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0)); + break; + case CLASS_WARLOCK: + info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0); + info->stats[STAT_STAMINA] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0)); + info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0); + info->stats[STAT_INTELLECT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0)); + info->stats[STAT_SPIRIT] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0)); + break; + case CLASS_DRUID: + info->stats[STAT_STRENGTH] += (lvl > 38 ? 2: (lvl > 6 && (lvl%2) ? 1: 0)); + info->stats[STAT_STAMINA] += (lvl > 32 ? 2: (lvl > 4 ? 1: 0)); + info->stats[STAT_AGILITY] += (lvl > 38 ? 2: (lvl > 8 && (lvl%2) ? 1: 0)); + info->stats[STAT_INTELLECT] += (lvl > 38 ? 3: (lvl > 4 ? 1: 0)); + info->stats[STAT_SPIRIT] += (lvl > 38 ? 3: (lvl > 5 ? 1: 0)); + } + } +} + +void ObjectMgr::LoadGuilds() +{ + Guild *newGuild; + uint32 count = 0; + + // 0 1 2 3 4 5 6 + QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT guild.guildid,guild.name,leaderguid,EmblemStyle,EmblemColor,BorderStyle,BorderColor," + // 7 8 9 10 11 12 + "BackgroundColor,info,motd,createdate,BankMoney,COUNT(guild_bank_tab.guildid) " + "FROM guild LEFT JOIN guild_bank_tab ON guild.guildid = guild_bank_tab.guildid GROUP BY guild.guildid ORDER BY guildid ASC"); + + if (!result) + { + + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u guild definitions", count); + return; + } + + // load guild ranks + // 0 1 2 3 4 + QueryResult_AutoPtr guildRanksResult = CharacterDatabase.Query("SELECT guildid,rid,rname,rights,BankMoneyPerDay FROM guild_rank ORDER BY guildid ASC, rid ASC"); + + // load guild members + // 0 1 2 3 4 5 6 + QueryResult_AutoPtr guildMembersResult = CharacterDatabase.Query("SELECT guildid,guild_member.guid,rank,pnote,offnote,BankResetTimeMoney,BankRemMoney," + // 7 8 9 10 11 12 + "BankResetTimeTab0,BankRemSlotsTab0,BankResetTimeTab1,BankRemSlotsTab1,BankResetTimeTab2,BankRemSlotsTab2," + // 13 14 15 16 17 18 + "BankResetTimeTab3,BankRemSlotsTab3,BankResetTimeTab4,BankRemSlotsTab4,BankResetTimeTab5,BankRemSlotsTab5," + // 19 20 21 22 23 + "characters.name, characters.level, characters.class, characters.zone, characters.logout_time " + "FROM guild_member LEFT JOIN characters ON characters.guid = guild_member.guid ORDER BY guildid ASC"); + + // load guild bank tab rights + // 0 1 2 3 4 + QueryResult_AutoPtr guildBankTabRightsResult = CharacterDatabase.Query("SELECT guildid,TabId,rid,gbright,SlotPerDay FROM guild_bank_right ORDER BY guildid ASC, TabId ASC"); + + barGoLink bar(result->GetRowCount()); + + do + { + //Field *fields = result->Fetch(); + + bar.step(); + ++count; + + newGuild = new Guild; + if (!newGuild->LoadGuildFromDB(result) || + !newGuild->LoadRanksFromDB(guildRanksResult) || + !newGuild->LoadMembersFromDB(guildMembersResult) || + !newGuild->LoadBankRightsFromDB(guildBankTabRightsResult) || + !newGuild->CheckGuildStructure() +) + { + newGuild->Disband(); + delete newGuild; + continue; + } + newGuild->LoadGuildEventLogFromDB(); + newGuild->LoadGuildBankEventLogFromDB(); + newGuild->LoadGuildBankFromDB(); + AddGuild(newGuild); + + } while (result->NextRow()); + + //delete unused LogGuid records in guild_eventlog and guild_bank_eventlog table + //you can comment these lines if you don't plan to change CONFIG_GUILD_EVENT_LOG_COUNT and CONFIG_GUILD_BANK_EVENT_LOG_COUNT + CharacterDatabase.PQuery("DELETE FROM guild_eventlog WHERE LogGuid > '%u'", sWorld.getConfig(CONFIG_GUILD_EVENT_LOG_COUNT)); + CharacterDatabase.PQuery("DELETE FROM guild_bank_eventlog WHERE LogGuid > '%u'", sWorld.getConfig(CONFIG_GUILD_BANK_EVENT_LOG_COUNT)); + + sLog.outString(); + sLog.outString(">> Loaded %u guild definitions", count); +} + +void ObjectMgr::LoadArenaTeams() +{ + uint32 count = 0; + + // 0 1 2 3 4 5 + QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT arena_team.arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle," + // 6 7 8 9 10 11 12 13 14 + "EmblemColor,BorderStyle,BorderColor, rating,games,wins,played,wins2,rank " + "FROM arena_team LEFT JOIN arena_team_stats ON arena_team.arenateamid = arena_team_stats.arenateamid ORDER BY arena_team.arenateamid ASC"); + + if (!result) + { + + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u arenateam definitions", count); + return; + } + + // load arena_team members + QueryResult_AutoPtr arenaTeamMembersResult = CharacterDatabase.Query( + // 0 1 2 3 4 5 6 7 8 + "SELECT arenateamid,member.guid,played_week,wons_week,played_season,wons_season,personal_rating,name,class " + "FROM arena_team_member member LEFT JOIN characters chars on member.guid = chars.guid ORDER BY member.arenateamid ASC"); + + barGoLink bar(result->GetRowCount()); + + do + { + //Field *fields = result->Fetch(); + + bar.step(); + ++count; + + ArenaTeam *newArenaTeam = new ArenaTeam; + if (!newArenaTeam->LoadArenaTeamFromDB(result) || + !newArenaTeam->LoadMembersFromDB(arenaTeamMembersResult)) + { + newArenaTeam->Disband(NULL); + delete newArenaTeam; + continue; + } + AddArenaTeam(newArenaTeam); + }while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u arenateam definitions", count); +} + +void ObjectMgr::LoadGroups() +{ + Group *group = NULL; + Field *fields = NULL; + uint64 groupGuid = 0; + uint32 count = 0; + + // Consistency cleaning before load to avoid having to do some checks later + // Delete all members that does not exist + CharacterDatabase.PExecute("DELETE FROM group_member WHERE NOT EXISTS (SELECT guid FROM characters WHERE guid=memberGuid)"); + // Delete all groups whose leader does not exist + CharacterDatabase.PExecute("DELETE FROM groups WHERE NOT EXISTS (SELECT guid FROM characters WHERE guid=leaderGuid)"); + // Delete all groups with less than 2 members + CharacterDatabase.PExecute("DELETE FROM groups WHERE guid NOT IN (SELECT guid FROM group_member GROUP BY guid HAVING COUNT(guid) > 1)"); + // Delete all rows from group_member or group_instance with no group + CharacterDatabase.PExecute("DELETE FROM group_member WHERE guid NOT IN (SELECT guid FROM groups)"); + CharacterDatabase.PExecute("DELETE FROM group_instance WHERE guid NOT IN (SELECT guid FROM groups)"); + + // ----------------------- Load Group definitions + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT leaderGuid, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, groupType, difficulty, raiddifficulty, guid FROM groups"); + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded 0 group definitions"); + return; + } + + barGoLink bar(result->GetRowCount()); + do + { + bar.step(); + fields = result->Fetch(); + ++count; + group = new Group; + groupGuid = MAKE_NEW_GUID(fields[15].GetUInt32(),0,HIGHGUID_GROUP); + group->LoadGroupFromDB(groupGuid, result, false); + // group load will never be false (we have run consistency sql's before loading) + AddGroup(group); + }while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u group definitions", count); + + // ----------------------- Load member + // 0 1 2 3 + result = CharacterDatabase.Query("SELECT guid, memberGuid, memberFlags, subgroup FROM group_member ORDER BY guid"); + if (!result) + { + barGoLink bar2(1); + bar2.step(); + sLog.outString(); + sLog.outString(">> Loaded 0 group members"); + return; + } + + barGoLink bar2(result->GetRowCount()); + uint32 groupLowGuid = 0; + count = 0; + do + { + bar2.step(); + fields = result->Fetch(); + + if (groupLowGuid != fields[0].GetUInt32()) + { + groupLowGuid = fields[0].GetUInt32(); + groupGuid = MAKE_NEW_GUID(groupLowGuid, 0, HIGHGUID_GROUP); + group = GetGroupByGUID(groupGuid); + // group will never be NULL (we have run consistency sql's before loading) + } + group->LoadMemberFromDB(fields[1].GetUInt32(), fields[2].GetUInt8(), fields[3].GetUInt8()); + ++count; + }while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u group members", count); + + + // ----------------------- Load instance save + // 0 1 2 3 4 5 + result = CharacterDatabase.Query("SELECT guid, map, instance, permanent, difficulty, resettime, " + // 6 + "(SELECT COUNT(1) FROM groups JOIN character_instance ON leaderGuid = groups.guid WHERE instance = group_instance.instance AND permanent = 1 LIMIT 1) " + "FROM group_instance LEFT JOIN instance ON instance = id ORDER BY guid"); + + if (!result) + { + barGoLink bar2(1); + bar2.step(); + sLog.outString(); + sLog.outString(">> Loaded 0 group-instance saves"); + return; + } + + barGoLink bar3(result->GetRowCount()); + count = 0; + do + { + bar3.step(); + fields = result->Fetch(); + groupGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_GROUP); + group = GetGroupByGUID(groupGuid); + // group will never be NULL (we have run consistency sql's before loading) + + MapEntry const* mapEntry = sMapStore.LookupEntry(fields[1].GetUInt32()); + if (!mapEntry || !mapEntry->IsDungeon()) + { + sLog.outErrorDb("Incorrect entry in group_instance table : no dungeon map %d", fields[1].GetUInt32()); + continue; + } + + uint32 diff = fields[4].GetUInt8(); + if (diff >= (mapEntry->IsRaid() ? MAX_RAID_DIFFICULTY : MAX_DUNGEON_DIFFICULTY)) + { + sLog.outErrorDb("Wrong dungeon difficulty use in group_instance table: %d", diff + 1); + diff = 0; // default for both difficaly types + } + + InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapEntry->MapID, fields[2].GetUInt32(), Difficulty(diff), time_t(fields[5].GetUInt64()), fields[6].GetBool(), true); + group->BindToInstance(save, fields[3].GetBool(), true); + ++count; + }while (result->NextRow()); + sLog.outString(); + sLog.outString(">> Loaded %u group-instance saves", count); +} + +void ObjectMgr::LoadQuests() +{ + // For reload case + for (QuestMap::const_iterator itr=mQuestTemplates.begin(); itr != mQuestTemplates.end(); ++itr) + delete itr->second; + mQuestTemplates.clear(); + + mExclusiveQuestGroups.clear(); + + // 0 1 2 3 4 5 6 7 8 9 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, Method, ZoneOrSort, SkillOrClassMask, MinLevel, MaxLevel, QuestLevel, Type, RequiredRaces, RequiredSkillValue," + // 10 11 12 13 14 15 16 17 18 19 + "RepObjectiveFaction, RepObjectiveValue, RepObjectiveFaction2, RepObjectiveValue2, RequiredMinRepFaction, RequiredMinRepValue, RequiredMaxRepFaction, RequiredMaxRepValue, SuggestedPlayers, LimitTime," + // 20 21 22 23 24 25 26 27 28 29 30 31 32 33 + "QuestFlags, SpecialFlags, CharTitleId, PlayersSlain, BonusTalents, RewardArenaPoints, PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestInChain, RewXPId, SrcItemId, SrcItemCount, SrcSpell," + // 34 35 36 37 38 39 40 41 42 43 44 + "Title, Details, Objectives, OfferRewardText, RequestItemsText, EndText, CompletedText, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4," + // 45 46 47 48 49 50 51 52 53 54 55 56 + "ReqItemId1, ReqItemId2, ReqItemId3, ReqItemId4, ReqItemId5, ReqItemId6, ReqItemCount1, ReqItemCount2, ReqItemCount3, ReqItemCount4, ReqItemCount5, ReqItemCount6," + // 57 58 59 60 61 62 63 64 + "ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4," + // 65 66 67 68 69 70 71 72 + "ReqCreatureOrGOId1, ReqCreatureOrGOId2, ReqCreatureOrGOId3, ReqCreatureOrGOId4, ReqCreatureOrGOCount1, ReqCreatureOrGOCount2, ReqCreatureOrGOCount3, ReqCreatureOrGOCount4," + // 73 74 75 76 + "ReqSpellCast1, ReqSpellCast2, ReqSpellCast3, ReqSpellCast4," + // 77 78 79 80 81 82 + "RewChoiceItemId1, RewChoiceItemId2, RewChoiceItemId3, RewChoiceItemId4, RewChoiceItemId5, RewChoiceItemId6," + // 83 84 85 86 87 88 + "RewChoiceItemCount1, RewChoiceItemCount2, RewChoiceItemCount3, RewChoiceItemCount4, RewChoiceItemCount5, RewChoiceItemCount6," + // 89 90 91 92 93 94 95 96 + "RewItemId1, RewItemId2, RewItemId3, RewItemId4, RewItemCount1, RewItemCount2, RewItemCount3, RewItemCount4," + // 97 98 99 100 101 102 103 104 105 106 + "RewRepFaction1, RewRepFaction2, RewRepFaction3, RewRepFaction4, RewRepFaction5, RewRepValueId1, RewRepValueId2, RewRepValueId3, RewRepValueId4, RewRepValueId5," + // 107 108 109 110 111 + "RewRepValue1, RewRepValue2, RewRepValue3, RewRepValue4, RewRepValue5," + // 112 113 114 115 116 117 118 119 120 121 122 123 + "RewHonorAddition, RewHonorMultiplier, RewOrReqMoney, RewMoneyMaxLevel, RewSpell, RewSpellCast, RewMailTemplateId, RewMailDelaySecs, PointMapId, PointX, PointY, PointOpt," + // 124 125 126 127 128 129 130 131 + "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, DetailsEmoteDelay1, DetailsEmoteDelay2, DetailsEmoteDelay3, DetailsEmoteDelay4," + // 132 133 134 135 136 137 + "IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4," + // 138 139 140 141 + "OfferRewardEmoteDelay1, OfferRewardEmoteDelay2, OfferRewardEmoteDelay3, OfferRewardEmoteDelay4," + // 142 143 + "StartScript, CompleteScript" + " FROM quest_template"); + if (result == NULL) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded 0 quests definitions"); + sLog.outErrorDb("`quest_template` table is empty!"); + return; + } + + // create multimap previous quest for each existed quest + // some quests can have many previous maps set by NextQuestId in previous quest + // for example set of race quests can lead to single not race specific quest + barGoLink bar(result->GetRowCount()); + do + { + bar.step(); + Field *fields = result->Fetch(); + + Quest * newQuest = new Quest(fields); + mQuestTemplates[newQuest->GetQuestId()] = newQuest; + } while (result->NextRow()); + + std::map usedMailTemplates; + + // Post processing + for (QuestMap::iterator iter = mQuestTemplates.begin(); iter != mQuestTemplates.end(); ++iter) + { + Quest * qinfo = iter->second; + + // additional quest integrity checks (GO, creature_template and item_template must be loaded already) + + if (qinfo->GetQuestMethod() >= 3) + { + sLog.outErrorDb("Quest %u has `Method` = %u, expected values are 0, 1 or 2.",qinfo->GetQuestId(),qinfo->GetQuestMethod()); + } + + if (qinfo->QuestFlags & ~QUEST_TRINITY_FLAGS_DB_ALLOWED) + { + sLog.outErrorDb("Quest %u has `SpecialFlags` = %u > max allowed value. Correct `SpecialFlags` to value <= %u", + qinfo->GetQuestId(),qinfo->QuestFlags >> 20, QUEST_TRINITY_FLAGS_DB_ALLOWED >> 20); + qinfo->QuestFlags &= QUEST_TRINITY_FLAGS_DB_ALLOWED; + } + + if (qinfo->QuestFlags & QUEST_FLAGS_DAILY && qinfo->QuestFlags & QUEST_FLAGS_WEEKLY) + { + sLog.outErrorDb("Weekly Quest %u is marked as daily quest in `QuestFlags`, removed daily flag.",qinfo->GetQuestId()); + qinfo->QuestFlags &= ~QUEST_FLAGS_DAILY; + } + + if (qinfo->QuestFlags & QUEST_FLAGS_DAILY) + { + if (!(qinfo->QuestFlags & QUEST_TRINITY_FLAGS_REPEATABLE)) + { + sLog.outErrorDb("Daily Quest %u not marked as repeatable in `SpecialFlags`, added.",qinfo->GetQuestId()); + qinfo->QuestFlags |= QUEST_TRINITY_FLAGS_REPEATABLE; + } + } + + if (qinfo->QuestFlags & QUEST_FLAGS_WEEKLY) + { + if (!(qinfo->QuestFlags & QUEST_TRINITY_FLAGS_REPEATABLE)) + { + sLog.outErrorDb("Weekly Quest %u not marked as repeatable in `SpecialFlags`, added.",qinfo->GetQuestId()); + qinfo->QuestFlags |= QUEST_TRINITY_FLAGS_REPEATABLE; + } + } + + if (qinfo->QuestFlags & QUEST_FLAGS_AUTO_REWARDED) + { + // at auto-reward can be rewarded only RewChoiceItemId[0] + for (int j = 1; j < QUEST_REWARD_CHOICES_COUNT; ++j ) + { + if (uint32 id = qinfo->RewChoiceItemId[j]) + { + sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item from `RewChoiceItemId%d` can't be rewarded with quest flag QUEST_FLAGS_AUTO_REWARDED.", + qinfo->GetQuestId(),j+1,id,j+1); + // no changes, quest ignore this data + } + } + } + + // client quest log visual (area case) + if (qinfo->ZoneOrSort > 0) + { + if (!GetAreaEntryByAreaID(qinfo->ZoneOrSort)) + { + sLog.outErrorDb("Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.", + qinfo->GetQuestId(),qinfo->ZoneOrSort); + // no changes, quest not dependent from this value but can have problems at client + } + } + // client quest log visual (sort case) + if (qinfo->ZoneOrSort < 0) + { + QuestSortEntry const* qSort = sQuestSortStore.LookupEntry(-int32(qinfo->ZoneOrSort)); + if (!qSort) + { + sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (sort case) but quest sort with this id does not exist.", + qinfo->GetQuestId(),qinfo->ZoneOrSort); + // no changes, quest not dependent from this value but can have problems at client (note some may be 0, we must allow this so no check) + } + //check SkillOrClass value (class case). + if (ClassByQuestSort(-int32(qinfo->ZoneOrSort))) + { + // SkillOrClass should not have class case when class case already set in ZoneOrSort. + if (qinfo->SkillOrClassMask < 0) + { + sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (class sort case) and `SkillOrClassMask` = %i (class case), redundant.", + qinfo->GetQuestId(),qinfo->ZoneOrSort,qinfo->SkillOrClassMask); + } + } + //check for proper SkillOrClass value (skill case) + if (int32 skill_id = SkillByQuestSort(-int32(qinfo->ZoneOrSort))) + { + // skill is positive value in SkillOrClass + if (qinfo->SkillOrClassMask != skill_id) + { + sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (skill sort case) but `SkillOrClassMask` does not have a corresponding value (%i).", + qinfo->GetQuestId(),qinfo->ZoneOrSort,skill_id); + //override, and force proper value here? + } + } + } + + // SkillOrClassMask (class case) + if (qinfo->SkillOrClassMask < 0) + { + if (!(-int32(qinfo->SkillOrClassMask) & CLASSMASK_ALL_PLAYABLE)) + { + sLog.outErrorDb("Quest %u has `SkillOrClassMask` = %i (class case) but classmask does not have valid class", + qinfo->GetQuestId(),qinfo->SkillOrClassMask); + } + } + // SkillOrClassMask (skill case) + if (qinfo->SkillOrClassMask > 0) + { + if (!sSkillLineStore.LookupEntry(qinfo->SkillOrClassMask)) + { + sLog.outErrorDb("Quest %u has `SkillOrClass` = %u (skill case) but skill (%i) does not exist", + qinfo->GetQuestId(),qinfo->SkillOrClassMask,qinfo->SkillOrClassMask); + } + } + + if (qinfo->RequiredSkillValue) + { + if (qinfo->RequiredSkillValue > sWorld.GetConfigMaxSkillValue()) + { + sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but max possible skill is %u, quest can't be done.", + qinfo->GetQuestId(),qinfo->RequiredSkillValue,sWorld.GetConfigMaxSkillValue()); + // no changes, quest can't be done for this requirement + } + + if (qinfo->SkillOrClassMask <= 0) + { + sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but `SkillOrClass` = %i (class case), value ignored.", + qinfo->GetQuestId(),qinfo->RequiredSkillValue,qinfo->SkillOrClassMask); + // no changes, quest can't be done for this requirement (fail at wrong skill id) + } + } + // else Skill quests can have 0 skill level, this is ok + + if (qinfo->RepObjectiveFaction2 && !sFactionStore.LookupEntry(qinfo->RepObjectiveFaction2)) + { + sLog.outErrorDb("Quest %u has `RepObjectiveFaction2` = %u but faction template %u does not exist, quest can't be done.", + qinfo->GetQuestId(),qinfo->RepObjectiveFaction2,qinfo->RepObjectiveFaction2); + // no changes, quest can't be done for this requirement + } + + if (qinfo->RepObjectiveFaction && !sFactionStore.LookupEntry(qinfo->RepObjectiveFaction)) + { + sLog.outErrorDb("Quest %u has `RepObjectiveFaction` = %u but faction template %u does not exist, quest can't be done.", + qinfo->GetQuestId(),qinfo->RepObjectiveFaction,qinfo->RepObjectiveFaction); + // no changes, quest can't be done for this requirement + } + + if (qinfo->RequiredMinRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMinRepFaction)) + { + sLog.outErrorDb("Quest %u has `RequiredMinRepFaction` = %u but faction template %u does not exist, quest can't be done.", + qinfo->GetQuestId(),qinfo->RequiredMinRepFaction,qinfo->RequiredMinRepFaction); + // no changes, quest can't be done for this requirement + } + + if (qinfo->RequiredMaxRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMaxRepFaction)) + { + sLog.outErrorDb("Quest %u has `RequiredMaxRepFaction` = %u but faction template %u does not exist, quest can't be done.", + qinfo->GetQuestId(),qinfo->RequiredMaxRepFaction,qinfo->RequiredMaxRepFaction); + // no changes, quest can't be done for this requirement + } + + if (qinfo->RequiredMinRepValue && qinfo->RequiredMinRepValue > ReputationMgr::Reputation_Cap) + { + sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but max reputation is %u, quest can't be done.", + qinfo->GetQuestId(),qinfo->RequiredMinRepValue,ReputationMgr::Reputation_Cap); + // no changes, quest can't be done for this requirement + } + + if (qinfo->RequiredMinRepValue && qinfo->RequiredMaxRepValue && qinfo->RequiredMaxRepValue <= qinfo->RequiredMinRepValue) + { + sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d and `RequiredMinRepValue` = %d, quest can't be done.", + qinfo->GetQuestId(),qinfo->RequiredMaxRepValue,qinfo->RequiredMinRepValue); + // no changes, quest can't be done for this requirement + } + + if (!qinfo->RepObjectiveFaction && qinfo->RepObjectiveValue > 0) + { + sLog.outErrorDb("Quest %u has `RepObjectiveValue` = %d but `RepObjectiveFaction` is 0, value has no effect", + qinfo->GetQuestId(),qinfo->RepObjectiveValue); + // warning + } + + if (!qinfo->RepObjectiveFaction2 && qinfo->RepObjectiveValue2 > 0) + { + sLog.outErrorDb("Quest %u has `RepObjectiveValue2` = %d but `RepObjectiveFaction2` is 0, value has no effect", + qinfo->GetQuestId(),qinfo->RepObjectiveValue2); + // warning + } + + if (!qinfo->RequiredMinRepFaction && qinfo->RequiredMinRepValue > 0) + { + sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but `RequiredMinRepFaction` is 0, value has no effect", + qinfo->GetQuestId(),qinfo->RequiredMinRepValue); + // warning + } + + if (!qinfo->RequiredMaxRepFaction && qinfo->RequiredMaxRepValue > 0) + { + sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d but `RequiredMaxRepFaction` is 0, value has no effect", + qinfo->GetQuestId(),qinfo->RequiredMaxRepValue); + // warning + } + + if (qinfo->CharTitleId && !sCharTitlesStore.LookupEntry(qinfo->CharTitleId)) + { + sLog.outErrorDb("Quest %u has `CharTitleId` = %u but CharTitle Id %u does not exist, quest can't be rewarded with title.", + qinfo->GetQuestId(),qinfo->GetCharTitleId(),qinfo->GetCharTitleId()); + qinfo->CharTitleId = 0; + // quest can't reward this title + } + + if (qinfo->SrcItemId) + { + if (!sItemStorage.LookupEntry(qinfo->SrcItemId)) + { + sLog.outErrorDb("Quest %u has `SrcItemId` = %u but item with entry %u does not exist, quest can't be done.", + qinfo->GetQuestId(),qinfo->SrcItemId,qinfo->SrcItemId); + qinfo->SrcItemId = 0; // quest can't be done for this requirement + } + else if (qinfo->SrcItemCount == 0) + { + sLog.outErrorDb("Quest %u has `SrcItemId` = %u but `SrcItemCount` = 0, set to 1 but need fix in DB.", + qinfo->GetQuestId(),qinfo->SrcItemId); + qinfo->SrcItemCount = 1; // update to 1 for allow quest work for backward compatibility with DB + } + } + else if (qinfo->SrcItemCount>0) + { + sLog.outErrorDb("Quest %u has `SrcItemId` = 0 but `SrcItemCount` = %u, useless value.", + qinfo->GetQuestId(),qinfo->SrcItemCount); + qinfo->SrcItemCount=0; // no quest work changes in fact + } + + if (qinfo->SrcSpell) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->SrcSpell); + if (!spellInfo) + { + sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u doesn't exist, quest can't be done.", + qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell); + qinfo->SrcSpell = 0; // quest can't be done for this requirement + } + else if (!SpellMgr::IsSpellValid(spellInfo)) + { + sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u is broken, quest can't be done.", + qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell); + qinfo->SrcSpell = 0; // quest can't be done for this requirement + } + } + + for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j) + { + uint32 id = qinfo->ReqItemId[j]; + if (id) + { + if (qinfo->ReqItemCount[j] == 0) + { + sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but `ReqItemCount%d` = 0, quest can't be done.", + qinfo->GetQuestId(),j+1,id,j+1); + // no changes, quest can't be done for this requirement + } + + qinfo->SetFlag(QUEST_TRINITY_FLAGS_DELIVER); + + if (!sItemStorage.LookupEntry(id)) + { + sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but item with entry %u does not exist, quest can't be done.", + qinfo->GetQuestId(),j+1,id,id); + qinfo->ReqItemCount[j] = 0; // prevent incorrect work of quest + } + } + else if (qinfo->ReqItemCount[j]>0) + { + sLog.outErrorDb("Quest %u has `ReqItemId%d` = 0 but `ReqItemCount%d` = %u, quest can't be done.", + qinfo->GetQuestId(),j+1,j+1,qinfo->ReqItemCount[j]); + qinfo->ReqItemCount[j] = 0; // prevent incorrect work of quest + } + } + + for (uint8 j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j) + { + uint32 id = qinfo->ReqSourceId[j]; + if (id) + { + if (!sItemStorage.LookupEntry(id)) + { + sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but item with entry %u does not exist, quest can't be done.", + qinfo->GetQuestId(),j+1,id,id); + // no changes, quest can't be done for this requirement + } + } + else + { + if (qinfo->ReqSourceCount[j]>0) + { + sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceCount%d` = %u.", + qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceCount[j]); + // no changes, quest ignore this data + } + } + } + + for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j) + { + uint32 id = qinfo->ReqSpell[j]; + if (id) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(id); + if (!spellInfo) + { + sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u but spell %u does not exist, quest can't be done.", + qinfo->GetQuestId(),j+1,id,id); + continue; + } + + if (!qinfo->ReqCreatureOrGOId[j]) + { + bool found = false; + for (uint8 k = 0; k < 3; ++k) + { + if ((spellInfo->Effect[k] == SPELL_EFFECT_QUEST_COMPLETE && uint32(spellInfo->EffectMiscValue[k]) == qinfo->QuestId) || + spellInfo->Effect[k] == SPELL_EFFECT_SEND_EVENT) + { + found = true; + break; + } + } + + if (found) + { + if (!qinfo->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT)) + { + sLog.outErrorDb("Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT for quest %u and ReqCreatureOrGOId%d = 0, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Quest flags or ReqCreatureOrGOId%d must be fixed, quest modified to enable objective.",spellInfo->Id,qinfo->QuestId,j+1,j+1); + + // this will prevent quest completing without objective + const_cast(qinfo)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT); + } + } + else + { + sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u and ReqCreatureOrGOId%d = 0 but spell %u does not have SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT effect for this quest, quest can't be done.", + qinfo->GetQuestId(),j+1,id,j+1,id); + // no changes, quest can't be done for this requirement + } + } + } + } + + for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j) + { + int32 id = qinfo->ReqCreatureOrGOId[j]; + if (id < 0 && !sGOStorage.LookupEntry(-id)) + { + sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but gameobject %u does not exist, quest can't be done.", + qinfo->GetQuestId(),j+1,id,uint32(-id)); + qinfo->ReqCreatureOrGOId[j] = 0; // quest can't be done for this requirement + } + + if (id > 0 && !sCreatureStorage.LookupEntry(id)) + { + sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but creature with entry %u does not exist, quest can't be done.", + qinfo->GetQuestId(),j+1,id,uint32(id)); + qinfo->ReqCreatureOrGOId[j] = 0; // quest can't be done for this requirement + } + + if (id) + { + // In fact SpeakTo and Kill are quite same: either you can speak to mob:SpeakTo or you can't:Kill/Cast + + qinfo->SetFlag(QUEST_TRINITY_FLAGS_KILL_OR_CAST | QUEST_TRINITY_FLAGS_SPEAKTO); + + if (!qinfo->ReqCreatureOrGOCount[j]) + { + sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %u but `ReqCreatureOrGOCount%d` = 0, quest can't be done.", + qinfo->GetQuestId(),j+1,id,j+1); + // no changes, quest can be incorrectly done, but we already report this + } + } + else if (qinfo->ReqCreatureOrGOCount[j]>0) + { + sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = 0 but `ReqCreatureOrGOCount%d` = %u.", + qinfo->GetQuestId(),j+1,j+1,qinfo->ReqCreatureOrGOCount[j]); + // no changes, quest ignore this data + } + } + + for (uint8 j = 0; j < QUEST_REWARD_CHOICES_COUNT; ++j) + { + uint32 id = qinfo->RewChoiceItemId[j]; + if (id) + { + if (!sItemStorage.LookupEntry(id)) + { + sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.", + qinfo->GetQuestId(),j+1,id,id); + qinfo->RewChoiceItemId[j] = 0; // no changes, quest will not reward this + } + + if (!qinfo->RewChoiceItemCount[j]) + { + sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but `RewChoiceItemCount%d` = 0, quest can't be done.", + qinfo->GetQuestId(),j+1,id,j+1); + // no changes, quest can't be done + } + } + else if (qinfo->RewChoiceItemCount[j]>0) + { + sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = 0 but `RewChoiceItemCount%d` = %u.", + qinfo->GetQuestId(),j+1,j+1,qinfo->RewChoiceItemCount[j]); + // no changes, quest ignore this data + } + } + + for (uint8 j = 0; j < QUEST_REWARDS_COUNT; ++j) + { + uint32 id = qinfo->RewItemId[j]; + if (id) + { + if (!sItemStorage.LookupEntry(id)) + { + sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.", + qinfo->GetQuestId(),j+1,id,id); + qinfo->RewItemId[j] = 0; // no changes, quest will not reward this item + } + + if (!qinfo->RewItemCount[j]) + { + sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but `RewItemCount%d` = 0, quest will not reward this item.", + qinfo->GetQuestId(),j+1,id,j+1); + // no changes + } + } + else if (qinfo->RewItemCount[j]>0) + { + sLog.outErrorDb("Quest %u has `RewItemId%d` = 0 but `RewItemCount%d` = %u.", + qinfo->GetQuestId(),j+1,j+1,qinfo->RewItemCount[j]); + // no changes, quest ignore this data + } + } + + for (uint8 j = 0; j < QUEST_REPUTATIONS_COUNT; ++j) + { + if (qinfo->RewRepFaction[j]) + { + if (abs(qinfo->RewRepValueId[j]) > 9) + { + sLog.outErrorDb("Quest %u has RewRepValueId%d = %i. That is outside the range of valid values (-9 to 9).", qinfo->GetQuestId(), j+1, qinfo->RewRepValueId[j]); + } + if (!sFactionStore.LookupEntry(qinfo->RewRepFaction[j])) + { + sLog.outErrorDb("Quest %u has `RewRepFaction%d` = %u but raw faction (faction.dbc) %u does not exist, quest will not reward reputation for this faction.", qinfo->GetQuestId(),j+1,qinfo->RewRepFaction[j] ,qinfo->RewRepFaction[j]); + qinfo->RewRepFaction[j] = 0; // quest will not reward this + } + } + + + else if (qinfo->RewRepValue[j] != 0) + { + sLog.outErrorDb("Quest %u has `RewRepFaction%d` = 0 but `RewRepValue%d` = %i.", + qinfo->GetQuestId(),j+1,j+1,qinfo->RewRepValue[j]); + // no changes, quest ignore this data + } + } + + + if (qinfo->RewSpell) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpell); + + if (!spellInfo) + { + sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u does not exist, spell removed as display reward.", + qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell); + qinfo->RewSpell = 0; // no spell reward will display for this quest + } + + else if (!SpellMgr::IsSpellValid(spellInfo)) + { + sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is broken, quest will not have a spell reward.", + qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell); + qinfo->RewSpell = 0; // no spell reward will display for this quest + } + + else if (GetTalentSpellCost(qinfo->RewSpell)) + { + sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is talent, quest will not have a spell reward.", + qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell); + qinfo->RewSpell = 0; // no spell reward will display for this quest + } + } + + if (qinfo->RewSpellCast > 0) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpellCast); + + if (!spellInfo) + { + sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u does not exist, quest will not have a spell reward.", + qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast); + qinfo->RewSpellCast = 0; // no spell will be casted on player + } + + else if (!SpellMgr::IsSpellValid(spellInfo)) + { + sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u is broken, quest will not have a spell reward.", + qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast); + qinfo->RewSpellCast = 0; // no spell will be casted on player + } + + else if (GetTalentSpellCost(qinfo->RewSpellCast)) + { + sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is talent, quest will not have a spell reward.", + qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast); + qinfo->RewSpellCast = 0; // no spell will be casted on player + } + } + + if (qinfo->RewMailTemplateId) + { + if (!sMailTemplateStore.LookupEntry(qinfo->RewMailTemplateId)) + { + sLog.outErrorDb("Quest %u has `RewMailTemplateId` = %u but mail template %u does not exist, quest will not have a mail reward.", + qinfo->GetQuestId(),qinfo->RewMailTemplateId,qinfo->RewMailTemplateId); + qinfo->RewMailTemplateId = 0; // no mail will send to player + qinfo->RewMailDelaySecs = 0; // no mail will send to player + } + else if (usedMailTemplates.find(qinfo->RewMailTemplateId) != usedMailTemplates.end()) + { + std::map::const_iterator used_mt_itr = usedMailTemplates.find(qinfo->RewMailTemplateId); + sLog.outErrorDb("Quest %u has `RewMailTemplateId` = %u but mail template %u already used for quest %u, quest will not have a mail reward.", + qinfo->GetQuestId(),qinfo->RewMailTemplateId,qinfo->RewMailTemplateId,used_mt_itr->second); + qinfo->RewMailTemplateId = 0; // no mail will send to player + qinfo->RewMailDelaySecs = 0; // no mail will send to player + } + else + usedMailTemplates[qinfo->RewMailTemplateId] = qinfo->GetQuestId(); + } + + if (qinfo->NextQuestInChain) + { + QuestMap::iterator qNextItr = mQuestTemplates.find(qinfo->NextQuestInChain); + if (qNextItr == mQuestTemplates.end()) + { + sLog.outErrorDb("Quest %u has `NextQuestInChain` = %u but quest %u does not exist, quest chain will not work.", + qinfo->GetQuestId(),qinfo->NextQuestInChain ,qinfo->NextQuestInChain); + qinfo->NextQuestInChain = 0; + } + else + qNextItr->second->prevChainQuests.push_back(qinfo->GetQuestId()); + } + + // fill additional data stores + if (qinfo->PrevQuestId) + { + if (mQuestTemplates.find(abs(qinfo->GetPrevQuestId())) == mQuestTemplates.end()) + { + sLog.outErrorDb("Quest %d has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetPrevQuestId()); + } + else + { + qinfo->prevQuests.push_back(qinfo->PrevQuestId); + } + } + + if (qinfo->NextQuestId) + { + QuestMap::iterator qNextItr = mQuestTemplates.find(abs(qinfo->GetNextQuestId())); + if (qNextItr == mQuestTemplates.end()) + { + sLog.outErrorDb("Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId()); + } + else + { + int32 signedQuestId = qinfo->NextQuestId < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId()); + qNextItr->second->prevQuests.push_back(signedQuestId); + } + } + + if (qinfo->ExclusiveGroup) + mExclusiveQuestGroups.insert(std::pair(qinfo->ExclusiveGroup, qinfo->GetQuestId())); + if (qinfo->LimitTime) + qinfo->SetFlag(QUEST_TRINITY_FLAGS_TIMED); + } + + // check QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE + for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(i); + if (!spellInfo) + continue; + + for (uint8 j = 0; j < 3; ++j) + { + if (spellInfo->Effect[j] != SPELL_EFFECT_QUEST_COMPLETE) + continue; + + uint32 quest_id = spellInfo->EffectMiscValue[j]; + + Quest const* quest = GetQuestTemplate(quest_id); + + // some quest referenced in spells not exist (outdated spells) + if (!quest) + continue; + + if (!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT)) + { + sLog.outErrorDb("Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE for quest %u , but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Quest flags must be fixed, quest modified to enable objective.",spellInfo->Id,quest_id); + + // this will prevent quest completing without objective + const_cast(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT); + } + } + } + + sLog.outString(); + sLog.outString(">> Loaded %lu quests definitions", (unsigned long)mQuestTemplates.size()); +} + +void ObjectMgr::LoadQuestLocales() +{ + mQuestLocaleMap.clear(); // need for reload case + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry," + "Title_loc1,Details_loc1,Objectives_loc1,OfferRewardText_loc1,RequestItemsText_loc1,EndText_loc1,CompletedText_loc1,ObjectiveText1_loc1,ObjectiveText2_loc1,ObjectiveText3_loc1,ObjectiveText4_loc1," + "Title_loc2,Details_loc2,Objectives_loc2,OfferRewardText_loc2,RequestItemsText_loc2,EndText_loc2,CompletedText_loc2,ObjectiveText1_loc2,ObjectiveText2_loc2,ObjectiveText3_loc2,ObjectiveText4_loc2," + "Title_loc3,Details_loc3,Objectives_loc3,OfferRewardText_loc3,RequestItemsText_loc3,EndText_loc3,CompletedText_loc3,ObjectiveText1_loc3,ObjectiveText2_loc3,ObjectiveText3_loc3,ObjectiveText4_loc3," + "Title_loc4,Details_loc4,Objectives_loc4,OfferRewardText_loc4,RequestItemsText_loc4,EndText_loc4,CompletedText_loc4,ObjectiveText1_loc4,ObjectiveText2_loc4,ObjectiveText3_loc4,ObjectiveText4_loc4," + "Title_loc5,Details_loc5,Objectives_loc5,OfferRewardText_loc5,RequestItemsText_loc5,EndText_loc5,CompletedText_loc5,ObjectiveText1_loc5,ObjectiveText2_loc5,ObjectiveText3_loc5,ObjectiveText4_loc5," + "Title_loc6,Details_loc6,Objectives_loc6,OfferRewardText_loc6,RequestItemsText_loc6,EndText_loc6,CompletedText_loc6,ObjectiveText1_loc6,ObjectiveText2_loc6,ObjectiveText3_loc6,ObjectiveText4_loc6," + "Title_loc7,Details_loc7,Objectives_loc7,OfferRewardText_loc7,RequestItemsText_loc7,EndText_loc7,CompletedText_loc7,ObjectiveText1_loc7,ObjectiveText2_loc7,ObjectiveText3_loc7,ObjectiveText4_loc7," + "Title_loc8,Details_loc8,Objectives_loc8,OfferRewardText_loc8,RequestItemsText_loc8,EndText_loc8,CompletedText_loc8,ObjectiveText1_loc8,ObjectiveText2_loc8,ObjectiveText3_loc8,ObjectiveText4_loc8" + " FROM locales_quest" +); + + if (!result) + return; + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + + QuestLocale& data = mQuestLocaleMap[entry]; + + for (uint8 i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[1+11*(i-1)].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.Title.size() <= idx) + data.Title.resize(idx+1); + + data.Title[idx] = str; + } + } + str = fields[1+11*(i-1)+1].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.Details.size() <= idx) + data.Details.resize(idx+1); + + data.Details[idx] = str; + } + } + str = fields[1+11*(i-1)+2].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.Objectives.size() <= idx) + data.Objectives.resize(idx+1); + + data.Objectives[idx] = str; + } + } + str = fields[1+11*(i-1)+3].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.OfferRewardText.size() <= idx) + data.OfferRewardText.resize(idx+1); + + data.OfferRewardText[idx] = str; + } + } + str = fields[1+11*(i-1)+4].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.RequestItemsText.size() <= idx) + data.RequestItemsText.resize(idx+1); + + data.RequestItemsText[idx] = str; + } + } + str = fields[1+11*(i-1)+5].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.EndText.size() <= idx) + data.EndText.resize(idx+1); + + data.EndText[idx] = str; + } + } + str = fields[1+11*(i-1)+6].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.CompletedText.size() <= idx) + data.CompletedText.resize(idx+1); + + data.CompletedText[idx] = str; + } + } + + for (uint8 k = 0; k < 4; ++k) + { + str = fields[1+11*(i-1)+7+k].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.ObjectiveText[k].size() <= idx) + data.ObjectiveText[k].resize(idx+1); + + data.ObjectiveText[k][idx] = str; + } + } + } + } + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %lu Quest locale strings", (unsigned long)mQuestLocaleMap.size()); +} + +void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename) +{ + if (sWorld.IsScriptScheduled()) // function don't must be called in time scripts use. + return; + + sLog.outString("%s :", tablename); + + scripts.clear(); // need for reload support + + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT id,delay,command,datalong,datalong2,dataint, x, y, z, o FROM %s", tablename); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u script definitions", count); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + ScriptInfo tmp; + tmp.id = fields[0].GetUInt32(); + tmp.delay = fields[1].GetUInt32(); + tmp.command = fields[2].GetUInt32(); + tmp.datalong = fields[3].GetUInt32(); + tmp.datalong2 = fields[4].GetUInt32(); + tmp.dataint = fields[5].GetInt32(); + tmp.x = fields[6].GetFloat(); + tmp.y = fields[7].GetFloat(); + tmp.z = fields[8].GetFloat(); + tmp.o = fields[9].GetFloat(); + + // generic command args check + switch (tmp.command) + { + case SCRIPT_COMMAND_TALK: + { + if (tmp.datalong > CHAT_TYPE_WHISPER) + { + sLog.outErrorDb("Table `%s` has invalid talk type (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.datalong,tmp.id); + continue; + } + if (tmp.dataint == 0) + { + sLog.outErrorDb("Table `%s` has invalid talk text id (dataint = %i) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.dataint,tmp.id); + continue; + } + if (tmp.dataint < MIN_DB_SCRIPT_STRING_ID || tmp.dataint >= MAX_DB_SCRIPT_STRING_ID) + { + sLog.outErrorDb("Table `%s` has out of range text id (dataint = %i expected %u-%u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.dataint,MIN_DB_SCRIPT_STRING_ID,MAX_DB_SCRIPT_STRING_ID,tmp.id); + continue; + } + + break; + } + + case SCRIPT_COMMAND_EMOTE: + { + if (!sEmotesStore.LookupEntry(tmp.datalong)) + { + sLog.outErrorDb("Table `%s` has invalid emote id (datalong = %u) in SCRIPT_COMMAND_EMOTE for script id %u",tablename,tmp.datalong,tmp.id); + continue; + } + break; + } + + case SCRIPT_COMMAND_TELEPORT_TO: + { + if (!sMapStore.LookupEntry(tmp.datalong)) + { + sLog.outErrorDb("Table `%s` has invalid map (Id: %u) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.datalong,tmp.id); + continue; + } + + if (!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o)) + { + sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.x,tmp.y,tmp.id); + continue; + } + break; + } + + case SCRIPT_COMMAND_KILL_CREDIT: + { + if (!GetCreatureTemplate(tmp.datalong)) + { + sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_KILL_CREDIT for script id %u",tablename,tmp.datalong,tmp.id); + continue; + } + break; + } + + case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: + { + if (!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o)) + { + sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.x,tmp.y,tmp.id); + continue; + } + + if (!GetCreatureTemplate(tmp.datalong)) + { + sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.datalong,tmp.id); + continue; + } + break; + } + + case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: + { + GameObjectData const* data = GetGOData(tmp.datalong); + if (!data) + { + sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,tmp.id); + continue; + } + + GameObjectInfo const* info = GetGameObjectInfo(data->id); + if (!info) + { + sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,data->id,tmp.id); + continue; + } + + if (info->type == GAMEOBJECT_TYPE_FISHINGNODE || + info->type == GAMEOBJECT_TYPE_FISHINGHOLE || + info->type == GAMEOBJECT_TYPE_DOOR || + info->type == GAMEOBJECT_TYPE_BUTTON || + info->type == GAMEOBJECT_TYPE_TRAP) + { + sLog.outErrorDb("Table `%s` have gameobject type (%u) unsupported by command SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,info->id,tmp.id); + continue; + } + break; + } + case SCRIPT_COMMAND_OPEN_DOOR: + case SCRIPT_COMMAND_CLOSE_DOOR: + { + GameObjectData const* data = GetGOData(tmp.datalong); + if (!data) + { + sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in %s for script id %u",tablename,tmp.datalong,(tmp.command == SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id); + continue; + } + + GameObjectInfo const* info = GetGameObjectInfo(data->id); + if (!info) + { + sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in %s for script id %u",tablename,tmp.datalong,data->id,(tmp.command == SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id); + continue; + } + + if (info->type != GAMEOBJECT_TYPE_DOOR) + { + sLog.outErrorDb("Table `%s` has gameobject type (%u) non supported by command %s for script id %u",tablename,info->id,(tmp.command == SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id); + continue; + } + + break; + } + case SCRIPT_COMMAND_QUEST_EXPLORED: + { + Quest const* quest = GetQuestTemplate(tmp.datalong); + if (!quest) + { + sLog.outErrorDb("Table `%s` has invalid quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",tablename,tmp.datalong,tmp.id); + continue; + } + + if (!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT)) + { + sLog.outErrorDb("Table `%s` has quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT in quest flags. Script command or quest flags wrong. Quest modified to require objective.",tablename,tmp.datalong,tmp.id); + + // this will prevent quest completing without objective + const_cast(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT); + + // continue; - quest objective requirement set and command can be allowed + } + + if (float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE) + { + sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u", + tablename,tmp.datalong2,tmp.id); + continue; + } + + if (tmp.datalong2 && float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE) + { + sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, max distance is %f or 0 for disable distance check", + tablename,tmp.datalong2,tmp.id,DEFAULT_VISIBILITY_DISTANCE); + continue; + } + + if (tmp.datalong2 && float(tmp.datalong2) < INTERACTION_DISTANCE) + { + sLog.outErrorDb("Table `%s` has too small distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, min distance is %f or 0 for disable distance check", + tablename,tmp.datalong2,tmp.id,INTERACTION_DISTANCE); + continue; + } + + break; + } + + case SCRIPT_COMMAND_REMOVE_AURA: + { + if (!sSpellStore.LookupEntry(tmp.datalong)) + { + sLog.outErrorDb("Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA or SCRIPT_COMMAND_CAST_SPELL for script id %u", + tablename,tmp.datalong,tmp.id); + continue; + } + if (tmp.datalong2 & ~0x1) // 1 bits (0,1) + { + sLog.outErrorDb("Table `%s` using unknown flags in datalong2 (%u)i n SCRIPT_COMMAND_CAST_SPELL for script id %u", + tablename,tmp.datalong2,tmp.id); + continue; + } + break; + } + case SCRIPT_COMMAND_CAST_SPELL: + { + if (!sSpellStore.LookupEntry(tmp.datalong)) + { + sLog.outErrorDb("Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA or SCRIPT_COMMAND_CAST_SPELL for script id %u", + tablename,tmp.datalong,tmp.id); + continue; + } + if (tmp.datalong2 & ~0x3) // 2 bits + { + sLog.outErrorDb("Table `%s` using unknown flags in datalong2 (%u)i n SCRIPT_COMMAND_CAST_SPELL for script id %u", + tablename,tmp.datalong2,tmp.id); + continue; + } + break; + } + + case SCRIPT_COMMAND_CREATE_ITEM: + { + if (!GetItemPrototype(tmp.datalong)) + { + sLog.outErrorDb("Table `%s` has nonexistent item (entry: %u) in SCRIPT_COMMAND_CREATE_ITEM for script id %u", + tablename, tmp.datalong, tmp.id); + continue; + } + if (!tmp.datalong2) + { + sLog.outErrorDb("Table `%s` SCRIPT_COMMAND_CREATE_ITEM but amount is %u for script id %u", + tablename, tmp.datalong2, tmp.id); + continue; + } + break; + } + } + + if (scripts.find(tmp.id) == scripts.end()) + { + ScriptMap emptyMap; + scripts[tmp.id] = emptyMap; + } + scripts[tmp.id].insert(std::pair(tmp.delay, tmp)); + + ++count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u script definitions", count); +} + +void ObjectMgr::LoadGameObjectScripts() +{ + LoadScripts(sGameObjectScripts, "gameobject_scripts"); + + // check ids + for (ScriptMapMap::const_iterator itr = sGameObjectScripts.begin(); itr != sGameObjectScripts.end(); ++itr) + { + if (!GetGOData(itr->first)) + sLog.outErrorDb("Table `gameobject_scripts` has not existing gameobject (GUID: %u) as script id",itr->first); + } +} + +void ObjectMgr::LoadQuestEndScripts() +{ + LoadScripts(sQuestEndScripts, "quest_end_scripts"); + + // check ids + for (ScriptMapMap::const_iterator itr = sQuestEndScripts.begin(); itr != sQuestEndScripts.end(); ++itr) + { + if (!GetQuestTemplate(itr->first)) + sLog.outErrorDb("Table `quest_end_scripts` has not existing quest (Id: %u) as script id",itr->first); + } +} + +void ObjectMgr::LoadQuestStartScripts() +{ + LoadScripts(sQuestStartScripts,"quest_start_scripts"); + + // check ids + for (ScriptMapMap::const_iterator itr = sQuestStartScripts.begin(); itr != sQuestStartScripts.end(); ++itr) + { + if (!GetQuestTemplate(itr->first)) + sLog.outErrorDb("Table `quest_start_scripts` has not existing quest (Id: %u) as script id",itr->first); + } +} + +void ObjectMgr::LoadSpellScripts() +{ + LoadScripts(sSpellScripts, "spell_scripts"); + + // check ids + for (ScriptMapMap::const_iterator itr = sSpellScripts.begin(); itr != sSpellScripts.end(); ++itr) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first); + + if (!spellInfo) + { + sLog.outErrorDb("Table `spell_scripts` has not existing spell (Id: %u) as script id",itr->first); + continue; + } + + //check for correct spellEffect + bool found = false; + for (uint8 i=0; i<3; ++i) + { + // skip empty effects + if (!spellInfo->Effect[i]) + continue; + + if (spellInfo->Effect[i] == SPELL_EFFECT_SCRIPT_EFFECT) + { + found = true; + break; + } + } + + if (!found) + sLog.outErrorDb("Table `spell_scripts` has unsupported spell (Id: %u) without SPELL_EFFECT_SCRIPT_EFFECT (%u) spell effect",itr->first,SPELL_EFFECT_SCRIPT_EFFECT); + } +} + +void ObjectMgr::LoadEventScripts() +{ + LoadScripts(sEventScripts, "event_scripts"); + + std::set evt_scripts; + // Load all possible script entries from gameobjects + for (uint32 i = 1; i < sGOStorage.MaxEntry; ++i) + { + GameObjectInfo const * goInfo = sGOStorage.LookupEntry(i); + if (goInfo) + { + switch(goInfo->type) + { + case GAMEOBJECT_TYPE_GOOBER: + if (goInfo->goober.eventId) + evt_scripts.insert(goInfo->goober.eventId); + break; + case GAMEOBJECT_TYPE_CHEST: + if (goInfo->chest.eventId) + evt_scripts.insert(goInfo->chest.eventId); + break; + case GAMEOBJECT_TYPE_CAMERA: + if (goInfo->camera.eventID) + evt_scripts.insert(goInfo->camera.eventID); + default: + break; + } + } + } + // Load all possible script entries from spells + for (uint32 i = 1; i < sSpellStore.GetNumRows(); ++i) + { + SpellEntry const * spell = sSpellStore.LookupEntry(i); + if (spell) + { + for (uint8 j=0; j<3; ++j) + { + if (spell->Effect[j] == SPELL_EFFECT_SEND_EVENT) + { + if (spell->EffectMiscValue[j]) + evt_scripts.insert(spell->EffectMiscValue[j]); + } + } + } + } + + // Then check if all scripts are in above list of possible script entries + for (ScriptMapMap::const_iterator itr = sEventScripts.begin(); itr != sEventScripts.end(); ++itr) + { + std::set::const_iterator itr2 = evt_scripts.find(itr->first); + if (itr2 == evt_scripts.end()) + sLog.outErrorDb("Table `event_scripts` has script (Id: %u) not referring to any gameobject_template type 10 data2 field, type 3 data6 field, type 13 data 2 field or any spell effect %u", + itr->first, SPELL_EFFECT_SEND_EVENT); + } +} + +//Load WP Scripts +void ObjectMgr::LoadWaypointScripts() +{ + LoadScripts(sWaypointScripts, "waypoint_scripts"); + + for (ScriptMapMap::const_iterator itr = sWaypointScripts.begin(); itr != sWaypointScripts.end(); ++itr) + { + QueryResult_AutoPtr query = WorldDatabase.PQuery("SELECT * FROM waypoint_scripts WHERE id = %u", itr->first); + if (!query || !query->GetRowCount()) + sLog.outErrorDb("There is no waypoint which links to the waypoint script %u", itr->first); + } +} + +void ObjectMgr::LoadGossipScripts() +{ + LoadScripts(sGossipScripts, "gossip_scripts"); + + // checks are done in LoadGossipMenuItems +} + +void ObjectMgr::LoadPageTexts() +{ + sPageTextStore.Free(); // for reload case + + sPageTextStore.Load(); + sLog.outString(">> Loaded %u page texts", sPageTextStore.RecordCount); + sLog.outString(); + + for (uint32 i = 1; i < sPageTextStore.MaxEntry; ++i) + { + // check data correctness + PageText const* page = sPageTextStore.LookupEntry(i); + if (!page) + continue; + + if (page->Next_Page && !sPageTextStore.LookupEntry(page->Next_Page)) + { + sLog.outErrorDb("Page text (Id: %u) has not existing next page (Id:%u)", i,page->Next_Page); + continue; + } + + // detect circular reference + std::set checkedPages; + for (PageText const* pageItr = page; pageItr; pageItr = sPageTextStore.LookupEntry(pageItr->Next_Page)) + { + if (!pageItr->Next_Page) + break; + checkedPages.insert(pageItr->Page_ID); + if (checkedPages.find(pageItr->Next_Page)!= checkedPages.end()) + { + std::ostringstream ss; + ss << "The text page(s) "; + for (std::set::iterator itr= checkedPages.begin(); itr != checkedPages.end(); ++itr) + ss << *itr << " "; + ss << "create(s) a circular reference, which can cause the server to freeze. Changing Next_Page of page " + << pageItr->Page_ID <<" to 0"; + sLog.outErrorDb(ss.str().c_str()); + const_cast(pageItr)->Next_Page = 0; + break; + } + } + } +} + +void ObjectMgr::LoadPageTextLocales() +{ + mPageTextLocaleMap.clear(); // need for reload case + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry,text_loc1,text_loc2,text_loc3,text_loc4,text_loc5,text_loc6,text_loc7,text_loc8 FROM locales_page_text"); + + if (!result) + return; + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + + PageTextLocale& data = mPageTextLocaleMap[entry]; + + for (uint8 i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[i].GetCppString(); + if (str.empty()) + continue; + + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.Text.size() <= idx) + data.Text.resize(idx+1); + + data.Text[idx] = str; + } + } + + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %lu PageText locale strings", (unsigned long)mPageTextLocaleMap.size()); +} + +struct SQLInstanceLoader : public SQLStorageLoaderBase +{ + template + void convert_from_str(uint32 /*field_pos*/, char *src, D &dst) + { + dst = D(objmgr.GetScriptId(src)); + } +}; + +void ObjectMgr::LoadInstanceTemplate() +{ + SQLInstanceLoader loader; + loader.Load(sInstanceTemplate); + + for (uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++) + { + InstanceTemplate* temp = (InstanceTemplate*)GetInstanceTemplate(i); + if (!temp) + continue; + + if (!MapManager::IsValidMAP(temp->map)) + sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", temp->map); + + if (!MapManager::IsValidMapCoord(temp->parent,temp->startLocX,temp->startLocY,temp->startLocZ,temp->startLocO)) + { + sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad parent entrance coordinates for map id %d template!", temp->map); + temp->parent = 0; // will have wrong continent 0 parent, at least existed + } + } + + sLog.outString(">> Loaded %u Instance Template definitions", sInstanceTemplate.RecordCount); + sLog.outString(); +} + +GossipText const *ObjectMgr::GetGossipText(uint32 Text_ID) const +{ + GossipTextMap::const_iterator itr = mGossipText.find(Text_ID); + if (itr != mGossipText.end()) + return &itr->second; + return NULL; +} + +void ObjectMgr::LoadGossipText() +{ + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT * FROM npc_text"); + + int count = 0; + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u npc texts", count); + return; + } + + int cic; + + barGoLink bar(result->GetRowCount()); + + do + { + ++count; + cic = 0; + + Field *fields = result->Fetch(); + + bar.step(); + + uint32 Text_ID = fields[cic++].GetUInt32(); + if (!Text_ID) + { + sLog.outErrorDb("Table `npc_text` has record wit reserved id 0, ignore."); + continue; + } + + GossipText& gText = mGossipText[Text_ID]; + + for (int i=0; i< 8; i++) + { + gText.Options[i].Text_0 = fields[cic++].GetCppString(); + gText.Options[i].Text_1 = fields[cic++].GetCppString(); + + gText.Options[i].Language = fields[cic++].GetUInt32(); + gText.Options[i].Probability = fields[cic++].GetFloat(); + + for (uint8 j=0; j < 3; ++j) + { + gText.Options[i].Emotes[j]._Delay = fields[cic++].GetUInt32(); + gText.Options[i].Emotes[j]._Emote = fields[cic++].GetUInt32(); + } + } + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u npc texts", count); +} + +void ObjectMgr::LoadNpcTextLocales() +{ + mNpcTextLocaleMap.clear(); // need for reload case + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry," + "Text0_0_loc1,Text0_1_loc1,Text1_0_loc1,Text1_1_loc1,Text2_0_loc1,Text2_1_loc1,Text3_0_loc1,Text3_1_loc1,Text4_0_loc1,Text4_1_loc1,Text5_0_loc1,Text5_1_loc1,Text6_0_loc1,Text6_1_loc1,Text7_0_loc1,Text7_1_loc1," + "Text0_0_loc2,Text0_1_loc2,Text1_0_loc2,Text1_1_loc2,Text2_0_loc2,Text2_1_loc2,Text3_0_loc2,Text3_1_loc1,Text4_0_loc2,Text4_1_loc2,Text5_0_loc2,Text5_1_loc2,Text6_0_loc2,Text6_1_loc2,Text7_0_loc2,Text7_1_loc2," + "Text0_0_loc3,Text0_1_loc3,Text1_0_loc3,Text1_1_loc3,Text2_0_loc3,Text2_1_loc3,Text3_0_loc3,Text3_1_loc1,Text4_0_loc3,Text4_1_loc3,Text5_0_loc3,Text5_1_loc3,Text6_0_loc3,Text6_1_loc3,Text7_0_loc3,Text7_1_loc3," + "Text0_0_loc4,Text0_1_loc4,Text1_0_loc4,Text1_1_loc4,Text2_0_loc4,Text2_1_loc4,Text3_0_loc4,Text3_1_loc1,Text4_0_loc4,Text4_1_loc4,Text5_0_loc4,Text5_1_loc4,Text6_0_loc4,Text6_1_loc4,Text7_0_loc4,Text7_1_loc4," + "Text0_0_loc5,Text0_1_loc5,Text1_0_loc5,Text1_1_loc5,Text2_0_loc5,Text2_1_loc5,Text3_0_loc5,Text3_1_loc1,Text4_0_loc5,Text4_1_loc5,Text5_0_loc5,Text5_1_loc5,Text6_0_loc5,Text6_1_loc5,Text7_0_loc5,Text7_1_loc5," + "Text0_0_loc6,Text0_1_loc6,Text1_0_loc6,Text1_1_loc6,Text2_0_loc6,Text2_1_loc6,Text3_0_loc6,Text3_1_loc1,Text4_0_loc6,Text4_1_loc6,Text5_0_loc6,Text5_1_loc6,Text6_0_loc6,Text6_1_loc6,Text7_0_loc6,Text7_1_loc6," + "Text0_0_loc7,Text0_1_loc7,Text1_0_loc7,Text1_1_loc7,Text2_0_loc7,Text2_1_loc7,Text3_0_loc7,Text3_1_loc1,Text4_0_loc7,Text4_1_loc7,Text5_0_loc7,Text5_1_loc7,Text6_0_loc7,Text6_1_loc7,Text7_0_loc7,Text7_1_loc7, " + "Text0_0_loc8,Text0_1_loc8,Text1_0_loc8,Text1_1_loc8,Text2_0_loc8,Text2_1_loc8,Text3_0_loc8,Text3_1_loc1,Text4_0_loc8,Text4_1_loc8,Text5_0_loc8,Text5_1_loc8,Text6_0_loc8,Text6_1_loc8,Text7_0_loc8,Text7_1_loc8 " + " FROM locales_npc_text"); + + if (!result) + return; + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + + NpcTextLocale& data = mNpcTextLocaleMap[entry]; + + for (uint8 i=1; i= 0) + { + if (data.Text_0[j].size() <= idx) + data.Text_0[j].resize(idx+1); + + data.Text_0[j][idx] = str0; + } + } + std::string str1 = fields[1+8*2*(i-1)+2*j+1].GetCppString(); + if (!str1.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.Text_1[j].size() <= idx) + data.Text_1[j].resize(idx+1); + + data.Text_1[j][idx] = str1; + } + } + } + } + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %lu NpcText locale strings", (unsigned long)mNpcTextLocaleMap.size()); +} + +//not very fast function but it is called only once a day, or on starting-up +void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp) +{ + time_t basetime = time(NULL); + sLog.outDebug("Returning mails current time: hour: %d, minute: %d, second: %d ", localtime(&basetime)->tm_hour, localtime(&basetime)->tm_min, localtime(&basetime)->tm_sec); + //delete all old mails without item and without body immediately, if starting server + if (!serverUp) + CharacterDatabase.PExecute("DELETE FROM mail WHERE expire_time < '" UI64FMTD "' AND has_items = '0' AND body = ''", (uint64)basetime); + // 0 1 2 3 4 5 6 7 8 9 + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT id,messageType,sender,receiver,has_items,expire_time,cod,checked,mailTemplateId FROM mail WHERE expire_time < '" UI64FMTD "'", (uint64)basetime); + if (!result) + { + barGoLink bar(1); + bar.step(); + sLog.outString(); + sLog.outString(">> Only expired mails (need to be return or delete) or DB table `mail` is empty."); + return; // any mails need to be returned or deleted + } + + //std::ostringstream delitems, delmails; //will be here for optimization + //bool deletemail = false, deleteitem = false; + //delitems << "DELETE FROM item_instance WHERE guid IN ("; + //delmails << "DELETE FROM mail WHERE id IN (" + + barGoLink bar(result->GetRowCount()); + uint32 count = 0; + Field *fields; + + do + { + bar.step(); + + fields = result->Fetch(); + Mail *m = new Mail; + m->messageID = fields[0].GetUInt32(); + m->messageType = fields[1].GetUInt8(); + m->sender = fields[2].GetUInt32(); + m->receiver = fields[3].GetUInt32(); + bool has_items = fields[4].GetBool(); + m->expire_time = (time_t)fields[5].GetUInt64(); + m->deliver_time = 0; + m->COD = fields[6].GetUInt32(); + m->checked = fields[7].GetUInt32(); + m->mailTemplateId = fields[8].GetInt16(); + + Player *pl = 0; + if (serverUp) + pl = GetPlayer((uint64)m->receiver); + if (pl && pl->m_mailsLoaded) + { //this code will run very improbably (the time is between 4 and 5 am, in game is online a player, who has old mail + //his in mailbox and he has already listed his mails) + delete m; + continue; + } + //delete or return mail: + if (has_items) + { + QueryResult_AutoPtr resultItems = CharacterDatabase.PQuery("SELECT item_guid,item_template FROM mail_items WHERE mail_id='%u'", m->messageID); + if (resultItems) + { + do + { + Field *fields2 = resultItems->Fetch(); + + uint32 item_guid_low = fields2[0].GetUInt32(); + uint32 item_template = fields2[1].GetUInt32(); + + m->AddItem(item_guid_low, item_template); + } + while (resultItems->NextRow()); + } + //if it is mail from AH, it shouldn't be returned, but deleted + if (m->messageType != MAIL_NORMAL || m->messageType == MAIL_AUCTION || (m->checked & (MAIL_CHECK_MASK_COD_PAYMENT | MAIL_CHECK_MASK_RETURNED))) + { + // mail open and then not returned + for (std::vector::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2) + CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", itr2->item_guid); + } + else + { + //mail will be returned: + CharacterDatabase.PExecute("UPDATE mail SET sender = '%u', receiver = '%u', expire_time = '" UI64FMTD "', deliver_time = '" UI64FMTD "',cod = '0', checked = '%u' WHERE id = '%u'", m->receiver, m->sender, (uint64)(basetime + 30*DAY), (uint64)basetime, MAIL_CHECK_MASK_RETURNED, m->messageID); + delete m; + continue; + } + } + + //deletemail = true; + //delmails << m->messageID << ", "; + CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", m->messageID); + delete m; + ++count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u mails", count); +} + +void ObjectMgr::LoadQuestAreaTriggers() +{ + mQuestAreaTriggerMap.clear(); // need for reload case + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id,quest FROM areatrigger_involvedrelation"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u quest trigger points", count); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + ++count; + bar.step(); + + Field *fields = result->Fetch(); + + uint32 trigger_ID = fields[0].GetUInt32(); + uint32 quest_ID = fields[1].GetUInt32(); + + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(trigger_ID); + if (!atEntry) + { + sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",trigger_ID); + continue; + } + + Quest const* quest = GetQuestTemplate(quest_ID); + + if (!quest) + { + sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not existing quest %u",trigger_ID,quest_ID); + continue; + } + + if (!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT)) + { + sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not quest %u, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Trigger or quest flags must be fixed, quest modified to require objective.",trigger_ID,quest_ID); + + // this will prevent quest completing without objective + const_cast(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT); + + // continue; - quest modified to required objective and trigger can be allowed. + } + + mQuestAreaTriggerMap[trigger_ID] = quest_ID; + + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u quest trigger points", count); +} + +void ObjectMgr::LoadTavernAreaTriggers() +{ + mTavernAreaTriggerSet.clear(); // need for reload case + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id FROM areatrigger_tavern"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u tavern triggers", count); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + ++count; + bar.step(); + + Field *fields = result->Fetch(); + + uint32 Trigger_ID = fields[0].GetUInt32(); + + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); + if (!atEntry) + { + sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID); + continue; + } + + mTavernAreaTriggerSet.insert(Trigger_ID); + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u tavern triggers", count); +} + +void ObjectMgr::LoadAreaTriggerScripts() +{ + mAreaTriggerScripts.clear(); // need for reload case + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, ScriptName FROM areatrigger_scripts"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u areatrigger scripts", count); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + ++count; + bar.step(); + + Field *fields = result->Fetch(); + + uint32 Trigger_ID = fields[0].GetUInt32(); + const char *scriptName = fields[1].GetString(); + + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); + if (!atEntry) + { + sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID); + continue; + } + mAreaTriggerScripts[Trigger_ID] = GetScriptId(scriptName); + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u areatrigger scripts", count); +} + +uint32 ObjectMgr::GetNearestTaxiNode(float x, float y, float z, uint32 mapid, uint32 team) +{ + bool found = false; + float dist = 10000; + uint32 id = 0; + + for (uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i) + { + TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i); + + if (!node || node->map_id != mapid || !node->MountCreatureID[team == ALLIANCE ? 1 : 0] && node->MountCreatureID[0] != 32981) // dk flight + continue; + + uint8 field = (uint8)((i - 1) / 32); + uint32 submask = 1<<((i-1)%32); + + // skip not taxi network nodes + if ((sTaxiNodesMask[field] & submask) == 0) + continue; + + float dist2 = (node->x - x)*(node->x - x)+(node->y - y)*(node->y - y)+(node->z - z)*(node->z - z); + if (found) + { + if (dist2 < dist) + { + dist = dist2; + id = i; + } + } + else + { + found = true; + dist = dist2; + id = i; + } + } + + return id; +} + +void ObjectMgr::GetTaxiPath(uint32 source, uint32 destination, uint32 &path, uint32 &cost) +{ + TaxiPathSetBySource::iterator src_i = sTaxiPathSetBySource.find(source); + if (src_i == sTaxiPathSetBySource.end()) + { + path = 0; + cost = 0; + return; + } + + TaxiPathSetForSource& pathSet = src_i->second; + + TaxiPathSetForSource::iterator dest_i = pathSet.find(destination); + if (dest_i == pathSet.end()) + { + path = 0; + cost = 0; + return; + } + + cost = dest_i->second.price; + path = dest_i->second.ID; +} + +uint32 ObjectMgr::GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt_team /* = false */) +{ + uint32 mount_entry = 0; + uint32 mount_id = 0; + + // select mount creature id + TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id); + if (node) + { + if (team == ALLIANCE) + mount_entry = node->MountCreatureID[1]; + else + mount_entry = node->MountCreatureID[0]; + + // Fix for Alliance not being able to use Acherus taxi + // only one mount type for both sides + if (mount_entry == 0 && allowed_alt_team) + { + // Simply reverse the selection. At least one team in theory should have a valid mount ID to choose. + mount_entry = team == ALLIANCE ? node->MountCreatureID[0] : node->MountCreatureID[1]; + } + + CreatureInfo const *mount_info = GetCreatureTemplate(mount_entry); + if (mount_info) + { + mount_id = mount_info->GetRandomValidModelId(); + if (!mount_id) + { + sLog.outErrorDb("No displayid found for the taxi mount with the entry %u! Can't load it!", mount_entry); + return false; + } + } + } + + CreatureModelInfo const *minfo = objmgr.GetCreatureModelRandomGender(mount_id); + if (minfo) + mount_id = minfo->modelid; + + return mount_id; +} + +void ObjectMgr::GetTaxiPathNodes(uint32 path, Path &pathnodes, std::vector& mapIds) +{ + if (path >= sTaxiPathNodesByPath.size()) + return; + + TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path]; + + pathnodes.Resize(nodeList.size()); + mapIds.resize(nodeList.size()); + + for (size_t i = 0; i < nodeList.size(); ++i) + { + pathnodes[ i ].x = nodeList[i].x; + pathnodes[ i ].y = nodeList[i].y; + pathnodes[ i ].z = nodeList[i].z; + + mapIds[i] = nodeList[i].mapid; + } +} + +void ObjectMgr::GetTransportPathNodes(uint32 path, TransportPath &pathnodes) +{ + if (path >= sTaxiPathNodesByPath.size()) + return; + + TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path]; + + pathnodes.Resize(nodeList.size()); + + for (size_t i = 0; i < nodeList.size(); ++i) + { + pathnodes[ i ].mapid = nodeList[i].mapid; + pathnodes[ i ].x = nodeList[i].x; + pathnodes[ i ].y = nodeList[i].y; + pathnodes[ i ].z = nodeList[i].z; + pathnodes[ i ].actionFlag = nodeList[i].actionFlag; + pathnodes[ i ].delay = nodeList[i].delay; + } +} + +void ObjectMgr::LoadGraveyardZones() +{ + mGraveYardMap.clear(); // need for reload case + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id,ghost_zone,faction FROM game_graveyard_zone"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u graveyard-zone links", count); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + ++count; + bar.step(); + + Field *fields = result->Fetch(); + + uint32 safeLocId = fields[0].GetUInt32(); + uint32 zoneId = fields[1].GetUInt32(); + uint32 team = fields[2].GetUInt32(); + + WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(safeLocId); + if (!entry) + { + sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",safeLocId); + continue; + } + + AreaTableEntry const *areaEntry = GetAreaEntryByAreaID(zoneId); + if (!areaEntry) + { + sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing zone id (%u), skipped.",zoneId); + continue; + } + + if (areaEntry->zone != 0) + { + sLog.outErrorDb("Table `game_graveyard_zone` has record subzone id (%u) instead of zone, skipped.",zoneId); + continue; + } + + if (team != 0 && team != HORDE && team != ALLIANCE) + { + sLog.outErrorDb("Table `game_graveyard_zone` has record for non player faction (%u), skipped.",team); + continue; + } + + if (!AddGraveYardLink(safeLocId,zoneId,team,false)) + sLog.outErrorDb("Table `game_graveyard_zone` has a duplicate record for Graveyard (ID: %u) and Zone (ID: %u), skipped.",safeLocId,zoneId); + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u graveyard-zone links", count); +} + +WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team) +{ + // search for zone associated closest graveyard + uint32 zoneId = MapManager::Instance().GetZoneId(MapId,x,y,z); + + // Simulate std. algorithm: + // found some graveyard associated to (ghost_zone,ghost_map) + // + // if mapId == graveyard.mapId (ghost in plain zone or city or battleground) and search graveyard at same map + // then check faction + // if mapId != graveyard.mapId (ghost in instance) and search any graveyard associated + // then check faction + GraveYardMap::const_iterator graveLow = mGraveYardMap.lower_bound(zoneId); + GraveYardMap::const_iterator graveUp = mGraveYardMap.upper_bound(zoneId); + MapEntry const* map = sMapStore.LookupEntry(MapId); + // not need to check validity of map object; MapId _MUST_ be valid here + + if (graveLow == graveUp && !map->IsBattleArena()) + { + //sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team); + return NULL; + } + + // at corpse map + bool foundNear = false; + float distNear = 10000; + WorldSafeLocsEntry const* entryNear = NULL; + + // at entrance map for corpse map + bool foundEntr = false; + float distEntr = 10000; + WorldSafeLocsEntry const* entryEntr = NULL; + + // some where other + WorldSafeLocsEntry const* entryFar = NULL; + + MapEntry const* mapEntry = sMapStore.LookupEntry(MapId); + + for (GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr) + { + GraveYardData const& data = itr->second; + + WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(data.safeLocId); + if (!entry) + { + sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",data.safeLocId); + continue; + } + + // skip enemy faction graveyard + // team == 0 case can be at call from .neargrave + if (data.team != 0 && team != 0 && data.team != team) + continue; + + // find now nearest graveyard at other map + if (MapId != entry->map_id) + { + // if find graveyard at different map from where entrance placed (or no entrance data), use any first + if (!mapEntry || + mapEntry->entrance_map < 0 || + uint32(mapEntry->entrance_map) != entry->map_id || + (mapEntry->entrance_x == 0 && mapEntry->entrance_y == 0)) + { + // not have any corrdinates for check distance anyway + entryFar = entry; + continue; + } + + // at entrance map calculate distance (2D); + float dist2 = (entry->x - mapEntry->entrance_x)*(entry->x - mapEntry->entrance_x) + +(entry->y - mapEntry->entrance_y)*(entry->y - mapEntry->entrance_y); + if (foundEntr) + { + if (dist2 < distEntr) + { + distEntr = dist2; + entryEntr = entry; + } + } + else + { + foundEntr = true; + distEntr = dist2; + entryEntr = entry; + } + } + // find now nearest graveyard at same map + else + { + float dist2 = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y)+(entry->z - z)*(entry->z - z); + if (foundNear) + { + if (dist2 < distNear) + { + distNear = dist2; + entryNear = entry; + } + } + else + { + foundNear = true; + distNear = dist2; + entryNear = entry; + } + } + } + + if (entryNear) + return entryNear; + + if (entryEntr) + return entryEntr; + + return entryFar; +} + +GraveYardData const* ObjectMgr::FindGraveYardData(uint32 id, uint32 zoneId) +{ + GraveYardMap::const_iterator graveLow = mGraveYardMap.lower_bound(zoneId); + GraveYardMap::const_iterator graveUp = mGraveYardMap.upper_bound(zoneId); + + for (GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr) + { + if (itr->second.safeLocId == id) + return &itr->second; + } + + return NULL; +} + +bool ObjectMgr::AddGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inDB) +{ + if (FindGraveYardData(id,zoneId)) + return false; + + // add link to loaded data + GraveYardData data; + data.safeLocId = id; + data.team = team; + + mGraveYardMap.insert(GraveYardMap::value_type(zoneId,data)); + + // add link to DB + if (inDB) + { + WorldDatabase.PExecuteLog("INSERT INTO game_graveyard_zone (id,ghost_zone,faction) " + "VALUES ('%u', '%u','%u')",id,zoneId,team); + } + + return true; +} + +void ObjectMgr::RemoveGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inDB) +{ + GraveYardMap::iterator graveLow = mGraveYardMap.lower_bound(zoneId); + GraveYardMap::iterator graveUp = mGraveYardMap.upper_bound(zoneId); + if (graveLow == graveUp) + { + //sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team); + return; + } + + bool found = false; + + GraveYardMap::iterator itr; + + for (itr = graveLow; itr != graveUp; ++itr) + { + GraveYardData & data = itr->second; + + // skip not matching safezone id + if (data.safeLocId != id) + continue; + + // skip enemy faction graveyard at same map (normal area, city, or battleground) + // team == 0 case can be at call from .neargrave + if (data.team != 0 && team != 0 && data.team != team) + continue; + + found = true; + break; + } + + // no match, return + if (!found) + return; + + // remove from links + mGraveYardMap.erase(itr); + + // remove link from DB + if (inDB) + { + WorldDatabase.PExecute("DELETE FROM game_graveyard_zone WHERE id = '%u' AND ghost_zone = '%u' AND faction = '%u'",id,zoneId,team); + } + + return; +} + +void ObjectMgr::LoadAreaTriggerTeleports() +{ + mAreaTriggers.clear(); // need for reload case + + uint32 count = 0; + + // 0 1 2 3 4 5 6 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id, access_id, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport"); + if (!result) + { + + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u area trigger teleport definitions", count); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + + bar.step(); + + ++count; + + uint32 Trigger_ID = fields[0].GetUInt32(); + + AreaTrigger at; + + at.access_id = fields[1].GetUInt32(); + at.target_mapId = fields[2].GetUInt32(); + at.target_X = fields[3].GetFloat(); + at.target_Y = fields[4].GetFloat(); + at.target_Z = fields[5].GetFloat(); + at.target_Orientation = fields[6].GetFloat(); + + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); + if (!atEntry) + { + sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID); + continue; + } + + MapEntry const* mapEntry = sMapStore.LookupEntry(at.target_mapId); + if (!mapEntry) + { + sLog.outErrorDb("Area trigger (ID:%u) target map (ID: %u) does not exist in `Map.dbc`.",Trigger_ID,at.target_mapId); + continue; + } + + if (at.target_X == 0 && at.target_Y == 0 && at.target_Z == 0) + { + sLog.outErrorDb("Area trigger (ID:%u) target coordinates not provided.",Trigger_ID); + continue; + } + + mAreaTriggers[Trigger_ID] = at; + + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u area trigger teleport definitions", count); +} + +void ObjectMgr::LoadAccessRequirements() +{ + mAccessRequirements.clear(); // need for reload case + + uint32 count = 0; + + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id, level_min, level_max, item, item2, heroic_key, heroic_key2, quest_done, quest_failed_text, heroic_quest_done, heroic_quest_failed_text, heroic_level_min, status FROM access_requirement"); + if (!result) + { + + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u access requirement definitions", count); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + + bar.step(); + + ++count; + + uint32 requiremt_ID = fields[0].GetUInt32(); + + AccessRequirement ar; + + ar.levelMin = fields[1].GetUInt8(); + ar.levelMax = fields[2].GetUInt8(); + ar.heroicLevelMin = fields[11].GetUInt8(); + ar.item = fields[3].GetUInt32(); + ar.item2 = fields[4].GetUInt32(); + ar.heroicKey = fields[5].GetUInt32(); + ar.heroicKey2 = fields[6].GetUInt32(); + ar.quest = fields[7].GetUInt32(); + ar.questFailedText = fields[8].GetCppString(); + ar.heroicQuest = fields[9].GetUInt32(); + ar.heroicQuestFailedText = fields[10].GetCppString(); + ar.status = fields[12].GetUInt8(); + + if (ar.item) + { + ItemPrototype const *pProto = GetItemPrototype(ar.item); + if (!pProto) + { + sLog.outError("Key item %u does not exist for requirement %u, removing key requirement.", ar.item, requiremt_ID); + ar.item = 0; + } + } + + if (ar.item2) + { + ItemPrototype const *pProto = GetItemPrototype(ar.item2); + if (!pProto) + { + sLog.outError("Second item %u does not exist for requirement %u, removing key requirement.", ar.item2, requiremt_ID); + ar.item2 = 0; + } + } + + if (ar.heroicKey) + { + ItemPrototype const *pProto = GetItemPrototype(ar.heroicKey); + if (!pProto) + { + sLog.outError("Heroic key %u not exist for trigger %u, remove key requirement.", ar.heroicKey, requiremt_ID); + ar.heroicKey = 0; + } + } + + if (ar.heroicKey2) + { + ItemPrototype const *pProto = GetItemPrototype(ar.heroicKey2); + if (!pProto) + { + sLog.outError("Second heroic key %u not exist for trigger %u, remove key requirement.", ar.heroicKey2, requiremt_ID); + ar.heroicKey2 = 0; + } + } + + if (ar.heroicQuest) + { + QuestMap::iterator qReqItr = mQuestTemplates.find(ar.heroicQuest); + if (qReqItr == mQuestTemplates.end()) + { + sLog.outErrorDb("Required Heroic Quest %u not exist for trigger %u, remove heroic quest done requirement.",ar.heroicQuest,requiremt_ID); + ar.heroicQuest = 0; + } + } + + if (ar.quest) + { + QuestMap::iterator qReqItr = mQuestTemplates.find(ar.quest); + if (qReqItr == mQuestTemplates.end()) + { + sLog.outErrorDb("Required Quest %u not exist for trigger %u, remove quest done requirement.",ar.quest,requiremt_ID); + ar.quest = 0; + } + } + + mAccessRequirements[requiremt_ID] = ar; + + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u access requirement definitions", count); +} + +/* + * Searches for the areatrigger which teleports players out of the given map with instance_template.parent field support + */ +AreaTrigger const* ObjectMgr::GetGoBackTrigger(uint32 Map) const +{ + bool useParentDbValue = false; + uint32 parentId = 0; + const MapEntry *mapEntry = sMapStore.LookupEntry(Map); + if (!mapEntry || mapEntry->entrance_map < 0) + return NULL; + + if (mapEntry->IsDungeon()) + { + const InstanceTemplate *iTemplate = objmgr.GetInstanceTemplate(Map); + + if (!iTemplate) + return NULL; + + parentId = iTemplate->parent; + useParentDbValue = true; + } + + uint32 entrance_map = uint32(mapEntry->entrance_map); + for (AreaTriggerMap::const_iterator itr = mAreaTriggers.begin(); itr != mAreaTriggers.end(); ++itr) + if ((!useParentDbValue && itr->second.target_mapId == entrance_map) || (useParentDbValue && itr->second.target_mapId == parentId)) + { + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(itr->first); + if (atEntry && atEntry->mapid == Map) + return &itr->second; + } + return NULL; +} + +/** + * Searches for the areatrigger which teleports players to the given map + */ +AreaTrigger const* ObjectMgr::GetMapEntranceTrigger(uint32 Map) const +{ + for (AreaTriggerMap::const_iterator itr = mAreaTriggers.begin(); itr != mAreaTriggers.end(); ++itr) + { + if (itr->second.target_mapId == Map) + { + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(itr->first); + if (atEntry) + return &itr->second; + } + } + return NULL; +} + +void ObjectMgr::SetHighestGuids() +{ + QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT MAX(guid) FROM characters"); + if (result) + m_hiCharGuid = (*result)[0].GetUInt32()+1; + + result = WorldDatabase.Query("SELECT MAX(guid) FROM creature"); + if (result) + m_hiCreatureGuid = (*result)[0].GetUInt32()+1; + + result = CharacterDatabase.Query("SELECT MAX(guid) FROM item_instance"); + if (result) + m_hiItemGuid = (*result)[0].GetUInt32()+1; + + // Cleanup other tables from not existed guids ( >= m_hiItemGuid) + CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item >= '%u'", m_hiItemGuid); + CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid >= '%u'", m_hiItemGuid); + CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE itemguid >= '%u'", m_hiItemGuid); + CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE item_guid >= '%u'", m_hiItemGuid); + + result = WorldDatabase.Query("SELECT MAX(guid) FROM gameobject"); + if (result) + m_hiGoGuid = (*result)[0].GetUInt32()+1; + + result = CharacterDatabase.Query("SELECT MAX(id) FROM auctionhouse"); + if (result) + m_auctionid = (*result)[0].GetUInt32()+1; + + result = CharacterDatabase.Query("SELECT MAX(id) FROM mail"); + if (result) + m_mailid = (*result)[0].GetUInt32()+1; + + result = CharacterDatabase.Query("SELECT MAX(guid) FROM corpse"); + if (result) + m_hiCorpseGuid = (*result)[0].GetUInt32()+1; + + result = CharacterDatabase.Query("SELECT MAX(arenateamid) FROM arena_team"); + if (result) + m_arenaTeamId = (*result)[0].GetUInt32()+1; + + result = CharacterDatabase.Query("SELECT MAX(setguid) FROM character_equipmentsets"); + if (result) + m_equipmentSetGuid = (*result)[0].GetUInt64()+1; + + result = CharacterDatabase.Query("SELECT MAX(guildid) FROM guild"); + if (result) + m_guildId = (*result)[0].GetUInt32()+1; + + result = CharacterDatabase.Query("SELECT MAX(guid) FROM groups"); + if (result) + m_hiGroupGuid = (*result)[0].GetUInt32()+1; +} + +uint32 ObjectMgr::GenerateArenaTeamId() +{ + if (m_arenaTeamId >= 0xFFFFFFFE) + { + sLog.outError("Arena team ids overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_arenaTeamId++; +} + +uint32 ObjectMgr::GenerateAuctionID() +{ + if (m_auctionid >= 0xFFFFFFFE) + { + sLog.outError("Auctions ids overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_auctionid++; +} + +uint64 ObjectMgr::GenerateEquipmentSetGuid() +{ + if (m_equipmentSetGuid >= 0xFFFFFFFFFFFFFFFEll) + { + sLog.outError("EquipmentSet guid overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_equipmentSetGuid++; +} + +uint32 ObjectMgr::GenerateGuildId() +{ + if (m_guildId >= 0xFFFFFFFE) + { + sLog.outError("Guild ids overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_guildId++; +} + +uint32 ObjectMgr::GenerateMailID() +{ + if (m_mailid >= 0xFFFFFFFE) + { + sLog.outError("Mail ids overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_mailid++; +} + +uint32 ObjectMgr::GenerateLowGuid(HighGuid guidhigh) +{ + switch(guidhigh) + { + case HIGHGUID_ITEM: + if (m_hiItemGuid >= 0xFFFFFFFE) + { + sLog.outError("Item guid overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_hiItemGuid++; + case HIGHGUID_UNIT: + if (m_hiCreatureGuid >= 0x00FFFFFE) + { + sLog.outError("Creature guid overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_hiCreatureGuid++; + case HIGHGUID_PET: + if (m_hiPetGuid >= 0x00FFFFFE) + { + sLog.outError("Pet guid overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_hiPetGuid++; + case HIGHGUID_VEHICLE: + if (m_hiVehicleGuid >= 0x00FFFFFF) + { + sLog.outError("Vehicle guid overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_hiVehicleGuid++; + case HIGHGUID_PLAYER: + if (m_hiCharGuid >= 0xFFFFFFFE) + { + sLog.outError("Players guid overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_hiCharGuid++; + case HIGHGUID_GAMEOBJECT: + if (m_hiGoGuid >= 0x00FFFFFE) + { + sLog.outError("Gameobject guid overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_hiGoGuid++; + case HIGHGUID_CORPSE: + if (m_hiCorpseGuid >= 0xFFFFFFFE) + { + sLog.outError("Corpse guid overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_hiCorpseGuid++; + case HIGHGUID_DYNAMICOBJECT: + if (m_hiDoGuid >= 0xFFFFFFFE) + { + sLog.outError("DynamicObject guid overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_hiDoGuid++; + case HIGHGUID_GROUP: + if (m_hiGroupGuid >= 0xFFFFFFFE) + { + sLog.outError("Group guid overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_hiGroupGuid++; + default: + ASSERT(0); + } + + ASSERT(0); + return 0; +} + +void ObjectMgr::LoadGameObjectLocales() +{ + mGameObjectLocaleMap.clear(); // need for reload case + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry," + "name_loc1,name_loc2,name_loc3,name_loc4,name_loc5,name_loc6,name_loc7,name_loc8," + "castbarcaption_loc1,castbarcaption_loc2,castbarcaption_loc3,castbarcaption_loc4," + "castbarcaption_loc5,castbarcaption_loc6,castbarcaption_loc7,castbarcaption_loc8 FROM locales_gameobject"); + + if (!result) + return; + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + + GameObjectLocale& data = mGameObjectLocaleMap[entry]; + + for (uint8 i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[i].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.Name.size() <= idx) + data.Name.resize(idx+1); + + data.Name[idx] = str; + } + } + } + + for (uint8 i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[i+(MAX_LOCALE-1)].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + if (data.CastBarCaption.size() <= idx) + data.CastBarCaption.resize(idx+1); + + data.CastBarCaption[idx] = str; + } + } + } + + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %lu gameobject locale strings", (unsigned long)mGameObjectLocaleMap.size()); +} + +struct SQLGameObjectLoader : public SQLStorageLoaderBase +{ + template + void convert_from_str(uint32 /*field_pos*/, char *src, D &dst) + { + dst = D(objmgr.GetScriptId(src)); + } +}; + +inline void CheckGOLockId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) +{ + if (sLockStore.LookupEntry(dataN)) + return; + + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but lock (Id: %u) not found.", + goInfo->id,goInfo->type,N,goInfo->door.lockId,goInfo->door.lockId); +} + +inline void CheckGOLinkedTrapId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) +{ + if (GameObjectInfo const* trapInfo = sGOStorage.LookupEntry(dataN)) + { + if (trapInfo->type != GAMEOBJECT_TYPE_TRAP) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.", + goInfo->id,goInfo->type,N,dataN,dataN,GAMEOBJECT_TYPE_TRAP); + } + /* disable check for while (too many error reports baout not existed in trap templates + else + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but trap GO (Entry %u) not exist in `gameobject_template`.", + goInfo->id,goInfo->type,N,dataN,dataN); + */ +} + +inline void CheckGOSpellId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) +{ + if (sSpellStore.LookupEntry(dataN)) + return; + + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but Spell (Entry %u) not exist.", + goInfo->id,goInfo->type,N,dataN,dataN); +} + +inline void CheckAndFixGOChairHeightId(GameObjectInfo const* goInfo,uint32 const& dataN,uint32 N) +{ + if (dataN <= (UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR)) + return; + + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but correct chair height in range 0..%i.", + goInfo->id,goInfo->type,N,dataN,UNIT_STAND_STATE_SIT_HIGH_CHAIR-UNIT_STAND_STATE_SIT_LOW_CHAIR); + + // prevent client and server unexpected work + const_cast(dataN) = 0; +} + +inline void CheckGONoDamageImmuneId(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) +{ + // 0/1 correct values + if (dataN <= 1) + return; + + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but expected boolean (0/1) noDamageImmune field value.", + goInfo->id,goInfo->type,N,dataN); +} + +inline void CheckGOConsumable(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) +{ + // 0/1 correct values + if (dataN <= 1) + return; + + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but expected boolean (0/1) consumable field value.", + goInfo->id,goInfo->type,N,dataN); +} + +void ObjectMgr::LoadGameobjectInfo() +{ + SQLGameObjectLoader loader; + loader.Load(sGOStorage); + + // some checks + for (uint32 id = 1; id < sGOStorage.MaxEntry; id++) + { + GameObjectInfo const* goInfo = sGOStorage.LookupEntry(id); + if (!goInfo) + continue; + + // some GO types have unused go template, check goInfo->displayId at GO spawn data loading or ignore + + switch(goInfo->type) + { + case GAMEOBJECT_TYPE_DOOR: //0 + { + if (goInfo->door.lockId) + CheckGOLockId(goInfo,goInfo->door.lockId,1); + CheckGONoDamageImmuneId(goInfo,goInfo->door.noDamageImmune,3); + break; + } + case GAMEOBJECT_TYPE_BUTTON: //1 + { + if (goInfo->button.lockId) + CheckGOLockId(goInfo,goInfo->button.lockId,1); + CheckGONoDamageImmuneId(goInfo,goInfo->button.noDamageImmune,4); + break; + } + case GAMEOBJECT_TYPE_QUESTGIVER: //2 + { + if (goInfo->questgiver.lockId) + CheckGOLockId(goInfo,goInfo->questgiver.lockId,0); + CheckGONoDamageImmuneId(goInfo,goInfo->questgiver.noDamageImmune,5); + break; + } + case GAMEOBJECT_TYPE_CHEST: //3 + { + if (goInfo->chest.lockId) + CheckGOLockId(goInfo,goInfo->chest.lockId,0); + + CheckGOConsumable(goInfo,goInfo->chest.consumable,3); + + if (goInfo->chest.linkedTrapId) // linked trap + CheckGOLinkedTrapId(goInfo,goInfo->chest.linkedTrapId,7); + break; + } + case GAMEOBJECT_TYPE_TRAP: //6 + { + if (goInfo->trap.lockId) + CheckGOLockId(goInfo,goInfo->trap.lockId,0); + /* disable check for while, too many not existed spells + if (goInfo->trap.spellId) // spell + CheckGOSpellId(goInfo,goInfo->trap.spellId,3); + */ + break; + } + case GAMEOBJECT_TYPE_CHAIR: //7 + CheckAndFixGOChairHeightId(goInfo,goInfo->chair.height,1); + break; + case GAMEOBJECT_TYPE_SPELL_FOCUS: //8 + { + if (goInfo->spellFocus.focusId) + { + if (!sSpellFocusObjectStore.LookupEntry(goInfo->spellFocus.focusId)) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but SpellFocus (Id: %u) not exist.", + id,goInfo->type,goInfo->spellFocus.focusId,goInfo->spellFocus.focusId); + } + + if (goInfo->spellFocus.linkedTrapId) // linked trap + CheckGOLinkedTrapId(goInfo,goInfo->spellFocus.linkedTrapId,2); + break; + } + case GAMEOBJECT_TYPE_GOOBER: //10 + { + if (goInfo->goober.lockId) + CheckGOLockId(goInfo,goInfo->goober.lockId,0); + + CheckGOConsumable(goInfo,goInfo->goober.consumable,3); + + if (goInfo->goober.pageId) // pageId + { + if (!sPageTextStore.LookupEntry(goInfo->goober.pageId)) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but PageText (Entry %u) not exist.", + id,goInfo->type,goInfo->goober.pageId,goInfo->goober.pageId); + } + /* disable check for while, too many not existed spells + if (goInfo->goober.spellId) // spell + CheckGOSpellId(goInfo,goInfo->goober.spellId,10); + */ + CheckGONoDamageImmuneId(goInfo,goInfo->goober.noDamageImmune,11); + if (goInfo->goober.linkedTrapId) // linked trap + CheckGOLinkedTrapId(goInfo,goInfo->goober.linkedTrapId,12); + break; + } + case GAMEOBJECT_TYPE_AREADAMAGE: //12 + { + if (goInfo->areadamage.lockId) + CheckGOLockId(goInfo,goInfo->areadamage.lockId,0); + break; + } + case GAMEOBJECT_TYPE_CAMERA: //13 + { + if (goInfo->camera.lockId) + CheckGOLockId(goInfo,goInfo->camera.lockId,0); + break; + } + case GAMEOBJECT_TYPE_MO_TRANSPORT: //15 + { + if (goInfo->moTransport.taxiPathId) + { + if (goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[goInfo->moTransport.taxiPathId].empty()) + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.", + id,goInfo->type,goInfo->moTransport.taxiPathId,goInfo->moTransport.taxiPathId); + } + break; + } + case GAMEOBJECT_TYPE_SUMMONING_RITUAL: //18 + { + /* disable check for while, too many not existed spells + // always must have spell + CheckGOSpellId(goInfo,goInfo->summoningRitual.spellId,1); + */ + break; + } + case GAMEOBJECT_TYPE_SPELLCASTER: //22 + { + // always must have spell + CheckGOSpellId(goInfo,goInfo->spellcaster.spellId,0); + break; + } + case GAMEOBJECT_TYPE_FLAGSTAND: //24 + { + if (goInfo->flagstand.lockId) + CheckGOLockId(goInfo,goInfo->flagstand.lockId,0); + CheckGONoDamageImmuneId(goInfo,goInfo->flagstand.noDamageImmune,5); + break; + } + case GAMEOBJECT_TYPE_FISHINGHOLE: //25 + { + if (goInfo->fishinghole.lockId) + CheckGOLockId(goInfo,goInfo->fishinghole.lockId,4); + break; + } + case GAMEOBJECT_TYPE_FLAGDROP: //26 + { + if (goInfo->flagdrop.lockId) + CheckGOLockId(goInfo,goInfo->flagdrop.lockId,0); + CheckGONoDamageImmuneId(goInfo,goInfo->flagdrop.noDamageImmune,3); + break; + } + case GAMEOBJECT_TYPE_BARBER_CHAIR: //32 + CheckAndFixGOChairHeightId(goInfo,goInfo->barberChair.chairheight,0); + break; + } + } + + sLog.outString(">> Loaded %u game object templates", sGOStorage.RecordCount); + sLog.outString(); +} + +void ObjectMgr::LoadExplorationBaseXP() +{ + uint32 count = 0; + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT level,basexp FROM exploration_basexp"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u BaseXP definitions", count); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + uint8 level = fields[0].GetUInt8(); + uint32 basexp = fields[1].GetUInt32(); + mBaseXPTable[level] = basexp; + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u BaseXP definitions", count); +} + +uint32 ObjectMgr::GetBaseXP(uint8 level) +{ + return mBaseXPTable[level] ? mBaseXPTable[level] : 0; +} + +uint32 ObjectMgr::GetXPForLevel(uint8 level) +{ + if (level < mPlayerXPperLevel.size()) + return mPlayerXPperLevel[level]; + return 0; +} + +void ObjectMgr::LoadPetNames() +{ + uint32 count = 0; + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT word,entry,half FROM pet_name_generation"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u pet name parts", count); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + std::string word = fields[0].GetString(); + uint32 entry = fields[1].GetUInt32(); + bool half = fields[2].GetBool(); + if (half) + PetHalfName1[entry].push_back(word); + else + PetHalfName0[entry].push_back(word); + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u pet name parts", count); +} + +void ObjectMgr::LoadPetNumber() +{ + QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT MAX(id) FROM character_pet"); + if (result) + { + Field *fields = result->Fetch(); + m_hiPetNumber = fields[0].GetUInt32()+1; + } + + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded the max pet number: %d", m_hiPetNumber-1); +} + +std::string ObjectMgr::GeneratePetName(uint32 entry) +{ + std::vector & list0 = PetHalfName0[entry]; + std::vector & list1 = PetHalfName1[entry]; + + if (list0.empty() || list1.empty()) + { + CreatureInfo const *cinfo = GetCreatureTemplate(entry); + char* petname = GetPetName(cinfo->family, sWorld.GetDefaultDbcLocale()); + if (!petname) + petname = cinfo->Name; + return std::string(petname); + } + + return *(list0.begin()+urand(0, list0.size()-1)) + *(list1.begin()+urand(0, list1.size()-1)); +} + +uint32 ObjectMgr::GeneratePetNumber() +{ + return ++m_hiPetNumber; +} + +void ObjectMgr::LoadCorpses() +{ + uint32 count = 0; + // 0 1 2 3 4 5 6 7 8 9 10 + QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT position_x, position_y, position_z, orientation, map, data, time, corpse_type, instance, phaseMask, guid FROM corpse WHERE corpse_type <> 0"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u corpses", count); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + + uint32 guid = fields[result->GetFieldCount()-1].GetUInt32(); + + Corpse *corpse = new Corpse; + if (!corpse->LoadFromDB(guid,fields)) + { + delete corpse; + continue; + } + + ObjectAccessor::Instance().AddCorpse(corpse); + + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u corpses", count); +} + +void ObjectMgr::LoadReputationOnKill() +{ + uint32 count = 0; + + // 0 1 2 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT creature_id, RewOnKillRepFaction1, RewOnKillRepFaction2," + // 3 4 5 6 7 8 9 + "IsTeamAward1, MaxStanding1, RewOnKillRepValue1, IsTeamAward2, MaxStanding2, RewOnKillRepValue2, TeamDependent " + "FROM creature_onkill_reputation"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 creature award reputation definitions. DB table `creature_onkill_reputation` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 creature_id = fields[0].GetUInt32(); + + ReputationOnKillEntry repOnKill; + repOnKill.repfaction1 = fields[1].GetUInt32(); + repOnKill.repfaction2 = fields[2].GetUInt32(); + repOnKill.is_teamaward1 = fields[3].GetBool(); + repOnKill.reputation_max_cap1 = fields[4].GetUInt32(); + repOnKill.repvalue1 = fields[5].GetInt32(); + repOnKill.is_teamaward2 = fields[6].GetBool(); + repOnKill.reputation_max_cap2 = fields[7].GetUInt32(); + repOnKill.repvalue2 = fields[8].GetInt32(); + repOnKill.team_dependent = fields[9].GetUInt8(); + + if (!GetCreatureTemplate(creature_id)) + { + sLog.outErrorDb("Table `creature_onkill_reputation` have data for not existed creature entry (%u), skipped",creature_id); + continue; + } + + if (repOnKill.repfaction1) + { + FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(repOnKill.repfaction1); + if (!factionEntry1) + { + sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction1); + continue; + } + } + + if (repOnKill.repfaction2) + { + FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(repOnKill.repfaction2); + if (!factionEntry2) + { + sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction2); + continue; + } + } + + mRepOnKill[creature_id] = repOnKill; + + ++count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u creature award reputation definitions", count); +} + +void ObjectMgr::LoadPointsOfInterest() +{ + uint32 count = 0; + + // 0 1 2 3 4 5 6 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, x, y, icon, flags, data, icon_name FROM points_of_interest"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 Points of Interest definitions. DB table `points_of_interest` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 point_id = fields[0].GetUInt32(); + + PointOfInterest POI; + POI.x = fields[1].GetFloat(); + POI.y = fields[2].GetFloat(); + POI.icon = fields[3].GetUInt32(); + POI.flags = fields[4].GetUInt32(); + POI.data = fields[5].GetUInt32(); + POI.icon_name = fields[6].GetCppString(); + + if (!Trinity::IsValidMapCoord(POI.x,POI.y)) + { + sLog.outErrorDb("Table `points_of_interest` (Entry: %u) have invalid coordinates (X: %f Y: %f), ignored.",point_id,POI.x,POI.y); + continue; + } + + mPointsOfInterest[point_id] = POI; + + ++count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u Points of Interest definitions", count); +} + +void ObjectMgr::LoadQuestPOI() +{ + uint32 count = 0; + + // 0 1 2 3 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT questId, id, objIndex, mapid, WorldMapAreaId, FloorId, unk3, unk4 FROM quest_poi order by questId"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 quest POI definitions. DB table `quest_poi` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 questId = fields[0].GetUInt32(); + uint32 id = fields[1].GetUInt32(); + int32 objIndex = fields[2].GetInt32(); + uint32 mapId = fields[3].GetUInt32(); + uint32 WorldMapAreaId = fields[4].GetUInt32(); + uint32 FloorId = fields[5].GetUInt32(); + uint32 unk3 = fields[6].GetUInt32(); + uint32 unk4 = fields[7].GetUInt32(); + + QuestPOI POI(id, objIndex, mapId, WorldMapAreaId, FloorId, unk3, unk4); + + QueryResult_AutoPtr points = WorldDatabase.PQuery("SELECT x, y FROM quest_poi_points WHERE questId='%u' AND id='%i'", questId, id); + + if (points) + { + do + { + Field *pointFields = points->Fetch(); + int32 x = pointFields[0].GetInt32(); + int32 y = pointFields[1].GetInt32(); + QuestPOIPoint point(x, y); + POI.points.push_back(point); + } while (points->NextRow()); + } + + mQuestPOIMap[questId].push_back(POI); + + ++count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u quest POI definitions", count); +} + +void ObjectMgr::LoadNPCSpellClickSpells() +{ + uint32 count = 0; + + mSpellClickInfoMap.clear(); + // 0 1 2 3 4 5 6 7 8 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT npc_entry, spell_id, quest_start, quest_start_active, quest_end, cast_flags, aura_required, aura_forbidden, user_type FROM npc_spellclick_spells"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 spellclick spells. DB table `npc_spellclick_spells` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 npc_entry = fields[0].GetUInt32(); + CreatureInfo const* cInfo = GetCreatureTemplate(npc_entry); + if (!cInfo) + { + sLog.outErrorDb("Table npc_spellclick_spells references unknown creature_template %u. Skipping entry.", npc_entry); + continue; + } + + if (!(cInfo->npcflag & UNIT_NPC_FLAG_SPELLCLICK)) + const_cast(cInfo)->npcflag |= UNIT_NPC_FLAG_SPELLCLICK; + + uint32 spellid = fields[1].GetUInt32(); + SpellEntry const *spellinfo = sSpellStore.LookupEntry(spellid); + if (!spellinfo) + { + sLog.outErrorDb("Table npc_spellclick_spells references unknown spellid %u. Skipping entry.", spellid); + continue; + } + + uint32 auraRequired = fields[6].GetUInt32(); + if (auraRequired) + { + SpellEntry const *aurReqInfo = sSpellStore.LookupEntry(auraRequired); + if (!aurReqInfo) + { + sLog.outErrorDb("Table npc_spellclick_spells references unknown aura required %u. Skipping entry.", auraRequired); + continue; + } + } + + uint32 auraForbidden = fields[7].GetUInt32(); + if (auraForbidden) + { + SpellEntry const *aurForInfo = sSpellStore.LookupEntry(auraForbidden); + if (!aurForInfo) + { + sLog.outErrorDb("Table npc_spellclick_spells references unknown aura forbidden %u. Skipping entry.", auraForbidden); + continue; + } + } + + uint32 quest_start = fields[2].GetUInt32(); + + // quest might be 0 to enable spellclick independent of any quest + if (quest_start) + { + if (mQuestTemplates.find(quest_start) == mQuestTemplates.end()) + { + sLog.outErrorDb("Table npc_spellclick_spells references unknown start quest %u. Skipping entry.", quest_start); + continue; + } + } + + bool quest_start_active = fields[3].GetBool(); + + uint32 quest_end = fields[4].GetUInt32(); + // quest might be 0 to enable spellclick active infinity after start quest + if (quest_end) + { + if (mQuestTemplates.find(quest_end) == mQuestTemplates.end()) + { + sLog.outErrorDb("Table npc_spellclick_spells references unknown end quest %u. Skipping entry.", quest_end); + continue; + } + } + + uint8 userType = fields[8].GetUInt8(); + if (userType >= SPELL_CLICK_USER_MAX) + sLog.outErrorDb("Table npc_spellclick_spells references unknown user type %u. Skipping entry.", uint32(userType)); + + uint8 castFlags = fields[5].GetUInt8(); + SpellClickInfo info; + info.spellId = spellid; + info.questStart = quest_start; + info.questStartCanActive = quest_start_active; + info.questEnd = quest_end; + info.castFlags = castFlags; + info.auraRequired = auraRequired; + info.auraForbidden = auraForbidden; + info.userType = SpellClickUserTypes(userType); + mSpellClickInfoMap.insert(SpellClickInfoMap::value_type(npc_entry, info)); + + // mark creature template as spell clickable + const_cast(cInfo)->npcflag |= UNIT_NPC_FLAG_SPELLCLICK; + + ++count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u spellclick definitions", count); +} + +void ObjectMgr::LoadWeatherZoneChances() +{ + uint32 count = 0; + + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT zone, spring_rain_chance, spring_snow_chance, spring_storm_chance, summer_rain_chance, summer_snow_chance, summer_storm_chance, fall_rain_chance, fall_snow_chance, fall_storm_chance, winter_rain_chance, winter_snow_chance, winter_storm_chance FROM game_weather"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 weather definitions. DB table `game_weather` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 zone_id = fields[0].GetUInt32(); + + WeatherZoneChances& wzc = mWeatherZoneMap[zone_id]; + + for (uint8 season = 0; season < WEATHER_SEASONS; ++season) + { + wzc.data[season].rainChance = fields[season * (MAX_WEATHER_TYPE-1) + 1].GetUInt32(); + wzc.data[season].snowChance = fields[season * (MAX_WEATHER_TYPE-1) + 2].GetUInt32(); + wzc.data[season].stormChance = fields[season * (MAX_WEATHER_TYPE-1) + 3].GetUInt32(); + + if (wzc.data[season].rainChance > 100) + { + wzc.data[season].rainChance = 25; + sLog.outErrorDb("Weather for zone %u season %u has wrong rain chance > 100%%",zone_id,season); + } + + if (wzc.data[season].snowChance > 100) + { + wzc.data[season].snowChance = 25; + sLog.outErrorDb("Weather for zone %u season %u has wrong snow chance > 100%%",zone_id,season); + } + + if (wzc.data[season].stormChance > 100) + { + wzc.data[season].stormChance = 25; + sLog.outErrorDb("Weather for zone %u season %u has wrong storm chance > 100%%",zone_id,season); + } + } + + ++count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u weather definitions", count); +} + +void ObjectMgr::SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t) +{ + mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = t; + WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance); + if (t) + WorldDatabase.PExecute("INSERT INTO creature_respawn VALUES ('%u', '" UI64FMTD "', '%u')", loguid, uint64(t), instance); +} + +void ObjectMgr::DeleteCreatureData(uint32 guid) +{ + // remove mapid*cellid -> guid_set map + CreatureData const* data = GetCreatureData(guid); + if (data) + RemoveCreatureFromGrid(guid, data); + + mCreatureDataMap.erase(guid); +} + +void ObjectMgr::SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t) +{ + mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = t; + WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance); + if (t) + WorldDatabase.PExecute("INSERT INTO gameobject_respawn VALUES ('%u', '" UI64FMTD "', '%u')", loguid, uint64(t), instance); +} + +void ObjectMgr::DeleteRespawnTimeForInstance(uint32 instance) +{ + RespawnTimes::iterator next; + + for (RespawnTimes::iterator itr = mGORespawnTimes.begin(); itr != mGORespawnTimes.end(); itr = next) + { + next = itr; + ++next; + + if (GUID_HIPART(itr->first) == instance) + mGORespawnTimes.erase(itr); + } + + for (RespawnTimes::iterator itr = mCreatureRespawnTimes.begin(); itr != mCreatureRespawnTimes.end(); itr = next) + { + next = itr; + ++next; + + if (GUID_HIPART(itr->first) == instance) + mCreatureRespawnTimes.erase(itr); + } + + WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'", instance); + WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'", instance); +} + +void ObjectMgr::DeleteGOData(uint32 guid) +{ + // remove mapid*cellid -> guid_set map + GameObjectData const* data = GetGOData(guid); + if (data) + RemoveGameobjectFromGrid(guid, data); + + mGameObjectDataMap.erase(guid); +} + +void ObjectMgr::AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance) +{ + // corpses are always added to spawn mode 0 and they are spawned by their instance id + CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid]; + cell_guids.corpses[player_guid] = instance; +} + +void ObjectMgr::DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid) +{ + // corpses are always added to spawn mode 0 and they are spawned by their instance id + CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid]; + cell_guids.corpses.erase(player_guid); +} + +void ObjectMgr::LoadQuestRelationsHelper(QuestRelations& map,char const* table) +{ + map.clear(); // need for reload case + + uint32 count = 0; + + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT id,quest FROM %s",table); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 quest relations from %s. DB table `%s` is empty.",table,table); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 id = fields[0].GetUInt32(); + uint32 quest = fields[1].GetUInt32(); + + if (mQuestTemplates.find(quest) == mQuestTemplates.end()) + { + sLog.outErrorDb("Table `%s: Quest %u listed for entry %u does not exist.",table,quest,id); + continue; + } + + map.insert(QuestRelations::value_type(id,quest)); + + ++count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u quest relations from %s", count,table); +} + +void ObjectMgr::LoadGameobjectQuestRelations() +{ + LoadQuestRelationsHelper(mGOQuestRelations,"gameobject_questrelation"); + + for (QuestRelations::iterator itr = mGOQuestRelations.begin(); itr != mGOQuestRelations.end(); ++itr) + { + GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first); + if (!goInfo) + sLog.outErrorDb("Table `gameobject_questrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second); + else if (goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER) + sLog.outErrorDb("Table `gameobject_questrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second); + } +} + +void ObjectMgr::LoadGameobjectInvolvedRelations() +{ + LoadQuestRelationsHelper(mGOQuestInvolvedRelations,"gameobject_involvedrelation"); + + for (QuestRelations::iterator itr = mGOQuestInvolvedRelations.begin(); itr != mGOQuestInvolvedRelations.end(); ++itr) + { + GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first); + if (!goInfo) + sLog.outErrorDb("Table `gameobject_involvedrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second); + else if (goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER) + sLog.outErrorDb("Table `gameobject_involvedrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second); + } +} + +void ObjectMgr::LoadCreatureQuestRelations() +{ + LoadQuestRelationsHelper(mCreatureQuestRelations,"creature_questrelation"); + + for (QuestRelations::iterator itr = mCreatureQuestRelations.begin(); itr != mCreatureQuestRelations.end(); ++itr) + { + CreatureInfo const* cInfo = GetCreatureTemplate(itr->first); + if (!cInfo) + sLog.outErrorDb("Table `creature_questrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second); + else if (!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER)) + sLog.outErrorDb("Table `creature_questrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER",itr->first,itr->second); + } +} + +void ObjectMgr::LoadCreatureInvolvedRelations() +{ + LoadQuestRelationsHelper(mCreatureQuestInvolvedRelations,"creature_involvedrelation"); + + for (QuestRelations::iterator itr = mCreatureQuestInvolvedRelations.begin(); itr != mCreatureQuestInvolvedRelations.end(); ++itr) + { + CreatureInfo const* cInfo = GetCreatureTemplate(itr->first); + if (!cInfo) + sLog.outErrorDb("Table `creature_involvedrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second); + else if (!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER)) + sLog.outErrorDb("Table `creature_involvedrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER",itr->first,itr->second); + } +} + +void ObjectMgr::LoadReservedPlayersNames() +{ + m_ReservedNames.clear(); // need for reload case + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT name FROM reserved_name"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u reserved player names", count); + return; + } + + barGoLink bar(result->GetRowCount()); + + Field* fields; + do + { + bar.step(); + fields = result->Fetch(); + std::string name= fields[0].GetCppString(); + + std::wstring wstr; + if (!Utf8toWStr (name,wstr)) + { + sLog.outError("Table `reserved_name` have invalid name: %s", name.c_str()); + continue; + } + + wstrToLower(wstr); + + m_ReservedNames.insert(wstr); + ++count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u reserved player names", count); +} + +bool ObjectMgr::IsReservedName(const std::string& name) const +{ + std::wstring wstr; + if (!Utf8toWStr (name,wstr)) + return false; + + wstrToLower(wstr); + + return m_ReservedNames.find(wstr) != m_ReservedNames.end(); +} + +enum LanguageType +{ + LT_BASIC_LATIN = 0x0000, + LT_EXTENDEN_LATIN = 0x0001, + LT_CYRILLIC = 0x0002, + LT_EAST_ASIA = 0x0004, + LT_ANY = 0xFFFF +}; + +static LanguageType GetRealmLanguageType(bool create) +{ + switch(sWorld.getConfig(CONFIG_REALM_ZONE)) + { + case REALM_ZONE_UNKNOWN: // any language + case REALM_ZONE_DEVELOPMENT: + case REALM_ZONE_TEST_SERVER: + case REALM_ZONE_QA_SERVER: + return LT_ANY; + case REALM_ZONE_UNITED_STATES: // extended-Latin + case REALM_ZONE_OCEANIC: + case REALM_ZONE_LATIN_AMERICA: + case REALM_ZONE_ENGLISH: + case REALM_ZONE_GERMAN: + case REALM_ZONE_FRENCH: + case REALM_ZONE_SPANISH: + return LT_EXTENDEN_LATIN; + case REALM_ZONE_KOREA: // East-Asian + case REALM_ZONE_TAIWAN: + case REALM_ZONE_CHINA: + return LT_EAST_ASIA; + case REALM_ZONE_RUSSIAN: // Cyrillic + return LT_CYRILLIC; + default: + return create ? LT_BASIC_LATIN : LT_ANY; // basic-Latin at create, any at login + } +} + +bool isValidString(std::wstring wstr, uint32 strictMask, bool numericOrSpace, bool create = false) +{ + if (strictMask == 0) // any language, ignore realm + { + if (isExtendedLatinString(wstr,numericOrSpace)) + return true; + if (isCyrillicString(wstr,numericOrSpace)) + return true; + if (isEastAsianString(wstr,numericOrSpace)) + return true; + return false; + } + + if (strictMask & 0x2) // realm zone specific + { + LanguageType lt = GetRealmLanguageType(create); + if (lt & LT_EXTENDEN_LATIN) + if (isExtendedLatinString(wstr,numericOrSpace)) + return true; + if (lt & LT_CYRILLIC) + if (isCyrillicString(wstr,numericOrSpace)) + return true; + if (lt & LT_EAST_ASIA) + if (isEastAsianString(wstr,numericOrSpace)) + return true; + } + + if (strictMask & 0x1) // basic Latin + { + if (isBasicLatinString(wstr,numericOrSpace)) + return true; + } + + return false; +} + +uint8 ObjectMgr::CheckPlayerName(const std::string& name, bool create) +{ + std::wstring wname; + if (!Utf8toWStr(name,wname)) + return CHAR_NAME_INVALID_CHARACTER; + + if (wname.size() > MAX_PLAYER_NAME) + return CHAR_NAME_TOO_LONG; + + uint32 minName = sWorld.getConfig(CONFIG_MIN_PLAYER_NAME); + if (wname.size() < minName) + return CHAR_NAME_TOO_SHORT; + + uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PLAYER_NAMES); + if (!isValidString(wname,strictMask,false,create)) + return CHAR_NAME_MIXED_LANGUAGES; + + return CHAR_NAME_SUCCESS; +} + +bool ObjectMgr::IsValidCharterName(const std::string& name) +{ + std::wstring wname; + if (!Utf8toWStr(name,wname)) + return false; + + if (wname.size() > MAX_CHARTER_NAME) + return false; + + uint32 minName = sWorld.getConfig(CONFIG_MIN_CHARTER_NAME); + if (wname.size() < minName) + return false; + + uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_CHARTER_NAMES); + + return isValidString(wname,strictMask,true); +} + +PetNameInvalidReason ObjectMgr::CheckPetName(const std::string& name) +{ + std::wstring wname; + if (!Utf8toWStr(name,wname)) + return PET_NAME_INVALID; + + if (wname.size() > MAX_PET_NAME) + return PET_NAME_TOO_LONG; + + uint32 minName = sWorld.getConfig(CONFIG_MIN_PET_NAME); + if (wname.size() < minName) + return PET_NAME_TOO_SHORT; + + uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PET_NAMES); + if (!isValidString(wname,strictMask,false)) + return PET_NAME_MIXED_LANGUAGES; + + return PET_NAME_SUCCESS; +} + +int ObjectMgr::GetIndexForLocale(LocaleConstant loc) +{ + if (loc == LOCALE_enUS) + return -1; + + for (size_t i=0; i < m_LocalForIndex.size(); ++i) + if (m_LocalForIndex[i] == loc) + return i; + + return -1; +} + +LocaleConstant ObjectMgr::GetLocaleForIndex(int i) +{ + if (i<0 || i >= m_LocalForIndex.size()) + return LOCALE_enUS; + + return m_LocalForIndex[i]; +} + +int ObjectMgr::GetOrNewIndexForLocale(LocaleConstant loc) +{ + if (loc == LOCALE_enUS) + return -1; + + for (size_t i=0; i < m_LocalForIndex.size(); ++i) + if (m_LocalForIndex[i] == loc) + return i; + + m_LocalForIndex.push_back(loc); + return m_LocalForIndex.size()-1; +} + +void ObjectMgr::LoadGameObjectForQuests() +{ + mGameObjectForQuestSet.clear(); // need for reload case + + if (!sGOStorage.MaxEntry) + { + barGoLink bar(1); + bar.step(); + sLog.outString(); + sLog.outString(">> Loaded 0 GameObjects for quests"); + return; + } + + barGoLink bar(sGOStorage.MaxEntry - 1); + uint32 count = 0; + + // collect GO entries for GO that must activated + for (uint32 go_entry = 1; go_entry < sGOStorage.MaxEntry; ++go_entry) + { + bar.step(); + GameObjectInfo const* goInfo = sGOStorage.LookupEntry(go_entry); + if (!goInfo) + continue; + + switch(goInfo->type) + { + // scan GO chest with loot including quest items + case GAMEOBJECT_TYPE_CHEST: + { + uint32 loot_id = goInfo->GetLootId(); + + // find quest loot for GO + if (LootTemplates_Gameobject.HaveQuestLootFor(loot_id)) + { + mGameObjectForQuestSet.insert(go_entry); + ++count; + } + break; + } + case GAMEOBJECT_TYPE_GOOBER: + { + if (goInfo->goober.questId) //quests objects + { + mGameObjectForQuestSet.insert(go_entry); + count++; + } + break; + } + default: + break; + } + } + + sLog.outString(); + sLog.outString(">> Loaded %u GameObjects for quests", count); +} + +bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value) +{ + int32 start_value = min_value; + int32 end_value = max_value; + // some string can have negative indexes range + if (start_value < 0) + { + if (end_value >= start_value) + { + sLog.outErrorDb("Table '%s' attempt loaded with invalid range (%d - %d), strings not loaded.",table,min_value,max_value); + return false; + } + + // real range (max+1,min+1) exaple: (-10,-1000) -> -999...-10+1 + std::swap(start_value,end_value); + ++start_value; + ++end_value; + } + else + { + if (start_value >= end_value) + { + sLog.outErrorDb("Table '%s' attempt loaded with invalid range (%d - %d), strings not loaded.",table,min_value,max_value); + return false; + } + } + + // cleanup affected map part for reloading case + for (TrinityStringLocaleMap::iterator itr = mTrinityStringLocaleMap.begin(); itr != mTrinityStringLocaleMap.end();) + { + if (itr->first >= start_value && itr->first < end_value) + mTrinityStringLocaleMap.erase(itr++); + else + ++itr; + } + + QueryResult_AutoPtr result = db.PQuery("SELECT entry,content_default,content_loc1,content_loc2,content_loc3,content_loc4,content_loc5,content_loc6,content_loc7,content_loc8 FROM %s",table); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + if (min_value == MIN_TRINITY_STRING_ID) // error only in case internal strings + sLog.outErrorDb(">> Loaded 0 trinity strings. DB table `%s` is empty. Cannot continue.",table); + else + sLog.outString(">> Loaded 0 string templates. DB table `%s` is empty.",table); + return false; + } + + uint32 count = 0; + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + int32 entry = fields[0].GetInt32(); + + if (entry == 0) + { + sLog.outErrorDb("Table `%s` contain reserved entry 0, ignored.",table); + continue; + } + else if (entry < start_value || entry >= end_value) + { + sLog.outErrorDb("Table `%s` contain entry %i out of allowed range (%d - %d), ignored.",table,entry,min_value,max_value); + continue; + } + + TrinityStringLocale& data = mTrinityStringLocaleMap[entry]; + + if (data.Content.size() > 0) + { + sLog.outErrorDb("Table `%s` contain data for already loaded entry %i (from another table?), ignored.",table,entry); + continue; + } + + data.Content.resize(1); + ++count; + + // 0 -> default, idx in to idx+1 + data.Content[0] = fields[1].GetCppString(); + + for (uint8 i = 1; i < MAX_LOCALE; ++i) + { + std::string str = fields[i+1].GetCppString(); + if (!str.empty()) + { + int idx = GetOrNewIndexForLocale(LocaleConstant(i)); + if (idx >= 0) + { + // 0 -> default, idx in to idx+1 + if (data.Content.size() <= idx+1) + data.Content.resize(idx+2); + + data.Content[idx+1] = str; + } + } + } + } while (result->NextRow()); + + sLog.outString(); + if (min_value == MIN_TRINITY_STRING_ID) + sLog.outString(">> Loaded %u Trinity strings from table %s", count,table); + else + sLog.outString(">> Loaded %u string templates from %s", count,table); + + return true; +} + +const char *ObjectMgr::GetTrinityString(int32 entry, int locale_idx) const +{ + // locale_idx == -1 -> default, locale_idx >= 0 in to idx+1 + // Content[0] always exist if exist TrinityStringLocale + if (TrinityStringLocale const *msl = GetTrinityStringLocale(entry)) + { + if (msl->Content.size() > locale_idx+1 && !msl->Content[locale_idx+1].empty()) + return msl->Content[locale_idx+1].c_str(); + else + return msl->Content[0].c_str(); + } + + if (entry > 0) + sLog.outErrorDb("Entry %i not found in `trinity_string` table.",entry); + else + sLog.outErrorDb("Trinity string entry %i not found in DB.",entry); + return ""; +} + +void ObjectMgr::LoadSpellDisabledEntrys() +{ + m_DisabledPlayerSpells.clear(); // need for reload case + m_DisabledCreatureSpells.clear(); + m_DisabledPetSpells.clear(); + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, disable_mask FROM spell_disabled"); + + uint32 total_count = 0; + + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u disabled spells", total_count); + return; + } + + barGoLink bar(result->GetRowCount()); + + Field* fields; + do + { + bar.step(); + fields = result->Fetch(); + uint32 spellid = fields[0].GetUInt32(); + if (!sSpellStore.LookupEntry(spellid)) + { + sLog.outErrorDb("Spell entry %u from `spell_disabled` doesn't exist in dbc, ignoring.",spellid); + continue; + } + uint32 disable_mask = fields[1].GetUInt32(); + if (disable_mask & SPELL_DISABLE_PLAYER) + m_DisabledPlayerSpells.insert(spellid); + if (disable_mask & SPELL_DISABLE_CREATURE) + m_DisabledCreatureSpells.insert(spellid); + if (disable_mask & SPELL_DISABLE_PET) + m_DisabledPetSpells.insert(spellid); + ++total_count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u disabled spells from `spell_disabled`", total_count); +} + +void ObjectMgr::LoadFishingBaseSkillLevel() +{ + mFishingBaseForArea.clear(); // for reload case + + uint32 count = 0; + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry,skill FROM skill_fishing_base_level"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `skill_fishing_base_level`, table is empty!"); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + uint32 entry = fields[0].GetUInt32(); + int32 skill = fields[1].GetInt32(); + + AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry); + if (!fArea) + { + sLog.outErrorDb("AreaId %u defined in `skill_fishing_base_level` does not exist",entry); + continue; + } + + mFishingBaseForArea[entry] = skill; + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u areas for fishing base skill level", count); +} + +bool ObjectMgr::CheckDeclinedNames(std::wstring mainpart, DeclinedName const& names) +{ + for (uint8 i =0; i < MAX_DECLINED_NAME_CASES; ++i) + { + std::wstring wname; + if (!Utf8toWStr(names.name[i],wname)) + return false; + + if (mainpart != GetMainPartOfName(wname,i+1)) + return false; + } + return true; +} + +uint32 ObjectMgr::GetAreaTriggerScriptId(uint32 trigger_id) +{ + AreaTriggerScriptMap::const_iterator i = mAreaTriggerScripts.find(trigger_id); + if (i!= mAreaTriggerScripts.end()) + return i->second; + return 0; +} + +SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial) +{ + switch(pSkill->categoryId) + { + case SKILL_CATEGORY_LANGUAGES: return SKILL_RANGE_LANGUAGE; + case SKILL_CATEGORY_WEAPON: + if (pSkill->id != SKILL_FIST_WEAPONS) + return SKILL_RANGE_LEVEL; + else + return SKILL_RANGE_MONO; + case SKILL_CATEGORY_ARMOR: + case SKILL_CATEGORY_CLASS: + if (pSkill->id != SKILL_LOCKPICKING) + return SKILL_RANGE_MONO; + else + return SKILL_RANGE_LEVEL; + case SKILL_CATEGORY_SECONDARY: + case SKILL_CATEGORY_PROFESSION: + // not set skills for professions and racial abilities + if (IsProfessionSkill(pSkill->id)) + return SKILL_RANGE_RANK; + else if (racial) + return SKILL_RANGE_NONE; + else + return SKILL_RANGE_MONO; + default: + case SKILL_CATEGORY_ATTRIBUTES: //not found in dbc + case SKILL_CATEGORY_GENERIC: //only GENERIC(DND) + return SKILL_RANGE_NONE; + } +} + +void ObjectMgr::LoadGameTele() +{ + m_GameTeleMap.clear(); // for reload case + + uint32 count = 0; + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT id, position_x, position_y, position_z, orientation, map, name FROM game_tele"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `game_tele`, table is empty!"); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + + uint32 id = fields[0].GetUInt32(); + + GameTele gt; + + gt.position_x = fields[1].GetFloat(); + gt.position_y = fields[2].GetFloat(); + gt.position_z = fields[3].GetFloat(); + gt.orientation = fields[4].GetFloat(); + gt.mapId = fields[5].GetUInt32(); + gt.name = fields[6].GetCppString(); + + if (!MapManager::IsValidMapCoord(gt.mapId,gt.position_x,gt.position_y,gt.position_z,gt.orientation)) + { + sLog.outErrorDb("Wrong position for id %u (name: %s) in `game_tele` table, ignoring.",id,gt.name.c_str()); + continue; + } + + if (!Utf8toWStr(gt.name,gt.wnameLow)) + { + sLog.outErrorDb("Wrong UTF8 name for id %u in `game_tele` table, ignoring.",id); + continue; + } + + wstrToLower(gt.wnameLow); + + m_GameTeleMap[id] = gt; + + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u GameTeleports", count); +} + +GameTele const* ObjectMgr::GetGameTele(const std::string& name) const +{ + // explicit name case + std::wstring wname; + if (!Utf8toWStr(name,wname)) + return false; + + // converting string that we try to find to lower case + wstrToLower(wname); + + // Alternative first GameTele what contains wnameLow as substring in case no GameTele location found + const GameTele* alt = NULL; + for (GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr) + { + if (itr->second.wnameLow == wname) + return &itr->second; + else if (alt == NULL && itr->second.wnameLow.find(wname) != std::wstring::npos) + alt = &itr->second; + } + + return alt; +} + +bool ObjectMgr::AddGameTele(GameTele& tele) +{ + // find max id + uint32 new_id = 0; + for (GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr) + if (itr->first > new_id) + new_id = itr->first; + + // use next + ++new_id; + + if (!Utf8toWStr(tele.name,tele.wnameLow)) + return false; + + wstrToLower(tele.wnameLow); + + m_GameTeleMap[new_id] = tele; + + return WorldDatabase.PExecuteLog("INSERT INTO game_tele (id,position_x,position_y,position_z,orientation,map,name) VALUES (%u,%f,%f,%f,%f,%d,'%s')", + new_id,tele.position_x,tele.position_y,tele.position_z,tele.orientation,tele.mapId,tele.name.c_str()); +} + +bool ObjectMgr::DeleteGameTele(const std::string& name) +{ + // explicit name case + std::wstring wname; + if (!Utf8toWStr(name,wname)) + return false; + + // converting string that we try to find to lower case + wstrToLower(wname); + + for (GameTeleMap::iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr) + { + if (itr->second.wnameLow == wname) + { + WorldDatabase.PExecuteLog("DELETE FROM game_tele WHERE name = '%s'",itr->second.name.c_str()); + m_GameTeleMap.erase(itr); + return true; + } + } + + return false; +} + +void ObjectMgr::LoadMailLevelRewards() +{ + m_mailLevelRewardMap.clear(); // for reload case + + uint32 count = 0; + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT level, raceMask, mailTemplateId, senderEntry FROM mail_level_reward"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `mail_level_reward`, table is empty!"); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + + uint8 level = fields[0].GetUInt8(); + uint32 raceMask = fields[1].GetUInt32(); + uint32 mailTemplateId = fields[2].GetUInt32(); + uint32 senderEntry = fields[3].GetUInt32(); + + if (level > MAX_LEVEL) + { + sLog.outErrorDb("Table `mail_level_reward` have data for level %u that more supported by client (%u), ignoring.",level,MAX_LEVEL); + continue; + } + + if (!(raceMask & RACEMASK_ALL_PLAYABLE)) + { + sLog.outErrorDb("Table `mail_level_reward` have raceMask (%u) for level %u that not include any player races, ignoring.",raceMask,level); + continue; + } + + if (!sMailTemplateStore.LookupEntry(mailTemplateId)) + { + sLog.outErrorDb("Table `mail_level_reward` have invalid mailTemplateId (%u) for level %u that invalid not include any player races, ignoring.",mailTemplateId,level); + continue; + } + + if (!GetCreatureTemplateStore(senderEntry)) + { + sLog.outErrorDb("Table `mail_level_reward` have not existed sender creature entry (%u) for level %u that invalid not include any player races, ignoring.",senderEntry,level); + continue; + } + + m_mailLevelRewardMap[level].push_back(MailLevelReward(raceMask,mailTemplateId,senderEntry)); + + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u level dependent mail rewards,", count); +} + +bool ObjectMgr::AddSpellToTrainer(uint32 entry, uint32 spell, Field *fields, std::set *skip_trainers, std::set *talentIds) +{ + if (entry >= TRINITY_TRAINER_START_REF) + return false; + + CreatureInfo const* cInfo = GetCreatureTemplate(entry); + if (!cInfo) + { + sLog.outErrorDb("Table `npc_trainer` have entry for not existed creature template (Entry: %u), ignore", entry); + return false; + } + + if (!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER)) + { + if (skip_trainers->find(entry) == skip_trainers->end()) + { + sLog.outErrorDb("Table `npc_trainer` have data for not creature template (Entry: %u) without trainer flag, ignore", entry); + skip_trainers->insert(entry); + } + return false; + } + + SpellEntry const *spellinfo = sSpellStore.LookupEntry(spell); + if (!spellinfo) + { + sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u) has non existing spell %u, ignore", entry,spell); + return false; + } + + if (!SpellMgr::IsSpellValid(spellinfo)) + { + sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u) has broken learning spell %u, ignore", entry, spell); + return false; + } + + if (GetTalentSpellCost(spell)) + { + if (talentIds->count(spell) == 0) + { + sLog.outErrorDb("Table `npc_trainer` has talent as learning spell %u, ignore", spell); + talentIds->insert(spell); + } + return false; + } + + TrainerSpellData& data = m_mCacheTrainerSpellMap[entry]; + + TrainerSpell& trainerSpell = data.spellList[spell]; + trainerSpell.spell = spell; + trainerSpell.spellCost = fields[2].GetUInt32(); + trainerSpell.reqSkill = fields[3].GetUInt32(); + trainerSpell.reqSkillValue = fields[4].GetUInt32(); + trainerSpell.reqLevel = fields[5].GetUInt32(); + + if (!trainerSpell.reqLevel) + trainerSpell.reqLevel = spellinfo->spellLevel; + + // calculate learned spell for profession case when stored cast-spell + trainerSpell.learnedSpell[0] = spell; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (spellinfo->Effect[i] != SPELL_EFFECT_LEARN_SPELL) + continue; + if (trainerSpell.learnedSpell[0] == spell) + trainerSpell.learnedSpell[0] = 0; + // player must be able to cast spell on himself + if (spellinfo->EffectImplicitTargetA[i] != 0 && spellinfo->EffectImplicitTargetA[i] != TARGET_UNIT_TARGET_ALLY + && spellinfo->EffectImplicitTargetA[i] != TARGET_UNIT_TARGET_ANY && spellinfo->EffectImplicitTargetA[i] != TARGET_UNIT_CASTER) + { + sLog.outErrorDb("Table `npc_trainer` has spell %u for trainer entry %u with learn effect which has incorrect target type, ignoring learn effect!", spell, entry); + continue; + } + + trainerSpell.learnedSpell[i] = spellinfo->EffectTriggerSpell[i]; + } + + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (!trainerSpell.learnedSpell[i]) + continue; + if (SpellMgr::IsProfessionSpell(trainerSpell.learnedSpell[i])) + { + data.trainerType = 2; + break; + } + } + return true; +} +int ObjectMgr::LoadReferenceTrainer(uint32 trainer, int32 spell, std::set *skip_trainers, std::set *talentIds) +{ + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT entry, spell,spellcost,reqskill,reqskillvalue,reqlevel FROM npc_trainer WHERE entry='%d'", spell); + if (!result) + return 0; + + uint32 count = 0; + do + { + + Field* fields = result->Fetch(); + + int32 spell = fields[1].GetInt32(); + if (spell < 0) + count += this->LoadReferenceTrainer(trainer, -spell, skip_trainers, talentIds); + else if (this->AddSpellToTrainer(trainer, uint32(spell), fields, skip_trainers, talentIds)) + ++count; + } while (result->NextRow()); + + return count; +} + +void ObjectMgr::LoadTrainerSpell() +{ + // For reload case + for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr) + itr->second.Clear(); + m_mCacheTrainerSpellMap.clear(); + + std::set skip_trainers; + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, spell,spellcost,reqskill,reqskillvalue,reqlevel FROM npc_trainer"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `npc_trainer`, table is empty!"); + return; + } + + barGoLink bar(result->GetRowCount()); + + std::set talentIds; + + uint32 count = 0; + do + { + bar.step(); + + Field* fields = result->Fetch(); + + uint32 entry = fields[0].GetUInt32(); + int32 spell = fields[1].GetInt32(); + if (spell < 0) + count += this->LoadReferenceTrainer(entry, -spell, &skip_trainers, &talentIds); + else if (this->AddSpellToTrainer(entry, uint32(spell), fields, &skip_trainers, &talentIds)) + ++count; + + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %d Trainers", count); +} + +int ObjectMgr::LoadReferenceVendor(int32 vendor, int32 item, std::set *skip_vendors) +{ + // find all items from the reference vendor + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT item, maxcount, incrtime, ExtendedCost FROM npc_vendor WHERE entry='%d' ORDER BY slot ASC", item); + if (!result) + return 0; + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + int32 item_id = fields[0].GetInt32(); + + // if item is a negative, its a reference + if (item_id < 0) + count += LoadReferenceVendor(vendor, -item_id, skip_vendors); + else + { + int32 maxcount = fields[1].GetInt32(); + uint32 incrtime = fields[2].GetUInt32(); + uint32 ExtendedCost = fields[3].GetUInt32(); + + if (!IsVendorItemValid(vendor,item_id,maxcount,incrtime,ExtendedCost,NULL,skip_vendors)) + continue; + + VendorItemData& vList = m_mCacheVendorItemMap[vendor]; + + vList.AddItem(item_id,maxcount,incrtime,ExtendedCost); + ++count; + } + + } while (result->NextRow()); + + return count; +} + +void ObjectMgr::LoadVendors() +{ + // For reload case + for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr) + itr->second.Clear(); + m_mCacheVendorItemMap.clear(); + + std::set skip_vendors; + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, item, maxcount, incrtime, ExtendedCost FROM npc_vendor ORDER BY entry, slot ASC"); + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `npc_vendor`, table is empty!"); + return; + } + + barGoLink bar(result->GetRowCount()); + + uint32 count = 0; + do + { + bar.step(); + Field* fields = result->Fetch(); + + uint32 entry = fields[0].GetUInt32(); + int32 item_id = fields[1].GetInt32(); + + // if item is a negative, its a reference + if (item_id < 0) + count += LoadReferenceVendor(entry, -item_id, &skip_vendors); + else + { + int32 maxcount = fields[2].GetInt32(); + uint32 incrtime = fields[3].GetUInt32(); + uint32 ExtendedCost = fields[4].GetUInt32(); + + if (!IsVendorItemValid(entry,item_id,maxcount,incrtime,ExtendedCost,NULL,&skip_vendors)) + continue; + + VendorItemData& vList = m_mCacheVendorItemMap[entry]; + + vList.AddItem(item_id,maxcount,incrtime,ExtendedCost); + ++count; + } + + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %d Vendors ", count); +} + +void ObjectMgr::LoadNpcTextId() +{ + + m_mCacheNpcTextIdMap.clear(); + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT npc_guid, textid FROM npc_gossip"); + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `npc_gossip`, table is empty!"); + return; + } + + barGoLink bar(result->GetRowCount()); + + uint32 count = 0; + uint32 guid,textid; + do + { + bar.step(); + + Field* fields = result->Fetch(); + + guid = fields[0].GetUInt32(); + textid = fields[1].GetUInt32(); + + if (!GetCreatureData(guid)) + { + sLog.outErrorDb("Table `npc_gossip` have not existed creature (GUID: %u) entry, ignore. ",guid); + continue; + } + if (!GetGossipText(textid)) + { + sLog.outErrorDb("Table `npc_gossip` for creature (GUID: %u) have wrong Textid (%u), ignore. ", guid, textid); + continue; + } + + m_mCacheNpcTextIdMap[guid] = textid ; + ++count; + + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %d NpcTextId ", count); +} + +void ObjectMgr::LoadGossipMenu() +{ + m_mGossipMenusMap.clear(); + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, text_id FROM gossip_menu"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded `gossip_menu`, table is empty!"); + return; + } + + barGoLink bar(result->GetRowCount()); + + uint32 count = 0; + + do + { + bar.step(); + + Field* fields = result->Fetch(); + + GossipMenus gMenu; + + gMenu.entry = fields[0].GetUInt32(); + gMenu.text_id = fields[1].GetUInt32(); + + if (!GetGossipText(gMenu.text_id)) + { + sLog.outErrorDb("Table gossip_menu entry %u are using non-existing text_id %u", gMenu.entry, gMenu.text_id); + continue; + } + + m_mGossipMenusMap.insert(GossipMenusMap::value_type(gMenu.entry, gMenu)); + + ++count; + } + while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u gossip_menu entries", count); +} + +void ObjectMgr::LoadGossipMenuItems() +{ + m_mGossipMenuItemsMap.clear(); + + QueryResult_AutoPtr result = WorldDatabase.Query( + "SELECT menu_id, id, option_icon, option_text, option_id, npc_option_npcflag, " + "action_menu_id, action_poi_id, action_script_id, box_coded, box_money, box_text " + "FROM gossip_menu_option"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded gossip_menu_option, table is empty!"); + return; + } + + barGoLink bar(result->GetRowCount()); + + uint32 count = 0; + + std::set gossipScriptSet; + + for (ScriptMapMap::const_iterator itr = sGossipScripts.begin(); itr != sGossipScripts.end(); ++itr) + gossipScriptSet.insert(itr->first); + + do + { + bar.step(); + + Field* fields = result->Fetch(); + + GossipMenuItems gMenuItem; + + gMenuItem.menu_id = fields[0].GetUInt32(); + gMenuItem.id = fields[1].GetUInt32(); + gMenuItem.option_icon = fields[2].GetUInt8(); + gMenuItem.option_text = fields[3].GetCppString(); + gMenuItem.option_id = fields[4].GetUInt32(); + gMenuItem.npc_option_npcflag = fields[5].GetUInt32(); + gMenuItem.action_menu_id = fields[6].GetUInt32(); + gMenuItem.action_poi_id = fields[7].GetUInt32(); + gMenuItem.action_script_id = fields[8].GetUInt32(); + gMenuItem.box_coded = fields[9].GetUInt8() != 0; + gMenuItem.box_money = fields[10].GetUInt32(); + gMenuItem.box_text = fields[11].GetCppString(); + + if (gMenuItem.option_icon >= GOSSIP_ICON_MAX) + { + sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has unknown icon id %u. Replacing with GOSSIP_ICON_CHAT", gMenuItem.menu_id, gMenuItem.id, gMenuItem.option_icon); + gMenuItem.option_icon = GOSSIP_ICON_CHAT; + } + + if (gMenuItem.option_id >= GOSSIP_OPTION_MAX) + sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has unknown option id %u. Option will not be used", gMenuItem.menu_id, gMenuItem.id, gMenuItem.option_id); + + if (gMenuItem.action_poi_id && !GetPointOfInterest(gMenuItem.action_poi_id)) + { + sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u use non-existing action_poi_id %u, ignoring", gMenuItem.menu_id, gMenuItem.id, gMenuItem.action_poi_id); + gMenuItem.action_poi_id = 0; + } + + if (gMenuItem.action_script_id) + { + if (gMenuItem.option_id != GOSSIP_OPTION_GOSSIP) + { + sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u have action_script_id %u but option_id is not GOSSIP_OPTION_GOSSIP, ignoring", gMenuItem.menu_id, gMenuItem.id, gMenuItem.action_script_id); + continue; + } + + if (sGossipScripts.find(gMenuItem.action_script_id) == sGossipScripts.end()) + { + sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u have action_script_id %u that does not exist in `gossip_scripts`, ignoring", gMenuItem.menu_id, gMenuItem.id, gMenuItem.action_script_id); + continue; + } + + gossipScriptSet.erase(gMenuItem.action_script_id); + } + + m_mGossipMenuItemsMap.insert(GossipMenuItemsMap::value_type(gMenuItem.menu_id, gMenuItem)); + + ++count; + + } + while (result->NextRow()); + + if (!gossipScriptSet.empty()) + { + for (std::set::const_iterator itr = gossipScriptSet.begin(); itr != gossipScriptSet.end(); ++itr) + sLog.outErrorDb("Table `gossip_scripts` contain unused script, id %u.", *itr); + } + + sLog.outString(); + sLog.outString(">> Loaded %u gossip_menu_option entries", count); +} + +void ObjectMgr::AddVendorItem(uint32 entry,uint32 item, int32 maxcount, uint32 incrtime, uint32 extendedcost, bool savetodb) +{ + VendorItemData& vList = m_mCacheVendorItemMap[entry]; + vList.AddItem(item,maxcount,incrtime,extendedcost); + + if (savetodb) WorldDatabase.PExecuteLog("INSERT INTO npc_vendor (entry,item,maxcount,incrtime,extendedcost) VALUES('%u','%u','%u','%u','%u')",entry, item, maxcount,incrtime,extendedcost); +} + +bool ObjectMgr::RemoveVendorItem(uint32 entry,uint32 item, bool savetodb) +{ + CacheVendorItemMap::iterator iter = m_mCacheVendorItemMap.find(entry); + if (iter == m_mCacheVendorItemMap.end()) + return false; + + if(!iter->second.RemoveItem(item)) + return false; + + if (savetodb) WorldDatabase.PExecuteLog("DELETE FROM npc_vendor WHERE entry='%u' AND item='%u'",entry, item); + return true; +} + +bool ObjectMgr::IsVendorItemValid(uint32 vendor_entry, uint32 item_id, int32 maxcount, uint32 incrtime, uint32 ExtendedCost, Player* pl, std::set* skip_vendors, uint32 ORnpcflag) const +{ + CreatureInfo const* cInfo = GetCreatureTemplate(vendor_entry); + if (!cInfo) + { + if (pl) + ChatHandler(pl).SendSysMessage(LANG_COMMAND_VENDORSELECTION); + else + sLog.outErrorDb("Table `(game_event_)npc_vendor` have data for not existed creature template (Entry: %u), ignore", vendor_entry); + return false; + } + + if (!((cInfo->npcflag | ORnpcflag) & UNIT_NPC_FLAG_VENDOR)) + { + if (!skip_vendors || skip_vendors->count(vendor_entry) == 0) + { + if (pl) + ChatHandler(pl).SendSysMessage(LANG_COMMAND_VENDORSELECTION); + else + sLog.outErrorDb("Table `(game_event_)npc_vendor` have data for not creature template (Entry: %u) without vendor flag, ignore", vendor_entry); + + if (skip_vendors) + skip_vendors->insert(vendor_entry); + } + return false; + } + + if (!GetItemPrototype(item_id)) + { + if (pl) + ChatHandler(pl).PSendSysMessage(LANG_ITEM_NOT_FOUND, item_id); + else + sLog.outErrorDb("Table `(game_event_)npc_vendor` for Vendor (Entry: %u) have in item list non-existed item (%u), ignore",vendor_entry,item_id); + return false; + } + + if (ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost)) + { + if (pl) + ChatHandler(pl).PSendSysMessage(LANG_EXTENDED_COST_NOT_EXIST,ExtendedCost); + else + sLog.outErrorDb("Table `(game_event_)npc_vendor` have Item (Entry: %u) with wrong ExtendedCost (%u) for vendor (%u), ignore",item_id,ExtendedCost,vendor_entry); + return false; + } + + if (maxcount > 0 && incrtime == 0) + { + if (pl) + ChatHandler(pl).PSendSysMessage("MaxCount != 0 (%u) but IncrTime == 0", maxcount); + else + sLog.outErrorDb("Table `(game_event_)npc_vendor` has `maxcount` (%u) for item %u of vendor (Entry: %u) but `incrtime`=0, ignore", maxcount, item_id, vendor_entry); + return false; + } + else if (maxcount == 0 && incrtime > 0) + { + if (pl) + ChatHandler(pl).PSendSysMessage("MaxCount == 0 but IncrTime<>= 0"); + else + sLog.outErrorDb("Table `(game_event_)npc_vendor` has `maxcount`=0 for item %u of vendor (Entry: %u) but `incrtime`<>0, ignore", item_id, vendor_entry); + return false; + } + + VendorItemData const* vItems = GetNpcVendorItemList(vendor_entry); + if (!vItems) + return true; // later checks for non-empty lists + + if(vItems->FindItemCostPair(item_id,ExtendedCost)) + { + if (pl) + ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST, item_id, ExtendedCost); + else + sLog.outErrorDb( "Table `npc_vendor` has duplicate items %u (with extended cost %u) for vendor (Entry: %u), ignoring", item_id, ExtendedCost, vendor_entry); + return false; + } + + if (vItems->GetItemCount() >= MAX_VENDOR_ITEMS) + { + if (pl) + ChatHandler(pl).SendSysMessage(LANG_COMMAND_ADDVENDORITEMITEMS); + else + sLog.outErrorDb("Table `npc_vendor` has too many items (%u >= %i) for vendor (Entry: %u), ignore", vItems->GetItemCount(), MAX_VENDOR_ITEMS, vendor_entry); + return false; + } + + return true; +} + +void ObjectMgr::LoadScriptNames() +{ + m_scriptNames.push_back(""); + QueryResult_AutoPtr result = WorldDatabase.Query( + "SELECT DISTINCT(ScriptName) FROM creature_template WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM item_template WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM areatrigger_scripts WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(script) FROM instance_template WHERE script <> ''"); + + if (!result) + { + barGoLink bar(1); + bar.step(); + sLog.outString(); + sLog.outErrorDb(">> Loaded empty set of Script Names!"); + return; + } + + barGoLink bar(result->GetRowCount()); + + //OnEvent Changes + m_scriptNames.push_back("scripted_on_events"); + uint32 count = 1; + + do + { + bar.step(); + m_scriptNames.push_back((*result)[0].GetString()); + ++count; + } while (result->NextRow()); + + std::sort(m_scriptNames.begin(), m_scriptNames.end()); + sLog.outString(); + sLog.outString(">> Loaded %d Script Names", count); +} + +uint32 ObjectMgr::GetScriptId(const char *name) +{ + // use binary search to find the script name in the sorted vector + // assume "" is the first element + if (!name) return 0; + ScriptNameMap::const_iterator itr = + std::lower_bound(m_scriptNames.begin(), m_scriptNames.end(), name); + if (itr == m_scriptNames.end() || *itr != name) return 0; + return itr - m_scriptNames.begin(); +} + +void ObjectMgr::CheckScripts(ScriptMapMap const& scripts,std::set& ids) +{ + for (ScriptMapMap::const_iterator itrMM = scripts.begin(); itrMM != scripts.end(); ++itrMM) + { + for (ScriptMap::const_iterator itrM = itrMM->second.begin(); itrM != itrMM->second.end(); ++itrM) + { + switch(itrM->second.command) + { + case SCRIPT_COMMAND_TALK: + { + if (!GetTrinityStringLocale (itrM->second.dataint)) + sLog.outErrorDb("Table `db_script_string` not has string id %u used db script (ID: %u)", itrM->second.dataint, itrMM->first); + + if (ids.find(itrM->second.dataint) != ids.end()) + ids.erase(itrM->second.dataint); + } + } + } + } +} + +void ObjectMgr::LoadDbScriptStrings() +{ + LoadTrinityStrings(WorldDatabase,"db_script_string",MIN_DB_SCRIPT_STRING_ID,MAX_DB_SCRIPT_STRING_ID); + + std::set ids; + + for (int32 i = MIN_DB_SCRIPT_STRING_ID; i < MAX_DB_SCRIPT_STRING_ID; ++i) + if (GetTrinityStringLocale(i)) + ids.insert(i); + + CheckScripts(sQuestEndScripts,ids); + CheckScripts(sQuestStartScripts,ids); + CheckScripts(sSpellScripts,ids); + CheckScripts(sGameObjectScripts,ids); + CheckScripts(sEventScripts,ids); + + CheckScripts(sWaypointScripts,ids); + + for (std::set::const_iterator itr = ids.begin(); itr != ids.end(); ++itr) + sLog.outErrorDb("Table `db_script_string` has unused string id %u", *itr); +} + +// Functions for scripting access +uint32 GetAreaTriggerScriptId(uint32 trigger_id) +{ + return objmgr.GetAreaTriggerScriptId(trigger_id); +} + +bool LoadTrinityStrings(DatabaseType& db, char const* table,int32 start_value, int32 end_value) +{ + // MAX_DB_SCRIPT_STRING_ID is max allowed negative value for scripts (scrpts can use only more deep negative values + // start/end reversed for negative values + if (start_value > MAX_DB_SCRIPT_STRING_ID || end_value >= start_value) + { + sLog.outErrorDb("Table '%s' load attempted with range (%d - %d) reserved by Trinity, strings not loaded.",table,start_value,end_value+1); + return false; + } + + return objmgr.LoadTrinityStrings(db,table,start_value,end_value); +} + +uint32 GetScriptId(const char *name) +{ + return objmgr.GetScriptId(name); +} + +ObjectMgr::ScriptNameMap & GetScriptNames() +{ + return objmgr.GetScriptNames(); +} + +GameObjectInfo const *GetGameObjectInfo(uint32 id) +{ + return objmgr.GetGameObjectInfo(id); +} + +CreatureInfo const *GetCreatureInfo(uint32 id) +{ + return objmgr.GetCreatureTemplate(id); +} + +void ObjectMgr::LoadTransportEvents() +{ + + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, waypoint_id, event_id FROM transport_events"); + + if (!result) + { + barGoLink bar1(1); + bar1.step(); + sLog.outString("\n>> Transport events table is empty \n"); + return; + } + + barGoLink bar1(result->GetRowCount()); + + do + { + bar1.step(); + + Field *fields = result->Fetch(); + + //Load event values + uint32 entry = fields[0].GetUInt32(); + uint32 waypoint_id = fields[1].GetUInt32(); + uint32 event_id = fields[2].GetUInt32(); + + uint32 event_count = (entry*100)+waypoint_id; + TransportEventMap[event_count] = event_id; + } + while (result->NextRow()); + + sLog.outString("\n>> Loaded %u transport events \n", result->GetRowCount()); +} + +CreatureInfo const* GetCreatureTemplateStore(uint32 entry) +{ + return sCreatureStorage.LookupEntry(entry); +} + +Quest const* GetQuestTemplateStore(uint32 entry) +{ + return objmgr.GetQuestTemplate(entry); +} + +uint64 ObjectMgr::GenerateGMTicketId() +{ + return ++m_GMticketid; +} + +void ObjectMgr::LoadGMTickets() +{ + if (!m_GMTicketList.empty()) + { + for (GmTicketList::const_iterator itr = m_GMTicketList.begin(); itr != m_GMTicketList.end(); ++itr) + delete *itr; + } + m_GMTicketList.clear(); + m_GMticketid = 0; + + QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT guid, playerGuid, name, message, createtime, map, posX, posY, posZ, timestamp, closed, assignedto, comment FROM gm_tickets"); + + if (!result) + { + barGoLink bar(1); + bar.step(); + sLog.outString(); + sLog.outString(">> GM Tickets table is empty, no tickets were loaded."); + return; + } + + uint16 count = 0; + barGoLink bar ((*result).GetRowCount()); + GM_Ticket *ticket; + do + { + Field *fields = result->Fetch(); + ticket = new GM_Ticket; + ticket->guid = fields[0].GetUInt64(); + ticket->playerGuid = fields[1].GetUInt64(); + ticket->name = fields[2].GetCppString(); + ticket->message = fields[3].GetCppString(); + ticket->createtime = fields[4].GetUInt64(); + ticket->map = fields[5].GetUInt32(); + ticket->pos_x = fields[6].GetFloat(); + ticket->pos_y = fields[7].GetFloat(); + ticket->pos_z = fields[8].GetFloat(); + ticket->timestamp = fields[9].GetUInt64(); + ticket->closed = fields[10].GetUInt64(); + ticket->assignedToGM = fields[11].GetUInt64(); + ticket->comment = fields[12].GetCppString(); + ++count; + bar.step(); + + m_GMTicketList.push_back(ticket); + + } while (result->NextRow()); + + result = CharacterDatabase.Query("SELECT MAX(guid) from gm_tickets"); + + if (result) + { + Field *fields = result->Fetch(); + m_GMticketid = fields[0].GetUInt64(); + } + + sLog.outString(">> Loaded %u GM Tickets from the database.", count); +} + +void ObjectMgr::AddOrUpdateGMTicket(GM_Ticket &ticket, bool create) +{ + if (create) + m_GMTicketList.push_back(&ticket); + + _AddOrUpdateGMTicket(ticket); +} + +void ObjectMgr::_AddOrUpdateGMTicket(GM_Ticket &ticket) +{ + std::string msg(ticket.message), name(ticket.name), comment(ticket.comment); + CharacterDatabase.escape_string(msg); + CharacterDatabase.escape_string(name); + CharacterDatabase.escape_string(comment); + std::ostringstream ss; + ss << "REPLACE INTO gm_tickets (guid, playerGuid, name, message, createtime, map, posX, posY, posZ, timestamp, closed, assignedto, comment) VALUES('"; + ss << ticket.guid << "', '"; + ss << ticket.playerGuid << "', '"; + ss << name << "', '"; + ss << msg << "', '" ; + ss << ticket.createtime << "', '"; + ss << ticket.map << "', '"; + ss << ticket.pos_x << "', '"; + ss << ticket.pos_y << "', '"; + ss << ticket.pos_z << "', '"; + ss << ticket.timestamp << "', '"; + ss << ticket.closed << "', '"; + ss << ticket.assignedToGM << "', '"; + ss << comment << "');"; + CharacterDatabase.BeginTransaction(); + CharacterDatabase.Execute(ss.str().c_str()); + CharacterDatabase.CommitTransaction(); +} + +void ObjectMgr::RemoveGMTicket(GM_Ticket *ticket, int64 source, bool permanently) +{ + for (GmTicketList::iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i) + if ((*i)->guid == ticket->guid) + { + if (permanently) + { + CharacterDatabase.PExecute("DELETE FROM gm_tickets WHERE guid = '%u'", ticket->guid); + i = m_GMTicketList.erase(i); + ticket = NULL; + return; + } + (*i)->closed = source; + _AddOrUpdateGMTicket(*(*i)); + } +} + +void ObjectMgr::RemoveGMTicket(uint64 ticketGuid, int64 source, bool permanently) +{ + GM_Ticket *ticket = GetGMTicket(ticketGuid); + assert(ticket); + RemoveGMTicket(ticket, source, permanently); +} + +CreatureBaseStats const* ObjectMgr::GetCreatureBaseStats(uint8 level, uint8 unitClass) +{ + CreatureBaseStatsMap::const_iterator it = m_creatureBaseStatsMap.find(MAKE_PAIR16(level,unitClass)); + + if (it != m_creatureBaseStatsMap.end()) + return &(it->second); + + struct DefaultCreatureBaseStats : public CreatureBaseStats + { + DefaultCreatureBaseStats() + { + BaseArmor = 1; + for (uint8 j = 0; j < MAX_CREATURE_BASE_HP; ++j) + BaseHealth[j] = 1; + BaseMana = 0; + } + }; + static const DefaultCreatureBaseStats def_stats; + return &def_stats; +} + +void ObjectMgr::LoadCreatureClassLevelStats() +{ + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT level, class, basehp0, basehp1, basehp2, basemana, basearmor FROM creature_classlevelstats"); + + if (!result) + { + barGoLink bar(1); + bar.step(); + sLog.outString(); + sLog.outString(">> Loaded 0 creature base stats. DB table `creature_classlevelstats` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + uint32 counter = 0; + + do + { + Field *fields = result->Fetch(); + + uint8 Level = fields[0].GetUInt32(); + uint8 Class = fields[1].GetUInt8(); + + CreatureBaseStats stats; + for (uint8 i = 0; i < MAX_CREATURE_BASE_HP; ++i) + stats.BaseHealth[i] = fields[i + 2].GetUInt32(); + stats.BaseMana = fields[5].GetUInt32(); + stats.BaseArmor = fields[6].GetUInt32(); + + if (Level > STRONG_MAX_LEVEL) + { + sLog.outErrorDb("Creature base stats for class %u has invalid level %u (max is %u) - set to %u", + Class, Level, STRONG_MAX_LEVEL, STRONG_MAX_LEVEL); + Level = STRONG_MAX_LEVEL; + } + + if (!Class || ((1 << (Class - 1)) & CLASSMASK_ALL_CREATURES) == 0) + sLog.outErrorDb("Creature base stats for level %u has invalid class %u", + Level, Class); + + for (uint8 i = 0; i < MAX_CREATURE_BASE_HP; ++i) + { + if (stats.BaseHealth[i] < 1) + { + sLog.outErrorDb("Creature base stats for class %u, level %u has invalid zero base HP[%u] - set to 1", + Class, Level, i); + stats.BaseHealth[i] = 1; + } + } + + m_creatureBaseStatsMap[MAKE_PAIR16(Level, Class)] = stats; + + bar.step(); + ++counter; + } + while (result->NextRow()); + + for (uint32 i = 0; i < sCreatureStorage.MaxEntry; ++i) + { + CreatureInfo const* info = sCreatureStorage.LookupEntry(i); + if (!info) + continue; + + for (uint16 lvl = info->minlevel; lvl <= info->maxlevel; ++lvl) + { + if (m_creatureBaseStatsMap.find(MAKE_PAIR16(lvl, info->unit_class)) == m_creatureBaseStatsMap.end()) + sLog.outErrorDb("Missing base stats for creature class %u level %u", info->unit_class, lvl); + } + } + + sLog.outString(); + sLog.outString(">> Loaded %u creature base stats.", counter); +} diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h new file mode 100644 index 00000000000..79b6ffdd0eb --- /dev/null +++ b/src/server/game/Globals/ObjectMgr.h @@ -0,0 +1,1085 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _OBJECTMGR_H +#define _OBJECTMGR_H + +#include "Log.h" +#include "Object.h" +#include "Bag.h" +#include "Creature.h" +#include "Player.h" +#include "DynamicObject.h" +#include "GameObject.h" +#include "Corpse.h" +#include "QuestDef.h" +#include "Path.h" +#include "ItemPrototype.h" +#include "NPCHandler.h" +#include "Database/DatabaseEnv.h" +#include "Mail.h" +#include "Map.h" +#include "ObjectAccessor.h" +#include "ObjectDefines.h" +#include "Policies/Singleton.h" +#include "Database/SQLStorage.h" +#include "Vehicle.h" +#include "ObjectMgr.h" +#include +#include +#include +#include "ConditionMgr.h" + +extern SQLStorage sCreatureStorage; +extern SQLStorage sCreatureDataAddonStorage; +extern SQLStorage sCreatureInfoAddonStorage; +extern SQLStorage sCreatureModelStorage; +extern SQLStorage sEquipmentStorage; +extern SQLStorage sGOStorage; +extern SQLStorage sPageTextStore; +extern SQLStorage sItemStorage; +extern SQLStorage sInstanceTemplate; + +class Group; +class Guild; +class ArenaTeam; +class Path; +class TransportPath; +class Item; + +struct GameTele +{ + float position_x; + float position_y; + float position_z; + float orientation; + uint32 mapId; + std::string name; + std::wstring wnameLow; +}; + +typedef UNORDERED_MAP GameTeleMap; + +struct ScriptInfo +{ + uint32 id; + uint32 delay; + uint32 command; + uint32 datalong; + uint32 datalong2; + int32 dataint; + float x; + float y; + float z; + float o; +}; + +typedef std::multimap ScriptMap; +typedef std::map ScriptMapMap; +extern ScriptMapMap sQuestEndScripts; +extern ScriptMapMap sQuestStartScripts; +extern ScriptMapMap sSpellScripts; +extern ScriptMapMap sGameObjectScripts; +extern ScriptMapMap sEventScripts; +extern ScriptMapMap sGossipScripts; +extern ScriptMapMap sWaypointScripts; + +struct SpellClickInfo +{ + uint32 spellId; + uint32 questStart; // quest start (quest must be active or rewarded for spell apply) + uint32 questEnd; // quest end (quest don't must be rewarded for spell apply) + bool questStartCanActive; // if true then quest start can be active (not only rewarded) + uint8 castFlags; + uint32 auraRequired; + uint32 auraForbidden; + SpellClickUserTypes userType; + + // helpers + bool IsFitToRequirements(Player const* player, Creature const * clickNpc) const; +}; + +typedef std::multimap SpellClickInfoMap; +typedef std::pair SpellClickInfoMapBounds; + +struct AreaTrigger +{ + uint32 access_id; + uint32 target_mapId; + float target_X; + float target_Y; + float target_Z; + float target_Orientation; +}; + +typedef std::set CellGuidSet; +typedef std::map CellCorpseSet; +struct CellObjectGuids +{ + CellGuidSet creatures; + CellGuidSet gameobjects; + CellCorpseSet corpses; +}; +typedef UNORDERED_MAP CellObjectGuidsMap; +typedef UNORDERED_MAP MapObjectGuids; + +typedef UNORDERED_MAP RespawnTimes; + +// Trinity string ranges +#define MIN_TRINITY_STRING_ID 1 // 'trinity_string' +#define MAX_TRINITY_STRING_ID 2000000000 +#define MIN_DB_SCRIPT_STRING_ID MAX_TRINITY_STRING_ID // 'db_script_string' +#define MAX_DB_SCRIPT_STRING_ID 2000010000 +#define MIN_CREATURE_AI_TEXT_STRING_ID (-1) // 'creature_ai_texts' +#define MAX_CREATURE_AI_TEXT_STRING_ID (-1000000) + +// Trinity Trainer Reference start range +#define TRINITY_TRAINER_START_REF 200000 + +struct TrinityStringLocale +{ + std::vector Content; // 0 -> default, i -> i-1 locale index +}; + +typedef std::map CreatureLinkedRespawnMap; +typedef UNORDERED_MAP CreatureDataMap; +typedef UNORDERED_MAP GameObjectDataMap; +typedef UNORDERED_MAP CreatureLocaleMap; +typedef UNORDERED_MAP GameObjectLocaleMap; +typedef UNORDERED_MAP ItemLocaleMap; +typedef UNORDERED_MAP QuestLocaleMap; +typedef UNORDERED_MAP NpcTextLocaleMap; +typedef UNORDERED_MAP PageTextLocaleMap; +typedef UNORDERED_MAP TrinityStringLocaleMap; +typedef UNORDERED_MAP GossipMenuItemsLocaleMap; +typedef UNORDERED_MAP PointOfInterestLocaleMap; + +typedef std::multimap QuestRelations; +typedef std::multimap ItemRequiredTargetMap; +typedef std::pair ItemRequiredTargetMapBounds; + +struct PetLevelInfo +{ + PetLevelInfo() : health(0), mana(0) { for (uint8 i=0; i < MAX_STATS; ++i) stats[i] = 0; } + + uint16 stats[MAX_STATS]; + uint16 health; + uint16 mana; + uint16 armor; +}; + +struct MailLevelReward +{ + MailLevelReward() : raceMask(0), mailTemplateId(0), senderEntry(0) {} + MailLevelReward(uint32 _raceMask, uint32 _mailTemplateId, uint32 _senderEntry) : raceMask(_raceMask), mailTemplateId(_mailTemplateId), senderEntry(_senderEntry) {} + + uint32 raceMask; + uint32 mailTemplateId; + uint32 senderEntry; +}; + +typedef std::list MailLevelRewardList; +typedef UNORDERED_MAP MailLevelRewardMap; + +struct ReputationOnKillEntry +{ + uint32 repfaction1; + uint32 repfaction2; + bool is_teamaward1; + uint32 reputation_max_cap1; + int32 repvalue1; + bool is_teamaward2; + uint32 reputation_max_cap2; + int32 repvalue2; + bool team_dependent; +}; + +struct PointOfInterest +{ + uint32 entry; + float x; + float y; + uint32 icon; + uint32 flags; + uint32 data; + std::string icon_name; +}; + +struct GossipMenuItems +{ + uint32 menu_id; + uint32 id; + uint8 option_icon; + std::string option_text; + uint32 option_id; + uint32 npc_option_npcflag; + uint32 action_menu_id; + uint32 action_poi_id; + uint32 action_script_id; + bool box_coded; + uint32 box_money; + std::string box_text; + ConditionList conditions; +}; + +struct GossipMenus +{ + uint32 entry; + uint32 text_id; + ConditionList conditions; +}; + +typedef std::multimap GossipMenusMap; +typedef std::pair GossipMenusMapBounds; +typedef std::pair GossipMenusMapBoundsNonConst; +typedef std::multimap GossipMenuItemsMap; +typedef std::pair GossipMenuItemsMapBounds; +typedef std::pair GossipMenuItemsMapBoundsNonConst; + +struct QuestPOIPoint +{ + int32 x; + int32 y; + + QuestPOIPoint() : x(0), y(0) {} + QuestPOIPoint(int32 _x, int32 _y) : x(_x), y(_y) {} +}; + +struct QuestPOI +{ + uint32 Id; + int32 ObjectiveIndex; + uint32 MapId; + uint32 AreaId; + uint32 Unk2; + uint32 Unk3; + uint32 Unk4; + std::vector points; + + QuestPOI() : Id(0), ObjectiveIndex(0), MapId(0), AreaId(0), Unk2(0), Unk3(0), Unk4(0) {} + QuestPOI(uint32 id, int32 objIndex, uint32 mapId, uint32 areaId, uint32 unk2, uint32 unk3, uint32 unk4) : Id(id), ObjectiveIndex(objIndex), MapId(mapId), AreaId(areaId), Unk2(unk2), Unk3(unk3), Unk4(unk4) {} +}; + +typedef std::vector QuestPOIVector; +typedef UNORDERED_MAP QuestPOIMap; + +#define WEATHER_SEASONS 4 +struct WeatherSeasonChances +{ + uint32 rainChance; + uint32 snowChance; + uint32 stormChance; +}; + +struct WeatherZoneChances +{ + WeatherSeasonChances data[WEATHER_SEASONS]; +}; + +struct GraveYardData +{ + uint32 safeLocId; + uint32 team; +}; +typedef std::multimap GraveYardMap; + +// NPC gossip text id +typedef UNORDERED_MAP CacheNpcTextIdMap; + +typedef UNORDERED_MAP CacheVendorItemMap; +typedef UNORDERED_MAP CacheTrainerSpellMap; + +enum SkillRangeType +{ + SKILL_RANGE_LANGUAGE, // 300..300 + SKILL_RANGE_LEVEL, // 1..max skill for level + SKILL_RANGE_MONO, // 1..1, grey monolite bar + SKILL_RANGE_RANK, // 1..skill for known rank + SKILL_RANGE_NONE, // 0..0 always +}; + +struct GM_Ticket +{ + uint64 guid; + uint64 playerGuid; + std::string name; + float pos_x; + float pos_y; + float pos_z; + uint32 map; + std::string message; + uint64 createtime; + uint64 timestamp; + int64 closed; // 0 = Open, -1 = Console, playerGuid = player abandoned ticket, other = GM who closed it. + uint64 assignedToGM; + std::string comment; +}; +typedef std::list GmTicketList; +SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial); + +#define MAX_PLAYER_NAME 12 // max allowed by client name length +#define MAX_INTERNAL_PLAYER_NAME 15 // max server internal player name length (> MAX_PLAYER_NAME for support declined names) +#define MAX_PET_NAME 12 // max allowed by client name length +#define MAX_CHARTER_NAME 24 // max allowed by client name length + +bool normalizePlayerName(std::string& name); + +struct LanguageDesc +{ + Language lang_id; + uint32 spell_id; + uint32 skill_id; +}; + +extern LanguageDesc lang_description[LANGUAGES_COUNT]; + LanguageDesc const* GetLanguageDescByID(uint32 lang); + +class PlayerDumpReader; + +class ObjectMgr +{ + friend class PlayerDumpReader; + + public: + ObjectMgr(); + ~ObjectMgr(); + + typedef UNORDERED_MAP ItemMap; + + typedef std::set< Group * > GroupSet; + + typedef UNORDERED_MAP GuildMap; + + typedef UNORDERED_MAP ArenaTeamMap; + + typedef UNORDERED_MAP QuestMap; + + typedef UNORDERED_MAP AreaTriggerMap; + + typedef UNORDERED_MAP AreaTriggerScriptMap; + + typedef UNORDERED_MAP AccessRequirementMap; + + typedef UNORDERED_MAP RepOnKillMap; + typedef UNORDERED_MAP PointOfInterestMap; + + typedef UNORDERED_MAP WeatherZoneMap; + + typedef std::vector ScriptNameMap; + + UNORDERED_MAP TransportEventMap; + + Player* GetPlayer(const char* name) const { return ObjectAccessor::Instance().FindPlayerByName(name);} + Player* GetPlayer(uint64 guid) const { return ObjectAccessor::FindPlayer(guid); } + + static GameObjectInfo const *GetGameObjectInfo(uint32 id) { return sGOStorage.LookupEntry(id); } + int LoadReferenceVendor(int32 vendor, int32 item_id, std::set *skip_vendors); + + void LoadGameobjectInfo(); + void AddGameobjectInfo(GameObjectInfo *goinfo); + + Group * GetGroupByGUID(const uint64 &guid) const; + void AddGroup(Group* group) { mGroupSet.insert(group); } + void RemoveGroup(Group* group) { mGroupSet.erase(group); } + + Guild* GetGuildByLeader(uint64 const&guid) const; + Guild* GetGuildById(uint32 GuildId) const; + Guild* GetGuildByName(const std::string& guildname) const; + std::string GetGuildNameById(uint32 GuildId) const; + void AddGuild(Guild* guild); + void RemoveGuild(uint32 Id); + + ArenaTeam* GetArenaTeamById(uint32 arenateamid) const; + ArenaTeam* GetArenaTeamByName(const std::string& arenateamname) const; + ArenaTeam* GetArenaTeamByCaptain(uint64 const& guid) const; + void AddArenaTeam(ArenaTeam* arenaTeam); + void RemoveArenaTeam(uint32 Id); + ArenaTeamMap::iterator GetArenaTeamMapBegin() { return mArenaTeamMap.begin(); } + ArenaTeamMap::iterator GetArenaTeamMapEnd() { return mArenaTeamMap.end(); } + + static CreatureInfo const *GetCreatureTemplate(uint32 id); + CreatureModelInfo const *GetCreatureModelInfo(uint32 modelid); + CreatureModelInfo const* GetCreatureModelRandomGender(uint32 display_id); + uint32 ChooseDisplayId(uint32 team, const CreatureInfo *cinfo, const CreatureData *data = NULL); + EquipmentInfo const *GetEquipmentInfo(uint32 entry); + static CreatureDataAddon const *GetCreatureAddon(uint32 lowguid) + { + return sCreatureDataAddonStorage.LookupEntry(lowguid); + } + + static CreatureDataAddon const *GetCreatureTemplateAddon(uint32 entry) + { + return sCreatureInfoAddonStorage.LookupEntry(entry); + } + + static ItemPrototype const* GetItemPrototype(uint32 id) { return sItemStorage.LookupEntry(id); } + + static InstanceTemplate const* GetInstanceTemplate(uint32 map) + { + return sInstanceTemplate.LookupEntry(map); + } + + PetLevelInfo const* GetPetLevelInfo(uint32 creature_id, uint8 level) const; + + PlayerClassInfo const* GetPlayerClassInfo(uint32 class_) const + { + if (class_ >= MAX_CLASSES) return NULL; + return &playerClassInfo[class_]; + } + void GetPlayerClassLevelInfo(uint32 class_,uint8 level, PlayerClassLevelInfo* info) const; + + PlayerInfo const* GetPlayerInfo(uint32 race, uint32 class_) const + { + if (race >= MAX_RACES) return NULL; + if (class_ >= MAX_CLASSES) return NULL; + PlayerInfo const* info = &playerInfo[race][class_]; + if (info->displayId_m == 0 || info->displayId_f == 0) return NULL; + return info; + } + void GetPlayerLevelInfo(uint32 race, uint32 class_, uint8 level, PlayerLevelInfo* info) const; + + uint64 GetPlayerGUIDByName(std::string name) const; + bool GetPlayerNameByGUID(const uint64 &guid, std::string &name) const; + uint32 GetPlayerTeamByGUID(const uint64 &guid) const; + uint32 GetPlayerAccountIdByGUID(const uint64 &guid) const; + uint32 GetPlayerAccountIdByPlayerName(const std::string& name) const; + + uint32 GetNearestTaxiNode(float x, float y, float z, uint32 mapid, uint32 team); + void GetTaxiPath(uint32 source, uint32 destination, uint32 &path, uint32 &cost); + uint32 GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt_team = false); + void GetTaxiPathNodes(uint32 path, Path &pathnodes, std::vector& mapIds); + void GetTransportPathNodes(uint32 path, TransportPath &pathnodes); + + Quest const* GetQuestTemplate(uint32 quest_id) const + { + QuestMap::const_iterator itr = mQuestTemplates.find(quest_id); + return itr != mQuestTemplates.end() ? itr->second : NULL; + } + QuestMap const& GetQuestTemplates() const { return mQuestTemplates; } + + uint32 GetQuestForAreaTrigger(uint32 Trigger_ID) const + { + QuestAreaTriggerMap::const_iterator itr = mQuestAreaTriggerMap.find(Trigger_ID); + if (itr != mQuestAreaTriggerMap.end()) + return itr->second; + return 0; + } + bool IsTavernAreaTrigger(uint32 Trigger_ID) const + { + return mTavernAreaTriggerSet.find(Trigger_ID) != mTavernAreaTriggerSet.end(); + } + + bool IsGameObjectForQuests(uint32 entry) const + { + return mGameObjectForQuestSet.find(entry) != mGameObjectForQuestSet.end(); + } + + GossipText const* GetGossipText(uint32 Text_ID) const; + + WorldSafeLocsEntry const *GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team); + bool AddGraveYardLink(uint32 id, uint32 zone, uint32 team, bool inDB = true); + void RemoveGraveYardLink(uint32 id, uint32 zone, uint32 team, bool inDB = false); + void LoadGraveyardZones(); + GraveYardData const* FindGraveYardData(uint32 id, uint32 zone); + + AreaTrigger const* GetAreaTrigger(uint32 trigger) const + { + AreaTriggerMap::const_iterator itr = mAreaTriggers.find(trigger); + if (itr != mAreaTriggers.end()) + return &itr->second; + return NULL; + } + + AccessRequirement const* GetAccessRequirement(uint32 requirement) const + { + AccessRequirementMap::const_iterator itr = mAccessRequirements.find(requirement); + if (itr != mAccessRequirements.end()) + return &itr->second; + return NULL; + } + + AreaTrigger const* GetGoBackTrigger(uint32 Map) const; + AreaTrigger const* GetMapEntranceTrigger(uint32 Map) const; + + uint32 GetAreaTriggerScriptId(uint32 trigger_id); + + ReputationOnKillEntry const* GetReputationOnKilEntry(uint32 id) const + { + RepOnKillMap::const_iterator itr = mRepOnKill.find(id); + if (itr != mRepOnKill.end()) + return &itr->second; + return NULL; + } + + PointOfInterest const* GetPointOfInterest(uint32 id) const + { + PointOfInterestMap::const_iterator itr = mPointsOfInterest.find(id); + if (itr != mPointsOfInterest.end()) + return &itr->second; + return NULL; + } + + QuestPOIVector const* GetQuestPOIVector(uint32 questId) + { + QuestPOIMap::const_iterator itr = mQuestPOIMap.find(questId); + if (itr != mQuestPOIMap.end()) + return &itr->second; + return NULL; + } + + VehicleAccessoryList const* GetVehicleAccessoryList(uint32 uiEntry) const + { + VehicleAccessoryMap::const_iterator itr = m_VehicleAccessoryMap.find(uiEntry); + if (itr != m_VehicleAccessoryMap.end()) + return &itr->second; + return NULL; + } + + void LoadGuilds(); + void LoadArenaTeams(); + void LoadGroups(); + void LoadQuests(); + void LoadQuestRelations() + { + sLog.outString("Loading GO Start Quest Data..."); + LoadGameobjectQuestRelations(); + sLog.outString("Loading GO End Quest Data..."); + LoadGameobjectInvolvedRelations(); + sLog.outString("Loading Creature Start Quest Data..."); + LoadCreatureQuestRelations(); + sLog.outString("Loading Creature End Quest Data..."); + LoadCreatureInvolvedRelations(); + } + void LoadGameobjectQuestRelations(); + void LoadGameobjectInvolvedRelations(); + void LoadCreatureQuestRelations(); + void LoadCreatureInvolvedRelations(); + + QuestRelations mGOQuestRelations; + QuestRelations mGOQuestInvolvedRelations; + QuestRelations mCreatureQuestRelations; + QuestRelations mCreatureQuestInvolvedRelations; + + void LoadGameObjectScripts(); + void LoadQuestEndScripts(); + void LoadQuestStartScripts(); + void LoadEventScripts(); + void LoadSpellScripts(); + void LoadGossipScripts(); + void LoadWaypointScripts(); + + void LoadTransportEvents(); + + bool LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value); + bool LoadTrinityStrings() { return LoadTrinityStrings(WorldDatabase,"trinity_string",MIN_TRINITY_STRING_ID,MAX_TRINITY_STRING_ID); } + void LoadDbScriptStrings(); + void LoadCreatureClassLevelStats(); + void LoadCreatureLocales(); + void LoadCreatureTemplates(); + void CheckCreatureTemplate(CreatureInfo const* cInfo); + void LoadCreatures(); + void LoadCreatureLinkedRespawn(); + bool CheckCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid) const; + bool SetCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid); + void LoadCreatureRespawnTimes(); + void LoadCreatureAddons(); + void LoadCreatureModelInfo(); + void LoadEquipmentTemplates(); + void LoadGameObjectLocales(); + void LoadGameobjects(); + void LoadGameobjectRespawnTimes(); + void LoadItemPrototypes(); + void LoadItemLocales(); + void LoadQuestLocales(); + void LoadNpcTextLocales(); + void LoadPageTextLocales(); + void LoadGossipMenuItemsLocales(); + void LoadPointOfInterestLocales(); + void LoadInstanceTemplate(); + void LoadMailLevelRewards(); + void LoadVehicleAccessories(); + + void LoadGossipText(); + + void LoadAreaTriggerTeleports(); + void LoadAccessRequirements(); + void LoadQuestAreaTriggers(); + void LoadAreaTriggerScripts(); + void LoadTavernAreaTriggers(); + void LoadGameObjectForQuests(); + + void LoadPageTexts(); + + void LoadPlayerInfo(); + void LoadPetLevelInfo(); + void LoadExplorationBaseXP(); + void LoadPetNames(); + void LoadPetNumber(); + void LoadCorpses(); + void LoadFishingBaseSkillLevel(); + + void LoadReputationOnKill(); + void LoadPointsOfInterest(); + void LoadQuestPOI(); + + void LoadNPCSpellClickSpells(); + + void LoadWeatherZoneChances(); + void LoadGameTele(); + + void LoadNpcTextId(); + + void LoadGossipMenu(); + void LoadGossipMenuItems(); + + void LoadVendors(); + void LoadTrainerSpell(); + bool AddSpellToTrainer(uint32 entry, uint32 spell, Field *fields, std::set *skip_trainers, std::set *talentIds); + int LoadReferenceTrainer(uint32 trainer, int32 spell, std::set *skip_trainers, std::set *talentIds); + void LoadGMTickets(); + + std::string GeneratePetName(uint32 entry); + uint32 GetBaseXP(uint8 level); + uint32 GetXPForLevel(uint8 level); + + int32 GetFishingBaseSkillLevel(uint32 entry) const + { + FishingBaseSkillMap::const_iterator itr = mFishingBaseForArea.find(entry); + return itr != mFishingBaseForArea.end() ? itr->second : 0; + } + + void ReturnOrDeleteOldMails(bool serverUp); + + CreatureBaseStats const* GetCreatureBaseStats(uint8 level, uint8 unitClass); + + void SetHighestGuids(); + uint32 GenerateLowGuid(HighGuid guidhigh); + uint32 GenerateArenaTeamId(); + uint32 GenerateAuctionID(); + uint64 GenerateEquipmentSetGuid(); + uint32 GenerateGuildId(); + uint32 GenerateMailID(); + uint32 GeneratePetNumber(); + + typedef std::multimap ExclusiveQuestGroups; + ExclusiveQuestGroups mExclusiveQuestGroups; + + MailLevelReward const* GetMailLevelReward(uint32 level,uint32 raceMask) + { + MailLevelRewardMap::const_iterator map_itr = m_mailLevelRewardMap.find(level); + if (map_itr == m_mailLevelRewardMap.end()) + return NULL; + + for (MailLevelRewardList::const_iterator set_itr = map_itr->second.begin(); set_itr != map_itr->second.end(); ++set_itr) + if (set_itr->raceMask & raceMask) + return &*set_itr; + + return NULL; + } + + WeatherZoneChances const* GetWeatherChances(uint32 zone_id) const + { + WeatherZoneMap::const_iterator itr = mWeatherZoneMap.find(zone_id); + if (itr != mWeatherZoneMap.end()) + return &itr->second; + else + return NULL; + } + + CellObjectGuids const& GetCellObjectGuids(uint16 mapid, uint8 spawnMode, uint32 cell_id) + { + return mMapObjectGuids[MAKE_PAIR32(mapid,spawnMode)][cell_id]; + } + + CreatureData const* GetCreatureData(uint32 guid) const + { + CreatureDataMap::const_iterator itr = mCreatureDataMap.find(guid); + if (itr == mCreatureDataMap.end()) return NULL; + return &itr->second; + } + CreatureData& NewOrExistCreatureData(uint32 guid) { return mCreatureDataMap[guid]; } + void DeleteCreatureData(uint32 guid); + uint32 GetLinkedRespawnGuid(uint32 guid) const + { + CreatureLinkedRespawnMap::const_iterator itr = mCreatureLinkedRespawnMap.find(guid); + if (itr == mCreatureLinkedRespawnMap.end()) return 0; + return itr->second; + } + CreatureLocale const* GetCreatureLocale(uint32 entry) const + { + CreatureLocaleMap::const_iterator itr = mCreatureLocaleMap.find(entry); + if (itr == mCreatureLocaleMap.end()) return NULL; + return &itr->second; + } + GameObjectLocale const* GetGameObjectLocale(uint32 entry) const + { + GameObjectLocaleMap::const_iterator itr = mGameObjectLocaleMap.find(entry); + if (itr == mGameObjectLocaleMap.end()) return NULL; + return &itr->second; + } + ItemLocale const* GetItemLocale(uint32 entry) const + { + ItemLocaleMap::const_iterator itr = mItemLocaleMap.find(entry); + if (itr == mItemLocaleMap.end()) return NULL; + return &itr->second; + } + QuestLocale const* GetQuestLocale(uint32 entry) const + { + QuestLocaleMap::const_iterator itr = mQuestLocaleMap.find(entry); + if (itr == mQuestLocaleMap.end()) return NULL; + return &itr->second; + } + NpcTextLocale const* GetNpcTextLocale(uint32 entry) const + { + NpcTextLocaleMap::const_iterator itr = mNpcTextLocaleMap.find(entry); + if (itr == mNpcTextLocaleMap.end()) return NULL; + return &itr->second; + } + PageTextLocale const* GetPageTextLocale(uint32 entry) const + { + PageTextLocaleMap::const_iterator itr = mPageTextLocaleMap.find(entry); + if (itr == mPageTextLocaleMap.end()) return NULL; + return &itr->second; + } + GossipMenuItemsLocale const* GetGossipMenuItemsLocale(uint32 entry) const + { + GossipMenuItemsLocaleMap::const_iterator itr = mGossipMenuItemsLocaleMap.find(entry); + if (itr == mGossipMenuItemsLocaleMap.end()) return NULL; + return &itr->second; + } + PointOfInterestLocale const* GetPointOfInterestLocale(uint32 poi_id) const + { + PointOfInterestLocaleMap::const_iterator itr = mPointOfInterestLocaleMap.find(poi_id); + if (itr == mPointOfInterestLocaleMap.end()) return NULL; + return &itr->second; + } + + bool IsGoOfSpecificEntrySpawned(uint32 entry) const + { + for (GameObjectDataMap::const_iterator it = mGameObjectDataMap.begin(); it != mGameObjectDataMap.end(); ++it) + if (it->second.id == entry) + return true; + + return false; + } + + GameObjectData const* GetGOData(uint32 guid) const + { + GameObjectDataMap::const_iterator itr = mGameObjectDataMap.find(guid); + if (itr == mGameObjectDataMap.end()) return NULL; + return &itr->second; + } + GameObjectData& NewGOData(uint32 guid) { return mGameObjectDataMap[guid]; } + void DeleteGOData(uint32 guid); + + TrinityStringLocale const* GetTrinityStringLocale(int32 entry) const + { + TrinityStringLocaleMap::const_iterator itr = mTrinityStringLocaleMap.find(entry); + if (itr == mTrinityStringLocaleMap.end()) return NULL; + return &itr->second; + } + const char *GetTrinityString(int32 entry, int locale_idx) const; + const char *GetTrinityStringForDBCLocale(int32 entry) const { return GetTrinityString(entry,DBCLocaleIndex); } + int32 GetDBCLocaleIndex() const { return DBCLocaleIndex; } + void SetDBCLocaleIndex(uint32 lang) { DBCLocaleIndex = GetIndexForLocale(LocaleConstant(lang)); } + + void AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance); + void DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid); + + time_t GetCreatureRespawnTime(uint32 loguid, uint32 instance) { return mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)]; } + void SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t); + time_t GetGORespawnTime(uint32 loguid, uint32 instance) { return mGORespawnTimes[MAKE_PAIR64(loguid,instance)]; } + void SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t); + void DeleteRespawnTimeForInstance(uint32 instance); + + // grid objects + void AddCreatureToGrid(uint32 guid, CreatureData const* data); + void RemoveCreatureFromGrid(uint32 guid, CreatureData const* data); + void AddGameobjectToGrid(uint32 guid, GameObjectData const* data); + void RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data); + uint32 AddGOData(uint32 entry, uint32 map, float x, float y, float z, float o, uint32 spawntimedelay = 0, float rotation0 = 0, float rotation1 = 0, float rotation2 = 0, float rotation3 = 0); + uint32 AddCreData(uint32 entry, uint32 team, uint32 map, float x, float y, float z, float o, uint32 spawntimedelay = 0); + bool MoveCreData(uint32 guid, uint32 map, Position pos); + + // reserved names + void LoadReservedPlayersNames(); + bool IsReservedName(const std::string& name) const; + + // name with valid structure and symbols + static uint8 CheckPlayerName(const std::string& name, bool create = false); + static PetNameInvalidReason CheckPetName(const std::string& name); + static bool IsValidCharterName(const std::string& name); + + static bool CheckDeclinedNames(std::wstring mainpart, DeclinedName const& names); + + void LoadSpellDisabledEntrys(); + bool IsPlayerSpellDisabled(uint32 spellid) { return (m_DisabledPlayerSpells.count(spellid) != 0); } + bool IsCreatureSpellDisabled(uint32 spellid) { return (m_DisabledCreatureSpells.count(spellid) != 0); } + bool IsPetSpellDisabled(uint32 spellid) { return (m_DisabledPetSpells.count(spellid) != 0); } + + int GetIndexForLocale(LocaleConstant loc); + LocaleConstant GetLocaleForIndex(int i); + + GameTele const* GetGameTele(uint32 id) const + { + GameTeleMap::const_iterator itr = m_GameTeleMap.find(id); + if (itr == m_GameTeleMap.end()) return NULL; + return &itr->second; + } + GameTele const* GetGameTele(const std::string& name) const; + GameTeleMap const& GetGameTeleMap() const { return m_GameTeleMap; } + bool AddGameTele(GameTele& data); + bool DeleteGameTele(const std::string& name); + + uint32 GetNpcGossip(uint32 entry) const + { + CacheNpcTextIdMap::const_iterator iter = m_mCacheNpcTextIdMap.find(entry); + if (iter == m_mCacheNpcTextIdMap.end()) + return 0; + + return iter->second; + } + + TrainerSpellData const* GetNpcTrainerSpells(uint32 entry) const + { + CacheTrainerSpellMap::const_iterator iter = m_mCacheTrainerSpellMap.find(entry); + if (iter == m_mCacheTrainerSpellMap.end()) + return NULL; + + return &iter->second; + } + + VendorItemData const* GetNpcVendorItemList(uint32 entry) const + { + CacheVendorItemMap::const_iterator iter = m_mCacheVendorItemMap.find(entry); + if (iter == m_mCacheVendorItemMap.end()) + return NULL; + + return &iter->second; + } + void AddVendorItem(uint32 entry,uint32 item, int32 maxcount, uint32 incrtime, uint32 ExtendedCost, bool savetodb = true); // for event + bool RemoveVendorItem(uint32 entry,uint32 item, bool savetodb = true); // for event + bool IsVendorItemValid(uint32 vendor_entry, uint32 item, int32 maxcount, uint32 ptime, uint32 ExtendedCost, Player* pl = NULL, std::set* skip_vendors = NULL, uint32 ORnpcflag = 0) const; + + void LoadScriptNames(); + ScriptNameMap &GetScriptNames() { return m_scriptNames; } + const char * GetScriptName(uint32 id) { return id < m_scriptNames.size() ? m_scriptNames[id].c_str() : ""; } + uint32 GetScriptId(const char *name); + + int GetOrNewIndexForLocale(LocaleConstant loc); + + SpellClickInfoMapBounds GetSpellClickInfoMapBounds(uint32 creature_id) const + { + return SpellClickInfoMapBounds(mSpellClickInfoMap.lower_bound(creature_id),mSpellClickInfoMap.upper_bound(creature_id)); + } + + GM_Ticket *GetGMTicket(uint64 ticketGuid) + { + for (GmTicketList::const_iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i) + if ((*i) && (*i)->guid == ticketGuid) + return (*i); + + return NULL; + } + GM_Ticket *GetGMTicketByPlayer(uint64 playerGuid) + { + for (GmTicketList::const_iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i) + if ((*i) && (*i)->playerGuid == playerGuid && (*i)->closed == 0) + return (*i); + + return NULL; + } + + GossipMenusMapBounds GetGossipMenusMapBounds(uint32 uiMenuId) const + { + return GossipMenusMapBounds(m_mGossipMenusMap.lower_bound(uiMenuId),m_mGossipMenusMap.upper_bound(uiMenuId)); + } + + GossipMenusMapBoundsNonConst GetGossipMenusMapBoundsNonConst(uint32 uiMenuId) + { + return GossipMenusMapBoundsNonConst(m_mGossipMenusMap.lower_bound(uiMenuId),m_mGossipMenusMap.upper_bound(uiMenuId)); + } + + GossipMenuItemsMapBounds GetGossipMenuItemsMapBounds(uint32 uiMenuId) const + { + return GossipMenuItemsMapBounds(m_mGossipMenuItemsMap.lower_bound(uiMenuId),m_mGossipMenuItemsMap.upper_bound(uiMenuId)); + } + GossipMenuItemsMapBoundsNonConst GetGossipMenuItemsMapBoundsNonConst(uint32 uiMenuId) + { + return GossipMenuItemsMapBoundsNonConst(m_mGossipMenuItemsMap.lower_bound(uiMenuId),m_mGossipMenuItemsMap.upper_bound(uiMenuId)); + } + + void AddOrUpdateGMTicket(GM_Ticket &ticket, bool create = false); + void _AddOrUpdateGMTicket(GM_Ticket &ticket); + void RemoveGMTicket(uint64 ticketGuid, int64 source = -1, bool permanently = false); + void RemoveGMTicket(GM_Ticket *ticket, int64 source = -1, bool permanently = false); + GmTicketList m_GMTicketList; + uint64 GenerateGMTicketId(); + + // for wintergrasp only + GraveYardMap mGraveYardMap; + protected: + + // first free id for selected id type + uint32 m_arenaTeamId; + uint32 m_auctionid; + uint64 m_equipmentSetGuid; + uint32 m_guildId; + uint32 m_ItemTextId; + uint32 m_mailid; + uint32 m_hiPetNumber; + uint64 m_GMticketid; + + // first free low guid for seelcted guid type + uint32 m_hiCharGuid; + uint32 m_hiCreatureGuid; + uint32 m_hiPetGuid; + uint32 m_hiVehicleGuid; + uint32 m_hiItemGuid; + uint32 m_hiGoGuid; + uint32 m_hiDoGuid; + uint32 m_hiCorpseGuid; + uint32 m_hiGroupGuid; + + QuestMap mQuestTemplates; + + typedef UNORDERED_MAP GossipTextMap; + typedef UNORDERED_MAP QuestAreaTriggerMap; + typedef std::set TavernAreaTriggerSet; + typedef std::set GameObjectForQuestSet; + + GroupSet mGroupSet; + GuildMap mGuildMap; + ArenaTeamMap mArenaTeamMap; + + QuestAreaTriggerMap mQuestAreaTriggerMap; + TavernAreaTriggerSet mTavernAreaTriggerSet; + GameObjectForQuestSet mGameObjectForQuestSet; + GossipTextMap mGossipText; + AreaTriggerMap mAreaTriggers; + AreaTriggerScriptMap mAreaTriggerScripts; + AccessRequirementMap mAccessRequirements; + + RepOnKillMap mRepOnKill; + + GossipMenusMap m_mGossipMenusMap; + GossipMenuItemsMap m_mGossipMenuItemsMap; + PointOfInterestMap mPointsOfInterest; + + QuestPOIMap mQuestPOIMap; + + WeatherZoneMap mWeatherZoneMap; + + //character reserved names + typedef std::set ReservedNamesMap; + ReservedNamesMap m_ReservedNames; + + std::set m_DisabledPlayerSpells; + std::set m_DisabledCreatureSpells; + std::set m_DisabledPetSpells; + +// GraveYardMap mGraveYardMap; + + GameTeleMap m_GameTeleMap; + + ScriptNameMap m_scriptNames; + + SpellClickInfoMap mSpellClickInfoMap; + + ItemRequiredTargetMap m_ItemRequiredTarget; + + VehicleAccessoryMap m_VehicleAccessoryMap; + + typedef std::vector LocalForIndex; + LocalForIndex m_LocalForIndex; + + int DBCLocaleIndex; + + private: + void LoadScripts(ScriptMapMap& scripts, char const* tablename); + void CheckScripts(ScriptMapMap const& scripts,std::set& ids); + void LoadCreatureAddons(SQLStorage& creatureaddons, char const* entryName, char const* comment); + void ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr); + void LoadQuestRelationsHelper(QuestRelations& map,char const* table); + + MailLevelRewardMap m_mailLevelRewardMap; + + CreatureBaseStatsMap m_creatureBaseStatsMap; + + typedef std::map PetLevelInfoMap; + // PetLevelInfoMap[creature_id][level] + PetLevelInfoMap petInfo; // [creature_id][level] + + PlayerClassInfo playerClassInfo[MAX_CLASSES]; + + void BuildPlayerLevelInfo(uint8 race, uint8 class_, uint8 level, PlayerLevelInfo* plinfo) const; + PlayerInfo playerInfo[MAX_RACES][MAX_CLASSES]; + + typedef std::vector PlayerXPperLevel; // [level] + PlayerXPperLevel mPlayerXPperLevel; + + typedef std::map BaseXPMap; // [area level][base xp] + BaseXPMap mBaseXPTable; + + typedef std::map FishingBaseSkillMap; // [areaId][base skill level] + FishingBaseSkillMap mFishingBaseForArea; + + typedef std::map > HalfNameMap; + HalfNameMap PetHalfName0; + HalfNameMap PetHalfName1; + + MapObjectGuids mMapObjectGuids; + CreatureDataMap mCreatureDataMap; + CreatureLinkedRespawnMap mCreatureLinkedRespawnMap; + CreatureLocaleMap mCreatureLocaleMap; + GameObjectDataMap mGameObjectDataMap; + GameObjectLocaleMap mGameObjectLocaleMap; + ItemLocaleMap mItemLocaleMap; + QuestLocaleMap mQuestLocaleMap; + NpcTextLocaleMap mNpcTextLocaleMap; + PageTextLocaleMap mPageTextLocaleMap; + TrinityStringLocaleMap mTrinityStringLocaleMap; + GossipMenuItemsLocaleMap mGossipMenuItemsLocaleMap; + PointOfInterestLocaleMap mPointOfInterestLocaleMap; + RespawnTimes mCreatureRespawnTimes; + RespawnTimes mGORespawnTimes; + + CacheNpcTextIdMap m_mCacheNpcTextIdMap; + CacheVendorItemMap m_mCacheVendorItemMap; + CacheTrainerSpellMap m_mCacheTrainerSpellMap; + + std::set difficultyEntries[MAX_DIFFICULTY - 1]; // already loaded difficulty 1 value in creatures, used in CheckCreatureTemplate + std::set hasDifficultyEntries[MAX_DIFFICULTY - 1]; // already loaded creatures with difficulty 1 values, used in CheckCreatureTemplate + +}; + +#define objmgr Trinity::Singleton::Instance() + +// scripting access functions + bool LoadTrinityStrings(DatabaseType& db, char const* table,int32 start_value = MAX_CREATURE_AI_TEXT_STRING_ID, int32 end_value = std::numeric_limits::min()); + uint32 GetAreaTriggerScriptId(uint32 trigger_id); + uint32 GetScriptId(const char *name); + ObjectMgr::ScriptNameMap& GetScriptNames(); + GameObjectInfo const *GetGameObjectInfo(uint32 id); + CreatureInfo const *GetCreatureInfo(uint32 id); + CreatureInfo const* GetCreatureTemplateStore(uint32 entry); + Quest const* GetQuestTemplateStore(uint32 entry); + +#endif diff --git a/src/server/game/Globals/SharedDefines.h b/src/server/game/Globals/SharedDefines.h deleted file mode 100644 index 903dd4b09ca..00000000000 --- a/src/server/game/Globals/SharedDefines.h +++ /dev/null @@ -1,2772 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_SHAREDDEFINES_H -#define TRINITY_SHAREDDEFINES_H - -#include "Platform/Define.h" -#include - -// loot modes for creatures and gameobjects, bitmask! -enum LootModes -{ - LOOT_MODE_DEFAULT = 1, - LOOT_MODE_HARD_MODE_1 = 2, - LOOT_MODE_HARD_MODE_2 = 4, - LOOT_MODE_HARD_MODE_3 = 8, - LOOT_MODE_HARD_MODE_4 = 16 -}; - -enum Gender -{ - GENDER_MALE = 0, - GENDER_FEMALE = 1, - GENDER_NONE = 2 -}; - -// Race value is index in ChrRaces.dbc -enum Races -{ - RACE_HUMAN = 1, - RACE_ORC = 2, - RACE_DWARF = 3, - RACE_NIGHTELF = 4, - RACE_UNDEAD_PLAYER = 5, - RACE_TAUREN = 6, - RACE_GNOME = 7, - RACE_TROLL = 8, - //RACE_GOBLIN = 9, - RACE_BLOODELF = 10, - RACE_DRAENEI = 11 - //RACE_FEL_ORC = 12, - //RACE_NAGA = 13, - //RACE_BROKEN = 14, - //RACE_SKELETON = 15, - //RACE_VRYKUL = 16, - //RACE_TUSKARR = 17, - //RACE_FOREST_TROLL = 18, - //RACE_TAUNKA = 19, - //RACE_NORTHREND_SKELETON = 20, - //RACE_ICE_TROLL = 21 -}; - -// max+1 for player race -#define MAX_RACES 12 - -#define RACEMASK_ALL_PLAYABLE \ - ((1<<(RACE_HUMAN-1)) |(1<<(RACE_ORC-1)) |(1<<(RACE_DWARF-1)) | \ - (1<<(RACE_NIGHTELF-1))|(1<<(RACE_UNDEAD_PLAYER-1))|(1<<(RACE_TAUREN-1)) | \ - (1<<(RACE_GNOME-1)) |(1<<(RACE_TROLL-1)) |(1<<(RACE_BLOODELF-1))| \ - (1<<(RACE_DRAENEI-1))) - -// Class value is index in ChrClasses.dbc -enum Classes -{ - CLASS_WARRIOR = 1, - CLASS_PALADIN = 2, - CLASS_HUNTER = 3, - CLASS_ROGUE = 4, - CLASS_PRIEST = 5, - CLASS_DEATH_KNIGHT = 6, - CLASS_SHAMAN = 7, - CLASS_MAGE = 8, - CLASS_WARLOCK = 9, - //CLASS_UNK = 10, - CLASS_DRUID = 11 -}; - -// max+1 for player class -#define MAX_CLASSES 12 - -#define CLASSMASK_ALL_PLAYABLE \ - ((1<<(CLASS_WARRIOR-1))|(1<<(CLASS_PALADIN-1))|(1<<(CLASS_HUNTER-1))| \ - (1<<(CLASS_ROGUE-1)) |(1<<(CLASS_PRIEST-1)) |(1<<(CLASS_SHAMAN-1))| \ - (1<<(CLASS_MAGE-1)) |(1<<(CLASS_WARLOCK-1))|(1<<(CLASS_DRUID-1)) | \ - (1<<(CLASS_DEATH_KNIGHT-1))) - -// valid classes for creature_template.unit_class -enum UnitClass -{ - UNIT_CLASS_WARRIOR = 1, - UNIT_CLASS_PALADIN = 2, - UNIT_CLASS_ROGUE = 4, - UNIT_CLASS_MAGE = 8, -}; - -#define CLASSMASK_ALL_CREATURES ((1<<(UNIT_CLASS_WARRIOR-1)) | (1<<(UNIT_CLASS_PALADIN-1)) | (1<<(UNIT_CLASS_ROGUE-1)) | (1<<(UNIT_CLASS_MAGE-1))) - -#define CLASSMASK_WAND_USERS ((1<<(CLASS_PRIEST-1))|(1<<(CLASS_MAGE-1))|(1<<(CLASS_WARLOCK-1))) - -#define PLAYER_MAX_BATTLEGROUND_QUEUES 2 - -enum ReputationRank -{ - REP_HATED = 0, - REP_HOSTILE = 1, - REP_UNFRIENDLY = 2, - REP_NEUTRAL = 3, - REP_FRIENDLY = 4, - REP_HONORED = 5, - REP_REVERED = 6, - REP_EXALTED = 7 -}; - -#define MIN_REPUTATION_RANK (REP_HATED) -#define MAX_REPUTATION_RANK 8 - -enum MoneyConstants -{ - COPPER = 1, - SILVER = COPPER*100, - GOLD = SILVER*100 -}; - -enum Stats -{ - STAT_STRENGTH = 0, - STAT_AGILITY = 1, - STAT_STAMINA = 2, - STAT_INTELLECT = 3, - STAT_SPIRIT = 4 -}; - -#define MAX_STATS 5 - -enum Powers -{ - POWER_MANA = 0, - POWER_RAGE = 1, - POWER_FOCUS = 2, - POWER_ENERGY = 3, - POWER_HAPPINESS = 4, - POWER_RUNE = 5, - POWER_RUNIC_POWER = 6, - MAX_POWERS = 7, - POWER_ALL = 127, // default for class? - POWER_HEALTH = 0xFFFFFFFE // (-2 as signed value) -}; - -enum SpellSchools -{ - SPELL_SCHOOL_NORMAL = 0, - SPELL_SCHOOL_HOLY = 1, - SPELL_SCHOOL_FIRE = 2, - SPELL_SCHOOL_NATURE = 3, - SPELL_SCHOOL_FROST = 4, - SPELL_SCHOOL_SHADOW = 5, - SPELL_SCHOOL_ARCANE = 6 -}; - -#define MAX_SPELL_SCHOOL 7 - -enum SpellSchoolMask -{ - SPELL_SCHOOL_MASK_NONE = 0x00, // not exist - SPELL_SCHOOL_MASK_NORMAL = (1 << SPELL_SCHOOL_NORMAL), // PHYSICAL (Armor) - SPELL_SCHOOL_MASK_HOLY = (1 << SPELL_SCHOOL_HOLY), - SPELL_SCHOOL_MASK_FIRE = (1 << SPELL_SCHOOL_FIRE), - SPELL_SCHOOL_MASK_NATURE = (1 << SPELL_SCHOOL_NATURE), - SPELL_SCHOOL_MASK_FROST = (1 << SPELL_SCHOOL_FROST), - SPELL_SCHOOL_MASK_SHADOW = (1 << SPELL_SCHOOL_SHADOW), - SPELL_SCHOOL_MASK_ARCANE = (1 << SPELL_SCHOOL_ARCANE), - - // unions - - // 124, not include normal and holy damage - SPELL_SCHOOL_MASK_SPELL = (SPELL_SCHOOL_MASK_FIRE | - SPELL_SCHOOL_MASK_NATURE | SPELL_SCHOOL_MASK_FROST | - SPELL_SCHOOL_MASK_SHADOW | SPELL_SCHOOL_MASK_ARCANE), - // 126 - SPELL_SCHOOL_MASK_MAGIC = (SPELL_SCHOOL_MASK_HOLY | SPELL_SCHOOL_MASK_SPELL), - - // 127 - SPELL_SCHOOL_MASK_ALL = (SPELL_SCHOOL_MASK_NORMAL | SPELL_SCHOOL_MASK_MAGIC) -}; - -inline SpellSchools GetFirstSchoolInMask(SpellSchoolMask mask) -{ - for (int i = 0; i < MAX_SPELL_SCHOOL; ++i) - if (mask & (1 << i)) - return SpellSchools(i); - - return SPELL_SCHOOL_NORMAL; -} - -enum ItemQualities -{ - ITEM_QUALITY_POOR = 0, //GREY - ITEM_QUALITY_NORMAL = 1, //WHITE - ITEM_QUALITY_UNCOMMON = 2, //GREEN - ITEM_QUALITY_RARE = 3, //BLUE - ITEM_QUALITY_EPIC = 4, //PURPLE - ITEM_QUALITY_LEGENDARY = 5, //ORANGE - ITEM_QUALITY_ARTIFACT = 6, //LIGHT YELLOW - ITEM_QUALITY_HEIRLOOM = 7 -}; - -#define MAX_ITEM_QUALITY 8 - -enum SpellCategory -{ - SPELL_CATEGORY_FOOD = 11, - SPELL_CATEGORY_DRINK = 59, -}; - -const uint32 ItemQualityColors[MAX_ITEM_QUALITY] = { - 0xff9d9d9d, //GREY - 0xffffffff, //WHITE - 0xff1eff00, //GREEN - 0xff0070dd, //BLUE - 0xffa335ee, //PURPLE - 0xffff8000, //ORANGE - 0xffe6cc80, //LIGHT YELLOW - 0xffe6cc80 //LIGHT YELLOW -}; - -// *********************************** -// Spell Attributes definitions -// *********************************** - -#define SPELL_ATTR_UNK0 0x00000001 // 0 -#define SPELL_ATTR_REQ_AMMO 0x00000002 // 1 -#define SPELL_ATTR_ON_NEXT_SWING 0x00000004 // 2 on next swing -#define SPELL_ATTR_UNK3 0x00000008 // 3 not set in 3.0.3 -#define SPELL_ATTR_UNK4 0x00000010 // 4 -#define SPELL_ATTR_TRADESPELL 0x00000020 // 5 trade spells, will be added by client to a sublist of profession spell -#define SPELL_ATTR_PASSIVE 0x00000040 // 6 Passive spell -#define SPELL_ATTR_UNK7 0x00000080 // 7 visible? -#define SPELL_ATTR_UNK8 0x00000100 // 8 -#define SPELL_ATTR_UNK9 0x00000200 // 9 -#define SPELL_ATTR_UNK10 0x00000400 // 10 on next swing 2 -#define SPELL_ATTR_UNK11 0x00000800 // 11 -#define SPELL_ATTR_DAYTIME_ONLY 0x00001000 // 12 only useable at daytime, not set in 2.4.2 -#define SPELL_ATTR_NIGHT_ONLY 0x00002000 // 13 only useable at night, not set in 2.4.2 -#define SPELL_ATTR_INDOORS_ONLY 0x00004000 // 14 only useable indoors, not set in 2.4.2 -#define SPELL_ATTR_OUTDOORS_ONLY 0x00008000 // 15 Only useable outdoors. -#define SPELL_ATTR_NOT_SHAPESHIFT 0x00010000 // 16 Not while shapeshifted -#define SPELL_ATTR_ONLY_STEALTHED 0x00020000 // 17 Must be in stealth -#define SPELL_ATTR_UNK18 0x00040000 // 18 -#define SPELL_ATTR_LEVEL_DAMAGE_CALCULATION 0x00080000 // 19 spelldamage depends on caster level -#define SPELL_ATTR_STOP_ATTACK_TARGET 0x00100000 // 20 Stop attack after use this spell (and not begin attack if use) -#define SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK 0x00200000 // 21 Cannot be dodged/parried/blocked -#define SPELL_ATTR_UNK22 0x00400000 // 22 shoot spells -#define SPELL_ATTR_CASTABLE_WHILE_DEAD 0x00800000 // 23 castable while dead? -#define SPELL_ATTR_CASTABLE_WHILE_MOUNTED 0x01000000 // 24 castable while mounted -#define SPELL_ATTR_DISABLED_WHILE_ACTIVE 0x02000000 // 25 Activate and start cooldown after aura fade or remove summoned creature or go -#define SPELL_ATTR_NEGATIVE_1 0x04000000 // 26 Many negative spells have this attr -#define SPELL_ATTR_CASTABLE_WHILE_SITTING 0x08000000 // 27 castable while sitting -#define SPELL_ATTR_CANT_USED_IN_COMBAT 0x10000000 // 28 Cannot be used in combat -#define SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY 0x20000000 // 29 unaffected by invulnerability (hmm possible not...) -#define SPELL_ATTR_BREAKABLE_BY_DAMAGE 0x40000000 // 30 -#define SPELL_ATTR_CANT_CANCEL 0x80000000 // 31 positive aura can't be canceled - -#define SPELL_ATTR_EX_DISMISS_PET 0x00000001 // 0 dismiss pet and not allow to summon new one? -#define SPELL_ATTR_EX_DRAIN_ALL_POWER 0x00000002 // 1 use all power (Only paladin Lay of Hands and Bunyanize) -#define SPELL_ATTR_EX_CHANNELED_1 0x00000004 // 2 channeled target -#define SPELL_ATTR_EX_PUT_CASTER_IN_COMBAT 0x00000008 // 3 spells that cause a caster to enter a combat -#define SPELL_ATTR_EX_UNK4 0x00000010 // 4 stealth and whirlwind -#define SPELL_ATTR_EX_NOT_BREAK_STEALTH 0x00000020 // 5 Not break stealth -#define SPELL_ATTR_EX_CHANNELED_2 0x00000040 // 6 channeled self -#define SPELL_ATTR_EX_NEGATIVE 0x00000080 // 7 -#define SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET 0x00000100 // 8 Spell req target not to be in combat state -#define SPELL_ATTR_EX_UNK9 0x00000200 // 9 melee spells -#define SPELL_ATTR_EX_UNK10 0x00000400 // 10 no generates threat on cast 100%? (old NO_INITIAL_AGGRO) -#define SPELL_ATTR_EX_UNK11 0x00000800 // 11 aura -#define SPELL_ATTR_EX_UNK12 0x00001000 // 12 -#define SPELL_ATTR_EX_UNK13 0x00002000 // 13 -#define SPELL_ATTR_EX_STACK_FOR_DIFF_CASTERS 0x00004000 // 14 -#define SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY 0x00008000 // 15 remove auras on immunity -#define SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE 0x00010000 // 16 on immuniy -#define SPELL_ATTR_EX_UNAUTOCASTABLE_BY_PET 0x00020000 // 17 -#define SPELL_ATTR_EX_UNK18 0x00040000 // 18 -#define SPELL_ATTR_EX_CANT_TARGET_SELF 0x00080000 // 19 Applies only to unit target - for example Divine Intervention (19752) -#define SPELL_ATTR_EX_REQ_COMBO_POINTS1 0x00100000 // 20 Req combo points on target -#define SPELL_ATTR_EX_UNK21 0x00200000 // 21 -#define SPELL_ATTR_EX_REQ_COMBO_POINTS2 0x00400000 // 22 Req combo points on target -#define SPELL_ATTR_EX_UNK23 0x00800000 // 23 -#define SPELL_ATTR_EX_UNK24 0x01000000 // 24 Req fishing pole?? -#define SPELL_ATTR_EX_UNK25 0x02000000 // 25 -#define SPELL_ATTR_EX_UNK26 0x04000000 // 26 works correctly with [target=focus] and [target=mouseover] macros? -#define SPELL_ATTR_EX_UNK27 0x08000000 // 27 -#define SPELL_ATTR_EX_IGNORE_IMMUNITY 0x10000000 // 28 removed from Chains of Ice 3.3.0 -#define SPELL_ATTR_EX_UNK29 0x20000000 // 29 -#define SPELL_ATTR_EX_ENABLE_AT_DODGE 0x40000000 // 30 Overpower, Wolverine Bite -#define SPELL_ATTR_EX_UNK31 0x80000000 // 31 - -#define SPELL_ATTR_EX2_UNK0 0x00000001 // 0 -#define SPELL_ATTR_EX2_UNK1 0x00000002 // 1 ? many triggered spells have this flag -#define SPELL_ATTR_EX2_CANT_REFLECTED 0x00000004 // 2 ? used for detect can or not spell reflected -#define SPELL_ATTR_EX2_UNK3 0x00000008 // 3 -#define SPELL_ATTR_EX2_UNK4 0x00000010 // 4 -#define SPELL_ATTR_EX2_AUTOREPEAT_FLAG 0x00000020 // 5 -#define SPELL_ATTR_EX2_UNK6 0x00000040 // 6 -#define SPELL_ATTR_EX2_UNK7 0x00000080 // 7 -#define SPELL_ATTR_EX2_UNK8 0x00000100 // 8 not set in 3.0.3 -#define SPELL_ATTR_EX2_UNK9 0x00000200 // 9 -#define SPELL_ATTR_EX2_UNK10 0x00000400 // 10 -#define SPELL_ATTR_EX2_HEALTH_FUNNEL 0x00000800 // 11 -#define SPELL_ATTR_EX2_UNK12 0x00001000 // 12 -#define SPELL_ATTR_EX2_UNK13 0x00002000 // 13 Items enchanted by spells with this flag preserve the enchant to arenas -#define SPELL_ATTR_EX2_UNK14 0x00004000 // 14 -#define SPELL_ATTR_EX2_UNK15 0x00008000 // 15 not set in 3.0.3 -#define SPELL_ATTR_EX2_TAME_BEAST 0x00010000 // 16 -#define SPELL_ATTR_EX2_NOT_RESET_AUTOSHOT 0x00020000 // 17 Hunters Shot and Stings only have this flag -#define SPELL_ATTR_EX2_UNK18 0x00040000 // 18 Only Revive pet - possible req dead pet -#define SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT 0x00080000 // 19 does not necessarly need shapeshift -#define SPELL_ATTR_EX2_UNK20 0x00100000 // 20 -#define SPELL_ATTR_EX2_DAMAGE_REDUCED_SHIELD 0x00200000 // 21 for ice blocks, pala immunity buffs, priest absorb shields, but used also for other spells -> not sure! -#define SPELL_ATTR_EX2_UNK22 0x00400000 // 22 -#define SPELL_ATTR_EX2_UNK23 0x00800000 // 23 Only mage Arcane Concentration have this flag -#define SPELL_ATTR_EX2_UNK24 0x01000000 // 24 -#define SPELL_ATTR_EX2_UNK25 0x02000000 // 25 -#define SPELL_ATTR_EX2_UNK26 0x04000000 // 26 unaffected by school immunity -#define SPELL_ATTR_EX2_UNK27 0x08000000 // 27 -#define SPELL_ATTR_EX2_UNK28 0x10000000 // 28 no breaks stealth if it fails?? -#define SPELL_ATTR_EX2_CANT_CRIT 0x20000000 // 29 Spell can't crit -#define SPELL_ATTR_EX2_TRIGGERED_CAN_TRIGGER 0x40000000 // 30 spell can trigger even if triggered -#define SPELL_ATTR_EX2_FOOD_BUFF 0x80000000 // 31 Food or Drink Buff (like Well Fed) - -#define SPELL_ATTR_EX3_UNK0 0x00000001 // 0 -#define SPELL_ATTR_EX3_UNK1 0x00000002 // 1 -#define SPELL_ATTR_EX3_UNK2 0x00000004 // 2 -#define SPELL_ATTR_EX3_BLOCKABLE_SPELL 0x00000008 // 3 Only dmg class melee in 3.1.3 -#define SPELL_ATTR_EX3_UNK4 0x00000010 // 4 Druid Rebirth only this spell have this flag -#define SPELL_ATTR_EX3_UNK5 0x00000020 // 5 -#define SPELL_ATTR_EX3_UNK6 0x00000040 // 6 -#define SPELL_ATTR_EX3_STACK_FOR_DIFF_CASTERS 0x00000080 // 7 separate stack for every caster -#define SPELL_ATTR_EX3_PLAYERS_ONLY 0x00000100 // 8 Player only? -#define SPELL_ATTR_EX3_TRIGGERED_CAN_TRIGGER_2 0x00000200 // 9 triggered from effect? -#define SPELL_ATTR_EX3_MAIN_HAND 0x00000400 // 10 Main hand weapon required -#define SPELL_ATTR_EX3_BATTLEGROUND 0x00000800 // 11 Can casted only on battleground -#define SPELL_ATTR_EX3_UNK12 0x00001000 // 12 -#define SPELL_ATTR_EX3_UNK13 0x00002000 // 13 -#define SPELL_ATTR_EX3_UNK14 0x00004000 // 14 "Honorless Target" only this spells have this flag -#define SPELL_ATTR_EX3_UNK15 0x00008000 // 15 Auto Shoot, Shoot, Throw, - this is autoshot flag -#define SPELL_ATTR_EX3_UNK16 0x00010000 // 16 no triggers effects that trigger on casting a spell?? (15290 - 2.2ptr change) -#define SPELL_ATTR_EX3_NO_INITIAL_AGGRO 0x00020000 // 17 Soothe Animal, 39758, Mind Soothe -#define SPELL_ATTR_EX3_UNK18 0x00040000 // 18 added to Explosive Trap Effect 3.3.0, removed from Mutilate 3.3.0 -#define SPELL_ATTR_EX3_DISABLE_PROC 0x00080000 // 19 during aura proc no spells can trigger (20178, 20375) -#define SPELL_ATTR_EX3_DEATH_PERSISTENT 0x00100000 // 20 Death persistent spells -#define SPELL_ATTR_EX3_UNK21 0x00200000 // 21 -#define SPELL_ATTR_EX3_REQ_WAND 0x00400000 // 22 Req wand -#define SPELL_ATTR_EX3_UNK23 0x00800000 // 23 -#define SPELL_ATTR_EX3_REQ_OFFHAND 0x01000000 // 24 Req offhand weapon -#define SPELL_ATTR_EX3_UNK25 0x02000000 // 25 no cause spell pushback ? -#define SPELL_ATTR_EX3_CAN_PROC_TRIGGERED 0x04000000 // 26 -#define SPELL_ATTR_EX3_DRAIN_SOUL 0x08000000 // 27 only drain soul has this flag -#define SPELL_ATTR_EX3_UNK28 0x10000000 // 28 -#define SPELL_ATTR_EX3_NO_DONE_BONUS 0x20000000 // 29 Ignore caster spellpower and done damage mods? -#define SPELL_ATTR_EX3_UNK30 0x40000000 // 30 Shaman's Fire Nova 3.3.0, Sweeping Strikes 3.3.0 -#define SPELL_ATTR_EX3_UNK31 0x80000000 // 31 - -#define SPELL_ATTR_EX4_UNK0 0x00000001 // 0 -#define SPELL_ATTR_EX4_UNK1 0x00000002 // 1 proc on finishing move? -#define SPELL_ATTR_EX4_UNK2 0x00000004 // 2 -#define SPELL_ATTR_EX4_CANT_PROC_FROM_SELFCAST 0x00000008 // 3 -#define SPELL_ATTR_EX4_UNK4 0x00000010 // 4 This will no longer cause guards to attack on use?? -#define SPELL_ATTR_EX4_UNK5 0x00000020 // 5 -#define SPELL_ATTR_EX4_NOT_STEALABLE 0x00000040 // 6 although such auras might be dispellable, they cannot be stolen -#define SPELL_ATTR_EX4_UNK7 0x00000080 // 7 -#define SPELL_ATTR_EX4_FIXED_DAMAGE 0x00000100 // 8 decimate, share damage? -#define SPELL_ATTR_EX4_UNK9 0x00000200 // 9 -#define SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST 0x00000400 // 10 Rogue Shiv have this flag -#define SPELL_ATTR_EX4_UNK11 0x00000800 // 11 -#define SPELL_ATTR_EX4_UNK12 0x00001000 // 12 -#define SPELL_ATTR_EX4_UNK13 0x00002000 // 13 -#define SPELL_ATTR_EX4_UNK14 0x00004000 // 14 -#define SPELL_ATTR_EX4_UNK15 0x00008000 // 15 -#define SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA 0x00010000 // 16 not usable in arena -#define SPELL_ATTR_EX4_USABLE_IN_ARENA 0x00020000 // 17 usable in arena -#define SPELL_ATTR_EX4_UNK18 0x00040000 // 18 -#define SPELL_ATTR_EX4_UNK19 0x00080000 // 19 -#define SPELL_ATTR_EX4_NOT_CHECK_SELFCAST_POWER 0x00100000 // 20 supersedes message "More powerful spell applied" for self casts. -#define SPELL_ATTR_EX4_UNK21 0x00200000 // 21 -#define SPELL_ATTR_EX4_UNK22 0x00400000 // 22 -#define SPELL_ATTR_EX4_UNK23 0x00800000 // 23 -#define SPELL_ATTR_EX4_UNK24 0x01000000 // 24 -#define SPELL_ATTR_EX4_UNK25 0x02000000 // 25 pet scaling auras -#define SPELL_ATTR_EX4_CAST_ONLY_IN_OUTLAND 0x04000000 // 26 Can only be used in Outland. -#define SPELL_ATTR_EX4_UNK27 0x08000000 // 27 -#define SPELL_ATTR_EX4_UNK28 0x10000000 // 28 -#define SPELL_ATTR_EX4_UNK29 0x20000000 // 29 -#define SPELL_ATTR_EX4_UNK30 0x40000000 // 30 -#define SPELL_ATTR_EX4_UNK31 0x80000000 // 31 - -#define SPELL_ATTR_EX5_UNK0 0x00000001 // 0 -#define SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP 0x00000002 // 1 not need reagents if UNIT_FLAG_PREPARATION -#define SPELL_ATTR_EX5_UNK2 0x00000004 // 2 -#define SPELL_ATTR_EX5_USABLE_WHILE_STUNNED 0x00000008 // 3 usable while stunned -#define SPELL_ATTR_EX5_UNK4 0x00000010 // 4 -#define SPELL_ATTR_EX5_SINGLE_TARGET_SPELL 0x00000020 // 5 Only one target can be apply at a time -#define SPELL_ATTR_EX5_UNK6 0x00000040 // 6 -#define SPELL_ATTR_EX5_UNK7 0x00000080 // 7 -#define SPELL_ATTR_EX5_UNK8 0x00000100 // 8 -#define SPELL_ATTR_EX5_START_PERIODIC_AT_APPLY 0x00000200 // 9 begin periodic tick at aura apply -#define SPELL_ATTR_EX5_UNK10 0x00000400 // 10 -#define SPELL_ATTR_EX5_UNK11 0x00000800 // 11 -#define SPELL_ATTR_EX5_UNK12 0x00001000 // 12 -#define SPELL_ATTR_EX5_UNK13 0x00002000 // 13 -#define SPELL_ATTR_EX5_UNK14 0x00004000 // 14 -#define SPELL_ATTR_EX5_UNK15 0x00008000 // 15 -#define SPELL_ATTR_EX5_UNK16 0x00010000 // 16 -#define SPELL_ATTR_EX5_USABLE_WHILE_FEARED 0x00020000 // 17 usable while feared -#define SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED 0x00040000 // 18 usable while confused -#define SPELL_ATTR_EX5_UNK19 0x00080000 // 19 -#define SPELL_ATTR_EX5_UNK20 0x00100000 // 20 -#define SPELL_ATTR_EX5_UNK21 0x00200000 // 21 -#define SPELL_ATTR_EX5_UNK22 0x00400000 // 22 -#define SPELL_ATTR_EX5_UNK23 0x00800000 // 23 -#define SPELL_ATTR_EX5_UNK24 0x01000000 // 24 -#define SPELL_ATTR_EX5_UNK25 0x02000000 // 25 -#define SPELL_ATTR_EX5_UNK26 0x04000000 // 26 -#define SPELL_ATTR_EX5_UNK27 0x08000000 // 27 -#define SPELL_ATTR_EX5_UNK28 0x10000000 // 28 -#define SPELL_ATTR_EX5_UNK29 0x20000000 // 29 -#define SPELL_ATTR_EX5_UNK30 0x40000000 // 30 -#define SPELL_ATTR_EX5_UNK31 0x80000000 // 31 Forces all nearby enemies to focus attacks caster - -#define SPELL_ATTR_EX6_UNK0 0x00000001 // 0 Only Move spell have this flag -#define SPELL_ATTR_EX6_ONLY_IN_ARENA 0x00000002 // 1 only usable in arena -#define SPELL_ATTR_EX6_IGNORE_CASTER_AURAS 0x00000004 // 2 -#define SPELL_ATTR_EX6_UNK3 0x00000008 // 3 -#define SPELL_ATTR_EX6_UNK4 0x00000010 // 4 -#define SPELL_ATTR_EX6_UNK5 0x00000020 // 5 -#define SPELL_ATTR_EX6_UNK6 0x00000040 // 6 -#define SPELL_ATTR_EX6_UNK7 0x00000080 // 7 -#define SPELL_ATTR_EX6_UNK8 0x00000100 // 8 -#define SPELL_ATTR_EX6_UNK9 0x00000200 // 9 -#define SPELL_ATTR_EX6_UNK10 0x00000400 // 10 -#define SPELL_ATTR_EX6_NOT_IN_RAID_INSTANCE 0x00000800 // 11 not usable in raid instance -#define SPELL_ATTR_EX6_UNK12 0x00001000 // 12 -#define SPELL_ATTR_EX6_UNK13 0x00002000 // 13 -#define SPELL_ATTR_EX6_UNK14 0x00004000 // 14 -#define SPELL_ATTR_EX6_UNK15 0x00008000 // 15 not set in 3.0.3 -#define SPELL_ATTR_EX6_UNK16 0x00010000 // 16 -#define SPELL_ATTR_EX6_UNK17 0x00020000 // 17 -#define SPELL_ATTR_EX6_UNK18 0x00040000 // 18 -#define SPELL_ATTR_EX6_UNK19 0x00080000 // 19 -#define SPELL_ATTR_EX6_UNK20 0x00100000 // 20 -#define SPELL_ATTR_EX6_CLIENT_UI_TARGET_EFFECTS 0x00200000 // 21 it's only client-side attribute -#define SPELL_ATTR_EX6_UNK22 0x00400000 // 22 -#define SPELL_ATTR_EX6_UNK23 0x00800000 // 23 not set in 3.0.3 -#define SPELL_ATTR_EX6_UNK24 0x01000000 // 24 not set in 3.0.3 -#define SPELL_ATTR_EX6_UNK25 0x02000000 // 25 not set in 3.0.3 -#define SPELL_ATTR_EX6_UNK26 0x04000000 // 26 not set in 3.0.3 -#define SPELL_ATTR_EX6_UNK27 0x08000000 // 27 not set in 3.0.3 -#define SPELL_ATTR_EX6_UNK28 0x10000000 // 28 not set in 3.0.3 -#define SPELL_ATTR_EX6_UNK29 0x20000000 // 29 not set in 3.0.3 -#define SPELL_ATTR_EX6_UNK30 0x40000000 // 30 not set in 3.0.3 -#define SPELL_ATTR_EX6_UNK31 0x80000000 // 31 not set in 3.0.3 - -#define SPELL_ATTR_EX7_UNK0 0x00000001 // 0 Shaman's new spells (Call of the ...), Feign Death. -#define SPELL_ATTR_EX7_UNK1 0x00000002 // 1 Not set in 3.2.2a. -#define SPELL_ATTR_EX7_REACTIVATE_AT_RESURRECT 0x00000004 // 2 Paladin's auras and 65607 only. -#define SPELL_ATTR_EX7_UNK3 0x00000008 // 3 Only 43574 test spell. -#define SPELL_ATTR_EX7_UNK4 0x00000010 // 4 Only 66109 test spell. -#define SPELL_ATTR_EX7_SUMMON_PLAYER_TOTEM 0x00000020 // 5 Only Shaman player totems. -#define SPELL_ATTR_EX7_UNK6 0x00000040 // 6 Dark Surge, Surge of Light, Burning Breath triggers (boss spells). -#define SPELL_ATTR_EX7_UNK7 0x00000080 // 7 66218 (Launch) spell. -#define SPELL_ATTR_EX7_UNK8 0x00000100 // 8 Teleports, mounts and other spells. -#define SPELL_ATTR_EX7_UNK9 0x00000200 // 9 Teleports, mounts and other spells. -#define SPELL_ATTR_EX7_DISPEL_CHARGES 0x00000400 // 10 Dispel and Spellsteal individual charges instead of whole aura. -#define SPELL_ATTR_EX7_INTERRUPT_ONLY_NONPLAYER 0x00000800 // 11 Only non-player casts interrupt, though Feral Charge - Bear has it. -#define SPELL_ATTR_EX7_UNK12 0x00001000 // 12 Not set in 3.2.2a. -#define SPELL_ATTR_EX7_UNK13 0x00002000 // 13 Not set in 3.2.2a. -#define SPELL_ATTR_EX7_UNK14 0x00004000 // 14 Only 52150 (Raise Dead - Pet) spell. -#define SPELL_ATTR_EX7_UNK15 0x00008000 // 15 Exorcism. Usable on players? 100% crit chance on undead and demons? -#define SPELL_ATTR_EX7_UNK16 0x00010000 // 16 Druid spells (29166, 54833, 64372, 68285). -#define SPELL_ATTR_EX7_UNK17 0x00020000 // 17 Only 27965 (Suicide) spell. -#define SPELL_ATTR_EX7_HAS_CHARGE_EFFECT 0x00040000 // 18 Only spells that have Charge among effects. -#define SPELL_ATTR_EX7_ZONE_TELEPORT 0x00080000 // 19 Teleports to specific zones. - -#define MIN_TALENT_SPEC 0 -#define MAX_TALENT_SPEC 1 -#define MIN_TALENT_SPECS 1 -#define MAX_TALENT_SPECS 2 -#define MAX_GLYPH_SLOT_INDEX 6 - -// Custom values -enum SpellClickUserTypes -{ - SPELL_CLICK_USER_ANY = 0, - SPELL_CLICK_USER_FRIEND = 1, - SPELL_CLICK_USER_RAID = 2, - SPELL_CLICK_USER_PARTY = 3, - SPELL_CLICK_USER_MAX = 4 -}; - -#define NPC_CLICK_CAST_CASTER_PLAYER 0x01 -#define NPC_CLICK_CAST_TARGET_PLAYER 0x02 -#define NPC_CLICK_CAST_ORIG_CASTER_OWNER 0x04 - -enum SheathTypes -{ - SHEATHETYPE_NONE = 0, - SHEATHETYPE_MAINHAND = 1, - SHEATHETYPE_OFFHAND = 2, - SHEATHETYPE_LARGEWEAPONLEFT = 3, - SHEATHETYPE_LARGEWEAPONRIGHT = 4, - SHEATHETYPE_HIPWEAPONLEFT = 5, - SHEATHETYPE_HIPWEAPONRIGHT = 6, - SHEATHETYPE_SHIELD = 7 -}; - -#define MAX_SHEATHETYPE 8 - -enum CharacterSlot -{ - SLOT_HEAD = 0, - SLOT_NECK = 1, - SLOT_SHOULDERS = 2, - SLOT_SHIRT = 3, - SLOT_CHEST = 4, - SLOT_WAIST = 5, - SLOT_LEGS = 6, - SLOT_FEET = 7, - SLOT_WRISTS = 8, - SLOT_HANDS = 9, - SLOT_FINGER1 = 10, - SLOT_FINGER2 = 11, - SLOT_TRINKET1 = 12, - SLOT_TRINKET2 = 13, - SLOT_BACK = 14, - SLOT_MAIN_HAND = 15, - SLOT_OFF_HAND = 16, - SLOT_RANGED = 17, - SLOT_TABARD = 18, - SLOT_EMPTY = 19 -}; - -enum Language -{ - LANG_UNIVERSAL = 0, - LANG_ORCISH = 1, - LANG_DARNASSIAN = 2, - LANG_TAURAHE = 3, - LANG_DWARVISH = 6, - LANG_COMMON = 7, - LANG_DEMONIC = 8, - LANG_TITAN = 9, - LANG_THALASSIAN = 10, - LANG_DRACONIC = 11, - LANG_KALIMAG = 12, - LANG_GNOMISH = 13, - LANG_TROLL = 14, - LANG_GUTTERSPEAK = 33, - LANG_DRAENEI = 35, - LANG_ZOMBIE = 36, - LANG_GNOMISH_BINARY = 37, - LANG_GOBLIN_BINARY = 38, - LANG_ADDON = 0xFFFFFFFF // used by addons, in 2.4.0 not exist, replaced by messagetype? -}; - -#define LANGUAGES_COUNT 19 - -enum TeamId -{ - TEAM_ALLIANCE = 0, - TEAM_HORDE, - TEAM_NEUTRAL, -}; - -enum Team -{ - HORDE = 67, - ALLIANCE = 469, - //TEAM_STEAMWHEEDLE_CARTEL = 169, // not used in code - //TEAM_ALLIANCE_FORCES = 891, - //TEAM_HORDE_FORCES = 892, - //TEAM_SANCTUARY = 936, - //TEAM_OUTLAND = 980, - TEAM_OTHER = 0, // if ReputationListId > 0 && Flags != FACTION_FLAG_TEAM_HEADER -}; - -const Team TeamId2Team[3] = {ALLIANCE, HORDE, TEAM_OTHER}; - -enum SpellEffects -{ - SPELL_EFFECT_INSTAKILL = 1, - SPELL_EFFECT_SCHOOL_DAMAGE = 2, - SPELL_EFFECT_DUMMY = 3, - SPELL_EFFECT_PORTAL_TELEPORT = 4, - SPELL_EFFECT_TELEPORT_UNITS = 5, - SPELL_EFFECT_APPLY_AURA = 6, - SPELL_EFFECT_ENVIRONMENTAL_DAMAGE = 7, - SPELL_EFFECT_POWER_DRAIN = 8, - SPELL_EFFECT_HEALTH_LEECH = 9, - SPELL_EFFECT_HEAL = 10, - SPELL_EFFECT_BIND = 11, - SPELL_EFFECT_PORTAL = 12, - SPELL_EFFECT_RITUAL_BASE = 13, - SPELL_EFFECT_RITUAL_SPECIALIZE = 14, - SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL = 15, - SPELL_EFFECT_QUEST_COMPLETE = 16, - SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL = 17, - SPELL_EFFECT_RESURRECT = 18, - SPELL_EFFECT_ADD_EXTRA_ATTACKS = 19, - SPELL_EFFECT_DODGE = 20, - SPELL_EFFECT_EVADE = 21, - SPELL_EFFECT_PARRY = 22, - SPELL_EFFECT_BLOCK = 23, - SPELL_EFFECT_CREATE_ITEM = 24, - SPELL_EFFECT_WEAPON = 25, - SPELL_EFFECT_DEFENSE = 26, - SPELL_EFFECT_PERSISTENT_AREA_AURA = 27, - SPELL_EFFECT_SUMMON = 28, - SPELL_EFFECT_LEAP = 29, - SPELL_EFFECT_ENERGIZE = 30, - SPELL_EFFECT_WEAPON_PERCENT_DAMAGE = 31, - SPELL_EFFECT_TRIGGER_MISSILE = 32, - SPELL_EFFECT_OPEN_LOCK = 33, - SPELL_EFFECT_SUMMON_CHANGE_ITEM = 34, - SPELL_EFFECT_APPLY_AREA_AURA_PARTY = 35, - SPELL_EFFECT_LEARN_SPELL = 36, - SPELL_EFFECT_SPELL_DEFENSE = 37, - SPELL_EFFECT_DISPEL = 38, - SPELL_EFFECT_LANGUAGE = 39, - SPELL_EFFECT_DUAL_WIELD = 40, - SPELL_EFFECT_JUMP = 41, - SPELL_EFFECT_JUMP2 = 42, - SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER= 43, - SPELL_EFFECT_SKILL_STEP = 44, - SPELL_EFFECT_ADD_HONOR = 45, - SPELL_EFFECT_SPAWN = 46, - SPELL_EFFECT_TRADE_SKILL = 47, - SPELL_EFFECT_STEALTH = 48, - SPELL_EFFECT_DETECT = 49, - SPELL_EFFECT_TRANS_DOOR = 50, - SPELL_EFFECT_FORCE_CRITICAL_HIT = 51, - SPELL_EFFECT_GUARANTEE_HIT = 52, - SPELL_EFFECT_ENCHANT_ITEM = 53, - SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY = 54, - SPELL_EFFECT_TAMECREATURE = 55, - SPELL_EFFECT_SUMMON_PET = 56, - SPELL_EFFECT_LEARN_PET_SPELL = 57, - SPELL_EFFECT_WEAPON_DAMAGE = 58, - SPELL_EFFECT_CREATE_RANDOM_ITEM = 59, - SPELL_EFFECT_PROFICIENCY = 60, - SPELL_EFFECT_SEND_EVENT = 61, - SPELL_EFFECT_POWER_BURN = 62, - SPELL_EFFECT_THREAT = 63, - SPELL_EFFECT_TRIGGER_SPELL = 64, - SPELL_EFFECT_APPLY_AREA_AURA_RAID = 65, - SPELL_EFFECT_CREATE_MANA_GEM = 66, - SPELL_EFFECT_HEAL_MAX_HEALTH = 67, - SPELL_EFFECT_INTERRUPT_CAST = 68, - SPELL_EFFECT_DISTRACT = 69, - SPELL_EFFECT_PULL = 70, - SPELL_EFFECT_PICKPOCKET = 71, - SPELL_EFFECT_ADD_FARSIGHT = 72, - SPELL_EFFECT_UNTRAIN_TALENTS = 73, - SPELL_EFFECT_APPLY_GLYPH = 74, - SPELL_EFFECT_HEAL_MECHANICAL = 75, - SPELL_EFFECT_SUMMON_OBJECT_WILD = 76, - SPELL_EFFECT_SCRIPT_EFFECT = 77, - SPELL_EFFECT_ATTACK = 78, - SPELL_EFFECT_SANCTUARY = 79, - SPELL_EFFECT_ADD_COMBO_POINTS = 80, - SPELL_EFFECT_CREATE_HOUSE = 81, - SPELL_EFFECT_BIND_SIGHT = 82, - SPELL_EFFECT_DUEL = 83, - SPELL_EFFECT_STUCK = 84, - SPELL_EFFECT_SUMMON_PLAYER = 85, - SPELL_EFFECT_ACTIVATE_OBJECT = 86, - SPELL_EFFECT_WMO_DAMAGE = 87, - SPELL_EFFECT_WMO_REPAIR = 88, - SPELL_EFFECT_WMO_CHANGE = 89, - SPELL_EFFECT_KILL_CREDIT = 90, - SPELL_EFFECT_THREAT_ALL = 91, - SPELL_EFFECT_ENCHANT_HELD_ITEM = 92, - SPELL_EFFECT_FORCE_DESELECT = 93, - SPELL_EFFECT_SELF_RESURRECT = 94, - SPELL_EFFECT_SKINNING = 95, - SPELL_EFFECT_CHARGE = 96, - SPELL_EFFECT_CAST_BUTTON = 97, - SPELL_EFFECT_KNOCK_BACK = 98, - SPELL_EFFECT_DISENCHANT = 99, - SPELL_EFFECT_INEBRIATE = 100, - SPELL_EFFECT_FEED_PET = 101, - SPELL_EFFECT_DISMISS_PET = 102, - SPELL_EFFECT_REPUTATION = 103, - SPELL_EFFECT_SUMMON_OBJECT_SLOT1 = 104, - SPELL_EFFECT_SUMMON_OBJECT_SLOT2 = 105, - SPELL_EFFECT_SUMMON_OBJECT_SLOT3 = 106, - SPELL_EFFECT_SUMMON_OBJECT_SLOT4 = 107, - SPELL_EFFECT_DISPEL_MECHANIC = 108, - SPELL_EFFECT_SUMMON_DEAD_PET = 109, - SPELL_EFFECT_DESTROY_ALL_TOTEMS = 110, - SPELL_EFFECT_DURABILITY_DAMAGE = 111, - SPELL_EFFECT_112 = 112, - SPELL_EFFECT_RESURRECT_NEW = 113, - SPELL_EFFECT_ATTACK_ME = 114, - SPELL_EFFECT_DURABILITY_DAMAGE_PCT = 115, - SPELL_EFFECT_SKIN_PLAYER_CORPSE = 116, - SPELL_EFFECT_SPIRIT_HEAL = 117, - SPELL_EFFECT_SKILL = 118, - SPELL_EFFECT_APPLY_AREA_AURA_PET = 119, - SPELL_EFFECT_TELEPORT_GRAVEYARD = 120, - SPELL_EFFECT_NORMALIZED_WEAPON_DMG = 121, - SPELL_EFFECT_122 = 122, - SPELL_EFFECT_SEND_TAXI = 123, - SPELL_EFFECT_PLAYER_PULL = 124, - SPELL_EFFECT_MODIFY_THREAT_PERCENT = 125, - SPELL_EFFECT_STEAL_BENEFICIAL_BUFF = 126, - SPELL_EFFECT_PROSPECTING = 127, - SPELL_EFFECT_APPLY_AREA_AURA_FRIEND = 128, - SPELL_EFFECT_APPLY_AREA_AURA_ENEMY = 129, - SPELL_EFFECT_REDIRECT_THREAT = 130, - SPELL_EFFECT_131 = 131, - SPELL_EFFECT_PLAY_MUSIC = 132, - SPELL_EFFECT_UNLEARN_SPECIALIZATION = 133, - SPELL_EFFECT_KILL_CREDIT2 = 134, - SPELL_EFFECT_CALL_PET = 135, - SPELL_EFFECT_HEAL_PCT = 136, - SPELL_EFFECT_ENERGIZE_PCT = 137, - SPELL_EFFECT_LEAP_BACK = 138, - SPELL_EFFECT_CLEAR_QUEST = 139, - SPELL_EFFECT_FORCE_CAST = 140, - SPELL_EFFECT_141 = 141, - SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE = 142, - SPELL_EFFECT_APPLY_AREA_AURA_OWNER = 143, - SPELL_EFFECT_KNOCK_BACK_2 = 144, - SPELL_EFFECT_145 = 145, - SPELL_EFFECT_ACTIVATE_RUNE = 146, - SPELL_EFFECT_QUEST_FAIL = 147, - SPELL_EFFECT_148 = 148, - SPELL_EFFECT_149 = 149, - SPELL_EFFECT_150 = 150, - SPELL_EFFECT_TRIGGER_SPELL_2 = 151, - SPELL_EFFECT_152 = 152, - SPELL_EFFECT_153 = 153, - SPELL_EFFECT_154 = 154, - SPELL_EFFECT_TITAN_GRIP = 155, - SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC = 156, - SPELL_EFFECT_CREATE_ITEM_2 = 157, - SPELL_EFFECT_MILLING = 158, - SPELL_EFFECT_ALLOW_RENAME_PET = 159, - SPELL_EFFECT_160 = 160, - SPELL_EFFECT_TALENT_SPEC_COUNT = 161, - SPELL_EFFECT_TALENT_SPEC_SELECT = 162, - SPELL_EFFECT_163 = 163, - SPELL_EFFECT_164 = 164, - TOTAL_SPELL_EFFECTS = 165 -}; - -enum SpellCastResult -{ - SPELL_FAILED_SUCCESS = 0, - SPELL_FAILED_AFFECTING_COMBAT = 1, - SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 2, - SPELL_FAILED_ALREADY_AT_FULL_MANA = 3, - SPELL_FAILED_ALREADY_AT_FULL_POWER = 4, - SPELL_FAILED_ALREADY_BEING_TAMED = 5, - SPELL_FAILED_ALREADY_HAVE_CHARM = 6, - SPELL_FAILED_ALREADY_HAVE_SUMMON = 7, - SPELL_FAILED_ALREADY_OPEN = 8, - SPELL_FAILED_AURA_BOUNCED = 9, - SPELL_FAILED_AUTOTRACK_INTERRUPTED = 10, - SPELL_FAILED_BAD_IMPLICIT_TARGETS = 11, - SPELL_FAILED_BAD_TARGETS = 12, - SPELL_FAILED_CANT_BE_CHARMED = 13, - SPELL_FAILED_CANT_BE_DISENCHANTED = 14, - SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 15, - SPELL_FAILED_CANT_BE_MILLED = 16, - SPELL_FAILED_CANT_BE_PROSPECTED = 17, - SPELL_FAILED_CANT_CAST_ON_TAPPED = 18, - SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 19, - SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 20, - SPELL_FAILED_CANT_STEALTH = 21, - SPELL_FAILED_CASTER_AURASTATE = 22, - SPELL_FAILED_CASTER_DEAD = 23, - SPELL_FAILED_CHARMED = 24, - SPELL_FAILED_CHEST_IN_USE = 25, - SPELL_FAILED_CONFUSED = 26, - SPELL_FAILED_DONT_REPORT = 27, - SPELL_FAILED_EQUIPPED_ITEM = 28, - SPELL_FAILED_EQUIPPED_ITEM_CLASS = 29, - SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 30, - SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 31, - SPELL_FAILED_ERROR = 32, - SPELL_FAILED_FIZZLE = 33, - SPELL_FAILED_FLEEING = 34, - SPELL_FAILED_FOOD_LOWLEVEL = 35, - SPELL_FAILED_HIGHLEVEL = 36, - SPELL_FAILED_HUNGER_SATIATED = 37, - SPELL_FAILED_IMMUNE = 38, - SPELL_FAILED_INCORRECT_AREA = 39, - SPELL_FAILED_INTERRUPTED = 40, - SPELL_FAILED_INTERRUPTED_COMBAT = 41, - SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 42, - SPELL_FAILED_ITEM_GONE = 43, - SPELL_FAILED_ITEM_NOT_FOUND = 44, - SPELL_FAILED_ITEM_NOT_READY = 45, - SPELL_FAILED_LEVEL_REQUIREMENT = 46, - SPELL_FAILED_LINE_OF_SIGHT = 47, - SPELL_FAILED_LOWLEVEL = 48, - SPELL_FAILED_LOW_CASTLEVEL = 49, - SPELL_FAILED_MAINHAND_EMPTY = 50, - SPELL_FAILED_MOVING = 51, - SPELL_FAILED_NEED_AMMO = 52, - SPELL_FAILED_NEED_AMMO_POUCH = 53, - SPELL_FAILED_NEED_EXOTIC_AMMO = 54, - SPELL_FAILED_NEED_MORE_ITEMS = 55, - SPELL_FAILED_NOPATH = 56, - SPELL_FAILED_NOT_BEHIND = 57, - SPELL_FAILED_NOT_FISHABLE = 58, - SPELL_FAILED_NOT_FLYING = 59, - SPELL_FAILED_NOT_HERE = 60, - SPELL_FAILED_NOT_INFRONT = 61, - SPELL_FAILED_NOT_IN_CONTROL = 62, - SPELL_FAILED_NOT_KNOWN = 63, - SPELL_FAILED_NOT_MOUNTED = 64, - SPELL_FAILED_NOT_ON_TAXI = 65, - SPELL_FAILED_NOT_ON_TRANSPORT = 66, - SPELL_FAILED_NOT_READY = 67, - SPELL_FAILED_NOT_SHAPESHIFT = 68, - SPELL_FAILED_NOT_STANDING = 69, - SPELL_FAILED_NOT_TRADEABLE = 70, - SPELL_FAILED_NOT_TRADING = 71, - SPELL_FAILED_NOT_UNSHEATHED = 72, - SPELL_FAILED_NOT_WHILE_GHOST = 73, - SPELL_FAILED_NOT_WHILE_LOOTING = 74, - SPELL_FAILED_NO_AMMO = 75, - SPELL_FAILED_NO_CHARGES_REMAIN = 76, - SPELL_FAILED_NO_CHAMPION = 77, - SPELL_FAILED_NO_COMBO_POINTS = 78, - SPELL_FAILED_NO_DUELING = 79, - SPELL_FAILED_NO_ENDURANCE = 80, - SPELL_FAILED_NO_FISH = 81, - SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 82, - SPELL_FAILED_NO_MOUNTS_ALLOWED = 83, - SPELL_FAILED_NO_PET = 84, - SPELL_FAILED_NO_POWER = 85, - SPELL_FAILED_NOTHING_TO_DISPEL = 86, - SPELL_FAILED_NOTHING_TO_STEAL = 87, - SPELL_FAILED_ONLY_ABOVEWATER = 88, - SPELL_FAILED_ONLY_DAYTIME = 89, - SPELL_FAILED_ONLY_INDOORS = 90, - SPELL_FAILED_ONLY_MOUNTED = 91, - SPELL_FAILED_ONLY_NIGHTTIME = 92, - SPELL_FAILED_ONLY_OUTDOORS = 93, - SPELL_FAILED_ONLY_SHAPESHIFT = 94, - SPELL_FAILED_ONLY_STEALTHED = 95, - SPELL_FAILED_ONLY_UNDERWATER = 96, - SPELL_FAILED_OUT_OF_RANGE = 97, - SPELL_FAILED_PACIFIED = 98, - SPELL_FAILED_POSSESSED = 99, - SPELL_FAILED_REAGENTS = 100, - SPELL_FAILED_REQUIRES_AREA = 101, - SPELL_FAILED_REQUIRES_SPELL_FOCUS = 102, - SPELL_FAILED_ROOTED = 103, - SPELL_FAILED_SILENCED = 104, - SPELL_FAILED_SPELL_IN_PROGRESS = 105, - SPELL_FAILED_SPELL_LEARNED = 106, - SPELL_FAILED_SPELL_UNAVAILABLE = 107, - SPELL_FAILED_STUNNED = 108, - SPELL_FAILED_TARGETS_DEAD = 109, - SPELL_FAILED_TARGET_AFFECTING_COMBAT = 110, - SPELL_FAILED_TARGET_AURASTATE = 111, - SPELL_FAILED_TARGET_DUELING = 112, - SPELL_FAILED_TARGET_ENEMY = 113, - SPELL_FAILED_TARGET_ENRAGED = 114, - SPELL_FAILED_TARGET_FRIENDLY = 115, - SPELL_FAILED_TARGET_IN_COMBAT = 116, - SPELL_FAILED_TARGET_IS_PLAYER = 117, - SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 118, - SPELL_FAILED_TARGET_NOT_DEAD = 119, - SPELL_FAILED_TARGET_NOT_IN_PARTY = 120, - SPELL_FAILED_TARGET_NOT_LOOTED = 121, - SPELL_FAILED_TARGET_NOT_PLAYER = 122, - SPELL_FAILED_TARGET_NO_POCKETS = 123, - SPELL_FAILED_TARGET_NO_WEAPONS = 124, - SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 125, - SPELL_FAILED_TARGET_UNSKINNABLE = 126, - SPELL_FAILED_THIRST_SATIATED = 127, - SPELL_FAILED_TOO_CLOSE = 128, - SPELL_FAILED_TOO_MANY_OF_ITEM = 129, - SPELL_FAILED_TOTEM_CATEGORY = 130, - SPELL_FAILED_TOTEMS = 131, - SPELL_FAILED_TRY_AGAIN = 132, - SPELL_FAILED_UNIT_NOT_BEHIND = 133, - SPELL_FAILED_UNIT_NOT_INFRONT = 134, - SPELL_FAILED_WRONG_PET_FOOD = 135, - SPELL_FAILED_NOT_WHILE_FATIGUED = 136, - SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 137, - SPELL_FAILED_NOT_WHILE_TRADING = 138, - SPELL_FAILED_TARGET_NOT_IN_RAID = 139, - SPELL_FAILED_TARGET_FREEFORALL = 140, - SPELL_FAILED_NO_EDIBLE_CORPSES = 141, - SPELL_FAILED_ONLY_BATTLEGROUNDS = 142, - SPELL_FAILED_TARGET_NOT_GHOST = 143, - SPELL_FAILED_TRANSFORM_UNUSABLE = 144, - SPELL_FAILED_WRONG_WEATHER = 145, - SPELL_FAILED_DAMAGE_IMMUNE = 146, - SPELL_FAILED_PREVENTED_BY_MECHANIC = 147, - SPELL_FAILED_PLAY_TIME = 148, - SPELL_FAILED_REPUTATION = 149, - SPELL_FAILED_MIN_SKILL = 150, - SPELL_FAILED_NOT_IN_ARENA = 151, - SPELL_FAILED_NOT_ON_SHAPESHIFT = 152, - SPELL_FAILED_NOT_ON_STEALTHED = 153, - SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 154, - SPELL_FAILED_NOT_ON_MOUNTED = 155, - SPELL_FAILED_TOO_SHALLOW = 156, - SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 157, - SPELL_FAILED_TARGET_IS_TRIVIAL = 158, - SPELL_FAILED_BM_OR_INVISGOD = 159, - SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 160, - SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 161, - SPELL_FAILED_NOT_IDLE = 162, - SPELL_FAILED_NOT_INACTIVE = 163, - SPELL_FAILED_PARTIAL_PLAYTIME = 164, - SPELL_FAILED_NO_PLAYTIME = 165, - SPELL_FAILED_NOT_IN_BATTLEGROUND = 166, - SPELL_FAILED_NOT_IN_RAID_INSTANCE = 167, - SPELL_FAILED_ONLY_IN_ARENA = 168, - SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 169, - SPELL_FAILED_ON_USE_ENCHANT = 170, - SPELL_FAILED_NOT_ON_GROUND = 171, - SPELL_FAILED_CUSTOM_ERROR = 172, - SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 173, - SPELL_FAILED_TOO_MANY_SOCKETS = 174, - SPELL_FAILED_INVALID_GLYPH = 175, - SPELL_FAILED_UNIQUE_GLYPH = 176, - SPELL_FAILED_GLYPH_SOCKET_LOCKED = 177, - SPELL_FAILED_NO_VALID_TARGETS = 178, - SPELL_FAILED_ITEM_AT_MAX_CHARGES = 179, - SPELL_FAILED_NOT_IN_BARBERSHOP = 180, - SPELL_FAILED_FISHING_TOO_LOW = 181, - SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW = 182, - SPELL_FAILED_SUMMON_PENDING = 183, - SPELL_FAILED_MAX_SOCKETS = 184, - SPELL_FAILED_PET_CAN_RENAME = 185, - SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED = 186, - SPELL_FAILED_UNKNOWN = 187, // actually doesn't exist in client - - SPELL_CAST_OK = 255 // custom value, don't must be send to client -}; - -// Spell aura states -enum AuraState -{ // (C) used in caster aura state (T) used in target aura state - // (c) used in caster aura state-not (t) used in target aura state-not - AURA_STATE_NONE = 0, // C | - AURA_STATE_DEFENSE = 1, // C | - AURA_STATE_HEALTHLESS_20_PERCENT = 2, // CcT | - AURA_STATE_BERSERKING = 3, // C T | - AURA_STATE_FROZEN = 4, // c t| frozen target - AURA_STATE_JUDGEMENT = 5, // C | - //AURA_STATE_UNKNOWN6 = 6, // | not used - AURA_STATE_HUNTER_PARRY = 7, // C | - //AURA_STATE_UNKNOWN7 = 7, // c | creature cheap shot / focused bursts spells - //AURA_STATE_UNKNOWN8 = 8, // t| test spells - //AURA_STATE_UNKNOWN9 = 9, // | - AURA_STATE_WARRIOR_VICTORY_RUSH = 10, // C | warrior victory rush - //AURA_STATE_UNKNOWN11 = 11, // C t| 60348 - Maelstrom Ready!, test spells - AURA_STATE_FAERIE_FIRE = 12, // c t| - AURA_STATE_HEALTHLESS_35_PERCENT = 13, // C T | - AURA_STATE_CONFLAGRATE = 14, // T | - AURA_STATE_SWIFTMEND = 15, // T | - AURA_STATE_DEADLY_POISON = 16, // T | - AURA_STATE_ENRAGE = 17, // C | - AURA_STATE_BLEEDING = 18, // T| - //AURA_STATE_UNKNOWN19 = 19, // | not used - //AURA_STATE_UNKNOWN20 = 20, // c | only (45317 Suicide) - //AURA_STATE_UNKNOWN21 = 21, // | not used - //AURA_STATE_UNKNOWN22 = 22, // C t| varius spells (63884, 50240) - AURA_STATE_HEALTH_ABOVE_75_PERCENT = 23, // C | -}; - -#define PER_CASTER_AURA_STATE_MASK (\ - (1<<(AURA_STATE_CONFLAGRATE-1))|(1<<(AURA_STATE_DEADLY_POISON-1))) - -// Spell mechanics -enum Mechanics -{ - MECHANIC_NONE = 0, - MECHANIC_CHARM = 1, - MECHANIC_DISORIENTED = 2, - MECHANIC_DISARM = 3, - MECHANIC_DISTRACT = 4, - MECHANIC_FEAR = 5, - MECHANIC_GRIP = 6, - MECHANIC_ROOT = 7, - MECHANIC_PACIFY = 8, //0 spells use this mechanic - MECHANIC_SILENCE = 9, - MECHANIC_SLEEP = 10, - MECHANIC_SNARE = 11, - MECHANIC_STUN = 12, - MECHANIC_FREEZE = 13, - MECHANIC_KNOCKOUT = 14, - MECHANIC_BLEED = 15, - MECHANIC_BANDAGE = 16, - MECHANIC_POLYMORPH = 17, - MECHANIC_BANISH = 18, - MECHANIC_SHIELD = 19, - MECHANIC_SHACKLE = 20, - MECHANIC_MOUNT = 21, - MECHANIC_INFECTED = 22, - MECHANIC_TURN = 23, - MECHANIC_HORROR = 24, - MECHANIC_INVULNERABILITY = 25, - MECHANIC_INTERRUPT = 26, - MECHANIC_DAZE = 27, - MECHANIC_DISCOVERY = 28, - MECHANIC_IMMUNE_SHIELD = 29, // Divine (Blessing) Shield/Protection and Ice Block - MECHANIC_SAPPED = 30, - MECHANIC_ENRAGED = 31 -}; - -// Used for spell 42292 Immune Movement Impairment and Loss of Control (0x49967da6) -#define IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK (\ - (1<(only this effect in the spell) can't cast to it, -//some aura(related to Mechanics or ImmuneToState) can't apply to it. -enum SpellImmunity -{ - IMMUNITY_EFFECT = 0, // enum SpellEffects - IMMUNITY_STATE = 1, // enum AuraType - IMMUNITY_SCHOOL = 2, // enum SpellSchoolMask - IMMUNITY_DAMAGE = 3, // enum SpellSchoolMask - IMMUNITY_DISPEL = 4, // enum DispelType - IMMUNITY_MECHANIC = 5, // enum Mechanics - IMMUNITY_ID = 6 -}; - -#define MAX_SPELL_IMMUNITY 7 - -enum Targets -{ - TARGET_UNIT_CASTER = 1, - TARGET_UNIT_NEARBY_ENEMY = 2, - TARGET_UNIT_NEARBY_ALLY = 3, - TARGET_UNIT_NEARBY_ALLY_UNK = 4, - TARGET_UNIT_PET = 5, - TARGET_UNIT_TARGET_ENEMY = 6, - TARGET_UNIT_AREA_ENTRY_SRC = 7, - TARGET_UNIT_AREA_ENTRY_DST = 8, - TARGET_DST_HOME = 9, // uses in teleport to innkeeper spells - TARGET_UNIT_TARGET_DEST_CASTER = 11, // teleport target to caster - TARGET_UNIT_AREA_ENEMY_SRC = 15, - TARGET_UNIT_AREA_ENEMY_DST = 16, - TARGET_DST_DB = 17, // uses in teleport spells and some other - TARGET_DST_CASTER = 18, - TARGET_UNIT_PARTY_CASTER = 20, - TARGET_UNIT_TARGET_ALLY = 21, - TARGET_SRC_CASTER = 22, - TARGET_GAMEOBJECT = 23, - //TARGET_OBJECT_OPEN - TARGET_UNIT_CONE_ENEMY = 24, - TARGET_UNIT_TARGET_ANY = 25, - TARGET_GAMEOBJECT_ITEM = 26, - //TARGET_OBJECT_ITEM_PICKLOCK - TARGET_UNIT_MASTER = 27, - TARGET_DEST_DYNOBJ_ENEMY = 28, - TARGET_DEST_DYNOBJ_ALLY = 29, // only for effect 27 - TARGET_UNIT_AREA_ALLY_SRC = 30, // in TargetB used only with TARGET_SRC_CASTER and in self casting range in TargetA - TARGET_UNIT_AREA_ALLY_DST = 31, - TARGET_MINION = 32, - //TARGET_DEST_SUMMON - TARGET_UNIT_AREA_PARTY_SRC = 33, - TARGET_UNIT_AREA_PARTY_DST = 34, // used in Tranquility - TARGET_UNIT_TARGET_PARTY = 35, - TARGET_DEST_CASTER_RANDOM_UNKNOWN = 36, //unknown - TARGET_UNIT_PARTY_TARGET = 37, - TARGET_UNIT_NEARBY_ENTRY = 38, - TARGET_UNIT_CASTER_FISHING = 39, - TARGET_GAMEOBJECT_NEARBY_ENTRY = 40, - TARGET_DEST_CASTER_FRONT_LEFT = 41, //earth totem - TARGET_DEST_CASTER_BACK_LEFT = 42, //water totem - TARGET_DEST_CASTER_BACK_RIGHT = 43, //air totem - TARGET_DEST_CASTER_FRONT_RIGHT = 44, //fire totem - TARGET_UNIT_CHAINHEAL = 45, - TARGET_DST_NEARBY_ENTRY = 46, - TARGET_DEST_CASTER_FRONT = 47, - TARGET_DEST_CASTER_BACK = 48, - TARGET_DEST_CASTER_RIGHT = 49, - TARGET_DEST_CASTER_LEFT = 50, - TARGET_OBJECT_AREA_SRC = 51, - TARGET_OBJECT_AREA_DST = 52, - TARGET_DST_TARGET_ENEMY = 53, // set unit coordinates as dest, only 16 target B imlemented - TARGET_UNIT_CONE_ENEMY_UNKNOWN = 54, // 180 degree, or different angle - TARGET_DEST_CASTER_FRONT_LEAP = 55, // for a leap spell - TARGET_UNIT_RAID_CASTER = 56, - TARGET_UNIT_TARGET_RAID = 57, - TARGET_UNIT_NEARBY_RAID = 58, - TARGET_UNIT_CONE_ALLY = 59, - TARGET_UNIT_CONE_ENTRY = 60, - TARGET_UNIT_CLASS_TARGET = 61, - TARGET_TEST = 62, // for a test spell - TARGET_DEST_TARGET_ANY = 63, - TARGET_DEST_TARGET_FRONT = 64, - TARGET_DEST_TARGET_BACK = 65, // uses in teleport behind spells - TARGET_DEST_TARGET_RIGHT = 66, - TARGET_DEST_TARGET_LEFT = 67, - TARGET_DEST_TARGET_FRONT_LEFT = 68, - TARGET_DEST_TARGET_BACK_LEFT = 69, - TARGET_DEST_TARGET_BACK_RIGHT = 70, - TARGET_DEST_TARGET_FRONT_RIGHT = 71, - TARGET_DEST_CASTER_RANDOM = 72, - TARGET_DEST_CASTER_RADIUS = 73, - TARGET_DEST_TARGET_RANDOM = 74, - TARGET_DEST_TARGET_RADIUS = 75, - TARGET_DEST_CHANNEL = 76, - TARGET_UNIT_CHANNEL = 77, - TARGET_DEST_DEST_FRONT = 78, - TARGET_DEST_DEST_BACK = 79, - TARGET_DEST_DEST_RIGHT = 80, - TARGET_DEST_DEST_LEFT = 81, - TARGET_DEST_DEST_FRONT_LEFT = 82, - TARGET_DEST_DEST_BACK_LEFT = 83, - TARGET_DEST_DEST_BACK_RIGHT = 84, - TARGET_DEST_DEST_FRONT_RIGHT = 85, - TARGET_DEST_DEST_RANDOM = 86, - TARGET_DEST_DEST = 87, - TARGET_DEST_DYNOBJ_NONE = 88, - TARGET_DEST_TRAJ = 89, - TARGET_UNIT_MINIPET = 90, - TARGET_DEST_DEST_RANDOM_DIR_DIST = 91, - TARGET_UNIT_UNK_92 = 92, - TARGET_CORPSE_AREA_ENEMY_PLAYER_SRC= 93, - TARGET_UNIT_VEHICLE = 94, - TARGET_UNIT_DRIVER = 95, - TARGET_UNIT_PASSENGER_0 = 96, - TARGET_UNIT_PASSENGER_1 = 97, - TARGET_UNIT_PASSENGER_2 = 98, - TARGET_UNIT_PASSENGER_3 = 99, - TARGET_UNIT_PASSENGER_4 = 100, - TARGET_UNIT_PASSENGER_5 = 101, - TARGET_UNIT_PASSENGER_6 = 102, - TARGET_UNIT_PASSENGER_7 = 103, - TARGET_UNIT_AREA_PATH = 104, - TARGET_UNIT_UNK_105 = 105, // 1 spell - TARGET_DEST_UNK_110 = 110, // some kind of traj? -}; - -#define TOTAL_SPELL_TARGETS 105 - -enum SpellMissInfo -{ - SPELL_MISS_NONE = 0, - SPELL_MISS_MISS = 1, - SPELL_MISS_RESIST = 2, - SPELL_MISS_DODGE = 3, - SPELL_MISS_PARRY = 4, - SPELL_MISS_BLOCK = 5, - SPELL_MISS_EVADE = 6, - SPELL_MISS_IMMUNE = 7, - SPELL_MISS_IMMUNE2 = 8, - SPELL_MISS_DEFLECT = 9, - SPELL_MISS_ABSORB = 10, - SPELL_MISS_REFLECT = 11 -}; - -enum SpellHitType -{ - SPELL_HIT_TYPE_UNK1 = 0x00001, - SPELL_HIT_TYPE_CRIT = 0x00002, - SPELL_HIT_TYPE_UNK3 = 0x00004, - SPELL_HIT_TYPE_UNK4 = 0x00008, - SPELL_HIT_TYPE_UNK5 = 0x00010, // replace caster? - SPELL_HIT_TYPE_UNK6 = 0x00020 -}; - -enum SpellDmgClass -{ - SPELL_DAMAGE_CLASS_NONE = 0, - SPELL_DAMAGE_CLASS_MAGIC = 1, - SPELL_DAMAGE_CLASS_MELEE = 2, - SPELL_DAMAGE_CLASS_RANGED = 3 -}; - -enum SpellPreventionType -{ - SPELL_PREVENTION_TYPE_NONE = 0, - SPELL_PREVENTION_TYPE_SILENCE = 1, - SPELL_PREVENTION_TYPE_PACIFY = 2 -}; - -enum GameobjectTypes -{ - GAMEOBJECT_TYPE_DOOR = 0, - GAMEOBJECT_TYPE_BUTTON = 1, - GAMEOBJECT_TYPE_QUESTGIVER = 2, - GAMEOBJECT_TYPE_CHEST = 3, - GAMEOBJECT_TYPE_BINDER = 4, - GAMEOBJECT_TYPE_GENERIC = 5, - GAMEOBJECT_TYPE_TRAP = 6, - GAMEOBJECT_TYPE_CHAIR = 7, - GAMEOBJECT_TYPE_SPELL_FOCUS = 8, - GAMEOBJECT_TYPE_TEXT = 9, - GAMEOBJECT_TYPE_GOOBER = 10, - GAMEOBJECT_TYPE_TRANSPORT = 11, - GAMEOBJECT_TYPE_AREADAMAGE = 12, - GAMEOBJECT_TYPE_CAMERA = 13, - GAMEOBJECT_TYPE_MAP_OBJECT = 14, - GAMEOBJECT_TYPE_MO_TRANSPORT = 15, - GAMEOBJECT_TYPE_DUEL_ARBITER = 16, - GAMEOBJECT_TYPE_FISHINGNODE = 17, - GAMEOBJECT_TYPE_SUMMONING_RITUAL = 18, - GAMEOBJECT_TYPE_MAILBOX = 19, - GAMEOBJECT_TYPE_DO_NOT_USE = 20, - GAMEOBJECT_TYPE_GUARDPOST = 21, - GAMEOBJECT_TYPE_SPELLCASTER = 22, - GAMEOBJECT_TYPE_MEETINGSTONE = 23, - GAMEOBJECT_TYPE_FLAGSTAND = 24, - GAMEOBJECT_TYPE_FISHINGHOLE = 25, - GAMEOBJECT_TYPE_FLAGDROP = 26, - GAMEOBJECT_TYPE_MINI_GAME = 27, - GAMEOBJECT_TYPE_DO_NOT_USE_2 = 28, - GAMEOBJECT_TYPE_CAPTURE_POINT = 29, - GAMEOBJECT_TYPE_AURA_GENERATOR = 30, - GAMEOBJECT_TYPE_DUNGEON_DIFFICULTY = 31, - GAMEOBJECT_TYPE_BARBER_CHAIR = 32, - GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING = 33, - GAMEOBJECT_TYPE_GUILD_BANK = 34, - GAMEOBJECT_TYPE_TRAPDOOR = 35 -}; - -#define MAX_GAMEOBJECT_TYPE 36 // sending to client this or greater value can crash client. - -#define GAMEOBJECT_FISHINGNODE_ENTRY 35591 // Better to define it somewhere instead of hardcoding everywhere - -enum GameObjectFlags -{ - GO_FLAG_IN_USE = 0x00000001, //disables interaction while animated - GO_FLAG_LOCKED = 0x00000002, //require key, spell, event, etc to be opened. Makes "Locked" appear in tooltip - GO_FLAG_INTERACT_COND = 0x00000004, //cannot interact (condition to interact) - GO_FLAG_TRANSPORT = 0x00000008, //any kind of transport? Object can transport (elevator, boat, car) - GO_FLAG_UNK1 = 0x00000010, // - GO_FLAG_NODESPAWN = 0x00000020, //never despawn, typically for doors, they just change state - GO_FLAG_TRIGGERED = 0x00000040, //typically, summoned objects. Triggered by spell or other events - GO_FLAG_DAMAGED = 0x00000200, - GO_FLAG_DESTROYED = 0x00000400, -}; - -enum TextEmotes -{ - TEXTEMOTE_AGREE = 1, - TEXTEMOTE_AMAZE = 2, - TEXTEMOTE_ANGRY = 3, - TEXTEMOTE_APOLOGIZE = 4, - TEXTEMOTE_APPLAUD = 5, - TEXTEMOTE_BASHFUL = 6, - TEXTEMOTE_BECKON = 7, - TEXTEMOTE_BEG = 8, - TEXTEMOTE_BITE = 9, - TEXTEMOTE_BLEED = 10, - TEXTEMOTE_BLINK = 11, - TEXTEMOTE_BLUSH = 12, - TEXTEMOTE_BONK = 13, - TEXTEMOTE_BORED = 14, - TEXTEMOTE_BOUNCE = 15, - TEXTEMOTE_BRB = 16, - TEXTEMOTE_BOW = 17, - TEXTEMOTE_BURP = 18, - TEXTEMOTE_BYE = 19, - TEXTEMOTE_CACKLE = 20, - TEXTEMOTE_CHEER = 21, - TEXTEMOTE_CHICKEN = 22, - TEXTEMOTE_CHUCKLE = 23, - TEXTEMOTE_CLAP = 24, - TEXTEMOTE_CONFUSED = 25, - TEXTEMOTE_CONGRATULATE = 26, - TEXTEMOTE_COUGH = 27, - TEXTEMOTE_COWER = 28, - TEXTEMOTE_CRACK = 29, - TEXTEMOTE_CRINGE = 30, - TEXTEMOTE_CRY = 31, - TEXTEMOTE_CURIOUS = 32, - TEXTEMOTE_CURTSEY = 33, - TEXTEMOTE_DANCE = 34, - TEXTEMOTE_DRINK = 35, - TEXTEMOTE_DROOL = 36, - TEXTEMOTE_EAT = 37, - TEXTEMOTE_EYE = 38, - TEXTEMOTE_FART = 39, - TEXTEMOTE_FIDGET = 40, - TEXTEMOTE_FLEX = 41, - TEXTEMOTE_FROWN = 42, - TEXTEMOTE_GASP = 43, - TEXTEMOTE_GAZE = 44, - TEXTEMOTE_GIGGLE = 45, - TEXTEMOTE_GLARE = 46, - TEXTEMOTE_GLOAT = 47, - TEXTEMOTE_GREET = 48, - TEXTEMOTE_GRIN = 49, - TEXTEMOTE_GROAN = 50, - TEXTEMOTE_GROVEL = 51, - TEXTEMOTE_GUFFAW = 52, - TEXTEMOTE_HAIL = 53, - TEXTEMOTE_HAPPY = 54, - TEXTEMOTE_HELLO = 55, - TEXTEMOTE_HUG = 56, - TEXTEMOTE_HUNGRY = 57, - TEXTEMOTE_KISS = 58, - TEXTEMOTE_KNEEL = 59, - TEXTEMOTE_LAUGH = 60, - TEXTEMOTE_LAYDOWN = 61, - TEXTEMOTE_MESSAGE = 62, - TEXTEMOTE_MOAN = 63, - TEXTEMOTE_MOON = 64, - TEXTEMOTE_MOURN = 65, - TEXTEMOTE_NO = 66, - TEXTEMOTE_NOD = 67, - TEXTEMOTE_NOSEPICK = 68, - TEXTEMOTE_PANIC = 69, - TEXTEMOTE_PEER = 70, - TEXTEMOTE_PLEAD = 71, - TEXTEMOTE_POINT = 72, - TEXTEMOTE_POKE = 73, - TEXTEMOTE_PRAY = 74, - TEXTEMOTE_ROAR = 75, - TEXTEMOTE_ROFL = 76, - TEXTEMOTE_RUDE = 77, - TEXTEMOTE_SALUTE = 78, - TEXTEMOTE_SCRATCH = 79, - TEXTEMOTE_SEXY = 80, - TEXTEMOTE_SHAKE = 81, - TEXTEMOTE_SHOUT = 82, - TEXTEMOTE_SHRUG = 83, - TEXTEMOTE_SHY = 84, - TEXTEMOTE_SIGH = 85, - TEXTEMOTE_SIT = 86, - TEXTEMOTE_SLEEP = 87, - TEXTEMOTE_SNARL = 88, - TEXTEMOTE_SPIT = 89, - TEXTEMOTE_STARE = 90, - TEXTEMOTE_SURPRISED = 91, - TEXTEMOTE_SURRENDER = 92, - TEXTEMOTE_TALK = 93, - TEXTEMOTE_TALKEX = 94, - TEXTEMOTE_TALKQ = 95, - TEXTEMOTE_TAP = 96, - TEXTEMOTE_THANK = 97, - TEXTEMOTE_THREATEN = 98, - TEXTEMOTE_TIRED = 99, - TEXTEMOTE_VICTORY = 100, - TEXTEMOTE_WAVE = 101, - TEXTEMOTE_WELCOME = 102, - TEXTEMOTE_WHINE = 103, - TEXTEMOTE_WHISTLE = 104, - TEXTEMOTE_WORK = 105, - TEXTEMOTE_YAWN = 106, - TEXTEMOTE_BOGGLE = 107, - TEXTEMOTE_CALM = 108, - TEXTEMOTE_COLD = 109, - TEXTEMOTE_COMFORT = 110, - TEXTEMOTE_CUDDLE = 111, - TEXTEMOTE_DUCK = 112, - TEXTEMOTE_INSULT = 113, - TEXTEMOTE_INTRODUCE = 114, - TEXTEMOTE_JK = 115, - TEXTEMOTE_LICK = 116, - TEXTEMOTE_LISTEN = 117, - TEXTEMOTE_LOST = 118, - TEXTEMOTE_MOCK = 119, - TEXTEMOTE_PONDER = 120, - TEXTEMOTE_POUNCE = 121, - TEXTEMOTE_PRAISE = 122, - TEXTEMOTE_PURR = 123, - TEXTEMOTE_PUZZLE = 124, - TEXTEMOTE_RAISE = 125, - TEXTEMOTE_READY = 126, - TEXTEMOTE_SHIMMY = 127, - TEXTEMOTE_SHIVER = 128, - TEXTEMOTE_SHOO = 129, - TEXTEMOTE_SLAP = 130, - TEXTEMOTE_SMIRK = 131, - TEXTEMOTE_SNIFF = 132, - TEXTEMOTE_SNUB = 133, - TEXTEMOTE_SOOTHE = 134, - TEXTEMOTE_STINK = 135, - TEXTEMOTE_TAUNT = 136, - TEXTEMOTE_TEASE = 137, - TEXTEMOTE_THIRSTY = 138, - TEXTEMOTE_VETO = 139, - TEXTEMOTE_SNICKER = 140, - TEXTEMOTE_STAND = 141, - TEXTEMOTE_TICKLE = 142, - TEXTEMOTE_VIOLIN = 143, - TEXTEMOTE_SMILE = 163, - TEXTEMOTE_RASP = 183, - TEXTEMOTE_PITY = 203, - TEXTEMOTE_GROWL = 204, - TEXTEMOTE_BARK = 205, - TEXTEMOTE_SCARED = 223, - TEXTEMOTE_FLOP = 224, - TEXTEMOTE_LOVE = 225, - TEXTEMOTE_MOO = 226, - TEXTEMOTE_OPENFIRE = 327, - TEXTEMOTE_FLIRT = 328, - TEXTEMOTE_JOKE = 329, - TEXTEMOTE_COMMEND = 243, - TEXTEMOTE_WINK = 363, - TEXTEMOTE_PAT = 364, - TEXTEMOTE_SERIOUS = 365, - TEXTEMOTE_MOUNTSPECIAL = 366, - TEXTEMOTE_GOODLUCK = 367, - TEXTEMOTE_BLAME = 368, - TEXTEMOTE_BLANK = 369, - TEXTEMOTE_BRANDISH = 370, - TEXTEMOTE_BREATH = 371, - TEXTEMOTE_DISAGREE = 372, - TEXTEMOTE_DOUBT = 373, - TEXTEMOTE_EMBARRASS = 374, - TEXTEMOTE_ENCOURAGE = 375, - TEXTEMOTE_ENEMY = 376, - TEXTEMOTE_EYEBROW = 377, - TEXTEMOTE_TOAST = 378 -}; - -enum Emote -{ - EMOTE_ONESHOT_NONE = 0, - EMOTE_ONESHOT_TALK = 1, - EMOTE_ONESHOT_BOW = 2, - EMOTE_ONESHOT_WAVE = 3, - EMOTE_ONESHOT_CHEER = 4, - EMOTE_ONESHOT_EXCLAMATION = 5, - EMOTE_ONESHOT_QUESTION = 6, - EMOTE_ONESHOT_EAT = 7, - EMOTE_STATE_DANCE = 10, - EMOTE_ONESHOT_LAUGH = 11, - EMOTE_STATE_SLEEP = 12, - EMOTE_STATE_SIT = 13, - EMOTE_ONESHOT_RUDE = 14, - EMOTE_ONESHOT_ROAR = 15, - EMOTE_ONESHOT_KNEEL = 16, - EMOTE_ONESHOT_KISS = 17, - EMOTE_ONESHOT_CRY = 18, - EMOTE_ONESHOT_CHICKEN = 19, - EMOTE_ONESHOT_BEG = 20, - EMOTE_ONESHOT_APPLAUD = 21, - EMOTE_ONESHOT_SHOUT = 22, - EMOTE_ONESHOT_FLEX = 23, - EMOTE_ONESHOT_SHY = 24, - EMOTE_ONESHOT_POINT = 25, - EMOTE_STATE_STAND = 26, - EMOTE_STATE_READYUNARMED = 27, - EMOTE_STATE_WORK_SHEATHED = 28, - EMOTE_STATE_POINT = 29, - EMOTE_STATE_NONE = 30, - EMOTE_ONESHOT_WOUND = 33, - EMOTE_ONESHOT_WOUNDCRITICAL = 34, - EMOTE_ONESHOT_ATTACKUNARMED = 35, - EMOTE_ONESHOT_ATTACK1H = 36, - EMOTE_ONESHOT_ATTACK2HTIGHT = 37, - EMOTE_ONESHOT_ATTACK2HLOOSE = 38, - EMOTE_ONESHOT_PARRYUNARMED = 39, - EMOTE_ONESHOT_PARRYSHIELD = 43, - EMOTE_ONESHOT_READYUNARMED = 44, - EMOTE_ONESHOT_READY1H = 45, - EMOTE_ONESHOT_READYBOW = 48, - EMOTE_ONESHOT_SPELLPRECAST = 50, - EMOTE_ONESHOT_SPELLCAST = 51, - EMOTE_ONESHOT_BATTLEROAR = 53, - EMOTE_ONESHOT_SPECIALATTACK1H = 54, - EMOTE_ONESHOT_KICK = 60, - EMOTE_ONESHOT_ATTACKTHROWN = 61, - EMOTE_STATE_STUN = 64, - EMOTE_STATE_DEAD = 65, - EMOTE_ONESHOT_SALUTE = 66, - EMOTE_STATE_KNEEL = 68, - EMOTE_STATE_USESTANDING = 69, - EMOTE_ONESHOT_WAVE_NOSHEATHE = 70, - EMOTE_ONESHOT_CHEER_NOSHEATHE = 71, - EMOTE_ONESHOT_EAT_NOSHEATHE = 92, - EMOTE_STATE_STUN_NOSHEATHE = 93, - EMOTE_ONESHOT_DANCE = 94, - EMOTE_ONESHOT_SALUTE_NOSHEATH = 113, - EMOTE_STATE_USESTANDING_NOSHEATHE = 133, - EMOTE_ONESHOT_LAUGH_NOSHEATHE = 153, - EMOTE_STATE_WORK = 173, - EMOTE_STATE_SPELLPRECAST = 193, - EMOTE_ONESHOT_READYRIFLE = 213, - EMOTE_STATE_READYRIFLE = 214, - EMOTE_STATE_WORK_MINING = 233, - EMOTE_STATE_WORK_CHOPWOOD = 234, - EMOTE_STATE_APPLAUD = 253, - EMOTE_ONESHOT_LIFTOFF = 254, - EMOTE_ONESHOT_YES = 273, - EMOTE_ONESHOT_NO = 274, - EMOTE_ONESHOT_TRAIN = 275, - EMOTE_ONESHOT_LAND = 293, - EMOTE_STATE_AT_EASE = 313, - EMOTE_STATE_READY1H = 333, - EMOTE_STATE_SPELLKNEELSTART = 353, - EMOTE_STATE_SUBMERGED = 373, - EMOTE_ONESHOT_SUBMERGE = 374, - EMOTE_STATE_READY2H = 375, - EMOTE_STATE_READYBOW = 376, - EMOTE_ONESHOT_MOUNTSPECIAL = 377, - EMOTE_STATE_TALK = 378, - EMOTE_STATE_FISHING = 379, - EMOTE_ONESHOT_FISHING = 380, - EMOTE_ONESHOT_LOOT = 381, - EMOTE_STATE_WHIRLWIND = 382, - EMOTE_STATE_DROWNED = 383, - EMOTE_STATE_HOLD_BOW = 384, - EMOTE_STATE_HOLD_RIFLE = 385, - EMOTE_STATE_HOLD_THROWN = 386, - EMOTE_ONESHOT_DROWN = 387, - EMOTE_ONESHOT_STOMP = 388, - EMOTE_ONESHOT_ATTACKOFF = 389, - EMOTE_ONESHOT_ATTACKOFFPIERCE = 390, - EMOTE_STATE_ROAR = 391, - EMOTE_STATE_LAUGH = 392, - EMOTE_ONESHOT_CREATURE_SPECIAL = 393, - EMOTE_ONESHOT_JUMPLANDRUN = 394, - EMOTE_ONESHOT_JUMPEND = 395, - EMOTE_ONESHOT_TALK_NOSHEATHE = 396, - EMOTE_ONESHOT_POINT_NOSHEATHE = 397, - EMOTE_STATE_CANNIBALIZE = 398, - EMOTE_ONESHOT_JUMPSTART = 399, - EMOTE_STATE_DANCESPECIAL = 400, - EMOTE_ONESHOT_DANCESPECIAL = 401, - EMOTE_ONESHOT_CUSTOMSPELL01 = 402, - EMOTE_ONESHOT_CUSTOMSPELL02 = 403, - EMOTE_ONESHOT_CUSTOMSPELL03 = 404, - EMOTE_ONESHOT_CUSTOMSPELL04 = 405, - EMOTE_ONESHOT_CUSTOMSPELL05 = 406, - EMOTE_ONESHOT_CUSTOMSPELL06 = 407, - EMOTE_ONESHOT_CUSTOMSPELL07 = 408, - EMOTE_ONESHOT_CUSTOMSPELL08 = 409, - EMOTE_ONESHOT_CUSTOMSPELL09 = 410, - EMOTE_ONESHOT_CUSTOMSPELL10 = 411, - EMOTE_STATE_EXCLAIM = 412, - EMOTE_STATE_DANCE_CUSTOM = 413, - EMOTE_STATE_SIT_CHAIR_MED = 415, - EMOTE_STATE_CUSTOM_SPELL_01 = 416, - EMOTE_STATE_CUSTOM_SPELL_02 = 417, - EMOTE_STATE_EAT = 418, - EMOTE_STATE_CUSTOM_SPELL_04 = 419, - EMOTE_STATE_CUSTOM_SPELL_03 = 420, - EMOTE_STATE_CUSTOM_SPELL_05 = 421, - EMOTE_STATE_SPELLEFFECT_HOLD = 422, - EMOTE_STATE_EAT_NO_SHEATHE = 423, - EMOTE_STATE_MOUNT = 424, - EMOTE_STATE_READY2HL = 425, - EMOTE_STATE_SIT_CHAIR_HIGH = 426, - EMOTE_STATE_FALL = 427, - EMOTE_STATE_LOOT = 428, - EMOTE_STATE_SUBMERGED_NEW = 429, - EMOTE_ONESHOT_COWER = 430, - EMOTE_STATE_COWER = 431, - EMOTE_ONESHOT_USESTANDING = 432, - EMOTE_STATE_STEALTH_STAND = 433, - EMOTE_ONESHOT_OMNICAST_GHOUL = 434, - EMOTE_ONESHOT_ATTACKBOW = 435, - EMOTE_ONESHOT_ATTACKRIFLE = 436, - EMOTE_STATE_SWIM_IDLE = 437, - EMOTE_STATE_ATTACK_UNARMED = 438, - EMOTE_ONESHOT_SPELLCAST_W_SOUND = 439, - EMOTE_ONESHOT_DODGE = 440, - EMOTE_ONESHOT_PARRY1H = 441, - EMOTE_ONESHOT_PARRY2H = 442, - EMOTE_ONESHOT_PARRY2HL = 443, - EMOTE_STATE_FLYFALL = 444, - EMOTE_ONESHOT_FLYDEATH = 445, - EMOTE_STATE_FLY_FALL = 446, - EMOTE_ONESHOT_FLY_SIT_GROUND_DOWN = 447, - EMOTE_ONESHOT_FLY_SIT_GROUND_UP = 448, - EMOTE_ONESHOT_EMERGE = 449, - EMOTE_ONESHOT_DRAGONSPIT = 450, - EMOTE_STATE_SPECIALUNARMED = 451, - EMOTE_ONESHOT_FLYGRAB = 452, - EMOTE_STATE_FLYGRABCLOSED = 453, - EMOTE_ONESHOT_FLYGRABTHROWN = 454, - EMOTE_STATE_FLY_SIT_GROUND = 455, - EMOTE_STATE_WALKBACKWARDS = 456, - EMOTE_ONESHOT_FLYTALK = 457, - EMOTE_ONESHOT_FLYATTACK1H = 458, - EMOTE_STATE_CUSTOMSPELL08 = 459, - EMOTE_ONESHOT_FLY_DRAGONSPIT = 460, - EMOTE_STATE_SIT_CHAIR_LOW = 461, - EMOTE_ONE_SHOT_STUN = 462, - EMOTE_ONESHOT_SPELLCAST_OMNI = 463, - EMOTE_STATE_READYTHROWN = 464 -}; - -enum Anim -{ - ANIM_STAND = 0x0, - ANIM_DEATH = 0x1, - ANIM_SPELL = 0x2, - ANIM_STOP = 0x3, - ANIM_WALK = 0x4, - ANIM_RUN = 0x5, - ANIM_DEAD = 0x6, - ANIM_RISE = 0x7, - ANIM_STANDWOUND = 0x8, - ANIM_COMBATWOUND = 0x9, - ANIM_COMBATCRITICAL = 0xA, - ANIM_SHUFFLE_LEFT = 0xB, - ANIM_SHUFFLE_RIGHT = 0xC, - ANIM_WALK_BACKWARDS = 0xD, - ANIM_STUN = 0xE, - ANIM_HANDS_CLOSED = 0xF, - ANIM_ATTACKUNARMED = 0x10, - ANIM_ATTACK1H = 0x11, - ANIM_ATTACK2HTIGHT = 0x12, - ANIM_ATTACK2HLOOSE = 0x13, - ANIM_PARRYUNARMED = 0x14, - ANIM_PARRY1H = 0x15, - ANIM_PARRY2HTIGHT = 0x16, - ANIM_PARRY2HLOOSE = 0x17, - ANIM_PARRYSHIELD = 0x18, - ANIM_READYUNARMED = 0x19, - ANIM_READY1H = 0x1A, - ANIM_READY2HTIGHT = 0x1B, - ANIM_READY2HLOOSE = 0x1C, - ANIM_READYBOW = 0x1D, - ANIM_DODGE = 0x1E, - ANIM_SPELLPRECAST = 0x1F, - ANIM_SPELLCAST = 0x20, - ANIM_SPELLCASTAREA = 0x21, - ANIM_NPCWELCOME = 0x22, - ANIM_NPCGOODBYE = 0x23, - ANIM_BLOCK = 0x24, - ANIM_JUMPSTART = 0x25, - ANIM_JUMP = 0x26, - ANIM_JUMPEND = 0x27, - ANIM_FALL = 0x28, - ANIM_SWIMIDLE = 0x29, - ANIM_SWIM = 0x2A, - ANIM_SWIM_LEFT = 0x2B, - ANIM_SWIM_RIGHT = 0x2C, - ANIM_SWIM_BACKWARDS = 0x2D, - ANIM_ATTACKBOW = 0x2E, - ANIM_FIREBOW = 0x2F, - ANIM_READYRIFLE = 0x30, - ANIM_ATTACKRIFLE = 0x31, - ANIM_LOOT = 0x32, - ANIM_SPELL_PRECAST_DIRECTED = 0x33, - ANIM_SPELL_PRECAST_OMNI = 0x34, - ANIM_SPELL_CAST_DIRECTED = 0x35, - ANIM_SPELL_CAST_OMNI = 0x36, - ANIM_SPELL_BATTLEROAR = 0x37, - ANIM_SPELL_READYABILITY = 0x38, - ANIM_SPELL_SPECIAL1H = 0x39, - ANIM_SPELL_SPECIAL2H = 0x3A, - ANIM_SPELL_SHIELDBASH = 0x3B, - ANIM_EMOTE_TALK = 0x3C, - ANIM_EMOTE_EAT = 0x3D, - ANIM_EMOTE_WORK = 0x3E, - ANIM_EMOTE_USE_STANDING = 0x3F, - ANIM_EMOTE_EXCLAMATION = 0x40, - ANIM_EMOTE_QUESTION = 0x41, - ANIM_EMOTE_BOW = 0x42, - ANIM_EMOTE_WAVE = 0x43, - ANIM_EMOTE_CHEER = 0x44, - ANIM_EMOTE_DANCE = 0x45, - ANIM_EMOTE_LAUGH = 0x46, - ANIM_EMOTE_SLEEP = 0x47, - ANIM_EMOTE_SIT_GROUND = 0x48, - ANIM_EMOTE_RUDE = 0x49, - ANIM_EMOTE_ROAR = 0x4A, - ANIM_EMOTE_KNEEL = 0x4B, - ANIM_EMOTE_KISS = 0x4C, - ANIM_EMOTE_CRY = 0x4D, - ANIM_EMOTE_CHICKEN = 0x4E, - ANIM_EMOTE_BEG = 0x4F, - ANIM_EMOTE_APPLAUD = 0x50, - ANIM_EMOTE_SHOUT = 0x51, - ANIM_EMOTE_FLEX = 0x52, - ANIM_EMOTE_SHY = 0x53, - ANIM_EMOTE_POINT = 0x54, - ANIM_ATTACK1HPIERCE = 0x55, - ANIM_ATTACK2HLOOSEPIERCE = 0x56, - ANIM_ATTACKOFF = 0x57, - ANIM_ATTACKOFFPIERCE = 0x58, - ANIM_SHEATHE = 0x59, - ANIM_HIPSHEATHE = 0x5A, - ANIM_MOUNT = 0x5B, - ANIM_RUN_LEANRIGHT = 0x5C, - ANIM_RUN_LEANLEFT = 0x5D, - ANIM_MOUNT_SPECIAL = 0x5E, - ANIM_KICK = 0x5F, - ANIM_SITDOWN = 0x60, - ANIM_SITTING = 0x61, - ANIM_SITUP = 0x62, - ANIM_SLEEPDOWN = 0x63, - ANIM_SLEEPING = 0x64, - ANIM_SLEEPUP = 0x65, - ANIM_SITCHAIRLOW = 0x66, - ANIM_SITCHAIRMEDIUM = 0x67, - ANIM_SITCHAIRHIGH = 0x68, - ANIM_LOADBOW = 0x69, - ANIM_LOADRIFLE = 0x6A, - ANIM_ATTACKTHROWN = 0x6B, - ANIM_READYTHROWN = 0x6C, - ANIM_HOLDBOW = 0x6D, - ANIM_HOLDRIFLE = 0x6E, - ANIM_HOLDTHROWN = 0x6F, - ANIM_LOADTHROWN = 0x70, - ANIM_EMOTE_SALUTE = 0x71, - ANIM_KNEELDOWN = 0x72, - ANIM_KNEELING = 0x73, - ANIM_KNEELUP = 0x74, - ANIM_ATTACKUNARMEDOFF = 0x75, - ANIM_SPECIALUNARMED = 0x76, - ANIM_STEALTHWALK = 0x77, - ANIM_STEALTHSTAND = 0x78, - ANIM_KNOCKDOWN = 0x79, - ANIM_EATING = 0x7A, - ANIM_USESTANDINGLOOP = 0x7B, - ANIM_CHANNELCASTDIRECTED = 0x7C, - ANIM_CHANNELCASTOMNI = 0x7D, - ANIM_WHIRLWIND = 0x7E, - ANIM_BIRTH = 0x7F, - ANIM_USESTANDINGSTART = 0x80, - ANIM_USESTANDINGEND = 0x81, - ANIM_HOWL = 0x82, - ANIM_DROWN = 0x83, - ANIM_DROWNED = 0x84, - ANIM_FISHINGCAST = 0x85, - ANIM_FISHINGLOOP = 0x86, - ANIM_FLY = 0x87, - ANIM_EMOTE_WORK_NO_SHEATHE = 0x88, - ANIM_EMOTE_STUN_NO_SHEATHE = 0x89, - ANIM_EMOTE_USE_STANDING_NO_SHEATHE= 0x8A, - ANIM_SPELL_SLEEP_DOWN = 0x8B, - ANIM_SPELL_KNEEL_START = 0x8C, - ANIM_SPELL_KNEEL_LOOP = 0x8D, - ANIM_SPELL_KNEEL_END = 0x8E, - ANIM_SPRINT = 0x8F, - ANIM_IN_FIGHT = 0x90, - - ANIM_GAMEOBJ_SPAWN = 145, - ANIM_GAMEOBJ_CLOSE = 146, - ANIM_GAMEOBJ_CLOSED = 147, - ANIM_GAMEOBJ_OPEN = 148, - ANIM_GAMEOBJ_OPENED = 149, - ANIM_GAMEOBJ_DESTROY = 150, - ANIM_GAMEOBJ_DESTROYED = 151, - ANIM_GAMEOBJ_REBUILD = 152, - ANIM_GAMEOBJ_CUSTOM0 = 153, - ANIM_GAMEOBJ_CUSTOM1 = 154, - ANIM_GAMEOBJ_CUSTOM2 = 155, - ANIM_GAMEOBJ_CUSTOM3 = 156, - ANIM_GAMEOBJ_DESPAWN = 157, - ANIM_HOLD = 158, - ANIM_DECAY = 159, - ANIM_BOWPULL = 160, - ANIM_BOWRELEASE = 161, - ANIM_SHIPSTART = 162, - ANIM_SHIPMOVEING = 163, - ANIM_SHIPSTOP = 164, - ANIM_GROUPARROW = 165, - ANIM_ARROW = 166, - ANIM_CORPSEARROW = 167, - ANIM_GUIDEARROW = 168, - ANIM_SWAY = 169, - ANIM_DRUIDCATPOUNCE = 170, - ANIM_DRUIDCATRIP = 171, - ANIM_DRUIDCATRAKE = 172, - ANIM_DRUIDCATRAVAGE = 173, - ANIM_DRUIDCATCLAW = 174, - ANIM_DRUIDCATCOWER = 175, - ANIM_DRUIDBEARSWIPE = 176, - ANIM_DRUIDBEARBITE = 177, - ANIM_DRUIDBEARMAUL = 178, - ANIM_DRUIDBEARBASH = 179, - ANIM_DRAGONTAIL = 180, - ANIM_DRAGONSTOMP = 181, - ANIM_DRAGONSPIT = 182, - ANIM_DRAGONSPITHOVER = 183, - ANIM_DRAGONSPITFLY = 184, - ANIM_EMOTEYES = 185, - ANIM_EMOTENO = 186, - ANIM_JUMPLANDRUN = 187, - ANIM_LOOTHOLD = 188, - ANIM_LOOTUP = 189, - ANIM_STANDHIGH = 190, - ANIM_IMPACT = 191, - ANIM_LIFTOFF = 192, - ANIM_HOVER = 193, - ANIM_SUCCUBUSENTICE = 194, - ANIM_EMOTETRAIN = 195, - ANIM_EMOTEDEAD = 196, - ANIM_EMOTEDANCEONCE = 197, - ANIM_DEFLECT = 198, - ANIM_EMOTEEATNOSHEATHE = 199, - ANIM_LAND = 200, - ANIM_SUBMERGE = 201, - ANIM_SUBMERGED = 202, - ANIM_CANNIBALIZE = 203, - ANIM_ARROWBIRTH = 204, - ANIM_GROURARROWBIRTH = 205, - ANIM_CORPSEARROWBIRTH = 206, - ANIM_GUIDEARROWBIRTH = 207, - ANIM_EMOTETALKNOSHEATHE = 208, - ANIM_EMOTEPOINTNOSHEATHE = 209, - ANIM_EMOTESALUTENOSHEATHE = 210, - ANIM_EMOTEDANCESPECIAL = 211, - ANIM_MUTILATE = 212, - ANIM_CUSTOMSPELL01 = 213, - ANIM_CUSTOMSPELL02 = 214, - ANIM_CUSTOMSPELL03 = 215, - ANIM_CUSTOMSPELL04 = 216, - ANIM_CUSTOMSPELL05 = 217, - ANIM_CUSTOMSPELL06 = 218, - ANIM_CUSTOMSPELL07 = 219, - ANIM_CUSTOMSPELL08 = 220, - ANIM_CUSTOMSPELL09 = 221, - ANIM_CUSTOMSPELL10 = 222, - ANIM_StealthRun = 223 -}; - -enum LockKeyType -{ - LOCK_KEY_NONE = 0, - LOCK_KEY_ITEM = 1, - LOCK_KEY_SKILL = 2 -}; - -enum LockType -{ - LOCKTYPE_PICKLOCK = 1, - LOCKTYPE_HERBALISM = 2, - LOCKTYPE_MINING = 3, - LOCKTYPE_DISARM_TRAP = 4, - LOCKTYPE_OPEN = 5, - LOCKTYPE_TREASURE = 6, - LOCKTYPE_CALCIFIED_ELVEN_GEMS = 7, - LOCKTYPE_CLOSE = 8, - LOCKTYPE_ARM_TRAP = 9, - LOCKTYPE_QUICK_OPEN = 10, - LOCKTYPE_QUICK_CLOSE = 11, - LOCKTYPE_OPEN_TINKERING = 12, - LOCKTYPE_OPEN_KNEELING = 13, - LOCKTYPE_OPEN_ATTACKING = 14, - LOCKTYPE_GAHZRIDIAN = 15, - LOCKTYPE_BLASTING = 16, - LOCKTYPE_SLOW_OPEN = 17, - LOCKTYPE_SLOW_CLOSE = 18, - LOCKTYPE_FISHING = 19, - LOCKTYPE_INSCRIPTION = 20, - LOCKTYPE_OPEN_FROM_VEHICLE = 21 -}; - -enum TrainerType // this is important type for npcs! -{ - TRAINER_TYPE_CLASS = 0, - TRAINER_TYPE_MOUNTS = 1, // on blizz it's 2 - TRAINER_TYPE_TRADESKILLS = 2, - TRAINER_TYPE_PETS = 3 -}; - -#define MAX_TRAINER_TYPE 4 - -// CreatureType.dbc -enum CreatureType -{ - CREATURE_TYPE_BEAST = 1, - CREATURE_TYPE_DRAGONKIN = 2, - CREATURE_TYPE_DEMON = 3, - CREATURE_TYPE_ELEMENTAL = 4, - CREATURE_TYPE_GIANT = 5, - CREATURE_TYPE_UNDEAD = 6, - CREATURE_TYPE_HUMANOID = 7, - CREATURE_TYPE_CRITTER = 8, - CREATURE_TYPE_MECHANICAL = 9, - CREATURE_TYPE_NOT_SPECIFIED = 10, - CREATURE_TYPE_TOTEM = 11, - CREATURE_TYPE_NON_COMBAT_PET = 12, - CREATURE_TYPE_GAS_CLOUD = 13 -}; - -uint32 const CREATURE_TYPEMASK_DEMON_OR_UNDEAD = (1 << (CREATURE_TYPE_DEMON-1)) | (1 << (CREATURE_TYPE_UNDEAD-1)); -uint32 const CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD = (1 << (CREATURE_TYPE_HUMANOID-1)) | (1 << (CREATURE_TYPE_UNDEAD-1)); -uint32 const CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL = (1 << (CREATURE_TYPE_MECHANICAL-1)) | (1 << (CREATURE_TYPE_ELEMENTAL-1)); - -// CreatureFamily.dbc -enum CreatureFamily -{ - CREATURE_FAMILY_WOLF = 1, - CREATURE_FAMILY_CAT = 2, - CREATURE_FAMILY_SPIDER = 3, - CREATURE_FAMILY_BEAR = 4, - CREATURE_FAMILY_BOAR = 5, - CREATURE_FAMILY_CROCOLISK = 6, - CREATURE_FAMILY_CARRION_BIRD = 7, - CREATURE_FAMILY_CRAB = 8, - CREATURE_FAMILY_GORILLA = 9, - CREATURE_FAMILY_HORSE_CUSTOM = 10, // not exist in DBC but used for horse like beasts in DB - CREATURE_FAMILY_RAPTOR = 11, - CREATURE_FAMILY_TALLSTRIDER = 12, - CREATURE_FAMILY_FELHUNTER = 15, - CREATURE_FAMILY_VOIDWALKER = 16, - CREATURE_FAMILY_SUCCUBUS = 17, - CREATURE_FAMILY_DOOMGUARD = 19, - CREATURE_FAMILY_SCORPID = 20, - CREATURE_FAMILY_TURTLE = 21, - CREATURE_FAMILY_IMP = 23, - CREATURE_FAMILY_BAT = 24, - CREATURE_FAMILY_HYENA = 25, - CREATURE_FAMILY_BIRD_OF_PREY = 26, - CREATURE_FAMILY_WIND_SERPENT = 27, - CREATURE_FAMILY_REMOTE_CONTROL = 28, - CREATURE_FAMILY_FELGUARD = 29, - CREATURE_FAMILY_DRAGONHAWK = 30, - CREATURE_FAMILY_RAVAGER = 31, - CREATURE_FAMILY_WARP_STALKER = 32, - CREATURE_FAMILY_SPOREBAT = 33, - CREATURE_FAMILY_NETHER_RAY = 34, - CREATURE_FAMILY_SERPENT = 35, - CREATURE_FAMILY_MOTH = 37, - CREATURE_FAMILY_CHIMAERA = 38, - CREATURE_FAMILY_DEVILSAUR = 39, - CREATURE_FAMILY_GHOUL = 40, - CREATURE_FAMILY_SILITHID = 41, - CREATURE_FAMILY_WORM = 42, - CREATURE_FAMILY_RHINO = 43, - CREATURE_FAMILY_WASP = 44, - CREATURE_FAMILY_CORE_HOUND = 45, - CREATURE_FAMILY_SPIRIT_BEAST = 46 -}; - -enum CreatureTypeFlags -{ - CREATURE_TYPEFLAGS_TAMEABLE = 0x000001, // Tameable by any hunter - CREATURE_TYPEFLAGS_GHOST = 0x000002, // Creature are also visible for not alive player. Allow gossip interaction if npcflag allow? - CREATURE_TYPEFLAGS_UNK3 = 0x000004, - CREATURE_TYPEFLAGS_UNK4 = 0x000008, - CREATURE_TYPEFLAGS_UNK5 = 0x000010, - CREATURE_TYPEFLAGS_UNK6 = 0x000020, - CREATURE_TYPEFLAGS_UNK7 = 0x000040, - CREATURE_TYPEFLAGS_UNK8 = 0x000080, - CREATURE_TYPEFLAGS_HERBLOOT = 0x000100, // Can be looted by herbalist - CREATURE_TYPEFLAGS_MININGLOOT = 0x000200, // Can be looted by miner - CREATURE_TYPEFLAGS_UNK11 = 0x000400, - CREATURE_TYPEFLAGS_UNK12 = 0x000800, // ? Related to mounts in some way. If mounted, fight mounted, mount appear as independant when rider dies? - CREATURE_TYPEFLAGS_UNK13 = 0x001000, // ? Can aid any player in combat if in range? - CREATURE_TYPEFLAGS_UNK14 = 0x002000, - CREATURE_TYPEFLAGS_UNK15 = 0x004000, // ? Possibly not in use - CREATURE_TYPEFLAGS_ENGINEERLOOT = 0x008000, // Can be looted by engineer - CREATURE_TYPEFLAGS_EXOTIC = 0x010000, // Can be tamed by hunter as exotic pet - CREATURE_TYPEFLAGS_UNK18 = 0x020000, // ? Related to vehicles/pvp? - CREATURE_TYPEFLAGS_UNK19 = 0x040000, // ? Related to vehicle/siege weapons? - CREATURE_TYPEFLAGS_UNK20 = 0x080000, - CREATURE_TYPEFLAGS_UNK21 = 0x100000, - CREATURE_TYPEFLAGS_UNK22 = 0x200000, - CREATURE_TYPEFLAGS_UNK23 = 0x400000, - CREATURE_TYPEFLAGS_UNK24 = 0x800000 // ? First seen in 3.2.2. Related to banner/backpack of creature/companion? -}; - -enum CreatureEliteType -{ - CREATURE_ELITE_NORMAL = 0, - CREATURE_ELITE_ELITE = 1, - CREATURE_ELITE_RAREELITE = 2, - CREATURE_ELITE_WORLDBOSS = 3, - CREATURE_ELITE_RARE = 4, - CREATURE_UNKNOWN = 5 // found in 2.2.3 for 2 mobs -}; - -// values based at Holidays.dbc -enum HolidayIds -{ - HOLIDAY_NONE = 0, - - HOLIDAY_FIREWORKS_SPECTACULAR = 62, - HOLIDAY_FEAST_OF_WINTER_VEIL = 141, - HOLIDAY_NOBLEGARDEN = 181, - HOLIDAY_CHILDRENS_WEEK = 201, - HOLIDAY_CALL_TO_ARMS_AV = 283, - HOLIDAY_CALL_TO_ARMS_WS = 284, - HOLIDAY_CALL_TO_ARMS_AB = 285, - HOLIDAY_FISHING_EXTRAVAGANZA = 301, - HOLIDAY_HARVEST_FESTIVAL = 321, - HOLIDAY_HALLOWS_END = 324, - HOLIDAY_LUNAR_FESTIVAL = 327, - HOLIDAY_LOVE_IS_IN_THE_AIR = 335, - HOLIDAY_FIRE_FESTIVAL = 341, - HOLIDAY_CALL_TO_ARMS_EY = 353, - HOLIDAY_BREWFEST = 372, - HOLIDAY_DARKMOON_FAIRE_ELWYNN = 374, - HOLIDAY_DARKMOON_FAIRE_THUNDER = 375, - HOLIDAY_DARKMOON_FAIRE_SHATTRATH = 376, - HOLIDAY_PIRATES_DAY = 398, - HOLIDAY_CALL_TO_ARMS_SA = 400, - HOLIDAY_PILGRIMS_BOUNTY = 404, - HOLIDAY_WOTLK_LAUNCH = 406, - HOLIDAY_DAY_OF_DEAD = 409, - HOLIDAY_CALL_TO_ARMS_ISLE_OF_C = 420 -}; - -// values based at QuestInfo.dbc -enum QuestTypes -{ - QUEST_TYPE_ELITE = 1, - QUEST_TYPE_LIFE = 21, - QUEST_TYPE_PVP = 41, - QUEST_TYPE_RAID = 62, - QUEST_TYPE_DUNGEON = 81, - QUEST_TYPE_WORLD_EVENT = 82, - QUEST_TYPE_LEGENDARY = 83, - QUEST_TYPE_ESCORT = 84, - QUEST_TYPE_HEROIC = 85, - QUEST_TYPE_RAID_10 = 88, - QUEST_TYPE_RAID_25 = 89 -}; - -// values based at QuestSort.dbc -enum QuestSort -{ - QUEST_SORT_EPIC = 1, - QUEST_SORT_WAILING_CAVERNS_OLD = 21, - QUEST_SORT_SEASONAL = 22, - QUEST_SORT_UNDERCITY_OLD = 23, - QUEST_SORT_HERBALISM = 24, - QUEST_SORT_BATTLEGROUNDS = 25, - QUEST_SORT_ULDAMN_OLD = 41, - QUEST_SORT_WARLOCK = 61, - QUEST_SORT_WARRIOR = 81, - QUEST_SORT_SHAMAN = 82, - QUEST_SORT_FISHING = 101, - QUEST_SORT_BLACKSMITHING = 121, - QUEST_SORT_PALADIN = 141, - QUEST_SORT_MAGE = 161, - QUEST_SORT_ROGUE = 162, - QUEST_SORT_ALCHEMY = 181, - QUEST_SORT_LEATHERWORKING = 182, - QUEST_SORT_ENGINERING = 201, - QUEST_SORT_TREASURE_MAP = 221, - QUEST_SORT_SUNKEN_TEMPLE_OLD = 241, - QUEST_SORT_HUNTER = 261, - QUEST_SORT_PRIEST = 262, - QUEST_SORT_DRUID = 263, - QUEST_SORT_TAILORING = 264, - QUEST_SORT_SPECIAL = 284, - QUEST_SORT_COOKING = 304, - QUEST_SORT_FIRST_AID = 324, - QUEST_SORT_LEGENDARY = 344, - QUEST_SORT_DARKMOON_FAIRE = 364, - QUEST_SORT_AHN_QIRAJ_WAR = 365, - QUEST_SORT_LUNAR_FESTIVAL = 366, - QUEST_SORT_REPUTATION = 367, - QUEST_SORT_INVASION = 368, - QUEST_SORT_MIDSUMMER = 369, - QUEST_SORT_BREWFEST = 370, - QUEST_SORT_INSCRIPTION = 371, - QUEST_SORT_DEATH_KNIGHT = 372, - QUEST_SORT_JEWELCRAFTING = 373 -}; - -inline uint8 ClassByQuestSort(int32 QuestSort) -{ - switch(QuestSort) - { - case QUEST_SORT_WARLOCK: return CLASS_WARLOCK; - case QUEST_SORT_WARRIOR: return CLASS_WARRIOR; - case QUEST_SORT_SHAMAN: return CLASS_SHAMAN; - case QUEST_SORT_PALADIN: return CLASS_PALADIN; - case QUEST_SORT_MAGE: return CLASS_MAGE; - case QUEST_SORT_ROGUE: return CLASS_ROGUE; - case QUEST_SORT_HUNTER: return CLASS_HUNTER; - case QUEST_SORT_PRIEST: return CLASS_PRIEST; - case QUEST_SORT_DRUID: return CLASS_DRUID; - case QUEST_SORT_DEATH_KNIGHT: return CLASS_DEATH_KNIGHT; - } - return 0; -} - -enum SkillType -{ - SKILL_NONE = 0, - - SKILL_FROST = 6, - SKILL_FIRE = 8, - SKILL_ARMS = 26, - SKILL_COMBAT = 38, - SKILL_SUBTLETY = 39, - SKILL_SWORDS = 43, - SKILL_AXES = 44, - SKILL_BOWS = 45, - SKILL_GUNS = 46, - SKILL_BEAST_MASTERY = 50, - SKILL_SURVIVAL = 51, - SKILL_MACES = 54, - SKILL_2H_SWORDS = 55, - SKILL_HOLY = 56, - SKILL_SHADOW = 78, - SKILL_DEFENSE = 95, - SKILL_LANG_COMMON = 98, - SKILL_RACIAL_DWARVEN = 101, - SKILL_LANG_ORCISH = 109, - SKILL_LANG_DWARVEN = 111, - SKILL_LANG_DARNASSIAN = 113, - SKILL_LANG_TAURAHE = 115, - SKILL_DUAL_WIELD = 118, - SKILL_RACIAL_TAUREN = 124, - SKILL_ORC_RACIAL = 125, - SKILL_RACIAL_NIGHT_ELF = 126, - SKILL_FIRST_AID = 129, - SKILL_FERAL_COMBAT = 134, - SKILL_STAVES = 136, - SKILL_LANG_THALASSIAN = 137, - SKILL_LANG_DRACONIC = 138, - SKILL_LANG_DEMON_TONGUE = 139, - SKILL_LANG_TITAN = 140, - SKILL_LANG_OLD_TONGUE = 141, - SKILL_SURVIVAL2 = 142, - SKILL_RIDING_HORSE = 148, - SKILL_RIDING_WOLF = 149, - SKILL_RIDING_RAM = 152, - SKILL_RIDING_TIGER = 150, - SKILL_SWIMING = 155, - SKILL_2H_MACES = 160, - SKILL_UNARMED = 162, - SKILL_MARKSMANSHIP = 163, - SKILL_BLACKSMITHING = 164, - SKILL_LEATHERWORKING = 165, - SKILL_ALCHEMY = 171, - SKILL_2H_AXES = 172, - SKILL_DAGGERS = 173, - SKILL_THROWN = 176, - SKILL_HERBALISM = 182, - SKILL_GENERIC_DND = 183, - SKILL_RETRIBUTION = 184, - SKILL_COOKING = 185, - SKILL_MINING = 186, - SKILL_PET_IMP = 188, - SKILL_PET_FELHUNTER = 189, - SKILL_TAILORING = 197, - SKILL_ENGINERING = 202, - SKILL_PET_SPIDER = 203, - SKILL_PET_VOIDWALKER = 204, - SKILL_PET_SUCCUBUS = 205, - SKILL_PET_INFERNAL = 206, - SKILL_PET_DOOMGUARD = 207, - SKILL_PET_WOLF = 208, - SKILL_PET_CAT = 209, - SKILL_PET_BEAR = 210, - SKILL_PET_BOAR = 211, - SKILL_PET_CROCILISK = 212, - SKILL_PET_CARRION_BIRD = 213, - SKILL_PET_CRAB = 214, - SKILL_PET_GORILLA = 215, - SKILL_PET_RAPTOR = 217, - SKILL_PET_TALLSTRIDER = 218, - SKILL_RACIAL_UNDED = 220, - SKILL_CROSSBOWS = 226, - SKILL_WANDS = 228, - SKILL_POLEARMS = 229, - SKILL_PET_SCORPID = 236, - SKILL_ARCANE = 237, - SKILL_PET_TURTLE = 251, - SKILL_ASSASSINATION = 253, - SKILL_FURY = 256, - SKILL_PROTECTION = 257, - SKILL_PROTECTION2 = 267, - SKILL_PET_TALENTS = 270, - SKILL_PLATE_MAIL = 293, - SKILL_LANG_GNOMISH = 313, - SKILL_LANG_TROLL = 315, - SKILL_ENCHANTING = 333, - SKILL_DEMONOLOGY = 354, - SKILL_AFFLICTION = 355, - SKILL_FISHING = 356, - SKILL_ENHANCEMENT = 373, - SKILL_RESTORATION = 374, - SKILL_ELEMENTAL_COMBAT = 375, - SKILL_SKINNING = 393, - SKILL_MAIL = 413, - SKILL_LEATHER = 414, - SKILL_CLOTH = 415, - SKILL_SHIELD = 433, - SKILL_FIST_WEAPONS = 473, - SKILL_RIDING_RAPTOR = 533, - SKILL_RIDING_MECHANOSTRIDER = 553, - SKILL_RIDING_UNDEAD_HORSE = 554, - SKILL_RESTORATION2 = 573, - SKILL_BALANCE = 574, - SKILL_DESTRUCTION = 593, - SKILL_HOLY2 = 594, - SKILL_DISCIPLINE = 613, - SKILL_LOCKPICKING = 633, - SKILL_PET_BAT = 653, - SKILL_PET_HYENA = 654, - SKILL_PET_BIRD_OF_PREY = 655, - SKILL_PET_WIND_SERPENT = 656, - SKILL_LANG_GUTTERSPEAK = 673, - SKILL_RIDING_KODO = 713, - SKILL_RACIAL_TROLL = 733, - SKILL_RACIAL_GNOME = 753, - SKILL_RACIAL_HUMAN = 754, - SKILL_JEWELCRAFTING = 755, - SKILL_RACIAL_BLOODELF = 756, - SKILL_PET_EVENT_RC = 758, - SKILL_LANG_DRAENEI = 759, - SKILL_RACIAL_DRAENEI = 760, - SKILL_PET_FELGUARD = 761, - SKILL_RIDING = 762, - SKILL_PET_DRAGONHAWK = 763, - SKILL_PET_NETHER_RAY = 764, - SKILL_PET_SPOREBAT = 765, - SKILL_PET_WARP_STALKER = 766, - SKILL_PET_RAVAGER = 767, - SKILL_PET_SERPENT = 768, - SKILL_INTERNAL = 769, - SKILL_DK_BLOOD = 770, - SKILL_DK_FROST = 771, - SKILL_DK_UNHOLY = 772, - SKILL_INSCRIPTION = 773, - SKILL_PET_MOTH = 775, - SKILL_RUNEFORGING = 776, - SKILL_MOUNTS = 777, - SKILL_COMPANIONS = 778, - SKILL_PET_EXOTIC_CHIMAERA = 780, - SKILL_PET_EXOTIC_DEVILSAUR = 781, - SKILL_PET_GHOUL = 782, - SKILL_PET_EXOTIC_SILITHID = 783, - SKILL_PET_EXOTIC_WORM = 784, - SKILL_PET_WASP = 785, - SKILL_PET_EXOTIC_RHINO = 786, - SKILL_PET_EXOTIC_CORE_HOUND = 787, - SKILL_PET_EXOTIC_SPIRIT_BEAST = 788 -}; - -#define MAX_SKILL_TYPE 789 - -inline SkillType SkillByLockType(LockType locktype) -{ - switch(locktype) - { - case LOCKTYPE_PICKLOCK: return SKILL_LOCKPICKING; - case LOCKTYPE_HERBALISM: return SKILL_HERBALISM; - case LOCKTYPE_MINING: return SKILL_MINING; - case LOCKTYPE_FISHING: return SKILL_FISHING; - case LOCKTYPE_INSCRIPTION: return SKILL_INSCRIPTION; - default: break; - } - return SKILL_NONE; -} - -inline uint32 SkillByQuestSort(int32 QuestSort) -{ - switch(QuestSort) - { - case QUEST_SORT_HERBALISM: return SKILL_HERBALISM; - case QUEST_SORT_FISHING: return SKILL_FISHING; - case QUEST_SORT_BLACKSMITHING: return SKILL_BLACKSMITHING; - case QUEST_SORT_ALCHEMY: return SKILL_ALCHEMY; - case QUEST_SORT_LEATHERWORKING: return SKILL_LEATHERWORKING; - case QUEST_SORT_ENGINERING: return SKILL_ENGINERING; - case QUEST_SORT_TAILORING: return SKILL_TAILORING; - case QUEST_SORT_COOKING: return SKILL_COOKING; - case QUEST_SORT_FIRST_AID: return SKILL_FIRST_AID; - case QUEST_SORT_JEWELCRAFTING: return SKILL_JEWELCRAFTING; - case QUEST_SORT_INSCRIPTION: return SKILL_INSCRIPTION; - } - return 0; -} - -enum SkillCategory -{ - SKILL_CATEGORY_ATTRIBUTES = 5, - SKILL_CATEGORY_WEAPON = 6, - SKILL_CATEGORY_CLASS = 7, - SKILL_CATEGORY_ARMOR = 8, - SKILL_CATEGORY_SECONDARY = 9, // secondary professions - SKILL_CATEGORY_LANGUAGES = 10, - SKILL_CATEGORY_PROFESSION = 11, // primary professions - SKILL_CATEGORY_GENERIC = 12 -}; - -enum TotemCategory -{ - TC_SKINNING_SKIFE_OLD = 1, - TC_EARTH_TOTEM = 2, - TC_AIR_TOTEM = 3, - TC_FIRE_TOTEM = 4, - TC_WATER_TOTEM = 5, - TC_COPPER_ROD = 6, - TC_SILVER_ROD = 7, - TC_GOLDEN_ROD = 8, - TC_TRUESILVER_ROD = 9, - TC_ARCANITE_ROD = 10, - TC_MINING_PICK_OLD = 11, - TC_PHILOSOPHERS_STONE = 12, - TC_BLACKSMITH_HAMMER_OLD = 13, - TC_ARCLIGHT_SPANNER = 14, - TC_GYROMATIC_MA = 15, - TC_MASTER_TOTEM = 21, - TC_FEL_IRON_ROD = 41, - TC_ADAMANTITE_ROD = 62, - TC_ETERNIUM_ROD = 63, - TC_HOLLOW_QUILL = 81, - TC_RUNED_AZURITE_ROD = 101, - TC_VIRTUOSO_INKING_SET = 121, - TC_DRUMS = 141, - TC_GNOMISH_ARMY_KNIFE = 161, - TC_BLACKSMITH_HAMMER = 162, - TC_MINING_PICK = 165, - TC_SKINNING_KNIFE = 166, - TC_HAMMER_PICK = 167, - TC_BLADED_PICKAXE = 168, - TC_FLINT_AND_TINDER = 169, - TC_RUNED_COBALT_ROD = 189, - TC_RUNED_TITANIUM_ROD = 190 -}; - -enum UnitDynFlags -{ - UNIT_DYNFLAG_NONE = 0x0000, - UNIT_DYNFLAG_LOOTABLE = 0x0001, - UNIT_DYNFLAG_TRACK_UNIT = 0x0002, - UNIT_DYNFLAG_TAPPED = 0x0004, // Lua_UnitIsTapped - UNIT_DYNFLAG_TAPPED_BY_PLAYER = 0x0008, // Lua_UnitIsTappedByPlayer - UNIT_DYNFLAG_SPECIALINFO = 0x0010, - UNIT_DYNFLAG_DEAD = 0x0020, - UNIT_DYNFLAG_REFER_A_FRIEND = 0x0040, - UNIT_DYNFLAG_TAPPED_BY_ALL_THREAT_LIST = 0x0080 // Lua_UnitIsTappedByAllThreatList -}; - -enum CorpseDynFlags -{ - CORPSE_DYNFLAG_LOOTABLE = 0x0001 -}; - -enum WeatherType -{ - WEATHER_TYPE_FINE = 0, - WEATHER_TYPE_RAIN = 1, - WEATHER_TYPE_SNOW = 2, - WEATHER_TYPE_STORM = 3, - WEATHER_TYPE_THUNDERS = 86, - WEATHER_TYPE_BLACKRAIN = 90 -}; - -#define MAX_WEATHER_TYPE 4 - -enum ChatMsg -{ - CHAT_MSG_ADDON = 0xFFFFFFFF, - CHAT_MSG_SYSTEM = 0x00, - CHAT_MSG_SAY = 0x01, - CHAT_MSG_PARTY = 0x02, - CHAT_MSG_RAID = 0x03, - CHAT_MSG_GUILD = 0x04, - CHAT_MSG_OFFICER = 0x05, - CHAT_MSG_YELL = 0x06, - CHAT_MSG_WHISPER = 0x07, - CHAT_MSG_WHISPER_FOREIGN = 0x08, - CHAT_MSG_WHISPER_INFORM = 0x09, - CHAT_MSG_EMOTE = 0x0A, - CHAT_MSG_TEXT_EMOTE = 0x0B, - CHAT_MSG_MONSTER_SAY = 0x0C, - CHAT_MSG_MONSTER_PARTY = 0x0D, - CHAT_MSG_MONSTER_YELL = 0x0E, - CHAT_MSG_MONSTER_WHISPER = 0x0F, - CHAT_MSG_MONSTER_EMOTE = 0x10, - CHAT_MSG_CHANNEL = 0x11, - CHAT_MSG_CHANNEL_JOIN = 0x12, - CHAT_MSG_CHANNEL_LEAVE = 0x13, - CHAT_MSG_CHANNEL_LIST = 0x14, - CHAT_MSG_CHANNEL_NOTICE = 0x15, - CHAT_MSG_CHANNEL_NOTICE_USER = 0x16, - CHAT_MSG_AFK = 0x17, - CHAT_MSG_DND = 0x18, - CHAT_MSG_IGNORED = 0x19, - CHAT_MSG_SKILL = 0x1A, - CHAT_MSG_LOOT = 0x1B, - CHAT_MSG_MONEY = 0x1C, - CHAT_MSG_OPENING = 0x1D, - CHAT_MSG_TRADESKILLS = 0x1E, - CHAT_MSG_PET_INFO = 0x1F, - CHAT_MSG_COMBAT_MISC_INFO = 0x20, - CHAT_MSG_COMBAT_XP_GAIN = 0x21, - CHAT_MSG_COMBAT_HONOR_GAIN = 0x22, - CHAT_MSG_COMBAT_FACTION_CHANGE = 0x23, - CHAT_MSG_BG_SYSTEM_NEUTRAL = 0x24, - CHAT_MSG_BG_SYSTEM_ALLIANCE = 0x25, - CHAT_MSG_BG_SYSTEM_HORDE = 0x26, - CHAT_MSG_RAID_LEADER = 0x27, - CHAT_MSG_RAID_WARNING = 0x28, - CHAT_MSG_RAID_BOSS_EMOTE = 0x29, - CHAT_MSG_RAID_BOSS_WHISPER = 0x2A, - CHAT_MSG_FILTERED = 0x2B, - CHAT_MSG_BATTLEGROUND = 0x2C, - CHAT_MSG_BATTLEGROUND_LEADER = 0x2D, - CHAT_MSG_RESTRICTED = 0x2E, - CHAT_MSG_BATTLENET = 0x2F, - CHAT_MSG_ACHIEVEMENT = 0x30, - CHAT_MSG_GUILD_ACHIEVEMENT = 0x31, - CHAT_MSG_ARENA_POINTS = 0x32, - CHAT_MSG_PARTY_LEADER = 0x33 -}; - -#define MAX_CHAT_MSG_TYPE 0x34 - -enum ChatLinkColors -{ - CHAT_LINK_COLOR_TRADE = 0xffffd000, // orange - CHAT_LINK_COLOR_TALENT = 0xff4e96f7, // blue - CHAT_LINK_COLOR_SPELL = 0xff71d5ff, // bright blue - CHAT_LINK_COLOR_ENCHANT = 0xffffd000, // orange - CHAT_LINK_COLOR_ACHIEVEMENT = 0xffffff00, - CHAT_LINK_COLOR_GLYPH = 0xff66bbff -}; - -// Values from ItemPetFood (power of (value-1) used for compare with CreatureFamilyEntry.petDietMask -enum PetDiet -{ - PET_DIET_MEAT = 1, - PET_DIET_FISH = 2, - PET_DIET_CHEESE = 3, - PET_DIET_BREAD = 4, - PET_DIET_FUNGAS = 5, - PET_DIET_FRUIT = 6, - PET_DIET_RAW_MEAT = 7, - PET_DIET_RAW_FISH = 8 -}; - -#define MAX_PET_DIET 9 - -#define CHAIN_SPELL_JUMP_RADIUS 10 - -// Max values for Guild & Guild Bank -#define GUILD_BANK_MAX_TABS 6 // send by client for money log also -#define GUILD_BANK_MAX_SLOTS 98 -#define GUILD_BANK_MAX_LOGS 25 -#define GUILD_BANK_MONEY_LOGS_TAB 100 // used for money log in DB -#define GUILD_EVENTLOG_MAX_RECORDS 100 -#define GUILD_RANKS_MIN_COUNT 5 -#define GUILD_RANKS_MAX_COUNT 10 - -enum AiReaction -{ - AI_REACTION_ALERT = 0, // pre-aggro (used in client packet handler) - AI_REACTION_FRIENDLY = 1, // (NOT used in client packet handler) - AI_REACTION_HOSTILE = 2, // sent on every attack, triggers aggro sound (used in client packet handler) - AI_REACTION_AFRAID = 3, // seen for polymorph (when AI not in control of self?) (NOT used in client packet handler) - AI_REACTION_DESTROY = 4, // used on object destroy (NOT used in client packet handler) -}; - -// Diminishing Returns Types -enum DiminishingReturnsType -{ - DRTYPE_NONE = 0, // this spell is not diminished, but may have limited it's duration to 10s - DRTYPE_PLAYER = 1, // this spell is diminished only when applied on players - DRTYPE_ALL = 2 // this spell is diminished in every case -}; - -// Diminishing Return Groups -enum DiminishingGroup -{ - // Common Groups - DIMINISHING_NONE = 0, - DIMINISHING_CONTROL_STUN, // Player Controlled stuns - DIMINISHING_TRIGGER_STUN, // By aura proced stuns, usualy chance on hit talents - DIMINISHING_CONTROL_ROOT, // Immobilizing effects from casted spells - DIMINISHING_TRIGGER_ROOT, // Immobilizing effects from triggered spells like Frostbite - DIMINISHING_CHARM, - DIMINISHING_POLYMORPH, // Also: Gouge, Sap, Repentance, Hungering Cold - DIMINISHING_KNOCKOUT, // Sap, Knockout mechanics - DIMINISHING_FEAR_BLIND, // Intimidating Shout, Howl of Terror, Blind - // Warlock Specific - DIMINISHING_DEATHCOIL, // Death Coil Diminish only with another Death Coil - // Druid Specific - DIMINISHING_CYCLONE, // From 2.3.0 - // Shared Class Specific - DIMINISHING_CHEAPSHOT_POUNCE, - DIMINISHING_DISARM, // From 2.3.0 - DIMINISHING_SILENCE, // From 2.3.0 - DIMINISHING_FREEZE_SLEEP, // Hunter's Freezing Trap - DIMINISHING_BANISH, - DIMINISHING_TAUNT, - DIMINISHING_LIMITONLY // Don't Diminish, but limit duration to 10s -}; - -enum SummonCategory -{ - SUMMON_CATEGORY_WILD = 0, - SUMMON_CATEGORY_ALLY = 1, - SUMMON_CATEGORY_PET = 2, - SUMMON_CATEGORY_PUPPET = 3, - SUMMON_CATEGORY_VEHICLE = 4, -}; - -enum SummonType -{ - SUMMON_TYPE_NONE = 0, - SUMMON_TYPE_PET = 1, - SUMMON_TYPE_GUARDIAN = 2, - SUMMON_TYPE_MINION = 3, - SUMMON_TYPE_TOTEM = 4, - SUMMON_TYPE_MINIPET = 5, - SUMMON_TYPE_GUARDIAN2 = 6, - SUMMON_TYPE_WILD2 = 7, - SUMMON_TYPE_WILD3 = 8, - SUMMON_TYPE_VEHICLE = 9, - SUMMON_TYPE_VEHICLE2 = 10, - SUMMON_TYPE_OBJECT = 11, -}; - -enum EventId -{ - EVENT_SPELLCLICK = 1001, - EVENT_FALL_GROUND = 1002, - EVENT_CHARGE = 1003, -}; - -enum ResponseCodes -{ - RESPONSE_SUCCESS = 0x00, - RESPONSE_FAILURE = 0x01, - RESPONSE_CANCELLED = 0x02, - RESPONSE_DISCONNECTED = 0x03, - RESPONSE_FAILED_TO_CONNECT = 0x04, - RESPONSE_CONNECTED = 0x05, - RESPONSE_VERSION_MISMATCH = 0x06, - - CSTATUS_CONNECTING = 0x07, - CSTATUS_NEGOTIATING_SECURITY = 0x08, - CSTATUS_NEGOTIATION_COMPLETE = 0x09, - CSTATUS_NEGOTIATION_FAILED = 0x0A, - CSTATUS_AUTHENTICATING = 0x0B, - - AUTH_OK = 0x0C, - AUTH_FAILED = 0x0D, - AUTH_REJECT = 0x0E, - AUTH_BAD_SERVER_PROOF = 0x0F, - AUTH_UNAVAILABLE = 0x10, - AUTH_SYSTEM_ERROR = 0x11, - AUTH_BILLING_ERROR = 0x12, - AUTH_BILLING_EXPIRED = 0x13, - AUTH_VERSION_MISMATCH = 0x14, - AUTH_UNKNOWN_ACCOUNT = 0x15, - AUTH_INCORRECT_PASSWORD = 0x16, - AUTH_SESSION_EXPIRED = 0x17, - AUTH_SERVER_SHUTTING_DOWN = 0x18, - AUTH_ALREADY_LOGGING_IN = 0x19, - AUTH_LOGIN_SERVER_NOT_FOUND = 0x1A, - AUTH_WAIT_QUEUE = 0x1B, - AUTH_BANNED = 0x1C, - AUTH_ALREADY_ONLINE = 0x1D, - AUTH_NO_TIME = 0x1E, - AUTH_DB_BUSY = 0x1F, - AUTH_SUSPENDED = 0x20, - AUTH_PARENTAL_CONTROL = 0x21, - AUTH_LOCKED_ENFORCED = 0x22, - - REALM_LIST_IN_PROGRESS = 0x23, - REALM_LIST_SUCCESS = 0x24, - REALM_LIST_FAILED = 0x25, - REALM_LIST_INVALID = 0x26, - REALM_LIST_REALM_NOT_FOUND = 0x27, - - ACCOUNT_CREATE_IN_PROGRESS = 0x28, - ACCOUNT_CREATE_SUCCESS = 0x29, - ACCOUNT_CREATE_FAILED = 0x2A, - - CHAR_LIST_RETRIEVING = 0x2B, - CHAR_LIST_RETRIEVED = 0x2C, - CHAR_LIST_FAILED = 0x2D, - - CHAR_CREATE_IN_PROGRESS = 0x2E, - CHAR_CREATE_SUCCESS = 0x2F, - CHAR_CREATE_ERROR = 0x30, - CHAR_CREATE_FAILED = 0x31, - CHAR_CREATE_NAME_IN_USE = 0x32, - CHAR_CREATE_DISABLED = 0x33, - CHAR_CREATE_PVP_TEAMS_VIOLATION = 0x34, - CHAR_CREATE_SERVER_LIMIT = 0x35, - CHAR_CREATE_ACCOUNT_LIMIT = 0x36, - CHAR_CREATE_SERVER_QUEUE = 0x37, - CHAR_CREATE_ONLY_EXISTING = 0x38, - CHAR_CREATE_EXPANSION = 0x39, - CHAR_CREATE_EXPANSION_CLASS = 0x3A, - CHAR_CREATE_LEVEL_REQUIREMENT = 0x3B, - CHAR_CREATE_UNIQUE_CLASS_LIMIT = 0x3C, - CHAR_CREATE_CHARACTER_IN_GUILD = 0x3D, - CHAR_CREATE_RESTRICTED_RACECLASS = 0x3E, - CHAR_CREATE_CHARACTER_CHOOSE_RACE = 0x3F, - CHAR_CREATE_CHARACTER_ARENA_LEADER = 0x40, - CHAR_CREATE_CHARACTER_DELETE_MAIL = 0x41, - CHAR_CREATE_CHARACTER_SWAP_FACTION = 0x42, - CHAR_CREATE_CHARACTER_RACE_ONLY = 0x43, - - CHAR_CREATE_CHARACTER_GOLD_LIMIT = 0x44, - - CHAR_CREATE_FORCE_LOGIN = 0x45, - - CHAR_DELETE_IN_PROGRESS = 0x46, - CHAR_DELETE_SUCCESS = 0x47, - CHAR_DELETE_FAILED = 0x48, - CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 0x49, - CHAR_DELETE_FAILED_GUILD_LEADER = 0x4A, - CHAR_DELETE_FAILED_ARENA_CAPTAIN = 0x4B, - - CHAR_LOGIN_IN_PROGRESS = 0x4C, - CHAR_LOGIN_SUCCESS = 0x4D, - CHAR_LOGIN_NO_WORLD = 0x4E, - CHAR_LOGIN_DUPLICATE_CHARACTER = 0x4F, - CHAR_LOGIN_NO_INSTANCES = 0x50, - CHAR_LOGIN_FAILED = 0x51, - CHAR_LOGIN_DISABLED = 0x52, - CHAR_LOGIN_NO_CHARACTER = 0x53, - CHAR_LOGIN_LOCKED_FOR_TRANSFER = 0x54, - CHAR_LOGIN_LOCKED_BY_BILLING = 0x55, - CHAR_LOGIN_LOCKED_BY_MOBILE_AH = 0x56, - - CHAR_NAME_SUCCESS = 0x57, - CHAR_NAME_FAILURE = 0x58, - CHAR_NAME_NO_NAME = 0x59, - CHAR_NAME_TOO_SHORT = 0x5A, - CHAR_NAME_TOO_LONG = 0x5B, - CHAR_NAME_INVALID_CHARACTER = 0x5C, - CHAR_NAME_MIXED_LANGUAGES = 0x5D, - CHAR_NAME_PROFANE = 0x5E, - CHAR_NAME_RESERVED = 0x5F, - CHAR_NAME_INVALID_APOSTROPHE = 0x60, - CHAR_NAME_MULTIPLE_APOSTROPHES = 0x61, - CHAR_NAME_THREE_CONSECUTIVE = 0x62, - CHAR_NAME_INVALID_SPACE = 0x63, - CHAR_NAME_CONSECUTIVE_SPACES = 0x64, - CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 0x65, - CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 0x66, - CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 0x67 -}; - -/// Ban function modes -enum BanMode -{ - BAN_ACCOUNT, - BAN_CHARACTER, - BAN_IP -}; - -/// Ban function return codes -enum BanReturn -{ - BAN_SUCCESS, - BAN_SYNTAX_ERROR, - BAN_NOTFOUND -}; - -// indexes of BattlemasterList.dbc -enum BattleGroundTypeId -{ - BATTLEGROUND_TYPE_NONE = 0, - BATTLEGROUND_AV = 1, - BATTLEGROUND_WS = 2, - BATTLEGROUND_AB = 3, - BATTLEGROUND_NA = 4, - BATTLEGROUND_BE = 5, - BATTLEGROUND_AA = 6, - BATTLEGROUND_EY = 7, - BATTLEGROUND_RL = 8, - BATTLEGROUND_SA = 9, - BATTLEGROUND_DS = 10, - BATTLEGROUND_RV = 11, - BATTLEGROUND_IC = 30, - BATTLEGROUND_RB = 32 -}; - -#define MAX_BATTLEGROUND_TYPE_ID 33 - -enum MailResponseType -{ - MAIL_SEND = 0, - MAIL_MONEY_TAKEN = 1, - MAIL_ITEM_TAKEN = 2, - MAIL_RETURNED_TO_SENDER = 3, - MAIL_DELETED = 4, - MAIL_MADE_PERMANENT = 5 -}; - -enum MailResponseResult -{ - MAIL_OK = 0, - MAIL_ERR_EQUIP_ERROR = 1, - MAIL_ERR_CANNOT_SEND_TO_SELF = 2, - MAIL_ERR_NOT_ENOUGH_MONEY = 3, - MAIL_ERR_RECIPIENT_NOT_FOUND = 4, - MAIL_ERR_NOT_YOUR_TEAM = 5, - MAIL_ERR_INTERNAL_ERROR = 6, - MAIL_ERR_DISABLED_FOR_TRIAL_ACC = 14, - MAIL_ERR_RECIPIENT_CAP_REACHED = 15, - MAIL_ERR_CANT_SEND_WRAPPED_COD = 16, - MAIL_ERR_MAIL_AND_CHAT_SUSPENDED = 17, - MAIL_ERR_TOO_MANY_ATTACHMENTS = 18, - MAIL_ERR_MAIL_ATTACHMENT_INVALID = 19, - MAIL_ERR_ITEM_HAS_EXPIRED = 21, -}; - -enum SpellFamilyNames -{ - SPELLFAMILY_GENERIC = 0, - SPELLFAMILY_UNK1 = 1, // events, holidays - // 2 - unused - SPELLFAMILY_MAGE = 3, - SPELLFAMILY_WARRIOR = 4, - SPELLFAMILY_WARLOCK = 5, - SPELLFAMILY_PRIEST = 6, - SPELLFAMILY_DRUID = 7, - SPELLFAMILY_ROGUE = 8, - SPELLFAMILY_HUNTER = 9, - SPELLFAMILY_PALADIN = 10, - SPELLFAMILY_SHAMAN = 11, - SPELLFAMILY_UNK2 = 12, // 2 spells (silence resistance) - SPELLFAMILY_POTION = 13, - // 14 - unused - SPELLFAMILY_DEATHKNIGHT = 15, - // 16 - unused - SPELLFAMILY_PET = 17 -}; - -#endif diff --git a/src/server/game/Groups/GroupHandler.cpp b/src/server/game/Groups/GroupHandler.cpp deleted file mode 100644 index f973bc24722..00000000000 --- a/src/server/game/Groups/GroupHandler.cpp +++ /dev/null @@ -1,940 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "Opcodes.h" -#include "Log.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "Group.h" -#include "SocialMgr.h" -#include "Util.h" -#include "SpellAuras.h" -#include "Vehicle.h" -#include "LFG.h" - -class Aura; - -/* differeces from off: - -you can uninvite yourself - is is useful - -you can accept invitation even if leader went offline -*/ -/* todo: - -group_destroyed msg is sent but not shown - -reduce xp gaining when in raid group - -quest sharing has to be corrected - -FIX sending PartyMemberStats -*/ - -void WorldSession::SendPartyResult(PartyOperation operation, const std::string& member, PartyResult res) -{ - WorldPacket data(SMSG_PARTY_COMMAND_RESULT, (4+member.size()+1+4+4)); - data << (uint32)operation; - data << member; - data << (uint32)res; - data << uint32(0); // LFD cooldown related (used with ERR_PARTY_LFG_BOOT_COOLDOWN_S and ERR_PARTY_LFG_BOOT_NOT_ELIGIBLE_S) - - SendPacket(&data); -} - -void WorldSession::HandleGroupInviteOpcode(WorldPacket & recv_data) -{ - std::string membername; - recv_data >> membername; - - // attempt add selected player - - // cheating - if (!normalizePlayerName(membername)) - { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_BAD_PLAYER_NAME_S); - return; - } - - Player *player = objmgr.GetPlayer(membername.c_str()); - - // no player - if (!player) - { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_BAD_PLAYER_NAME_S); - return; - } - - // restrict invite to GMs - if (!sWorld.getConfig(CONFIG_ALLOW_GM_GROUP) && !GetPlayer()->isGameMaster() && player->isGameMaster()) - return; - - // can't group with - if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && GetPlayer()->GetTeam() != player->GetTeam()) - { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_PLAYER_WRONG_FACTION); - return; - } - if (GetPlayer()->GetInstanceId() != 0 && player->GetInstanceId() != 0 && GetPlayer()->GetInstanceId() != player->GetInstanceId() && GetPlayer()->GetMapId() == player->GetMapId()) - { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_TARGET_NOT_IN_INSTANCE_S); - return; - } - // just ignore us - if (player->GetInstanceId() != 0 && player->GetDungeonDifficulty() != GetPlayer()->GetDungeonDifficulty()) - { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_IGNORING_YOU_S); - return; - } - - if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) - { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_IGNORING_YOU_S); - return; - } - - Group *group = GetPlayer()->GetGroup(); - if (group && group->isBGGroup()) - group = GetPlayer()->GetOriginalGroup(); - - Group *group2 = player->GetGroup(); - if (group2 && group2->isBGGroup()) - group2 = player->GetOriginalGroup(); - // player already in another group or invited - if (group2 || player->GetGroupInvite()) - { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_ALREADY_IN_GROUP_S); - return; - } - - if (group) - { - // not have permissions for invite - if (group->isRaidGroup() && !group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) - { - SendPartyResult(PARTY_OP_INVITE, "", ERR_NOT_LEADER); - return; - } - // not have place - if (group->IsFull()) - { - SendPartyResult(PARTY_OP_INVITE, "", ERR_GROUP_FULL); - return; - } - } - - // ok, but group not exist, start a new group - // but don't create and save the group to the DB until - // at least one person joins - if (!group) - { - group = new Group; - // new group: if can't add then delete - if (!group->AddLeaderInvite(GetPlayer())) - { - delete group; - return; - } - if (!group->AddInvite(player)) - { - delete group; - return; - } - } - else - { - // already existed group: if can't add then just leave - if (!group->AddInvite(player)) - { - return; - } - } - - // ok, we do it - WorldPacket data(SMSG_GROUP_INVITE, 10); // guess size - data << uint8(1); // invited/already in group flag - data << GetPlayer()->GetName(); // max len 48 - data << uint32(0); // unk - data << uint8(0); // count - //for (int i = 0; i < count; ++i) - // data << uint32(0); - data << uint32(0); // unk - player->GetSession()->SendPacket(&data); - - SendLfgUpdatePlayer(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); - SendLfgUpdateParty(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); - SendPartyResult(PARTY_OP_INVITE, membername, ERR_PARTY_RESULT_OK); -} - -void WorldSession::HandleGroupAcceptOpcode(WorldPacket & /*recv_data*/) -{ - Group *group = GetPlayer()->GetGroupInvite(); - if (!group) return; - - if (group->GetLeaderGUID() == GetPlayer()->GetGUID()) - { - sLog.outError("HandleGroupAcceptOpcode: player %s(%d) tried to accept an invite to his own group", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); - return; - } - - // remove in from ivites in any case - group->RemoveInvite(GetPlayer()); - - /** error handling **/ - /********************/ - - // not have place - if (group->IsFull()) - { - SendPartyResult(PARTY_OP_INVITE, "", ERR_GROUP_FULL); - return; - } - - Player* leader = objmgr.GetPlayer(group->GetLeaderGUID()); - - // forming a new group, create it - if (!group->IsCreated()) - { - if (leader) - group->RemoveInvite(leader); - group->Create(group->GetLeaderGUID(), group->GetLeaderName()); - objmgr.AddGroup(group); - } - - // everything's fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!! - if (!group->AddMember(GetPlayer()->GetGUID(), GetPlayer()->GetName())) - return; - - SendLfgUpdatePlayer(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); - for (GroupReference *itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) - if (Player *plrg = itr->getSource()) - { - plrg->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_CLEAR_LOCK_LIST); - plrg->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_CLEAR_LOCK_LIST); - } - - group->BroadcastGroupUpdate(); -} - -void WorldSession::HandleGroupDeclineOpcode(WorldPacket & /*recv_data*/) -{ - Group *group = GetPlayer()->GetGroupInvite(); - if (!group) return; - - // remember leader if online - Player *leader = objmgr.GetPlayer(group->GetLeaderGUID()); - - // uninvite, group can be deleted - GetPlayer()->UninviteFromGroup(); - - if (!leader || !leader->GetSession()) - return; - - // report - WorldPacket data(SMSG_GROUP_DECLINE, 10); // guess size - data << GetPlayer()->GetName(); - leader->GetSession()->SendPacket(&data); -} - -void WorldSession::HandleGroupUninviteGuidOpcode(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - recv_data.read_skip(); // reason - - //can't uninvite yourself - if (guid == GetPlayer()->GetGUID()) - { - sLog.outError("WorldSession::HandleGroupUninviteGuidOpcode: leader %s(%d) tried to uninvite himself from the group.", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); - return; - } - - PartyResult res = GetPlayer()->CanUninviteFromGroup(); - if (res != ERR_PARTY_RESULT_OK) - { - SendPartyResult(PARTY_OP_UNINVITE, "", res); - return; - } - - Group* grp = GetPlayer()->GetGroup(); - if (!grp) - return; - - if (grp->IsMember(guid)) - { - Player::RemoveFromGroup(grp,guid); - return; - } - - if (Player* plr = grp->GetInvited(guid)) - { - plr->UninviteFromGroup(); - return; - } - - SendPartyResult(PARTY_OP_UNINVITE, "", ERR_TARGET_NOT_IN_GROUP_S); -} - -void WorldSession::HandleGroupUninviteOpcode(WorldPacket & recv_data) -{ - std::string membername; - recv_data >> membername; - - // player not found - if (!normalizePlayerName(membername)) - return; - - // can't uninvite yourself - if (GetPlayer()->GetName() == membername) - { - sLog.outError("WorldSession::HandleGroupUninviteOpcode: leader %s(%d) tried to uninvite himself from the group.", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); - return; - } - - PartyResult res = GetPlayer()->CanUninviteFromGroup(); - if (res != ERR_PARTY_RESULT_OK) - { - SendPartyResult(PARTY_OP_UNINVITE, "", res); - return; - } - - Group* grp = GetPlayer()->GetGroup(); - if (!grp) - return; - - if (uint64 guid = grp->GetMemberGUID(membername)) - { - Player::RemoveFromGroup(grp,guid); - return; - } - - if (Player* plr = grp->GetInvited(membername)) - { - plr->UninviteFromGroup(); - return; - } - - SendPartyResult(PARTY_OP_UNINVITE, membername, ERR_TARGET_NOT_IN_GROUP_S); -} - -void WorldSession::HandleGroupSetLeaderOpcode(WorldPacket & recv_data) -{ - Group *group = GetPlayer()->GetGroup(); - if (!group) - return; - - uint64 guid; - recv_data >> guid; - - Player *player = objmgr.GetPlayer(guid); - - /** error handling **/ - if (!player || !group->IsLeader(GetPlayer()->GetGUID()) || player->GetGroup() != group) - return; - /********************/ - - // everything's fine, do it - group->ChangeLeader(guid); -} - -void WorldSession::HandleGroupDisbandOpcode(WorldPacket & /*recv_data*/) -{ - if (!GetPlayer()->GetGroup()) - return; - - if (_player->InBattleGround()) - { - SendPartyResult(PARTY_OP_INVITE, "", ERR_INVITE_RESTRICTED); - return; - } - - /** error handling **/ - /********************/ - - // everything's fine, do it - SendPartyResult(PARTY_OP_LEAVE, GetPlayer()->GetName(), ERR_PARTY_RESULT_OK); - - GetPlayer()->RemoveFromGroup(); -} - -void WorldSession::HandleLootMethodOpcode(WorldPacket & recv_data) -{ - Group *group = GetPlayer()->GetGroup(); - if (!group) - return; - - uint32 lootMethod; - uint64 lootMaster; - uint32 lootThreshold; - recv_data >> lootMethod >> lootMaster >> lootThreshold; - - /** error handling **/ - if (!group->IsLeader(GetPlayer()->GetGUID())) - return; - /********************/ - - // everything's fine, do it - group->SetLootMethod((LootMethod)lootMethod); - group->SetLooterGuid(lootMaster); - group->SetLootThreshold((ItemQualities)lootThreshold); - group->SendUpdate(); -} - -void WorldSession::HandleLootRoll(WorldPacket &recv_data) -{ - if (!GetPlayer()->GetGroup()) - return; - - uint64 Guid; - uint32 NumberOfPlayers; - uint8 rollType; - recv_data >> Guid; //guid of the item rolled - recv_data >> NumberOfPlayers; - recv_data >> rollType; //0: pass, 1: need, 2: greed - - //sLog.outDebug("WORLD RECIEVE CMSG_LOOT_ROLL, From:%u, Numberofplayers:%u, Choise:%u", (uint32)Guid, NumberOfPlayers, Choise); - - Group* group = GetPlayer()->GetGroup(); - if (!group) - return; - - // everything's fine, do it - group->CountRollVote(GetPlayer()->GetGUID(), Guid, NumberOfPlayers, rollType); - - switch (rollType) - { - case ROLL_NEED: - GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED, 1); - break; - case ROLL_GREED: - GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED, 1); - break; - } -} - -void WorldSession::HandleMinimapPingOpcode(WorldPacket& recv_data) -{ - if (!GetPlayer()->GetGroup()) - return; - - float x, y; - recv_data >> x; - recv_data >> y; - - //sLog.outDebug("Received opcode MSG_MINIMAP_PING X: %f, Y: %f", x, y); - - /** error handling **/ - /********************/ - - // everything's fine, do it - WorldPacket data(MSG_MINIMAP_PING, (8+4+4)); - data << uint64(GetPlayer()->GetGUID()); - data << float(x); - data << float(y); - GetPlayer()->GetGroup()->BroadcastPacket(&data, true, -1, GetPlayer()->GetGUID()); -} - -void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data) -{ - uint32 minimum, maximum, roll; - recv_data >> minimum; - recv_data >> maximum; - - /** error handling **/ - if (minimum > maximum || maximum > 10000) // < 32768 for urand call - return; - /********************/ - - // everything's fine, do it - roll = urand(minimum, maximum); - - //sLog.outDebug("ROLL: MIN: %u, MAX: %u, ROLL: %u", minimum, maximum, roll); - - WorldPacket data(MSG_RANDOM_ROLL, 4+4+4+8); - data << uint32(minimum); - data << uint32(maximum); - data << uint32(roll); - data << uint64(GetPlayer()->GetGUID()); - if (GetPlayer()->GetGroup()) - GetPlayer()->GetGroup()->BroadcastPacket(&data, false); - else - SendPacket(&data); -} - -void WorldSession::HandleRaidTargetUpdateOpcode(WorldPacket & recv_data) -{ - Group *group = GetPlayer()->GetGroup(); - if (!group) - return; - - uint8 x; - recv_data >> x; - - /** error handling **/ - /********************/ - - // everything's fine, do it - if (x == 0xFF) // target icon request - { - group->SendTargetIconList(this); - } - else // target icon update - { - if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) - return; - - uint64 guid; - recv_data >> guid; - group->SetTargetIcon(x, _player->GetGUID(), guid); - } -} - -void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket & /*recv_data*/) -{ - Group *group = GetPlayer()->GetGroup(); - if (!group) - return; - - if (_player->InBattleGround()) - return; - - /** error handling **/ - if (!group->IsLeader(GetPlayer()->GetGUID()) || group->GetMembersCount() < 2) - return; - /********************/ - - // everything's fine, do it (is it 0 (PARTY_OP_INVITE) correct code) - SendPartyResult(PARTY_OP_INVITE, "", ERR_PARTY_RESULT_OK); - group->ConvertToRaid(); -} - -void WorldSession::HandleGroupChangeSubGroupOpcode(WorldPacket & recv_data) -{ - // we will get correct pointer for group here, so we don't have to check if group is BG raid - Group *group = GetPlayer()->GetGroup(); - if (!group) - return; - - std::string name; - uint8 groupNr; - recv_data >> name; - - recv_data >> groupNr; - - /** error handling **/ - uint64 senderGuid = GetPlayer()->GetGUID(); - if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid)) - return; - - if (!group->HasFreeSlotSubGroup(groupNr)) - return; - /********************/ - - Player *movedPlayer=objmgr.GetPlayer(name.c_str()); - if (!movedPlayer) - return; - - //Do not allow leader to change group of player in combat - if (movedPlayer->isInCombat()) - return; - - // everything's fine, do it - group->ChangeMembersGroup(movedPlayer, groupNr); -} - -void WorldSession::HandleGroupAssistantLeaderOpcode(WorldPacket & recv_data) -{ - Group *group = GetPlayer()->GetGroup(); - if (!group) - return; - - uint64 guid; - uint8 flag; - recv_data >> guid; - recv_data >> flag; - - /** error handling **/ - if (!group->IsLeader(GetPlayer()->GetGUID())) - return; - /********************/ - - // everything's fine, do it - group->SetAssistant(guid, (flag != 0)); -} - -void WorldSession::HandlePartyAssignmentOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("MSG_PARTY_ASSIGNMENT"); - - Group *group = GetPlayer()->GetGroup(); - if (!group) - return; - - uint8 flag, apply; - uint64 guid; - recv_data >> flag >> apply; - recv_data >> guid; - - /** error handling **/ - uint64 senderGuid = GetPlayer()->GetGUID(); - if (!group->IsLeader(senderGuid) && group->IsAssistant(senderGuid)) - return; - /********************/ - - // everything's fine, do it - if (flag == 0) - group->SetMainTank(guid, apply); - - else if (flag == 1) - group->SetMainAssistant(guid, apply); -} - -void WorldSession::HandleRaidReadyCheckOpcode(WorldPacket & recv_data) -{ - Group *group = GetPlayer()->GetGroup(); - if (!group) - return; - - if (recv_data.empty()) // request - { - /** error handling **/ - if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) - return; - /********************/ - - // everything's fine, do it - WorldPacket data(MSG_RAID_READY_CHECK, 8); - data << GetPlayer()->GetGUID(); - group->BroadcastPacket(&data, false, -1); - - group->OfflineReadyCheck(); - } - else // answer - { - uint8 state; - recv_data >> state; - - // everything's fine, do it - WorldPacket data(MSG_RAID_READY_CHECK_CONFIRM, 9); - data << uint64(GetPlayer()->GetGUID()); - data << uint8(state); - group->BroadcastReadyCheck(&data); - } -} - -void WorldSession::HandleRaidReadyCheckFinishedOpcode(WorldPacket & /*recv_data*/) -{ - //Group* group = GetPlayer()->GetGroup(); - //if (!group) - // return; - - //if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) - // return; - - // Is any reaction need? -} - -void WorldSession::BuildPartyMemberStatsChangedPacket(Player *player, WorldPacket *data) -{ - uint32 mask = player->GetGroupUpdateFlag(); - - if (mask == GROUP_UPDATE_FLAG_NONE) - return; - - if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) // if update power type, update current/max power also - mask |= (GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER); - - if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) // same for pets - mask |= (GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER); - - uint32 byteCount = 0; - for (int i = 1; i < GROUP_UPDATE_FLAGS_COUNT; ++i) - if (mask & (1 << i)) - byteCount += GroupUpdateLength[i]; - - data->Initialize(SMSG_PARTY_MEMBER_STATS, 8 + 4 + byteCount); - data->append(player->GetPackGUID()); - *data << (uint32) mask; - - if (mask & GROUP_UPDATE_FLAG_STATUS) - { - if (player) - { - if (player->IsPvP()) - *data << (uint16) (MEMBER_STATUS_ONLINE | MEMBER_STATUS_PVP); - else - *data << (uint16) MEMBER_STATUS_ONLINE; - } - else - *data << (uint16) MEMBER_STATUS_OFFLINE; - } - - if (mask & GROUP_UPDATE_FLAG_CUR_HP) - *data << (uint32) player->GetHealth(); - - if (mask & GROUP_UPDATE_FLAG_MAX_HP) - *data << (uint32) player->GetMaxHealth(); - - Powers powerType = player->getPowerType(); - if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) - *data << (uint8) powerType; - - if (mask & GROUP_UPDATE_FLAG_CUR_POWER) - *data << (uint16) player->GetPower(powerType); - - if (mask & GROUP_UPDATE_FLAG_MAX_POWER) - *data << (uint16) player->GetMaxPower(powerType); - - if (mask & GROUP_UPDATE_FLAG_LEVEL) - *data << (uint16) player->getLevel(); - - if (mask & GROUP_UPDATE_FLAG_ZONE) - *data << (uint16) player->GetZoneId(); - - if (mask & GROUP_UPDATE_FLAG_POSITION) - *data << (uint16) player->GetPositionX() << (uint16) player->GetPositionY(); - - if (mask & GROUP_UPDATE_FLAG_AURAS) - { - const uint64& auramask = player->GetAuraUpdateMaskForRaid(); - *data << uint64(auramask); - for (uint32 i = 0; i < MAX_AURAS; ++i) - { - if (auramask & (uint64(1) << i)) - { - AuraApplication const * aurApp = player->GetVisibleAura(i); - *data << uint32(aurApp ? aurApp->GetBase()->GetId() : 0); - *data << uint8(1); - } - } - } - - Pet *pet = player->GetPet(); - if (mask & GROUP_UPDATE_FLAG_PET_GUID) - { - if (pet) - *data << (uint64) pet->GetGUID(); - else - *data << (uint64) 0; - } - - if (mask & GROUP_UPDATE_FLAG_PET_NAME) - { - if (pet) - *data << pet->GetName(); - else - *data << (uint8) 0; - } - - if (mask & GROUP_UPDATE_FLAG_PET_MODEL_ID) - { - if (pet) - *data << (uint16) pet->GetDisplayId(); - else - *data << (uint16) 0; - } - - if (mask & GROUP_UPDATE_FLAG_PET_CUR_HP) - { - if (pet) - *data << (uint32) pet->GetHealth(); - else - *data << (uint32) 0; - } - - if (mask & GROUP_UPDATE_FLAG_PET_MAX_HP) - { - if (pet) - *data << (uint32) pet->GetMaxHealth(); - else - *data << (uint32) 0; - } - - if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) - { - if (pet) - *data << (uint8) pet->getPowerType(); - else - *data << (uint8) 0; - } - - if (mask & GROUP_UPDATE_FLAG_PET_CUR_POWER) - { - if (pet) - *data << (uint16) pet->GetPower(pet->getPowerType()); - else - *data << (uint16) 0; - } - - if (mask & GROUP_UPDATE_FLAG_PET_MAX_POWER) - { - if (pet) - *data << (uint16) pet->GetMaxPower(pet->getPowerType()); - else - *data << (uint16) 0; - } - - if (mask & GROUP_UPDATE_FLAG_VEHICLE_SEAT) - { - if (player->GetVehicle()){ - Vehicle* vv=player->GetVehicle(); - *data << (uint32) vv->GetVehicleInfo()->m_seatID[player->m_movementInfo.t_seat]; - } - } - - if (mask & GROUP_UPDATE_FLAG_PET_AURAS) - { - if (pet) - { - const uint64& auramask = pet->GetAuraUpdateMaskForRaid(); - *data << uint64(auramask); - for (uint32 i = 0; i < MAX_AURAS; ++i) - { - if (auramask & (uint64(1) << i)) - { - AuraApplication const * aurApp = player->GetVisibleAura(i); - *data << uint32(aurApp ? aurApp->GetBase()->GetId() : 0); - *data << uint8(1); - } - } - } - else - *data << (uint64) 0; - } -} - -/*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/ -void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_REQUEST_PARTY_MEMBER_STATS"); - uint64 Guid; - recv_data >> Guid; - - Player *player = objmgr.GetPlayer(Guid); - if (!player) - { - WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 3+4+2); - data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related - data.appendPackGUID(Guid); - data << (uint32) GROUP_UPDATE_FLAG_STATUS; - data << (uint16) MEMBER_STATUS_OFFLINE; - SendPacket(&data); - return; - } - - Pet *pet = player->GetPet(); - - WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 4+2+2+2+1+2*6+8+1+8); - data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related - data.append(player->GetPackGUID()); - - uint32 mask1 = 0x00040BFF; // common mask, real flags used 0x000040BFF - if (pet) - mask1 = 0x7FFFFFFF; // for hunters and other classes with pets - - Powers powerType = player->getPowerType(); - data << (uint32) mask1; // group update mask - data << (uint16) MEMBER_STATUS_ONLINE; // member's online status - data << (uint32) player->GetHealth(); // GROUP_UPDATE_FLAG_CUR_HP - data << (uint32) player->GetMaxHealth(); // GROUP_UPDATE_FLAG_MAX_HP - data << (uint8) powerType; // GROUP_UPDATE_FLAG_POWER_TYPE - data << (uint16) player->GetPower(powerType); // GROUP_UPDATE_FLAG_CUR_POWER - data << (uint16) player->GetMaxPower(powerType); // GROUP_UPDATE_FLAG_MAX_POWER - data << (uint16) player->getLevel(); // GROUP_UPDATE_FLAG_LEVEL - data << (uint16) player->GetZoneId(); // GROUP_UPDATE_FLAG_ZONE - data << (uint16) player->GetPositionX(); // GROUP_UPDATE_FLAG_POSITION - data << (uint16) player->GetPositionY(); // GROUP_UPDATE_FLAG_POSITION - - uint64 auramask = 0; - size_t maskPos = data.wpos(); - data << (uint64) auramask; // placeholder - for (uint8 i = 0; i < MAX_AURAS; ++i) - { - if (AuraApplication * aurApp = player->GetVisibleAura(i)) - { - auramask |= (uint64(1) << i); - data << (uint32) aurApp->GetBase()->GetId(); - data << (uint8) 1; - } - } - data.put(maskPos,auramask); // GROUP_UPDATE_FLAG_AURAS - - if (pet) - { - Powers petpowertype = pet->getPowerType(); - data << (uint64) pet->GetGUID(); // GROUP_UPDATE_FLAG_PET_GUID - data << pet->GetName(); // GROUP_UPDATE_FLAG_PET_NAME - data << (uint16) pet->GetDisplayId(); // GROUP_UPDATE_FLAG_PET_MODEL_ID - data << (uint32) pet->GetHealth(); // GROUP_UPDATE_FLAG_PET_CUR_HP - data << (uint32) pet->GetMaxHealth(); // GROUP_UPDATE_FLAG_PET_MAX_HP - data << (uint8) petpowertype; // GROUP_UPDATE_FLAG_PET_POWER_TYPE - data << (uint16) pet->GetPower(petpowertype); // GROUP_UPDATE_FLAG_PET_CUR_POWER - data << (uint16) pet->GetMaxPower(petpowertype); // GROUP_UPDATE_FLAG_PET_MAX_POWER - - uint64 petauramask = 0; - size_t petMaskPos = data.wpos(); - data << (uint64) petauramask; // placeholder - for (uint8 i = 0; i < MAX_AURAS; ++i) - { - if (AuraApplication * auraApp = pet->GetVisibleAura(i)) - { - petauramask |= (uint64(1) << i); - data << (uint32) auraApp->GetBase()->GetId(); - data << (uint8) 1; - } - } - data.put(petMaskPos,petauramask); // GROUP_UPDATE_FLAG_PET_AURAS - } - else - { - data << (uint8) 0; // GROUP_UPDATE_FLAG_PET_NAME - data << (uint64) 0; // GROUP_UPDATE_FLAG_PET_AURAS - } - - SendPacket(&data); -} - -/*!*/void WorldSession::HandleRequestRaidInfoOpcode(WorldPacket & /*recv_data*/) -{ - // every time the player checks the character screen - _player->SendRaidInfo(); -} - -/*void WorldSession::HandleGroupCancelOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: got CMSG_GROUP_CANCEL."); -}*/ - -void WorldSession::HandleOptOutOfLootOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_OPT_OUT_OF_LOOT"); - - uint32 passOnLoot; - recv_data >> passOnLoot; // 1 always pass, 0 do not pass - - // ignore if player not loaded - if (!GetPlayer()) // needed because STATUS_AUTHED - { - if (passOnLoot != 0) - sLog.outError("CMSG_OPT_OUT_OF_LOOT value<>0 for not-loaded character!"); - return; - } - - GetPlayer()->SetPassOnGroupLoot(passOnLoot); -} diff --git a/src/server/game/Guilds/GuildHandler.cpp b/src/server/game/Guilds/GuildHandler.cpp deleted file mode 100644 index 6803fe63a86..00000000000 --- a/src/server/game/Guilds/GuildHandler.cpp +++ /dev/null @@ -1,1225 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectMgr.h" -#include "Log.h" -#include "Opcodes.h" -#include "Guild.h" -#include "GossipDef.h" -#include "SocialMgr.h" - -void WorldSession::HandleGuildQueryOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_QUERY"); - - uint32 guildId; - recvPacket >> guildId; - - if (Guild *guild = objmgr.GetGuildById(guildId)) - { - guild->Query(this); - return; - } - - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); -} - -void WorldSession::HandleGuildCreateOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_CREATE"); - - std::string gname; - recvPacket >> gname; - - if (GetPlayer()->GetGuildId()) // already in guild - return; - - Guild *guild = new Guild; - if (!guild->Create(GetPlayer(), gname)) - { - delete guild; - return; - } - - objmgr.AddGuild(guild); -} - -void WorldSession::HandleGuildInviteOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_INVITE"); - - std::string Invitedname, plname; - - Player * player = NULL; - recvPacket >> Invitedname; - - if (normalizePlayerName(Invitedname)) - player = ObjectAccessor::Instance().FindPlayerByName(Invitedname.c_str()); - - if (!player) - { - SendGuildCommandResult(GUILD_INVITE_S, Invitedname, ERR_GUILD_PLAYER_NOT_FOUND_S); - return; - } - - Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - // OK result but not send invite - if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) - return; - - // not let enemies sign guild charter - if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeam() != GetPlayer()->GetTeam()) - { - SendGuildCommandResult(GUILD_INVITE_S, Invitedname, ERR_GUILD_NOT_ALLIED); - return; - } - - if (player->GetGuildId()) - { - plname = player->GetName(); - SendGuildCommandResult(GUILD_INVITE_S, plname, ERR_ALREADY_IN_GUILD_S); - return; - } - - if (player->GetGuildIdInvited()) - { - plname = player->GetName(); - SendGuildCommandResult(GUILD_INVITE_S, plname, ERR_ALREADY_INVITED_TO_GUILD_S); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_INVITE)) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - sLog.outDebug("Player %s Invited %s to Join his Guild", GetPlayer()->GetName(), Invitedname.c_str()); - - player->SetGuildIdInvited(GetPlayer()->GetGuildId()); - // Put record into guildlog - guild->LogGuildEvent(GUILD_EVENT_LOG_INVITE_PLAYER, GetPlayer()->GetGUIDLow(), player->GetGUIDLow(), 0); - - WorldPacket data(SMSG_GUILD_INVITE, (8+10)); // guess size - data << GetPlayer()->GetName(); - data << guild->GetName(); - player->GetSession()->SendPacket(&data); - - sLog.outDebug("WORLD: Sent (SMSG_GUILD_INVITE)"); -} - -void WorldSession::HandleGuildRemoveOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_REMOVE"); - - std::string plName; - recvPacket >> plName; - - if (!normalizePlayerName(plName)) - return; - - Guild* guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_REMOVE)) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - uint64 plGuid; - MemberSlot* slot = guild->GetMemberSlot(plName, plGuid); - if (!slot) - { - SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); - return; - } - - if (slot->RankId == GR_GUILDMASTER) - { - SendGuildCommandResult(GUILD_QUIT_S, "", ERR_GUILD_LEADER_LEAVE); - return; - } - - //do not allow to kick player with same or higher rights - if (GetPlayer()->GetRank() >= slot->RankId) - { - SendGuildCommandResult(GUILD_QUIT_S, plName, ERR_GUILD_RANK_TOO_HIGH_S); - return; - } - - guild->DelMember(plGuid); - // Put record into guildlog - guild->LogGuildEvent(GUILD_EVENT_LOG_UNINVITE_PLAYER, GetPlayer()->GetGUIDLow(), GUID_LOPART(plGuid), 0); - - guild->BroadcastEvent(GE_REMOVED, 0, 2, plName, _player->GetName(), ""); -} - -void WorldSession::HandleGuildAcceptOpcode(WorldPacket& /*recvPacket*/) -{ - Guild *guild; - Player *player = GetPlayer(); - - sLog.outDebug("WORLD: Received CMSG_GUILD_ACCEPT"); - - guild = objmgr.GetGuildById(player->GetGuildIdInvited()); - if (!guild || player->GetGuildId()) - return; - - // not let enemies sign guild charter - if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeam() != objmgr.GetPlayerTeamByGUID(guild->GetLeader())) - return; - - if (!guild->AddMember(GetPlayer()->GetGUID(),guild->GetLowestRank())) - return; - // Put record into guildlog - guild->LogGuildEvent(GUILD_EVENT_LOG_JOIN_GUILD, GetPlayer()->GetGUIDLow(), 0, 0); - - guild->BroadcastEvent(GE_JOINED, player->GetGUID(), 1, player->GetName(), "", ""); - - sLog.outDebug("WORLD: Sent (SMSG_GUILD_EVENT)"); -} - -void WorldSession::HandleGuildDeclineOpcode(WorldPacket& /*recvPacket*/) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_DECLINE"); - - GetPlayer()->SetGuildIdInvited(0); - GetPlayer()->SetInGuild(0); -} - -void WorldSession::HandleGuildInfoOpcode(WorldPacket& /*recvPacket*/) -{ - Guild *guild; - sLog.outDebug("WORLD: Received CMSG_GUILD_INFO"); - - guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - WorldPacket data(SMSG_GUILD_INFO, (guild->GetName().size() + 4 + 4 + 4)); - data << guild->GetName(); - data << secsToTimeBitFields(guild->GetCreatedDate()); // 3.x (prev. year + month + day) - data << guild->GetMemberSize(); // char amount - data << guild->GetMemberSize(); // acc amount - - SendPacket(&data); -} - -void WorldSession::HandleGuildRosterOpcode(WorldPacket& /*recvPacket*/) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_ROSTER"); - - if (Guild* guild = objmgr.GetGuildById(_player->GetGuildId())) - guild->Roster(this); -} - -void WorldSession::HandleGuildPromoteOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_PROMOTE"); - - std::string plName; - recvPacket >> plName; - - if (!normalizePlayerName(plName)) - return; - - Guild* guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_PROMOTE)) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - uint64 plGuid; - MemberSlot* slot = guild->GetMemberSlot(plName, plGuid); - - if (!slot) - { - SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); - return; - } - - if (plGuid == GetPlayer()->GetGUID()) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_NAME_INVALID); - return; - } - - //allow to promote only to lower rank than member's rank - //guildmaster's rank = 0 - //GetPlayer()->GetRank() + 1 is highest rank that current player can promote to - if (GetPlayer()->GetRank() + 1 >= slot->RankId) - { - SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_RANK_TOO_HIGH_S); - return; - } - - uint32 newRankId = slot->RankId - 1; //when promoting player, rank is decreased - - guild->BroadcastEvent(GE_PROMOTION, 0, 3, _player->GetName(), plName, guild->GetRankName(newRankId)); - - guild->ChangeRank(plGuid, newRankId); - // Put record into guildlog - guild->LogGuildEvent(GUILD_EVENT_LOG_PROMOTE_PLAYER, GetPlayer()->GetGUIDLow(), GUID_LOPART(plGuid), newRankId); -} - -void WorldSession::HandleGuildDemoteOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_DEMOTE"); - - std::string plName; - recvPacket >> plName; - - if (!normalizePlayerName(plName)) - return; - - Guild* guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_DEMOTE)) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - uint64 plGuid; - MemberSlot* slot = guild->GetMemberSlot(plName, plGuid); - - if (!slot) - { - SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); - return; - } - - if (plGuid == GetPlayer()->GetGUID()) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_NAME_INVALID); - return; - } - - //do not allow to demote same or higher rank - if (GetPlayer()->GetRank() >= slot->RankId) - { - SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_RANK_TOO_HIGH_S); - return; - } - - //do not allow to demote lowest rank - if (slot->RankId >= guild->GetLowestRank()) - { - SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_RANK_TOO_LOW_S); - return; - } - - uint32 newRankId = slot->RankId + 1; //when demoting player, rank is increased - - guild->ChangeRank(plGuid, newRankId); - // Put record into guildlog - guild->LogGuildEvent(GUILD_EVENT_LOG_DEMOTE_PLAYER, GetPlayer()->GetGUIDLow(), GUID_LOPART(plGuid), newRankId); - - guild->BroadcastEvent(GE_DEMOTION, 0, 3, _player->GetName(), plName, guild->GetRankName(slot->RankId)); -} - -void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_LEAVE"); - - Guild *guild = objmgr.GetGuildById(_player->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (_player->GetGUID() == guild->GetLeader() && guild->GetMemberSize() > 1) - { - SendGuildCommandResult(GUILD_QUIT_S, "", ERR_GUILD_LEADER_LEAVE); - return; - } - - if (_player->GetGUID() == guild->GetLeader()) - { - guild->Disband(); - return; - } - - guild->DelMember(_player->GetGUID()); - // Put record into guildlog - guild->LogGuildEvent(GUILD_EVENT_LOG_LEAVE_GUILD, _player->GetGUIDLow(), 0, 0); - - guild->BroadcastEvent(GE_LEFT, _player->GetGUID(), 1, _player->GetName(), "", ""); - - SendGuildCommandResult(GUILD_QUIT_S, guild->GetName(), ERR_PLAYER_NO_MORE_IN_GUILD); -} - -void WorldSession::HandleGuildDisbandOpcode(WorldPacket& /*recvPacket*/) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_DISBAND"); - - Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (GetPlayer()->GetGUID() != guild->GetLeader()) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - guild->Disband(); - - sLog.outDebug("WORLD: Guild Successfully Disbanded"); -} - -void WorldSession::HandleGuildLeaderOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_LEADER"); - - std::string name; - recvPacket >> name; - - Player *oldLeader = GetPlayer(); - - if (!normalizePlayerName(name)) - return; - - Guild *guild = objmgr.GetGuildById(oldLeader->GetGuildId()); - - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (oldLeader->GetGUID() != guild->GetLeader()) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - uint64 newLeaderGUID; - MemberSlot* slot = guild->GetMemberSlot(name, newLeaderGUID); - - if (!slot) - { - SendGuildCommandResult(GUILD_INVITE_S, name, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); - return; - } - - guild->SetLeader(newLeaderGUID); - guild->ChangeRank(oldLeader->GetGUID(), GR_OFFICER); - - guild->BroadcastEvent(GE_LEADER_CHANGED, 0, 2, oldLeader->GetName(), name, ""); -} - -void WorldSession::HandleGuildMOTDOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_MOTD"); - - std::string MOTD; - - if (!recvPacket.empty()) - recvPacket >> MOTD; - else - MOTD = ""; - - Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_SETMOTD)) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - guild->SetMOTD(MOTD); - - guild->BroadcastEvent(GE_MOTD, 0, 1, MOTD, "", ""); -} - -void WorldSession::HandleGuildSetPublicNoteOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_SET_PUBLIC_NOTE"); - - std::string name,PNOTE; - recvPacket >> name; - - if (!normalizePlayerName(name)) - return; - - Guild* guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_EPNOTE)) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - uint64 plGuid; - MemberSlot* slot = guild->GetMemberSlot(name, plGuid); - - if (!slot) - { - SendGuildCommandResult(GUILD_INVITE_S, name, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); - return; - } - - recvPacket >> PNOTE; - guild->SetPNOTE(plGuid, PNOTE); - - guild->Roster(this); -} - -void WorldSession::HandleGuildSetOfficerNoteOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_SET_OFFICER_NOTE"); - - std::string plName, OFFNOTE; - recvPacket >> plName; - - if (!normalizePlayerName(plName)) - return; - - Guild* guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_EOFFNOTE)) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - uint64 plGuid; - MemberSlot* slot = guild->GetMemberSlot(plName, plGuid); - - if (!slot) - { - SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); - return; - } - - recvPacket >> OFFNOTE; - guild->SetOFFNOTE(plGuid, OFFNOTE); - - guild->Roster(this); -} - -void WorldSession::HandleGuildRankOpcode(WorldPacket& recvPacket) -{ - std::string rankname; - uint32 rankId; - uint32 rights, MoneyPerDay; - - sLog.outDebug("WORLD: Received CMSG_GUILD_RANK"); - - Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - recvPacket.rpos(recvPacket.wpos()); // set to end to avoid warnings spam - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - else if (GetPlayer()->GetGUID() != guild->GetLeader()) - { - recvPacket.rpos(recvPacket.wpos()); // set to end to avoid warnings spam - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - recvPacket >> rankId; - recvPacket >> rights; - recvPacket >> rankname; - recvPacket >> MoneyPerDay; - - for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) - { - uint32 BankRights; - uint32 BankSlotPerDay; - - recvPacket >> BankRights; - recvPacket >> BankSlotPerDay; - guild->SetBankRightsAndSlots(rankId, uint8(i), uint16(BankRights & 0xFF), uint16(BankSlotPerDay), true); - } - - sLog.outDebug("WORLD: Changed RankName to %s , Rights to 0x%.4X", rankname.c_str(), rights); - - guild->SetBankMoneyPerDay(rankId, MoneyPerDay); - guild->SetRankName(rankId, rankname); - - if (rankId == GR_GUILDMASTER) // prevent loss leader rights - rights = GR_RIGHT_ALL; - - guild->SetRankRights(rankId, rights); - - guild->Query(this); - guild->Roster(); // broadcast for tab rights update -} - -void WorldSession::HandleGuildAddRankOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_ADD_RANK"); - - std::string rankname; - recvPacket >> rankname; - - Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (GetPlayer()->GetGUID() != guild->GetLeader()) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - if (guild->GetRanksSize() >= GUILD_RANKS_MAX_COUNT) // client not let create more 10 than ranks - return; - - guild->CreateRank(rankname, GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); - - guild->Query(this); - guild->Roster(); // broadcast for tab rights update -} - -void WorldSession::HandleGuildDelRankOpcode(WorldPacket& /*recvPacket*/) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_DEL_RANK"); - - Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - else if (GetPlayer()->GetGUID() != guild->GetLeader()) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - guild->DelRank(); - - guild->Query(this); - guild->Roster(); // broadcast for tab rights update -} - -void WorldSession::SendGuildCommandResult(uint32 typecmd, const std::string& str,uint32 cmdresult) -{ - WorldPacket data(SMSG_GUILD_COMMAND_RESULT, (8+str.size()+1)); - data << typecmd; - data << str; - data << cmdresult; - SendPacket(&data); - - sLog.outDebug("WORLD: Sent (SMSG_GUILD_COMMAND_RESULT)"); -} - -void WorldSession::HandleGuildChangeInfoTextOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: Received CMSG_GUILD_INFO_TEXT"); - - std::string GINFO; - - recvPacket >> GINFO; - - Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_MODIFY_GUILD_INFO)) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - guild->SetGINFO(GINFO); -} - -void WorldSession::HandleSaveGuildEmblemOpcode(WorldPacket& recvPacket) -{ - sLog.outDebug("WORLD: Received MSG_SAVE_GUILD_EMBLEM"); - - uint64 vendorGuid; - - uint32 EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor; - - recvPacket >> vendorGuid; - recvPacket >> EmblemStyle >> EmblemColor >> BorderStyle >> BorderColor >> BackgroundColor; - - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorGuid,UNIT_NPC_FLAG_TABARDDESIGNER); - if (!pCreature) - { - //"That's not an emblem vendor!" - SendSaveGuildEmblem(ERR_GUILDEMBLEM_INVALIDVENDOR); - sLog.outDebug("WORLD: HandleSaveGuildEmblemOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(vendorGuid)); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - //"You are not part of a guild!"; - SendSaveGuildEmblem(ERR_GUILDEMBLEM_NOGUILD); - return; - } - - if (guild->GetLeader() != GetPlayer()->GetGUID()) - { - //"Only guild leaders can create emblems." - SendSaveGuildEmblem(ERR_GUILDEMBLEM_NOTGUILDMASTER); - return; - } - - if (GetPlayer()->GetMoney() < 10*GOLD) - { - //"You can't afford to do that." - SendSaveGuildEmblem(ERR_GUILDEMBLEM_NOTENOUGHMONEY); - return; - } - - GetPlayer()->ModifyMoney(-10*GOLD); - guild->SetEmblem(EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor); - - //"Guild Emblem saved." - SendSaveGuildEmblem(ERR_GUILDEMBLEM_SUCCESS); - - guild->Query(this); -} - -void WorldSession::HandleGuildEventLogQueryOpcode(WorldPacket& /* recvPacket */) -{ - // empty - sLog.outDebug("WORLD: Received (MSG_GUILD_EVENT_LOG_QUERY)"); - if (uint32 GuildId = GetPlayer()->GetGuildId()) - if (Guild *pGuild = objmgr.GetGuildById(GuildId)) - pGuild->DisplayGuildEventLog(this); -} - -/****** GUILD BANK *******/ - -void WorldSession::HandleGuildBankMoneyWithdrawn(WorldPacket & /* recv_data */) -{ - sLog.outDebug("WORLD: Received (MSG_GUILD_BANK_MONEY_WITHDRAWN)"); - if (uint32 GuildId = GetPlayer()->GetGuildId()) - if (Guild *pGuild = objmgr.GetGuildById(GuildId)) - pGuild->SendMoneyInfo(this, GetPlayer()->GetGUIDLow()); -} - -void WorldSession::HandleGuildPermissions(WorldPacket& /* recv_data */) -{ - sLog.outDebug("WORLD: Received (MSG_GUILD_PERMISSIONS)"); - - if (uint32 GuildId = GetPlayer()->GetGuildId()) - { - if (Guild *pGuild = objmgr.GetGuildById(GuildId)) - { - uint32 rankId = GetPlayer()->GetRank(); - - WorldPacket data(MSG_GUILD_PERMISSIONS, 4*15+1); - data << uint32(rankId); // guild rank id - data << uint32(pGuild->GetRankRights(rankId)); // rank rights - // money per day left - data << uint32(pGuild->GetMemberMoneyWithdrawRem(GetPlayer()->GetGUIDLow())); - data << uint8(pGuild->GetPurchasedTabs()); // tabs count - // why sending all info when not all tabs are purchased??? - for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) - { - data << uint32(pGuild->GetBankRights(rankId, uint8(i))); - data << uint32(pGuild->GetMemberSlotWithdrawRem(GetPlayer()->GetGUIDLow(), uint8(i))); - } - SendPacket(&data); - sLog.outDebug("WORLD: Sent (MSG_GUILD_PERMISSIONS)"); - } - } -} - -/* Called when clicking on Guild bank gameobject */ -void WorldSession::HandleGuildBankerActivate(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received (CMSG_GUILD_BANKER_ACTIVATE)"); - - uint64 GoGuid; - uint8 unk; - recv_data >> GoGuid >> unk; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - return; - - if (uint32 GuildId = GetPlayer()->GetGuildId()) - { - if (Guild *pGuild = objmgr.GetGuildById(GuildId)) - { - pGuild->DisplayGuildBankTabsInfo(this); // this also will load guild bank if not yet - return; - } - } - - SendGuildCommandResult(GUILD_UNK1, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); -} - -/* Called when opening guild bank tab only (first one) */ -void WorldSession::HandleGuildBankQueryTab(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_QUERY_TAB)"); - - uint64 GoGuid; - uint8 TabId, unk1; - recv_data >> GoGuid >> TabId >> unk1; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - return; - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - return; - - Guild *pGuild = objmgr.GetGuildById(GuildId); - if (!pGuild) - return; - - if (TabId >= pGuild->GetPurchasedTabs()) - return; - - // Let's update the amount of gold the player can withdraw before displaying the content - // This is useful if money withdraw right has changed - pGuild->SendMoneyInfo(this, GetPlayer()->GetGUIDLow()); - pGuild->DisplayGuildBankContent(this, TabId); -} - -void WorldSession::HandleGuildBankDepositMoney(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_DEPOSIT_MONEY)"); - - uint64 GoGuid; - uint32 money; - recv_data >> GoGuid >> money; - - if (!money) - return; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - return; - - if (GetPlayer()->GetMoney() < money) - return; - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - return; - - Guild *pGuild = objmgr.GetGuildById(GuildId); - if (!pGuild) - return; - - if (!pGuild->GetPurchasedTabs()) - return; - - CharacterDatabase.BeginTransaction(); - - pGuild->SetBankMoney(pGuild->GetGuildBankMoney()+money); - GetPlayer()->ModifyMoney(-int(money)); - GetPlayer()->SaveGoldToDB(); - - CharacterDatabase.CommitTransaction(); - - // logging money - if (_player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) - { - sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit money (Amount: %u) to guild bank (Guild ID %u)", - _player->GetName(),_player->GetSession()->GetAccountId(),money,GuildId); - } - - // log - pGuild->LogBankEvent(GUILD_BANK_LOG_DEPOSIT_MONEY, uint8(0), GetPlayer()->GetGUIDLow(), money); - - pGuild->DisplayGuildBankTabsInfo(this); - pGuild->DisplayGuildBankContent(this, 0); - pGuild->DisplayGuildBankMoneyUpdate(this); -} - -void WorldSession::HandleGuildBankWithdrawMoney(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_WITHDRAW_MONEY)"); - - uint64 GoGuid; - uint32 money; - recv_data >> GoGuid >> money; - - if (!money) - return; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - return; - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (GuildId == 0) - return; - - Guild *pGuild = objmgr.GetGuildById(GuildId); - if (!pGuild) - return; - - if (!pGuild->GetPurchasedTabs()) - return; - - if (pGuild->GetGuildBankMoney()HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_WITHDRAW_GOLD)) - return; - - CharacterDatabase.BeginTransaction(); - - if (!pGuild->MemberMoneyWithdraw(money, GetPlayer()->GetGUIDLow())) - { - CharacterDatabase.RollbackTransaction(); - return; - } - - GetPlayer()->ModifyMoney(money); - GetPlayer()->SaveGoldToDB(); - - CharacterDatabase.CommitTransaction(); - - // Log - pGuild->LogBankEvent(GUILD_BANK_LOG_WITHDRAW_MONEY, uint8(0), GetPlayer()->GetGUIDLow(), money); - - pGuild->SendMoneyInfo(this, GetPlayer()->GetGUIDLow()); - pGuild->DisplayGuildBankTabsInfo(this); - pGuild->DisplayGuildBankContent(this,0); - pGuild->DisplayGuildBankMoneyUpdate(this); -} - -void WorldSession::HandleGuildBankSwapItems(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_SWAP_ITEMS)"); - - uint64 GoGuid; - uint8 BankToBank; - - uint8 BankTab, BankTabSlot, AutoStore; - uint8 PlayerSlot = NULL_SLOT; - uint8 PlayerBag = NULL_BAG; - uint8 BankTabDst = 0, BankTabSlotDst = 0, unk2; - uint8 ToChar = 1; - uint32 ItemEntry, unk1; - uint32 AutoStoreCount = 0; - uint32 SplitedAmount = 0; - - recv_data >> GoGuid >> BankToBank; - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - { - recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet - return; - } - - Guild *pGuild = objmgr.GetGuildById(GuildId); - if (!pGuild) - { - recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet - return; - } - - if (BankToBank) - { - recv_data >> BankTabDst; - recv_data >> BankTabSlotDst; - recv_data >> unk1; // always 0 - recv_data >> BankTab; - recv_data >> BankTabSlot; - recv_data >> ItemEntry; - recv_data >> unk2; // always 0 - recv_data >> SplitedAmount; - - if (BankTabSlotDst >= GUILD_BANK_MAX_SLOTS || - (BankTabDst == BankTab && BankTabSlotDst == BankTabSlot) || - BankTab >= pGuild->GetPurchasedTabs() || - BankTabDst >= pGuild->GetPurchasedTabs()) - { - recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet - return; - } - } - else - { - recv_data >> BankTab; - recv_data >> BankTabSlot; - recv_data >> ItemEntry; - recv_data >> AutoStore; - if (AutoStore) - { - recv_data >> AutoStoreCount; - recv_data.read_skip(); // ToChar (?), always and expected to be 1 (autostore only triggered in guild->ToChar) - recv_data.read_skip(); // unknown, always 0 - } - else - { - recv_data >> PlayerBag; - recv_data >> PlayerSlot; - recv_data >> ToChar; - recv_data >> SplitedAmount; - } - - if (BankTabSlot >= GUILD_BANK_MAX_SLOTS && BankTabSlot != 0xFF || - BankTab >= pGuild->GetPurchasedTabs()) - { - recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet - return; - } - } - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - return; - - if (BankTab >= pGuild->GetPurchasedTabs()) - return; - - // Bank <-> Bank - if (BankToBank) - { - pGuild->SwapItems(_player, BankTab, BankTabSlot, BankTabDst, BankTabSlotDst, SplitedAmount); - return; - } - - // Player <-> Bank - - // allow work with inventory only - if (!Player::IsInventoryPos(PlayerBag, PlayerSlot) && !(PlayerBag == NULL_BAG && PlayerSlot == NULL_SLOT)) - { - _player->SendEquipError(EQUIP_ERR_NONE, NULL, NULL); - return; - } - - // BankToChar swap or char to bank remaining - if (ToChar) // Bank -> Char cases - pGuild->MoveFromBankToChar(_player, BankTab, BankTabSlot, PlayerBag, PlayerSlot, SplitedAmount); - else // Char -> Bank cases - pGuild->MoveFromCharToBank(_player, PlayerBag, PlayerSlot, BankTab, BankTabSlot, SplitedAmount); -} - -void WorldSession::HandleGuildBankBuyTab(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_BUY_TAB)"); - - uint64 GoGuid; - uint8 TabId; - - recv_data >> GoGuid; - recv_data >> TabId; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - return; - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - return; - - Guild *pGuild = objmgr.GetGuildById(GuildId); - if (!pGuild) - return; - - // m_PurchasedTabs = 0 when buying Tab 0, that is why this check can be made - if (TabId != pGuild->GetPurchasedTabs()) - return; - - uint32 TabCost = GetGuildBankTabPrice(TabId) * GOLD; - if (!TabCost) - return; - - if (GetPlayer()->GetMoney() < TabCost) // Should not happen, this is checked by client - return; - - // Go on with creating tab - pGuild->CreateNewBankTab(); - GetPlayer()->ModifyMoney(-int(TabCost)); - pGuild->SetBankMoneyPerDay(GetPlayer()->GetRank(), WITHDRAW_MONEY_UNLIMITED); - pGuild->SetBankRightsAndSlots(GetPlayer()->GetRank(), TabId, GUILD_BANK_RIGHT_FULL, WITHDRAW_SLOT_UNLIMITED, true); - pGuild->Roster(); // broadcast for tab rights update - pGuild->DisplayGuildBankTabsInfo(this); -} - -void WorldSession::HandleGuildBankUpdateTab(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_UPDATE_TAB)"); - - uint64 GoGuid; - uint8 TabId; - std::string Name; - std::string IconIndex; - - recv_data >> GoGuid; - recv_data >> TabId; - recv_data >> Name; - recv_data >> IconIndex; - - if (Name.empty()) - return; - - if (IconIndex.empty()) - return; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - return; - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - return; - - Guild *pGuild = objmgr.GetGuildById(GuildId); - if (!pGuild) - return; - - if (TabId >= pGuild->GetPurchasedTabs()) - return; - - pGuild->SetGuildBankTabInfo(TabId, Name, IconIndex); - pGuild->DisplayGuildBankTabsInfo(this); - pGuild->DisplayGuildBankContent(this, TabId); -} - -void WorldSession::HandleGuildBankLogQuery(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received (MSG_GUILD_BANK_LOG_QUERY)"); - - uint8 TabId; - recv_data >> TabId; - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - return; - - Guild *pGuild = objmgr.GetGuildById(GuildId); - if (!pGuild) - return; - - // GUILD_BANK_MAX_TABS send by client for money log - if (TabId >= pGuild->GetPurchasedTabs() && TabId != GUILD_BANK_MAX_TABS) - return; - - pGuild->DisplayGuildBankLogs(this, TabId); -} - -void WorldSession::HandleQueryGuildBankTabText(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: Received MSG_QUERY_GUILD_BANK_TEXT"); - - uint8 TabId; - recv_data >> TabId; - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - return; - - Guild *pGuild = objmgr.GetGuildById(GuildId); - if (!pGuild) - return; - - if (TabId >= pGuild->GetPurchasedTabs()) - return; - - pGuild->SendGuildBankTabText(this, TabId); -} - -void WorldSession::HandleSetGuildBankTabText(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_SET_GUILD_BANK_TEXT"); - - uint8 TabId; - std::string Text; - recv_data >> TabId; - recv_data >> Text; - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - return; - - Guild *pGuild = objmgr.GetGuildById(GuildId); - if (!pGuild) - return; - - if (TabId >= pGuild->GetPurchasedTabs()) - return; - - pGuild->SetGuildBankTabText(TabId, Text); -} - -void WorldSession::SendSaveGuildEmblem(uint32 msg) -{ - WorldPacket data(MSG_SAVE_GUILD_EMBLEM, 4); - data << uint32(msg); // not part of guild - SendPacket(&data); -} diff --git a/src/server/game/LookingForGroup/LFG.h b/src/server/game/LookingForGroup/LFG.h deleted file mode 100644 index c1b55443852..00000000000 --- a/src/server/game/LookingForGroup/LFG.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _LFG_H -#define _LFG_H - -#include "Platform/Define.h" -#include "Object.h" - -enum LfgRoles -{ - ROLE_NONE = 0x00, - ROLE_LEADER = 0x01, - ROLE_TANK = 0x02, - ROLE_HEALER = 0x04, - ROLE_DAMAGE = 0x08, -}; - -enum LfgUpdateType -{ - LFG_UPDATETYPE_LEADER = 1, - LFG_UPDATETYPE_ROLECHECK_ABORTED = 4, - LFG_UPDATETYPE_JOIN_PROPOSAL = 5, - LFG_UPDATETYPE_ROLECHECK_FAILED = 6, - LFG_UPDATETYPE_REMOVED_FROM_QUEUE = 7, - LFG_UPDATETYPE_PROPOSAL_FAILED = 8, - LFG_UPDATETYPE_PROPOSAL_DECLINED = 9, - LFG_UPDATETYPE_GROUP_FOUND = 10, - LFG_UPDATETYPE_ADDED_TO_QUEUE = 12, - LFG_UPDATETYPE_PROPOSAL_FOUND = 13, - LFG_UPDATETYPE_CLEAR_LOCK_LIST = 14, - LFG_UPDATETYPE_GROUP_MEMBER_OFFLINE = 15, - LFG_UPDATETYPE_GROUP_DISBAND = 16, -}; - -typedef std::set LfgDungeonSet; - -struct LookingForGroup -{ - LookingForGroup(): roles(0) - { - donerandomDungeons.clear(); - applyDungeons.clear(); - } - std::string comment; - int8 roles; - - bool isDungeonDone(const uint32 entry) - { - return donerandomDungeons.find(entry) != donerandomDungeons.end(); - } - - LfgDungeonSet applyDungeons; // Dungeons the player have applied for - LfgDungeonSet donerandomDungeons; // Finished random Dungeons (to calculate the bonus); -}; - -#endif diff --git a/src/server/game/LookingForGroup/LFGHandler.cpp b/src/server/game/LookingForGroup/LFGHandler.cpp deleted file mode 100644 index 0746973ff4c..00000000000 --- a/src/server/game/LookingForGroup/LFGHandler.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "LFGMgr.h" -#include "WorldSession.h" -#include "WorldPacket.h" -#include "Player.h" - -void WorldSession::HandleLfgJoinOpcode(WorldPacket &recv_data) -{ - sLog.outDebug("CMSG_LFG_JOIN"); - - uint8 numDungeons; - uint32 dungeon; - uint32 roles; - std::string comment; - - recv_data >> roles; - recv_data.read_skip(); // unk - always 0 - recv_data.read_skip(); // unk - always 0 - recv_data >> numDungeons; - if (!numDungeons) - { - sLog.outError("Invalid CMSG_LFG_JOIN packet sent by %s", GetPlayer()->GetName()); - recv_data.rpos(recv_data.wpos()); - return; - } - - GetPlayer()->m_lookingForGroup.roles = uint8(roles); - for (int8 i = 0 ; i < numDungeons; ++i) - { - recv_data >> dungeon; - // remove the type from the dungeon entry - GetPlayer()->m_lookingForGroup.applyDungeons.insert((dungeon & 0x00FFFFFF)); - } - - recv_data >> numDungeons; // unk - always 3 - for (int8 i = 0 ; i < numDungeons; ++i) - recv_data.read_skip(); // unk - always 0 - - recv_data >> comment; - - GetPlayer()->m_lookingForGroup.comment = comment; - sLFGMgr.Join(GetPlayer()); -} - -void WorldSession::HandleLfgLeaveOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("CMSG_LFG_LEAVE"); - - // Check cheating - only leader can leave the queue - if (Group *grp = GetPlayer()->GetGroup()) - { - if (grp->GetLeaderGUID() != GetPlayer()->GetGUID()) - return; - else - sLFGMgr.Leave(GetPlayer(), grp); - } - else - sLFGMgr.Leave(GetPlayer()); -} - -void WorldSession::HandleLfgSetRolesOpcode(WorldPacket &recv_data) -{ - sLog.outDebug("CMSG_LFG_SET_ROLES"); - - uint8 roles; - recv_data >> roles; // Player Group Roles - - Group *grp = GetPlayer()->GetGroup(); - if (!grp) - return; - GetPlayer()->m_lookingForGroup.roles = roles; - sLFGMgr.UpdateRoleCheck(grp, GetPlayer()); -} - -void WorldSession::HandleSetLfgCommentOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_SET_LFG_COMMENT"); - - std::string comment; - recv_data >> comment; - - GetPlayer()->m_lookingForGroup.comment = comment; -} - -void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket &/*recv_data*/) -{ - sLog.outDebug("CMSG_LFD_PLAYER_LOCK_INFO_REQUEST"); - sLFGMgr.SendLfgPlayerInfo(GetPlayer()); -} - -void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket &/*recv_data*/) -{ - sLog.outDebug("CMSG_LFD_PARTY_LOCK_INFO_REQUEST"); - sLFGMgr.SendLfgPartyInfo(GetPlayer()); -} - -void WorldSession::SendLfgUpdatePlayer(uint8 updateType) -{ - bool queued = false; - bool extrainfo = false; - - switch(updateType) - { - case LFG_UPDATETYPE_JOIN_PROPOSAL: - case LFG_UPDATETYPE_ADDED_TO_QUEUE: - queued = true; - extrainfo = true; - break; - //case LFG_UPDATETYPE_CLEAR_LOCK_LIST: // TODO: Sometimes has extrainfo - Check ocurrences... - case LFG_UPDATETYPE_PROPOSAL_FOUND: - extrainfo = true; - break; - } - sLog.outDebug("SMSG_LFG_UPDATE_PLAYER"); - WorldPacket data(SMSG_LFG_UPDATE_PLAYER, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + GetPlayer()->m_lookingForGroup.applyDungeons.size() * 4 + GetPlayer()->m_lookingForGroup.comment.length())); - data << uint8(updateType); // Lfg Update type - data << uint8(extrainfo); // Extra info - if (extrainfo) - { - data << uint8(queued); // Join the queue - data << uint8(0); // unk - Always 0 - data << uint8(0); // unk - Always 0 - - uint8 size = GetPlayer()->m_lookingForGroup.applyDungeons.size(); - data << uint8(size); - - for (LfgDungeonSet::const_iterator it = GetPlayer()->m_lookingForGroup.applyDungeons.begin(); it != GetPlayer()->m_lookingForGroup.applyDungeons.end(); ++it) - data << uint32(*it); - data << GetPlayer()->m_lookingForGroup.comment; - } - SendPacket(&data); -} - -void WorldSession::SendLfgUpdateParty(uint8 updateType) -{ - bool join = false; - bool extrainfo = false; - bool queued = false; - - switch(updateType) - { - case LFG_UPDATETYPE_JOIN_PROPOSAL: - extrainfo = true; - break; - case LFG_UPDATETYPE_ADDED_TO_QUEUE: - extrainfo = true; - join = true; - queued = true; - break; - case LFG_UPDATETYPE_CLEAR_LOCK_LIST: - // join = true; // TODO: Sometimes queued and extrainfo - Check ocurrences... - queued = true; - break; - case LFG_UPDATETYPE_PROPOSAL_FOUND: - extrainfo = true; - join = true; - break; - } - - sLog.outDebug("SMSG_LFG_UPDATE_PARTY"); - WorldPacket data(SMSG_LFG_UPDATE_PARTY, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + 1 + GetPlayer()->m_lookingForGroup.applyDungeons.size() * 4 + GetPlayer()->m_lookingForGroup.comment.length())); - data << uint8(updateType); // Lfg Update type - data << uint8(extrainfo); // Extra info - if (extrainfo) - { - data << uint8(join); // LFG Join - data << uint8(queued); // Join the queue - data << uint8(0); // unk - Always 0 - data << uint8(0); // unk - Always 0 - for (uint8 i = 0; i < 3; ++i) - data << uint8(0); // unk - Always 0 - - uint8 size = GetPlayer()->m_lookingForGroup.applyDungeons.size(); - data << uint8(size); - - for (LfgDungeonSet::const_iterator it = GetPlayer()->m_lookingForGroup.applyDungeons.begin(); it != GetPlayer()->m_lookingForGroup.applyDungeons.end(); ++it) - data << uint32(*it); - - data << GetPlayer()->m_lookingForGroup.comment; - } - SendPacket(&data); -} - -void WorldSession::SendLfgRoleChosen(uint64 guid, uint8 roles) -{ - sLog.outDebug("SMSG_LFG_ROLE_CHOSEN"); - - WorldPacket data(SMSG_LFG_ROLE_CHOSEN); - data << uint64(guid); // Guid - data << uint8(roles > 0); // Ready - data << uint32(roles); // Roles - SendPacket(&data); -} - -void WorldSession::SendLfgJoinResult(uint8 checkResult, uint8 checkValue) -{ - if (checkResult == LFG_JOIN_PARTY_NOT_MEET_REQS) // Should never happen - its handled in Mgr - return; - - sLog.outDebug("SMSG_LFG_JOIN_RESULT"); - - WorldPacket data(SMSG_LFG_JOIN_RESULT); - data << uint32(checkResult); // Check Result - data << uint32(checkValue); // Check Value - SendPacket(&data); -} - -void WorldSession::SendLfgQueueStatus(uint32 dungeon, int32 waitTime, int32 avgWaitTime, int32 waitTimeTanks, int32 waitTimeHealer, int32 waitTimeDps, uint32 queuedTime, uint8 tanks, uint8 healers, uint8 dps) -{ - sLog.outDebug("SMSG_LFG_QUEUE_STATUS"); - WorldPacket data(SMSG_LFG_QUEUE_STATUS); - - data << uint32(dungeon); // Dungeon - data << uint32(avgWaitTime); // Average Wait time - data << uint32(waitTime); // Wait Time - data << uint32(waitTimeTanks); // Wait Tanks - data << uint32(waitTimeHealer); // Wait Healers - data << uint32(waitTimeDps); // Wait Dps - data << uint8(tanks); // Tanks needed - data << uint8(healers); // Healers needed - data << uint8(dps); // Dps needed - data << uint32(queuedTime); // Player wait time in queue - SendPacket(&data); -} - -void WorldSession::SendLfgUpdateSearch(bool update) -{ - sLog.outDebug("SMSG_LFG_UPDATE_SEARCH"); - - WorldPacket data(SMSG_LFG_UPDATE_SEARCH); - data << uint8(update); // In Lfg Queue? - SendPacket(&data); -} diff --git a/src/server/game/LookingForGroup/LFGMgr.cpp b/src/server/game/LookingForGroup/LFGMgr.cpp deleted file mode 100644 index ba418cdb191..00000000000 --- a/src/server/game/LookingForGroup/LFGMgr.cpp +++ /dev/null @@ -1,1100 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "Policies/SingletonImp.h" -#include "Common.h" -#include "SharedDefines.h" -#include "Group.h" -#include "Player.h" -#include "LFGMgr.h" -#include "ObjectMgr.h" -#include "WorldPacket.h" - -INSTANTIATE_SINGLETON_1(LFGMgr); - -/*********************************************************/ -/*** LFG QUEUES ***/ -/*********************************************************/ - -LFGQueue::LFGQueue() -{ - m_LfgQueue.clear(); - avgWaitTime = -1; - waitTimeTanks = -1; - waitTimeHealer = -1; - waitTimeDps = -1; -} - -LFGQueue::~LFGQueue() -{ - m_LfgQueue.clear(); -} - -void LFGQueue::AddToQueue(uint64 guid, LfgQueueInfo* pqInfo) -{ - if (LfgQueueInfo* qInfo = m_LfgQueue[guid]) - delete qInfo; - m_LfgQueue[guid] = pqInfo; - // ATM will only add it to the queue... No find group implementation... yet (on purpose) -} - -bool LFGQueue::RemoveFromQueue(uint64 guid) -{ - if (m_LfgQueue.empty()) - return false; - - LfgQueueInfoMap::iterator itr = m_LfgQueue.find(guid); - if (itr == m_LfgQueue.end()) - return false; - - delete itr->second; - m_LfgQueue.erase(itr); - return true; -} - -LfgQueueInfo* LFGQueue::GetQueueInfo(uint64 guid) -{ - return m_LfgQueue[guid]; -} - -void LFGQueue::Update() -{ - if (m_LfgQueue.empty()) - return; - - Player *plr; - LfgQueueInfo *queue; - time_t currTime = time(NULL); - uint32 queuedTime; - uint8 role = 0; - int32 waitTime = -1; - for (LfgQueueInfoMap::const_iterator itQueue = m_LfgQueue.begin(); itQueue != m_LfgQueue.end(); ++itQueue) - { - queue = itQueue->second; - // Update queue status - queuedTime = uint32(currTime - queue->joinTime); - for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer) - { - plr = objmgr.GetPlayer(itPlayer->first); - if (!plr) - continue; - role = itPlayer->second; - if (role & ROLE_TANK) - { - if (role & ROLE_HEALER || role & ROLE_DAMAGE) - waitTime = avgWaitTime; - else - waitTime = waitTimeTanks; - } - else if (role & ROLE_HEALER) - { - if (role & ROLE_DAMAGE) - waitTime = avgWaitTime; - else - waitTime = waitTimeDps; - } - plr->GetSession()->SendLfgQueueStatus(queue->dungeonId, waitTime, avgWaitTime, waitTimeTanks, waitTimeHealer, waitTimeDps, queuedTime, queue->tanks, queue->healers, queue->dps); - } - } -} - -LFGMgr::LFGMgr() -{ - m_QueueTimer = 0; - m_update = true; -} - -LFGMgr::~LFGMgr() -{ - // RewardList to be removed -> query quest system - for (LfgRewardList::iterator it = m_RewardList.begin(); it != m_RewardList.end(); ++it) - delete *it; - m_RewardList.clear(); - - // RewardDoneList to be removed -> query quest system - for (LfgRewardList::iterator it = m_RewardDoneList.begin(); it != m_RewardDoneList.end(); ++it) - delete *it; - m_RewardDoneList.clear(); - - for(LFGQueueMap::iterator it = m_Queues.begin(); it != m_Queues.end(); ++it) - delete it->second; - m_Queues.clear(); - - for (LfgDungeonMap::iterator it = m_DungeonsMap.begin(); it != m_DungeonsMap.end(); ++it) - { - it->second->clear(); - delete it->second; - } - m_DungeonsMap.clear(); - - for (LfgRoleCheckMap::iterator it = m_RoleChecks.begin(); it != m_RoleChecks.end(); ++it) - delete it->second; - m_RoleChecks.clear(); -} - -void LFGMgr::Update(uint32 diff) -{ - if (!m_update) - return; - - // Update all players status queue info - if (m_QueueTimer > LFG_QUEUEUPDATE_INTERVAL) - { - m_QueueTimer = 0; - for (LFGQueueMap::iterator it = m_Queues.begin(); it != m_Queues.end(); ++it) - it->second->Update(); - } - else - m_QueueTimer += diff; - - time_t currTime = time(NULL); - - // Remove obsolete role checks - LfgRoleCheckMap::iterator itRoleCheck; - LfgRoleCheck *pRoleCheck; - for (LfgRoleCheckMap::iterator it = m_RoleChecks.begin(); it != m_RoleChecks.end();) - { - itRoleCheck = it++; - pRoleCheck = itRoleCheck->second; - if (currTime < pRoleCheck->cancelTime) - continue; - pRoleCheck->result = LFG_ROLECHECK_MISSING_ROLE; - - WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + pRoleCheck->dungeons.size() * 4 + 1 + pRoleCheck->roles.size() * (8 + 1 + 4 + 1)); - sLog.outDebug("SMSG_LFG_ROLE_CHECK_UPDATE"); - BuildLfgRoleCheck(data, pRoleCheck); - Player *plr = NULL; - for (LfgRolesMap::const_iterator itRoles = pRoleCheck->roles.begin(); itRoles != pRoleCheck->roles.end(); ++itRoles) - { - plr = objmgr.GetPlayer(itRoles->first); - if (!plr) - continue; - plr->GetSession()->SendPacket(&data); - plr->m_lookingForGroup.applyDungeons.clear(); - plr->m_lookingForGroup.roles = 0; - - if (itRoles->first == pRoleCheck->leader) - plr->GetSession()->SendLfgJoinResult(LFG_JOIN_FAILED, pRoleCheck->result); - } - delete pRoleCheck; - m_RoleChecks.erase(itRoleCheck); - } -} - -/// -/// Initialize Looking For Group -/// -void LFGMgr::InitLFG() -{ - // Fill reward data (to be removed -> query quest system) - LfgReward *reward; - for (uint8 i = 0; i <= LFG_REWARD_DATA_SIZE; ++i) - { - reward = new LfgReward(); - reward->strangers = 0; - reward->baseXP = RewardDungeonData[i][0]; - reward->baseMoney = RewardDungeonData[i][1]; - reward->variableMoney = 0; - reward->variableXP = 0; - reward->itemId = RewardDungeonData[i][2]; - reward->displayId = RewardDungeonData[i][3]; - reward->stackCount = RewardDungeonData[i][4]; - m_RewardList.push_back(reward); - } - - for (uint8 i = 0; i < LFG_REWARD_DATA_SIZE; ++i) - { - reward = new LfgReward(); - reward->strangers = 0; - reward->baseXP = RewardDungeonDoneData[i][0]; - reward->baseMoney = RewardDungeonDoneData[i][1]; - reward->variableMoney = 0; - reward->variableXP = 0; - reward->itemId = RewardDungeonDoneData[i][2]; - reward->displayId = RewardDungeonDoneData[i][3]; - reward->stackCount = RewardDungeonDoneData[i][4]; - m_RewardDoneList.push_back(reward); - } - // Initialize dungeonMap - m_DungeonsMap[LFG_ALL_DUNGEONS] = GetAllDungeons(); - m_DungeonsMap[LFG_RANDOM_CLASSIC] = GetDungeonsByRandom(LFG_RANDOM_CLASSIC); - m_DungeonsMap[LFG_RANDOM_BC_NORMAL] = GetDungeonsByRandom(LFG_RANDOM_BC_NORMAL); - m_DungeonsMap[LFG_RANDOM_BC_HEROIC] = GetDungeonsByRandom(LFG_RANDOM_BC_HEROIC); - m_DungeonsMap[LFG_RANDOM_LK_NORMAL] = GetDungeonsByRandom(LFG_RANDOM_LK_NORMAL); - m_DungeonsMap[LFG_RANDOM_LK_HEROIC] = GetDungeonsByRandom(LFG_RANDOM_LK_HEROIC); -} - -/// -/// Adds the player to lfg queue -/// -/// Player -void LFGMgr::Join(Player *plr) -{ - Group *grp = plr->GetGroup(); - - // TODO - 2010-05-27 Anyone can init rolecheck when already in a LFD Group? - if (grp && grp->GetLeaderGUID() != plr->GetGUID()) - return; - - // Previous checks before joining - LfgJoinResult result = LFG_JOIN_OK; - if (plr->InBattleGround() || plr->InArena()) - result = LFG_JOIN_USING_BG_SYSTEM; - else if (plr->HasAura(LFG_SPELL_DESERTER)) - result = LFG_JOIN_DESERTER; - else if (plr->HasAura(LFG_SPELL_COOLDOWN)) - result = LFG_JOIN_RANDOM_COOLDOWN; - else - { - // Check if all dungeons are valid - for (LfgDungeonSet::const_iterator it = plr->m_lookingForGroup.applyDungeons.begin(); it != plr->m_lookingForGroup.applyDungeons.end(); ++it) - { - if ((m_DungeonsMap[LFG_ALL_DUNGEONS])->find(*it) == (m_DungeonsMap[LFG_ALL_DUNGEONS])->end()) - { - result = LFG_JOIN_DUNGEON_INVALID; - break; - } - } - } - - if (grp && result == LFG_JOIN_OK) - { - if (grp->GetMembersCount() > MAXGROUPSIZE) - result = LFG_JOIN_TOO_MUCH_MEMBERS; - else if(grp->isRaidGroup()) - result = LFG_JOIN_MIXED_RAID_DUNGEON; - else - { - for (GroupReference *itr = grp->GetFirstMember(); itr != NULL && result == LFG_JOIN_OK; itr = itr->next()) - { - if (Player *plrg = itr->getSource()) - { - if (plrg->HasAura(LFG_SPELL_DESERTER)) - result = LFG_JOIN_PARTY_DESERTER; - else if (plrg->HasAura(LFG_SPELL_COOLDOWN)) - result = LFG_JOIN_PARTY_RANDOM_COOLDOWN; - } - else - result = LFG_JOIN_DISCONNECTED; - } - } - } - - if (result != LFG_JOIN_OK) - { - plr->m_lookingForGroup.applyDungeons.clear(); - plr->m_lookingForGroup.roles = 0; - plr->GetSession()->SendLfgJoinResult(result, 0); - return; - } - - if (grp) - { - Player *plrg = NULL; - for (GroupReference *itr = plr->GetGroup()->GetFirstMember(); itr != NULL; itr = itr->next()) - { - plrg = itr->getSource(); // Not null, checked earlier - plrg->m_lookingForGroup.applyDungeons = plr->m_lookingForGroup.applyDungeons; - plrg->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_JOIN_PROPOSAL); - } - UpdateRoleCheck(grp, plr); - } - else - { - plr->GetSession()->SendLfgJoinResult(LFG_JOIN_OK, 0); - plr->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_JOIN_PROPOSAL); - - // Add player to queue - LfgQueueInfo *pqInfo; - uint8 groupType = 0; - uint8 tanks = LFG_TANKS_NEEDED; - uint8 healers = LFG_HEALERS_NEEDED; - uint8 dps = LFG_DPS_NEEDED; - if (plr->m_lookingForGroup.roles & ROLE_TANK) - --tanks; - else if (plr->m_lookingForGroup.roles & ROLE_HEALER) - --healers; - else - --dps; - m_update = false; - for (LfgDungeonSet::const_iterator it = plr->m_lookingForGroup.applyDungeons.begin(); it != plr->m_lookingForGroup.applyDungeons.end(); ++it) - { - groupType = GetDungeonGroupType(*it); - pqInfo = m_Queues[groupType] ? m_Queues[groupType]->GetQueueInfo(plr->GetGUID()) : NULL; - // if exist we have already added the player with another dungeon sharing same GroupType - if (pqInfo) - continue; - pqInfo = new LfgQueueInfo(); - pqInfo->dungeonId = *it; - pqInfo->joinTime = time_t(time(NULL)); - pqInfo->tanks = tanks; - pqInfo->healers = healers; - pqInfo->dps = dps; - pqInfo->roles[plr->GetGUID()] = plr->m_lookingForGroup.roles; - if (!m_Queues[groupType]) - m_Queues[groupType] = new LFGQueue(); - m_Queues[groupType]->AddToQueue(plr->GetGUID(), pqInfo); - } - m_update = true; - } -} - -/// -/// Leave the lfg queue -/// -/// Player (could be NULL) -/// Group (could be NULL) -void LFGMgr::Leave(Player *plr, Group *grp /* = NULL*/) -{ - uint64 guid = grp ? grp->GetGUID() : plr ? plr->GetGUID() : 0; - assert(guid); - - // Check if player was in a rolecheck - if (grp) - { - LfgRoleCheckMap::iterator itRoleCheck = m_RoleChecks.find(GUID_LOPART(grp->GetGUID())); - if (itRoleCheck != m_RoleChecks.end()) - { - UpdateRoleCheck(grp); // No player to update role = LFG_ROLECHECK_ABORTED - return; - } - } - - // Check if player/group was in the queue - bool inQueue = false; - for (LFGQueueMap::iterator it = m_Queues.begin(); it != m_Queues.end(); ++it) - inQueue |= it->second->RemoveFromQueue(guid); - - // Not in queue - if (!inQueue) - return; - - if (grp) - { - for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - if (Player *plrg = itr->getSource()) - { - plrg->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); - plrg->m_lookingForGroup.applyDungeons.clear(); - plrg->m_lookingForGroup.roles = 0; - } - } - else - { - plr->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); - plr->m_lookingForGroup.applyDungeons.clear(); - plr->m_lookingForGroup.roles = 0; - } -} - -/// -/// Update the Role check info with the player selected role. -/// -/// Group -/// Player -void LFGMgr::UpdateRoleCheck(Group *grp, Player *plr /* = NULL*/) -{ - assert(grp); - - uint32 rolecheckId = GUID_LOPART(grp->GetGUID()); - LfgRoleCheck *pRoleCheck = NULL; - LfgRolesMap check_roles; - LfgRoleCheckMap::iterator itRoleCheck = m_RoleChecks.find(rolecheckId); - bool newRoleCheck = itRoleCheck == m_RoleChecks.end(); - if (newRoleCheck) - { - if (!grp->IsLeader(plr->GetGUID())) - return; - - pRoleCheck = new LfgRoleCheck(); - pRoleCheck->cancelTime = time_t(time(NULL)) + LFG_TIME_ROLECHECK; - pRoleCheck->result = LFG_ROLECHECK_INITIALITING; - pRoleCheck->leader = plr->GetGUID(); - - for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - if (Player *plrg = itr->getSource()) - pRoleCheck->roles[plrg->GetGUID()] = 0; - - pRoleCheck->dungeons = plr->m_lookingForGroup.applyDungeons; - } - else - pRoleCheck = itRoleCheck->second; - - LfgLockStatusMap *playersLockMap = NULL; - if (plr) - { - // Player selected no role. - if (plr->m_lookingForGroup.roles < ROLE_TANK) - pRoleCheck->result = LFG_ROLECHECK_NO_ROLE; - else - { - // Check if all players have selected a role - pRoleCheck->roles[plr->GetGUID()] = plr->m_lookingForGroup.roles; - uint8 size = 0; - for (LfgRolesMap::const_iterator itRoles = pRoleCheck->roles.begin(); itRoles != pRoleCheck->roles.end() && itRoles->second != ROLE_NONE; ++itRoles) - ++size; - - if (pRoleCheck->roles.size() == size) - { - // use temporal var to check roles, CheckGroupRoles modifies the roles - for (LfgRolesMap::const_iterator itRoles = pRoleCheck->roles.begin(); itRoles != pRoleCheck->roles.end(); ++itRoles) - check_roles[itRoles->first] = itRoles->second; - - if (!CheckGroupRoles(check_roles)) // Group is not posible - pRoleCheck->result = LFG_ROLECHECK_WRONG_ROLES; - else - { - // Check if we can find a dungeon for that group - pRoleCheck->result = LFG_ROLECHECK_FINISHED; - if (pRoleCheck->dungeons.size() > 1) - playersLockMap = GetPartyLockStatusDungeons(plr, &pRoleCheck->dungeons); - else - { - LfgDungeonSet::const_iterator it = pRoleCheck->dungeons.begin(); - LFGDungeonEntry const *dungeon = sLFGDungeonStore.LookupEntry(*it); - if (dungeon && dungeon->type == LFG_TYPE_RANDOM) - playersLockMap = GetPartyLockStatusDungeons(plr, m_DungeonsMap[*it]); - else - playersLockMap = GetPartyLockStatusDungeons(plr, &pRoleCheck->dungeons); - } - } - } - } - } - else - pRoleCheck->result = LFG_ROLECHECK_ABORTED; - - WorldSession *session; - WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + pRoleCheck->dungeons.size() * 4 + 1 + pRoleCheck->roles.size() * (8 + 1 + 4 + 1)); - sLog.outDebug("SMSG_LFG_ROLE_CHECK_UPDATE"); - BuildLfgRoleCheck(data, pRoleCheck); - - Player *plrg = NULL; - for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - plrg = itr->getSource(); - if (!plrg) - continue; - - session = plrg->GetSession(); - if (!newRoleCheck && plr) - session->SendLfgRoleChosen(plr->GetGUID(), plr->m_lookingForGroup.roles); - session->SendPacket(&data); - - switch(pRoleCheck->result) - { - case LFG_ROLECHECK_INITIALITING: - continue; - case LFG_ROLECHECK_FINISHED: - if (!playersLockMap) - { - session->SendLfgUpdateParty(LFG_UPDATETYPE_ADDED_TO_QUEUE); - } - else - { - if (grp->IsLeader(plrg->GetGUID())) - { - uint32 size = 0; - for (LfgLockStatusMap::const_iterator it = playersLockMap->begin(); it != playersLockMap->end(); ++it) - size += 8 + 4 + it->second->size() * (4 + 4); - WorldPacket data(SMSG_LFG_JOIN_RESULT, 4 + 4 + size); - sLog.outDebug("SMSG_LFG_JOIN_RESULT"); - data << uint32(LFG_JOIN_PARTY_NOT_MEET_REQS); // Check Result - data << uint32(0); // Check Value (always 0 when PartyNotMeetReqs - BuildPartyLockDungeonBlock(data, playersLockMap); - session->SendPacket(&data); - } - session->SendLfgUpdateParty(LFG_UPDATETYPE_ROLECHECK_FAILED); - plrg->m_lookingForGroup.applyDungeons.clear(); - plrg->m_lookingForGroup.roles = 0; - } - break; - default: - if (grp->IsLeader(plrg->GetGUID())) - session->SendLfgJoinResult(LFG_JOIN_FAILED, pRoleCheck->result); - session->SendLfgUpdateParty(LFG_UPDATETYPE_ROLECHECK_FAILED); - plrg->m_lookingForGroup.applyDungeons.clear(); - plrg->m_lookingForGroup.roles = 0; - break; - } - } - - if (pRoleCheck->result == LFG_ROLECHECK_FINISHED) - { - // Add qroup to queue - LfgQueueInfo *pqInfo; - uint8 groupType = 0; - uint8 tanks = LFG_TANKS_NEEDED; - uint8 healers = LFG_HEALERS_NEEDED; - uint8 dps = LFG_DPS_NEEDED; - for (LfgRolesMap::const_iterator it = check_roles.begin(); it != check_roles.end(); ++it) - { - if (it->second & ROLE_TANK) - --tanks; - else if (it->second & ROLE_HEALER) - --healers; - else - --dps; - } - uint64 guid = grp->GetGUID(); - m_update = false; - for (LfgDungeonSet::const_iterator it = pRoleCheck->dungeons.begin(); it != pRoleCheck->dungeons.end(); ++it) - { - groupType = GetDungeonGroupType(*it); - pqInfo = m_Queues[groupType] ? m_Queues[groupType]->GetQueueInfo(guid) : NULL; - // if exist we have already added the player with another dungeon sharing same GroupType - if (pqInfo) - continue; - pqInfo = new LfgQueueInfo(); - pqInfo->dungeonId = *it; - pqInfo->joinTime = time_t(time(NULL)); - pqInfo->tanks = tanks; - pqInfo->healers = healers; - pqInfo->dps = dps; - for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - if (Player *plrg = itr->getSource()) - pqInfo->roles[plrg->GetGUID()] = plrg->m_lookingForGroup.roles; - } - if (!m_Queues[groupType]) - m_Queues[groupType] = new LFGQueue(); - m_Queues[groupType]->AddToQueue(guid, pqInfo); - } - m_update = true; - } - - if (pRoleCheck->result != LFG_ROLECHECK_INITIALITING) - { - delete pRoleCheck; - if (!newRoleCheck) - m_RoleChecks.erase(itRoleCheck); - } - else if (newRoleCheck) - m_RoleChecks[rolecheckId] = pRoleCheck; -} - -/// -/// Check if a group can be formed with the given group -/// -/// Map of roles -/// bool, will be used to remove ROLE_LEADER -/// bool -bool LFGMgr::CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag /*= true*/) -{ - if (!groles.size()) - return false; - - uint8 damage = 0; - uint8 tank = 0; - uint8 healer = 0; - uint64 tguid = 0; - uint64 hguid = 0; - uint64 dguid = 0; - uint64 guid = 0; - uint8 role = 0; - - if (removeLeaderFlag) - for (LfgRolesMap::iterator it = groles.begin(); it != groles.end(); ++it) - it->second &= ~ROLE_LEADER; - - for (LfgRolesMap::const_iterator it = groles.begin(); it != groles.end(); ++it) - { - guid = it->first; - role = it->second; - - if (role == ROLE_NONE) - return false; - - if (role & ROLE_TANK) - { - if (!tank) - { - tguid = guid; - ++tank; - } - else - { - if (groles[tguid] == ROLE_TANK) - tguid = guid; - groles[tguid] -= ROLE_TANK; - return CheckGroupRoles(groles, false); - } - } - - if (role & ROLE_HEALER) - { - if (!healer) - { - hguid = guid; - ++healer; - } - else - { - if (groles[hguid] == ROLE_HEALER) - hguid = guid; - groles[hguid] -= ROLE_HEALER; - return CheckGroupRoles(groles, false); - } - } - - if (role & ROLE_DAMAGE) - { - if (damage < 3) - { - if (!damage) - dguid = guid; - ++damage; - } - else - { - if (groles[dguid] == ROLE_DAMAGE) - dguid = guid; - groles[dguid] -= ROLE_DAMAGE; - if (!CheckGroupRoles(groles, false)) - groles[dguid] += ROLE_DAMAGE; - else - return true; - } - } - } - return true; -} - - - -// --------------------------------------------------------------------------// -// Packet Functions -// --------------------------------------------------------------------------// - -/// -/// Build lfgRolecheck packet -/// -/// WorldPacket -/// Player -/// Player status in LFG system -void LFGMgr::BuildLfgRoleCheck(WorldPacket &data, LfgRoleCheck *pRoleCheck) -{ - assert(pRoleCheck); - - Player *plr; - uint8 roles; - - data << uint32(pRoleCheck->result); // Check result - data << uint8(pRoleCheck->result == LFG_ROLECHECK_INITIALITING); - data << uint8(pRoleCheck->dungeons.size()); // Number of dungeons - LFGDungeonEntry const *dungeon; - for (LfgDungeonSet::iterator it = pRoleCheck->dungeons.begin(); it != pRoleCheck->dungeons.end(); ++it) - { - dungeon = sLFGDungeonStore.LookupEntry(*it); // not null - been checked at join time - data << uint32(dungeon->Entry()); // Dungeon - } - - data << uint8(pRoleCheck->roles.size()); // Players in group - // Leader info MUST be sent 1st :S - roles = pRoleCheck->roles[pRoleCheck->leader]; - data << uint64(pRoleCheck->leader); // Guid - data << uint8(roles > 0); // Ready - data << uint32(roles); // Roles - plr = objmgr.GetPlayer(pRoleCheck->leader); - if (plr) - data << uint8(plr->getLevel()); // Level - else - data << uint8(0); - - for (LfgRolesMap::const_iterator itPlayers = pRoleCheck->roles.begin(); itPlayers != pRoleCheck->roles.end(); ++itPlayers) - { - if (itPlayers->first == pRoleCheck->leader) - continue; - - roles = itPlayers->second; - data << uint64(itPlayers->first); // Guid - data << uint8(roles > 0); // Ready - data << uint32(roles); // Roles - plr = objmgr.GetPlayer(pRoleCheck->leader); - if (plr) - data << uint8(plr->getLevel()); // Level - else - data << uint8(0); - } -} - -/// -/// Build and Send LFG lock player info and reward -/// -/// Player -void LFGMgr::SendLfgPlayerInfo(Player *plr) -{ - uint32 rsize = 0; - uint32 lsize = 0; - LfgDungeonSet *randomlist = GetRandomDungeons(plr->getLevel(), plr->GetSession()->Expansion()); - LfgLockStatusSet *lockSet = GetPlayerLockStatusDungeons(plr, m_DungeonsMap[LFG_ALL_DUNGEONS]); - if (randomlist) - rsize = randomlist->size(); - if (lockSet) - lsize = lockSet->size(); - - sLog.outDebug("SMSG_LFG_PLAYER_INFO"); - WorldPacket data(SMSG_LFG_PLAYER_INFO, 1 + rsize * (4 + 1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4) + 4 + lsize * (4 + 4)); - if (!randomlist) - data << uint8(0); - else - { - data << uint8(randomlist->size()); // Random Dungeon count - for (LfgDungeonSet::iterator it = randomlist->begin(); it != randomlist->end(); ++it) - { - data << uint32(*it); // Entry - BuildRewardBlock(data, *it, plr); - } - randomlist->clear(); - delete randomlist; - } - BuildPlayerLockDungeonBlock(data, lockSet); - plr->GetSession()->SendPacket(&data); -} - -/// -/// Build and Send LFG lock party info and reward -/// -/// Player -void LFGMgr::SendLfgPartyInfo(Player *plr) -{ - if (LfgLockStatusMap *lockMap = GetPartyLockStatusDungeons(plr, m_DungeonsMap[LFG_ALL_DUNGEONS])) - { - uint32 size = 0; - for (LfgLockStatusMap::const_iterator it = lockMap->begin(); it != lockMap->end(); ++it) - size += 8 + 4 + it->second->size() * (4 + 4); - sLog.outDebug("SMSG_LFG_PARTY_INFO"); - WorldPacket data(SMSG_LFG_PARTY_INFO, 1 + size); - BuildPartyLockDungeonBlock(data, lockMap); - plr->GetSession()->SendPacket(&data); - } -} - -/// -/// Build Reward packet structure for a given dungeon -/// -/// WorldPacket -/// Dungeon entry -/// Player -void LFGMgr::BuildRewardBlock(WorldPacket &data, uint32 dungeon, Player *plr) -{ - bool done = plr->m_lookingForGroup.isDungeonDone(dungeon); - LfgReward *reward = GetRandomDungeonReward(dungeon, done, plr->getLevel()); - - if (!reward) - return; - - data << uint8(done); - if (data.GetOpcode() == SMSG_LFG_PLAYER_REWARD) - data << uint32(reward->strangers); - data << uint32(reward->baseMoney); - data << uint32(reward->baseXP); - data << uint32(reward->variableMoney); - data << uint32(reward->variableXP); - data << uint8(reward->itemId != 0); - if (reward->itemId) - { - data << uint32(reward->itemId); - data << uint32(reward->displayId); - data << uint32(reward->stackCount); - } -} - -/// -/// Build Party Dungeon lock status packet -/// -/// WorldPacket -/// lock status map -void LFGMgr::BuildPartyLockDungeonBlock(WorldPacket &data, LfgLockStatusMap *lockMap) -{ - assert(lockMap); - - data << uint8(lockMap->size()); - - LfgLockStatusSet *lockSet; - uint64 guid; - for (LfgLockStatusMap::const_iterator it = lockMap->begin(); it != lockMap->end(); ++it) - { - guid = it->first; - lockSet = it->second; - if (!lockSet) - continue; - - data << uint64(guid); // Player guid - BuildPlayerLockDungeonBlock(data, lockSet); - } - lockMap->clear(); - delete lockMap; -} - -/// -/// Build Player Dungeon lock status packet -/// -/// WorldPacket -/// lock status list -void LFGMgr::BuildPlayerLockDungeonBlock(WorldPacket &data, LfgLockStatusSet *lockSet) -{ - assert(lockSet); - data << uint32(lockSet->size()); // Size of lock dungeons - for (LfgLockStatusSet::iterator it = lockSet->begin(); it != lockSet->end(); ++it) - { - data << uint32((*it)->dungeon); // Dungeon entry + type - data << uint32((*it)->lockstatus); // Lock status - delete (*it); - } - lockSet->clear(); - delete lockSet; -} - - - - -// --------------------------------------------------------------------------// -// Auxiliar Functions -// --------------------------------------------------------------------------// - -/// -/// Get all Group members list of dungeons that can't be done and reason -/// leader excluded as the list given is he list he can do -/// -/// Group -/// Dungeons to check -/// LfgLockStatusMap* -LfgLockStatusMap* LFGMgr::GetPartyLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons) -{ - assert(plr); - assert(dungeons); - Group *grp = plr->GetGroup(); - if (!grp) - return NULL; - - Player *plrg; - LfgLockStatusSet *dungeonSet = NULL; - LfgLockStatusMap *dungeonMap = new LfgLockStatusMap(); - for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - plrg = itr->getSource(); - if (!plrg || plrg == plr) - continue; - - dungeonSet = GetPlayerLockStatusDungeons(plrg, dungeons); - if (dungeonSet) - (*dungeonMap)[plrg->GetGUID()] = dungeonSet; - } - - if (!dungeonMap->size()) - { - delete dungeonMap; - dungeonMap = NULL; - } - return dungeonMap; -} - -/// -/// Get list of dungeons player can't do and reasons -/// -/// Player -/// Dungeons to check -/// LfgLockStatusSet* -LfgLockStatusSet* LFGMgr::GetPlayerLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons) -{ - LfgLockStatusSet *list = new LfgLockStatusSet(); - LfgLockStatus *lockstatus = NULL; - LFGDungeonEntry const *dungeon; - LfgLockStatusType locktype; - uint8 level = plr->getLevel(); - uint8 expansion = plr->GetSession()->Expansion(); - - for (LfgDungeonSet::const_iterator it = dungeons->begin(); it != dungeons->end(); ++it) - { - dungeon = sLFGDungeonStore.LookupEntry(*it); - assert(dungeon); // Will never happen - We provide a list from sLFGDungeonStore - - locktype = LFG_LOCKSTATUS_OK; - if (dungeon->expansion > expansion) - locktype = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION; - else if (dungeon->minlevel > level) - locktype = LFG_LOCKSTATUS_TOO_LOW_LEVEL; - else if (dungeon->maxlevel < level) - locktype = LFG_LOCKSTATUS_TOO_HIGH_LEVEL; - /* TODO - Use these types when needed... - else if () - locktype = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE; - else if () - locktype = LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE; - else if () // Locked due to WG, closed by GM, done daily, etc - locktype = LFG_LOCKSTATUS_RAID_LOCKED; - else if () - locktype = LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL; - else if () - locktype = LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL; - else if () // Need list of instances and needed quest to enter - locktype = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED; - else if () // Need list of instances and needed key to enter - locktype = LFG_LOCKSTATUS_MISSING_ITEM; - else if () // Need list of instances and needed season to open - locktype = LFG_LOCKSTATUS_NOT_IN_SEASON; - */ - - if (locktype != LFG_LOCKSTATUS_OK) - { - lockstatus = new LfgLockStatus(); - lockstatus->dungeon = dungeon->Entry(); - lockstatus->lockstatus = locktype; - list->insert(lockstatus); - } - } - if (!list->size()) - { - delete list; - list = NULL; - } - return list; -} - -/// -/// Get the dungeon list that can be done. -/// -/// LfgDungeonSet* -LfgDungeonSet* LFGMgr::GetAllDungeons() -{ - LfgDungeonSet *dungeons = new LfgDungeonSet(); - LFGDungeonEntry const *dungeon; - for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) - { - dungeon = sLFGDungeonStore.LookupEntry(i); - if (!dungeon || dungeon->type == LFG_TYPE_ZONE) - continue; - dungeons->insert(dungeon->ID); - } - if (!dungeons->size()) - { - delete dungeons; - return NULL; - } - else - return dungeons; -} - -/// -/// Get the dungeon list that can be done given a random dungeon entry. -/// -/// Random dungeon entry -/// LfgDungeonSet* -LfgDungeonSet* LFGMgr::GetDungeonsByRandom(uint32 randomdungeon) -{ - LFGDungeonEntry const *dungeon = sLFGDungeonStore.LookupEntry(randomdungeon); - if (!dungeon) - return NULL; - - uint32 grouptype = dungeon->grouptype; - LfgDungeonSet *random = new LfgDungeonSet(); - for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) - { - dungeon = sLFGDungeonStore.LookupEntry(i); - if (!dungeon || dungeon->type == LFG_TYPE_RANDOM || dungeon->grouptype != grouptype) - continue; - random->insert(dungeon->ID); - } - if (!random->size()) - { - delete random; - return NULL; - } - else - return random; -} - -/// -/// Get the random dungeon list that can be done at a certain level and expansion. -/// -/// Player level -/// Player account expansion -/// LfgDungeonSet* -LfgDungeonSet* LFGMgr::GetRandomDungeons(uint8 level, uint8 expansion) -{ - LfgDungeonSet *list = new LfgDungeonSet(); - LFGDungeonEntry const *dungeon; - for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) - { - dungeon = sLFGDungeonStore.LookupEntry(i); - if (dungeon && dungeon->expansion <= expansion && dungeon->type == LFG_TYPE_RANDOM && - dungeon->minlevel <= level && level <= dungeon->maxlevel) - list->insert(dungeon->Entry()); - } - return list; -} - -/// -/// Get the reward of a given random dungeon -/// -/// random dungeon id -/// Dungeon previously done -/// -LfgReward* LFGMgr::GetRandomDungeonReward(uint32 dungeon, bool done, uint8 level) -{ - uint8 index = 0; - switch((dungeon & 0x00FFFFFF)) // Get dungeon id from dungeon entry - { - case LFG_RANDOM_CLASSIC: - if (level < 15) - index = LFG_REWARD_LEVEL0; - else if (level < 24) - index = LFG_REWARD_LEVEL1; - else if (level < 35) - index = LFG_REWARD_LEVEL2; - else if (level < 46) - index = LFG_REWARD_LEVEL3; - else if (level < 56) - index = LFG_REWARD_LEVEL4; - else - index = LFG_REWARD_LEVEL5; - break; - case LFG_RANDOM_BC_NORMAL: - index = LFG_REWARD_BC_NORMAL; - break; - case LFG_RANDOM_BC_HEROIC: - index = LFG_REWARD_BC_HEROIC; - break; - case LFG_RANDOM_LK_NORMAL: - index = level == 80 ? LFG_REWARD_LK_NORMAL80 : LFG_REWARD_LK_NORMAL; - break; - case LFG_RANDOM_LK_HEROIC: - index = LFG_REWARD_LK_HEROIC; - break; - default: // This should never happen! - done = false; - index = LFG_REWARD_LEVEL0; - sLog.outError("LFGMgr::GetRandomDungeonReward: Dungeon %u is not random dungeon!", dungeon); - break; - } - return done ? m_RewardDoneList.at(index) : m_RewardList.at(index); -} - -/// -/// Given a Dungeon id returns the dungeon Group Type -/// -/// Dungeon id -/// uint8: GroupType -uint8 LFGMgr::GetDungeonGroupType(uint32 dungeonId) -{ - LFGDungeonEntry const *dungeon = sLFGDungeonStore.LookupEntry(dungeonId); - if (!dungeon) - return 0; - - return dungeon->grouptype; -} diff --git a/src/server/game/LookingForGroup/LFGMgr.h b/src/server/game/LookingForGroup/LFGMgr.h deleted file mode 100644 index b19da4e3d00..00000000000 --- a/src/server/game/LookingForGroup/LFGMgr.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _LFGMGR_H -#define _LFGMGR_H - -#include "Common.h" -#include "Policies/Singleton.h" -#include "Group.h" -#include "LFG.h" - -enum LFGenum -{ - LFG_TIME_ROLECHECK = 2*MINUTE, - LFG_TANKS_NEEDED = 1, - LFG_HEALERS_NEEDED = 1, - LFG_DPS_NEEDED = 3, - LFG_QUEUEUPDATE_INTERVAL = 15000, - LFG_SPELL_COOLDOWN = 71328, - LFG_SPELL_DESERTER = 71041, -}; - -enum LfgType -{ - LFG_TYPE_DUNGEON = 1, - LFG_TYPE_RAID = 2, - LFG_TYPE_QUEST = 3, - LFG_TYPE_ZONE = 4, - LFG_TYPE_HEROIC = 5, - LFG_TYPE_RANDOM = 6, -}; - -enum LfgGroupType -{ - LFG_GROUPTYPE_CLASSIC = 1, - LFG_GROUPTYPE_BC_NORMAL = 2, - LFG_GROUPTYPE_BC_HEROIC = 3, - LFG_GROUPTYPE_WTLK_NORMAL = 4, - LFG_GROUPTYPE_WTLK_HEROIC = 5, - LFG_GROUPTYPE_CLASSIC_RAID = 6, - LFG_GROUPTYPE_BC_RAID = 7, - LFG_GROUPTYPE_WTLK_RAID_10 = 8, - LFG_GROUPTYPE_WTLK_RAID_25 = 9, -}; - -enum LfgLockStatusType -{ - LFG_LOCKSTATUS_OK = 0, // Internal use only - LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION = 1, - LFG_LOCKSTATUS_TOO_LOW_LEVEL = 2, - LFG_LOCKSTATUS_TOO_HIGH_LEVEL = 3, - LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE = 4, - LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE = 5, - LFG_LOCKSTATUS_RAID_LOCKED = 6, - LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL = 1001, - LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL = 1002, - LFG_LOCKSTATUS_QUEST_NOT_COMPLETED = 1022, - LFG_LOCKSTATUS_MISSING_ITEM = 1025, - LFG_LOCKSTATUS_NOT_IN_SEASON = 1031, -}; - -enum LfgJoinResult -{ - LFG_JOIN_OK = 0, // Joined (no client msg) - LFG_JOIN_FAILED = 1, // RoleCheck Failed - LFG_JOIN_GROUPFULL = 2, // Your group is full - LFG_JOIN_UNK3 = 3, // No client reaction - LFG_JOIN_INTERNAL_ERROR = 4, // Internal LFG Error - LFG_JOIN_NOT_MEET_REQS = 5, // You do not meet the requirements for the chosen dungeons - LFG_JOIN_PARTY_NOT_MEET_REQS = 6, // One or more party members do not meet the requirements for the chosen dungeons - LFG_JOIN_MIXED_RAID_DUNGEON = 7, // You cannot mix dungeons, raids, and random when picking dungeons - LFG_JOIN_MULTI_REALM = 8, // The dungeon you chose does not support players from multiple realms - LFG_JOIN_DISCONNECTED = 9, // One or more party members are pending invites or disconnected - LFG_JOIN_PARTY_INFO_FAILED = 10, // Could not retrieve information about some party members - LFG_JOIN_DUNGEON_INVALID = 11, // One or more dungeons was not valid - LFG_JOIN_DESERTER = 12, // You can not queue for dungeons until your deserter debuff wears off - LFG_JOIN_PARTY_DESERTER = 13, // One or more party members has a deserter debuff - LFG_JOIN_RANDOM_COOLDOWN = 14, // You can not queue for random dungeons while on random dungeon cooldown - LFG_JOIN_PARTY_RANDOM_COOLDOWN = 15, // One or more party members are on random dungeon cooldown - LFG_JOIN_TOO_MUCH_MEMBERS = 16, // You can not enter dungeons with more that 5 party members - LFG_JOIN_USING_BG_SYSTEM = 17, // You can not use the dungeon system while in BG or arenas - LFG_JOIN_FAILED2 = 18, // RoleCheck Failed -}; - -enum LfgRoleCheckResult -{ - LFG_ROLECHECK_FINISHED = 1, // Role check finished - LFG_ROLECHECK_INITIALITING = 2, // Role check begins - LFG_ROLECHECK_MISSING_ROLE = 3, // Someone didn't selected a role after 2 mins - LFG_ROLECHECK_WRONG_ROLES = 4, // Can't form a group with that role selection - LFG_ROLECHECK_ABORTED = 5, // Someone leave the group - LFG_ROLECHECK_NO_ROLE = 6, // Someone selected no role -}; - -enum LfgRandomDungeonEntries -{ - LFG_ALL_DUNGEONS = 0, - LFG_RANDOM_CLASSIC = 258, - LFG_RANDOM_BC_NORMAL = 259, - LFG_RANDOM_BC_HEROIC = 260, - LFG_RANDOM_LK_NORMAL = 261, - LFG_RANDOM_LK_HEROIC = 262, -}; - -enum LfgRewardEnums -{ - LFG_REWARD_LEVEL0 = 10, - LFG_REWARD_LEVEL1 = 0, - LFG_REWARD_LEVEL2 = 1, - LFG_REWARD_LEVEL3 = 2, - LFG_REWARD_LEVEL4 = 3, - LFG_REWARD_LEVEL5 = 4, - LFG_REWARD_BC_NORMAL = 5, - LFG_REWARD_BC_HEROIC = 6, - LFG_REWARD_LK_NORMAL = 7, - LFG_REWARD_LK_NORMAL80 = 7, - LFG_REWARD_LK_HEROIC = 8, - LFG_REWARD_DATA_SIZE = 10, -}; - -const uint32 RewardDungeonData[LFG_REWARD_DATA_SIZE+1][5] = -{ // XP, money, item, item display, count - {310, 3500, 51999, 56915, 1}, // Classic 15-23 - {470, 7000, 52000, 56915, 1}, // Classic 24-34 - {825, 13000, 52001, 56915, 1}, // Classic 35-45 - {12250, 16500, 52002, 56915, 1}, // Classic 46-55 - {14300, 18000, 52003, 56915, 1}, // Classic 56-60 - {1600, 62000, 52004, 56915, 1}, // BC Normal - {1900, 88000, 52005, 56915, 1}, // BC Heroic - {33100, 148000, 47241, 62232, 2}, // LK Normal - {0, 198600, 47241, 62232, 2}, // LK Normal - Level 80 - {0, 264600, 49426, 64062, 2}, // LK Heroic - {0, 0, 0, 0, 0}, // Classic - No level -}; - -const uint32 RewardDungeonDoneData[LFG_REWARD_DATA_SIZE][5] = -{ // XP, money, item, item display, count - {200, 1800, 51999, 56915, 1}, // Classic 15-23 - {310, 3500, 52000, 56915, 1}, // Classic 24-34 - {550, 6500, 52001, 56915, 1}, // Classic 35-45 - {8150, 8500, 52002, 56915, 1}, // Classic 46-55 - {9550, 9000, 52003, 56915, 1}, // Classic 56-60 - {1100, 31000, 52004, 56915, 1}, // BC Normal - {12650, 44000, 52005, 56915, 1}, // BC Heroic - {16550, 74000, 0, 0, 0}, // LK Normal - {0, 99300, 0, 0, 0}, // LK Normal - Level 80 - {0, 132300, 47241, 62232, 2}, // LK Heroic -}; - -// Dungeon and reason why player can't join -struct LfgLockStatus -{ - uint32 dungeon; - LfgLockStatusType lockstatus; -}; - -// Reward info -struct LfgReward -{ - uint32 strangers; - uint32 baseMoney; - uint32 baseXP; - uint32 variableMoney; - uint32 variableXP; - uint32 itemId; - uint32 displayId; - uint32 stackCount; -}; - -typedef std::set LfgLockStatusSet; -typedef std::vector LfgRewardList; -typedef std::map LfgLockStatusMap; -typedef std::map LfgDungeonMap; - -typedef std::map LfgAnswerMap; -typedef std::map LfgRolesMap; -typedef std::set LfgGuidSet; - -// Stores player or group queue info -struct LfgQueueInfo -{ - time_t joinTime; // Player queue join time (to calculate wait times) - uint32 dungeonId; // Selected Player/Group Dungeon - LfgRolesMap roles; // Selected Player Role/s - uint8 tanks; // Tanks needed - uint8 healers; // Healers needed - uint8 dps; // Dps needed -}; - -// Stores all rolecheck info of a group that wants to join LFG -struct LfgRoleCheck -{ - time_t cancelTime; - LfgRolesMap roles; - LfgRoleCheckResult result; - LfgDungeonSet dungeons; - uint64 leader; -}; - -typedef std::map LfgQueueInfoMap; -typedef std::map LfgRoleCheckMap; - -class LFGQueue -{ - public: - LFGQueue(); - ~LFGQueue(); - - void Update(); - void AddToQueue(uint64 guid, LfgQueueInfo *pqInfo); - bool RemoveFromQueue(uint64 guid); - LfgQueueInfo* GetQueueInfo(uint64 guid); - private: - LfgQueueInfoMap m_LfgQueue; - int32 avgWaitTime; - int32 waitTimeTanks; - int32 waitTimeHealer; - int32 waitTimeDps; -}; - -typedef std::map LFGQueueMap; - -class LFGMgr -{ -public: - LFGMgr(); - ~LFGMgr(); - - void InitLFG(); - void SendLfgPlayerInfo(Player *plr); - void SendLfgPartyInfo(Player *plr); - void Join(Player *plr); - void Leave(Player *plr, Group *grp = NULL); - void UpdateRoleCheck(Group *grp, Player *plr = NULL); - void Update(uint32 diff); - -private: - void BuildLfgRoleCheck(WorldPacket &data, LfgRoleCheck *pRoleCheck); - void BuildAvailableRandomDungeonList(WorldPacket &data, Player *plr); - void BuildRewardBlock(WorldPacket &data, uint32 dungeon, Player *plr); - void BuildPlayerLockDungeonBlock(WorldPacket &data, LfgLockStatusSet *lockSet); - void BuildPartyLockDungeonBlock(WorldPacket &data, LfgLockStatusMap *lockMap); - bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true); - - LfgLockStatusMap* GetPartyLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons); - LfgLockStatusSet* GetPlayerLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons); - LfgDungeonSet* GetRandomDungeons(uint8 level, uint8 expansion); - LfgDungeonSet* GetDungeonsByRandom(uint32 randomdungeon); - LfgDungeonSet* GetAllDungeons(); - LfgReward* GetRandomDungeonReward(uint32 dungeon, bool done, uint8 level); - uint8 GetDungeonGroupType(uint32 dungeon); - - LfgRewardList m_RewardList; - LfgRewardList m_RewardDoneList; - LfgDungeonMap m_DungeonsMap; - - LFGQueueMap m_Queues; - LfgRoleCheckMap m_RoleChecks; - uint32 m_QueueTimer; - bool m_update; -}; - -#define sLFGMgr Trinity::Singleton::Instance() -#endif diff --git a/src/server/game/Loot/LootHandler.cpp b/src/server/game/Loot/LootHandler.cpp deleted file mode 100644 index 55aefb3c1f5..00000000000 --- a/src/server/game/Loot/LootHandler.cpp +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "Log.h" -#include "Corpse.h" -#include "GameObject.h" -#include "Player.h" -#include "ObjectAccessor.h" -#include "WorldSession.h" -#include "LootMgr.h" -#include "Object.h" -#include "Group.h" -#include "World.h" -#include "Util.h" - -void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); - Player *player = GetPlayer(); - uint64 lguid = player->GetLootGUID(); - Loot *loot; - uint8 lootSlot; - - recv_data >> lootSlot; - - if (IS_GAMEOBJECT_GUID(lguid)) - { - GameObject *go = player->GetMap()->GetGameObject(lguid); - - // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO - if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player,INTERACTION_DISTANCE))) - { - player->SendLootRelease(lguid); - return; - } - - loot = &go->loot; - } - else if (IS_ITEM_GUID(lguid)) - { - Item *pItem = player->GetItemByGuid(lguid); - - if (!pItem) - { - player->SendLootRelease(lguid); - return; - } - - loot = &pItem->loot; - } - else if (IS_CORPSE_GUID(lguid)) - { - Corpse *bones = ObjectAccessor::GetCorpse(*player, lguid); - if (!bones) - { - player->SendLootRelease(lguid); - return; - } - loot = &bones->loot; - } - else - { - Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); - - bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass() == CLASS_ROGUE && pCreature->lootForPickPocketed); - - if (!ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) - { - player->SendLootRelease(lguid); - return; - } - - loot = &pCreature->loot; - } - - QuestItem *qitem = NULL; - QuestItem *ffaitem = NULL; - QuestItem *conditem = NULL; - - LootItem *item = loot->LootItemInSlot(lootSlot,player,&qitem,&ffaitem,&conditem); - - if (!item) - { - player->SendEquipError(EQUIP_ERR_ALREADY_LOOTED, NULL, NULL); - return; - } - - // questitems use the blocked field for other purposes - if (!qitem && item->is_blocked) - { - player->SendLootRelease(lguid); - return; - } - - ItemPosCountVec dest; - uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item->itemid, item->count); - if (msg == EQUIP_ERR_OK) - { - Item * newitem = player->StoreNewItem(dest, item->itemid, true, item->randomPropertyId); - - if (qitem) - { - qitem->is_looted = true; - //freeforall is 1 if everyone's supposed to get the quest item. - if (item->freeforall || loot->GetPlayerQuestItems().size() == 1) - player->SendNotifyLootItemRemoved(lootSlot); - else - loot->NotifyQuestItemRemoved(qitem->index); - } - else - { - if (ffaitem) - { - //freeforall case, notify only one player of the removal - ffaitem->is_looted=true; - player->SendNotifyLootItemRemoved(lootSlot); - } - else - { - //not freeforall, notify everyone - if (conditem) - conditem->is_looted=true; - loot->NotifyItemRemoved(lootSlot); - } - } - - //if only one person is supposed to loot the item, then set it to looted - if (!item->freeforall) - item->is_looted = true; - - --loot->unlootedCount; - - player->SendNewItem(newitem, uint32(item->count), false, false, true); - player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count); - player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item->count); - player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item->itemid, item->count); - } - else - player->SendEquipError(msg, NULL, NULL); -} - -void WorldSession::HandleLootMoneyOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("WORLD: CMSG_LOOT_MONEY"); - - Player *player = GetPlayer(); - uint64 guid = player->GetLootGUID(); - if (!guid) - return; - - Loot *pLoot = NULL; - - switch(GUID_HIPART(guid)) - { - case HIGHGUID_GAMEOBJECT: - { - GameObject *pGameObject = GetPlayer()->GetMap()->GetGameObject(guid); - - // not check distance for GO in case owned GO (fishing bobber case, for example) - if (pGameObject && ((pGameObject->GetOwnerGUID() == _player->GetGUID() || pGameObject->IsWithinDistInMap(_player,INTERACTION_DISTANCE)))) - pLoot = &pGameObject->loot; - - break; - } - case HIGHGUID_CORPSE: // remove insignia ONLY in BG - { - Corpse *bones = ObjectAccessor::GetCorpse(*GetPlayer(), guid); - - if (bones && bones->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) - pLoot = &bones->loot; - - break; - } - case HIGHGUID_ITEM: - { - if (Item *item = GetPlayer()->GetItemByGuid(guid)) - pLoot = &item->loot; - break; - } - case HIGHGUID_UNIT: - { - Creature* pCreature = GetPlayer()->GetMap()->GetCreature(guid); - - bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass() == CLASS_ROGUE && pCreature->lootForPickPocketed); - - if (ok_loot && pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) - pLoot = &pCreature->loot ; - - break; - } - default: - return; // unlootable type - } - - if (pLoot) - { - if (!IS_ITEM_GUID(guid) && player->GetGroup()) //item can be looted only single player - { - Group *group = player->GetGroup(); - - std::vector playersNear; - for (GroupReference *itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* playerGroup = itr->getSource(); - if (!playerGroup) - continue; - if (player->IsWithinDistInMap(playerGroup,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) - playersNear.push_back(playerGroup); - } - - uint32 money_per_player = uint32((pLoot->gold)/(playersNear.size())); - - for (std::vector::const_iterator i = playersNear.begin(); i != playersNear.end(); ++i) - { - (*i)->ModifyMoney(money_per_player); - (*i)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, money_per_player); - //Offset surely incorrect, but works - WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4); - data << uint32(money_per_player); - (*i)->GetSession()->SendPacket(&data); - } - } - else - { - player->ModifyMoney(pLoot->gold); - player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, pLoot->gold); - } - pLoot->gold = 0; - pLoot->NotifyMoneyRemoved(); - } -} - -void WorldSession::HandleLootOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_LOOT"); - - uint64 guid; - recv_data >> guid; - - // Check possible cheat - if (!_player->isAlive()) - return; - - GetPlayer()->SendLoot(guid, LOOT_CORPSE); -} - -void WorldSession::HandleLootReleaseOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_LOOT_RELEASE"); - - // cheaters can modify lguid to prevent correct apply loot release code and re-loot - // use internal stored guid - recv_data.read_skip(); // guid; - - if (uint64 lguid = GetPlayer()->GetLootGUID()) - DoLootRelease(lguid); -} - -void WorldSession::DoLootRelease(uint64 lguid) -{ - Player *player = GetPlayer(); - Loot *loot; - - player->SetLootGUID(0); - player->SendLootRelease(lguid); - - player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); - - if (!player->IsInWorld()) - return; - - if (IS_GAMEOBJECT_GUID(lguid)) - { - GameObject *go = GetPlayer()->GetMap()->GetGameObject(lguid); - - // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO - if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player,INTERACTION_DISTANCE))) - return; - - loot = &go->loot; - - if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR) - { - // locked doors are opened with spelleffect openlock, prevent remove its as looted - go->UseDoorOrButton(); - } - else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) - { - // GO is mineral vein? so it is not removed after its looted - if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST) - { - uint32 go_min = go->GetGOInfo()->chest.minSuccessOpens; - uint32 go_max = go->GetGOInfo()->chest.maxSuccessOpens; - - // only vein pass this check - if (go_min != 0 && go_max > go_min) - { - float amount_rate = sWorld.getRate(RATE_MINING_AMOUNT); - float min_amount = go_min*amount_rate; - float max_amount = go_max*amount_rate; - - go->AddUse(); - float uses = float(go->GetUseCount()); - - if (uses < max_amount) - { - if (uses >= min_amount) - { - float chance_rate = sWorld.getRate(RATE_MINING_NEXT); - - int32 ReqValue = 175; - LockEntry const *lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId); - if (lockInfo) - ReqValue = lockInfo->Skill[0]; - float skill = float(player->GetSkillValue(SKILL_MINING))/(ReqValue+25); - double chance = pow(0.8*chance_rate,4*(1/double(max_amount))*double(uses)); - if (roll_chance_f(100*chance+skill)) - { - go->SetLootState(GO_READY); - } - else // not have more uses - go->SetLootState(GO_JUST_DEACTIVATED); - } - else // 100% chance until min uses - go->SetLootState(GO_READY); - } - else // max uses already - go->SetLootState(GO_JUST_DEACTIVATED); - } - else // not vein - go->SetLootState(GO_JUST_DEACTIVATED); - } - else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) - { // The fishing hole used once more - go->AddUse(); // if the max usage is reached, will be despawned in next tick - if (go->GetUseCount() >= irand(go->GetGOInfo()->fishinghole.minSuccessOpens,go->GetGOInfo()->fishinghole.maxSuccessOpens)) - { - go->SetLootState(GO_JUST_DEACTIVATED); - } - else - go->SetLootState(GO_READY); - } - else // not chest (or vein/herb/etc) - go->SetLootState(GO_JUST_DEACTIVATED); - - loot->clear(); - } - else - { - // not fully looted object - go->SetLootState(GO_ACTIVATED); - - // if the round robin player release, reset it. - if (player->GetGUID() == loot->roundRobinPlayer) - { - if (Group* pGroup = player->GetGroup()) - { - if (pGroup->GetLootMethod() != MASTER_LOOT) - { - loot->roundRobinPlayer = 0; - } - } - else - loot->roundRobinPlayer = 0; - } - } - } - else if (IS_CORPSE_GUID(lguid)) // ONLY remove insignia at BG - { - Corpse *corpse = ObjectAccessor::GetCorpse(*player, lguid); - if (!corpse || !corpse->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) - return; - - loot = &corpse->loot; - - if (loot->isLooted()) - { - loot->clear(); - corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); - } - } - else if (IS_ITEM_GUID(lguid)) - { - Item *pItem = player->GetItemByGuid(lguid); - if (!pItem) - return; - - ItemPrototype const* proto = pItem->GetProto(); - - // destroy only 5 items from stack in case prospecting and milling - if ((proto->BagFamily & (BAG_FAMILY_MASK_MINING_SUPP|BAG_FAMILY_MASK_HERBS)) && - proto->Class == ITEM_CLASS_TRADE_GOODS) - { - pItem->m_lootGenerated = false; - pItem->loot.clear(); - - uint32 count = pItem->GetCount(); - - // >=5 checked in spell code, but will work for cheating cases also with removing from another stacks. - if (count > 5) - count = 5; - - player->DestroyItemCount(pItem, count, true); - } - else - // FIXME: item must not be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or cheating possible. - player->DestroyItem(pItem->GetBagSlot(),pItem->GetSlot(), true); - return; // item can be looted only single player - } - else - { - Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); - - bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass() == CLASS_ROGUE && pCreature->lootForPickPocketed); - if (!ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) - return; - - loot = &pCreature->loot; - if (loot->isLooted()) - { - // skip pickpocketing loot for speed, skinning timer redunction is no-op in fact - if (!pCreature->isAlive()) - pCreature->AllLootRemovedFromCorpse(); - - pCreature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - pCreature->SetLootRecipient(NULL); - loot->clear(); - } - else - { - // if the round robin player release, reset it. - if (player->GetGUID() == loot->roundRobinPlayer) - { - if (Group* pGroup = player->GetGroup()) - { - if (pGroup->GetLootMethod() != MASTER_LOOT) - { - loot->roundRobinPlayer = 0; - pGroup->SendLooter(pCreature, NULL); - - // force update of dynamic flags, otherwise other group's players still not able to loot. - pCreature->ForceValuesUpdateAtIndex(UNIT_DYNAMIC_FLAGS); - } - } - else - loot->roundRobinPlayer = 0; - } - } - } - - //Player is not looking at loot list, he doesn't need to see updates on the loot list - loot->RemoveLooter(player->GetGUID()); -} - -void WorldSession::HandleLootMasterGiveOpcode(WorldPacket & recv_data) -{ - uint8 slotid; - uint64 lootguid, target_playerguid; - - recv_data >> lootguid >> slotid >> target_playerguid; - - if (!_player->GetGroup() || _player->GetGroup()->GetLooterGuid() != _player->GetGUID()) - { - _player->SendLootRelease(GetPlayer()->GetLootGUID()); - return; - } - - Player *target = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(target_playerguid, 0, HIGHGUID_PLAYER)); - if (!target) - return; - - sLog.outDebug("WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName()); - - if (_player->GetLootGUID() != lootguid) - return; - - Loot *pLoot = NULL; - - if (IS_CRE_OR_VEH_GUID(GetPlayer()->GetLootGUID())) - { - Creature *pCreature = GetPlayer()->GetMap()->GetCreature(lootguid); - if (!pCreature) - return; - - pLoot = &pCreature->loot; - } - else if (IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) - { - GameObject *pGO = GetPlayer()->GetMap()->GetGameObject(lootguid); - if (!pGO) - return; - - pLoot = &pGO->loot; - } - - if (!pLoot) - return; - - if (slotid > pLoot->items.size()) - { - sLog.outDebug("AutoLootItem: Player %s might be using a hack! (slot %d, size %lu)",GetPlayer()->GetName(), slotid, (unsigned long)pLoot->items.size()); - return; - } - - LootItem& item = pLoot->items[slotid]; - - ItemPosCountVec dest; - uint8 msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); - if (msg != EQUIP_ERR_OK) - { - target->SendEquipError(msg, NULL, NULL); - _player->SendEquipError(msg, NULL, NULL); // send duplicate of error massage to master looter - return; - } - - // not move item from loot to target inventory - Item * newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId); - target->SendNewItem(newitem, uint32(item.count), false, false, true); - target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); - target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, pLoot->loot_type, item.count); - target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); - - // mark as looted - item.count=0; - item.is_looted=true; - - pLoot->NotifyItemRemoved(slotid); - --pLoot->unlootedCount; -} - diff --git a/src/server/game/Map/Cell/Cell.h b/src/server/game/Map/Cell/Cell.h deleted file mode 100644 index 49e0329ace6..00000000000 --- a/src/server/game/Map/Cell/Cell.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_CELL_H -#define TRINITY_CELL_H - -#include - -#include "GameSystem/TypeContainer.h" -#include "GameSystem/TypeContainerVisitor.h" - -#include "GridDefines.h" - -class Map; -class WorldObject; - -enum District -{ - UPPER_DISTRICT = 1, - LOWER_DISTRICT = 1 << 1, - LEFT_DISTRICT = 1 << 2, - RIGHT_DISTRICT = 1 << 3, - CENTER_DISTRICT = 1 << 4, - UPPER_LEFT_DISTRICT = (UPPER_DISTRICT | LEFT_DISTRICT), - UPPER_RIGHT_DISTRICT = (UPPER_DISTRICT | RIGHT_DISTRICT), - LOWER_LEFT_DISTRICT = (LOWER_DISTRICT | LEFT_DISTRICT), - LOWER_RIGHT_DISTRICT = (LOWER_DISTRICT | RIGHT_DISTRICT), - ALL_DISTRICT = (UPPER_DISTRICT | LOWER_DISTRICT | LEFT_DISTRICT | RIGHT_DISTRICT | CENTER_DISTRICT) -}; - -struct CellArea -{ - CellArea() : right_offset(0), left_offset(0), upper_offset(0), lower_offset(0) {} - CellArea(int right, int left, int upper, int lower) : right_offset(right), left_offset(left), upper_offset(upper), lower_offset(lower) {} - bool operator!() const { return !right_offset && !left_offset && !upper_offset && !lower_offset; } - - void ResizeBorders(CellPair& begin_cell, CellPair& end_cell) const - { - begin_cell << left_offset; - begin_cell -= lower_offset; - end_cell >> right_offset; - end_cell += upper_offset; - } - - int right_offset; - int left_offset; - int upper_offset; - int lower_offset; -}; - -struct Cell -{ - Cell() { data.All = 0; } - Cell(const Cell &cell) { data.All = cell.data.All; } - explicit Cell(CellPair const& p); - - void operator|=(Cell &cell) - { - data.Part.reserved = 0; - cell.data.Part.reserved = 0; - uint32 x, y, old_x, old_y; - Compute(x, y); - cell.Compute(old_x, old_y); - - if (std::abs(int(x-old_x)) > 1 || std::abs(int(y-old_y)) > 1) - { - data.Part.reserved = ALL_DISTRICT; - cell.data.Part.reserved = ALL_DISTRICT; - return; - } - - if (x < old_x) - { - data.Part.reserved |= LEFT_DISTRICT; - cell.data.Part.reserved |= RIGHT_DISTRICT; - } - else if (old_x < x) - { - data.Part.reserved |= RIGHT_DISTRICT; - cell.data.Part.reserved |= LEFT_DISTRICT; - } - if (y < old_y) - { - data.Part.reserved |= UPPER_DISTRICT; - cell.data.Part.reserved |= LOWER_DISTRICT; - } - else if (old_y < y) - { - data.Part.reserved |= LOWER_DISTRICT; - cell.data.Part.reserved |= UPPER_DISTRICT; - } - } - - void Compute(uint32 &x, uint32 &y) const - { - x = data.Part.grid_x*MAX_NUMBER_OF_CELLS + data.Part.cell_x; - y = data.Part.grid_y*MAX_NUMBER_OF_CELLS + data.Part.cell_y; - } - - bool DiffCell(const Cell &cell) const - { - return(data.Part.cell_x != cell.data.Part.cell_x || - data.Part.cell_y != cell.data.Part.cell_y); - } - - bool DiffGrid(const Cell &cell) const - { - return(data.Part.grid_x != cell.data.Part.grid_x || - data.Part.grid_y != cell.data.Part.grid_y); - } - - uint32 CellX() const { return data.Part.cell_x; } - uint32 CellY() const { return data.Part.cell_y; } - uint32 GridX() const { return data.Part.grid_x; } - uint32 GridY() const { return data.Part.grid_y; } - bool NoCreate() const { return data.Part.nocreate; } - void SetNoCreate() { data.Part.nocreate = 1; } - - CellPair cellPair() const - { - return CellPair( - data.Part.grid_x*MAX_NUMBER_OF_CELLS+data.Part.cell_x, - data.Part.grid_y*MAX_NUMBER_OF_CELLS+data.Part.cell_y); - } - - Cell& operator=(const Cell &cell) - { - this->data.All = cell.data.All; - return *this; - } - - bool operator == (const Cell &cell) const { return (data.All == cell.data.All); } - bool operator != (const Cell &cell) const { return !operator == (cell); } - union - { - struct - { - unsigned grid_x : 6; - unsigned grid_y : 6; - unsigned cell_x : 6; - unsigned cell_y : 6; - unsigned nocreate : 1; - unsigned reserved : 7; - } Part; - uint32 All; - } data; - - template void Visit(const CellPair&, TypeContainerVisitor &visitor, Map &) const; - template void Visit(const CellPair&, TypeContainerVisitor &visitor, Map &, const WorldObject&, float) const; - template void Visit(const CellPair&, TypeContainerVisitor &visitor, Map &, float, float, float) const; - - static CellArea CalculateCellArea(const WorldObject &obj, float radius); - static CellArea CalculateCellArea(float x, float y, float radius); - -private: - template void VisitCircle(TypeContainerVisitor &, Map &, const CellPair&, const CellPair&) const; -}; - -#endif - diff --git a/src/server/game/Map/Cell/CellImpl.h b/src/server/game/Map/Cell/CellImpl.h deleted file mode 100644 index d906e81a5c9..00000000000 --- a/src/server/game/Map/Cell/CellImpl.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_CELLIMPL_H -#define TRINITY_CELLIMPL_H - -#include - -#include "Cell.h" -#include "Map.h" -#include "Object.h" - -inline Cell::Cell(CellPair const& p) -{ - data.Part.grid_x = p.x_coord / MAX_NUMBER_OF_CELLS; - data.Part.grid_y = p.y_coord / MAX_NUMBER_OF_CELLS; - data.Part.cell_x = p.x_coord % MAX_NUMBER_OF_CELLS; - data.Part.cell_y = p.y_coord % MAX_NUMBER_OF_CELLS; - data.Part.nocreate = 0; - data.Part.reserved = 0; -} - -template -inline void -Cell::Visit(const CellPair& standing_cell, TypeContainerVisitor &visitor, Map &m) const -{ - if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - return; - - uint16 district = (District)this->data.Part.reserved; - if (district == CENTER_DISTRICT) - { - m.Visit(*this, visitor); - return; - } - - // set up the cell range based on the district - // the overloaded operators handle range checking - CellPair begin_cell = standing_cell; - CellPair end_cell = standing_cell; - - switch(district) - { - case ALL_DISTRICT: - { - begin_cell << 1; begin_cell -= 1; // upper left - end_cell >> 1; end_cell += 1; // lower right - break; - } - case UPPER_LEFT_DISTRICT: - { - begin_cell << 1; begin_cell -= 1; // upper left - break; - } - case UPPER_RIGHT_DISTRICT: - { - begin_cell -= 1; // up - end_cell >> 1; // right - break; - } - case LOWER_LEFT_DISTRICT: - { - begin_cell << 1; // left - end_cell += 1; // down - break; - } - case LOWER_RIGHT_DISTRICT: - { - end_cell >> 1; end_cell += 1; // lower right - break; - } - case LEFT_DISTRICT: - { - begin_cell -= 1; // up - end_cell >> 1; end_cell += 1; // lower right - break; - } - case RIGHT_DISTRICT: - { - begin_cell << 1; begin_cell -= 1; // upper left - end_cell += 1; // down - break; - } - case UPPER_DISTRICT: - { - begin_cell << 1; begin_cell -= 1; // upper left - end_cell >> 1; // right - break; - } - case LOWER_DISTRICT: - { - begin_cell << 1; // left - end_cell >> 1; end_cell += 1; // lower right - break; - } - default: - { - assert(false); - break; - } - } - - // loop the cell range - for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; x++) - { - for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; y++) - { - CellPair cell_pair(x,y); - Cell r_zone(cell_pair); - r_zone.data.Part.nocreate = this->data.Part.nocreate; - m.Visit(r_zone, visitor); - } - } -} - -inline int CellHelper(const float radius) -{ - if (radius < 1.0f) - return 0; - - return (int)ceilf(radius/SIZE_OF_GRID_CELL); -} - -inline CellArea Cell::CalculateCellArea(const WorldObject &obj, float radius) -{ - return Cell::CalculateCellArea(obj.GetPositionX(), obj.GetPositionY(), radius); -} - -inline CellArea Cell::CalculateCellArea(float x, float y, float radius) -{ - if (radius <= 0.0f) - return CellArea(); - - //lets calculate object coord offsets from cell borders. - //TODO: add more correct/generic method for this task - const float x_offset = (x - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL; - const float y_offset = (y - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL; - - const float x_val = floor(x_offset + CENTER_GRID_CELL_ID + 0.5f); - const float y_val = floor(y_offset + CENTER_GRID_CELL_ID + 0.5f); - - const float x_off = (x_offset - x_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL; - const float y_off = (y_offset - y_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL; - - const float tmp_diff = radius - CENTER_GRID_CELL_OFFSET; - //lets calculate upper/lower/right/left corners for cell search - int right = CellHelper(tmp_diff + x_off); - int left = CellHelper(tmp_diff - x_off); - int upper = CellHelper(tmp_diff + y_off); - int lower = CellHelper(tmp_diff - y_off); - - return CellArea(right, left, upper, lower); -} - -template -inline void -Cell::Visit(const CellPair& standing_cell, TypeContainerVisitor &visitor, Map &m, float radius, float x_off, float y_off) const -{ - if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - return; - - //no jokes here... Actually placing ASSERT() here was good idea, but - //we had some problems with DynamicObjects, which pass radius = 0.0f (DB issue?) - //maybe it is better to just return when radius <= 0.0f? - if (radius <= 0.0f) - { - m.Visit(*this, visitor); - return; - } - //lets limit the upper value for search radius - if (radius > 333.0f) - radius = 333.0f; - - //lets calculate object coord offsets from cell borders. - CellArea area = Cell::CalculateCellArea(x_off, y_off, radius); - //if radius fits inside standing cell - if (!area) - { - m.Visit(*this, visitor); - return; - } - - CellPair begin_cell = standing_cell; - CellPair end_cell = standing_cell; - - area.ResizeBorders(begin_cell, end_cell); - //visit all cells, found in CalculateCellArea() - //if radius is known to reach cell area more than 4x4 then we should call optimized VisitCircle - //currently this technique works with MAX_NUMBER_OF_CELLS 16 and higher, with lower values - //there are nothing to optimize because SIZE_OF_GRID_CELL is too big... - if (((end_cell.x_coord - begin_cell.x_coord) > 4) && ((end_cell.y_coord - begin_cell.y_coord) > 4)) - { - VisitCircle(visitor, m, begin_cell, end_cell); - return; - } - - //ALWAYS visit standing cell first!!! Since we deal with small radiuses - //it is very essential to call visitor for standing cell firstly... - m.Visit(*this, visitor); - - // loop the cell range - for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x) - { - for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y) - { - CellPair cell_pair(x,y); - //lets skip standing cell since we already visited it - if (cell_pair != standing_cell) - { - Cell r_zone(cell_pair); - r_zone.data.Part.nocreate = this->data.Part.nocreate; - m.Visit(r_zone, visitor); - } - } - } -} - -template -inline void -Cell::Visit(const CellPair& l, TypeContainerVisitor &visitor, Map &m, const WorldObject &obj, float radius) const -{ - //we should increase search radius by object's radius, otherwise - //we could have problems with huge creatures, which won't attack nearest players etc - Visit(l, visitor, m, radius + obj.GetObjectSize(), obj.GetPositionX(), obj.GetPositionY()); -} - -template -inline void -Cell::VisitCircle(TypeContainerVisitor &visitor, Map &m, const CellPair& begin_cell, const CellPair& end_cell) const -{ - //here is an algorithm for 'filling' circum-squared octagon - uint32 x_shift = (uint32)ceilf((end_cell.x_coord - begin_cell.x_coord) * 0.3f - 0.5f); - //lets calculate x_start/x_end coords for central strip... - const uint32 x_start = begin_cell.x_coord + x_shift; - const uint32 x_end = end_cell.x_coord - x_shift; - - //visit central strip with constant width... - for (uint32 x = x_start; x <= x_end; ++x) - { - for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y) - { - CellPair cell_pair(x,y); - Cell r_zone(cell_pair); - r_zone.data.Part.nocreate = this->data.Part.nocreate; - m.Visit(r_zone, visitor); - } - } - - //if x_shift == 0 then we have too small cell area, which were already - //visited at previous step, so just return from procedure... - if (x_shift == 0) - return; - - uint32 y_start = end_cell.y_coord; - uint32 y_end = begin_cell.y_coord; - //now we are visiting borders of an octagon... - for (uint32 step = 1; step <= (x_start - begin_cell.x_coord); ++step) - { - //each step reduces strip height by 2 cells... - y_end += 1; - y_start -= 1; - for (uint32 y = y_start; y >= y_end; --y) - { - //we visit cells symmetrically from both sides, heading from center to sides and from up to bottom - //e.g. filling 2 trapezoids after filling central cell strip... - CellPair cell_pair_left(x_start - step, y); - Cell r_zone_left(cell_pair_left); - r_zone_left.data.Part.nocreate = this->data.Part.nocreate; - m.Visit(r_zone_left, visitor); - - //right trapezoid cell visit - CellPair cell_pair_right(x_end + step, y); - Cell r_zone_right(cell_pair_right); - r_zone_right.data.Part.nocreate = this->data.Part.nocreate; - m.Visit(r_zone_right, visitor); - } - } -} -#endif - diff --git a/src/server/game/Map/Grid/GridDefines.h b/src/server/game/Map/Grid/GridDefines.h deleted file mode 100644 index 5269d0a094d..00000000000 --- a/src/server/game/Map/Grid/GridDefines.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_GRIDDEFINES_H -#define TRINITY_GRIDDEFINES_H - -#include "Common.h" -#include "GameSystem/NGrid.h" -#include - -// Forward class definitions -class Corpse; -class Creature; -class DynamicObject; -class GameObject; -class Pet; -class Player; - -#define MAX_NUMBER_OF_CELLS 8 - -#define MAX_NUMBER_OF_GRIDS 64 - -#define SIZE_OF_GRIDS 533.33333f -#define CENTER_GRID_ID (MAX_NUMBER_OF_GRIDS/2) - -#define CENTER_GRID_OFFSET (SIZE_OF_GRIDS/2) - -#define MIN_GRID_DELAY (MINUTE*IN_MILISECONDS) -#define MIN_MAP_UPDATE_DELAY 50 - -#define SIZE_OF_GRID_CELL (SIZE_OF_GRIDS/MAX_NUMBER_OF_CELLS) - -#define CENTER_GRID_CELL_ID (MAX_NUMBER_OF_CELLS*MAX_NUMBER_OF_GRIDS/2) -#define CENTER_GRID_CELL_OFFSET (SIZE_OF_GRID_CELL/2) - -#define TOTAL_NUMBER_OF_CELLS_PER_MAP (MAX_NUMBER_OF_GRIDS*MAX_NUMBER_OF_CELLS) - -#define MAP_RESOLUTION 128 - -#define MAP_SIZE (SIZE_OF_GRIDS*MAX_NUMBER_OF_GRIDS) -#define MAP_HALFSIZE (MAP_SIZE/2) - -// Creature used instead pet to simplify *::Visit templates (not required duplicate code for Creature->Pet case) -typedef TYPELIST_4(Player, Creature/*pets*/, Corpse/*resurrectable*/, DynamicObject/*farsight target*/) AllWorldObjectTypes; -typedef TYPELIST_4(GameObject, Creature/*except pets*/, DynamicObject, Corpse/*Bones*/) AllGridObjectTypes; - -typedef GridRefManager CorpseMapType; -typedef GridRefManager CreatureMapType; -typedef GridRefManager DynamicObjectMapType; -typedef GridRefManager GameObjectMapType; -typedef GridRefManager PlayerMapType; - -typedef Grid GridType; -typedef NGrid NGridType; - -typedef TypeMapContainer GridTypeMapContainer; -typedef TypeMapContainer WorldTypeMapContainer; - -template -struct CoordPair -{ - CoordPair(uint32 x=0, uint32 y=0) : x_coord(x), y_coord(y) {} - CoordPair(const CoordPair &obj) : x_coord(obj.x_coord), y_coord(obj.y_coord) {} - bool operator == (const CoordPair &obj) const { return (obj.x_coord == x_coord && obj.y_coord == y_coord); } - bool operator != (const CoordPair &obj) const { return !operator == (obj); } - CoordPair& operator=(const CoordPair &obj) - { - x_coord = obj.x_coord; - y_coord = obj.y_coord; - return *this; - } - - void operator<<(const uint32 val) - { - if (x_coord > val) - x_coord -= val; - else - x_coord = 0; - } - - void operator>>(const uint32 val) - { - if (x_coord+val < LIMIT) - x_coord += val; - else - x_coord = LIMIT - 1; - } - - void operator-=(const uint32 val) - { - if (y_coord > val) - y_coord -= val; - else - y_coord = 0; - } - - void operator+=(const uint32 val) - { - if (y_coord+val < LIMIT) - y_coord += val; - else - y_coord = LIMIT - 1; - } - - uint32 x_coord; - uint32 y_coord; -}; - -typedef CoordPair GridPair; -typedef CoordPair CellPair; - -namespace Trinity -{ - template - inline RET_TYPE Compute(float x, float y, float center_offset, float size) - { - // calculate and store temporary values in double format for having same result as same mySQL calculations - double x_offset = (double(x) - center_offset)/size; - double y_offset = (double(y) - center_offset)/size; - - int x_val = int(x_offset+CENTER_VAL + 0.5); - int y_val = int(y_offset+CENTER_VAL + 0.5); - return RET_TYPE(x_val, y_val); - } - - inline GridPair ComputeGridPair(float x, float y) - { - return Compute(x, y, CENTER_GRID_OFFSET, SIZE_OF_GRIDS); - } - - inline CellPair ComputeCellPair(float x, float y) - { - return Compute(x, y, CENTER_GRID_CELL_OFFSET, SIZE_OF_GRID_CELL); - } - - inline CellPair ComputeCellPair(float x, float y, float &x_off, float &y_off) - { - double x_offset = (double(x) - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL; - double y_offset = (double(y) - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL; - - int x_val = int(x_offset + CENTER_GRID_CELL_ID + 0.5); - int y_val = int(y_offset + CENTER_GRID_CELL_ID + 0.5); - x_off = (float(x_offset) - x_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL; - y_off = (float(y_offset) - y_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL; - return CellPair(x_val, y_val); - } - - inline void NormalizeMapCoord(float &c) - { - if (c > MAP_HALFSIZE - 0.5) - c = MAP_HALFSIZE - 0.5; - else if (c < -(MAP_HALFSIZE - 0.5)) - c = -(MAP_HALFSIZE - 0.5); - } - - inline bool IsValidMapCoord(float c) - { - return finite(c) && (std::fabs(c) <= MAP_HALFSIZE - 0.5); - } - - inline bool IsValidMapCoord(float x, float y) - { - return IsValidMapCoord(x) && IsValidMapCoord(y); - } - - inline bool IsValidMapCoord(float x, float y, float z) - { - return IsValidMapCoord(x,y) && finite(z); - } - - inline bool IsValidMapCoord(float x, float y, float z, float o) - { - return IsValidMapCoord(x,y,z) && finite(o); - } -} -#endif diff --git a/src/server/game/Map/Grid/GridNotifiers.cpp b/src/server/game/Map/Grid/GridNotifiers.cpp deleted file mode 100644 index b10dfa8791e..00000000000 --- a/src/server/game/Map/Grid/GridNotifiers.cpp +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "GridNotifiers.h" -#include "GridNotifiersImpl.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "UpdateData.h" -#include "Item.h" -#include "Map.h" -#include "Transports.h" -#include "ObjectAccessor.h" -#include "CellImpl.h" - -using namespace Trinity; - -void -VisibleNotifier::SendToSelf() -{ - // at this moment i_clientGUIDs have guids that not iterate at grid level checks - // but exist one case when this possible and object not out of range: transports - if (Transport* transport = i_player.GetTransport()) - for (Transport::PlayerSet::const_iterator itr = transport->GetPassengers().begin();itr != transport->GetPassengers().end();++itr) - { - if (vis_guids.find((*itr)->GetGUID()) != vis_guids.end()) - { - vis_guids.erase((*itr)->GetGUID()); - - i_player.UpdateVisibilityOf((*itr), i_data, i_visibleNow); - - if (!(*itr)->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) - (*itr)->UpdateVisibilityOf(&i_player); - } - } - - for (Player::ClientGUIDs::const_iterator it = vis_guids.begin();it != vis_guids.end(); ++it) - { - i_player.m_clientGUIDs.erase(*it); - i_data.AddOutOfRangeGUID(*it); - - if (IS_PLAYER_GUID(*it)) - { - Player* plr = ObjectAccessor::FindPlayer(*it); - if (plr && plr->IsInWorld() && !plr->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) - plr->UpdateVisibilityOf(&i_player); - } - } - - if (!i_data.HasData()) - return; - - WorldPacket packet; - i_data.BuildPacket(&packet); - i_player.GetSession()->SendPacket(&packet); - - for (std::set::const_iterator it = i_visibleNow.begin(); it != i_visibleNow.end(); ++it) - i_player.SendInitialVisiblePackets(*it); -} - -void -VisibleChangesNotifier::Visit(PlayerMapType &m) -{ - for (PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) - { - if (iter->getSource() == &i_object) - continue; - - iter->getSource()->UpdateVisibilityOf(&i_object); - - if (!iter->getSource()->GetSharedVisionList().empty()) - for (SharedVisionList::const_iterator i = iter->getSource()->GetSharedVisionList().begin(); - i != iter->getSource()->GetSharedVisionList().end(); ++i) - if ((*i)->m_seer == iter->getSource()) - (*i)->UpdateVisibilityOf(&i_object); - } -} - -void -VisibleChangesNotifier::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - if (!iter->getSource()->GetSharedVisionList().empty()) - for (SharedVisionList::const_iterator i = iter->getSource()->GetSharedVisionList().begin(); - i != iter->getSource()->GetSharedVisionList().end(); ++i) - if ((*i)->m_seer == iter->getSource()) - (*i)->UpdateVisibilityOf(&i_object); -} - -void -VisibleChangesNotifier::Visit(DynamicObjectMapType &m) -{ - for (DynamicObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - if (IS_PLAYER_GUID(iter->getSource()->GetCasterGUID())) - if (Player* caster = (Player*)iter->getSource()->GetCaster()) - if (caster->m_seer == iter->getSource()) - caster->UpdateVisibilityOf(&i_object); -} - -inline void CreatureUnitRelocationWorker(Creature* c, Unit* u) -{ - if (!u->isAlive() || !c->isAlive() || c == u || u->isInFlight()) - return; - - if (c->HasReactState(REACT_AGGRESSIVE) && !c->hasUnitState(UNIT_STAT_SIGHTLESS)) - if (c->_IsWithinDist(u, c->m_SightDistance, true) && c->IsAIEnabled) - c->AI()->MoveInLineOfSight_Safe(u); -} - -void PlayerRelocationNotifier::Visit(PlayerMapType &m) -{ - for (PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) - { - Player* plr = iter->getSource(); - - vis_guids.erase(plr->GetGUID()); - - i_player.UpdateVisibilityOf(plr,i_data,i_visibleNow); - - if (plr->m_seer->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) - continue; - - plr->UpdateVisibilityOf(&i_player); - } -} - -void PlayerRelocationNotifier::Visit(CreatureMapType &m) -{ - bool relocated_for_ai = (&i_player == i_player.m_seer); - - for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter) - { - Creature * c = iter->getSource(); - - vis_guids.erase(c->GetGUID()); - - i_player.UpdateVisibilityOf(c,i_data,i_visibleNow); - - if (relocated_for_ai && !c->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) - CreatureUnitRelocationWorker(c, &i_player); - } -} - -void CreatureRelocationNotifier::Visit(PlayerMapType &m) -{ - for (PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) - { - Player * pl = iter->getSource(); - - if (!pl->m_seer->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) - pl->UpdateVisibilityOf(&i_creature); - - CreatureUnitRelocationWorker(&i_creature, pl); - } -} - -void CreatureRelocationNotifier::Visit(CreatureMapType &m) -{ - if (!i_creature.isAlive()) - return; - - for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter) - { - Creature* c = iter->getSource(); - CreatureUnitRelocationWorker(&i_creature, c); - - if (!c->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) - CreatureUnitRelocationWorker(c, &i_creature); - } -} - -void DelayedUnitRelocation::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - { - Creature * unit = iter->getSource(); - if (!unit->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) - continue; - - CreatureRelocationNotifier relocate(*unit); - - TypeContainerVisitor c2world_relocation(relocate); - TypeContainerVisitor c2grid_relocation(relocate); - - cell.Visit(p, c2world_relocation, i_map, *unit, i_radius); - cell.Visit(p, c2grid_relocation, i_map, *unit, i_radius); - } -} - -void DelayedUnitRelocation::Visit(PlayerMapType &m) -{ - for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - { - Player * player = iter->getSource(); - WorldObject const *viewPoint = player->m_seer; - - if (!viewPoint->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) - continue; - - if (player != viewPoint && !viewPoint->IsPositionValid()) - continue; - - CellPair pair2(Trinity::ComputeCellPair(viewPoint->GetPositionX(), viewPoint->GetPositionY())); - Cell cell2(pair2); - //cell.SetNoCreate(); need load cells around viewPoint or player, that's why its commented - - PlayerRelocationNotifier relocate(*player); - TypeContainerVisitor c2world_relocation(relocate); - TypeContainerVisitor c2grid_relocation(relocate); - - cell2.Visit(pair2, c2world_relocation, i_map, *viewPoint, i_radius); - cell2.Visit(pair2, c2grid_relocation, i_map, *viewPoint, i_radius); - - relocate.SendToSelf(); - } -} - -void AIRelocationNotifier::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - { - Creature *c = iter->getSource(); - CreatureUnitRelocationWorker(c, &i_unit); - if (isCreature) - CreatureUnitRelocationWorker((Creature*)&i_unit, c); - } -} - -void -MessageDistDeliverer::Visit(PlayerMapType &m) -{ - for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - { - Player *target = iter->getSource(); - if (!target->InSamePhase(i_phaseMask)) - continue; - - if (target->GetExactDistSq(i_source) > i_distSq) - continue; - - // Send packet to all who are sharing the player's vision - if (!target->GetSharedVisionList().empty()) - { - SharedVisionList::const_iterator i = target->GetSharedVisionList().begin(); - for (; i != target->GetSharedVisionList().end(); ++i) - if ((*i)->m_seer == target) - SendPacket(*i); - } - - if (target->m_seer == target || target->GetVehicle()) - SendPacket(target); - } -} - -void -MessageDistDeliverer::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - { - if (!iter->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (iter->getSource()->GetExactDistSq(i_source) > i_distSq) - continue; - - // Send packet to all who are sharing the creature's vision - if (!iter->getSource()->GetSharedVisionList().empty()) - { - SharedVisionList::const_iterator i = iter->getSource()->GetSharedVisionList().begin(); - for (; i != iter->getSource()->GetSharedVisionList().end(); ++i) - if ((*i)->m_seer == iter->getSource()) - SendPacket(*i); - } - } -} - -void -MessageDistDeliverer::Visit(DynamicObjectMapType &m) -{ - for (DynamicObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - { - if (!iter->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (iter->getSource()->GetExactDistSq(i_source) > i_distSq) - continue; - - if (IS_PLAYER_GUID(iter->getSource()->GetCasterGUID())) - { - // Send packet back to the caster if the caster has vision of dynamic object - Player* caster = (Player*)iter->getSource()->GetCaster(); - if (caster && caster->m_seer == iter->getSource()) - SendPacket(caster); - } - } -} - -/* -void -MessageDistDeliverer::VisitObject(Player* plr) -{ - if (!i_ownTeamOnly || (i_source.GetTypeId() == TYPEID_PLAYER && plr->GetTeam() == ((Player&)i_source).GetTeam())) - { - SendPacket(plr); - } -} -*/ - -template void -ObjectUpdater::Visit(GridRefManager &m) -{ - for (typename GridRefManager::iterator iter = m.begin(); iter != m.end(); ++iter) - { - if (iter->getSource()->IsInWorld()) - iter->getSource()->Update(i_timeDiff); - } -} - -bool CannibalizeObjectCheck::operator()(Corpse* u) -{ - // ignore bones - if (u->GetType() == CORPSE_BONES) - return false; - - Player* owner = ObjectAccessor::FindPlayer(u->GetOwnerGUID()); - - if (!owner || i_funit->IsFriendlyTo(owner)) - return false; - - if (i_funit->IsWithinDistInMap(u, i_range)) - return true; - - return false; -} - -template void ObjectUpdater::Visit(GameObjectMapType &); -template void ObjectUpdater::Visit(DynamicObjectMapType &); diff --git a/src/server/game/Map/Grid/GridNotifiers.h b/src/server/game/Map/Grid/GridNotifiers.h deleted file mode 100644 index b0abf0aae79..00000000000 --- a/src/server/game/Map/Grid/GridNotifiers.h +++ /dev/null @@ -1,1232 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_GRIDNOTIFIERS_H -#define TRINITY_GRIDNOTIFIERS_H - -#include "ObjectGridLoader.h" -#include "UpdateData.h" -#include - -#include "Corpse.h" -#include "Object.h" -#include "DynamicObject.h" -#include "GameObject.h" -#include "Player.h" -#include "Unit.h" -#include "CreatureAI.h" - -class Player; -//class Map; - -namespace Trinity -{ - struct VisibleNotifier - { - Player &i_player; - UpdateData i_data; - std::set i_visibleNow; - Player::ClientGUIDs vis_guids; - - VisibleNotifier(Player &player) : i_player(player), vis_guids(player.m_clientGUIDs) {} - template void Visit(GridRefManager &m); - void SendToSelf(void); - }; - - struct VisibleChangesNotifier - { - WorldObject &i_object; - - explicit VisibleChangesNotifier(WorldObject &object) : i_object(object) {} - template void Visit(GridRefManager &) {} - void Visit(PlayerMapType &); - void Visit(CreatureMapType &); - void Visit(DynamicObjectMapType &); - }; - - struct PlayerRelocationNotifier : public VisibleNotifier - { - PlayerRelocationNotifier(Player &pl) : VisibleNotifier(pl) {} - - template void Visit(GridRefManager &m) { VisibleNotifier::Visit(m); } - void Visit(CreatureMapType &); - void Visit(PlayerMapType &); - }; - - struct CreatureRelocationNotifier - { - Creature &i_creature; - CreatureRelocationNotifier(Creature &c) : i_creature(c) {} - template void Visit(GridRefManager &) {} - void Visit(CreatureMapType &); - void Visit(PlayerMapType &); - }; - - struct DelayedUnitRelocation - { - Map &i_map; - Cell &cell; - CellPair &p; - const float i_radius; - DelayedUnitRelocation(Cell &c, CellPair &pair, Map &map, float radius) : - cell(c), p(pair), i_map(map), i_radius(radius) {} - template void Visit(GridRefManager &) {} - void Visit(CreatureMapType &); - void Visit(PlayerMapType &); - }; - - struct AIRelocationNotifier - { - Unit &i_unit; - bool isCreature; - explicit AIRelocationNotifier(Unit &unit) : i_unit(unit), isCreature(unit.GetTypeId() == TYPEID_UNIT) {} - template void Visit(GridRefManager &) {} - void Visit(CreatureMapType &); - }; - - struct GridUpdater - { - GridType &i_grid; - uint32 i_timeDiff; - GridUpdater(GridType &grid, uint32 diff) : i_grid(grid), i_timeDiff(diff) {} - - template void updateObjects(GridRefManager &m) - { - for (typename GridRefManager::iterator iter = m.begin(); iter != m.end(); ++iter) - iter->getSource()->Update(i_timeDiff); - } - - void Visit(PlayerMapType &m) { updateObjects(m); } - void Visit(CreatureMapType &m){ updateObjects(m); } - void Visit(GameObjectMapType &m) { updateObjects(m); } - void Visit(DynamicObjectMapType &m) { updateObjects(m); } - void Visit(CorpseMapType &m) { updateObjects(m); } - }; - - struct MessageDistDeliverer - { - WorldObject *i_source; - WorldPacket *i_message; - uint32 i_phaseMask; - float i_distSq; - uint32 team; - Player const* skipped_receiver; - MessageDistDeliverer(WorldObject *src, WorldPacket *msg, float dist, bool own_team_only = false, Player const* skipped = NULL) - : i_source(src), i_message(msg), i_distSq(dist * dist), i_phaseMask(src->GetPhaseMask()) - , team((own_team_only && src->GetTypeId() == TYPEID_PLAYER) ? ((Player*)src)->GetTeam() : 0) - , skipped_receiver(skipped) - { - } - void Visit(PlayerMapType &m); - void Visit(CreatureMapType &m); - void Visit(DynamicObjectMapType &m); - template void Visit(GridRefManager &) {} - - void SendPacket(Player* plr) - { - // never send packet to self - if (plr == i_source || (team && plr->GetTeam() != team) || skipped_receiver == plr) - return; - - plr->GetSession()->SendPacket(i_message); - } - }; - - struct ObjectUpdater - { - uint32 i_timeDiff; - explicit ObjectUpdater(const uint32 &diff) : i_timeDiff(diff) {} - template void Visit(GridRefManager &m); - void Visit(PlayerMapType &) {} - void Visit(CorpseMapType &) {} - void Visit(CreatureMapType &); - }; - - // SEARCHERS & LIST SEARCHERS & WORKERS - - // WorldObject searchers & workers - - template - struct WorldObjectSearcher - { - uint32 i_phaseMask; - WorldObject* &i_object; - Check &i_check; - - WorldObjectSearcher(WorldObject const* searcher, WorldObject* & result, Check& check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {} - - void Visit(GameObjectMapType &m); - void Visit(PlayerMapType &m); - void Visit(CreatureMapType &m); - void Visit(CorpseMapType &m); - void Visit(DynamicObjectMapType &m); - - template void Visit(GridRefManager &) {} - }; - - template - struct WorldObjectListSearcher - { - uint32 i_phaseMask; - std::list &i_objects; - Check& i_check; - - WorldObjectListSearcher(WorldObject const* searcher, std::list &objects, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects),i_check(check) {} - - void Visit(PlayerMapType &m); - void Visit(CreatureMapType &m); - void Visit(CorpseMapType &m); - void Visit(GameObjectMapType &m); - void Visit(DynamicObjectMapType &m); - - template void Visit(GridRefManager &) {} - }; - - template - struct WorldObjectWorker - { - uint32 i_phaseMask; - Do const& i_do; - - WorldObjectWorker(WorldObject const* searcher, Do const& _do) - : i_phaseMask(searcher->GetPhaseMask()), i_do(_do) {} - - void Visit(GameObjectMapType &m) - { - for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - i_do(itr->getSource()); - } - - void Visit(PlayerMapType &m) - { - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - i_do(itr->getSource()); - } - void Visit(CreatureMapType &m) - { - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - i_do(itr->getSource()); - } - - void Visit(CorpseMapType &m) - { - for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - i_do(itr->getSource()); - } - - void Visit(DynamicObjectMapType &m) - { - for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - i_do(itr->getSource()); - } - - template void Visit(GridRefManager &) {} - }; - - // Gameobject searchers - - template - struct GameObjectSearcher - { - uint32 i_phaseMask; - GameObject* &i_object; - Check &i_check; - - GameObjectSearcher(WorldObject const* searcher, GameObject* & result, Check& check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {} - - void Visit(GameObjectMapType &m); - - template void Visit(GridRefManager &) {} - }; - - // Last accepted by Check GO if any (Check can change requirements at each call) - template - struct GameObjectLastSearcher - { - uint32 i_phaseMask; - GameObject* &i_object; - Check& i_check; - - GameObjectLastSearcher(WorldObject const* searcher, GameObject* & result, Check& check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) {} - - void Visit(GameObjectMapType &m); - - template void Visit(GridRefManager &) {} - }; - - template - struct GameObjectListSearcher - { - uint32 i_phaseMask; - std::list &i_objects; - Check& i_check; - - GameObjectListSearcher(WorldObject const* searcher, std::list &objects, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {} - - void Visit(GameObjectMapType &m); - - template void Visit(GridRefManager &) {} - }; - - // Unit searchers - - // First accepted by Check Unit if any - template - struct UnitSearcher - { - uint32 i_phaseMask; - Unit* &i_object; - Check & i_check; - - UnitSearcher(WorldObject const* searcher, Unit* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {} - - void Visit(CreatureMapType &m); - void Visit(PlayerMapType &m); - - template void Visit(GridRefManager &) {} - }; - - // Last accepted by Check Unit if any (Check can change requirements at each call) - template - struct UnitLastSearcher - { - uint32 i_phaseMask; - Unit* &i_object; - Check & i_check; - - UnitLastSearcher(WorldObject const* searcher, Unit* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {} - - void Visit(CreatureMapType &m); - void Visit(PlayerMapType &m); - - template void Visit(GridRefManager &) {} - }; - - // All accepted by Check units if any - template - struct UnitListSearcher - { - uint32 i_phaseMask; - std::list &i_objects; - Check& i_check; - - UnitListSearcher(WorldObject const* searcher, std::list &objects, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects),i_check(check) {} - - void Visit(PlayerMapType &m); - void Visit(CreatureMapType &m); - - template void Visit(GridRefManager &) {} - }; - - // Creature searchers - - template - struct CreatureSearcher - { - uint32 i_phaseMask; - Creature* &i_object; - Check & i_check; - - CreatureSearcher(WorldObject const* searcher, Creature* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {} - - void Visit(CreatureMapType &m); - - template void Visit(GridRefManager &) {} - }; - - // Last accepted by Check Creature if any (Check can change requirements at each call) - template - struct CreatureLastSearcher - { - uint32 i_phaseMask; - Creature* &i_object; - Check & i_check; - - CreatureLastSearcher(WorldObject const* searcher, Creature* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {} - - void Visit(CreatureMapType &m); - - template void Visit(GridRefManager &) {} - }; - - template - struct CreatureListSearcher - { - uint32 i_phaseMask; - std::list &i_objects; - Check& i_check; - - CreatureListSearcher(WorldObject const* searcher, std::list &objects, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects),i_check(check) {} - - void Visit(CreatureMapType &m); - - template void Visit(GridRefManager &) {} - }; - - template - struct CreatureWorker - { - uint32 i_phaseMask; - Do& i_do; - - CreatureWorker(WorldObject const* searcher, Do& _do) - : i_phaseMask(searcher->GetPhaseMask()), i_do(_do) {} - - void Visit(CreatureMapType &m) - { - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - i_do(itr->getSource()); - } - - template void Visit(GridRefManager &) {} - }; - - // Player searchers - - template - struct PlayerSearcher - { - uint32 i_phaseMask; - Player* &i_object; - Check & i_check; - - PlayerSearcher(WorldObject const* searcher, Player* & result, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {} - - void Visit(PlayerMapType &m); - - template void Visit(GridRefManager &) {} - }; - - template - struct PlayerListSearcher - { - uint32 i_phaseMask; - std::list &i_objects; - Check& i_check; - - PlayerListSearcher(WorldObject const* searcher, std::list &objects, Check & check) - : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects),i_check(check) {} - - void Visit(PlayerMapType &m); - - template void Visit(GridRefManager &) {} - }; - - template - struct PlayerWorker - { - uint32 i_phaseMask; - Do& i_do; - - PlayerWorker(WorldObject const* searcher, Do& _do) - : i_phaseMask(searcher->GetPhaseMask()), i_do(_do) {} - - void Visit(PlayerMapType &m) - { - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - i_do(itr->getSource()); - } - - template void Visit(GridRefManager &) {} - }; - - template - struct PlayerDistWorker - { - WorldObject const* i_searcher; - float i_dist; - Do& i_do; - - PlayerDistWorker(WorldObject const* searcher, float _dist, Do& _do) - : i_searcher(searcher), i_dist(_dist), i_do(_do) {} - - void Visit(PlayerMapType &m) - { - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_searcher) && itr->getSource()->IsWithinDist(i_searcher,i_dist)) - i_do(itr->getSource()); - } - - template void Visit(GridRefManager &) {} - }; - - // CHECKS && DO classes - - // WorldObject check classes - class RaiseDeadObjectCheck - { - public: - RaiseDeadObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {} - bool operator()(Creature* u) - { - if (i_funit->GetTypeId() != TYPEID_PLAYER || !((Player*)i_funit)->isHonorOrXPTarget(u) || - u->getDeathState() != CORPSE || u->isDeadByDefault() || u->isInFlight() || - (u->GetCreatureTypeMask() & (1 << (CREATURE_TYPE_HUMANOID-1))) == 0 || - (u->GetDisplayId() != u->GetNativeDisplayId())) - return false; - - return i_funit->IsWithinDistInMap(u, i_range); - } - template bool operator()(NOT_INTERESTED*) { return false; } - private: - Unit* const i_funit; - float i_range; - }; - - class ExplodeCorpseObjectCheck - { - public: - ExplodeCorpseObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {} - bool operator()(Player* u) - { - if (u->getDeathState() != CORPSE || u->isInFlight() || - u->HasAuraType(SPELL_AURA_GHOST) || (u->GetDisplayId() != u->GetNativeDisplayId())) - return false; - - return i_funit->IsWithinDistInMap(u, i_range); - } - bool operator()(Creature* u) - { - if (u->getDeathState() != CORPSE || u->isInFlight() || u->isDeadByDefault() || - (u->GetDisplayId() != u->GetNativeDisplayId()) || - (u->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL) != 0) - return false; - - return i_funit->IsWithinDistInMap(u, i_range); - } - template bool operator()(NOT_INTERESTED*) { return false; } - private: - Unit* const i_funit; - float i_range; - }; - - class CannibalizeObjectCheck - { - public: - CannibalizeObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {} - bool operator()(Player* u) - { - if (i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight()) - return false; - - return i_funit->IsWithinDistInMap(u, i_range); - } - bool operator()(Corpse* u); - bool operator()(Creature* u) - { - if (i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() || - (u->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) == 0) - return false; - - return i_funit->IsWithinDistInMap(u, i_range); - } - template bool operator()(NOT_INTERESTED*) { return false; } - private: - Unit* const i_funit; - float i_range; - }; - - // WorldObject do classes - - class RespawnDo - { - public: - RespawnDo() {} - void operator()(Creature* u) const { u->Respawn(); } - void operator()(GameObject* u) const { u->Respawn(); } - void operator()(WorldObject*) const {} - void operator()(Corpse*) const {} - }; - - // GameObject checks - - class GameObjectFocusCheck - { - public: - GameObjectFocusCheck(Unit const* unit,uint32 focusId) : i_unit(unit), i_focusId(focusId) {} - bool operator()(GameObject* go) const - { - if (go->GetGOInfo()->type != GAMEOBJECT_TYPE_SPELL_FOCUS) - return false; - - if (go->GetGOInfo()->spellFocus.focusId != i_focusId) - return false; - - float dist = (go->GetGOInfo()->spellFocus.dist)/2; - - return go->IsWithinDistInMap(i_unit, dist); - } - private: - Unit const* i_unit; - uint32 i_focusId; - }; - - // Find the nearest Fishing hole and return true only if source object is in range of hole - class NearestGameObjectFishingHole - { - public: - NearestGameObjectFishingHole(WorldObject const& obj, float range) : i_obj(obj), i_range(range) {} - bool operator()(GameObject* go) - { - if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_FISHINGHOLE && go->isSpawned() && i_obj.IsWithinDistInMap(go, i_range) && i_obj.IsWithinDistInMap(go, go->GetGOInfo()->fishinghole.radius)) - { - i_range = i_obj.GetDistance(go); - return true; - } - return false; - } - float GetLastRange() const { return i_range; } - private: - WorldObject const& i_obj; - float i_range; - - // prevent clone - NearestGameObjectFishingHole(NearestGameObjectFishingHole const&); - }; - - class NearestGameObjectCheck - { - public: - NearestGameObjectCheck(WorldObject const& obj) : i_obj(obj), i_range(999) {} - bool operator()(GameObject* go) - { - if (i_obj.IsWithinDistInMap(go, i_range)) - { - i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check - return true; - } - return false; - } - float GetLastRange() const { return i_range; } - private: - WorldObject const& i_obj; - float i_range; - - // prevent clone this object - NearestGameObjectCheck(NearestGameObjectCheck const&); - }; - - // Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest GO) - class NearestGameObjectEntryInObjectRangeCheck - { - public: - NearestGameObjectEntryInObjectRangeCheck(WorldObject const& obj,uint32 entry, float range) : i_obj(obj), i_entry(entry), i_range(range) {} - bool operator()(GameObject* go) - { - if (go->GetEntry() == i_entry && i_obj.IsWithinDistInMap(go, i_range)) - { - i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check - return true; - } - return false; - } - float GetLastRange() const { return i_range; } - private: - WorldObject const& i_obj; - uint32 i_entry; - float i_range; - - // prevent clone this object - NearestGameObjectEntryInObjectRangeCheck(NearestGameObjectEntryInObjectRangeCheck const&); - }; - - class GameObjectWithDbGUIDCheck - { - public: - GameObjectWithDbGUIDCheck(WorldObject const& obj,uint32 db_guid) : i_obj(obj), i_db_guid(db_guid) {} - bool operator()(GameObject const* go) const - { - return go->GetDBTableGUIDLow() == i_db_guid; - } - private: - WorldObject const& i_obj; - uint32 i_db_guid; - }; - - // Unit checks - - class MostHPMissingInRange - { - public: - MostHPMissingInRange(Unit const* obj, float range, uint32 hp) : i_obj(obj), i_range(range), i_hp(hp) {} - bool operator()(Unit* u) - { - if (u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && u->GetMaxHealth() - u->GetHealth() > i_hp) - { - i_hp = u->GetMaxHealth() - u->GetHealth(); - return true; - } - return false; - } - private: - Unit const* i_obj; - float i_range; - uint32 i_hp; - }; - - class FriendlyCCedInRange - { - public: - FriendlyCCedInRange(Unit const* obj, float range) : i_obj(obj), i_range(range) {} - bool operator()(Unit* u) - { - if (u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && - (u->isFeared() || u->isCharmed() || u->isFrozen() || u->hasUnitState(UNIT_STAT_STUNNED) || u->hasUnitState(UNIT_STAT_CONFUSED))) - { - return true; - } - return false; - } - private: - Unit const* i_obj; - float i_range; - }; - - class FriendlyMissingBuffInRange - { - public: - FriendlyMissingBuffInRange(Unit const* obj, float range, uint32 spellid) : i_obj(obj), i_range(range), i_spell(spellid) {} - bool operator()(Unit* u) - { - if (u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && - !(u->HasAura(i_spell))) - { - return true; - } - return false; - } - private: - Unit const* i_obj; - float i_range; - uint32 i_spell; - }; - - class AnyUnfriendlyUnitInObjectRangeCheck - { - public: - AnyUnfriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} - bool operator()(Unit* u) - { - if (u->isAlive() && i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u)) - return true; - else - return false; - } - private: - WorldObject const* i_obj; - Unit const* i_funit; - float i_range; - }; - - class AnyUnfriendlyNoTotemUnitInObjectRangeCheck - { - public: - AnyUnfriendlyNoTotemUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} - bool operator()(Unit* u) - { - if (!u->isAlive()) - return false; - - if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->isTotem()) - return false; - - return i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u); - } - private: - WorldObject const* i_obj; - Unit const* i_funit; - float i_range; - }; - - class AnyUnfriendlyVisibleUnitInObjectRangeCheck - { - public: - AnyUnfriendlyVisibleUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) - : i_obj(obj), i_funit(funit), i_range(range) {} - - bool operator()(Unit* u) - { - return u->isAlive() - && i_obj->IsWithinDistInMap(u, i_range) - && !i_funit->IsFriendlyTo(u) - && u->isVisibleForOrDetect(i_funit, false); - } - private: - WorldObject const* i_obj; - Unit const* i_funit; - float i_range; - }; - - class CreatureWithDbGUIDCheck - { - public: - CreatureWithDbGUIDCheck(WorldObject const* obj, uint32 lowguid) : i_obj(obj), i_lowguid(lowguid) {} - bool operator()(Creature* u) - { - return u->GetDBTableGUIDLow() == i_lowguid; - } - private: - WorldObject const* i_obj; - uint32 i_lowguid; - }; - - class AnyFriendlyUnitInObjectRangeCheck - { - public: - AnyFriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} - bool operator()(Unit* u) - { - if (u->isAlive() && i_obj->IsWithinDistInMap(u, i_range) && i_funit->IsFriendlyTo(u)) - return true; - else - return false; - } - private: - WorldObject const* i_obj; - Unit const* i_funit; - float i_range; - }; - - class AnyUnitInObjectRangeCheck - { - public: - AnyUnitInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {} - bool operator()(Unit* u) - { - if (u->isAlive() && i_obj->IsWithinDistInMap(u, i_range)) - return true; - - return false; - } - private: - WorldObject const* i_obj; - float i_range; - }; - - // Success at unit in range, range update for next check (this can be use with UnitLastSearcher to find nearest unit) - class NearestAttackableUnitInObjectRangeCheck - { - public: - NearestAttackableUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} - bool operator()(Unit* u) - { - if (u->isTargetableForAttack() && i_obj->IsWithinDistInMap(u, i_range) && - !i_funit->IsFriendlyTo(u) && u->isVisibleForOrDetect(i_funit,false)) - { - i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check - return true; - } - - return false; - } - private: - WorldObject const* i_obj; - Unit const* i_funit; - float i_range; - - // prevent clone this object - NearestAttackableUnitInObjectRangeCheck(NearestAttackableUnitInObjectRangeCheck const&); - }; - - class AnyAoETargetUnitInObjectRangeCheck - { - public: - AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) - : i_obj(obj), i_funit(funit), i_range(range) - { - Unit const* check = i_funit; - Unit const* owner = i_funit->GetOwner(); - if (owner) - check = owner; - i_targetForPlayer = (check->GetTypeId() == TYPEID_PLAYER); - } - bool operator()(Unit* u) - { - // Check contains checks for: live, non-selectable, non-attackable flags, flight check and GM check, ignore totems - if (!u->isTargetableForAttack()) - return false; - if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->isTotem()) - return false; - - if ((i_targetForPlayer ? !i_funit->IsFriendlyTo(u) : i_funit->IsHostileTo(u))&& i_obj->IsWithinDistInMap(u, i_range)) - return true; - - return false; - } - private: - bool i_targetForPlayer; - WorldObject const* i_obj; - Unit const* i_funit; - float i_range; - }; - - // do attack at call of help to friendly crearture - class CallOfHelpCreatureInRangeDo - { - public: - CallOfHelpCreatureInRangeDo(Unit* funit, Unit* enemy, float range) - : i_funit(funit), i_enemy(enemy), i_range(range) - {} - void operator()(Creature* u) - { - if (u == i_funit) - return; - - if (!u->CanAssistTo(i_funit, i_enemy, false)) - return; - - // too far - if (!u->IsWithinDistInMap(i_enemy, i_range)) - return; - - // only if see assisted creature's enemy - if (!u->IsWithinLOSInMap(i_enemy)) - return; - - if (u->AI()) - u->AI()->AttackStart(i_enemy); - } - private: - Unit* const i_funit; - Unit* const i_enemy; - float i_range; - }; - - struct AnyDeadUnitCheck - { - bool operator()(Unit* u) { return !u->isAlive(); } - }; - - struct AnyStealthedCheck - { - bool operator()(Unit* u) { return u->GetVisibility() == VISIBILITY_GROUP_STEALTH; } - }; - - // Creature checks - - class NearestHostileUnitCheck - { - public: - explicit NearestHostileUnitCheck(Creature const* creature, float dist = 0) : me(creature) - { - m_range = (dist == 0 ? 9999 : dist); - } - bool operator()(Unit* u) - { - if (!me->IsWithinDistInMap(u, m_range)) - return false; - - if (!me->canAttack(u)) - return false; - - m_range = me->GetDistance(u); // use found unit range as new range limit for next check - return true; - } - - private: - Creature const *me; - float m_range; - NearestHostileUnitCheck(NearestHostileUnitCheck const&); - }; - - class NearestHostileUnitInAttackDistanceCheck - { - public: - explicit NearestHostileUnitInAttackDistanceCheck(Creature const* creature, float dist = 0) : me(creature) - { - m_range = (dist == 0 ? 9999 : dist); - m_force = (dist == 0 ? false : true); - } - bool operator()(Unit* u) - { - if (!me->IsWithinDistInMap(u, m_range)) - return false; - - if (m_force) - { - if (!me->canAttack(u)) - return false; - } - else - { - if (!me->canStartAttack(u, false)) - return false; - } - - m_range = me->GetDistance(u); // use found unit range as new range limit for next check - return true; - } - float GetLastRange() const { return m_range; } - private: - Creature const *me; - float m_range; - bool m_force; - NearestHostileUnitInAttackDistanceCheck(NearestHostileUnitInAttackDistanceCheck const&); - }; - - class AnyAssistCreatureInRangeCheck - { - public: - AnyAssistCreatureInRangeCheck(Unit* funit, Unit* enemy, float range) - : i_funit(funit), i_enemy(enemy), i_range(range) - { - } - bool operator()(Creature* u) - { - if (u == i_funit) - return false; - - if (!u->CanAssistTo(i_funit, i_enemy)) - return false; - - // too far - if (!i_funit->IsWithinDistInMap(u, i_range)) - return false; - - // only if see assisted creature - if (!i_funit->IsWithinLOSInMap(u)) - return false; - - return true; - } - private: - Unit* const i_funit; - Unit* const i_enemy; - float i_range; - }; - - class NearestAssistCreatureInCreatureRangeCheck - { - public: - NearestAssistCreatureInCreatureRangeCheck(Creature* obj, Unit* enemy, float range) - : i_obj(obj), i_enemy(enemy), i_range(range) {} - - bool operator()(Creature* u) - { - if (u == i_obj) - return false; - if (!u->CanAssistTo(i_obj,i_enemy)) - return false; - - if (!i_obj->IsWithinDistInMap(u, i_range)) - return false; - - if (!i_obj->IsWithinLOSInMap(u)) - return false; - - i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check - return true; - } - float GetLastRange() const { return i_range; } - private: - Creature* const i_obj; - Unit* const i_enemy; - float i_range; - - // prevent clone this object - NearestAssistCreatureInCreatureRangeCheck(NearestAssistCreatureInCreatureRangeCheck const&); - }; - - // Success at unit in range, range update for next check (this can be use with CreatureLastSearcher to find nearest creature) - class NearestCreatureEntryWithLiveStateInObjectRangeCheck - { - public: - NearestCreatureEntryWithLiveStateInObjectRangeCheck(WorldObject const& obj, uint32 entry, bool alive, float range) - : i_obj(obj), i_entry(entry), i_alive(alive), i_range(range) {} - - bool operator()(Creature* u) - { - if (u->GetEntry() == i_entry && u->isAlive() == i_alive && i_obj.IsWithinDistInMap(u, i_range)) - { - i_range = i_obj.GetDistance(u); // use found unit range as new range limit for next check - return true; - } - return false; - } - float GetLastRange() const { return i_range; } - private: - WorldObject const& i_obj; - uint32 i_entry; - bool i_alive; - float i_range; - - // prevent clone this object - NearestCreatureEntryWithLiveStateInObjectRangeCheck(NearestCreatureEntryWithLiveStateInObjectRangeCheck const&); - }; - - class AnyPlayerInObjectRangeCheck - { - public: - AnyPlayerInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {} - bool operator()(Player* u) - { - if (u->isAlive() && i_obj->IsWithinDistInMap(u, i_range)) - return true; - - return false; - } - private: - WorldObject const* i_obj; - float i_range; - }; - - class AllFriendlyCreaturesInGrid - { - public: - AllFriendlyCreaturesInGrid(Unit const* obj) : pUnit(obj) {} - bool operator() (Unit* u) - { - if (u->isAlive() && u->GetVisibility() == VISIBILITY_ON && u->IsFriendlyTo(pUnit)) - return true; - - return false; - } - private: - Unit const* pUnit; - }; - - class AllGameObjectsWithEntryInRange - { - public: - AllGameObjectsWithEntryInRange(const WorldObject* pObject, uint32 uiEntry, float fMaxRange) : m_pObject(pObject), m_uiEntry(uiEntry), m_fRange(fMaxRange) {} - bool operator() (GameObject* pGo) - { - if (pGo->GetEntry() == m_uiEntry && m_pObject->IsWithinDist(pGo,m_fRange,false)) - return true; - - return false; - } - private: - const WorldObject* m_pObject; - uint32 m_uiEntry; - float m_fRange; - }; - - class AllCreaturesOfEntryInRange - { - public: - AllCreaturesOfEntryInRange(const WorldObject* pObject, uint32 uiEntry, float fMaxRange) : m_pObject(pObject), m_uiEntry(uiEntry), m_fRange(fMaxRange) {} - bool operator() (Unit* pUnit) - { - if (pUnit->GetEntry() == m_uiEntry && m_pObject->IsWithinDist(pUnit,m_fRange,false)) - return true; - - return false; - } - - private: - const WorldObject* m_pObject; - uint32 m_uiEntry; - float m_fRange; - }; - - class PlayerAtMinimumRangeAway - { - public: - PlayerAtMinimumRangeAway(Unit const* unit, float fMinRange) : pUnit(unit), fRange(fMinRange) {} - bool operator() (Player* pPlayer) - { - //No threat list check, must be done explicit if expected to be in combat with creature - if (!pPlayer->isGameMaster() && pPlayer->isAlive() && !pUnit->IsWithinDist(pPlayer,fRange,false)) - return true; - - return false; - } - - private: - Unit const* pUnit; - float fRange; - }; - - class GameObjectInRangeCheck - { - public: - GameObjectInRangeCheck(float _x, float _y, float _z, float _range) : x(_x), y(_y), z(_z), range(_range) {} - bool operator() (GameObject* go) - { - return go->IsInRange(x, y, z, range); - } - private: - float x, y, z, range; - }; - - // Player checks and do - - // Prepare using Builder localized packets with caching and send to player - template - class LocalizedPacketDo - { - public: - explicit LocalizedPacketDo(Builder& builder) : i_builder(builder) {} - - ~LocalizedPacketDo() - { - for (size_t i = 0; i < i_data_cache.size(); ++i) - delete i_data_cache[i]; - } - void operator()(Player* p); - - private: - Builder& i_builder; - std::vector i_data_cache; // 0 = default, i => i-1 locale index - }; - - // Prepare using Builder localized packets with caching and send to player - template - class LocalizedPacketListDo - { - public: - typedef std::vector WorldPacketList; - explicit LocalizedPacketListDo(Builder& builder) : i_builder(builder) {} - - ~LocalizedPacketListDo() - { - for (size_t i = 0; i < i_data_cache.size(); ++i) - for (size_t j = 0; j < i_data_cache[i].size(); ++j) - delete i_data_cache[i][j]; - } - void operator()(Player* p); - - private: - Builder& i_builder; - std::vector i_data_cache; - // 0 = default, i => i-1 locale index - }; -} -#endif diff --git a/src/server/game/Map/Grid/GridNotifiersImpl.h b/src/server/game/Map/Grid/GridNotifiersImpl.h deleted file mode 100644 index 26a9c0bd328..00000000000 --- a/src/server/game/Map/Grid/GridNotifiersImpl.h +++ /dev/null @@ -1,453 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_GRIDNOTIFIERSIMPL_H -#define TRINITY_GRIDNOTIFIERSIMPL_H - -#include "GridNotifiers.h" -#include "WorldPacket.h" -#include "Corpse.h" -#include "Player.h" -#include "UpdateData.h" -#include "CreatureAI.h" -#include "SpellAuras.h" - - -template -inline void -Trinity::VisibleNotifier::Visit(GridRefManager &m) -{ - for (typename GridRefManager::iterator iter = m.begin(); iter != m.end(); ++iter) - { - vis_guids.erase(iter->getSource()->GetGUID()); - i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_visibleNow); - } -} - -inline void -Trinity::ObjectUpdater::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter) - if (iter->getSource()->IsInWorld() && !iter->getSource()->isSpiritService()) - iter->getSource()->Update(i_timeDiff); -} - -// SEARCHERS & LIST SEARCHERS & WORKERS - -// WorldObject searchers & workers - -template -void Trinity::WorldObjectSearcher::Visit(GameObjectMapType &m) -{ - // already found - if (i_object) - return; - - for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->getSource())) - { - i_object = itr->getSource(); - return; - } - } -} - -template -void Trinity::WorldObjectSearcher::Visit(PlayerMapType &m) -{ - // already found - if (i_object) - return; - - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->getSource())) - { - i_object = itr->getSource(); - return; - } - } -} - -template -void Trinity::WorldObjectSearcher::Visit(CreatureMapType &m) -{ - // already found - if (i_object) - return; - - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->getSource())) - { - i_object = itr->getSource(); - return; - } - } -} - -template -void Trinity::WorldObjectSearcher::Visit(CorpseMapType &m) -{ - // already found - if (i_object) - return; - - for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->getSource())) - { - i_object = itr->getSource(); - return; - } - } -} - -template -void Trinity::WorldObjectSearcher::Visit(DynamicObjectMapType &m) -{ - // already found - if (i_object) - return; - - for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->getSource())) - { - i_object = itr->getSource(); - return; - } - } -} - -template -void Trinity::WorldObjectListSearcher::Visit(PlayerMapType &m) -{ - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); -} - -template -void Trinity::WorldObjectListSearcher::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); -} - -template -void Trinity::WorldObjectListSearcher::Visit(CorpseMapType &m) -{ - for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); -} - -template -void Trinity::WorldObjectListSearcher::Visit(GameObjectMapType &m) -{ - for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); -} - -template -void Trinity::WorldObjectListSearcher::Visit(DynamicObjectMapType &m) -{ - for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); -} - -// Gameobject searchers - -template -void Trinity::GameObjectSearcher::Visit(GameObjectMapType &m) -{ - // already found - if (i_object) - return; - - for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->getSource())) - { - i_object = itr->getSource(); - return; - } - } -} - -template -void Trinity::GameObjectLastSearcher::Visit(GameObjectMapType &m) -{ - for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->getSource())) - i_object = itr->getSource(); - } -} - -template -void Trinity::GameObjectListSearcher::Visit(GameObjectMapType &m) -{ - for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); -} - -// Unit searchers - -template -void Trinity::UnitSearcher::Visit(CreatureMapType &m) -{ - // already found - if (i_object) - return; - - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->getSource())) - { - i_object = itr->getSource(); - return; - } - } -} - -template -void Trinity::UnitSearcher::Visit(PlayerMapType &m) -{ - // already found - if (i_object) - return; - - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->getSource())) - { - i_object = itr->getSource(); - return; - } - } -} - -template -void Trinity::UnitLastSearcher::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->getSource())) - i_object = itr->getSource(); - } -} - -template -void Trinity::UnitLastSearcher::Visit(PlayerMapType &m) -{ - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->getSource())) - i_object = itr->getSource(); - } -} - -template -void Trinity::UnitListSearcher::Visit(PlayerMapType &m) -{ - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); -} - -template -void Trinity::UnitListSearcher::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); -} - -// Creature searchers - -template -void Trinity::CreatureSearcher::Visit(CreatureMapType &m) -{ - // already found - if (i_object) - return; - - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->getSource())) - { - i_object = itr->getSource(); - return; - } - } -} - -template -void Trinity::CreatureLastSearcher::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->getSource())) - i_object = itr->getSource(); - } -} - -template -void Trinity::CreatureListSearcher::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); -} - -template -void Trinity::PlayerListSearcher::Visit(PlayerMapType &m) -{ - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_phaseMask)) - if (i_check(itr->getSource())) - i_objects.push_back(itr->getSource()); -} - -template -void Trinity::PlayerSearcher::Visit(PlayerMapType &m) -{ - // already found - if (i_object) - return; - - for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - if (!itr->getSource()->InSamePhase(i_phaseMask)) - continue; - - if (i_check(itr->getSource())) - { - i_object = itr->getSource(); - return; - } - } -} - -template -void Trinity::LocalizedPacketDo::operator()(Player* p) -{ - int32 loc_idx = p->GetSession()->GetSessionDbLocaleIndex(); - uint32 cache_idx = loc_idx+1; - WorldPacket* data; - - // create if not cached yet - if (i_data_cache.size() < cache_idx+1 || !i_data_cache[cache_idx]) - { - if (i_data_cache.size() < cache_idx+1) - i_data_cache.resize(cache_idx+1); - - data = new WorldPacket(SMSG_MESSAGECHAT, 200); - - i_builder(*data,loc_idx); - - i_data_cache[cache_idx] = data; - } - else - data = i_data_cache[cache_idx]; - - p->SendDirectMessage(data); -} - -template -void Trinity::LocalizedPacketListDo::operator()(Player* p) -{ - int32 loc_idx = p->GetSession()->GetSessionDbLocaleIndex(); - uint32 cache_idx = loc_idx+1; - WorldPacketList* data_list; - - // create if not cached yet - if (i_data_cache.size() < cache_idx+1 || i_data_cache[cache_idx].empty()) - { - if (i_data_cache.size() < cache_idx+1) - i_data_cache.resize(cache_idx+1); - - data_list = &i_data_cache[cache_idx]; - - i_builder(*data_list,loc_idx); - } - else - data_list = &i_data_cache[cache_idx]; - - for (size_t i = 0; i < data_list->size(); ++i) - p->SendDirectMessage((*data_list)[i]); -} - -#endif // TRINITY_GRIDNOTIFIERSIMPL_H diff --git a/src/server/game/Map/Grid/GridStates.cpp b/src/server/game/Map/Grid/GridStates.cpp deleted file mode 100644 index 9d39531cfad..00000000000 --- a/src/server/game/Map/Grid/GridStates.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "GridStates.h" -#include "GridNotifiers.h" -#include "GameSystem/Grid.h" -#include "Log.h" - -void -InvalidState::Update(Map &, NGridType &, GridInfo &, const uint32 &/*x*/, const uint32 &/*y*/, const uint32 &) const -{ -} - -void -ActiveState::Update(Map &m, NGridType &grid, GridInfo & info, const uint32 &x, const uint32 &y, const uint32 &t_diff) const -{ - // Only check grid activity every (grid_expiry/10) ms, because it's really useless to do it every cycle - info.UpdateTimeTracker(t_diff); - if (info.getTimeTracker().Passed()) - { - if (grid.ActiveObjectsInGrid() == 0 && !m.ActiveObjectsNearGrid(x, y)) - { - ObjectGridStoper stoper(grid); - stoper.StopN(); - grid.SetGridState(GRID_STATE_IDLE); - sLog.outDebug("Grid[%u,%u] on map %u moved to IDLE state", x, y, m.GetId()); - } - else - { - m.ResetGridExpiry(grid, 0.1f); - } - } -} - -void -IdleState::Update(Map &m, NGridType &grid, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &) const -{ - m.ResetGridExpiry(grid); - grid.SetGridState(GRID_STATE_REMOVAL); - sLog.outDebug("Grid[%u,%u] on map %u moved to REMOVAL state", x, y, m.GetId()); -} - -void -RemovalState::Update(Map &m, NGridType &grid, GridInfo &info, const uint32 &x, const uint32 &y, const uint32 &t_diff) const -{ - if (!info.getUnloadLock()) - { - info.UpdateTimeTracker(t_diff); - if (info.getTimeTracker().Passed()) - { - if (!m.UnloadGrid(x, y, false)) - { - sLog.outDebug("Grid[%u,%u] for map %u differed unloading due to players or active objects nearby", x, y, m.GetId()); - m.ResetGridExpiry(grid); - } - } - } -} - diff --git a/src/server/game/Map/Grid/GridStates.h b/src/server/game/Map/Grid/GridStates.h deleted file mode 100644 index c2a75ec45b7..00000000000 --- a/src/server/game/Map/Grid/GridStates.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_GRIDSTATES_H -#define TRINITY_GRIDSTATES_H - -#include "Map.h" -#include "Object.h" - -class GridState -{ - public: -#ifdef TRINITY_DEBUG -#define MAGIC_TESTVAL 0xFBE823BA - GridState() { i_Magic = MAGIC_TESTVAL; } - bool checkMagic() - { - if (i_Magic != MAGIC_TESTVAL) - { - sLog.outError("!!! GridState: Magic value gone !!!"); - return false; - } - return true; - } - void setMagic() { i_Magic = MAGIC_TESTVAL; } - unsigned int i_Magic; -#endif - virtual void Update(Map &, NGridType&, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const = 0; -}; - -class InvalidState : public GridState -{ - public: - - void Update(Map &, NGridType &, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const; -}; - -class ActiveState : public GridState -{ - public: - - void Update(Map &, NGridType &, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const; -}; - -class IdleState : public GridState -{ - public: - - void Update(Map &, NGridType &, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const; -}; - -class RemovalState : public GridState -{ - public: - - void Update(Map &, NGridType &, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const; -}; -#endif - diff --git a/src/server/game/Map/Grid/ObjectGridLoader.cpp b/src/server/game/Map/Grid/ObjectGridLoader.cpp deleted file mode 100644 index ab69d9a966b..00000000000 --- a/src/server/game/Map/Grid/ObjectGridLoader.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ObjectGridLoader.h" -#include "ObjectAccessor.h" -#include "ObjectMgr.h" -#include "Creature.h" -#include "Vehicle.h" -#include "GameObject.h" -#include "DynamicObject.h" -#include "Corpse.h" -#include "World.h" -#include "CellImpl.h" -#include "CreatureAI.h" - -class ObjectGridRespawnMover -{ - public: - ObjectGridRespawnMover() {} - - void Move(GridType &grid); - - template void Visit(GridRefManager &) {} - void Visit(CreatureMapType &m); -}; - -void -ObjectGridRespawnMover::Move(GridType &grid) -{ - TypeContainerVisitor mover(*this); - grid.Visit(mover); -} - -void -ObjectGridRespawnMover::Visit(CreatureMapType &m) -{ - // creature in unloading grid can have respawn point in another grid - // if it will be unloaded then it will not respawn in original grid until unload/load original grid - // move to respawn point to prevent this case. For player view in respawn grid this will be normal respawn. - for (CreatureMapType::iterator iter = m.begin(); iter != m.end();) - { - Creature * c = iter->getSource(); - ++iter; - - assert(!c->isPet() && "ObjectGridRespawnMover don't must be called for pets"); - - Cell const& cur_cell = c->GetCurrentCell(); - - float resp_x, resp_y, resp_z; - c->GetRespawnCoord(resp_x, resp_y, resp_z); - CellPair resp_val = Trinity::ComputeCellPair(resp_x, resp_y); - Cell resp_cell(resp_val); - - if (cur_cell.DiffGrid(resp_cell)) - { - c->GetMap()->CreatureRespawnRelocation(c); - // false result ignored: will be unload with other creatures at grid - } - } -} - -// for loading world object at grid loading (Corpses) -class ObjectWorldLoader -{ - public: - explicit ObjectWorldLoader(ObjectGridLoader& gloader) - : i_cell(gloader.i_cell), i_grid(gloader.i_grid), i_map(gloader.i_map), i_corpses (0) - {} - - void Visit(CorpseMapType &m); - - template void Visit(GridRefManager&) { } - - private: - Cell i_cell; - NGridType &i_grid; - Map* i_map; - public: - uint32 i_corpses; -}; - -template void addUnitState(T* /*obj*/, CellPair const& /*cell_pair*/) -{ -} - -template<> void addUnitState(Creature *obj, CellPair const& cell_pair) -{ - Cell cell(cell_pair); - - obj->SetCurrentCell(cell); - if (obj->isSpiritService()) - obj->setDeathState(DEAD); -} - -template -void AddObjectHelper(CellPair &cell, GridRefManager &m, uint32 &count, Map* map, T *obj) -{ - obj->GetGridRef().link(&m, obj); - addUnitState(obj,cell); - obj->AddToWorld(); - if (obj->isActiveObject()) - map->AddToActive(obj); - - ++count; -} - -template -void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager &m, uint32 &count, Map* map) -{ - for (CellGuidSet::const_iterator i_guid = guid_set.begin(); i_guid != guid_set.end(); ++i_guid) - { - T* obj = new T; - uint32 guid = *i_guid; - //sLog.outString("DEBUG: LoadHelper from table: %s for (guid: %u) Loading",table,guid); - if (!obj->LoadFromDB(guid, map)) - { - delete obj; - continue; - } - - AddObjectHelper(cell, m, count, map, obj); - } -} - -void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType &m, uint32 &count, Map* map) -{ - if (cell_corpses.empty()) - return; - - for (CellCorpseSet::const_iterator itr = cell_corpses.begin(); itr != cell_corpses.end(); ++itr) - { - if (itr->second != map->GetInstanceId()) - continue; - - uint32 player_guid = itr->first; - - Corpse *obj = ObjectAccessor::Instance().GetCorpseForPlayerGUID(player_guid); - if (!obj) - continue; - - // TODO: this is a hack - // corpse's map should be reset when the map is unloaded - // but it may still exist when the grid is unloaded but map is not - // in that case map == currMap - obj->SetMap(map); - - AddObjectHelper(cell, m, count, map, obj); - } -} - -void -ObjectGridLoader::Visit(GameObjectMapType &m) -{ - uint32 x = (i_cell.GridX()*MAX_NUMBER_OF_CELLS) + i_cell.CellX(); - uint32 y = (i_cell.GridY()*MAX_NUMBER_OF_CELLS) + i_cell.CellY(); - CellPair cell_pair(x,y); - uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; - - CellObjectGuids const& cell_guids = objmgr.GetCellObjectGuids(i_map->GetId(), i_map->GetSpawnMode(), cell_id); - - LoadHelper(cell_guids.gameobjects, cell_pair, m, i_gameObjects, i_map); -} - -void -ObjectGridLoader::Visit(CreatureMapType &m) -{ - uint32 x = (i_cell.GridX()*MAX_NUMBER_OF_CELLS) + i_cell.CellX(); - uint32 y = (i_cell.GridY()*MAX_NUMBER_OF_CELLS) + i_cell.CellY(); - CellPair cell_pair(x,y); - uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; - - CellObjectGuids const& cell_guids = objmgr.GetCellObjectGuids(i_map->GetId(), i_map->GetSpawnMode(), cell_id); - - LoadHelper(cell_guids.creatures, cell_pair, m, i_creatures, i_map); -} - -void -ObjectWorldLoader::Visit(CorpseMapType &m) -{ - uint32 x = (i_cell.GridX()*MAX_NUMBER_OF_CELLS) + i_cell.CellX(); - uint32 y = (i_cell.GridY()*MAX_NUMBER_OF_CELLS) + i_cell.CellY(); - CellPair cell_pair(x,y); - uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; - - // corpses are always added to spawn mode 0 and they are spawned by their instance id - CellObjectGuids const& cell_guids = objmgr.GetCellObjectGuids(i_map->GetId(), 0, cell_id); - LoadHelper(cell_guids.corpses, cell_pair, m, i_corpses, i_map); -} - -void -ObjectGridLoader::Load(GridType &grid) -{ - { - TypeContainerVisitor loader(*this); - grid.Visit(loader); - } - - { - ObjectWorldLoader wloader(*this); - TypeContainerVisitor loader(wloader); - grid.Visit(loader); - i_corpses = wloader.i_corpses; - } -} - -void ObjectGridLoader::LoadN(void) -{ - i_gameObjects = 0; i_creatures = 0; i_corpses = 0; - i_cell.data.Part.cell_y = 0; - for (unsigned int x=0; x < MAX_NUMBER_OF_CELLS; ++x) - { - i_cell.data.Part.cell_x = x; - for (unsigned int y=0; y < MAX_NUMBER_OF_CELLS; ++y) - { - i_cell.data.Part.cell_y = y; - GridLoader loader; - loader.Load(i_grid(x, y), *this); - } - } - sLog.outDebug("%u GameObjects, %u Creatures, and %u Corpses/Bones loaded for grid %u on map %u", i_gameObjects, i_creatures, i_corpses,i_grid.GetGridId(), i_map->GetId()); -} - -void ObjectGridUnloader::MoveToRespawnN() -{ - for (unsigned int x=0; x < MAX_NUMBER_OF_CELLS; ++x) - { - for (unsigned int y=0; y < MAX_NUMBER_OF_CELLS; ++y) - { - ObjectGridRespawnMover mover; - mover.Move(i_grid(x, y)); - } - } -} - -void -ObjectGridUnloader::Unload(GridType &grid) -{ - TypeContainerVisitor unloader(*this); - grid.Visit(unloader); -} - -template -void -ObjectGridUnloader::Visit(GridRefManager &m) -{ - while (!m.isEmpty()) - { - T *obj = m.getFirst()->getSource(); - // if option set then object already saved at this moment - if (!sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY)) - obj->SaveRespawnTime(); - ///- object will get delinked from the manager when deleted - delete obj; - } -} - -void -ObjectGridStoper::Stop(GridType &grid) -{ - TypeContainerVisitor stoper(*this); - grid.Visit(stoper); -} - -void -ObjectGridStoper::Visit(CreatureMapType &m) -{ - // stop any fights at grid de-activation and remove dynobjects created at cast by creatures - for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter) - { - iter->getSource()->RemoveAllDynObjects(); - if (iter->getSource()->isInCombat()) - { - iter->getSource()->CombatStop(); - iter->getSource()->DeleteThreatList(); - iter->getSource()->AI()->EnterEvadeMode(); - } - } -} - -void -ObjectGridCleaner::Stop(GridType &grid) -{ - TypeContainerVisitor stoper(*this); - grid.Visit(stoper); -} - -void -ObjectGridCleaner::Visit(CreatureMapType &m) -{ - for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter) - iter->getSource()->CleanupsBeforeDelete(); -} - -template -void -ObjectGridCleaner::Visit(GridRefManager &m) -{ - for (typename GridRefManager::iterator iter = m.begin(); iter != m.end(); ++iter) - iter->getSource()->RemoveFromWorld(); -} - -template void ObjectGridUnloader::Visit(CreatureMapType &); -template void ObjectGridUnloader::Visit(GameObjectMapType &); -template void ObjectGridUnloader::Visit(DynamicObjectMapType &); -template void ObjectGridUnloader::Visit(CorpseMapType &); -template void ObjectGridCleaner::Visit(GameObjectMapType &); -template void ObjectGridCleaner::Visit(DynamicObjectMapType &); -template void ObjectGridCleaner::Visit(CorpseMapType &); diff --git a/src/server/game/Map/Grid/ObjectGridLoader.h b/src/server/game/Map/Grid/ObjectGridLoader.h deleted file mode 100644 index e890bf8d482..00000000000 --- a/src/server/game/Map/Grid/ObjectGridLoader.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_OBJECTGRIDLOADER_H -#define TRINITY_OBJECTGRIDLOADER_H - -#include "Utilities/TypeList.h" -#include "Platform/Define.h" -#include "GameSystem/GridLoader.h" -#include "GridDefines.h" -#include "Cell.h" - -class ObjectWorldLoader; - -class ObjectGridLoader -{ - friend class ObjectWorldLoader; - - public: - ObjectGridLoader(NGridType &grid, Map* map, const Cell &cell) - : i_cell(cell), i_grid(grid), i_map(map), i_gameObjects(0), i_creatures(0), i_corpses (0) - {} - - void Load(GridType &grid); - void Visit(GameObjectMapType &m); - void Visit(CreatureMapType &m); - void Visit(CorpseMapType &) {} - - void Visit(DynamicObjectMapType&) { } - - void LoadN(void); - - private: - Cell i_cell; - NGridType &i_grid; - Map* i_map; - uint32 i_gameObjects; - uint32 i_creatures; - uint32 i_corpses; -}; - -class ObjectGridUnloader -{ - public: - ObjectGridUnloader(NGridType &grid) : i_grid(grid) {} - - void MoveToRespawnN(); - void UnloadN() - { - for (unsigned int x=0; x < MAX_NUMBER_OF_CELLS; ++x) - { - for (unsigned int y=0; y < MAX_NUMBER_OF_CELLS; ++y) - { - GridLoader loader; - loader.Unload(i_grid(x, y), *this); - } - } - } - - void Unload(GridType &grid); - template void Visit(GridRefManager &m); - private: - NGridType &i_grid; -}; - -class ObjectGridStoper -{ - public: - ObjectGridStoper(NGridType &grid) : i_grid(grid) {} - - void StopN() - { - for (unsigned int x=0; x < MAX_NUMBER_OF_CELLS; ++x) - { - for (unsigned int y=0; y < MAX_NUMBER_OF_CELLS; ++y) - { - GridLoader loader; - loader.Stop(i_grid(x, y), *this); - } - } - } - - void Stop(GridType &grid); - void Visit(CreatureMapType &m); - - template void Visit(GridRefManager &) {} - private: - NGridType &i_grid; -}; - -class ObjectGridCleaner -{ - public: - ObjectGridCleaner(NGridType &grid) : i_grid(grid) {} - - void CleanN() - { - for (unsigned int x=0; x < MAX_NUMBER_OF_CELLS; ++x) - { - for (unsigned int y=0; y < MAX_NUMBER_OF_CELLS; ++y) - { - GridLoader loader; - loader.Stop(i_grid(x, y), *this); - } - } - } - - void Stop(GridType &grid); - void Visit(CreatureMapType &m); - template void Visit(GridRefManager &); - private: - NGridType &i_grid; -}; - -typedef GridLoader GridLoaderType; -#endif - diff --git a/src/server/game/Map/Map.cpp b/src/server/game/Map/Map.cpp deleted file mode 100644 index 11bfdcd6f99..00000000000 --- a/src/server/game/Map/Map.cpp +++ /dev/null @@ -1,3936 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "MapManager.h" -#include "Player.h" -#include "Vehicle.h" -#include "GridNotifiers.h" -#include "Log.h" -#include "GridStates.h" -#include "CellImpl.h" -#include "InstanceData.h" -#include "Map.h" -#include "GridNotifiersImpl.h" -#include "Config/ConfigEnv.h" -#include "Transports.h" -#include "ObjectAccessor.h" -#include "ObjectMgr.h" -#include "World.h" -#include "Group.h" -#include "MapRefManager.h" -#include "Vehicle.h" -#include "WaypointManager.h" -#include "DBCEnums.h" -#include "ScriptMgr.h" -#include "ScriptedCreature.h" -#include "GossipDef.h" - -#include "MapInstanced.h" -#include "InstanceSaveMgr.h" -#include "VMapFactory.h" - -#define DEFAULT_GRID_EXPIRY 300 -#define MAX_GRID_LOAD_TIME 50 -#define MAX_CREATURE_ATTACK_RADIUS (45.0f * sWorld.getRate(RATE_CREATURE_AGGRO)) - -GridState* si_GridStates[MAX_GRID_STATE]; - -struct ScriptAction -{ - uint64 sourceGUID; - uint64 targetGUID; - uint64 ownerGUID; // owner of source if source is item - ScriptInfo const* script; // pointer to static script data -}; - -Map::~Map() -{ - UnloadAll(); - - while (!i_worldObjects.empty()) - { - WorldObject *obj = *i_worldObjects.begin(); - assert(obj->m_isWorldObject); - //assert(obj->GetTypeId() == TYPEID_CORPSE); - obj->RemoveFromWorld(); - obj->ResetMap(); - } - - if (!m_scriptSchedule.empty()) - sWorld.DecreaseScheduledScriptCount(m_scriptSchedule.size()); -} - -bool Map::ExistMap(uint32 mapid,int gx,int gy) -{ - int len = sWorld.GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1; - char* tmp = new char[len]; - snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),mapid,gx,gy); - - FILE *pf=fopen(tmp,"rb"); - - if (!pf) - { - sLog.outError("Map file '%s': does not exist!",tmp); - delete[] tmp; - return false; - } - - map_fileheader header; - fread(&header, sizeof(header), 1, pf); - if (header.mapMagic != uint32(MAP_MAGIC) || - header.versionMagic != uint32(MAP_VERSION_MAGIC)) - { - sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.",tmp); - delete [] tmp; - fclose(pf); //close file before return - return false; - } - - delete [] tmp; - fclose(pf); - return true; -} - -bool Map::ExistVMap(uint32 mapid,int gx,int gy) -{ - if (VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager()) - { - if (vmgr->isMapLoadingEnabled()) - { - // x and y are swapped !! => fixed now - bool exists = vmgr->existsMap((sWorld.GetDataPath()+ "vmaps").c_str(), mapid, gx,gy); - if (!exists) - { - std::string name = vmgr->getDirFileName(mapid,gx,gy); - sLog.outError("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()); - return false; - } - } - } - - return true; -} - -void Map::LoadVMap(int gx,int gy) -{ - // x and y are swapped !! - int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapManager()->loadMap((sWorld.GetDataPath()+ "vmaps").c_str(), GetId(), gx,gy); - switch(vmapLoadResult) - { - case VMAP::VMAP_LOAD_RESULT_OK: - sLog.outDetail("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: - sLog.outDetail("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: - DEBUG_LOG("Ignored VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx,gy,gx,gy); - break; - } -} - -void Map::LoadMap(int gx,int gy, bool reload) -{ - if (i_InstanceId != 0) - { - if (GridMaps[gx][gy]) - return; - - // load grid map for base map - if (!m_parentMap->GridMaps[gx][gy]) - m_parentMap->EnsureGridCreated(GridPair(63-gx,63-gy)); - - ((MapInstanced*)(m_parentMap))->AddGridMapReference(GridPair(gx,gy)); - GridMaps[gx][gy] = m_parentMap->GridMaps[gx][gy]; - return; - } - - if (GridMaps[gx][gy] && !reload) - return; - - //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]) - { - sLog.outDetail("Unloading previously loaded map %u before reloading.",GetId()); - delete (GridMaps[gx][gy]); - GridMaps[gx][gy]=NULL; - } - - // map file name - char *tmp=NULL; - 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); - sLog.outDetail("Loading map %s",tmp); - // loading data - GridMaps[gx][gy] = new GridMap(); - if (!GridMaps[gx][gy]->loadData(tmp)) - { - sLog.outError("Error loading map file: \n %s\n", tmp); - } - delete [] tmp; -} - -void Map::LoadMapAndVMap(int gx,int gy) -{ - LoadMap(gx,gy); - if (i_InstanceId == 0) - LoadVMap(gx, gy); // Only load the data for the base map -} - -void Map::InitStateMachine() -{ - si_GridStates[GRID_STATE_INVALID] = new InvalidState; - si_GridStates[GRID_STATE_ACTIVE] = new ActiveState; - si_GridStates[GRID_STATE_IDLE] = new IdleState; - si_GridStates[GRID_STATE_REMOVAL] = new RemovalState; -} - -void Map::DeleteStateMachine() -{ - delete si_GridStates[GRID_STATE_INVALID]; - delete si_GridStates[GRID_STATE_ACTIVE]; - delete si_GridStates[GRID_STATE_IDLE]; - delete si_GridStates[GRID_STATE_REMOVAL]; -} - -Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) - : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId), m_unloadTimer(0), - m_activeNonPlayersIter(m_activeNonPlayers.end()), - i_gridExpiry(expiry), m_parentMap(_parent ? _parent : this), - m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), - m_VisibilityNotifyPeriod(DEFAULT_VISIBILITY_NOTIFY_PERIOD), - i_scriptLock(false) -{ - for (unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx) - { - for (unsigned int j=0; j < MAX_NUMBER_OF_GRIDS; ++j) - { - //z code - GridMaps[idx][j] =NULL; - setNGrid(NULL, idx, j); - } - } - - //lets initialize visibility distance for map - Map::InitVisibilityDistance(); -} - -void Map::InitVisibilityDistance() -{ - //init visibility for continents - m_VisibleDistance = World::GetMaxVisibleDistanceOnContinents(); - m_VisibilityNotifyPeriod = World::GetVisibilityNotifyPeriodOnContinents(); -} - -// Template specialization of utility methods -template -void Map::AddToGrid(T* obj, NGridType *grid, Cell const& cell) -{ - if (obj->m_isWorldObject) - (*grid)(cell.CellX(), cell.CellY()).template AddWorldObject(obj); - else - (*grid)(cell.CellX(), cell.CellY()).template AddGridObject(obj); -} - -template<> -void Map::AddToGrid(Creature* obj, NGridType *grid, Cell const& cell) -{ - if (obj->m_isWorldObject) - (*grid)(cell.CellX(), cell.CellY()).AddWorldObject(obj); - else - (*grid)(cell.CellX(), cell.CellY()).AddGridObject(obj); - - obj->SetCurrentCell(cell); -} - -template -void Map::RemoveFromGrid(T* obj, NGridType *grid, Cell const& cell) -{ - if (obj->m_isWorldObject) - (*grid)(cell.CellX(), cell.CellY()).template RemoveWorldObject(obj); - else - (*grid)(cell.CellX(), cell.CellY()).template RemoveGridObject(obj); -} - -template -void Map::SwitchGridContainers(T* obj, bool on) -{ - CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); - if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - { - sLog.outError("Map::SwitchGridContainers: Object " I64FMT " has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUID(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord); - return; - } - - Cell cell(p); - if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) - return; - - DEBUG_LOG("Switch object " I64FMT " from grid[%u,%u] %u", obj->GetGUID(), cell.data.Part.grid_x, cell.data.Part.grid_y, on); - NGridType *ngrid = getNGrid(cell.GridX(), cell.GridY()); - assert(ngrid != NULL); - - GridType &grid = (*ngrid)(cell.CellX(), cell.CellY()); - - if (on) - { - grid.RemoveGridObject(obj); - grid.AddWorldObject(obj); - /*if (!grid.RemoveGridObject(obj, obj->GetGUID()) - || !grid.AddWorldObject(obj, obj->GetGUID())) - { - assert(false); - }*/ - } - else - { - grid.RemoveWorldObject(obj); - grid.AddGridObject(obj); - /*if (!grid.RemoveWorldObject(obj, obj->GetGUID()) - || !grid.AddGridObject(obj, obj->GetGUID())) - { - assert(false); - }*/ - } - obj->m_isWorldObject = on; -} - -template void Map::SwitchGridContainers(Creature *, bool); -//template void Map::SwitchGridContainers(DynamicObject *, bool); - -template -void Map::DeleteFromWorld(T* obj) -{ - // Note: In case resurrectable corpse and pet its removed from global lists in own destructor - delete obj; -} - -template<> -void Map::DeleteFromWorld(Player* pl) -{ - ObjectAccessor::Instance().RemoveObject(pl); - delete pl; -} - -void -Map::EnsureGridCreated(const GridPair &p) -{ - if (!getNGrid(p.x_coord, p.y_coord)) - { - Guard guard(*this); - if (!getNGrid(p.x_coord, p.y_coord)) - { - sLog.outDebug("Creating grid[%u,%u] for map %u instance %u", p.x_coord, p.y_coord, GetId(), i_InstanceId); - - setNGrid(new NGridType(p.x_coord*MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, sWorld.getConfig(CONFIG_GRID_UNLOAD)), - p.x_coord, p.y_coord); - - // build a linkage between this map and NGridType - buildNGridLinkage(getNGrid(p.x_coord, p.y_coord)); - - getNGrid(p.x_coord, p.y_coord)->SetGridState(GRID_STATE_IDLE); - - //z coord - int gx = (MAX_NUMBER_OF_GRIDS - 1) - p.x_coord; - int gy = (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord; - - if (!GridMaps[gx][gy]) - LoadMapAndVMap(gx,gy); - } - } -} - -void -Map::EnsureGridLoadedAtEnter(const Cell &cell, Player *player) -{ - EnsureGridLoaded(cell); - NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); - assert(grid != NULL); - - if (player) - { - DEBUG_LOG("Player %s enter cell[%u,%u] triggers loading of grid[%u,%u] on map %u", player->GetName(), cell.CellX(), cell.CellY(), cell.GridX(), cell.GridY(), GetId()); - } - else - { - DEBUG_LOG("Active object nearby triggers loading of grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), GetId()); - } - - // refresh grid state & timer - if (grid->GetGridState() != GRID_STATE_ACTIVE) - { - ResetGridExpiry(*grid, 0.1f); - grid->SetGridState(GRID_STATE_ACTIVE); - } -} - -bool Map::EnsureGridLoaded(const Cell &cell) -{ - EnsureGridCreated(GridPair(cell.GridX(), cell.GridY())); - NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); - - assert(grid != NULL); - if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY())) - { - sLog.outDebug("Loading grid[%u,%u] for map %u instance %u", cell.GridX(), cell.GridY(), GetId(), i_InstanceId); - - ObjectGridLoader loader(*grid, this, cell); - loader.LoadN(); - - // Add resurrectable corpses to world object list in grid - ObjectAccessor::Instance().AddCorpsesToGrid(GridPair(cell.GridX(),cell.GridY()),(*grid)(cell.CellX(), cell.CellY()), this); - - setGridObjectDataLoaded(true,cell.GridX(), cell.GridY()); - return true; - } - - return false; -} - -void Map::LoadGrid(float x, float y) -{ - CellPair pair = Trinity::ComputeCellPair(x, y); - Cell cell(pair); - EnsureGridLoaded(cell); -} - -bool Map::Add(Player *player) -{ - // Check if we are adding to correct map - assert (player->GetMap() == this); - CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); - if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - { - sLog.outError("Map::Add: Player (GUID: %u) has invalid coordinates X:%f Y:%f grid cell [%u:%u]", player->GetGUIDLow(), player->GetPositionX(), player->GetPositionY(), p.x_coord, p.y_coord); - return false; - } - - player->SetMap(this); - - Cell cell(p); - EnsureGridLoadedAtEnter(cell, player); - NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); - assert(grid != NULL); - AddToGrid(player, grid, cell); - - player->AddToWorld(); - - SendInitSelf(player); - SendInitTransports(player); - - player->m_clientGUIDs.clear(); - player->UpdateObjectVisibility(true); - - return true; -} - -template -void -Map::Add(T *obj) -{ - CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); - if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - { - sLog.outError("Map::Add: Object " UI64FMTD " has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUID(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord); - return; - } - - Cell cell(p); - if (obj->IsInWorld()) // need some clean up later - { - obj->UpdateObjectVisibility(true); - return; - } - - if (obj->isActiveObject()) - EnsureGridLoadedAtEnter(cell); - else - EnsureGridCreated(GridPair(cell.GridX(), cell.GridY())); - - NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); - assert(grid != NULL); - - AddToGrid(obj,grid,cell); - //obj->SetMap(this); - obj->AddToWorld(); - - if (obj->isActiveObject()) - AddToActive(obj); - - DEBUG_LOG("Object %u enters grid[%u,%u]", GUID_LOPART(obj->GetGUID()), cell.GridX(), cell.GridY()); - - //something, such as vehicle, needs to be update immediately - //also, trigger needs to cast spell, if not update, cannot see visual - obj->UpdateObjectVisibility(true); -} - -/* -void Map::MessageBroadcast(Player *player, WorldPacket *msg, bool to_self) -{ - CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); - - if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - { - sLog.outError("Map::MessageBroadcast: Player (GUID: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", player->GetGUIDLow(), player->GetPositionX(), player->GetPositionY(), p.x_coord, p.y_coord); - return; - } - - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) - return; - - Trinity::MessageDeliverer post_man(*player, msg, to_self); - TypeContainerVisitor message(post_man); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *this, *player, GetVisibilityDistance()); -} - -void Map::MessageBroadcast(WorldObject *obj, WorldPacket *msg) -{ - CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); - - if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - { - sLog.outError("Map::MessageBroadcast: Object (GUID: %u TypeId: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUIDLow(), obj->GetTypeId(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord); - return; - } - - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) - return; - - //TODO: currently on continents when Visibility.Distance.InFlight > Visibility.Distance.Continents - //we have alot of blinking mobs because monster move packet send is broken... - Trinity::ObjectMessageDeliverer post_man(*obj,msg); - TypeContainerVisitor message(post_man); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *this, *obj, GetVisibilityDistance()); -} - -void Map::MessageDistBroadcast(Player *player, WorldPacket *msg, float dist, bool to_self, bool own_team_only) -{ - CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); - - if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - { - sLog.outError("Map::MessageBroadcast: Player (GUID: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", player->GetGUIDLow(), player->GetPositionX(), player->GetPositionY(), p.x_coord, p.y_coord); - return; - } - - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) - return; - - Trinity::MessageDistDeliverer post_man(*player, msg, dist, to_self, own_team_only); - TypeContainerVisitor message(post_man); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *this, *player, dist); -} - -void Map::MessageDistBroadcast(WorldObject *obj, WorldPacket *msg, float dist) -{ - CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); - - if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - { - sLog.outError("Map::MessageBroadcast: Object (GUID: %u TypeId: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUIDLow(), obj->GetTypeId(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord); - return; - } - - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) - return; - - Trinity::ObjectMessageDistDeliverer post_man(*obj, msg, dist); - TypeContainerVisitor message(post_man); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *this, *obj, dist); -} -*/ - -bool Map::loaded(const GridPair &p) const -{ - return (getNGrid(p.x_coord, p.y_coord) && isGridObjectDataLoaded(p.x_coord, p.y_coord)); -} - -void Map::Update(const uint32 &t_diff) -{ - /// update players at tick - for (m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter) - { - Player* plr = m_mapRefIter->getSource(); - if (plr && plr->IsInWorld()) - plr->Update(t_diff); - } - - /// update active cells around players and active objects - resetMarkedCells(); - - Trinity::ObjectUpdater updater(t_diff); - // for creature - TypeContainerVisitor grid_object_update(updater); - // for pets - TypeContainerVisitor world_object_update(updater); - - // the player iterator is stored in the map object - // to make sure calls to Map::Remove don't invalidate it - for (m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter) - { - Player* plr = m_mapRefIter->getSource(); - - if (!plr->IsInWorld()) - continue; - - CellPair standing_cell(Trinity::ComputeCellPair(plr->GetPositionX(), plr->GetPositionY())); - - // Check for correctness of standing_cell, it also avoids problems with update_cell - if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - continue; - - // the overloaded operators handle range checking - // so ther's no need for range checking inside the loop - CellPair begin_cell(standing_cell), end_cell(standing_cell); - //lets update mobs/objects in ALL visible cells around player! - CellArea area = Cell::CalculateCellArea(*plr, GetVisibilityDistance()); - area.ResizeBorders(begin_cell, end_cell); - - for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x) - { - for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y) - { - // marked cells are those that have been visited - // don't visit the same cell twice - uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; - if (!isCellMarked(cell_id)) - { - markCell(cell_id); - CellPair pair(x,y); - Cell cell(pair); - cell.data.Part.reserved = CENTER_DISTRICT; - //cell.SetNoCreate(); - cell.Visit(pair, grid_object_update, *this); - cell.Visit(pair, world_object_update, *this); - } - } - } - } - - // non-player active objects - if (!m_activeNonPlayers.empty()) - { - for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end();) - { - // skip not in world - WorldObject* obj = *m_activeNonPlayersIter; - - // step before processing, in this case if Map::Remove remove next object we correctly - // step to next-next, and if we step to end() then newly added objects can wait next update. - ++m_activeNonPlayersIter; - - if (!obj->IsInWorld()) - continue; - - CellPair standing_cell(Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY())); - - // Check for correctness of standing_cell, it also avoids problems with update_cell - if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - continue; - - // the overloaded operators handle range checking - // so ther's no need for range checking inside the loop - CellPair begin_cell(standing_cell), end_cell(standing_cell); - begin_cell << 1; begin_cell -= 1; // upper left - end_cell >> 1; end_cell += 1; // lower right - - for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x) - { - for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y) - { - // marked cells are those that have been visited - // don't visit the same cell twice - uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; - if (!isCellMarked(cell_id)) - { - markCell(cell_id); - CellPair pair(x,y); - Cell cell(pair); - cell.data.Part.reserved = CENTER_DISTRICT; - //cell.SetNoCreate(); - cell.Visit(pair, grid_object_update, *this); - cell.Visit(pair, world_object_update, *this); - } - } - } - } - } - - ///- Process necessary scripts - if (!m_scriptSchedule.empty()) - { - i_scriptLock = true; - ScriptsProcess(); - i_scriptLock = false; - } - - MoveAllCreaturesInMoveList(); - - if (!m_mapRefManager.isEmpty() || !m_activeNonPlayers.empty()) - ProcessRelocationNotifies(t_diff); -} - -struct ResetNotifier -{ - templateinline void resetNotify(GridRefManager &m) - { - for (typename GridRefManager::iterator iter=m.begin(); iter != m.end(); ++iter) - iter->getSource()->ResetAllNotifies(); - } - template void Visit(GridRefManager &) {} - void Visit(CreatureMapType &m) { resetNotify(m);} - void Visit(PlayerMapType &m) { resetNotify(m);} -}; - -void Map::ProcessRelocationNotifies(const uint32 & diff) -{ - for (GridRefManager::iterator i = GridRefManager::begin(); i != GridRefManager::end(); ++i) - { - NGridType *grid = i->getSource(); - - if (grid->GetGridState() != GRID_STATE_ACTIVE) - continue; - - grid->getGridInfoRef()->getRelocationTimer().TUpdate(diff); - if (!grid->getGridInfoRef()->getRelocationTimer().TPassed()) - continue; - - uint32 gx = grid->getX(), gy = grid->getY(); - - CellPair cell_min(gx*MAX_NUMBER_OF_CELLS, gy*MAX_NUMBER_OF_CELLS); - CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS); - - for (uint32 x = cell_min.x_coord; x < cell_max.x_coord; ++x) - { - for (uint32 y = cell_min.y_coord; y < cell_max.y_coord; ++y) - { - uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; - if (!isCellMarked(cell_id)) - continue; - - CellPair pair(x,y); - Cell cell(pair); - cell.SetNoCreate(); - - Trinity::DelayedUnitRelocation cell_relocation(cell, pair, *this, GetVisibilityDistance()); - TypeContainerVisitor grid_object_relocation(cell_relocation); - TypeContainerVisitor world_object_relocation(cell_relocation); - Visit(cell, grid_object_relocation); - Visit(cell, world_object_relocation); - } - } - } - - ResetNotifier reset; - TypeContainerVisitor grid_notifier(reset); - TypeContainerVisitor world_notifier(reset); - for (GridRefManager::iterator i = GridRefManager::begin(); i != GridRefManager::end(); ++i) - { - NGridType *grid = i->getSource(); - - if (grid->GetGridState() != GRID_STATE_ACTIVE) - continue; - - if (!grid->getGridInfoRef()->getRelocationTimer().TPassed()) - continue; - - grid->getGridInfoRef()->getRelocationTimer().TReset(diff, m_VisibilityNotifyPeriod); - - uint32 gx = grid->getX(), gy = grid->getY(); - - CellPair cell_min(gx*MAX_NUMBER_OF_CELLS, gy*MAX_NUMBER_OF_CELLS); - CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS); - - for (uint32 x = cell_min.x_coord; x < cell_max.x_coord; ++x) - { - for (uint32 y = cell_min.y_coord; y < cell_max.y_coord; ++y) - { - uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; - if (!isCellMarked(cell_id)) - continue; - - CellPair pair(x,y); - Cell cell(pair); - cell.SetNoCreate(); - Visit(cell, grid_notifier); - Visit(cell, world_notifier); - } - } - } -} - -void Map::Remove(Player *player, bool remove) -{ - player->RemoveFromWorld(); - SendRemoveTransports(player); - - CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); - if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - sLog.outCrash("Map::Remove: Player is in invalid cell!"); - else - { - Cell cell(p); - if (!getNGrid(cell.data.Part.grid_x, cell.data.Part.grid_y)) - sLog.outError("Map::Remove() i_grids was NULL x:%d, y:%d",cell.data.Part.grid_x,cell.data.Part.grid_y); - else - { - DEBUG_LOG("Remove player %s from grid[%u,%u]", player->GetName(), cell.GridX(), cell.GridY()); - NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); - assert(grid != NULL); - - player->UpdateObjectVisibility(true); - RemoveFromGrid(player,grid,cell); - } - } - - if (remove) - DeleteFromWorld(player); -} - -bool Map::RemoveBones(uint64 guid, float x, float y) -{ - if (IsRemovalGrid(x, y)) - { - Corpse * corpse = ObjectAccessor::Instance().GetObjectInWorld(GetId(), x, y, guid, (Corpse*)NULL); - if (corpse && corpse->GetTypeId() == TYPEID_CORPSE && corpse->GetType() == CORPSE_BONES) - corpse->DeleteBonesFromWorld(); - else - return false; - } - return true; -} - -template -void -Map::Remove(T *obj, bool remove) -{ - obj->RemoveFromWorld(); - if (obj->isActiveObject()) - RemoveFromActive(obj); - - CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); - if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - sLog.outError("Map::Remove: Object " I64FMT " has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUID(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord); - else - { - Cell cell(p); - if (loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) - { - DEBUG_LOG("Remove object " I64FMT " from grid[%u,%u]", obj->GetGUID(), cell.data.Part.grid_x, cell.data.Part.grid_y); - NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); - assert(grid != NULL); - - obj->UpdateObjectVisibility(true); - RemoveFromGrid(obj,grid,cell); - } - } - - obj->ResetMap(); - - if (remove) - { - // if option set then object already saved at this moment - if (!sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY)) - obj->SaveRespawnTime(); - DeleteFromWorld(obj); - } -} - -void -Map::PlayerRelocation(Player *player, float x, float y, float z, float orientation) -{ - assert(player); - - CellPair old_val = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); - CellPair new_val = Trinity::ComputeCellPair(x, y); - - Cell old_cell(old_val); - Cell new_cell(new_val); - - player->Relocate(x, y, z, orientation); - - if (old_cell.DiffGrid(new_cell) || old_cell.DiffCell(new_cell)) - { - DEBUG_LOG("Player %s relocation grid[%u,%u]cell[%u,%u]->grid[%u,%u]cell[%u,%u]", player->GetName(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); - - NGridType* oldGrid = getNGrid(old_cell.GridX(), old_cell.GridY()); - RemoveFromGrid(player, oldGrid,old_cell); - - if (old_cell.DiffGrid(new_cell)) - EnsureGridLoadedAtEnter(new_cell, player); - - NGridType* newGrid = getNGrid(new_cell.GridX(), new_cell.GridY()); - AddToGrid(player, newGrid,new_cell); - } - - player->UpdateObjectVisibility(false); -} - -void -Map::CreatureRelocation(Creature *creature, float x, float y, float z, float ang) -{ - assert(CheckGridIntegrity(creature,false)); - - Cell old_cell = creature->GetCurrentCell(); - - CellPair new_val = Trinity::ComputeCellPair(x, y); - Cell new_cell(new_val); - - // delay creature move for grid/cell to grid/cell moves - if (old_cell.DiffCell(new_cell) || old_cell.DiffGrid(new_cell)) - { - #ifdef TRINITY_DEBUG - if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) - sLog.outDebug("Creature (GUID: %u Entry: %u) added to moving list from grid[%u,%u]cell[%u,%u] to grid[%u,%u]cell[%u,%u].", creature->GetGUIDLow(), creature->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); - #endif - AddCreatureToMoveList(creature, x, y, z, ang); - // in diffcell/diffgrid case notifiers called at finishing move creature in Map::MoveAllCreaturesInMoveList - } - else - { - creature->Relocate(x, y, z, ang); - creature->UpdateObjectVisibility(false); - } - - assert(CheckGridIntegrity(creature,true)); -} - -void Map::AddCreatureToMoveList(Creature *c, float x, float y, float z, float ang) -{ - if (!c) - return; - - i_creaturesToMove[c] = CreatureMover(x, y, z, ang); -} - -void Map::MoveAllCreaturesInMoveList() -{ - while (!i_creaturesToMove.empty()) - { - // get data and remove element; - CreatureMoveList::iterator iter = i_creaturesToMove.begin(); - Creature* c = iter->first; - CreatureMover cm = iter->second; - i_creaturesToMove.erase(iter); - - // calculate cells - CellPair new_val = Trinity::ComputeCellPair(cm.x, cm.y); - Cell new_cell(new_val); - - // do move or do move to respawn or remove creature if previous all fail - if (CreatureCellRelocation(c,new_cell)) - { - // update pos - c->Relocate(cm.x, cm.y, cm.z, cm.ang); - //CreatureRelocationNotify(c,new_cell,new_cell.cellPair()); - c->UpdateObjectVisibility(false); - } - else - { - // if creature can't be move in new cell/grid (not loaded) move it to repawn cell/grid - // creature coordinates will be updated and notifiers send - if (!CreatureRespawnRelocation(c)) - { - // ... or unload (if respawn grid also not loaded) - #ifdef TRINITY_DEBUG - if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) - sLog.outDebug("Creature (GUID: %u Entry: %u) cannot be move to unloaded respawn grid.",c->GetGUIDLow(),c->GetEntry()); - #endif - AddObjectToRemoveList(c); - } - } - } -} - -bool Map::CreatureCellRelocation(Creature *c, Cell new_cell) -{ - Cell const& old_cell = c->GetCurrentCell(); - if (!old_cell.DiffGrid(new_cell)) // in same grid - { - // if in same cell then none do - if (old_cell.DiffCell(new_cell)) - { - #ifdef TRINITY_DEBUG - if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) - sLog.outDebug("Creature (GUID: %u Entry: %u) moved in grid[%u,%u] from cell[%u,%u] to cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.CellX(), new_cell.CellY()); - #endif - - RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); - AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); - } - else - { - #ifdef TRINITY_DEBUG - if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) - sLog.outDebug("Creature (GUID: %u Entry: %u) moved in same grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY()); - #endif - } - - return true; - } - - // in diff. grids but active creature - if (c->isActiveObject()) - { - EnsureGridLoadedAtEnter(new_cell); - - #ifdef TRINITY_DEBUG - if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) - sLog.outDebug("Active creature (GUID: %u Entry: %u) moved from grid[%u,%u]cell[%u,%u] to grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); - #endif - - RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); - AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); - - return true; - } - - // in diff. loaded grid normal creature - if (loaded(GridPair(new_cell.GridX(), new_cell.GridY()))) - { - #ifdef TRINITY_DEBUG - if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) - sLog.outDebug("Creature (GUID: %u Entry: %u) moved from grid[%u,%u]cell[%u,%u] to grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); - #endif - - RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); - EnsureGridCreated(GridPair(new_cell.GridX(), new_cell.GridY())); - AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); - - return true; - } - - // fail to move: normal creature attempt move to unloaded grid - #ifdef TRINITY_DEBUG - if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) - sLog.outDebug("Creature (GUID: %u Entry: %u) attempted to move from grid[%u,%u]cell[%u,%u] to unloaded grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); - #endif - return false; -} - -bool Map::CreatureRespawnRelocation(Creature *c) -{ - float resp_x, resp_y, resp_z, resp_o; - c->GetRespawnCoord(resp_x, resp_y, resp_z, &resp_o); - - CellPair resp_val = Trinity::ComputeCellPair(resp_x, resp_y); - Cell resp_cell(resp_val); - - c->CombatStop(); - c->GetMotionMaster()->Clear(); - - #ifdef TRINITY_DEBUG - if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) - sLog.outDebug("Creature (GUID: %u Entry: %u) moved from grid[%u,%u]cell[%u,%u] to respawn grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), c->GetCurrentCell().GridX(), c->GetCurrentCell().GridY(), c->GetCurrentCell().CellX(), c->GetCurrentCell().CellY(), resp_cell.GridX(), resp_cell.GridY(), resp_cell.CellX(), resp_cell.CellY()); - #endif - - // teleport it to respawn point (like normal respawn if player see) - if (CreatureCellRelocation(c,resp_cell)) - { - c->Relocate(resp_x, resp_y, resp_z, resp_o); - c->GetMotionMaster()->Initialize(); // prevent possible problems with default move generators - //CreatureRelocationNotify(c,resp_cell,resp_cell.cellPair()); - c->UpdateObjectVisibility(false); - return true; - } - else - return false; -} - -bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool unloadAll) -{ - NGridType *grid = getNGrid(x, y); - assert(grid != NULL); - - { - if (!unloadAll && ActiveObjectsNearGrid(x, y)) - return false; - - sLog.outDebug("Unloading grid[%u,%u] for map %u", x,y, GetId()); - - ObjectGridUnloader unloader(*grid); - - if (!unloadAll) - { - // Finish creature moves, remove and delete all creatures with delayed remove before moving to respawn grids - // Must know real mob position before move - MoveAllCreaturesInMoveList(); - - // move creatures to respawn grids if this is diff.grid or to remove list - unloader.MoveToRespawnN(); - - // Finish creature moves, remove and delete all creatures with delayed remove before unload - MoveAllCreaturesInMoveList(); - } - - ObjectGridCleaner cleaner(*grid); - cleaner.CleanN(); - - RemoveAllObjectsInRemoveList(); - - unloader.UnloadN(); - - assert(i_objectsToRemove.empty()); - - delete grid; - setNGrid(NULL, x, y); - } - int gx = (MAX_NUMBER_OF_GRIDS - 1) - x; - int gy = (MAX_NUMBER_OF_GRIDS - 1) - y; - - // delete grid map, but don't delete if it is from parent map (and thus only reference) - //+++if (GridMaps[gx][gy]) don't check for GridMaps[gx][gy], we might have to unload vmaps - { - if (i_InstanceId == 0) - { - if (GridMaps[gx][gy]) - { - GridMaps[gx][gy]->unloadData(); - delete GridMaps[gx][gy]; - } - // x and y are swapped - VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId(), gx, gy); - } - else - ((MapInstanced*)m_parentMap)->RemoveGridMapReference(GridPair(gx, gy)); - - GridMaps[gx][gy] = NULL; - } - DEBUG_LOG("Unloading grid[%u,%u] for map %u finished", x,y, GetId()); - return true; -} - -void Map::RemoveAllPlayers() -{ - if (HavePlayers()) - { - for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) - { - Player* plr = itr->getSource(); - if (!plr->IsBeingTeleportedFar()) - { - // this is happening for bg - sLog.outError("Map::UnloadAll: player %s is still in map %u during unload, this should not happen!", plr->GetName(), GetId()); - plr->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation()); - } - } - } -} - -void Map::UnloadAll() -{ - // clear all delayed moves, useless anyway do this moves before map unload. - i_creaturesToMove.clear(); - - for (GridRefManager::iterator i = GridRefManager::begin(); i != GridRefManager::end();) - { - NGridType &grid(*i->getSource()); - ++i; - UnloadGrid(grid.getX(), grid.getY(), true); // deletes the grid and removes it from the GridRefManager - } -} - -//***************************** -// Grid function -//***************************** -GridMap::GridMap() -{ - m_flags = 0; - // Area data - m_gridArea = 0; - m_area_map = NULL; - // Height level data - m_gridHeight = INVALID_HEIGHT; - m_gridGetHeight = &GridMap::getHeightFromFlat; - m_V9 = NULL; - m_V8 = NULL; - // Liquid data - m_liquidType = 0; - m_liquid_offX = 0; - m_liquid_offY = 0; - m_liquid_width = 0; - m_liquid_height = 0; - m_liquidLevel = INVALID_HEIGHT; - m_liquid_type = NULL; - m_liquid_map = NULL; -} - -GridMap::~GridMap() -{ - unloadData(); -} - -bool GridMap::loadData(char *filename) -{ - // Unload old data if exist - unloadData(); - - map_fileheader header; - // Not return error if file not found - FILE *in = fopen(filename, "rb"); - if (!in) - return true; - fread(&header, sizeof(header),1,in); - if (header.mapMagic == uint32(MAP_MAGIC) && - header.versionMagic == uint32(MAP_VERSION_MAGIC)) - { - // loadup area data - if (header.areaMapOffset && !loadAreaData(in, header.areaMapOffset, header.areaMapSize)) - { - sLog.outError("Error loading map area data\n"); - fclose(in); - return false; - } - // loadup height data - if (header.heightMapOffset && !loadHeihgtData(in, header.heightMapOffset, header.heightMapSize)) - { - sLog.outError("Error loading map height data\n"); - fclose(in); - return false; - } - // loadup liquid data - if (header.liquidMapOffset && !loadLiquidData(in, header.liquidMapOffset, header.liquidMapSize)) - { - sLog.outError("Error loading map liquids data\n"); - fclose(in); - return false; - } - fclose(in); - return true; - } - sLog.outError("Map file '%s' is a non-compatible version (outdated?). Please, create new using the ad.exe program.", filename); - fclose(in); - return false; -} - -void GridMap::unloadData() -{ - if (m_area_map) delete[] m_area_map; - if (m_V9) delete[] m_V9; - if (m_V8) delete[] m_V8; - if (m_liquid_type) delete[] m_liquid_type; - if (m_liquid_map) delete[] m_liquid_map; - m_area_map = NULL; - m_V9 = NULL; - m_V8 = NULL; - m_liquid_type = NULL; - m_liquid_map = NULL; - m_gridGetHeight = &GridMap::getHeightFromFlat; -} - -bool GridMap::loadAreaData(FILE *in, uint32 offset, uint32 /*size*/) -{ - map_areaHeader header; - fseek(in, offset, SEEK_SET); - fread(&header, sizeof(header), 1, in); - if (header.fourcc != uint32(MAP_AREA_MAGIC)) - return false; - - m_gridArea = header.gridArea; - if (!(header.flags & MAP_AREA_NO_AREA)) - { - m_area_map = new uint16 [16*16]; - fread(m_area_map, sizeof(uint16), 16*16, in); - } - return true; -} - -bool GridMap::loadHeihgtData(FILE *in, uint32 offset, uint32 /*size*/) -{ - map_heightHeader header; - fseek(in, offset, SEEK_SET); - fread(&header, sizeof(header), 1, in); - if (header.fourcc != uint32(MAP_HEIGHT_MAGIC)) - return false; - - m_gridHeight = header.gridHeight; - if (!(header.flags & MAP_HEIGHT_NO_HEIGHT)) - { - if ((header.flags & MAP_HEIGHT_AS_INT16)) - { - m_uint16_V9 = new uint16 [129*129]; - m_uint16_V8 = new uint16 [128*128]; - fread(m_uint16_V9, sizeof(uint16), 129*129, in); - fread(m_uint16_V8, sizeof(uint16), 128*128, in); - m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 65535; - m_gridGetHeight = &GridMap::getHeightFromUint16; - } - else if ((header.flags & MAP_HEIGHT_AS_INT8)) - { - m_uint8_V9 = new uint8 [129*129]; - m_uint8_V8 = new uint8 [128*128]; - fread(m_uint8_V9, sizeof(uint8), 129*129, in); - fread(m_uint8_V8, sizeof(uint8), 128*128, in); - m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 255; - m_gridGetHeight = &GridMap::getHeightFromUint8; - } - else - { - m_V9 = new float [129*129]; - m_V8 = new float [128*128]; - fread(m_V9, sizeof(float), 129*129, in); - fread(m_V8, sizeof(float), 128*128, in); - m_gridGetHeight = &GridMap::getHeightFromFloat; - } - } - else - m_gridGetHeight = &GridMap::getHeightFromFlat; - return true; -} - -bool GridMap::loadLiquidData(FILE *in, uint32 offset, uint32 /*size*/) -{ - map_liquidHeader header; - fseek(in, offset, SEEK_SET); - fread(&header, sizeof(header), 1, in); - if (header.fourcc != uint32(MAP_LIQUID_MAGIC)) - return false; - - m_liquidType = header.liquidType; - m_liquid_offX = header.offsetX; - m_liquid_offY = header.offsetY; - m_liquid_width = header.width; - m_liquid_height= header.height; - m_liquidLevel = header.liquidLevel; - - if (!(header.flags & MAP_LIQUID_NO_TYPE)) - { - m_liquid_type = new uint8 [16*16]; - fread(m_liquid_type, sizeof(uint8), 16*16, in); - } - if (!(header.flags & MAP_LIQUID_NO_HEIGHT)) - { - m_liquid_map = new float [m_liquid_width*m_liquid_height]; - fread(m_liquid_map, sizeof(float), m_liquid_width*m_liquid_height, in); - } - return true; -} - -uint16 GridMap::getArea(float x, float y) -{ - if (!m_area_map) - return m_gridArea; - - x = 16 * (32 - x/SIZE_OF_GRIDS); - y = 16 * (32 - y/SIZE_OF_GRIDS); - int lx = (int)x & 15; - int ly = (int)y & 15; - return m_area_map[lx*16 + ly]; -} - -float GridMap::getHeightFromFlat(float /*x*/, float /*y*/) const -{ - return m_gridHeight; -} - -float GridMap::getHeightFromFloat(float x, float y) const -{ - if (!m_V8 || !m_V9) - return m_gridHeight; - - x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); - y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); - - int x_int = (int)x; - int y_int = (int)y; - x -= x_int; - y -= y_int; - x_int&=(MAP_RESOLUTION - 1); - y_int&=(MAP_RESOLUTION - 1); - - // Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid - // +--------------> X - // | h1-------h2 Coordinates is: - // | | \ 1 / | h1 0,0 - // | | \ / | h2 0,1 - // | | 2 h5 3 | h3 1,0 - // | | / \ | h4 1,1 - // | | / 4 \ | h5 1/2,1/2 - // | h3-------h4 - // V Y - // For find height need - // 1 - detect triangle - // 2 - solve linear equation from triangle points - // Calculate coefficients for solve h = a*x + b*y + c - - float a,b,c; - // Select triangle: - if (x+y < 1) - { - if (x > y) - { - // 1 triangle (h1, h2, h5 points) - float h1 = m_V9[(x_int)*129 + y_int]; - float h2 = m_V9[(x_int+1)*129 + y_int]; - float h5 = 2 * m_V8[x_int*128 + y_int]; - a = h2-h1; - b = h5-h1-h2; - c = h1; - } - else - { - // 2 triangle (h1, h3, h5 points) - float h1 = m_V9[x_int*129 + y_int ]; - float h3 = m_V9[x_int*129 + y_int+1]; - float h5 = 2 * m_V8[x_int*128 + y_int]; - a = h5 - h1 - h3; - b = h3 - h1; - c = h1; - } - } - else - { - if (x > y) - { - // 3 triangle (h2, h4, h5 points) - float h2 = m_V9[(x_int+1)*129 + y_int ]; - float h4 = m_V9[(x_int+1)*129 + y_int+1]; - float h5 = 2 * m_V8[x_int*128 + y_int]; - a = h2 + h4 - h5; - b = h4 - h2; - c = h5 - h4; - } - else - { - // 4 triangle (h3, h4, h5 points) - float h3 = m_V9[(x_int)*129 + y_int+1]; - float h4 = m_V9[(x_int+1)*129 + y_int+1]; - float h5 = 2 * m_V8[x_int*128 + y_int]; - a = h4 - h3; - b = h3 + h4 - h5; - c = h5 - h4; - } - } - // Calculate height - return a * x + b * y + c; -} - -float GridMap::getHeightFromUint8(float x, float y) const -{ - if (!m_uint8_V8 || !m_uint8_V9) - return m_gridHeight; - - x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); - y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); - - int x_int = (int)x; - int y_int = (int)y; - x -= x_int; - y -= y_int; - x_int&=(MAP_RESOLUTION - 1); - y_int&=(MAP_RESOLUTION - 1); - - int32 a, b, c; - uint8 *V9_h1_ptr = &m_uint8_V9[x_int*128 + x_int + y_int]; - if (x+y < 1) - { - if (x > y) - { - // 1 triangle (h1, h2, h5 points) - int32 h1 = V9_h1_ptr[ 0]; - int32 h2 = V9_h1_ptr[129]; - int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int]; - a = h2-h1; - b = h5-h1-h2; - c = h1; - } - else - { - // 2 triangle (h1, h3, h5 points) - int32 h1 = V9_h1_ptr[0]; - int32 h3 = V9_h1_ptr[1]; - int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int]; - a = h5 - h1 - h3; - b = h3 - h1; - c = h1; - } - } - else - { - if (x > y) - { - // 3 triangle (h2, h4, h5 points) - int32 h2 = V9_h1_ptr[129]; - int32 h4 = V9_h1_ptr[130]; - int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int]; - a = h2 + h4 - h5; - b = h4 - h2; - c = h5 - h4; - } - else - { - // 4 triangle (h3, h4, h5 points) - int32 h3 = V9_h1_ptr[ 1]; - int32 h4 = V9_h1_ptr[130]; - int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int]; - a = h4 - h3; - b = h3 + h4 - h5; - c = h5 - h4; - } - } - // Calculate height - return (float)((a * x) + (b * y) + c)*m_gridIntHeightMultiplier + m_gridHeight; -} - -float GridMap::getHeightFromUint16(float x, float y) const -{ - if (!m_uint16_V8 || !m_uint16_V9) - return m_gridHeight; - - x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); - y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); - - int x_int = (int)x; - int y_int = (int)y; - x -= x_int; - y -= y_int; - x_int&=(MAP_RESOLUTION - 1); - y_int&=(MAP_RESOLUTION - 1); - - int32 a, b, c; - uint16 *V9_h1_ptr = &m_uint16_V9[x_int*128 + x_int + y_int]; - if (x+y < 1) - { - if (x > y) - { - // 1 triangle (h1, h2, h5 points) - int32 h1 = V9_h1_ptr[ 0]; - int32 h2 = V9_h1_ptr[129]; - int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int]; - a = h2-h1; - b = h5-h1-h2; - c = h1; - } - else - { - // 2 triangle (h1, h3, h5 points) - int32 h1 = V9_h1_ptr[0]; - int32 h3 = V9_h1_ptr[1]; - int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int]; - a = h5 - h1 - h3; - b = h3 - h1; - c = h1; - } - } - else - { - if (x > y) - { - // 3 triangle (h2, h4, h5 points) - int32 h2 = V9_h1_ptr[129]; - int32 h4 = V9_h1_ptr[130]; - int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int]; - a = h2 + h4 - h5; - b = h4 - h2; - c = h5 - h4; - } - else - { - // 4 triangle (h3, h4, h5 points) - int32 h3 = V9_h1_ptr[ 1]; - int32 h4 = V9_h1_ptr[130]; - int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int]; - a = h4 - h3; - b = h3 + h4 - h5; - c = h5 - h4; - } - } - // Calculate height - return (float)((a * x) + (b * y) + c)*m_gridIntHeightMultiplier + m_gridHeight; -} - -float GridMap::getLiquidLevel(float x, float y) -{ - if (!m_liquid_map) - return m_liquidLevel; - - x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); - y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); - - int cx_int = ((int)x & (MAP_RESOLUTION-1)) - m_liquid_offY; - int cy_int = ((int)y & (MAP_RESOLUTION-1)) - m_liquid_offX; - - if (cx_int < 0 || cx_int >=m_liquid_height) - return INVALID_HEIGHT; - if (cy_int < 0 || cy_int >=m_liquid_width) - return INVALID_HEIGHT; - - return m_liquid_map[cx_int*m_liquid_width + cy_int]; -} - -uint8 GridMap::getTerrainType(float x, float y) -{ - if (!m_liquid_type) - return m_liquidType; - - x = 16 * (32 - x/SIZE_OF_GRIDS); - y = 16 * (32 - y/SIZE_OF_GRIDS); - int lx = (int)x & 15; - int ly = (int)y & 15; - return m_liquid_type[lx*16 + ly]; -} - -// Get water state on map -inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data) -{ - // Check water type (if no water return) - if (!m_liquid_type && !m_liquidType) - return LIQUID_MAP_NO_WATER; - - // Get cell - float cx = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); - float cy = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); - - int x_int = (int)cx & (MAP_RESOLUTION-1); - int y_int = (int)cy & (MAP_RESOLUTION-1); - - // Check water type in cell - uint8 type = m_liquid_type ? m_liquid_type[(x_int>>3)*16 + (y_int>>3)] : m_liquidType; - if (type == 0) - return LIQUID_MAP_NO_WATER; - - // Check req liquid type mask - if (ReqLiquidType && !(ReqLiquidType&type)) - return LIQUID_MAP_NO_WATER; - - // Check water level: - // Check water height map - int lx_int = x_int - m_liquid_offY; - int ly_int = y_int - m_liquid_offX; - if (lx_int < 0 || lx_int >=m_liquid_height) - return LIQUID_MAP_NO_WATER; - if (ly_int < 0 || ly_int >=m_liquid_width) - return LIQUID_MAP_NO_WATER; - - // Get water level - float liquid_level = m_liquid_map ? m_liquid_map[lx_int*m_liquid_width + ly_int] : m_liquidLevel; - // Get ground level (sub 0.2 for fix some errors) - float ground_level = getHeight(x, y); - - // Check water level and ground level - if (liquid_level < ground_level || z < ground_level - 2) - return LIQUID_MAP_NO_WATER; - - // All ok in water -> store data - if (data) - { - data->type = type; - data->level = liquid_level; - data->depth_level = ground_level; - } - - // For speed check as int values - int delta = int((liquid_level - z) * 10); - - // Get position delta - if (delta > 20) // Under water - return LIQUID_MAP_UNDER_WATER; - if (delta > 0) // In water - return LIQUID_MAP_IN_WATER; - if (delta > -1) // Walk on water - return LIQUID_MAP_WATER_WALK; - // Above water - return LIQUID_MAP_ABOVE_WATER; -} - -inline GridMap *Map::GetGrid(float x, float y) -{ - // half opt method - int gx=(int)(32-x/SIZE_OF_GRIDS); //grid x - int gy=(int)(32-y/SIZE_OF_GRIDS); //grid y - - // ensure GridMap is loaded - EnsureGridCreated(GridPair(63-gx,63-gy)); - - return GridMaps[gx][gy]; -} - -float Map::GetHeight(float x, float y, float z, bool pUseVmaps) const -{ - // find raw .map surface under Z coordinates - float mapHeight; - if (GridMap *gmap = const_cast(this)->GetGrid(x, y)) - { - float _mapheight = gmap->getHeight(x,y); - - // look from a bit higher pos to find the floor, ignore under surface case - if (z + 2.0f > _mapheight) - mapHeight = _mapheight; - else - mapHeight = VMAP_INVALID_HEIGHT_VALUE; - } - else - mapHeight = VMAP_INVALID_HEIGHT_VALUE; - - float vmapHeight; - if (pUseVmaps) - { - VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); - if (vmgr->isHeightCalcEnabled()) - { - // look from a bit higher pos to find the floor - vmapHeight = vmgr->getHeight(GetId(), x, y, z + 2.0f); - } - else - vmapHeight = VMAP_INVALID_HEIGHT_VALUE; - } - else - vmapHeight = VMAP_INVALID_HEIGHT_VALUE; - - // mapHeight set for any above raw ground Z or <= INVALID_HEIGHT - // vmapheight set for any under Z value or <= INVALID_HEIGHT - - if (vmapHeight > INVALID_HEIGHT) - { - if (mapHeight > INVALID_HEIGHT) - { - // we have mapheight and vmapheight and must select more appropriate - - // we are already under the surface or vmap height above map heigt - // or if the distance of the vmap height is less the land height distance - if (z < mapHeight || vmapHeight > mapHeight || fabs(mapHeight-z) > fabs(vmapHeight-z)) - return vmapHeight; - else - return mapHeight; // better use .map surface height - - } - else - return vmapHeight; // we have only vmapHeight (if have) - } - else - { - if (!pUseVmaps) - return mapHeight; // explicitly use map data (if have) - else if (mapHeight > INVALID_HEIGHT && (z < mapHeight + 2 || z == MAX_HEIGHT)) - return mapHeight; // explicitly use map data if original z < mapHeight but map found (z+2 > mapHeight) - else - return VMAP_INVALID_HEIGHT_VALUE; // we not have any height - } -} - -inline bool IsOutdoorWMO(uint32 mogpFlags, int32 adtId, int32 rootId, int32 groupId, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry) -{ - bool outdoor = true; - - if(wmoEntry && atEntry) - { - if(atEntry->flags & AREA_FLAG_OUTSIDE) - return true; - if(atEntry->flags & AREA_FLAG_INSIDE) - return false; - } - - outdoor = mogpFlags&0x8; - - if(wmoEntry) - { - if(wmoEntry->Flags & 4) - return true; - if((wmoEntry->Flags & 2)!=0) - outdoor = false; - } - return outdoor; -} - -bool Map::IsOutdoors(float x, float y, float z) const -{ - uint32 mogpFlags; - int32 adtId, rootId, groupId; - - // no wmo found? -> outside by default - if(!GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId)) - return true; - - AreaTableEntry const* atEntry = 0; - WMOAreaTableEntry const* wmoEntry= GetWMOAreaTableEntryByTripple(rootId, adtId, groupId); - if(wmoEntry) - { - DEBUG_LOG("Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId); - atEntry = GetAreaEntryByAreaID(wmoEntry->areaId); - } - return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry); -} - -bool Map::GetAreaInfo(float x, float y, float z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const -{ - float vmap_z = z; - VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); - if (vmgr->getAreaInfo(GetId(), x, y, vmap_z, flags, adtId, rootId, groupId)) - { - // check if there's terrain between player height and object height - if(GridMap *gmap = const_cast(this)->GetGrid(x, y)) - { - float _mapheight = gmap->getHeight(x,y); - // z + 2.0f condition taken from GetHeight(), not sure if it's such a great choice... - if(z + 2.0f > _mapheight && _mapheight > vmap_z) - return false; - } - return true; - } - return false; -} - -uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const -{ - uint32 mogpFlags; - int32 adtId, rootId, groupId; - WMOAreaTableEntry const* wmoEntry = 0; - AreaTableEntry const* atEntry = 0; - bool haveAreaInfo = false; - - if (GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId)) - { - haveAreaInfo = true; - if (wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId)) - atEntry = GetAreaEntryByAreaID(wmoEntry->areaId); - } - - uint16 areaflag; - - if (atEntry) - areaflag = atEntry->exploreFlag; - else - { - if (GridMap *gmap = const_cast(this)->GetGrid(x, y)) - areaflag = gmap->getArea(x, y); - // this used while not all *.map files generated (instances) - else - areaflag = GetAreaFlagByMapId(i_mapEntry->MapID); - } - - if (isOutdoors) - { - if (haveAreaInfo) - *isOutdoors = IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry); - else - *isOutdoors = true; - } - return areaflag; - } - -uint8 Map::GetTerrainType(float x, float y) const -{ - if (GridMap *gmap = const_cast(this)->GetGrid(x, y)) - return gmap->getTerrainType(x, y); - else - return 0; -} - -ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data) const -{ - ZLiquidStatus result = LIQUID_MAP_NO_WATER; - VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); - float liquid_level, ground_level = INVALID_HEIGHT; - uint32 liquid_type; - if (vmgr->GetLiquidLevel(GetId(), x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type)) - { - sLog.outDebug("getLiquidStatus(): vmap liquid level: %f ground: %f type: %u", liquid_level, ground_level, liquid_type); - // Check water level and ground level - if (liquid_level > ground_level && z > ground_level - 2) - { - // All ok in water -> store data - if (data) - { - data->type = liquid_type; - data->level = liquid_level; - data->depth_level = ground_level; - } - - // For speed check as int values - int delta = int((liquid_level - z) * 10); - - // Get position delta - if (delta > 20) // Under water - return LIQUID_MAP_UNDER_WATER; - if (delta > 0 ) // In water - return LIQUID_MAP_IN_WATER; - if (delta > -1) // Walk on water - return LIQUID_MAP_WATER_WALK; - result = LIQUID_MAP_ABOVE_WATER; - } - } - - if(GridMap* gmap = const_cast(this)->GetGrid(x, y)) - { - LiquidData map_data; - ZLiquidStatus map_result = gmap->getLiquidStatus(x, y, z, ReqLiquidType, &map_data); - // Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER: - if (map_result != LIQUID_MAP_NO_WATER && (map_data.level > ground_level)) - { - if (data) - *data = map_data; - return map_result; - } - } - return result; -} - -float Map::GetWaterLevel(float x, float y) const -{ - if (GridMap* gmap = const_cast(this)->GetGrid(x, y)) - return gmap->getLiquidLevel(x, y); - else - return 0; -} - -uint32 Map::GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id) -{ - AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); - - if (entry) - return entry->ID; - else - return 0; -} - -uint32 Map::GetZoneIdByAreaFlag(uint16 areaflag,uint32 map_id) -{ - AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); - - if (entry) - return (entry->zone != 0) ? entry->zone : entry->ID; - else - return 0; -} - -void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag,uint32 map_id) -{ - AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); - - areaid = entry ? entry->ID : 0; - zoneid = entry ? ((entry->zone != 0) ? entry->zone : entry->ID) : 0; -} - -bool Map::IsInWater(float x, float y, float pZ, LiquidData *data) const -{ - // Check surface in x, y point for liquid - if (const_cast(this)->GetGrid(x, y)) - { - LiquidData liquid_status; - LiquidData *liquid_ptr = data ? data : &liquid_status; - if (getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, liquid_ptr)) - return true; - } - return false; -} - -bool Map::IsUnderWater(float x, float y, float z) const -{ - if (const_cast(this)->GetGrid(x, y)) - { - if (getLiquidStatus(x, y, z, MAP_LIQUID_TYPE_WATER|MAP_LIQUID_TYPE_OCEAN)&LIQUID_MAP_UNDER_WATER) - return true; - } - return false; -} - -bool Map::CheckGridIntegrity(Creature* c, bool moved) const -{ - Cell const& cur_cell = c->GetCurrentCell(); - - CellPair xy_val = Trinity::ComputeCellPair(c->GetPositionX(), c->GetPositionY()); - Cell xy_cell(xy_val); - if (xy_cell != cur_cell) - { - sLog.outDebug("Creature (GUID: %u) X: %f Y: %f (%s) is in grid[%u,%u]cell[%u,%u] instead of grid[%u,%u]cell[%u,%u]", - c->GetGUIDLow(), - c->GetPositionX(),c->GetPositionY(),(moved ? "final" : "original"), - cur_cell.GridX(), cur_cell.GridY(), cur_cell.CellX(), cur_cell.CellY(), - xy_cell.GridX(), xy_cell.GridY(), xy_cell.CellX(), xy_cell.CellY()); - return true; // not crash at error, just output error in debug mode - } - - return true; -} - -const char* Map::GetMapName() const -{ - return i_mapEntry ? i_mapEntry->name[sWorld.GetDefaultDbcLocale()] : "UNNAMEDMAP\x0"; -} - -void Map::UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair) -{ - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - Trinity::VisibleChangesNotifier notifier(*obj); - TypeContainerVisitor player_notifier(notifier); - cell.Visit(cellpair, player_notifier, *this, *obj, GetVisibilityDistance()); -} - -void Map::UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpair) -{ - Trinity::VisibleNotifier notifier(*player); - - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - TypeContainerVisitor world_notifier(notifier); - TypeContainerVisitor grid_notifier(notifier); - cell.Visit(cellpair, world_notifier, *this, *player, GetVisibilityDistance()); - cell.Visit(cellpair, grid_notifier, *this, *player, GetVisibilityDistance()); - - // send data - notifier.SendToSelf(); -} -/* -void Map::PlayerRelocationNotify(Player* player, Cell cell, CellPair cellpair) -{ - Trinity::PlayerRelocationNotifier relocationNotifier(*player); - cell.data.Part.reserved = ALL_DISTRICT; - - TypeContainerVisitor p2grid_relocation(relocationNotifier); - TypeContainerVisitor p2world_relocation(relocationNotifier); - - cell.Visit(cellpair, p2grid_relocation, *this, *player, MAX_CREATURE_ATTACK_RADIUS); - cell.Visit(cellpair, p2world_relocation, *this, *player, MAX_CREATURE_ATTACK_RADIUS); -} - -void Map::CreatureRelocationNotify(Creature *creature, Cell cell, CellPair cellpair) -{ - Trinity::CreatureRelocationNotifier relocationNotifier(*creature); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); // not trigger load unloaded grids at notifier call - - TypeContainerVisitor c2world_relocation(relocationNotifier); - TypeContainerVisitor c2grid_relocation(relocationNotifier); - - cell.Visit(cellpair, c2world_relocation, *this, *creature, MAX_CREATURE_ATTACK_RADIUS); - cell.Visit(cellpair, c2grid_relocation, *this, *creature, MAX_CREATURE_ATTACK_RADIUS); -} -*/ - -void Map::SendInitSelf(Player * player) -{ - sLog.outDetail("Creating player data for himself %u", player->GetGUIDLow()); - - UpdateData data; - - // attach to player data current transport data - if (Transport* transport = player->GetTransport()) - { - transport->BuildCreateUpdateBlockForPlayer(&data, player); - } - - // build data for self presence in world at own client (one time for map) - player->BuildCreateUpdateBlockForPlayer(&data, player); - - // build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map - if (Transport* transport = player->GetTransport()) - { - for (Transport::PlayerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr) - { - if (player != (*itr) && player->HaveAtClient(*itr)) - { - (*itr)->BuildCreateUpdateBlockForPlayer(&data, player); - } - } - } - - WorldPacket packet; - data.BuildPacket(&packet); - player->GetSession()->SendPacket(&packet); -} - -void Map::SendInitTransports(Player * player) -{ - // Hack to send out transports - MapManager::TransportMap& tmap = MapManager::Instance().m_TransportsByMap; - - // no transports at map - if (tmap.find(player->GetMapId()) == tmap.end()) - return; - - UpdateData transData; - - MapManager::TransportSet& tset = tmap[player->GetMapId()]; - - for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i) - { - // send data for current transport in other place - if ((*i) != player->GetTransport() && (*i)->GetMapId() == GetId()) - { - (*i)->BuildCreateUpdateBlockForPlayer(&transData, player); - } - } - - WorldPacket packet; - transData.BuildPacket(&packet); - player->GetSession()->SendPacket(&packet); -} - -void Map::SendRemoveTransports(Player * player) -{ - // Hack to send out transports - MapManager::TransportMap& tmap = MapManager::Instance().m_TransportsByMap; - - // no transports at map - if (tmap.find(player->GetMapId()) == tmap.end()) - return; - - UpdateData transData; - - MapManager::TransportSet& tset = tmap[player->GetMapId()]; - - // except used transport - for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i) - if ((*i) != player->GetTransport() && (*i)->GetMapId() != GetId()) - (*i)->BuildOutOfRangeUpdateBlock(&transData); - - WorldPacket packet; - transData.BuildPacket(&packet); - player->GetSession()->SendPacket(&packet); -} - -inline void Map::setNGrid(NGridType *grid, uint32 x, uint32 y) -{ - if (x >= MAX_NUMBER_OF_GRIDS || y >= MAX_NUMBER_OF_GRIDS) - { - sLog.outError("map::setNGrid() Invalid grid coordinates found: %d, %d!",x,y); - assert(false); - } - i_grids[x][y] = grid; -} - -void Map::DelayedUpdate(const uint32 t_diff) -{ - RemoveAllObjectsInRemoveList(); - - // Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load ! - // This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended - if (!IsBattleGroundOrArena()) - { - for (GridRefManager::iterator i = GridRefManager::begin(); i != GridRefManager::end();) - { - NGridType *grid = i->getSource(); - GridInfo *info = i->getSource()->getGridInfoRef(); - ++i; // The update might delete the map and we need the next map before the iterator gets invalid - assert(grid->GetGridState() >= 0 && grid->GetGridState() < MAX_GRID_STATE); - si_GridStates[grid->GetGridState()]->Update(*this, *grid, *info, grid->getX(), grid->getY(), t_diff); - } - } -} - -void Map::AddObjectToRemoveList(WorldObject *obj) -{ - assert(obj->GetMapId() == GetId() && obj->GetInstanceId() == GetInstanceId()); - - obj->CleanupsBeforeDelete(false); // remove or simplify at least cross referenced links - - i_objectsToRemove.insert(obj); - //sLog.outDebug("Object (GUID: %u TypeId: %u) added to removing list.",obj->GetGUIDLow(),obj->GetTypeId()); -} - -void Map::AddObjectToSwitchList(WorldObject *obj, bool on) -{ - assert(obj->GetMapId() == GetId() && obj->GetInstanceId() == GetInstanceId()); - - std::map::iterator itr = i_objectsToSwitch.find(obj); - if (itr == i_objectsToSwitch.end()) - i_objectsToSwitch.insert(itr, std::make_pair(obj, on)); - else if (itr->second != on) - i_objectsToSwitch.erase(itr); - else - assert(false); -} - -void Map::RemoveAllObjectsInRemoveList() -{ - while (!i_objectsToSwitch.empty()) - { - std::map::iterator itr = i_objectsToSwitch.begin(); - WorldObject *obj = itr->first; - bool on = itr->second; - i_objectsToSwitch.erase(itr); - - switch(obj->GetTypeId()) - { - case TYPEID_UNIT: - if (!obj->ToCreature()->isPet()) - SwitchGridContainers(obj->ToCreature(), on); - break; - } - } - - //sLog.outDebug("Object remover 1 check."); - while (!i_objectsToRemove.empty()) - { - std::set::iterator itr = i_objectsToRemove.begin(); - WorldObject* obj = *itr; - - switch(obj->GetTypeId()) - { - case TYPEID_CORPSE: - { - Corpse* corpse = ObjectAccessor::Instance().GetCorpse(*obj, obj->GetGUID()); - if (!corpse) - sLog.outError("Tried to delete corpse/bones %u that is not in map.", obj->GetGUIDLow()); - else - Remove(corpse,true); - break; - } - case TYPEID_DYNAMICOBJECT: - Remove((DynamicObject*)obj,true); - break; - case TYPEID_GAMEOBJECT: - Remove((GameObject*)obj,true); - break; - case TYPEID_UNIT: - // in case triggered sequence some spell can continue casting after prev CleanupsBeforeDelete call - // make sure that like sources auras/etc removed before destructor start - obj->ToCreature()->CleanupsBeforeDelete(); - Remove(obj->ToCreature(),true); - break; - default: - sLog.outError("Non-grid object (TypeId: %u) is in grid object remove list, ignored.",obj->GetTypeId()); - break; - } - - i_objectsToRemove.erase(itr); - } - - //sLog.outDebug("Object remover 2 check."); -} - -uint32 Map::GetPlayersCountExceptGMs() const -{ - uint32 count = 0; - for (MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) - if (!itr->getSource()->isGameMaster()) - ++count; - return count; -} - -void Map::SendToPlayers(WorldPacket const* data) const -{ - for (MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) - itr->getSource()->GetSession()->SendPacket(data); -} - -bool Map::ActiveObjectsNearGrid(uint32 x, uint32 y) const -{ - ASSERT(x < MAX_NUMBER_OF_GRIDS); - ASSERT(y < MAX_NUMBER_OF_GRIDS); - - CellPair cell_min(x*MAX_NUMBER_OF_CELLS, y*MAX_NUMBER_OF_CELLS); - CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS); - - //we must find visible range in cells so we unload only non-visible cells... - float viewDist = GetVisibilityDistance(); - int cell_range = (int)ceilf(viewDist / SIZE_OF_GRID_CELL) + 1; - - cell_min << cell_range; - cell_min -= cell_range; - cell_max >> cell_range; - cell_max += cell_range; - - for (MapRefManager::const_iterator iter = m_mapRefManager.begin(); iter != m_mapRefManager.end(); ++iter) - { - Player* plr = iter->getSource(); - - CellPair p = Trinity::ComputeCellPair(plr->GetPositionX(), plr->GetPositionY()); - if ((cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) && - (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord)) - return true; - } - - for (ActiveNonPlayers::const_iterator iter = m_activeNonPlayers.begin(); iter != m_activeNonPlayers.end(); ++iter) - { - WorldObject* obj = *iter; - - CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); - if ((cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) && - (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord)) - return true; - } - - return false; -} - -void Map::AddToActive(Creature* c) -{ - AddToActiveHelper(c); - - // also not allow unloading spawn grid to prevent creating creature clone at load - if (!c->isPet() && c->GetDBTableGUIDLow()) - { - float x,y,z; - c->GetRespawnCoord(x,y,z); - GridPair p = Trinity::ComputeGridPair(x, y); - if (getNGrid(p.x_coord, p.y_coord)) - getNGrid(p.x_coord, p.y_coord)->incUnloadActiveLock(); - else - { - GridPair p2 = Trinity::ComputeGridPair(c->GetPositionX(), c->GetPositionY()); - sLog.outError("Active creature (GUID: %u Entry: %u) added to grid[%u,%u] but spawn grid[%u,%u] was not loaded.", - c->GetGUIDLow(), c->GetEntry(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord); - } - } -} - -void Map::RemoveFromActive(Creature* c) -{ - RemoveFromActiveHelper(c); - - // also allow unloading spawn grid - if (!c->isPet() && c->GetDBTableGUIDLow()) - { - float x,y,z; - c->GetRespawnCoord(x,y,z); - GridPair p = Trinity::ComputeGridPair(x, y); - if (getNGrid(p.x_coord, p.y_coord)) - getNGrid(p.x_coord, p.y_coord)->decUnloadActiveLock(); - else - { - GridPair p2 = Trinity::ComputeGridPair(c->GetPositionX(), c->GetPositionY()); - sLog.outError("Active creature (GUID: %u Entry: %u) removed from grid[%u,%u] but spawn grid[%u,%u] was not loaded.", - c->GetGUIDLow(), c->GetEntry(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord); - } - } -} - -template void Map::Add(Corpse *); -template void Map::Add(Creature *); -template void Map::Add(GameObject *); -template void Map::Add(DynamicObject *); - -template void Map::Remove(Corpse *,bool); -template void Map::Remove(Creature *,bool); -template void Map::Remove(GameObject *, bool); -template void Map::Remove(DynamicObject *, bool); - -/* ******* Dungeon Instance Maps ******* */ - -InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) - : Map(id, expiry, InstanceId, SpawnMode, _parent), - m_resetAfterUnload(false), m_unloadWhenEmpty(false), - i_data(NULL), i_script_id(0) -{ - //lets initialize visibility distance for dungeons - InstanceMap::InitVisibilityDistance(); - - // the timer is started by default, and stopped when the first player joins - // this make sure it gets unloaded if for some reason no player joins - m_unloadTimer = std::max(sWorld.getConfig(CONFIG_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY); -} - -InstanceMap::~InstanceMap() -{ - if (i_data) - { - delete i_data; - i_data = NULL; - } -} - -void InstanceMap::InitVisibilityDistance() -{ - //init visibility distance for instances - m_VisibleDistance = World::GetMaxVisibleDistanceInInstances(); - m_VisibilityNotifyPeriod = World::GetVisibilityNotifyPeriodInInstances(); -} - -/* - Do map specific checks to see if the player can enter -*/ -bool InstanceMap::CanEnter(Player *player) -{ - if (player->GetMapRef().getTarget() == this) - { - sLog.outError("InstanceMap::CanEnter - player %s(%u) already in map %d,%d,%d!", player->GetName(), player->GetGUIDLow(), GetId(), GetInstanceId(), GetSpawnMode()); - assert(false); - return false; - } - - // allow GM's to enter - if (player->isGameMaster()) - return Map::CanEnter(player); - - // cannot enter if the instance is full (player cap), GMs don't count - uint32 maxPlayers = GetMaxPlayers(); - if (GetPlayersCountExceptGMs() >= maxPlayers) - { - sLog.outDetail("MAP: Instance '%u' of map '%s' cannot have more than '%u' players. Player '%s' rejected", GetInstanceId(), GetMapName(), maxPlayers, player->GetName()); - player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAX_PLAYERS); - return false; - } - - // cannot enter while an encounter is in progress on raids - /*Group *pGroup = player->GetGroup(); - if (!player->isGameMaster() && pGroup && pGroup->InCombatToInstance(GetInstanceId()) && player->GetMapId() != GetId())*/ - if (IsRaid() && GetInstanceData() && GetInstanceData()->IsEncounterInProgress()) - { - player->SendTransferAborted(GetId(), TRANSFER_ABORT_ZONE_IN_COMBAT); - return false; - } - - return Map::CanEnter(player); -} - -/* - Do map specific checks and add the player to the map if successful. -*/ -bool InstanceMap::Add(Player *player) -{ - // TODO: Not sure about checking player level: already done in HandleAreaTriggerOpcode - // GMs still can teleport player in instance. - // Is it needed? - - { - Guard guard(*this); - // Check moved to void WorldSession::HandleMoveWorldportAckOpcode() - //if (!CanEnter(player)) - //return false; - - // Dungeon only code - if (IsDungeon()) - { - // get or create an instance save for the map - InstanceSave *mapSave = sInstanceSaveManager.GetInstanceSave(GetInstanceId()); - if (!mapSave) - { - sLog.outDetail("InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId()); - mapSave = sInstanceSaveManager.AddInstanceSave(GetId(), GetInstanceId(), Difficulty(GetSpawnMode()), 0, true); - } - - // check for existing instance binds - InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), Difficulty(GetSpawnMode())); - if (playerBind && playerBind->perm) - { - // cannot enter other instances if bound permanently - if (playerBind->save != mapSave) - { - sLog.outError("InstanceMap::Add: player %s(%d) is permanently bound to instance %d,%d,%d,%d,%d,%d but he is being put into instance %d,%d,%d,%d,%d,%d", player->GetName(), player->GetGUIDLow(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset()); - return false; - } - } - else - { - Group *pGroup = player->GetGroup(); - if (pGroup) - { - // solo saves should be reset when entering a group - InstanceGroupBind *groupBind = pGroup->GetBoundInstance(this); - if (playerBind) - { - sLog.outError("InstanceMap::Add: player %s(%d) is being put into instance %d,%d,%d,%d,%d,%d but he is in group %d and is bound to instance %d,%d,%d,%d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), GUID_LOPART(pGroup->GetLeaderGUID()), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset()); - if (groupBind) sLog.outError("InstanceMap::Add: the group is bound to the instance %d,%d,%d,%d,%d,%d", groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty(), groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset()); - //assert(false); - return false; - } - // bind to the group or keep using the group save - if (!groupBind) - pGroup->BindToInstance(mapSave, false); - else - { - // cannot jump to a different instance without resetting it - if (groupBind->save != mapSave) - { - sLog.outError("InstanceMap::Add: player %s(%d) is being put into instance %d,%d,%d but he is in group %d which is bound to instance %d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), GUID_LOPART(pGroup->GetLeaderGUID()), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty()); - if (mapSave) - sLog.outError("MapSave players: %d, group count: %d", mapSave->GetPlayerCount(), mapSave->GetGroupCount()); - else - sLog.outError("MapSave NULL"); - if (groupBind->save) - sLog.outError("GroupBind save players: %d, group count: %d", groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount()); - else - sLog.outError("GroupBind save NULL"); - return false; - } - // if the group/leader is permanently bound to the instance - // players also become permanently bound when they enter - if (groupBind->perm) - { - WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4); - data << uint32(0); - player->GetSession()->SendPacket(&data); - player->BindToInstance(mapSave, true); - } - } - } - else - { - // set up a solo bind or continue using it - if (!playerBind) - player->BindToInstance(mapSave, false); - else - // cannot jump to a different instance without resetting it - assert(playerBind->save == mapSave); - } - } - } - - // for normal instances cancel the reset schedule when the - // first player enters (no players yet) - SetResetSchedule(false); - - sLog.outDetail("MAP: Player '%s' entered instance '%u' of map '%s'", player->GetName(), GetInstanceId(), GetMapName()); - // initialize unload state - m_unloadTimer = 0; - m_resetAfterUnload = false; - m_unloadWhenEmpty = false; - } - - // this will acquire the same mutex so it cannot be in the previous block - Map::Add(player); - - if (i_data) - i_data->OnPlayerEnter(player); - - return true; -} - -void InstanceMap::Update(const uint32& t_diff) -{ - Map::Update(t_diff); - - if (i_data) - i_data->Update(t_diff); -} - -void InstanceMap::Remove(Player *player, bool remove) -{ - sLog.outDetail("MAP: Removing player '%s' from instance '%u' of map '%s' before relocating to another map", player->GetName(), 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.getConfig(CONFIG_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY); - Map::Remove(player, remove); - // for normal instances schedule the reset after all players have left - SetResetSchedule(true); -} - -void InstanceMap::CreateInstanceData(bool load) -{ - if (i_data != NULL) - return; - - InstanceTemplate const* mInstance = objmgr.GetInstanceTemplate(GetId()); - if (mInstance) - { - i_script_id = mInstance->script_id; - i_data = sScriptMgr.CreateInstanceData(this); - } - - if (!i_data) - return; - - i_data->Initialize(); - - if (load) - { - // TODO: make a global storage for this - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT data FROM instance WHERE map = '%u' AND id = '%u'", GetId(), i_InstanceId); - if (result) - { - Field* fields = result->Fetch(); - std::string data = fields[0].GetString(); - if (data != "") - { - sLog.outDebug("Loading instance data for `%s` with id %u", objmgr.GetScriptName(i_script_id), i_InstanceId); - i_data->Load(data.c_str()); - } - } - } -} - -/* - Returns true if there are no players in the instance -*/ -bool InstanceMap::Reset(uint8 method) -{ - // note: since the map may not be loaded when the instance needs to be reset - // the instance must be deleted from the DB by InstanceSaveManager - - if (HavePlayers()) - { - if (method == INSTANCE_RESET_ALL) - { - // notify the players to leave the instance so it can be reset - for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) - itr->getSource()->SendResetFailedNotify(GetId()); - } - else - { - if (method == INSTANCE_RESET_GLOBAL) - // set the homebind timer for players inside (1 minute) - for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) - itr->getSource()->m_InstanceValid = false; - - // the unload timer is not started - // instead the map will unload immediately after the players have left - m_unloadWhenEmpty = true; - m_resetAfterUnload = true; - } - } - else - { - // unloaded at next update - m_unloadTimer = MIN_UNLOAD_DELAY; - m_resetAfterUnload = true; - } - - return m_mapRefManager.isEmpty(); -} - -void InstanceMap::PermBindAllPlayers(Player *player) -{ - if (!IsDungeon()) - return; - - InstanceSave *save = sInstanceSaveManager.GetInstanceSave(GetInstanceId()); - if (!save) - { - sLog.outError("Cannot bind players, no instance save available for map!"); - return; - } - - Group *group = player->GetGroup(); - // group members outside the instance group don't get bound - for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) - { - Player* plr = itr->getSource(); - // players inside an instance cannot be bound to other instances - // some players may already be permanently bound, in this case nothing happens - InstancePlayerBind *bind = plr->GetBoundInstance(save->GetMapId(), save->GetDifficulty()); - if (!bind || !bind->perm) - { - plr->BindToInstance(save, true); - WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4); - data << uint32(0); - plr->GetSession()->SendPacket(&data); - } - - // if the leader is not in the instance the group will not get a perm bind - if (group && group->GetLeaderGUID() == plr->GetGUID()) - group->BindToInstance(save, true); - } -} - -void InstanceMap::UnloadAll() -{ - assert(!HavePlayers()); - - if (m_resetAfterUnload == true) - objmgr.DeleteRespawnTimeForInstance(GetInstanceId()); - - Map::UnloadAll(); -} - -void InstanceMap::SendResetWarnings(uint32 timeLeft) const -{ - for (MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) - itr->getSource()->SendInstanceResetWarning(GetId(), itr->getSource()->GetDifficulty(IsRaid()), timeLeft); -} - -void InstanceMap::SetResetSchedule(bool on) -{ - // only for normal instances - // the reset time is only scheduled when there are no payers inside - // it is assumed that the reset time will rarely (if ever) change while the reset is scheduled - if (IsDungeon() && !HavePlayers() && !IsRaidOrHeroicDungeon()) - { - InstanceSave *save = sInstanceSaveManager.GetInstanceSave(GetInstanceId()); - if (!save) sLog.outError("InstanceMap::SetResetSchedule: cannot turn schedule %s, no save available for instance %d of %d", on ? "on" : "off", GetInstanceId(), GetId()); - else sInstanceSaveManager.ScheduleReset(on, save->GetResetTime(), InstanceSaveManager::InstResetEvent(0, GetId(), Difficulty(GetSpawnMode()), GetInstanceId())); - } -} - -MapDifficulty const* Map::GetMapDifficulty() const -{ - return GetMapDifficultyData(GetId(),GetDifficulty()); -} - -uint32 InstanceMap::GetMaxPlayers() const -{ - if (MapDifficulty const* mapDiff = GetMapDifficulty()) - { - if (mapDiff->maxPlayers || IsRegularDifficulty()) // Normal case (expect that regular difficulty always have correct maxplayers) - return mapDiff->maxPlayers; - else // DBC have 0 maxplayers for heroic instances with expansion < 2 - { // The heroic entry exists, so we don't have to check anything, simply return normal max players - MapDifficulty const* normalDiff = GetMapDifficultyData(GetId(), REGULAR_DIFFICULTY); - return normalDiff ? normalDiff->maxPlayers : 0; - } - } - else // I'd rather assert(false); - return 0; -} - -uint32 InstanceMap::GetMaxResetDelay() const -{ - MapDifficulty const* mapDiff = GetMapDifficulty(); - return mapDiff ? mapDiff->resetTime : 0; -} - -/* ******* Battleground Instance Maps ******* */ - -BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent, uint8 spawnMode) - : Map(id, expiry, InstanceId, spawnMode, _parent) -{ - //lets initialize visibility distance for BG/Arenas - BattleGroundMap::InitVisibilityDistance(); -} - -BattleGroundMap::~BattleGroundMap() -{ -} - -void BattleGroundMap::InitVisibilityDistance() -{ - //init visibility distance for BG/Arenas - m_VisibleDistance = World::GetMaxVisibleDistanceInBGArenas(); - m_VisibilityNotifyPeriod = World::GetVisibilityNotifyPeriodInBGArenas(); -} - -bool BattleGroundMap::CanEnter(Player * player) -{ - if (player->GetMapRef().getTarget() == this) - { - sLog.outError("BGMap::CanEnter - player %u is already in map!", player->GetGUIDLow()); - assert(false); - return false; - } - - if (player->GetBattleGroundId() != GetInstanceId()) - return false; - - // player number limit is checked in bgmgr, no need to do it here - - return Map::CanEnter(player); -} - -bool BattleGroundMap::Add(Player * player) -{ - { - Guard guard(*this); - //Check moved to void WorldSession::HandleMoveWorldportAckOpcode() - //if (!CanEnter(player)) - //return false; - // reset instance validity, battleground maps do not homebind - player->m_InstanceValid = true; - } - return Map::Add(player); -} - -void BattleGroundMap::Remove(Player *player, bool remove) -{ - sLog.outDetail("MAP: Removing player '%s' from bg '%u' of map '%s' before relocating to another map", player->GetName(), GetInstanceId(), GetMapName()); - Map::Remove(player, remove); -} - -void BattleGroundMap::SetUnload() -{ - m_unloadTimer = MIN_UNLOAD_DELAY; -} - -void BattleGroundMap::RemoveAllPlayers() -{ - if (HavePlayers()) - for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) - if (Player* plr = itr->getSource()) - if (!plr->IsBeingTeleportedFar()) - plr->TeleportTo(plr->GetBattleGroundEntryPoint()); - -} - -/// Put scripts in the execution queue -void Map::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, Object* target) -{ - ///- Find the script map - ScriptMapMap::const_iterator s = scripts.find(id); - if (s == scripts.end()) - return; - - // prepare static data - uint64 sourceGUID = source ? source->GetGUID() : (uint64)0; //some script commands doesn't have source - uint64 targetGUID = target ? target->GetGUID() : (uint64)0; - uint64 ownerGUID = (source->GetTypeId() == TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0; - - ///- Schedule script execution for all scripts in the script map - ScriptMap const *s2 = &(s->second); - bool immedScript = false; - for (ScriptMap::const_iterator iter = s2->begin(); iter != s2->end(); ++iter) - { - ScriptAction sa; - sa.sourceGUID = sourceGUID; - sa.targetGUID = targetGUID; - sa.ownerGUID = ownerGUID; - - sa.script = &iter->second; - m_scriptSchedule.insert(std::pair(time_t(sWorld.GetGameTime() + iter->first), sa)); - if (iter->first == 0) - immedScript = true; - - sWorld.IncreaseScheduledScriptsCount(); - } - ///- If one of the effects should be immediate, launch the script execution - if (/*start &&*/ immedScript && !i_scriptLock) - { - i_scriptLock = true; - ScriptsProcess(); - i_scriptLock = false; - } -} - -void Map::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target) -{ - // NOTE: script record _must_ exist until command executed - - // prepare static data - uint64 sourceGUID = source ? source->GetGUID() : (uint64)0; - uint64 targetGUID = target ? target->GetGUID() : (uint64)0; - uint64 ownerGUID = (source->GetTypeId() == TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0; - - ScriptAction sa; - sa.sourceGUID = sourceGUID; - sa.targetGUID = targetGUID; - sa.ownerGUID = ownerGUID; - - sa.script = &script; - m_scriptSchedule.insert(std::pair(time_t(sWorld.GetGameTime() + delay), sa)); - - sWorld.IncreaseScheduledScriptsCount(); - - ///- If effects should be immediate, launch the script execution - if (delay == 0 && !i_scriptLock) - { - i_scriptLock = true; - ScriptsProcess(); - i_scriptLock = false; - } -} - -/// Process queued scripts -void Map::ScriptsProcess() -{ - if (m_scriptSchedule.empty()) - return; - - ///- Process overdue queued scripts - std::multimap::iterator iter = m_scriptSchedule.begin(); - // ok as multimap is a *sorted* associative container - while (!m_scriptSchedule.empty() && (iter->first <= sWorld.GetGameTime())) - { - ScriptAction const& step = iter->second; - - Object* source = NULL; - - if (step.sourceGUID) - { - switch (GUID_HIPART(step.sourceGUID)) - { - case HIGHGUID_ITEM: - // case HIGHGUID_CONTAINER: == HIGHGUID_ITEM - { - Player* player = HashMapHolder::Find(step.ownerGUID); - if (player) - source = player->GetItemByGuid(step.sourceGUID); - break; - } - case HIGHGUID_UNIT: - source = HashMapHolder::Find(step.sourceGUID); - break; - case HIGHGUID_PET: - source = HashMapHolder::Find(step.sourceGUID); - break; - //case HIGHGUID_VEHICLE: - // source = HashMapHolder::Find(step.sourceGUID); - // break; - case HIGHGUID_PLAYER: - source = HashMapHolder::Find(step.sourceGUID); - break; - case HIGHGUID_GAMEOBJECT: - source = HashMapHolder::Find(step.sourceGUID); - break; - case HIGHGUID_CORPSE: - source = HashMapHolder::Find(step.sourceGUID); - break; - case HIGHGUID_MO_TRANSPORT: - for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter) - { - if ((*iter)->GetGUID() == step.sourceGUID) - { - source = reinterpret_cast(*iter); - break; - } - } - break; - default: - sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.sourceGUID)); - break; - } - } - - //if (source && !source->IsInWorld()) source = NULL; - - Object* target = NULL; - - if (step.targetGUID) - { - switch (GUID_HIPART(step.targetGUID)) - { - case HIGHGUID_UNIT: - target = HashMapHolder::Find(step.targetGUID); - break; - case HIGHGUID_PET: - target = HashMapHolder::Find(step.targetGUID); - break; - //case HIGHGUID_VEHICLE: - // target = HashMapHolder::Find(step.targetGUID); - // break; - case HIGHGUID_PLAYER: // empty GUID case also - target = HashMapHolder::Find(step.targetGUID); - break; - case HIGHGUID_GAMEOBJECT: - target = HashMapHolder::Find(step.targetGUID); - break; - case HIGHGUID_CORPSE: - target = HashMapHolder::Find(step.targetGUID); - break; - default: - sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.targetGUID)); - break; - } - } - - //if (target && !target->IsInWorld()) target = NULL; - - switch (step.script->command) - { - case SCRIPT_COMMAND_TALK: - { - if (!source) - { - sLog.outError("SCRIPT_COMMAND_TALK (script id: %u) call for NULL source.", step.script->id); - break; - } - - Creature* cSource = NULL; - cSource = source->ToCreature() != NULL ? source->ToCreature() : target->ToCreature(); - - if (!cSource) - { - sLog.outError("SCRIPT_COMMAND_TALK (script id: %u) call for non supported source (TypeId: %u, Entry: %u, GUID: %u), skipping.", - step.script->id, source->GetTypeId(), source->GetEntry(), source->GetGUIDLow()); - break; - } - - if (step.script->datalong > CHAT_TYPE_WHISPER) - { - sLog.outError("SCRIPT_COMMAND_TALK (script id: %u) invalid chat type (%u), skipping.", step.script->id, step.script->datalong); - break; - } - - uint64 unit_target = target ? target->GetGUID() : 0; - - //datalong 0=normal say, 1=whisper, 2=yell, 3=emote text, 4=boss emote text - //TODO: Update for more chat types - switch (step.script->datalong) - { - case CHAT_TYPE_SAY: // Say - cSource->Say(step.script->dataint, LANG_UNIVERSAL, unit_target); - break; - case CHAT_TYPE_YELL: // Yell - cSource->Yell(step.script->dataint, LANG_UNIVERSAL, unit_target); - break; - case CHAT_TYPE_TEXT_EMOTE: // Emote text - cSource->TextEmote(step.script->dataint, unit_target); - break; - case CHAT_TYPE_BOSS_EMOTE: // Boss Emote text - cSource->MonsterTextEmote(step.script->dataint, unit_target, true); - break; - case CHAT_TYPE_WHISPER: // Whisper - if (!unit_target || !IS_PLAYER_GUID(unit_target)) - { - sLog.outError("SCRIPT_COMMAND_TALK (script id: %u) attempt to whisper (%u) NULL, skipping.", step.script->id, - step.script->datalong); - break; - } - cSource->Whisper(step.script->dataint,unit_target); - break; - default: - break; // must be already checked at load - } - break; - } - - case SCRIPT_COMMAND_EMOTE: - { - if (!source) - { - sLog.outError("SCRIPT_COMMAND_EMOTE (script id: %u) call for NULL source.", step.script->id); - break; - } - - Creature* cSource = NULL; - cSource = source->ToCreature() != NULL ? source->ToCreature() : target->ToCreature(); - - if (!cSource) - { - sLog.outError("SCRIPT_COMMAND_TALK (script id: %u) call for non supported source (TypeId: %u, Entry: %u, GUID: %u), skipping.", - step.script->id, source->GetTypeId(), source->GetEntry(), source->GetGUIDLow()); - break; - } - - if (step.script->datalong2) - cSource->SetUInt32Value(UNIT_NPC_EMOTESTATE, step.script->datalong); - else - cSource->HandleEmoteCommand(step.script->datalong); - break; - } - - case SCRIPT_COMMAND_FIELD_SET: - { - if (!source) - { - sLog.outError("SCRIPT_COMMAND_FIELD_SET (script id: %u) call for NULL source.", step.script->id); - break; - } - - Creature* cSource = source->ToCreature() != NULL ? source->ToCreature() : target->ToCreature(); - if (!cSource) - { - sLog.outError("SCRIPT_COMMAND_FIELD_SET (script id: %u) call for non-creature source.", step.script->id); - break; - } - - if (step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= cSource->GetValuesCount()) - { - sLog.outError("SCRIPT_COMMAND_FIELD_SET (script id: %u) call for wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u).", - step.script->id, step.script->datalong,source->GetValuesCount(),source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); - break; - } - - cSource->SetUInt32Value(step.script->datalong, step.script->datalong2); - break; - } - - case SCRIPT_COMMAND_MOVE_TO: - { - if (!source) - { - sLog.outError("SCRIPT_COMMAND_MOVE_TO (script id: %u) call for NULL creature.", step.script->id); - break; - } - - Creature* cSource = source->ToCreature() != NULL ? source->ToCreature() : target->ToCreature(); - if (!cSource) - { - sLog.outError("SCRIPT_COMMAND_MOVE_TO (script id: %u) call for non-creature (TypeId: %u, Entry: %u, GUID: %u), skipping.", - step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); - break; - } - - cSource->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, step.script->datalong2); - cSource->GetMap()->CreatureRelocation(cSource, step.script->x, step.script->y, step.script->z, 0); - break; - } - - case SCRIPT_COMMAND_FLAG_SET: - { - if (!source) - { - sLog.outError("SCRIPT_COMMAND_FLAG_SET (script id: %u) call for NULL object.", step.script->id); - break; - } - - Creature* cSource = source->ToCreature() != NULL ? source->ToCreature() : target->ToCreature(); - if (!cSource) - { - sLog.outError("SCRIPT_COMMAND_FLAG_SET (script id: %u) call for non-creature source.", step.script->id); - break; - } - - if (step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= cSource->GetValuesCount()) - { - sLog.outError("SCRIPT_COMMAND_FLAG_SET (script id: %u) call for wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u).", - step.script->id, step.script->datalong,source->GetValuesCount(),source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); - break; - } - - cSource->SetFlag(step.script->datalong, step.script->datalong2); - break; - } - - case SCRIPT_COMMAND_FLAG_REMOVE: - { - if (!source) - { - sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE (script id: %u) call for NULL object.", step.script->id); - break; - } - - Creature* cSource = source->ToCreature() != NULL ? source->ToCreature() : target->ToCreature(); - if (!cSource) - { - sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE (script id: %u) call for non-creature source.", step.script->id); - break; - } - - if (step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= cSource->GetValuesCount()) - { - sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE (script id: %u) call for wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u).", - step.script->id, step.script->datalong,source->GetValuesCount(),source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); - break; - } - - cSource->RemoveFlag(step.script->datalong, step.script->datalong2); - break; - } - - case SCRIPT_COMMAND_TELEPORT_TO: - { - // accept object in any one from target/source arg - if (!target && !source) - { - sLog.outError("SCRIPT_COMMAND_TELEPORT_TO (script id: %u) call for NULL object.", step.script->id); - break; - } - - if (step.script->datalong2 == 0) - { - Player* pSource = target->ToPlayer() != NULL ? target->ToPlayer() : source->ToPlayer(); - // must be only Player - if (!pSource) - { - sLog.outError("SCRIPT_COMMAND_TELEPORT_TO (script id: %u) call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", - step.script->id, source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0); - break; - } - - pSource->TeleportTo(step.script->datalong, step.script->x, step.script->y, step.script->z, step.script->o); - } - else if (step.script->datalong2 == 1) - { - Creature *cSource = target->ToCreature() != NULL ? target->ToCreature() : source->ToCreature(); - // must be only Creature - if (!cSource) - { - sLog.outError("SCRIPT_COMMAND_TELEPORT_TO (script id: %u) call for non-creature (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", - step.script->id, source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0); - break; - } - - cSource->NearTeleportTo(step.script->x, step.script->y, step.script->z, step.script->o); - } - break; - } - - case SCRIPT_COMMAND_KILL_CREDIT: - { - // accept player in any one from target/source arg - if (!target && !source) - { - sLog.outError("SCRIPT_COMMAND_KILL_CREDIT (script id: %u) call for NULL object.", step.script->id); - break; - } - - Player* pSource = target->ToPlayer() != NULL ? target->ToPlayer() : source->ToPlayer(); - // must be only Player - if (!pSource) - { - sLog.outError("SCRIPT_COMMAND_KILL_CREDIT (script id: %u) call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", - step.script->id, source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0); - break; - } - - if (step.script->datalong2) - pSource->RewardPlayerAndGroupAtEvent(step.script->datalong, pSource); - else - pSource->KilledMonsterCredit(step.script->datalong, 0); - - break; - } - - case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: - { - if (!step.script->datalong) // creature not specified - { - sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE (script id: %u) call with no creature parameter.", step.script->id); - break; - } - - if (!source) - { - sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE (script id: %u) call for NULL source object.", step.script->id); - break; - } - - WorldObject* summoner = dynamic_cast(source); - - if (!summoner) - { - sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE (script id: %u) call for non-WorldObject (TypeId: %u, Entry: %u, GUID: %u), skipping.", - step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); - break; - } - - float x = step.script->x; - float y = step.script->y; - float z = step.script->z; - float o = step.script->o; - - Creature* pCreature = summoner->SummonCreature(step.script->datalong, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,step.script->datalong2); - if (!pCreature) - { - sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON (script id: %u) failed for creature (entry: %u).", step.script->id, step.script->datalong); - break; - } - - break; - } - - case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: - { - if (!step.script->datalong) // gameobject not specified - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT (script id: %u) call with no gameobject parameter.", step.script->id); - break; - } - - if (!source) - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT (script id: %u) call for NULL source object.", step.script->id); - break; - } - - WorldObject* summoner = dynamic_cast(source); - - if (!summoner) - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT (script id: %u) call for non-WorldObject (TypeId: %u, Entry: %u, GUID: %u), skipping.", - step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); - break; - } - - GameObject *go = NULL; - int32 time_to_despawn = step.script->datalong2<5 ? 5 : (int32)step.script->datalong2; - - CellPair p(Trinity::ComputeCellPair(summoner->GetPositionX(), summoner->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - Trinity::GameObjectWithDbGUIDCheck go_check(*summoner,step.script->datalong); - Trinity::GameObjectSearcher checker(summoner, go,go_check); - - TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); - cell.Visit(p, object_checker, *summoner->GetMap()); - - if (!go) - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT (script id: %u) failed for gameobject(guid: %u).", step.script->id, step.script->datalong); - break; - } - - if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE || - go->GetGoType() == GAMEOBJECT_TYPE_DOOR || - go->GetGoType() == GAMEOBJECT_TYPE_BUTTON || - go->GetGoType() == GAMEOBJECT_TYPE_TRAP) - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT (script id: %u) can not be used with gameobject of type %u (guid: %u).", - step.script->id, uint32(go->GetGoType()), step.script->datalong); - break; - } - - if (go->isSpawned()) - break; //gameobject already spawned - - go->SetLootState(GO_READY); - go->SetRespawnTime(time_to_despawn); //despawn object in ? seconds - - go->GetMap()->Add(go); - break; - } - case SCRIPT_COMMAND_OPEN_DOOR: - { - if (!step.script->datalong) // door not specified - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR (script id: %u) call for NULL target door.", step.script->id); - break; - } - - if (!source) - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR (script id: %u) call for NULL source unit.", step.script->id); - break; - } - - if (!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player) - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR (script id: %u) call for non-unit (TypeId: %u, Entry: %u, GUID: %u), skipping.", - step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); - break; - } - - GameObject *door = NULL; - WorldObject* wSource = (WorldObject*)source; - - int32 time_to_close = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2; - - CellPair p(Trinity::ComputeCellPair(wSource->GetPositionX(), wSource->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - Trinity::GameObjectWithDbGUIDCheck go_check(*wSource, step.script->datalong); - Trinity::GameObjectSearcher checker(wSource, door, go_check); - - TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); - cell.Visit(p, object_checker, *wSource->GetMap()); - - if (!door) - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR (script id: %u) failed for gameobject(guid: %u).", step.script->id, step.script->datalong); - break; - } - if (door->GetGoType() != GAMEOBJECT_TYPE_DOOR) - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR (script id: %u) failed for non-door(GoType: %u, Entry: %u, GUID: %u).", - step.script->id, door->GetGoType(),door->GetEntry(),door->GetGUIDLow()); - break; - } - - if (door->GetGoState() != GO_STATE_READY) - break; //door already open - - door->UseDoorOrButton(time_to_close); - - if (target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType() == GAMEOBJECT_TYPE_BUTTON) - ((GameObject*)target)->UseDoorOrButton(time_to_close); - break; - } - case SCRIPT_COMMAND_CLOSE_DOOR: - { - if (!step.script->datalong) // guid for door not specified - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR (script id: %u) call for NULL door.", step.script->id); - break; - } - - if (!source) - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR (script id: %u) call for NULL unit.", step.script->id); - break; - } - - if (!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player) - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR (script id: %u) call for non-unit (TypeId: %u, Entry: %u, GUID: %u), skipping.", - step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); - break; - } - - GameObject *door = NULL; - WorldObject* wSource = (WorldObject*)source; - - int32 time_to_open = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2; - - CellPair p(Trinity::ComputeCellPair(wSource->GetPositionX(), wSource->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - Trinity::GameObjectWithDbGUIDCheck go_check(*wSource, step.script->datalong); - Trinity::GameObjectSearcher checker(wSource, door, go_check); - - TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); - cell.Visit(p, object_checker, *wSource->GetMap()); - - if (!door) - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR (script id: %u) failed for gameobject(guid: %u).", step.script->id, step.script->datalong); - break; - } - if (door->GetGoType() != GAMEOBJECT_TYPE_DOOR) - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR (script id: %u) failed for non-door(GoType: %u, Entry: %u, GUID: %u).", - step.script->id, door->GetGoType(),door->GetEntry(),door->GetGUIDLow()); - break; - } - - if (door->GetGoState() == GO_STATE_READY) - break; //door already closed - - door->UseDoorOrButton(time_to_open); - - if (target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType() == GAMEOBJECT_TYPE_BUTTON) - ((GameObject*)target)->UseDoorOrButton(time_to_open); - - break; - } - case SCRIPT_COMMAND_QUEST_EXPLORED: - { - if (!source) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED (script id %u) call for NULL source.", step.script->id); - break; - } - - if (!target) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED (script id %u) call for NULL target.", step.script->id); - break; - } - - // when script called for item spell casting then target == (unit or GO) and source is player - WorldObject* worldObject; - Player* pTarget; - - pTarget = target->ToPlayer(); - if (pTarget) - { - if (source->GetTypeId() != TYPEID_UNIT && source->GetTypeId() != TYPEID_GAMEOBJECT && source->GetTypeId() != TYPEID_PLAYER) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED (script id %u) call for non-creature, non-gameobject or non-player (TypeId: %u), skipping.", - step.script->id, source->GetTypeId()); - break; - } - - worldObject = (WorldObject*)source; - } - else - { - if (target->GetTypeId() != TYPEID_UNIT && target->GetTypeId() != TYPEID_GAMEOBJECT && target->GetTypeId() != TYPEID_PLAYER) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED (script id %u) call for non-creature, non-gameobject or non-player (TypeId: %u), skipping.", - step.script->id, target->GetTypeId()); - break; - } - - pTarget = source->ToPlayer(); - if (!pTarget) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED (script id %u) call for non-player (TypeId: %u), skipping.", step.script->id, source->GetTypeId()); - break; - } - - worldObject = (WorldObject*)target; - } - - // quest id and flags checked at script loading - if ((worldObject->GetTypeId() != TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) && - (step.script->datalong2 == 0 || worldObject->IsWithinDistInMap(pTarget, float(step.script->datalong2)))) - pTarget->AreaExploredOrEventHappens(step.script->datalong); - else - pTarget->FailQuest(step.script->datalong); - - break; - } - - case SCRIPT_COMMAND_ACTIVATE_OBJECT: - { - if (!source) - { - sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT (script id: %u) must have source caster.", step.script->id); - break; - } - - if (!source->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT (script id: %u) source caster isn't unit (TypeId: %u, Entry: %u, GUID: %u), skipping.", - step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); - break; - } - - if (!target) - { - sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT (script id: %u) call for NULL gameobject.", step.script->id); - break; - } - - if (target->GetTypeId() != TYPEID_GAMEOBJECT) - { - sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT (script id: %u) call for non-gameobject (TypeId: %u, Entry: %u, GUID: %u), skipping.", - step.script->id, target->GetTypeId(),target->GetEntry(),target->GetGUIDLow()); - break; - } - - Unit* caster = (Unit*)source; - - GameObject *go = (GameObject*)target; - - go->Use(caster); - break; - } - - case SCRIPT_COMMAND_REMOVE_AURA: - { - Object* cmdTarget = step.script->datalong2 ? source : target; - - if (!cmdTarget) - { - sLog.outError("SCRIPT_COMMAND_REMOVE_AURA (script id: %u) call for NULL %s.", step.script->id, step.script->datalong2 ? "source" : "target"); - break; - } - - if (!cmdTarget->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_REMOVE_AURA (script id: %u) %s isn't unit (TypeId: %u, Entry: %u, GUID: %u), skipping.", - step.script->id, step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId(),cmdTarget->GetEntry(),cmdTarget->GetGUIDLow()); - break; - } - - ((Unit*)cmdTarget)->RemoveAurasDueToSpell(step.script->datalong); - break; - } - - case SCRIPT_COMMAND_CAST_SPELL: - { - // TODO: Allow gameobjects to be targets and casters - if (!source) - { - sLog.outError("SCRIPT_COMMAND_CAST_SPELL (script id: %u) must have source caster.", step.script->id); - break; - } - - Unit* uSource = NULL; - Unit* uTarget = NULL; - // source/target cast spell at target/source (script->datalong2: 0: s->t 1: s->s 2: t->t 3: t->s - switch (step.script->datalong2) - { - case 0: // source -> target - uSource = dynamic_cast(source); - uTarget = dynamic_cast(target); - break; - case 1: // source -> source - uSource = dynamic_cast(source); - uTarget = dynamic_cast(source); - break; - case 2: // target -> target - uSource = dynamic_cast(target); - uTarget = dynamic_cast(target); - break; - case 3: // target -> source - uSource = dynamic_cast(target); - uTarget = dynamic_cast(source); - break; - case 4: // creature - uSource = dynamic_cast(source); - uTarget = GetClosestCreatureWithEntry(uSource, step.script->dataint, step.script->x); - break; - } - - if (!uSource || !uSource->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_CAST_SPELL (script id: %u) no source unit found for spell %u", step.script->id, step.script->datalong); - break; - } - - if (!uTarget || !uTarget->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_CAST_SPELL (script id: %u) no target unit found for spell %u", step.script->id, step.script->datalong); - break; - } - - uSource->CastSpell(uTarget, step.script->datalong, false); - break; - } - - case SCRIPT_COMMAND_PLAY_SOUND: - { - if (!source) - { - sLog.outError("SCRIPT_COMMAND_PLAY_SOUND (script id: %u) call for NULL creature.", step.script->id); - break; - } - - WorldObject* pSource = dynamic_cast(source); - if (!pSource) - { - sLog.outError("SCRIPT_COMMAND_PLAY_SOUND (script id: %u) call for non-world object (TypeId: %u, Entry: %u, GUID: %u), skipping.", - step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); - break; - } - - // bitmask: 0/1=anyone/target, 0/2=with distance dependent - Player* pTarget; - if (step.script->datalong2 & 1) - { - if (!target) - { - sLog.outError("SCRIPT_COMMAND_PLAY_SOUND (script id: %u) in targeted mode call for NULL target.", step.script->id); - break; - } - - pTarget = target->ToPlayer(); - if (!pTarget) - { - sLog.outError("SCRIPT_COMMAND_PLAY_SOUND (script id: %u) in targeted mode call for non-player (TypeId: %u, Entry: %u, GUID: %u), skipping.", - step.script->id, target->GetTypeId(),target->GetEntry(),target->GetGUIDLow()); - break; - } - } - - // bitmask: 0/1=anyone/target, 0/2=with distance dependent - if (step.script->datalong2 & 2) - pSource->PlayDistanceSound(step.script->datalong, pTarget); - else - pSource->PlayDirectSound(step.script->datalong, pTarget); - break; - } - - case SCRIPT_COMMAND_CREATE_ITEM: - { - if (!target && !source) - { - sLog.outError("SCRIPT_COMMAND_CREATE_ITEM (script id: %u) call for NULL object.", step.script->id); - break; - } - - Player *pReceiver = target->ToPlayer() != NULL ? target->ToPlayer() : source->ToPlayer(); - // only Player - if (!pReceiver) - { - sLog.outError("SCRIPT_COMMAND_CREATE_ITEM (script id: %u) call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", - step.script->id, source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0); - break; - } - - ItemPosCountVec dest; - uint8 msg = pReceiver->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, step.script->datalong, step.script->datalong2); - if (msg == EQUIP_ERR_OK) - { - if (Item* item = pReceiver->StoreNewItem(dest, step.script->datalong, true)) - pReceiver->SendNewItem(item, step.script->datalong2, false, true); - } - else - pReceiver->SendEquipError(msg,NULL,NULL); - - break; - } - - case SCRIPT_COMMAND_DESPAWN_SELF: - { - if (!target && !source) - { - sLog.outError("SCRIPT_COMMAND_DESPAWN_SELF (script id: %u) call for NULL object.", step.script->id); - break; - } - - Creature* cSource = target->ToCreature(); - // only creature - if (!cSource) - { - sLog.outError("SCRIPT_COMMAND_DESPAWN_SELF (script id: %u) call for non-creature (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", - step.script->id, source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0); - break; - } - - cSource->ForcedDespawn(step.script->datalong); - break; - } - - case SCRIPT_COMMAND_LOAD_PATH: - { - if (!source) - { - sLog.outError("SCRIPT_COMMAND_START_MOVE (script id: %u) cannot be applied to NON-existing unit.", step.script->id); - break; - } - - if (!source->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_START_MOVE (script id: %u) source mover isn't unit (TypeId: %u, Entry: %u, GUID: %u), skipping.", - step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); - break; - } - - if (!sWaypointMgr->GetPath(step.script->datalong)) - { - sLog.outError("SCRIPT_COMMAND_START_MOVE (script id: %u) source mover has an invalid path, skipping.", step.script->id, step.script->datalong2); - break; - } - - ((Unit*)source)->GetMotionMaster()->MovePath(step.script->datalong, step.script->datalong2); - break; - } - - case SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT: - { - if (!step.script->datalong || !step.script->datalong2) - { - sLog.outError("SCRIPT_COMMAND_CALLSCRIPT (script id: %u) calls invalid db_script_id or lowguid not present: skipping.", step.script->id); - break; - } - - Creature* cTarget; - if (source) //using grid searcher - { - WorldObject* wSource = (WorldObject*)source; - CellPair p(Trinity::ComputeCellPair(wSource->GetPositionX(), wSource->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - Trinity::CreatureWithDbGUIDCheck target_check(wSource, step.script->datalong); - Trinity::CreatureSearcher checker(wSource, cTarget, target_check); - - TypeContainerVisitor, GridTypeMapContainer > unit_checker(checker); - cell.Visit(p, unit_checker, *wSource->GetMap()); - } - else //check hashmap holders - { - if (CreatureData const* data = objmgr.GetCreatureData(step.script->datalong)) - cTarget = ObjectAccessor::GetObjectInWorld(data->mapid, data->posX, data->posY, MAKE_NEW_GUID(step.script->datalong, data->id, HIGHGUID_UNIT), cTarget); - } - - if (!cTarget) - { - sLog.outError("SCRIPT_COMMAND_CALLSCRIPT (script id: %u) target not found, creature entry %u", step.script->id, step.script->datalong); - break; - } - - //Lets choose our ScriptMap map - ScriptMapMap *datamap = NULL; - switch (step.script->dataint) - { - case 1: //QUEST END SCRIPTMAP - datamap = &sQuestEndScripts; - break; - case 2: //QUEST START SCRIPTMAP - datamap = &sQuestStartScripts; - break; - case 3: //SPELLS SCRIPTMAP - datamap = &sSpellScripts; - break; - case 4: //GAMEOBJECTS SCRIPTMAP - datamap = &sGameObjectScripts; - break; - case 5: //EVENTS SCRIPTMAP - datamap = &sEventScripts; - break; - case 6: //WAYPOINTS SCRIPTMAP - datamap = &sWaypointScripts; - break; - default: - sLog.outError("SCRIPT_COMMAND_CALLSCRIPT ERROR: no scriptmap present... ignoring"); - break; - } - //if no scriptmap present... - if (!datamap) - break; - - uint32 script_id = step.script->datalong2; - //insert script into schedule but do not start it - ScriptsStart(*datamap, script_id, cTarget, NULL/*, false*/); - break; - } - - case SCRIPT_COMMAND_KILL: - { - // TODO: Allow to kill objects other than self? - if (!source) - break; - - Creature* cSource = source->ToCreature(); - if (!cSource) - break; - - if (cSource->isDead()) - { - sLog.outError("SCRIPT_COMMAND_KILL (script id: %u) called for already dead creature, entry %u, guidLow %u", - step.script->id, cSource->GetEntry(), cSource->GetGUIDLow()); - break; - } - - cSource->setDeathState(JUST_DIED); - if (step.script->dataint == 1) - cSource->RemoveCorpse(); - - break; - } - - case SCRIPT_COMMAND_ORIENTATION: - { - if (!source || !source->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_ORIENTATION (script id: %u) call for NULL or non-unit source.", step.script->id); - break; - } - - Unit* uSource = (Unit*)source; - - if (!step.script->datalong) - uSource->SetOrientation(step.script->o); - else - { - if (!target || !target->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_ORIENTATION (script id: %u) call for NULL or non-unit target.", step.script->id); - break; - } - uSource->SetInFront((Unit*)target); - } - - uSource->SendMovementFlagUpdate(); - break; - } - case SCRIPT_COMMAND_EQUIP: - { - if (!source) - { - sLog.outError("SCRIPT_COMMAND_EQUIP (script id: %u) call for NULL source.", step.script->id); - break; - } - - Creature* cSource = source->ToCreature(); - if (!cSource) - { - sLog.outError("SCRIPT_COMMAND_EQUIP (script id: %u) call, source is non-creature.", step.script->id); - break; - } - - cSource->LoadEquipment(step.script->datalong); - break; - } - case SCRIPT_COMMAND_MODEL: - { - if (!source) - { - sLog.outError("SCRIPT_COMMAND_EQUIP (script id: %u) call for NULL source.", step.script->id); - break; - } - - Creature* cSource = source->ToCreature(); - if (!cSource) - { - sLog.outError("SCRIPT_COMMAND_EQUIP (script id: %u) call, source is non-creature.", step.script->id); - break; - } - - cSource->SetDisplayId(step.script->datalong); - break; - } - - case SCRIPT_COMMAND_CLOSE_GOSSIP: - { - if (!source) - { - sLog.outError("SCRIPT_COMMAND_CLOSE_GOSSIP (script id: %u) for null source", step.script->id); - break; - } - - Player *pSource = source->ToPlayer(); - if (!pSource) - { - sLog.outError("SCRIPT_COMMAND_CLOSE_GOSSIP (script id: %u) for non-player source.", step.script->id); - break; - } - - pSource->PlayerTalkClass->CloseGossip(); - break; - } - - case SCRIPT_COMMAND_PLAYMOVIE: - { - if (!source) - { - sLog.outError("SCRIPT_COMMAND_PLAYMOVIE (script id: %u) call for NULL source.", step.script->id); - break; - } - - Player* pSource = source->ToPlayer(); - if (!pSource) - { - sLog.outError("SCRIPT_COMMAND_PLAYMOVIE (script id: %u) call for non-player source.", step.script->id); - break; - } - pSource->SendMovieStart(step.script->datalong); - break; - } - - default: - sLog.outError("Unknown script command %u called.", step.script->command); - break; - } - - m_scriptSchedule.erase(iter); - sWorld.DecreaseScheduledScriptCount(); - - iter = m_scriptSchedule.begin(); - } -} - -Creature* -Map::GetCreature(uint64 guid) -{ - Creature * ret = NULL; - if (IS_CRE_OR_VEH_GUID(guid)) - ret = ObjectAccessor::GetObjectInWorld(guid, (Creature*)NULL); - - if (!ret) - return NULL; - - if (ret->GetMapId() != GetId()) - return NULL; - - if (ret->GetInstanceId() != GetInstanceId()) - return NULL; - - return ret; -} - -GameObject* -Map::GetGameObject(uint64 guid) -{ - GameObject * ret = ObjectAccessor::GetObjectInWorld(guid, (GameObject*)NULL); - if (!ret) - return NULL; - if (ret->GetMapId() != GetId()) - return NULL; - if (ret->GetInstanceId() != GetInstanceId()) - return NULL; - return ret; -} - -DynamicObject* -Map::GetDynamicObject(uint64 guid) -{ - DynamicObject * ret = ObjectAccessor::GetObjectInWorld(guid, (DynamicObject*)NULL); - if (!ret) - return NULL; - if (ret->GetMapId() != GetId()) - return NULL; - if (ret->GetInstanceId() != GetInstanceId()) - return NULL; - return ret; -} - -void Map::UpdateIteratorBack(Player *player) -{ - if (m_mapRefIter == player->GetMapRef()) - m_mapRefIter = m_mapRefIter->nocheck_prev(); -} diff --git a/src/server/game/Map/Map.h b/src/server/game/Map/Map.h deleted file mode 100644 index ceb526b8244..00000000000 --- a/src/server/game/Map/Map.h +++ /dev/null @@ -1,689 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_MAP_H -#define TRINITY_MAP_H - -#include "Platform/Define.h" -#include "Policies/ThreadingModel.h" -#include "ace/RW_Thread_Mutex.h" -#include "ace/Thread_Mutex.h" - -#include "DBCStructure.h" -#include "GridDefines.h" -#include "Cell.h" -#include "Timer.h" -#include "SharedDefines.h" -#include "GameSystem/GridRefManager.h" -#include "MapRefManager.h" -#include "mersennetwister/MersenneTwister.h" - -#include -#include - -class Unit; -class WorldPacket; -class InstanceData; -class Group; -class InstanceSave; -class Object; -class WorldObject; -class TempSummon; -class Player; -class CreatureGroup; -struct ScriptInfo; -struct ScriptAction; -struct Position; -class BattleGround; - -//****************************************** -// Map file format defines -//****************************************** -#define MAP_MAGIC 'SPAM' -#define MAP_VERSION_MAGIC '0.1w' -#define MAP_AREA_MAGIC 'AERA' -#define MAP_HEIGHT_MAGIC 'TGHM' -#define MAP_LIQUID_MAGIC 'QILM' - -struct map_fileheader -{ - uint32 mapMagic; - uint32 versionMagic; - uint32 areaMapOffset; - uint32 areaMapSize; - uint32 heightMapOffset; - uint32 heightMapSize; - uint32 liquidMapOffset; - uint32 liquidMapSize; -}; - -#define MAP_AREA_NO_AREA 0x0001 - -struct map_areaHeader -{ - uint32 fourcc; - uint16 flags; - uint16 gridArea; -}; - -#define MAP_HEIGHT_NO_HEIGHT 0x0001 -#define MAP_HEIGHT_AS_INT16 0x0002 -#define MAP_HEIGHT_AS_INT8 0x0004 - -struct map_heightHeader -{ - uint32 fourcc; - uint32 flags; - float gridHeight; - float gridMaxHeight; -}; - -#define MAP_LIQUID_NO_TYPE 0x0001 -#define MAP_LIQUID_NO_HEIGHT 0x0002 - -struct map_liquidHeader -{ - uint32 fourcc; - uint16 flags; - uint16 liquidType; - uint8 offsetX; - uint8 offsetY; - uint8 width; - uint8 height; - float liquidLevel; -}; - -enum ZLiquidStatus -{ - LIQUID_MAP_NO_WATER = 0x00000000, - LIQUID_MAP_ABOVE_WATER = 0x00000001, - LIQUID_MAP_WATER_WALK = 0x00000002, - LIQUID_MAP_IN_WATER = 0x00000004, - LIQUID_MAP_UNDER_WATER = 0x00000008 -}; - -#define MAP_LIQUID_TYPE_NO_WATER 0x00 -#define MAP_LIQUID_TYPE_WATER 0x01 -#define MAP_LIQUID_TYPE_OCEAN 0x02 -#define MAP_LIQUID_TYPE_MAGMA 0x04 -#define MAP_LIQUID_TYPE_SLIME 0x08 - -#define MAP_ALL_LIQUIDS (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN | MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME) - -#define MAP_LIQUID_TYPE_DARK_WATER 0x10 -#define MAP_LIQUID_TYPE_WMO_WATER 0x20 - -struct LiquidData -{ - uint32 type; - float level; - float depth_level; -}; - -class GridMap -{ - uint32 m_flags; - // Area data - uint16 m_gridArea; - uint16 *m_area_map; - // Height level data - float m_gridHeight; - float m_gridIntHeightMultiplier; - union{ - float *m_V9; - uint16 *m_uint16_V9; - uint8 *m_uint8_V9; - }; - union{ - float *m_V8; - uint16 *m_uint16_V8; - uint8 *m_uint8_V8; - }; - // Liquid data - uint16 m_liquidType; - uint8 m_liquid_offX; - uint8 m_liquid_offY; - uint8 m_liquid_width; - uint8 m_liquid_height; - float m_liquidLevel; - uint8 *m_liquid_type; - float *m_liquid_map; - - bool loadAreaData(FILE *in, uint32 offset, uint32 size); - bool loadHeihgtData(FILE *in, uint32 offset, uint32 size); - bool loadLiquidData(FILE *in, uint32 offset, uint32 size); - - // Get height functions and pointers - typedef float (GridMap::*pGetHeightPtr) (float x, float y) const; - pGetHeightPtr m_gridGetHeight; - float getHeightFromFloat(float x, float y) const; - float getHeightFromUint16(float x, float y) const; - float getHeightFromUint8(float x, float y) const; - float getHeightFromFlat(float x, float y) const; - -public: - GridMap(); - ~GridMap(); - bool loadData(char *filaname); - void unloadData(); - - uint16 getArea(float x, float y); - inline float getHeight(float x, float y) {return (this->*m_gridGetHeight)(x, y);} - float getLiquidLevel(float x, float y); - uint8 getTerrainType(float x, float y); - ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data = 0); -}; - -struct CreatureMover -{ - CreatureMover() : x(0), y(0), z(0), ang(0) {} - CreatureMover(float _x, float _y, float _z, float _ang) : x(_x), y(_y), z(_z), ang(_ang) {} - - float x, y, z, ang; -}; - -// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform -#if defined(__GNUC__) -#pragma pack(1) -#else -#pragma pack(push,1) -#endif - -struct InstanceTemplate -{ - uint32 map; - uint32 parent; - uint32 access_id; - float startLocX; - float startLocY; - float startLocZ; - float startLocO; - uint32 script_id; - bool allowMount; -}; - -enum LevelRequirementVsMode -{ - LEVELREQUIREMENT_HEROIC = 70 -}; - -#if defined(__GNUC__) -#pragma pack() -#else -#pragma pack(pop) -#endif - -typedef UNORDERED_MAP CreatureMoveList; - -#define MAX_HEIGHT 100000.0f // can be use for find ground height at surface -#define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE -#define MIN_UNLOAD_DELAY 1 // immediate unload - -typedef std::map CreatureGroupHolderType; - -class Map : public GridRefManager, public Trinity::ObjectLevelLockable -{ - friend class MapReference; - public: - Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent = NULL); - virtual ~Map(); - - // currently unused for normal maps - bool CanUnload(uint32 diff) - { - if (!m_unloadTimer) return false; - if (m_unloadTimer <= diff) return true; - m_unloadTimer -= diff; - return false; - } - - virtual bool Add(Player *); - virtual void Remove(Player *, bool); - template void Add(T *); - template void Remove(T *, bool); - - virtual void Update(const uint32&); - - /* - void MessageBroadcast(Player *, WorldPacket *, bool to_self); - void MessageBroadcast(WorldObject *, WorldPacket *); - void MessageDistBroadcast(Player *, WorldPacket *, float dist, bool to_self, bool own_team_only = false); - void MessageDistBroadcast(WorldObject *, WorldPacket *, float dist); - */ - - float GetVisibilityDistance() const { return m_VisibleDistance; } - //function for setting up visibility distance for maps on per-type/per-Id basis - virtual void InitVisibilityDistance(); - - void PlayerRelocation(Player *, float x, float y, float z, float orientation); - void CreatureRelocation(Creature *creature, float x, float y, float z, float ang); - - template void Visit(const Cell& cell, TypeContainerVisitor &visitor); - - bool IsRemovalGrid(float x, float y) const - { - GridPair p = Trinity::ComputeGridPair(x, y); - return !getNGrid(p.x_coord, p.y_coord) || getNGrid(p.x_coord, p.y_coord)->GetGridState() == GRID_STATE_REMOVAL; - } - - bool IsLoaded(float x, float y) const - { - GridPair p = Trinity::ComputeGridPair(x, y); - return loaded(p); - } - - bool GetUnloadLock(const GridPair &p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); } - void SetUnloadLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); } - void LoadGrid(float x, float y); - bool UnloadGrid(const uint32 &x, const uint32 &y, bool pForce); - virtual void UnloadAll(); - - void ResetGridExpiry(NGridType &grid, float factor = 1) const - { - grid.ResetTimeTracker(time_t(float(i_gridExpiry)*factor)); - } - - time_t GetGridExpiry(void) const { return i_gridExpiry; } - uint32 GetId(void) const { return i_mapEntry->MapID; } - - static bool ExistMap(uint32 mapid, int gx, int gy); - static bool ExistVMap(uint32 mapid, int gx, int gy); - - static void InitStateMachine(); - static void DeleteStateMachine(); - - Map const * GetParent() const { return m_parentMap; } - - // some calls like isInWater should not use vmaps due to processor power - // can return INVALID_HEIGHT if under z+2 z coord not found height - float GetHeight(float x, float y, float z, bool pCheckVMap=true) const; - - ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data = 0) const; - - uint16 GetAreaFlag(float x, float y, float z, bool *isOutdoors=0) const; - bool GetAreaInfo(float x, float y, float z, uint32 &mogpflags, int32 &adtId, int32 &rootId, int32 &groupId) const; - - bool IsOutdoors(float x, float y, float z) const; - - uint8 GetTerrainType(float x, float y) const; - float GetWaterLevel(float x, float y) const; - bool IsInWater(float x, float y, float z, LiquidData *data = 0) const; - bool IsUnderWater(float x, float y, float z) const; - - static uint32 GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id); - static uint32 GetZoneIdByAreaFlag(uint16 areaflag,uint32 map_id); - static void GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag,uint32 map_id); - - uint32 GetAreaId(float x, float y, float z) const - { - return GetAreaIdByAreaFlag(GetAreaFlag(x,y,z),GetId()); - } - - uint32 GetZoneId(float x, float y, float z) const - { - return GetZoneIdByAreaFlag(GetAreaFlag(x,y,z),GetId()); - } - - void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const - { - GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(x,y,z),GetId()); - } - - void MoveAllCreaturesInMoveList(); - void RemoveAllObjectsInRemoveList(); - virtual void RemoveAllPlayers(); - - bool CreatureRespawnRelocation(Creature *c); // used only in MoveAllCreaturesInMoveList and ObjectGridUnloader - - // assert print helper - bool CheckGridIntegrity(Creature* c, bool moved) const; - - uint32 GetInstanceId() const { return i_InstanceId; } - uint8 GetSpawnMode() const { return (i_spawnMode); } - virtual bool CanEnter(Player* /*player*/) { return true; } - const char* GetMapName() const; - - // have meaning only for instanced map (that have set real difficulty) - Difficulty GetDifficulty() const { return Difficulty(GetSpawnMode()); } - bool IsRegularDifficulty() const { return GetDifficulty() == REGULAR_DIFFICULTY; } - MapDifficulty const* GetMapDifficulty() const; - - bool Instanceable() const { return i_mapEntry && i_mapEntry->Instanceable(); } - // NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable - bool IsDungeon() const { return i_mapEntry && i_mapEntry->IsDungeon(); } - bool IsNonRaidDungeon() const { return i_mapEntry && i_mapEntry->IsNonRaidDungeon(); } - bool IsRaid() const { return i_mapEntry && i_mapEntry->IsRaid(); } - bool IsRaidOrHeroicDungeon() const { return IsRaid() || i_spawnMode > DUNGEON_DIFFICULTY_NORMAL; } - bool IsHeroic() const { return IsRaid() ? i_spawnMode >= RAID_DIFFICULTY_10MAN_HEROIC : i_spawnMode >= DUNGEON_DIFFICULTY_HEROIC; } - bool IsBattleGround() const { return i_mapEntry && i_mapEntry->IsBattleGround(); } - bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); } - bool IsBattleGroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattleGroundOrArena(); } - bool GetEntrancePos(int32 &mapid, float &x, float &y) - { - if (!i_mapEntry) - return false; - return i_mapEntry->GetEntrancePos(mapid, x, y); - } - - void AddObjectToRemoveList(WorldObject *obj); - void AddObjectToSwitchList(WorldObject *obj, bool on); - virtual void DelayedUpdate(const uint32 diff); - - virtual bool RemoveBones(uint64 guid, float x, float y); - - void UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair); - void UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpair); - - void resetMarkedCells() { marked_cells.reset(); } - bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); } - void markCell(uint32 pCellId) { marked_cells.set(pCellId); } - - bool HavePlayers() const { return !m_mapRefManager.isEmpty(); } - uint32 GetPlayersCountExceptGMs() const; - bool ActiveObjectsNearGrid(uint32 x, uint32 y) const; - - void AddWorldObject(WorldObject *obj) { i_worldObjects.insert(obj); } - void RemoveWorldObject(WorldObject *obj) { i_worldObjects.erase(obj); } - - void SendToPlayers(WorldPacket const* data) const; - - typedef MapRefManager PlayerList; - PlayerList const& GetPlayers() const { return m_mapRefManager; } - - //per-map script storage - void ScriptsStart(std::map > const& scripts, uint32 id, Object* source, Object* target); - void ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target); - - // must called with AddToWorld - template - void AddToActive(T* obj) { AddToActiveHelper(obj); } - - void AddToActive(Creature* obj); - - // must called with RemoveFromWorld - template - void RemoveFromActive(T* obj) { RemoveFromActiveHelper(obj); } - - void RemoveFromActive(Creature* obj); - - template void SwitchGridContainers(T* obj, bool active); - template void VisitAll(const float &x, const float &y, float radius, NOTIFIER ¬ifier); - template void VisitWorld(const float &x, const float &y, float radius, NOTIFIER ¬ifier); - template void VisitGrid(const float &x, const float &y, float radius, NOTIFIER ¬ifier); - CreatureGroupHolderType CreatureGroupHolder; - - void UpdateIteratorBack(Player *player); - -#ifdef MAP_BASED_RAND_GEN - MTRand mtRand; - int32 irand(int32 min, int32 max) { return int32 (mtRand.randInt(max - min)) + min; } - uint32 urand(uint32 min, uint32 max) { return mtRand.randInt(max - min) + min; } - int32 rand32() { return mtRand.randInt(); } - double rand_norm() { return mtRand.randExc(); } - double rand_chance() { return mtRand.randExc(100.0); } -#endif - - TempSummon *SummonCreature(uint32 entry, const Position &pos, SummonPropertiesEntry const *properties = NULL, uint32 duration = 0, Unit *summoner = NULL, uint32 vehId = 0); - Creature* GetCreature(uint64 guid); - GameObject* GetGameObject(uint64 guid); - DynamicObject* GetDynamicObject(uint64 guid); - private: - void LoadMapAndVMap(int gx, int gy); - void LoadVMap(int gx, int gy); - void LoadMap(int gx,int gy, bool reload = false); - GridMap *GetGrid(float x, float y); - - void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; } - - void SendInitSelf(Player * player); - - void SendInitTransports(Player * player); - void SendRemoveTransports(Player * player); - - bool CreatureCellRelocation(Creature *creature, Cell new_cell); - - void AddCreatureToMoveList(Creature *c, float x, float y, float z, float ang); - CreatureMoveList i_creaturesToMove; - - bool loaded(const GridPair &) const; - void EnsureGridCreated(const GridPair &); - bool EnsureGridLoaded(Cell const&); - void EnsureGridLoadedAtEnter(Cell const&, Player* player = NULL); - - void buildNGridLinkage(NGridType* pNGridType) { pNGridType->link(this); } - - template void AddType(T *obj); - template void RemoveType(T *obj, bool); - - NGridType* getNGrid(uint32 x, uint32 y) const - { - ASSERT(x < MAX_NUMBER_OF_GRIDS); - ASSERT(y < MAX_NUMBER_OF_GRIDS); - return i_grids[x][y]; - } - - bool isGridObjectDataLoaded(uint32 x, uint32 y) const { return getNGrid(x,y)->isGridObjectDataLoaded(); } - void setGridObjectDataLoaded(bool pLoaded, uint32 x, uint32 y) { getNGrid(x,y)->setGridObjectDataLoaded(pLoaded); } - - void setNGrid(NGridType* grid, uint32 x, uint32 y); - void ScriptsProcess(); - - void UpdateActiveCells(const float &x, const float &y, const uint32 &t_diff); - protected: - void SetUnloadReferenceLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); } - - typedef Trinity::ObjectLevelLockable::Lock Guard; - - MapEntry const* i_mapEntry; - uint8 i_spawnMode; - uint32 i_InstanceId; - uint32 m_unloadTimer; - float m_VisibleDistance; - - MapRefManager m_mapRefManager; - MapRefManager::iterator m_mapRefIter; - - int32 m_VisibilityNotifyPeriod; - - typedef std::set ActiveNonPlayers; - ActiveNonPlayers m_activeNonPlayers; - ActiveNonPlayers::iterator m_activeNonPlayersIter; - - private: - time_t i_gridExpiry; - - //used for fast base_map (e.g. MapInstanced class object) search for - //InstanceMaps and BattleGroundMaps... - Map* m_parentMap; - - NGridType* i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; - GridMap *GridMaps[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; - std::bitset marked_cells; - - //these functions used to process player/mob aggro reactions and - //visibility calculations. Highly optimized for massive calculations - void ProcessRelocationNotifies(const uint32 &diff); - - bool i_scriptLock; - std::set i_objectsToRemove; - std::map i_objectsToSwitch; - std::set i_worldObjects; - std::multimap m_scriptSchedule; - - // Type specific code for add/remove to/from grid - template - void AddToGrid(T*, NGridType *, Cell const&); - - template - void RemoveFromGrid(T*, NGridType *, Cell const&); - - template - void DeleteFromWorld(T*); - - template - void AddToActiveHelper(T* obj) - { - m_activeNonPlayers.insert(obj); - } - - template - void RemoveFromActiveHelper(T* obj) - { - // Map::Update for active object in proccess - if (m_activeNonPlayersIter != m_activeNonPlayers.end()) - { - ActiveNonPlayers::iterator itr = m_activeNonPlayers.find(obj); - if (itr == m_activeNonPlayers.end()) - return; - if (itr == m_activeNonPlayersIter) - ++m_activeNonPlayersIter; - m_activeNonPlayers.erase(itr); - } - else - m_activeNonPlayers.erase(obj); - } -}; - -enum InstanceResetMethod -{ - INSTANCE_RESET_ALL, - INSTANCE_RESET_CHANGE_DIFFICULTY, - INSTANCE_RESET_GLOBAL, - INSTANCE_RESET_GROUP_DISBAND, - INSTANCE_RESET_GROUP_JOIN, - INSTANCE_RESET_RESPAWN_DELAY -}; - -class InstanceMap : public Map -{ - public: - InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent); - ~InstanceMap(); - bool Add(Player *); - void Remove(Player *, bool); - void Update(const uint32&); - void CreateInstanceData(bool load); - bool Reset(uint8 method); - uint32 GetScriptId() { return i_script_id; } - InstanceData* GetInstanceData() { return i_data; } - void PermBindAllPlayers(Player *player); - void UnloadAll(); - bool CanEnter(Player* player); - void SendResetWarnings(uint32 timeLeft) const; - void SetResetSchedule(bool on); - - uint32 GetMaxPlayers() const; - uint32 GetMaxResetDelay() const; - - virtual void InitVisibilityDistance(); - private: - bool m_resetAfterUnload; - bool m_unloadWhenEmpty; - InstanceData* i_data; - uint32 i_script_id; -}; - -class BattleGroundMap : public Map -{ - public: - BattleGroundMap(uint32 id, time_t, uint32 InstanceId, Map* _parent, uint8 spawnMode); - ~BattleGroundMap(); - - bool Add(Player *); - void Remove(Player *, bool); - bool CanEnter(Player* player); - void SetUnload(); - //void UnloadAll(bool pForce); - void RemoveAllPlayers(); - - virtual void InitVisibilityDistance(); - BattleGround* GetBG() { return m_bg; } - void SetBG(BattleGround* bg) { m_bg = bg; } - private: - BattleGround* m_bg; -}; - -/*inline -uint64 -Map::CalculateGridMask(const uint32 &y) const -{ - uint64 mask = 1; - mask <<= y; - return mask; -} -*/ - -template -inline void -Map::Visit(const Cell& cell, TypeContainerVisitor &visitor) -{ - const uint32 x = cell.GridX(); - const uint32 y = cell.GridY(); - const uint32 cell_x = cell.CellX(); - const uint32 cell_y = cell.CellY(); - - if (!cell.NoCreate() || loaded(GridPair(x,y))) - { - EnsureGridLoaded(cell); - getNGrid(x, y)->Visit(cell_x, cell_y, visitor); - } -} - -template -inline void -Map::VisitAll(const float &x, const float &y, float radius, NOTIFIER ¬ifier) -{ - CellPair p(Trinity::ComputeCellPair(x, y)); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - TypeContainerVisitor world_object_notifier(notifier); - cell.Visit(p, world_object_notifier, *this, radius, x, y); - TypeContainerVisitor grid_object_notifier(notifier); - cell.Visit(p, grid_object_notifier, *this, radius, x, y); -} - -template -inline void -Map::VisitWorld(const float &x, const float &y, float radius, NOTIFIER ¬ifier) -{ - CellPair p(Trinity::ComputeCellPair(x, y)); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - TypeContainerVisitor world_object_notifier(notifier); - cell.Visit(p, world_object_notifier, *this, radius, x, y); -} - -template -inline void -Map::VisitGrid(const float &x, const float &y, float radius, NOTIFIER ¬ifier) -{ - CellPair p(Trinity::ComputeCellPair(x, y)); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - TypeContainerVisitor grid_object_notifier(notifier); - cell.Visit(p, grid_object_notifier, *this, radius, x, y); -} -#endif diff --git a/src/server/game/Map/MapInstanced.cpp b/src/server/game/Map/MapInstanced.cpp deleted file mode 100644 index 0736bfa6fb3..00000000000 --- a/src/server/game/Map/MapInstanced.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "MapInstanced.h" -#include "ObjectMgr.h" -#include "MapManager.h" -#include "BattleGround.h" -#include "VMapFactory.h" -#include "InstanceSaveMgr.h" -#include "World.h" - -MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, DUNGEON_DIFFICULTY_NORMAL) -{ - // initialize instanced maps list - m_InstancedMaps.clear(); - // fill with zero - memset(&GridMapReference, 0, MAX_NUMBER_OF_GRIDS*MAX_NUMBER_OF_GRIDS*sizeof(uint16)); -} - -void MapInstanced::InitVisibilityDistance() -{ - if (m_InstancedMaps.empty()) - return; - //initialize visibility distances for all instance copies - for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) - { - (*i).second->InitVisibilityDistance(); - } -} - -void MapInstanced::Update(const uint32& t) -{ - // take care of loaded GridMaps (when unused, unload it!) - Map::Update(t); - - // update the instanced maps - InstancedMaps::iterator i = m_InstancedMaps.begin(); - - while (i != m_InstancedMaps.end()) - { - if (i->second->CanUnload(t)) - { - if (!DestroyInstance(i)) // iterator incremented - { - //m_unloadTimer - } - } - else - { - // update only here, because it may schedule some bad things before delete - i->second->Update(t); - ++i; - } - } -} - -void MapInstanced::DelayedUpdate(const uint32 diff) -{ - for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) - i->second->DelayedUpdate(diff); - - Map::DelayedUpdate(diff); // this may be removed -} - -/* -void MapInstanced::RelocationNotify() -{ - for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) - i->second->RelocationNotify(); -} -*/ - -bool MapInstanced::RemoveBones(uint64 guid, float x, float y) -{ - bool remove_result = false; - - for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) - { - remove_result = remove_result || i->second->RemoveBones(guid, x, y); - } - - return remove_result || Map::RemoveBones(guid,x,y); -} - -void MapInstanced::UnloadAll() -{ - // Unload instanced maps - for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) - i->second->UnloadAll(); - - // Delete the maps only after everything is unloaded to prevent crashes - for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) - delete i->second; - - m_InstancedMaps.clear(); - - // Unload own grids (just dummy(placeholder) grids, neccesary to unload GridMaps!) - Map::UnloadAll(); -} - -/* -- return the right instance for the object, based on its InstanceId -- create the instance if it's not created already -- the player is not actually added to the instance (only in InstanceMap::Add) -*/ -Map* MapInstanced::CreateInstance(const uint32 mapId, Player * player) -{ - if (GetId() != mapId || !player) - return NULL; - - Map* map = NULL; - uint32 NewInstanceId = 0; // instanceId of the resulting map - - if (IsBattleGroundOrArena()) - { - // instantiate or find existing bg map for player - // the instance id is set in battlegroundid - NewInstanceId = player->GetBattleGroundId(); - if (!NewInstanceId) return NULL; - map = _FindMap(NewInstanceId); - if (!map) - map = CreateBattleGround(NewInstanceId, player->GetBattleGround()); - } - else - { - InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty(IsRaid())); - InstanceSave *pSave = pBind ? pBind->save : NULL; - - // the player's permanent player bind is taken into consideration first - // then the player's group bind and finally the solo bind. - if (!pBind || !pBind->perm) - { - InstanceGroupBind *groupBind = NULL; - Group *group = player->GetGroup(); - // use the player's difficulty setting (it may not be the same as the group's) - if (group) - { - groupBind = group->GetBoundInstance(this); - if (groupBind) - pSave = groupBind->save; - } - } - if (pSave) - { - // solo/perm/group - NewInstanceId = pSave->GetInstanceId(); - map = _FindMap(NewInstanceId); - // it is possible that the save exists but the map doesn't - if (!map) - map = CreateInstance(NewInstanceId, pSave, pSave->GetDifficulty()); - } - else - { - // if no instanceId via group members or instance saves is found - // the instance will be created for the first time - NewInstanceId = MapManager::Instance().GenerateInstanceId(); - - Difficulty diff = player->GetGroup() ? player->GetGroup()->GetDifficulty(IsRaid()) : player->GetDifficulty(IsRaid()); - map = CreateInstance(NewInstanceId, NULL, diff); - } - } - - return map; -} - -InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, Difficulty difficulty) -{ - // load/create a map - Guard guard(*this); - - // make sure we have a valid map id - const MapEntry* entry = sMapStore.LookupEntry(GetId()); - if (!entry) - { - sLog.outError("CreateInstance: no entry for map %d", GetId()); - assert(false); - } - const InstanceTemplate * iTemplate = objmgr.GetInstanceTemplate(GetId()); - if (!iTemplate) - { - sLog.outError("CreateInstance: no instance template for map %d", GetId()); - assert(false); - } - - // some instances only have one difficulty - MapDifficulty const* mapDiff = GetMapDifficultyData(GetId(),difficulty); - if (!mapDiff) - difficulty = DUNGEON_DIFFICULTY_NORMAL; - - sLog.outDebug("MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal"); - - InstanceMap *map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this); - ASSERT(map->IsDungeon()); - - bool load_data = save != NULL; - map->CreateInstanceData(load_data); - - m_InstancedMaps[InstanceId] = map; - return map; -} - -BattleGroundMap* MapInstanced::CreateBattleGround(uint32 InstanceId, BattleGround* bg) -{ - // load/create a map - Guard guard(*this); - - sLog.outDebug("MapInstanced::CreateBattleGround: map bg %d for %d created.", InstanceId, GetId()); - - PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),bg->GetMinLevel()); - - uint8 spawnMode = bracketEntry ? bracketEntry->difficulty : REGULAR_DIFFICULTY; - - BattleGroundMap *map = new BattleGroundMap(GetId(), GetGridExpiry(), InstanceId, this, spawnMode); - ASSERT(map->IsBattleGroundOrArena()); - map->SetBG(bg); - bg->SetBgMap(map); - - m_InstancedMaps[InstanceId] = map; - return map; -} - -// increments the iterator after erase -bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) -{ - itr->second->RemoveAllPlayers(); - if (itr->second->HavePlayers()) - { - ++itr; - return false; - } - - itr->second->UnloadAll(); - // should only unload VMaps if this is the last instance and grid unloading is enabled - if (m_InstancedMaps.size() <= 1 && sWorld.getConfig(CONFIG_GRID_UNLOAD)) - { - VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(itr->second->GetId()); - // in that case, unload grids of the base map, too - // so in the next map creation, (EnsureGridCreated actually) VMaps will be reloaded - Map::UnloadAll(); - } - // erase map - delete itr->second; - m_InstancedMaps.erase(itr++); - return true; -} - -bool MapInstanced::CanEnter(Player * /*player*/) -{ - //assert(false); - return true; -} diff --git a/src/server/game/Map/MapInstanced.h b/src/server/game/Map/MapInstanced.h deleted file mode 100644 index 536257da011..00000000000 --- a/src/server/game/Map/MapInstanced.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_MAP_INSTANCED_H -#define TRINITY_MAP_INSTANCED_H - -#include "Map.h" -#include "InstanceSaveMgr.h" -#include "DBCEnums.h" - -class MapInstanced : public Map -{ - friend class MapManager; - public: - typedef UNORDERED_MAP< uint32, Map* > InstancedMaps; - - MapInstanced(uint32 id, time_t expiry); - ~MapInstanced() {} - - // functions overwrite Map versions - void Update(const uint32&); - void DelayedUpdate(const uint32 diff); - //void RelocationNotify(); - bool RemoveBones(uint64 guid, float x, float y); - void UnloadAll(); - bool CanEnter(Player* player); - - Map* CreateInstance(const uint32 mapId, Player * player); - Map* FindMap(uint32 InstanceId) const { return _FindMap(InstanceId); } - bool DestroyInstance(InstancedMaps::iterator &itr); - - void AddGridMapReference(const GridPair &p) - { - ++GridMapReference[p.x_coord][p.y_coord]; - SetUnloadReferenceLock(GridPair(63-p.x_coord, 63-p.y_coord), true); - } - - void RemoveGridMapReference(GridPair const& p) - { - --GridMapReference[p.x_coord][p.y_coord]; - if (!GridMapReference[p.x_coord][p.y_coord]) - SetUnloadReferenceLock(GridPair(63-p.x_coord, 63-p.y_coord), false); - } - - InstancedMaps &GetInstancedMaps() { return m_InstancedMaps; } - virtual void InitVisibilityDistance(); - - private: - - InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave *save, Difficulty difficulty); - BattleGroundMap* CreateBattleGround(uint32 InstanceId, BattleGround* bg); - - InstancedMaps m_InstancedMaps; - - Map* _FindMap(uint32 InstanceId) const - { - InstancedMaps::const_iterator i = m_InstancedMaps.find(InstanceId); - return(i == m_InstancedMaps.end() ? NULL : i->second); - } - - uint16 GridMapReference[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; -}; -#endif diff --git a/src/server/game/Map/MapManager.cpp b/src/server/game/Map/MapManager.cpp deleted file mode 100644 index de3d0ebbaff..00000000000 --- a/src/server/game/Map/MapManager.cpp +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "MapManager.h" -#include "InstanceSaveMgr.h" -#include "Policies/SingletonImp.h" -#include "Database/DatabaseEnv.h" -#include "Log.h" -#include "ObjectAccessor.h" -#include "Transports.h" -#include "GridDefines.h" -#include "MapInstanced.h" -#include "InstanceData.h" -#include "DestinationHolderImp.h" -#include "Config/ConfigEnv.h" -#include "World.h" -#include "CellImpl.h" -#include "Corpse.h" -#include "ObjectMgr.h" -#include "Language.h" -#include "WorldPacket.h" - -#define CLASS_LOCK Trinity::ClassLevelLockable -INSTANTIATE_SINGLETON_2(MapManager, CLASS_LOCK); -INSTANTIATE_CLASS_MUTEX(MapManager, ACE_Thread_Mutex); - -extern GridState* si_GridStates[]; // debugging code, should be deleted some day - -MapManager::MapManager() -{ - i_gridCleanUpDelay = sWorld.getConfig(CONFIG_INTERVAL_GRIDCLEAN); - i_timer.SetInterval(sWorld.getConfig(CONFIG_INTERVAL_MAPUPDATE)); -} - -MapManager::~MapManager() -{ - for (MapMapType::iterator iter=i_maps.begin(); iter != i_maps.end(); ++iter) - delete iter->second; - - for (TransportSet::iterator i = m_Transports.begin(); i != m_Transports.end(); ++i) - delete *i; - - Map::DeleteStateMachine(); -} - -void MapManager::Initialize() -{ - Map::InitStateMachine(); - - // debugging code, should be deleted some day - { - for (uint8 i = 0; i < MAX_GRID_STATE; ++i) - i_GridStates[i] = si_GridStates[i]; - - i_GridStateErrorCount = 0; - } - int num_threads(sWorld.getConfig(CONFIG_NUMTHREADS)); - // Start mtmaps if needed. - if (num_threads > 0 && m_updater.activate(num_threads) == -1) - abort(); - - InitMaxInstanceId(); -} - -void MapManager::InitializeVisibilityDistanceInfo() -{ - for (MapMapType::iterator iter=i_maps.begin(); iter != i_maps.end(); ++iter) - (*iter).second->InitVisibilityDistance(); -} - -// debugging code, should be deleted some day -void MapManager::checkAndCorrectGridStatesArray() -{ - bool ok = true; - for (int i=0; icheckMagic()) - { - ok = false; - si_GridStates[i]->setMagic(); - } - #endif - } - if (!ok) - ++i_GridStateErrorCount; -} - -Map* MapManager::_createBaseMap(uint32 id) -{ - Map *m = _findMap(id); - - if (m == NULL) - { - Guard guard(*this); - - const MapEntry* entry = sMapStore.LookupEntry(id); - if (entry && entry->Instanceable()) - { - m = new MapInstanced(id, i_gridCleanUpDelay); - } - else - { - m = new Map(id, i_gridCleanUpDelay, 0, REGULAR_DIFFICULTY); - } - i_maps[id] = m; - } - - assert(m != NULL); - return m; -} - -Map* MapManager::CreateMap(uint32 id, const WorldObject* obj, uint32 /*instanceId*/) -{ - ASSERT(obj); - //if (!obj->IsInWorld()) sLog.outError("GetMap: called for map %d with object (typeid %d, guid %d, mapid %d, instanceid %d) who is not in world!", id, obj->GetTypeId(), obj->GetGUIDLow(), obj->GetMapId(), obj->GetInstanceId()); - Map *m = _createBaseMap(id); - - if (m && (obj->GetTypeId() == TYPEID_PLAYER) && m->Instanceable()) m = ((MapInstanced*)m)->CreateInstance(id, (Player*)obj); - - return m; -} - -Map* MapManager::FindMap(uint32 mapid, uint32 instanceId) const -{ - Map *map = _findMap(mapid); - if (!map) - return NULL; - - if (!map->Instanceable()) - return instanceId == 0 ? map : NULL; - - return ((MapInstanced*)map)->FindMap(instanceId); -} - -bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck) -{ - const MapEntry *entry = sMapStore.LookupEntry(mapid); - if (!entry) - return false; - - if (!entry->IsDungeon()) - return true; - - const char *mapName = entry->name[player->GetSession()->GetSessionDbcLocale()]; - - Group* pGroup = player->GetGroup(); - if (entry->IsRaid()) - { - // can only enter in a raid group - // GMs can avoid raid limitations - if ((!pGroup || !pGroup->isRaidGroup()) && !player->isGameMaster() && !sWorld.getConfig(CONFIG_INSTANCE_IGNORE_RAID)) - { - // probably there must be special opcode, because client has this string constant in GlobalStrings.lua - // TODO: this is not a good place to send the message - player->GetSession()->SendAreaTriggerMessage(player->GetSession()->GetTrinityString(LANG_INSTANCE_RAID_GROUP_ONLY), mapName); - sLog.outDebug("MAP: Player '%s' must be in a raid group to enter instance '%s'", player->GetName(), mapName); - return false; - } - } - - //The player has a heroic mode and tries to enter into instance which has no a heroic mode - MapDifficulty const* mapDiff = GetMapDifficultyData(entry->MapID,player->GetDifficulty(entry->IsRaid())); - if (!mapDiff) - { - bool isNormalTargetMap = entry->IsRaid() - ? (player->GetRaidDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) - : (player->GetDungeonDifficulty() == DUNGEON_DIFFICULTY_NORMAL); - - // Send aborted message - // FIX ME: what about absent normal/heroic mode with specific players limit... - player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY, isNormalTargetMap ? DUNGEON_DIFFICULTY_NORMAL : DUNGEON_DIFFICULTY_HEROIC); - return false; - } - - if (!player->isAlive()) - { - if (Corpse *corpse = player->GetCorpse()) - { - // let enter in ghost mode in instance that connected to inner instance with corpse - uint32 instance_map = corpse->GetMapId(); - do - { - if (instance_map == mapid) - break; - - InstanceTemplate const* instance = objmgr.GetInstanceTemplate(instance_map); - instance_map = instance ? instance->parent : 0; - } - while (instance_map); - - if (!instance_map) - { - WorldPacket data(SMSG_CORPSE_NOT_IN_INSTANCE); - player->GetSession()->SendPacket(&data); - sLog.outDebug("MAP: Player '%s' does not have a corpse in instance '%s' and cannot enter.", player->GetName(), mapName); - return false; - } - sLog.outDebug("MAP: Player '%s' has corpse in instance '%s' and can enter.", player->GetName(), mapName); - } - else - sLog.outDebug("Map::CanPlayerEnter - player '%s' is dead but does not have a corpse!", player->GetName()); - } - - InstanceTemplate const* instance = objmgr.GetInstanceTemplate(mapid); - if (!instance) - return false; - - //Get instance where player's group is bound & its map - if (pGroup) - { - InstanceGroupBind* boundedInstance = pGroup->GetBoundInstance(player); - if (boundedInstance && boundedInstance->save) - { - if (Map *boundedMap = MapManager::Instance().FindMap(mapid,boundedInstance->save->GetInstanceId())) - { - // Player permanently bounded to different instance than groups one - InstancePlayerBind* playerBoundedInstance = player->GetBoundInstance(mapid, player->GetDungeonDifficulty()); - if (playerBoundedInstance && playerBoundedInstance->perm && playerBoundedInstance->save && - boundedInstance->save->GetInstanceId() != playerBoundedInstance->save->GetInstanceId()) - { - //TODO: send some kind of error message to the player - return false; - } - - // Encounters in progress - if (!loginCheck && entry->IsRaid() && ((InstanceMap*)boundedMap)->GetInstanceData() && ((InstanceMap*)boundedMap)->GetInstanceData()->IsEncounterInProgress()) - { - sLog.outDebug("MAP: Player '%s' cannot enter instance '%s' while an encounter is in progress.", player->GetName(), mapName); - player->SendTransferAborted(mapid, TRANSFER_ABORT_ZONE_IN_COMBAT); - return false; - } - - // Instance is full - MapDifficulty const* mapDiff = ((InstanceMap*)boundedMap)->GetMapDifficulty(); - int8 maxPlayers = mapDiff ? mapDiff->maxPlayers : 0; - if (maxPlayers != -1) //-1: unlimited access - { - if (boundedMap->GetPlayersCountExceptGMs() >= (loginCheck ? maxPlayers+1 : maxPlayers)) - { - sLog.outDebug("MAP: Player '%s' cannot enter instance '%s' because it is full.", player->GetName(), mapName); - player->SendTransferAborted(mapid, TRANSFER_ABORT_MAX_PLAYERS); - return false; - } - } - } - } - } - - //Other requirements - return player->Satisfy(objmgr.GetAccessRequirement(instance->access_id), mapid, true); -} - -void MapManager::RemoveBonesFromMap(uint32 mapid, uint64 guid, float x, float y) -{ - bool remove_result = _createBaseMap(mapid)->RemoveBones(guid, x, y); - - if (!remove_result) - { - sLog.outDebug("Bones %u not found in world. Delete from DB also.", GUID_LOPART(guid)); - } -} - -void MapManager::Update(uint32 diff) -{ - i_timer.Update(diff); - if (!i_timer.Passed()) - return; - - MapMapType::iterator iter = i_maps.begin(); - for (; iter != i_maps.end(); ++iter) - { - if (m_updater.activated()) - m_updater.schedule_update(*iter->second, i_timer.GetCurrent()); - else - { - iter->second->Update(i_timer.GetCurrent()); - } - } - if (m_updater.activated()) - m_updater.wait(); - - for (iter = i_maps.begin(); iter != i_maps.end(); ++iter) - iter->second->DelayedUpdate(i_timer.GetCurrent()); - - ObjectAccessor::Instance().Update(i_timer.GetCurrent()); - for (TransportSet::iterator iter = m_Transports.begin(); iter != m_Transports.end(); ++iter) - (*iter)->Update(i_timer.GetCurrent()); - - i_timer.SetCurrent(0); -} - -void MapManager::DoDelayedMovesAndRemoves() -{ -} - -bool MapManager::ExistMapAndVMap(uint32 mapid, float x,float y) -{ - GridPair p = Trinity::ComputeGridPair(x,y); - - int gx=63-p.x_coord; - int gy=63-p.y_coord; - - return Map::ExistMap(mapid,gx,gy) && Map::ExistVMap(mapid,gx,gy); -} - -bool MapManager::IsValidMAP(uint32 mapid) -{ - MapEntry const* mEntry = sMapStore.LookupEntry(mapid); - return mEntry && (!mEntry->IsDungeon() || objmgr.GetInstanceTemplate(mapid)); - // TODO: add check for battleground template -} - -void MapManager::UnloadAll() -{ - for (MapMapType::iterator iter=i_maps.begin(); iter != i_maps.end(); ++iter) - iter->second->UnloadAll(); - - while (!i_maps.empty()) - { - delete i_maps.begin()->second; - i_maps.erase(i_maps.begin()); - } - - if (m_updater.activated()) - m_updater.deactivate(); -} - -void MapManager::InitMaxInstanceId() -{ - i_MaxInstanceId = 0; - - QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT MAX(id) FROM instance"); - if (result) - i_MaxInstanceId = result->Fetch()[0].GetUInt32(); -} - -uint32 MapManager::GetNumInstances() -{ - Guard guard(*this); - - uint32 ret = 0; - for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) - { - Map *map = itr->second; - if (!map->Instanceable()) - continue; - MapInstanced::InstancedMaps &maps = ((MapInstanced *)map)->GetInstancedMaps(); - for (MapInstanced::InstancedMaps::iterator mitr = maps.begin(); mitr != maps.end(); ++mitr) - if (mitr->second->IsDungeon()) ret++; - } - return ret; -} - -uint32 MapManager::GetNumPlayersInInstances() -{ - Guard guard(*this); - - uint32 ret = 0; - for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) - { - Map *map = itr->second; - if (!map->Instanceable()) - continue; - MapInstanced::InstancedMaps &maps = ((MapInstanced *)map)->GetInstancedMaps(); - for (MapInstanced::InstancedMaps::iterator mitr = maps.begin(); mitr != maps.end(); ++mitr) - if (mitr->second->IsDungeon()) - ret += ((InstanceMap*)mitr->second)->GetPlayers().getSize(); - } - return ret; -} diff --git a/src/server/game/Map/MapManager.h b/src/server/game/Map/MapManager.h deleted file mode 100644 index d94f9fced0e..00000000000 --- a/src/server/game/Map/MapManager.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_MAPMANAGER_H -#define TRINITY_MAPMANAGER_H - -#include "Platform/Define.h" -#include "Policies/Singleton.h" -#include "ace/Thread_Mutex.h" -#include "Common.h" -#include "Map.h" -#include "GridStates.h" -#include "MapUpdater.h" - -class Transport; - -class MapManager : public Trinity::Singleton > -{ - - friend class Trinity::OperatorNew; - typedef UNORDERED_MAP MapMapType; - typedef std::pair::iterator, bool> MapMapPair; - - public: - - Map* CreateMap(uint32, const WorldObject* obj, uint32 instanceId); - Map const* CreateBaseMap(uint32 id) const { return const_cast(this)->_createBaseMap(id); } - Map* FindMap(uint32 mapid, uint32 instanceId = 0) const; - - uint16 GetAreaFlag(uint32 mapid, float x, float y, float z) const - { - Map const* m = CreateBaseMap(mapid); - return m->GetAreaFlag(x, y, z); - } - uint32 GetAreaId(uint32 mapid, float x, float y, float z) const - { - return Map::GetAreaIdByAreaFlag(GetAreaFlag(mapid, x, y, z),mapid); - } - uint32 GetZoneId(uint32 mapid, float x, float y, float z) const - { - return Map::GetZoneIdByAreaFlag(GetAreaFlag(mapid, x, y, z),mapid); - } - void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z) - { - Map::GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(mapid, x, y, z),mapid); - } - - void Initialize(void); - void Update(uint32); - - void SetGridCleanUpDelay(uint32 t) - { - if (t < MIN_GRID_DELAY) - i_gridCleanUpDelay = MIN_GRID_DELAY; - else - i_gridCleanUpDelay = t; - } - - void SetMapUpdateInterval(uint32 t) - { - if (t > MIN_MAP_UPDATE_DELAY) - t = MIN_MAP_UPDATE_DELAY; - - i_timer.SetInterval(t); - i_timer.Reset(); - } - - //void LoadGrid(int mapid, int instId, float x, float y, const WorldObject* obj, bool no_unload = false); - void UnloadAll(); - - static bool ExistMapAndVMap(uint32 mapid, float x, float y); - static bool IsValidMAP(uint32 mapid); - - static bool IsValidMapCoord(uint32 mapid, float x,float y) - { - return IsValidMAP(mapid) && Trinity::IsValidMapCoord(x,y); - } - - static bool IsValidMapCoord(uint32 mapid, float x,float y,float z) - { - return IsValidMAP(mapid) && Trinity::IsValidMapCoord(x,y,z); - } - - static bool IsValidMapCoord(uint32 mapid, float x,float y,float z,float o) - { - return IsValidMAP(mapid) && Trinity::IsValidMapCoord(x,y,z,o); - } - - static bool IsValidMapCoord(WorldLocation const& loc) - { - return IsValidMapCoord(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), loc.GetOrientation()); - } - - void DoDelayedMovesAndRemoves(); - - void LoadTransports(); - - typedef std::set TransportSet; - TransportSet m_Transports; - - typedef std::map TransportMap; - TransportMap m_TransportsByMap; - - bool CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck = false); - void RemoveBonesFromMap(uint32 mapid, uint64 guid, float x, float y); - uint32 GenerateInstanceId() { return ++i_MaxInstanceId; } - void InitMaxInstanceId(); - void InitializeVisibilityDistanceInfo(); - - /* statistics */ - uint32 GetNumInstances(); - uint32 GetNumPlayersInInstances(); - - private: - // debugging code, should be deleted some day - void checkAndCorrectGridStatesArray(); // just for debugging to find some memory overwrites - GridState* i_GridStates[MAX_GRID_STATE]; // shadow entries to the global array in Map.cpp - int i_GridStateErrorCount; - private: - MapManager(); - ~MapManager(); - - MapManager(const MapManager &); - MapManager& operator=(const MapManager &); - - Map* _createBaseMap(uint32 id); - Map* _findMap(uint32 id) const - { - MapMapType::const_iterator iter = i_maps.find(id); - return (iter == i_maps.end() ? NULL : iter->second); - } - - typedef Trinity::ClassLevelLockable::Lock Guard; - uint32 i_gridCleanUpDelay; - MapMapType i_maps; - IntervalTimer i_timer; - - uint32 i_MaxInstanceId; - MapUpdater m_updater; -}; -#endif diff --git a/src/server/game/Map/MapRefManager.h b/src/server/game/Map/MapRefManager.h deleted file mode 100644 index 4337aa75fd9..00000000000 --- a/src/server/game/Map/MapRefManager.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _MAPREFMANAGER -#define _MAPREFMANAGER - -#include "Utilities/LinkedReference/RefManager.h" - -class MapReference; - -class MapRefManager : public RefManager -{ - public: - typedef LinkedListHead::Iterator< MapReference > iterator; - typedef LinkedListHead::Iterator< MapReference const > const_iterator; - - MapReference* getFirst() { return (MapReference*)RefManager::getFirst(); } - MapReference const* getFirst() const { return (MapReference const*)RefManager::getFirst(); } - MapReference* getLast() { return (MapReference*)RefManager::getLast(); } - MapReference const* getLast() const { return (MapReference const*)RefManager::getLast(); } - - iterator begin() { return iterator(getFirst()); } - iterator end() { return iterator(NULL); } - iterator rbegin() { return iterator(getLast()); } - iterator rend() { return iterator(NULL); } - const_iterator begin() const { return const_iterator(getFirst()); } - const_iterator end() const { return const_iterator(NULL); } -}; -#endif - diff --git a/src/server/game/Map/MapReference.h b/src/server/game/Map/MapReference.h deleted file mode 100644 index 7cd4fcde76c..00000000000 --- a/src/server/game/Map/MapReference.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _MAPREFERENCE_H -#define _MAPREFERENCE_H - -#include "Utilities/LinkedReference/Reference.h" -#include "Map.h" - -class MapReference : public Reference -{ - protected: - void targetObjectBuildLink() - { - // called from link() - getTarget()->m_mapRefManager.insertFirst(this); - getTarget()->m_mapRefManager.incSize(); - } - void targetObjectDestroyLink() - { - // called from unlink() - if (isValid()) getTarget()->m_mapRefManager.decSize(); - } - void sourceObjectDestroyLink() - { - // called from invalidate() - getTarget()->m_mapRefManager.decSize(); - } - public: - MapReference() : Reference() {} - ~MapReference() { unlink(); } - MapReference *next() { return (MapReference*)Reference::next(); } - MapReference const *next() const { return (MapReference const*)Reference::next(); } - MapReference *nockeck_prev() { return (MapReference*)Reference::nocheck_prev(); } - MapReference const *nocheck_prev() const { return (MapReference const*)Reference::nocheck_prev(); } -}; -#endif - diff --git a/src/server/game/Map/MapUpdater.cpp b/src/server/game/Map/MapUpdater.cpp deleted file mode 100644 index f9bb5e2bbbc..00000000000 --- a/src/server/game/Map/MapUpdater.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include "MapUpdater.h" -#include "DelayExecutor.h" -#include "Map.h" -#include "Database/DatabaseEnv.h" - -#include -#include - -class WDBThreadStartReq1 : public ACE_Method_Request -{ - public: - - WDBThreadStartReq1() - { - } - - virtual int call() - { - WorldDatabase.ThreadStart(); - return 0; - } -}; - -class WDBThreadEndReq1 : public ACE_Method_Request -{ - public: - - WDBThreadEndReq1() - { - } - - virtual int call() - { - WorldDatabase.ThreadEnd(); - return 0; - } -}; - -class MapUpdateRequest : public ACE_Method_Request -{ - private: - - Map& m_map; - MapUpdater& m_updater; - ACE_UINT32 m_diff; - - public: - - MapUpdateRequest(Map& m, MapUpdater& u, ACE_UINT32 d) - : m_map(m), m_updater(u), m_diff(d) - { - } - - virtual int call() - { - m_map.Update (m_diff); - m_updater.update_finished (); - return 0; - } -}; - -MapUpdater::MapUpdater() - : m_mutex(), m_condition(m_mutex), m_executor(), pending_requests(0) -{ -} - -MapUpdater::~MapUpdater() -{ - deactivate(); -} - -int MapUpdater::activate(size_t num_threads) -{ - return m_executor.activate((int)num_threads, new WDBThreadStartReq1, new WDBThreadEndReq1); -} - -int MapUpdater::deactivate() -{ - wait(); - - return m_executor.deactivate(); -} - -int MapUpdater::wait() -{ - ACE_GUARD_RETURN(ACE_Thread_Mutex, guard, m_mutex, -1); - - while (pending_requests > 0) - m_condition.wait(); - - return 0; -} - -int MapUpdater::schedule_update(Map& map, ACE_UINT32 diff) -{ - ACE_GUARD_RETURN(ACE_Thread_Mutex, guard, m_mutex, -1); - - ++pending_requests; - - if (m_executor.execute(new MapUpdateRequest(map, *this, diff)) == -1) - { - ACE_DEBUG((LM_ERROR, ACE_TEXT("(%t) \n"), ACE_TEXT("Failed to schedule Map Update"))); - - --pending_requests; - return -1; - } - - return 0; -} - -bool MapUpdater::activated() -{ - return m_executor.activated(); -} - -void MapUpdater::update_finished() -{ - ACE_GUARD(ACE_Thread_Mutex, guard, m_mutex); - - if (pending_requests == 0) - { - ACE_ERROR((LM_ERROR, ACE_TEXT("(%t)\n"), ACE_TEXT("MapUpdater::update_finished BUG, report to devs"))); - return; - } - - --pending_requests; - - m_condition.broadcast(); -} diff --git a/src/server/game/Map/MapUpdater.h b/src/server/game/Map/MapUpdater.h deleted file mode 100644 index f301b15ca2f..00000000000 --- a/src/server/game/Map/MapUpdater.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef _MAP_UPDATER_H_INCLUDED -#define _MAP_UPDATER_H_INCLUDED - -#include -#include - -#include "DelayExecutor.h" - -class Map; - -class MapUpdater -{ - public: - - MapUpdater(); - virtual ~MapUpdater(); - - friend class MapUpdateRequest; - - int schedule_update(Map& map, ACE_UINT32 diff); - - int wait(); - - int activate(size_t num_threads); - - int deactivate(); - - bool activated(); - - private: - - DelayExecutor m_executor; - ACE_Condition_Thread_Mutex m_condition; - ACE_Thread_Mutex m_mutex; - size_t pending_requests; - - void update_finished(); -}; - -#endif //_MAP_UPDATER_H_INCLUDED diff --git a/src/server/game/Map/ObjectPosSelector.cpp b/src/server/game/Map/ObjectPosSelector.cpp deleted file mode 100644 index 899dfec3fdb..00000000000 --- a/src/server/game/Map/ObjectPosSelector.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ObjectPosSelector.h" - -ObjectPosSelector::ObjectPosSelector(float x,float y,float size,float dist) -: m_center_x(x),m_center_y(y),m_size(size),m_dist(dist) -{ - m_anglestep = acos(m_dist/(m_dist+2*m_size)); - - m_nextUsedPos[USED_POS_PLUS] = m_UsedPosLists[USED_POS_PLUS].end(); - m_nextUsedPos[USED_POS_MINUS] = m_UsedPosLists[USED_POS_MINUS].end(); - - m_smallStepAngle[USED_POS_PLUS] = 0; - m_smallStepAngle[USED_POS_MINUS] = 0; - - m_smallStepOk[USED_POS_PLUS] = false; - m_smallStepOk[USED_POS_MINUS] = false; - - m_smallStepNextUsedPos[USED_POS_PLUS] = NULL; - m_smallStepNextUsedPos[USED_POS_MINUS] = NULL; -} - -ObjectPosSelector::UsedPosList::value_type const* ObjectPosSelector::nextUsedPos(UsedPosType uptype) -{ - UsedPosList::const_iterator itr = m_nextUsedPos[uptype]; - if(itr!=m_UsedPosLists[uptype].end()) - ++itr; - - if(itr==m_UsedPosLists[uptype].end()) - { - if(!m_UsedPosLists[~uptype].empty()) - return &*m_UsedPosLists[~uptype].rbegin(); - else - return NULL; - } - else - return &*itr; -} - -void ObjectPosSelector::AddUsedPos(float size,float angle,float dist) -{ - if(angle>=0) - m_UsedPosLists[USED_POS_PLUS].insert(UsedPosList::value_type(angle,UsedPos(1.0,size,dist))); - else - m_UsedPosLists[USED_POS_MINUS].insert(UsedPosList::value_type(-angle,UsedPos(-1.0,size,dist))); -} - -void ObjectPosSelector::InitializeAngle() -{ - m_nextUsedPos[USED_POS_PLUS] = m_UsedPosLists[USED_POS_PLUS].begin(); - m_nextUsedPos[USED_POS_MINUS] = m_UsedPosLists[USED_POS_MINUS].begin(); - - m_smallStepAngle[USED_POS_PLUS] = 0; - m_smallStepAngle[USED_POS_MINUS] = 0; - - m_smallStepOk[USED_POS_PLUS] = true; - m_smallStepOk[USED_POS_MINUS] = true; -} - -bool ObjectPosSelector::FirstAngle(float& angle) -{ - if(m_UsedPosLists[USED_POS_PLUS].empty() && !m_UsedPosLists[USED_POS_MINUS].empty() ) - return NextAngleFor(*m_UsedPosLists[USED_POS_MINUS].begin(),1.0,USED_POS_PLUS,angle); - else if(m_UsedPosLists[USED_POS_MINUS].empty() && !m_UsedPosLists[USED_POS_PLUS].empty() ) - return NextAngleFor(*m_UsedPosLists[USED_POS_PLUS].begin(),-1.0,USED_POS_MINUS,angle); - - return false; -} - -bool ObjectPosSelector::NextAngle(float& angle) -{ - while(m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() || - m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end() || - m_smallStepOk[USED_POS_PLUS] || m_smallStepOk[USED_POS_MINUS] ) - { - // calculate next possible angle - if(NextPosibleAngle(angle)) - return true; - } - - return false; -} - -bool ObjectPosSelector::NextUsedAngle(float& angle) -{ - while(m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() || - m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end() ) - { - // calculate next possible angle - if(!NextPosibleAngle(angle)) - return true; - } - - return false; -} - -bool ObjectPosSelector::NextPosibleAngle( float& angle ) -{ - // ++ direction less updated - if( m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() && - (m_nextUsedPos[USED_POS_MINUS]==m_UsedPosLists[USED_POS_MINUS].end() || m_nextUsedPos[USED_POS_PLUS]->first <= m_nextUsedPos[USED_POS_MINUS]->first) ) - { - bool ok; - if(m_smallStepOk[USED_POS_PLUS]) - ok = NextSmallStepAngle(1.0,USED_POS_PLUS,angle); - else - ok = NextAngleFor(*m_nextUsedPos[USED_POS_PLUS],1.0,USED_POS_PLUS,angle); - - if(!ok) - ++m_nextUsedPos[USED_POS_PLUS]; // increase. only at fail (original or checked) - return ok; - } - // -- direction less updated - else if( m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end()) - { - bool ok; - if(m_smallStepOk[USED_POS_MINUS]) - ok = NextSmallStepAngle(-1.0,USED_POS_MINUS,angle); - else - ok = NextAngleFor(*m_nextUsedPos[USED_POS_MINUS],-1.0,USED_POS_MINUS,angle); - - if(!ok) - ++m_nextUsedPos[USED_POS_MINUS]; - return ok; - } - else // both list empty - { - if( m_smallStepOk[USED_POS_PLUS] && (!m_smallStepOk[USED_POS_MINUS] || m_smallStepAngle[USED_POS_PLUS] <= m_smallStepAngle[USED_POS_MINUS]) ) - { - return NextSmallStepAngle(1.0,USED_POS_PLUS,angle); - } - // -- direction less updated - else if( m_smallStepOk[USED_POS_MINUS] ) - { - return NextSmallStepAngle(-1.0,USED_POS_MINUS,angle); - } - } - - // no angles - return false; -} diff --git a/src/server/game/Map/ObjectPosSelector.h b/src/server/game/Map/ObjectPosSelector.h deleted file mode 100644 index 84050611121..00000000000 --- a/src/server/game/Map/ObjectPosSelector.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _OBJECT_POS_SELECTOR_H -#define _OBJECT_POS_SELECTOR_H - -#include - -#include - -enum UsedPosType { USED_POS_PLUS, USED_POS_MINUS }; - -inline UsedPosType operator ~(UsedPosType uptype) -{ - return uptype==USED_POS_PLUS ? USED_POS_MINUS : USED_POS_PLUS; -} - -struct ObjectPosSelector -{ - struct UsedPos - { - UsedPos(float sign_, float size_,float dist_) : sign(sign_), size(size_),dist(dist_) {} - - float sign; - - float size; // size of point - float dist; // dist to central point (including central point size) - }; - - typedef std::multimap UsedPosList; // abs(angle)->Node - - ObjectPosSelector(float x,float y,float size,float dist); - - void AddUsedPos(float size,float angle,float dist); - void InitializeAngle(); - - bool FirstAngle(float& angle); - bool NextAngle(float& angle); - bool NextUsedAngle(float& angle); - - bool NextPosibleAngle( float& angle ); - - bool CheckAngle(UsedPosList::value_type const& nextUsedPos, float sign, float angle ) const - { - float angle_step2 = GetAngle(nextUsedPos.second); - - float next_angle = nextUsedPos.first; - if(nextUsedPos.second.sign * sign < 0) // last node from diff. list (-pi+alpha) - next_angle = 2*M_PI-next_angle; // move to positive - - return fabs(angle)+angle_step2 <= next_angle; - } - - bool CheckOriginal() const - { - return (m_UsedPosLists[USED_POS_PLUS].empty() || CheckAngle( *m_UsedPosLists[USED_POS_PLUS].begin(),1.0,0)) && - (m_UsedPosLists[USED_POS_MINUS].empty() || CheckAngle( *m_UsedPosLists[USED_POS_MINUS].begin(),-1.0,0)); - } - - bool IsNonBalanced() const { return m_UsedPosLists[USED_POS_PLUS].empty() != m_UsedPosLists[USED_POS_MINUS].empty(); } - - bool NextAngleFor( UsedPosList::value_type const& usedPos, float sign, UsedPosType uptype, float &angle ) - { - float angle_step = GetAngle(usedPos.second); - - // next possible angle - angle = usedPos.first * usedPos.second.sign + angle_step * sign; - - UsedPosList::value_type const* nextNode = nextUsedPos(uptype); - if(nextNode) - { - // if next node permit use selected angle, then do it - if(!CheckAngle(*nextNode, sign, angle)) - { - m_smallStepOk[uptype] = false; - return false; - } - } - - // possible more points - m_smallStepOk[uptype] = true; - m_smallStepAngle[uptype] = angle; - m_smallStepNextUsedPos[uptype] = nextNode; - - return true; - } - - bool NextSmallStepAngle( float sign, UsedPosType uptype, float &angle ) - { - // next possible angle - angle = m_smallStepAngle[uptype] + m_anglestep * sign; - - if(fabs(angle) > M_PI) - { - m_smallStepOk[uptype] = false; - return false; - } - - if(m_smallStepNextUsedPos[uptype]) - { - if(fabs(angle) >= m_smallStepNextUsedPos[uptype]->first) - { - m_smallStepOk[uptype] = false; - return false; - } - - // if next node permit use selected angle, then do it - if(!CheckAngle(*m_smallStepNextUsedPos[uptype], sign, angle)) - { - m_smallStepOk[uptype] = false; - return false; - } - } - - // possible more points - m_smallStepAngle[uptype] = angle; - return true; - } - - // next used post for m_nextUsedPos[uptype] - UsedPosList::value_type const* nextUsedPos(UsedPosType uptype); - - // angle from used pos to next possible free pos - float GetAngle(UsedPos const& usedPos) const { return acos(m_dist/(usedPos.dist+usedPos.size+m_size)); } - - float m_center_x; - float m_center_y; - float m_size; // size of object in center - float m_dist; // distance for searching pos (including central object size) - float m_anglestep; - - UsedPosList m_UsedPosLists[2]; - UsedPosList::const_iterator m_nextUsedPos[2]; - - // field for small step from first after next used pos until next pos - float m_smallStepAngle[2]; - bool m_smallStepOk[2]; - UsedPosList::value_type const* m_smallStepNextUsedPos[2]; -}; -#endif diff --git a/src/server/game/Map/ZoneScript.h b/src/server/game/Map/ZoneScript.h deleted file mode 100644 index ab74c8aa5d4..00000000000 --- a/src/server/game/Map/ZoneScript.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef ZONE_SCRIPT_H_ -#define ZONE_SCRIPT_H_ - -#include "Common.h" -#include "Creature.h" - -//struct CreatureData; -class Creature; -class GameObject; - -class ZoneScript -{ - public: - explicit ZoneScript() {} - - virtual uint32 GetCreatureEntry(uint32 /*guidlow*/, const CreatureData *data) { return data->id; } - virtual uint32 GetGameObjectEntry(uint32 /*guidlow*/, uint32 entry) { return entry; } - - virtual void OnCreatureCreate(Creature *, bool /*add*/) {} - virtual void OnGameObjectCreate(GameObject * /*go*/, bool /*add*/) {} - - //All-purpose data storage 64 bit - virtual uint64 GetData64(uint32 /*DataId*/) { return 0; } - virtual void SetData64(uint32 /*DataId*/, uint64 /*Value*/) {} - - //All-purpose data storage 32 bit - virtual uint32 GetData(uint32 /*DataId*/) { return 0; } - virtual void SetData(uint32 /*DataId*/, uint32 /*Value*/) {} - - virtual void ProcessEvent(GameObject * /*obj*/, uint32 /*eventId*/) {} -}; - -#endif \ No newline at end of file diff --git a/src/server/game/Maps/Cell/Cell.h b/src/server/game/Maps/Cell/Cell.h new file mode 100644 index 00000000000..49e0329ace6 --- /dev/null +++ b/src/server/game/Maps/Cell/Cell.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_CELL_H +#define TRINITY_CELL_H + +#include + +#include "GameSystem/TypeContainer.h" +#include "GameSystem/TypeContainerVisitor.h" + +#include "GridDefines.h" + +class Map; +class WorldObject; + +enum District +{ + UPPER_DISTRICT = 1, + LOWER_DISTRICT = 1 << 1, + LEFT_DISTRICT = 1 << 2, + RIGHT_DISTRICT = 1 << 3, + CENTER_DISTRICT = 1 << 4, + UPPER_LEFT_DISTRICT = (UPPER_DISTRICT | LEFT_DISTRICT), + UPPER_RIGHT_DISTRICT = (UPPER_DISTRICT | RIGHT_DISTRICT), + LOWER_LEFT_DISTRICT = (LOWER_DISTRICT | LEFT_DISTRICT), + LOWER_RIGHT_DISTRICT = (LOWER_DISTRICT | RIGHT_DISTRICT), + ALL_DISTRICT = (UPPER_DISTRICT | LOWER_DISTRICT | LEFT_DISTRICT | RIGHT_DISTRICT | CENTER_DISTRICT) +}; + +struct CellArea +{ + CellArea() : right_offset(0), left_offset(0), upper_offset(0), lower_offset(0) {} + CellArea(int right, int left, int upper, int lower) : right_offset(right), left_offset(left), upper_offset(upper), lower_offset(lower) {} + bool operator!() const { return !right_offset && !left_offset && !upper_offset && !lower_offset; } + + void ResizeBorders(CellPair& begin_cell, CellPair& end_cell) const + { + begin_cell << left_offset; + begin_cell -= lower_offset; + end_cell >> right_offset; + end_cell += upper_offset; + } + + int right_offset; + int left_offset; + int upper_offset; + int lower_offset; +}; + +struct Cell +{ + Cell() { data.All = 0; } + Cell(const Cell &cell) { data.All = cell.data.All; } + explicit Cell(CellPair const& p); + + void operator|=(Cell &cell) + { + data.Part.reserved = 0; + cell.data.Part.reserved = 0; + uint32 x, y, old_x, old_y; + Compute(x, y); + cell.Compute(old_x, old_y); + + if (std::abs(int(x-old_x)) > 1 || std::abs(int(y-old_y)) > 1) + { + data.Part.reserved = ALL_DISTRICT; + cell.data.Part.reserved = ALL_DISTRICT; + return; + } + + if (x < old_x) + { + data.Part.reserved |= LEFT_DISTRICT; + cell.data.Part.reserved |= RIGHT_DISTRICT; + } + else if (old_x < x) + { + data.Part.reserved |= RIGHT_DISTRICT; + cell.data.Part.reserved |= LEFT_DISTRICT; + } + if (y < old_y) + { + data.Part.reserved |= UPPER_DISTRICT; + cell.data.Part.reserved |= LOWER_DISTRICT; + } + else if (old_y < y) + { + data.Part.reserved |= LOWER_DISTRICT; + cell.data.Part.reserved |= UPPER_DISTRICT; + } + } + + void Compute(uint32 &x, uint32 &y) const + { + x = data.Part.grid_x*MAX_NUMBER_OF_CELLS + data.Part.cell_x; + y = data.Part.grid_y*MAX_NUMBER_OF_CELLS + data.Part.cell_y; + } + + bool DiffCell(const Cell &cell) const + { + return(data.Part.cell_x != cell.data.Part.cell_x || + data.Part.cell_y != cell.data.Part.cell_y); + } + + bool DiffGrid(const Cell &cell) const + { + return(data.Part.grid_x != cell.data.Part.grid_x || + data.Part.grid_y != cell.data.Part.grid_y); + } + + uint32 CellX() const { return data.Part.cell_x; } + uint32 CellY() const { return data.Part.cell_y; } + uint32 GridX() const { return data.Part.grid_x; } + uint32 GridY() const { return data.Part.grid_y; } + bool NoCreate() const { return data.Part.nocreate; } + void SetNoCreate() { data.Part.nocreate = 1; } + + CellPair cellPair() const + { + return CellPair( + data.Part.grid_x*MAX_NUMBER_OF_CELLS+data.Part.cell_x, + data.Part.grid_y*MAX_NUMBER_OF_CELLS+data.Part.cell_y); + } + + Cell& operator=(const Cell &cell) + { + this->data.All = cell.data.All; + return *this; + } + + bool operator == (const Cell &cell) const { return (data.All == cell.data.All); } + bool operator != (const Cell &cell) const { return !operator == (cell); } + union + { + struct + { + unsigned grid_x : 6; + unsigned grid_y : 6; + unsigned cell_x : 6; + unsigned cell_y : 6; + unsigned nocreate : 1; + unsigned reserved : 7; + } Part; + uint32 All; + } data; + + template void Visit(const CellPair&, TypeContainerVisitor &visitor, Map &) const; + template void Visit(const CellPair&, TypeContainerVisitor &visitor, Map &, const WorldObject&, float) const; + template void Visit(const CellPair&, TypeContainerVisitor &visitor, Map &, float, float, float) const; + + static CellArea CalculateCellArea(const WorldObject &obj, float radius); + static CellArea CalculateCellArea(float x, float y, float radius); + +private: + template void VisitCircle(TypeContainerVisitor &, Map &, const CellPair&, const CellPair&) const; +}; + +#endif + diff --git a/src/server/game/Maps/Cell/CellImpl.h b/src/server/game/Maps/Cell/CellImpl.h new file mode 100644 index 00000000000..d906e81a5c9 --- /dev/null +++ b/src/server/game/Maps/Cell/CellImpl.h @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_CELLIMPL_H +#define TRINITY_CELLIMPL_H + +#include + +#include "Cell.h" +#include "Map.h" +#include "Object.h" + +inline Cell::Cell(CellPair const& p) +{ + data.Part.grid_x = p.x_coord / MAX_NUMBER_OF_CELLS; + data.Part.grid_y = p.y_coord / MAX_NUMBER_OF_CELLS; + data.Part.cell_x = p.x_coord % MAX_NUMBER_OF_CELLS; + data.Part.cell_y = p.y_coord % MAX_NUMBER_OF_CELLS; + data.Part.nocreate = 0; + data.Part.reserved = 0; +} + +template +inline void +Cell::Visit(const CellPair& standing_cell, TypeContainerVisitor &visitor, Map &m) const +{ + if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + return; + + uint16 district = (District)this->data.Part.reserved; + if (district == CENTER_DISTRICT) + { + m.Visit(*this, visitor); + return; + } + + // set up the cell range based on the district + // the overloaded operators handle range checking + CellPair begin_cell = standing_cell; + CellPair end_cell = standing_cell; + + switch(district) + { + case ALL_DISTRICT: + { + begin_cell << 1; begin_cell -= 1; // upper left + end_cell >> 1; end_cell += 1; // lower right + break; + } + case UPPER_LEFT_DISTRICT: + { + begin_cell << 1; begin_cell -= 1; // upper left + break; + } + case UPPER_RIGHT_DISTRICT: + { + begin_cell -= 1; // up + end_cell >> 1; // right + break; + } + case LOWER_LEFT_DISTRICT: + { + begin_cell << 1; // left + end_cell += 1; // down + break; + } + case LOWER_RIGHT_DISTRICT: + { + end_cell >> 1; end_cell += 1; // lower right + break; + } + case LEFT_DISTRICT: + { + begin_cell -= 1; // up + end_cell >> 1; end_cell += 1; // lower right + break; + } + case RIGHT_DISTRICT: + { + begin_cell << 1; begin_cell -= 1; // upper left + end_cell += 1; // down + break; + } + case UPPER_DISTRICT: + { + begin_cell << 1; begin_cell -= 1; // upper left + end_cell >> 1; // right + break; + } + case LOWER_DISTRICT: + { + begin_cell << 1; // left + end_cell >> 1; end_cell += 1; // lower right + break; + } + default: + { + assert(false); + break; + } + } + + // loop the cell range + for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; x++) + { + for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; y++) + { + CellPair cell_pair(x,y); + Cell r_zone(cell_pair); + r_zone.data.Part.nocreate = this->data.Part.nocreate; + m.Visit(r_zone, visitor); + } + } +} + +inline int CellHelper(const float radius) +{ + if (radius < 1.0f) + return 0; + + return (int)ceilf(radius/SIZE_OF_GRID_CELL); +} + +inline CellArea Cell::CalculateCellArea(const WorldObject &obj, float radius) +{ + return Cell::CalculateCellArea(obj.GetPositionX(), obj.GetPositionY(), radius); +} + +inline CellArea Cell::CalculateCellArea(float x, float y, float radius) +{ + if (radius <= 0.0f) + return CellArea(); + + //lets calculate object coord offsets from cell borders. + //TODO: add more correct/generic method for this task + const float x_offset = (x - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL; + const float y_offset = (y - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL; + + const float x_val = floor(x_offset + CENTER_GRID_CELL_ID + 0.5f); + const float y_val = floor(y_offset + CENTER_GRID_CELL_ID + 0.5f); + + const float x_off = (x_offset - x_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL; + const float y_off = (y_offset - y_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL; + + const float tmp_diff = radius - CENTER_GRID_CELL_OFFSET; + //lets calculate upper/lower/right/left corners for cell search + int right = CellHelper(tmp_diff + x_off); + int left = CellHelper(tmp_diff - x_off); + int upper = CellHelper(tmp_diff + y_off); + int lower = CellHelper(tmp_diff - y_off); + + return CellArea(right, left, upper, lower); +} + +template +inline void +Cell::Visit(const CellPair& standing_cell, TypeContainerVisitor &visitor, Map &m, float radius, float x_off, float y_off) const +{ + if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + return; + + //no jokes here... Actually placing ASSERT() here was good idea, but + //we had some problems with DynamicObjects, which pass radius = 0.0f (DB issue?) + //maybe it is better to just return when radius <= 0.0f? + if (radius <= 0.0f) + { + m.Visit(*this, visitor); + return; + } + //lets limit the upper value for search radius + if (radius > 333.0f) + radius = 333.0f; + + //lets calculate object coord offsets from cell borders. + CellArea area = Cell::CalculateCellArea(x_off, y_off, radius); + //if radius fits inside standing cell + if (!area) + { + m.Visit(*this, visitor); + return; + } + + CellPair begin_cell = standing_cell; + CellPair end_cell = standing_cell; + + area.ResizeBorders(begin_cell, end_cell); + //visit all cells, found in CalculateCellArea() + //if radius is known to reach cell area more than 4x4 then we should call optimized VisitCircle + //currently this technique works with MAX_NUMBER_OF_CELLS 16 and higher, with lower values + //there are nothing to optimize because SIZE_OF_GRID_CELL is too big... + if (((end_cell.x_coord - begin_cell.x_coord) > 4) && ((end_cell.y_coord - begin_cell.y_coord) > 4)) + { + VisitCircle(visitor, m, begin_cell, end_cell); + return; + } + + //ALWAYS visit standing cell first!!! Since we deal with small radiuses + //it is very essential to call visitor for standing cell firstly... + m.Visit(*this, visitor); + + // loop the cell range + for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x) + { + for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y) + { + CellPair cell_pair(x,y); + //lets skip standing cell since we already visited it + if (cell_pair != standing_cell) + { + Cell r_zone(cell_pair); + r_zone.data.Part.nocreate = this->data.Part.nocreate; + m.Visit(r_zone, visitor); + } + } + } +} + +template +inline void +Cell::Visit(const CellPair& l, TypeContainerVisitor &visitor, Map &m, const WorldObject &obj, float radius) const +{ + //we should increase search radius by object's radius, otherwise + //we could have problems with huge creatures, which won't attack nearest players etc + Visit(l, visitor, m, radius + obj.GetObjectSize(), obj.GetPositionX(), obj.GetPositionY()); +} + +template +inline void +Cell::VisitCircle(TypeContainerVisitor &visitor, Map &m, const CellPair& begin_cell, const CellPair& end_cell) const +{ + //here is an algorithm for 'filling' circum-squared octagon + uint32 x_shift = (uint32)ceilf((end_cell.x_coord - begin_cell.x_coord) * 0.3f - 0.5f); + //lets calculate x_start/x_end coords for central strip... + const uint32 x_start = begin_cell.x_coord + x_shift; + const uint32 x_end = end_cell.x_coord - x_shift; + + //visit central strip with constant width... + for (uint32 x = x_start; x <= x_end; ++x) + { + for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y) + { + CellPair cell_pair(x,y); + Cell r_zone(cell_pair); + r_zone.data.Part.nocreate = this->data.Part.nocreate; + m.Visit(r_zone, visitor); + } + } + + //if x_shift == 0 then we have too small cell area, which were already + //visited at previous step, so just return from procedure... + if (x_shift == 0) + return; + + uint32 y_start = end_cell.y_coord; + uint32 y_end = begin_cell.y_coord; + //now we are visiting borders of an octagon... + for (uint32 step = 1; step <= (x_start - begin_cell.x_coord); ++step) + { + //each step reduces strip height by 2 cells... + y_end += 1; + y_start -= 1; + for (uint32 y = y_start; y >= y_end; --y) + { + //we visit cells symmetrically from both sides, heading from center to sides and from up to bottom + //e.g. filling 2 trapezoids after filling central cell strip... + CellPair cell_pair_left(x_start - step, y); + Cell r_zone_left(cell_pair_left); + r_zone_left.data.Part.nocreate = this->data.Part.nocreate; + m.Visit(r_zone_left, visitor); + + //right trapezoid cell visit + CellPair cell_pair_right(x_end + step, y); + Cell r_zone_right(cell_pair_right); + r_zone_right.data.Part.nocreate = this->data.Part.nocreate; + m.Visit(r_zone_right, visitor); + } + } +} +#endif + diff --git a/src/server/game/Maps/Grid/GridDefines.h b/src/server/game/Maps/Grid/GridDefines.h new file mode 100644 index 00000000000..5269d0a094d --- /dev/null +++ b/src/server/game/Maps/Grid/GridDefines.h @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_GRIDDEFINES_H +#define TRINITY_GRIDDEFINES_H + +#include "Common.h" +#include "GameSystem/NGrid.h" +#include + +// Forward class definitions +class Corpse; +class Creature; +class DynamicObject; +class GameObject; +class Pet; +class Player; + +#define MAX_NUMBER_OF_CELLS 8 + +#define MAX_NUMBER_OF_GRIDS 64 + +#define SIZE_OF_GRIDS 533.33333f +#define CENTER_GRID_ID (MAX_NUMBER_OF_GRIDS/2) + +#define CENTER_GRID_OFFSET (SIZE_OF_GRIDS/2) + +#define MIN_GRID_DELAY (MINUTE*IN_MILISECONDS) +#define MIN_MAP_UPDATE_DELAY 50 + +#define SIZE_OF_GRID_CELL (SIZE_OF_GRIDS/MAX_NUMBER_OF_CELLS) + +#define CENTER_GRID_CELL_ID (MAX_NUMBER_OF_CELLS*MAX_NUMBER_OF_GRIDS/2) +#define CENTER_GRID_CELL_OFFSET (SIZE_OF_GRID_CELL/2) + +#define TOTAL_NUMBER_OF_CELLS_PER_MAP (MAX_NUMBER_OF_GRIDS*MAX_NUMBER_OF_CELLS) + +#define MAP_RESOLUTION 128 + +#define MAP_SIZE (SIZE_OF_GRIDS*MAX_NUMBER_OF_GRIDS) +#define MAP_HALFSIZE (MAP_SIZE/2) + +// Creature used instead pet to simplify *::Visit templates (not required duplicate code for Creature->Pet case) +typedef TYPELIST_4(Player, Creature/*pets*/, Corpse/*resurrectable*/, DynamicObject/*farsight target*/) AllWorldObjectTypes; +typedef TYPELIST_4(GameObject, Creature/*except pets*/, DynamicObject, Corpse/*Bones*/) AllGridObjectTypes; + +typedef GridRefManager CorpseMapType; +typedef GridRefManager CreatureMapType; +typedef GridRefManager DynamicObjectMapType; +typedef GridRefManager GameObjectMapType; +typedef GridRefManager PlayerMapType; + +typedef Grid GridType; +typedef NGrid NGridType; + +typedef TypeMapContainer GridTypeMapContainer; +typedef TypeMapContainer WorldTypeMapContainer; + +template +struct CoordPair +{ + CoordPair(uint32 x=0, uint32 y=0) : x_coord(x), y_coord(y) {} + CoordPair(const CoordPair &obj) : x_coord(obj.x_coord), y_coord(obj.y_coord) {} + bool operator == (const CoordPair &obj) const { return (obj.x_coord == x_coord && obj.y_coord == y_coord); } + bool operator != (const CoordPair &obj) const { return !operator == (obj); } + CoordPair& operator=(const CoordPair &obj) + { + x_coord = obj.x_coord; + y_coord = obj.y_coord; + return *this; + } + + void operator<<(const uint32 val) + { + if (x_coord > val) + x_coord -= val; + else + x_coord = 0; + } + + void operator>>(const uint32 val) + { + if (x_coord+val < LIMIT) + x_coord += val; + else + x_coord = LIMIT - 1; + } + + void operator-=(const uint32 val) + { + if (y_coord > val) + y_coord -= val; + else + y_coord = 0; + } + + void operator+=(const uint32 val) + { + if (y_coord+val < LIMIT) + y_coord += val; + else + y_coord = LIMIT - 1; + } + + uint32 x_coord; + uint32 y_coord; +}; + +typedef CoordPair GridPair; +typedef CoordPair CellPair; + +namespace Trinity +{ + template + inline RET_TYPE Compute(float x, float y, float center_offset, float size) + { + // calculate and store temporary values in double format for having same result as same mySQL calculations + double x_offset = (double(x) - center_offset)/size; + double y_offset = (double(y) - center_offset)/size; + + int x_val = int(x_offset+CENTER_VAL + 0.5); + int y_val = int(y_offset+CENTER_VAL + 0.5); + return RET_TYPE(x_val, y_val); + } + + inline GridPair ComputeGridPair(float x, float y) + { + return Compute(x, y, CENTER_GRID_OFFSET, SIZE_OF_GRIDS); + } + + inline CellPair ComputeCellPair(float x, float y) + { + return Compute(x, y, CENTER_GRID_CELL_OFFSET, SIZE_OF_GRID_CELL); + } + + inline CellPair ComputeCellPair(float x, float y, float &x_off, float &y_off) + { + double x_offset = (double(x) - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL; + double y_offset = (double(y) - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL; + + int x_val = int(x_offset + CENTER_GRID_CELL_ID + 0.5); + int y_val = int(y_offset + CENTER_GRID_CELL_ID + 0.5); + x_off = (float(x_offset) - x_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL; + y_off = (float(y_offset) - y_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL; + return CellPair(x_val, y_val); + } + + inline void NormalizeMapCoord(float &c) + { + if (c > MAP_HALFSIZE - 0.5) + c = MAP_HALFSIZE - 0.5; + else if (c < -(MAP_HALFSIZE - 0.5)) + c = -(MAP_HALFSIZE - 0.5); + } + + inline bool IsValidMapCoord(float c) + { + return finite(c) && (std::fabs(c) <= MAP_HALFSIZE - 0.5); + } + + inline bool IsValidMapCoord(float x, float y) + { + return IsValidMapCoord(x) && IsValidMapCoord(y); + } + + inline bool IsValidMapCoord(float x, float y, float z) + { + return IsValidMapCoord(x,y) && finite(z); + } + + inline bool IsValidMapCoord(float x, float y, float z, float o) + { + return IsValidMapCoord(x,y,z) && finite(o); + } +} +#endif diff --git a/src/server/game/Maps/Grid/GridNotifiers.cpp b/src/server/game/Maps/Grid/GridNotifiers.cpp new file mode 100644 index 00000000000..b10dfa8791e --- /dev/null +++ b/src/server/game/Maps/Grid/GridNotifiers.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "UpdateData.h" +#include "Item.h" +#include "Map.h" +#include "Transports.h" +#include "ObjectAccessor.h" +#include "CellImpl.h" + +using namespace Trinity; + +void +VisibleNotifier::SendToSelf() +{ + // at this moment i_clientGUIDs have guids that not iterate at grid level checks + // but exist one case when this possible and object not out of range: transports + if (Transport* transport = i_player.GetTransport()) + for (Transport::PlayerSet::const_iterator itr = transport->GetPassengers().begin();itr != transport->GetPassengers().end();++itr) + { + if (vis_guids.find((*itr)->GetGUID()) != vis_guids.end()) + { + vis_guids.erase((*itr)->GetGUID()); + + i_player.UpdateVisibilityOf((*itr), i_data, i_visibleNow); + + if (!(*itr)->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) + (*itr)->UpdateVisibilityOf(&i_player); + } + } + + for (Player::ClientGUIDs::const_iterator it = vis_guids.begin();it != vis_guids.end(); ++it) + { + i_player.m_clientGUIDs.erase(*it); + i_data.AddOutOfRangeGUID(*it); + + if (IS_PLAYER_GUID(*it)) + { + Player* plr = ObjectAccessor::FindPlayer(*it); + if (plr && plr->IsInWorld() && !plr->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) + plr->UpdateVisibilityOf(&i_player); + } + } + + if (!i_data.HasData()) + return; + + WorldPacket packet; + i_data.BuildPacket(&packet); + i_player.GetSession()->SendPacket(&packet); + + for (std::set::const_iterator it = i_visibleNow.begin(); it != i_visibleNow.end(); ++it) + i_player.SendInitialVisiblePackets(*it); +} + +void +VisibleChangesNotifier::Visit(PlayerMapType &m) +{ + for (PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + { + if (iter->getSource() == &i_object) + continue; + + iter->getSource()->UpdateVisibilityOf(&i_object); + + if (!iter->getSource()->GetSharedVisionList().empty()) + for (SharedVisionList::const_iterator i = iter->getSource()->GetSharedVisionList().begin(); + i != iter->getSource()->GetSharedVisionList().end(); ++i) + if ((*i)->m_seer == iter->getSource()) + (*i)->UpdateVisibilityOf(&i_object); + } +} + +void +VisibleChangesNotifier::Visit(CreatureMapType &m) +{ + for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) + if (!iter->getSource()->GetSharedVisionList().empty()) + for (SharedVisionList::const_iterator i = iter->getSource()->GetSharedVisionList().begin(); + i != iter->getSource()->GetSharedVisionList().end(); ++i) + if ((*i)->m_seer == iter->getSource()) + (*i)->UpdateVisibilityOf(&i_object); +} + +void +VisibleChangesNotifier::Visit(DynamicObjectMapType &m) +{ + for (DynamicObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter) + if (IS_PLAYER_GUID(iter->getSource()->GetCasterGUID())) + if (Player* caster = (Player*)iter->getSource()->GetCaster()) + if (caster->m_seer == iter->getSource()) + caster->UpdateVisibilityOf(&i_object); +} + +inline void CreatureUnitRelocationWorker(Creature* c, Unit* u) +{ + if (!u->isAlive() || !c->isAlive() || c == u || u->isInFlight()) + return; + + if (c->HasReactState(REACT_AGGRESSIVE) && !c->hasUnitState(UNIT_STAT_SIGHTLESS)) + if (c->_IsWithinDist(u, c->m_SightDistance, true) && c->IsAIEnabled) + c->AI()->MoveInLineOfSight_Safe(u); +} + +void PlayerRelocationNotifier::Visit(PlayerMapType &m) +{ + for (PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + { + Player* plr = iter->getSource(); + + vis_guids.erase(plr->GetGUID()); + + i_player.UpdateVisibilityOf(plr,i_data,i_visibleNow); + + if (plr->m_seer->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) + continue; + + plr->UpdateVisibilityOf(&i_player); + } +} + +void PlayerRelocationNotifier::Visit(CreatureMapType &m) +{ + bool relocated_for_ai = (&i_player == i_player.m_seer); + + for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + { + Creature * c = iter->getSource(); + + vis_guids.erase(c->GetGUID()); + + i_player.UpdateVisibilityOf(c,i_data,i_visibleNow); + + if (relocated_for_ai && !c->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) + CreatureUnitRelocationWorker(c, &i_player); + } +} + +void CreatureRelocationNotifier::Visit(PlayerMapType &m) +{ + for (PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + { + Player * pl = iter->getSource(); + + if (!pl->m_seer->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) + pl->UpdateVisibilityOf(&i_creature); + + CreatureUnitRelocationWorker(&i_creature, pl); + } +} + +void CreatureRelocationNotifier::Visit(CreatureMapType &m) +{ + if (!i_creature.isAlive()) + return; + + for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + { + Creature* c = iter->getSource(); + CreatureUnitRelocationWorker(&i_creature, c); + + if (!c->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) + CreatureUnitRelocationWorker(c, &i_creature); + } +} + +void DelayedUnitRelocation::Visit(CreatureMapType &m) +{ + for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) + { + Creature * unit = iter->getSource(); + if (!unit->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) + continue; + + CreatureRelocationNotifier relocate(*unit); + + TypeContainerVisitor c2world_relocation(relocate); + TypeContainerVisitor c2grid_relocation(relocate); + + cell.Visit(p, c2world_relocation, i_map, *unit, i_radius); + cell.Visit(p, c2grid_relocation, i_map, *unit, i_radius); + } +} + +void DelayedUnitRelocation::Visit(PlayerMapType &m) +{ + for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter) + { + Player * player = iter->getSource(); + WorldObject const *viewPoint = player->m_seer; + + if (!viewPoint->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) + continue; + + if (player != viewPoint && !viewPoint->IsPositionValid()) + continue; + + CellPair pair2(Trinity::ComputeCellPair(viewPoint->GetPositionX(), viewPoint->GetPositionY())); + Cell cell2(pair2); + //cell.SetNoCreate(); need load cells around viewPoint or player, that's why its commented + + PlayerRelocationNotifier relocate(*player); + TypeContainerVisitor c2world_relocation(relocate); + TypeContainerVisitor c2grid_relocation(relocate); + + cell2.Visit(pair2, c2world_relocation, i_map, *viewPoint, i_radius); + cell2.Visit(pair2, c2grid_relocation, i_map, *viewPoint, i_radius); + + relocate.SendToSelf(); + } +} + +void AIRelocationNotifier::Visit(CreatureMapType &m) +{ + for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) + { + Creature *c = iter->getSource(); + CreatureUnitRelocationWorker(c, &i_unit); + if (isCreature) + CreatureUnitRelocationWorker((Creature*)&i_unit, c); + } +} + +void +MessageDistDeliverer::Visit(PlayerMapType &m) +{ + for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter) + { + Player *target = iter->getSource(); + if (!target->InSamePhase(i_phaseMask)) + continue; + + if (target->GetExactDistSq(i_source) > i_distSq) + continue; + + // Send packet to all who are sharing the player's vision + if (!target->GetSharedVisionList().empty()) + { + SharedVisionList::const_iterator i = target->GetSharedVisionList().begin(); + for (; i != target->GetSharedVisionList().end(); ++i) + if ((*i)->m_seer == target) + SendPacket(*i); + } + + if (target->m_seer == target || target->GetVehicle()) + SendPacket(target); + } +} + +void +MessageDistDeliverer::Visit(CreatureMapType &m) +{ + for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) + { + if (!iter->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (iter->getSource()->GetExactDistSq(i_source) > i_distSq) + continue; + + // Send packet to all who are sharing the creature's vision + if (!iter->getSource()->GetSharedVisionList().empty()) + { + SharedVisionList::const_iterator i = iter->getSource()->GetSharedVisionList().begin(); + for (; i != iter->getSource()->GetSharedVisionList().end(); ++i) + if ((*i)->m_seer == iter->getSource()) + SendPacket(*i); + } + } +} + +void +MessageDistDeliverer::Visit(DynamicObjectMapType &m) +{ + for (DynamicObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter) + { + if (!iter->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (iter->getSource()->GetExactDistSq(i_source) > i_distSq) + continue; + + if (IS_PLAYER_GUID(iter->getSource()->GetCasterGUID())) + { + // Send packet back to the caster if the caster has vision of dynamic object + Player* caster = (Player*)iter->getSource()->GetCaster(); + if (caster && caster->m_seer == iter->getSource()) + SendPacket(caster); + } + } +} + +/* +void +MessageDistDeliverer::VisitObject(Player* plr) +{ + if (!i_ownTeamOnly || (i_source.GetTypeId() == TYPEID_PLAYER && plr->GetTeam() == ((Player&)i_source).GetTeam())) + { + SendPacket(plr); + } +} +*/ + +template void +ObjectUpdater::Visit(GridRefManager &m) +{ + for (typename GridRefManager::iterator iter = m.begin(); iter != m.end(); ++iter) + { + if (iter->getSource()->IsInWorld()) + iter->getSource()->Update(i_timeDiff); + } +} + +bool CannibalizeObjectCheck::operator()(Corpse* u) +{ + // ignore bones + if (u->GetType() == CORPSE_BONES) + return false; + + Player* owner = ObjectAccessor::FindPlayer(u->GetOwnerGUID()); + + if (!owner || i_funit->IsFriendlyTo(owner)) + return false; + + if (i_funit->IsWithinDistInMap(u, i_range)) + return true; + + return false; +} + +template void ObjectUpdater::Visit(GameObjectMapType &); +template void ObjectUpdater::Visit(DynamicObjectMapType &); diff --git a/src/server/game/Maps/Grid/GridNotifiers.h b/src/server/game/Maps/Grid/GridNotifiers.h new file mode 100644 index 00000000000..b0abf0aae79 --- /dev/null +++ b/src/server/game/Maps/Grid/GridNotifiers.h @@ -0,0 +1,1232 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_GRIDNOTIFIERS_H +#define TRINITY_GRIDNOTIFIERS_H + +#include "ObjectGridLoader.h" +#include "UpdateData.h" +#include + +#include "Corpse.h" +#include "Object.h" +#include "DynamicObject.h" +#include "GameObject.h" +#include "Player.h" +#include "Unit.h" +#include "CreatureAI.h" + +class Player; +//class Map; + +namespace Trinity +{ + struct VisibleNotifier + { + Player &i_player; + UpdateData i_data; + std::set i_visibleNow; + Player::ClientGUIDs vis_guids; + + VisibleNotifier(Player &player) : i_player(player), vis_guids(player.m_clientGUIDs) {} + template void Visit(GridRefManager &m); + void SendToSelf(void); + }; + + struct VisibleChangesNotifier + { + WorldObject &i_object; + + explicit VisibleChangesNotifier(WorldObject &object) : i_object(object) {} + template void Visit(GridRefManager &) {} + void Visit(PlayerMapType &); + void Visit(CreatureMapType &); + void Visit(DynamicObjectMapType &); + }; + + struct PlayerRelocationNotifier : public VisibleNotifier + { + PlayerRelocationNotifier(Player &pl) : VisibleNotifier(pl) {} + + template void Visit(GridRefManager &m) { VisibleNotifier::Visit(m); } + void Visit(CreatureMapType &); + void Visit(PlayerMapType &); + }; + + struct CreatureRelocationNotifier + { + Creature &i_creature; + CreatureRelocationNotifier(Creature &c) : i_creature(c) {} + template void Visit(GridRefManager &) {} + void Visit(CreatureMapType &); + void Visit(PlayerMapType &); + }; + + struct DelayedUnitRelocation + { + Map &i_map; + Cell &cell; + CellPair &p; + const float i_radius; + DelayedUnitRelocation(Cell &c, CellPair &pair, Map &map, float radius) : + cell(c), p(pair), i_map(map), i_radius(radius) {} + template void Visit(GridRefManager &) {} + void Visit(CreatureMapType &); + void Visit(PlayerMapType &); + }; + + struct AIRelocationNotifier + { + Unit &i_unit; + bool isCreature; + explicit AIRelocationNotifier(Unit &unit) : i_unit(unit), isCreature(unit.GetTypeId() == TYPEID_UNIT) {} + template void Visit(GridRefManager &) {} + void Visit(CreatureMapType &); + }; + + struct GridUpdater + { + GridType &i_grid; + uint32 i_timeDiff; + GridUpdater(GridType &grid, uint32 diff) : i_grid(grid), i_timeDiff(diff) {} + + template void updateObjects(GridRefManager &m) + { + for (typename GridRefManager::iterator iter = m.begin(); iter != m.end(); ++iter) + iter->getSource()->Update(i_timeDiff); + } + + void Visit(PlayerMapType &m) { updateObjects(m); } + void Visit(CreatureMapType &m){ updateObjects(m); } + void Visit(GameObjectMapType &m) { updateObjects(m); } + void Visit(DynamicObjectMapType &m) { updateObjects(m); } + void Visit(CorpseMapType &m) { updateObjects(m); } + }; + + struct MessageDistDeliverer + { + WorldObject *i_source; + WorldPacket *i_message; + uint32 i_phaseMask; + float i_distSq; + uint32 team; + Player const* skipped_receiver; + MessageDistDeliverer(WorldObject *src, WorldPacket *msg, float dist, bool own_team_only = false, Player const* skipped = NULL) + : i_source(src), i_message(msg), i_distSq(dist * dist), i_phaseMask(src->GetPhaseMask()) + , team((own_team_only && src->GetTypeId() == TYPEID_PLAYER) ? ((Player*)src)->GetTeam() : 0) + , skipped_receiver(skipped) + { + } + void Visit(PlayerMapType &m); + void Visit(CreatureMapType &m); + void Visit(DynamicObjectMapType &m); + template void Visit(GridRefManager &) {} + + void SendPacket(Player* plr) + { + // never send packet to self + if (plr == i_source || (team && plr->GetTeam() != team) || skipped_receiver == plr) + return; + + plr->GetSession()->SendPacket(i_message); + } + }; + + struct ObjectUpdater + { + uint32 i_timeDiff; + explicit ObjectUpdater(const uint32 &diff) : i_timeDiff(diff) {} + template void Visit(GridRefManager &m); + void Visit(PlayerMapType &) {} + void Visit(CorpseMapType &) {} + void Visit(CreatureMapType &); + }; + + // SEARCHERS & LIST SEARCHERS & WORKERS + + // WorldObject searchers & workers + + template + struct WorldObjectSearcher + { + uint32 i_phaseMask; + WorldObject* &i_object; + Check &i_check; + + WorldObjectSearcher(WorldObject const* searcher, WorldObject* & result, Check& check) + : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {} + + void Visit(GameObjectMapType &m); + void Visit(PlayerMapType &m); + void Visit(CreatureMapType &m); + void Visit(CorpseMapType &m); + void Visit(DynamicObjectMapType &m); + + template void Visit(GridRefManager &) {} + }; + + template + struct WorldObjectListSearcher + { + uint32 i_phaseMask; + std::list &i_objects; + Check& i_check; + + WorldObjectListSearcher(WorldObject const* searcher, std::list &objects, Check & check) + : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects),i_check(check) {} + + void Visit(PlayerMapType &m); + void Visit(CreatureMapType &m); + void Visit(CorpseMapType &m); + void Visit(GameObjectMapType &m); + void Visit(DynamicObjectMapType &m); + + template void Visit(GridRefManager &) {} + }; + + template + struct WorldObjectWorker + { + uint32 i_phaseMask; + Do const& i_do; + + WorldObjectWorker(WorldObject const* searcher, Do const& _do) + : i_phaseMask(searcher->GetPhaseMask()), i_do(_do) {} + + void Visit(GameObjectMapType &m) + { + for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + i_do(itr->getSource()); + } + + void Visit(PlayerMapType &m) + { + for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + i_do(itr->getSource()); + } + void Visit(CreatureMapType &m) + { + for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + i_do(itr->getSource()); + } + + void Visit(CorpseMapType &m) + { + for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + i_do(itr->getSource()); + } + + void Visit(DynamicObjectMapType &m) + { + for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + i_do(itr->getSource()); + } + + template void Visit(GridRefManager &) {} + }; + + // Gameobject searchers + + template + struct GameObjectSearcher + { + uint32 i_phaseMask; + GameObject* &i_object; + Check &i_check; + + GameObjectSearcher(WorldObject const* searcher, GameObject* & result, Check& check) + : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {} + + void Visit(GameObjectMapType &m); + + template void Visit(GridRefManager &) {} + }; + + // Last accepted by Check GO if any (Check can change requirements at each call) + template + struct GameObjectLastSearcher + { + uint32 i_phaseMask; + GameObject* &i_object; + Check& i_check; + + GameObjectLastSearcher(WorldObject const* searcher, GameObject* & result, Check& check) + : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) {} + + void Visit(GameObjectMapType &m); + + template void Visit(GridRefManager &) {} + }; + + template + struct GameObjectListSearcher + { + uint32 i_phaseMask; + std::list &i_objects; + Check& i_check; + + GameObjectListSearcher(WorldObject const* searcher, std::list &objects, Check & check) + : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {} + + void Visit(GameObjectMapType &m); + + template void Visit(GridRefManager &) {} + }; + + // Unit searchers + + // First accepted by Check Unit if any + template + struct UnitSearcher + { + uint32 i_phaseMask; + Unit* &i_object; + Check & i_check; + + UnitSearcher(WorldObject const* searcher, Unit* & result, Check & check) + : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {} + + void Visit(CreatureMapType &m); + void Visit(PlayerMapType &m); + + template void Visit(GridRefManager &) {} + }; + + // Last accepted by Check Unit if any (Check can change requirements at each call) + template + struct UnitLastSearcher + { + uint32 i_phaseMask; + Unit* &i_object; + Check & i_check; + + UnitLastSearcher(WorldObject const* searcher, Unit* & result, Check & check) + : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {} + + void Visit(CreatureMapType &m); + void Visit(PlayerMapType &m); + + template void Visit(GridRefManager &) {} + }; + + // All accepted by Check units if any + template + struct UnitListSearcher + { + uint32 i_phaseMask; + std::list &i_objects; + Check& i_check; + + UnitListSearcher(WorldObject const* searcher, std::list &objects, Check & check) + : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects),i_check(check) {} + + void Visit(PlayerMapType &m); + void Visit(CreatureMapType &m); + + template void Visit(GridRefManager &) {} + }; + + // Creature searchers + + template + struct CreatureSearcher + { + uint32 i_phaseMask; + Creature* &i_object; + Check & i_check; + + CreatureSearcher(WorldObject const* searcher, Creature* & result, Check & check) + : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {} + + void Visit(CreatureMapType &m); + + template void Visit(GridRefManager &) {} + }; + + // Last accepted by Check Creature if any (Check can change requirements at each call) + template + struct CreatureLastSearcher + { + uint32 i_phaseMask; + Creature* &i_object; + Check & i_check; + + CreatureLastSearcher(WorldObject const* searcher, Creature* & result, Check & check) + : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {} + + void Visit(CreatureMapType &m); + + template void Visit(GridRefManager &) {} + }; + + template + struct CreatureListSearcher + { + uint32 i_phaseMask; + std::list &i_objects; + Check& i_check; + + CreatureListSearcher(WorldObject const* searcher, std::list &objects, Check & check) + : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects),i_check(check) {} + + void Visit(CreatureMapType &m); + + template void Visit(GridRefManager &) {} + }; + + template + struct CreatureWorker + { + uint32 i_phaseMask; + Do& i_do; + + CreatureWorker(WorldObject const* searcher, Do& _do) + : i_phaseMask(searcher->GetPhaseMask()), i_do(_do) {} + + void Visit(CreatureMapType &m) + { + for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + i_do(itr->getSource()); + } + + template void Visit(GridRefManager &) {} + }; + + // Player searchers + + template + struct PlayerSearcher + { + uint32 i_phaseMask; + Player* &i_object; + Check & i_check; + + PlayerSearcher(WorldObject const* searcher, Player* & result, Check & check) + : i_phaseMask(searcher->GetPhaseMask()), i_object(result),i_check(check) {} + + void Visit(PlayerMapType &m); + + template void Visit(GridRefManager &) {} + }; + + template + struct PlayerListSearcher + { + uint32 i_phaseMask; + std::list &i_objects; + Check& i_check; + + PlayerListSearcher(WorldObject const* searcher, std::list &objects, Check & check) + : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects),i_check(check) {} + + void Visit(PlayerMapType &m); + + template void Visit(GridRefManager &) {} + }; + + template + struct PlayerWorker + { + uint32 i_phaseMask; + Do& i_do; + + PlayerWorker(WorldObject const* searcher, Do& _do) + : i_phaseMask(searcher->GetPhaseMask()), i_do(_do) {} + + void Visit(PlayerMapType &m) + { + for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + i_do(itr->getSource()); + } + + template void Visit(GridRefManager &) {} + }; + + template + struct PlayerDistWorker + { + WorldObject const* i_searcher; + float i_dist; + Do& i_do; + + PlayerDistWorker(WorldObject const* searcher, float _dist, Do& _do) + : i_searcher(searcher), i_dist(_dist), i_do(_do) {} + + void Visit(PlayerMapType &m) + { + for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_searcher) && itr->getSource()->IsWithinDist(i_searcher,i_dist)) + i_do(itr->getSource()); + } + + template void Visit(GridRefManager &) {} + }; + + // CHECKS && DO classes + + // WorldObject check classes + class RaiseDeadObjectCheck + { + public: + RaiseDeadObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {} + bool operator()(Creature* u) + { + if (i_funit->GetTypeId() != TYPEID_PLAYER || !((Player*)i_funit)->isHonorOrXPTarget(u) || + u->getDeathState() != CORPSE || u->isDeadByDefault() || u->isInFlight() || + (u->GetCreatureTypeMask() & (1 << (CREATURE_TYPE_HUMANOID-1))) == 0 || + (u->GetDisplayId() != u->GetNativeDisplayId())) + return false; + + return i_funit->IsWithinDistInMap(u, i_range); + } + template bool operator()(NOT_INTERESTED*) { return false; } + private: + Unit* const i_funit; + float i_range; + }; + + class ExplodeCorpseObjectCheck + { + public: + ExplodeCorpseObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {} + bool operator()(Player* u) + { + if (u->getDeathState() != CORPSE || u->isInFlight() || + u->HasAuraType(SPELL_AURA_GHOST) || (u->GetDisplayId() != u->GetNativeDisplayId())) + return false; + + return i_funit->IsWithinDistInMap(u, i_range); + } + bool operator()(Creature* u) + { + if (u->getDeathState() != CORPSE || u->isInFlight() || u->isDeadByDefault() || + (u->GetDisplayId() != u->GetNativeDisplayId()) || + (u->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL) != 0) + return false; + + return i_funit->IsWithinDistInMap(u, i_range); + } + template bool operator()(NOT_INTERESTED*) { return false; } + private: + Unit* const i_funit; + float i_range; + }; + + class CannibalizeObjectCheck + { + public: + CannibalizeObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {} + bool operator()(Player* u) + { + if (i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight()) + return false; + + return i_funit->IsWithinDistInMap(u, i_range); + } + bool operator()(Corpse* u); + bool operator()(Creature* u) + { + if (i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() || + (u->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) == 0) + return false; + + return i_funit->IsWithinDistInMap(u, i_range); + } + template bool operator()(NOT_INTERESTED*) { return false; } + private: + Unit* const i_funit; + float i_range; + }; + + // WorldObject do classes + + class RespawnDo + { + public: + RespawnDo() {} + void operator()(Creature* u) const { u->Respawn(); } + void operator()(GameObject* u) const { u->Respawn(); } + void operator()(WorldObject*) const {} + void operator()(Corpse*) const {} + }; + + // GameObject checks + + class GameObjectFocusCheck + { + public: + GameObjectFocusCheck(Unit const* unit,uint32 focusId) : i_unit(unit), i_focusId(focusId) {} + bool operator()(GameObject* go) const + { + if (go->GetGOInfo()->type != GAMEOBJECT_TYPE_SPELL_FOCUS) + return false; + + if (go->GetGOInfo()->spellFocus.focusId != i_focusId) + return false; + + float dist = (go->GetGOInfo()->spellFocus.dist)/2; + + return go->IsWithinDistInMap(i_unit, dist); + } + private: + Unit const* i_unit; + uint32 i_focusId; + }; + + // Find the nearest Fishing hole and return true only if source object is in range of hole + class NearestGameObjectFishingHole + { + public: + NearestGameObjectFishingHole(WorldObject const& obj, float range) : i_obj(obj), i_range(range) {} + bool operator()(GameObject* go) + { + if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_FISHINGHOLE && go->isSpawned() && i_obj.IsWithinDistInMap(go, i_range) && i_obj.IsWithinDistInMap(go, go->GetGOInfo()->fishinghole.radius)) + { + i_range = i_obj.GetDistance(go); + return true; + } + return false; + } + float GetLastRange() const { return i_range; } + private: + WorldObject const& i_obj; + float i_range; + + // prevent clone + NearestGameObjectFishingHole(NearestGameObjectFishingHole const&); + }; + + class NearestGameObjectCheck + { + public: + NearestGameObjectCheck(WorldObject const& obj) : i_obj(obj), i_range(999) {} + bool operator()(GameObject* go) + { + if (i_obj.IsWithinDistInMap(go, i_range)) + { + i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check + return true; + } + return false; + } + float GetLastRange() const { return i_range; } + private: + WorldObject const& i_obj; + float i_range; + + // prevent clone this object + NearestGameObjectCheck(NearestGameObjectCheck const&); + }; + + // Success at unit in range, range update for next check (this can be use with GameobjectLastSearcher to find nearest GO) + class NearestGameObjectEntryInObjectRangeCheck + { + public: + NearestGameObjectEntryInObjectRangeCheck(WorldObject const& obj,uint32 entry, float range) : i_obj(obj), i_entry(entry), i_range(range) {} + bool operator()(GameObject* go) + { + if (go->GetEntry() == i_entry && i_obj.IsWithinDistInMap(go, i_range)) + { + i_range = i_obj.GetDistance(go); // use found GO range as new range limit for next check + return true; + } + return false; + } + float GetLastRange() const { return i_range; } + private: + WorldObject const& i_obj; + uint32 i_entry; + float i_range; + + // prevent clone this object + NearestGameObjectEntryInObjectRangeCheck(NearestGameObjectEntryInObjectRangeCheck const&); + }; + + class GameObjectWithDbGUIDCheck + { + public: + GameObjectWithDbGUIDCheck(WorldObject const& obj,uint32 db_guid) : i_obj(obj), i_db_guid(db_guid) {} + bool operator()(GameObject const* go) const + { + return go->GetDBTableGUIDLow() == i_db_guid; + } + private: + WorldObject const& i_obj; + uint32 i_db_guid; + }; + + // Unit checks + + class MostHPMissingInRange + { + public: + MostHPMissingInRange(Unit const* obj, float range, uint32 hp) : i_obj(obj), i_range(range), i_hp(hp) {} + bool operator()(Unit* u) + { + if (u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && u->GetMaxHealth() - u->GetHealth() > i_hp) + { + i_hp = u->GetMaxHealth() - u->GetHealth(); + return true; + } + return false; + } + private: + Unit const* i_obj; + float i_range; + uint32 i_hp; + }; + + class FriendlyCCedInRange + { + public: + FriendlyCCedInRange(Unit const* obj, float range) : i_obj(obj), i_range(range) {} + bool operator()(Unit* u) + { + if (u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && + (u->isFeared() || u->isCharmed() || u->isFrozen() || u->hasUnitState(UNIT_STAT_STUNNED) || u->hasUnitState(UNIT_STAT_CONFUSED))) + { + return true; + } + return false; + } + private: + Unit const* i_obj; + float i_range; + }; + + class FriendlyMissingBuffInRange + { + public: + FriendlyMissingBuffInRange(Unit const* obj, float range, uint32 spellid) : i_obj(obj), i_range(range), i_spell(spellid) {} + bool operator()(Unit* u) + { + if (u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && + !(u->HasAura(i_spell))) + { + return true; + } + return false; + } + private: + Unit const* i_obj; + float i_range; + uint32 i_spell; + }; + + class AnyUnfriendlyUnitInObjectRangeCheck + { + public: + AnyUnfriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} + bool operator()(Unit* u) + { + if (u->isAlive() && i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u)) + return true; + else + return false; + } + private: + WorldObject const* i_obj; + Unit const* i_funit; + float i_range; + }; + + class AnyUnfriendlyNoTotemUnitInObjectRangeCheck + { + public: + AnyUnfriendlyNoTotemUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} + bool operator()(Unit* u) + { + if (!u->isAlive()) + return false; + + if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->isTotem()) + return false; + + return i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u); + } + private: + WorldObject const* i_obj; + Unit const* i_funit; + float i_range; + }; + + class AnyUnfriendlyVisibleUnitInObjectRangeCheck + { + public: + AnyUnfriendlyVisibleUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) + : i_obj(obj), i_funit(funit), i_range(range) {} + + bool operator()(Unit* u) + { + return u->isAlive() + && i_obj->IsWithinDistInMap(u, i_range) + && !i_funit->IsFriendlyTo(u) + && u->isVisibleForOrDetect(i_funit, false); + } + private: + WorldObject const* i_obj; + Unit const* i_funit; + float i_range; + }; + + class CreatureWithDbGUIDCheck + { + public: + CreatureWithDbGUIDCheck(WorldObject const* obj, uint32 lowguid) : i_obj(obj), i_lowguid(lowguid) {} + bool operator()(Creature* u) + { + return u->GetDBTableGUIDLow() == i_lowguid; + } + private: + WorldObject const* i_obj; + uint32 i_lowguid; + }; + + class AnyFriendlyUnitInObjectRangeCheck + { + public: + AnyFriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} + bool operator()(Unit* u) + { + if (u->isAlive() && i_obj->IsWithinDistInMap(u, i_range) && i_funit->IsFriendlyTo(u)) + return true; + else + return false; + } + private: + WorldObject const* i_obj; + Unit const* i_funit; + float i_range; + }; + + class AnyUnitInObjectRangeCheck + { + public: + AnyUnitInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {} + bool operator()(Unit* u) + { + if (u->isAlive() && i_obj->IsWithinDistInMap(u, i_range)) + return true; + + return false; + } + private: + WorldObject const* i_obj; + float i_range; + }; + + // Success at unit in range, range update for next check (this can be use with UnitLastSearcher to find nearest unit) + class NearestAttackableUnitInObjectRangeCheck + { + public: + NearestAttackableUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} + bool operator()(Unit* u) + { + if (u->isTargetableForAttack() && i_obj->IsWithinDistInMap(u, i_range) && + !i_funit->IsFriendlyTo(u) && u->isVisibleForOrDetect(i_funit,false)) + { + i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check + return true; + } + + return false; + } + private: + WorldObject const* i_obj; + Unit const* i_funit; + float i_range; + + // prevent clone this object + NearestAttackableUnitInObjectRangeCheck(NearestAttackableUnitInObjectRangeCheck const&); + }; + + class AnyAoETargetUnitInObjectRangeCheck + { + public: + AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) + : i_obj(obj), i_funit(funit), i_range(range) + { + Unit const* check = i_funit; + Unit const* owner = i_funit->GetOwner(); + if (owner) + check = owner; + i_targetForPlayer = (check->GetTypeId() == TYPEID_PLAYER); + } + bool operator()(Unit* u) + { + // Check contains checks for: live, non-selectable, non-attackable flags, flight check and GM check, ignore totems + if (!u->isTargetableForAttack()) + return false; + if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->isTotem()) + return false; + + if ((i_targetForPlayer ? !i_funit->IsFriendlyTo(u) : i_funit->IsHostileTo(u))&& i_obj->IsWithinDistInMap(u, i_range)) + return true; + + return false; + } + private: + bool i_targetForPlayer; + WorldObject const* i_obj; + Unit const* i_funit; + float i_range; + }; + + // do attack at call of help to friendly crearture + class CallOfHelpCreatureInRangeDo + { + public: + CallOfHelpCreatureInRangeDo(Unit* funit, Unit* enemy, float range) + : i_funit(funit), i_enemy(enemy), i_range(range) + {} + void operator()(Creature* u) + { + if (u == i_funit) + return; + + if (!u->CanAssistTo(i_funit, i_enemy, false)) + return; + + // too far + if (!u->IsWithinDistInMap(i_enemy, i_range)) + return; + + // only if see assisted creature's enemy + if (!u->IsWithinLOSInMap(i_enemy)) + return; + + if (u->AI()) + u->AI()->AttackStart(i_enemy); + } + private: + Unit* const i_funit; + Unit* const i_enemy; + float i_range; + }; + + struct AnyDeadUnitCheck + { + bool operator()(Unit* u) { return !u->isAlive(); } + }; + + struct AnyStealthedCheck + { + bool operator()(Unit* u) { return u->GetVisibility() == VISIBILITY_GROUP_STEALTH; } + }; + + // Creature checks + + class NearestHostileUnitCheck + { + public: + explicit NearestHostileUnitCheck(Creature const* creature, float dist = 0) : me(creature) + { + m_range = (dist == 0 ? 9999 : dist); + } + bool operator()(Unit* u) + { + if (!me->IsWithinDistInMap(u, m_range)) + return false; + + if (!me->canAttack(u)) + return false; + + m_range = me->GetDistance(u); // use found unit range as new range limit for next check + return true; + } + + private: + Creature const *me; + float m_range; + NearestHostileUnitCheck(NearestHostileUnitCheck const&); + }; + + class NearestHostileUnitInAttackDistanceCheck + { + public: + explicit NearestHostileUnitInAttackDistanceCheck(Creature const* creature, float dist = 0) : me(creature) + { + m_range = (dist == 0 ? 9999 : dist); + m_force = (dist == 0 ? false : true); + } + bool operator()(Unit* u) + { + if (!me->IsWithinDistInMap(u, m_range)) + return false; + + if (m_force) + { + if (!me->canAttack(u)) + return false; + } + else + { + if (!me->canStartAttack(u, false)) + return false; + } + + m_range = me->GetDistance(u); // use found unit range as new range limit for next check + return true; + } + float GetLastRange() const { return m_range; } + private: + Creature const *me; + float m_range; + bool m_force; + NearestHostileUnitInAttackDistanceCheck(NearestHostileUnitInAttackDistanceCheck const&); + }; + + class AnyAssistCreatureInRangeCheck + { + public: + AnyAssistCreatureInRangeCheck(Unit* funit, Unit* enemy, float range) + : i_funit(funit), i_enemy(enemy), i_range(range) + { + } + bool operator()(Creature* u) + { + if (u == i_funit) + return false; + + if (!u->CanAssistTo(i_funit, i_enemy)) + return false; + + // too far + if (!i_funit->IsWithinDistInMap(u, i_range)) + return false; + + // only if see assisted creature + if (!i_funit->IsWithinLOSInMap(u)) + return false; + + return true; + } + private: + Unit* const i_funit; + Unit* const i_enemy; + float i_range; + }; + + class NearestAssistCreatureInCreatureRangeCheck + { + public: + NearestAssistCreatureInCreatureRangeCheck(Creature* obj, Unit* enemy, float range) + : i_obj(obj), i_enemy(enemy), i_range(range) {} + + bool operator()(Creature* u) + { + if (u == i_obj) + return false; + if (!u->CanAssistTo(i_obj,i_enemy)) + return false; + + if (!i_obj->IsWithinDistInMap(u, i_range)) + return false; + + if (!i_obj->IsWithinLOSInMap(u)) + return false; + + i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check + return true; + } + float GetLastRange() const { return i_range; } + private: + Creature* const i_obj; + Unit* const i_enemy; + float i_range; + + // prevent clone this object + NearestAssistCreatureInCreatureRangeCheck(NearestAssistCreatureInCreatureRangeCheck const&); + }; + + // Success at unit in range, range update for next check (this can be use with CreatureLastSearcher to find nearest creature) + class NearestCreatureEntryWithLiveStateInObjectRangeCheck + { + public: + NearestCreatureEntryWithLiveStateInObjectRangeCheck(WorldObject const& obj, uint32 entry, bool alive, float range) + : i_obj(obj), i_entry(entry), i_alive(alive), i_range(range) {} + + bool operator()(Creature* u) + { + if (u->GetEntry() == i_entry && u->isAlive() == i_alive && i_obj.IsWithinDistInMap(u, i_range)) + { + i_range = i_obj.GetDistance(u); // use found unit range as new range limit for next check + return true; + } + return false; + } + float GetLastRange() const { return i_range; } + private: + WorldObject const& i_obj; + uint32 i_entry; + bool i_alive; + float i_range; + + // prevent clone this object + NearestCreatureEntryWithLiveStateInObjectRangeCheck(NearestCreatureEntryWithLiveStateInObjectRangeCheck const&); + }; + + class AnyPlayerInObjectRangeCheck + { + public: + AnyPlayerInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {} + bool operator()(Player* u) + { + if (u->isAlive() && i_obj->IsWithinDistInMap(u, i_range)) + return true; + + return false; + } + private: + WorldObject const* i_obj; + float i_range; + }; + + class AllFriendlyCreaturesInGrid + { + public: + AllFriendlyCreaturesInGrid(Unit const* obj) : pUnit(obj) {} + bool operator() (Unit* u) + { + if (u->isAlive() && u->GetVisibility() == VISIBILITY_ON && u->IsFriendlyTo(pUnit)) + return true; + + return false; + } + private: + Unit const* pUnit; + }; + + class AllGameObjectsWithEntryInRange + { + public: + AllGameObjectsWithEntryInRange(const WorldObject* pObject, uint32 uiEntry, float fMaxRange) : m_pObject(pObject), m_uiEntry(uiEntry), m_fRange(fMaxRange) {} + bool operator() (GameObject* pGo) + { + if (pGo->GetEntry() == m_uiEntry && m_pObject->IsWithinDist(pGo,m_fRange,false)) + return true; + + return false; + } + private: + const WorldObject* m_pObject; + uint32 m_uiEntry; + float m_fRange; + }; + + class AllCreaturesOfEntryInRange + { + public: + AllCreaturesOfEntryInRange(const WorldObject* pObject, uint32 uiEntry, float fMaxRange) : m_pObject(pObject), m_uiEntry(uiEntry), m_fRange(fMaxRange) {} + bool operator() (Unit* pUnit) + { + if (pUnit->GetEntry() == m_uiEntry && m_pObject->IsWithinDist(pUnit,m_fRange,false)) + return true; + + return false; + } + + private: + const WorldObject* m_pObject; + uint32 m_uiEntry; + float m_fRange; + }; + + class PlayerAtMinimumRangeAway + { + public: + PlayerAtMinimumRangeAway(Unit const* unit, float fMinRange) : pUnit(unit), fRange(fMinRange) {} + bool operator() (Player* pPlayer) + { + //No threat list check, must be done explicit if expected to be in combat with creature + if (!pPlayer->isGameMaster() && pPlayer->isAlive() && !pUnit->IsWithinDist(pPlayer,fRange,false)) + return true; + + return false; + } + + private: + Unit const* pUnit; + float fRange; + }; + + class GameObjectInRangeCheck + { + public: + GameObjectInRangeCheck(float _x, float _y, float _z, float _range) : x(_x), y(_y), z(_z), range(_range) {} + bool operator() (GameObject* go) + { + return go->IsInRange(x, y, z, range); + } + private: + float x, y, z, range; + }; + + // Player checks and do + + // Prepare using Builder localized packets with caching and send to player + template + class LocalizedPacketDo + { + public: + explicit LocalizedPacketDo(Builder& builder) : i_builder(builder) {} + + ~LocalizedPacketDo() + { + for (size_t i = 0; i < i_data_cache.size(); ++i) + delete i_data_cache[i]; + } + void operator()(Player* p); + + private: + Builder& i_builder; + std::vector i_data_cache; // 0 = default, i => i-1 locale index + }; + + // Prepare using Builder localized packets with caching and send to player + template + class LocalizedPacketListDo + { + public: + typedef std::vector WorldPacketList; + explicit LocalizedPacketListDo(Builder& builder) : i_builder(builder) {} + + ~LocalizedPacketListDo() + { + for (size_t i = 0; i < i_data_cache.size(); ++i) + for (size_t j = 0; j < i_data_cache[i].size(); ++j) + delete i_data_cache[i][j]; + } + void operator()(Player* p); + + private: + Builder& i_builder; + std::vector i_data_cache; + // 0 = default, i => i-1 locale index + }; +} +#endif diff --git a/src/server/game/Maps/Grid/GridNotifiersImpl.h b/src/server/game/Maps/Grid/GridNotifiersImpl.h new file mode 100644 index 00000000000..26a9c0bd328 --- /dev/null +++ b/src/server/game/Maps/Grid/GridNotifiersImpl.h @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_GRIDNOTIFIERSIMPL_H +#define TRINITY_GRIDNOTIFIERSIMPL_H + +#include "GridNotifiers.h" +#include "WorldPacket.h" +#include "Corpse.h" +#include "Player.h" +#include "UpdateData.h" +#include "CreatureAI.h" +#include "SpellAuras.h" + + +template +inline void +Trinity::VisibleNotifier::Visit(GridRefManager &m) +{ + for (typename GridRefManager::iterator iter = m.begin(); iter != m.end(); ++iter) + { + vis_guids.erase(iter->getSource()->GetGUID()); + i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_visibleNow); + } +} + +inline void +Trinity::ObjectUpdater::Visit(CreatureMapType &m) +{ + for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + if (iter->getSource()->IsInWorld() && !iter->getSource()->isSpiritService()) + iter->getSource()->Update(i_timeDiff); +} + +// SEARCHERS & LIST SEARCHERS & WORKERS + +// WorldObject searchers & workers + +template +void Trinity::WorldObjectSearcher::Visit(GameObjectMapType &m) +{ + // already found + if (i_object) + return; + + for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + { + i_object = itr->getSource(); + return; + } + } +} + +template +void Trinity::WorldObjectSearcher::Visit(PlayerMapType &m) +{ + // already found + if (i_object) + return; + + for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + { + i_object = itr->getSource(); + return; + } + } +} + +template +void Trinity::WorldObjectSearcher::Visit(CreatureMapType &m) +{ + // already found + if (i_object) + return; + + for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + { + i_object = itr->getSource(); + return; + } + } +} + +template +void Trinity::WorldObjectSearcher::Visit(CorpseMapType &m) +{ + // already found + if (i_object) + return; + + for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + { + i_object = itr->getSource(); + return; + } + } +} + +template +void Trinity::WorldObjectSearcher::Visit(DynamicObjectMapType &m) +{ + // already found + if (i_object) + return; + + for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + { + i_object = itr->getSource(); + return; + } + } +} + +template +void Trinity::WorldObjectListSearcher::Visit(PlayerMapType &m) +{ + for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); +} + +template +void Trinity::WorldObjectListSearcher::Visit(CreatureMapType &m) +{ + for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); +} + +template +void Trinity::WorldObjectListSearcher::Visit(CorpseMapType &m) +{ + for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); +} + +template +void Trinity::WorldObjectListSearcher::Visit(GameObjectMapType &m) +{ + for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); +} + +template +void Trinity::WorldObjectListSearcher::Visit(DynamicObjectMapType &m) +{ + for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); +} + +// Gameobject searchers + +template +void Trinity::GameObjectSearcher::Visit(GameObjectMapType &m) +{ + // already found + if (i_object) + return; + + for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + { + i_object = itr->getSource(); + return; + } + } +} + +template +void Trinity::GameObjectLastSearcher::Visit(GameObjectMapType &m) +{ + for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + i_object = itr->getSource(); + } +} + +template +void Trinity::GameObjectListSearcher::Visit(GameObjectMapType &m) +{ + for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); +} + +// Unit searchers + +template +void Trinity::UnitSearcher::Visit(CreatureMapType &m) +{ + // already found + if (i_object) + return; + + for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + { + i_object = itr->getSource(); + return; + } + } +} + +template +void Trinity::UnitSearcher::Visit(PlayerMapType &m) +{ + // already found + if (i_object) + return; + + for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + { + i_object = itr->getSource(); + return; + } + } +} + +template +void Trinity::UnitLastSearcher::Visit(CreatureMapType &m) +{ + for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + i_object = itr->getSource(); + } +} + +template +void Trinity::UnitLastSearcher::Visit(PlayerMapType &m) +{ + for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + i_object = itr->getSource(); + } +} + +template +void Trinity::UnitListSearcher::Visit(PlayerMapType &m) +{ + for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); +} + +template +void Trinity::UnitListSearcher::Visit(CreatureMapType &m) +{ + for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); +} + +// Creature searchers + +template +void Trinity::CreatureSearcher::Visit(CreatureMapType &m) +{ + // already found + if (i_object) + return; + + for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + { + i_object = itr->getSource(); + return; + } + } +} + +template +void Trinity::CreatureLastSearcher::Visit(CreatureMapType &m) +{ + for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + i_object = itr->getSource(); + } +} + +template +void Trinity::CreatureListSearcher::Visit(CreatureMapType &m) +{ + for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); +} + +template +void Trinity::PlayerListSearcher::Visit(PlayerMapType &m) +{ + for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->InSamePhase(i_phaseMask)) + if (i_check(itr->getSource())) + i_objects.push_back(itr->getSource()); +} + +template +void Trinity::PlayerSearcher::Visit(PlayerMapType &m) +{ + // already found + if (i_object) + return; + + for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + { + if (!itr->getSource()->InSamePhase(i_phaseMask)) + continue; + + if (i_check(itr->getSource())) + { + i_object = itr->getSource(); + return; + } + } +} + +template +void Trinity::LocalizedPacketDo::operator()(Player* p) +{ + int32 loc_idx = p->GetSession()->GetSessionDbLocaleIndex(); + uint32 cache_idx = loc_idx+1; + WorldPacket* data; + + // create if not cached yet + if (i_data_cache.size() < cache_idx+1 || !i_data_cache[cache_idx]) + { + if (i_data_cache.size() < cache_idx+1) + i_data_cache.resize(cache_idx+1); + + data = new WorldPacket(SMSG_MESSAGECHAT, 200); + + i_builder(*data,loc_idx); + + i_data_cache[cache_idx] = data; + } + else + data = i_data_cache[cache_idx]; + + p->SendDirectMessage(data); +} + +template +void Trinity::LocalizedPacketListDo::operator()(Player* p) +{ + int32 loc_idx = p->GetSession()->GetSessionDbLocaleIndex(); + uint32 cache_idx = loc_idx+1; + WorldPacketList* data_list; + + // create if not cached yet + if (i_data_cache.size() < cache_idx+1 || i_data_cache[cache_idx].empty()) + { + if (i_data_cache.size() < cache_idx+1) + i_data_cache.resize(cache_idx+1); + + data_list = &i_data_cache[cache_idx]; + + i_builder(*data_list,loc_idx); + } + else + data_list = &i_data_cache[cache_idx]; + + for (size_t i = 0; i < data_list->size(); ++i) + p->SendDirectMessage((*data_list)[i]); +} + +#endif // TRINITY_GRIDNOTIFIERSIMPL_H diff --git a/src/server/game/Maps/Grid/GridStates.cpp b/src/server/game/Maps/Grid/GridStates.cpp new file mode 100644 index 00000000000..9d39531cfad --- /dev/null +++ b/src/server/game/Maps/Grid/GridStates.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "GridStates.h" +#include "GridNotifiers.h" +#include "GameSystem/Grid.h" +#include "Log.h" + +void +InvalidState::Update(Map &, NGridType &, GridInfo &, const uint32 &/*x*/, const uint32 &/*y*/, const uint32 &) const +{ +} + +void +ActiveState::Update(Map &m, NGridType &grid, GridInfo & info, const uint32 &x, const uint32 &y, const uint32 &t_diff) const +{ + // Only check grid activity every (grid_expiry/10) ms, because it's really useless to do it every cycle + info.UpdateTimeTracker(t_diff); + if (info.getTimeTracker().Passed()) + { + if (grid.ActiveObjectsInGrid() == 0 && !m.ActiveObjectsNearGrid(x, y)) + { + ObjectGridStoper stoper(grid); + stoper.StopN(); + grid.SetGridState(GRID_STATE_IDLE); + sLog.outDebug("Grid[%u,%u] on map %u moved to IDLE state", x, y, m.GetId()); + } + else + { + m.ResetGridExpiry(grid, 0.1f); + } + } +} + +void +IdleState::Update(Map &m, NGridType &grid, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &) const +{ + m.ResetGridExpiry(grid); + grid.SetGridState(GRID_STATE_REMOVAL); + sLog.outDebug("Grid[%u,%u] on map %u moved to REMOVAL state", x, y, m.GetId()); +} + +void +RemovalState::Update(Map &m, NGridType &grid, GridInfo &info, const uint32 &x, const uint32 &y, const uint32 &t_diff) const +{ + if (!info.getUnloadLock()) + { + info.UpdateTimeTracker(t_diff); + if (info.getTimeTracker().Passed()) + { + if (!m.UnloadGrid(x, y, false)) + { + sLog.outDebug("Grid[%u,%u] for map %u differed unloading due to players or active objects nearby", x, y, m.GetId()); + m.ResetGridExpiry(grid); + } + } + } +} + diff --git a/src/server/game/Maps/Grid/GridStates.h b/src/server/game/Maps/Grid/GridStates.h new file mode 100644 index 00000000000..c2a75ec45b7 --- /dev/null +++ b/src/server/game/Maps/Grid/GridStates.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_GRIDSTATES_H +#define TRINITY_GRIDSTATES_H + +#include "Map.h" +#include "Object.h" + +class GridState +{ + public: +#ifdef TRINITY_DEBUG +#define MAGIC_TESTVAL 0xFBE823BA + GridState() { i_Magic = MAGIC_TESTVAL; } + bool checkMagic() + { + if (i_Magic != MAGIC_TESTVAL) + { + sLog.outError("!!! GridState: Magic value gone !!!"); + return false; + } + return true; + } + void setMagic() { i_Magic = MAGIC_TESTVAL; } + unsigned int i_Magic; +#endif + virtual void Update(Map &, NGridType&, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const = 0; +}; + +class InvalidState : public GridState +{ + public: + + void Update(Map &, NGridType &, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const; +}; + +class ActiveState : public GridState +{ + public: + + void Update(Map &, NGridType &, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const; +}; + +class IdleState : public GridState +{ + public: + + void Update(Map &, NGridType &, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const; +}; + +class RemovalState : public GridState +{ + public: + + void Update(Map &, NGridType &, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &t_diff) const; +}; +#endif + diff --git a/src/server/game/Maps/Grid/ObjectGridLoader.cpp b/src/server/game/Maps/Grid/ObjectGridLoader.cpp new file mode 100644 index 00000000000..ab69d9a966b --- /dev/null +++ b/src/server/game/Maps/Grid/ObjectGridLoader.cpp @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ObjectGridLoader.h" +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "Creature.h" +#include "Vehicle.h" +#include "GameObject.h" +#include "DynamicObject.h" +#include "Corpse.h" +#include "World.h" +#include "CellImpl.h" +#include "CreatureAI.h" + +class ObjectGridRespawnMover +{ + public: + ObjectGridRespawnMover() {} + + void Move(GridType &grid); + + template void Visit(GridRefManager &) {} + void Visit(CreatureMapType &m); +}; + +void +ObjectGridRespawnMover::Move(GridType &grid) +{ + TypeContainerVisitor mover(*this); + grid.Visit(mover); +} + +void +ObjectGridRespawnMover::Visit(CreatureMapType &m) +{ + // creature in unloading grid can have respawn point in another grid + // if it will be unloaded then it will not respawn in original grid until unload/load original grid + // move to respawn point to prevent this case. For player view in respawn grid this will be normal respawn. + for (CreatureMapType::iterator iter = m.begin(); iter != m.end();) + { + Creature * c = iter->getSource(); + ++iter; + + assert(!c->isPet() && "ObjectGridRespawnMover don't must be called for pets"); + + Cell const& cur_cell = c->GetCurrentCell(); + + float resp_x, resp_y, resp_z; + c->GetRespawnCoord(resp_x, resp_y, resp_z); + CellPair resp_val = Trinity::ComputeCellPair(resp_x, resp_y); + Cell resp_cell(resp_val); + + if (cur_cell.DiffGrid(resp_cell)) + { + c->GetMap()->CreatureRespawnRelocation(c); + // false result ignored: will be unload with other creatures at grid + } + } +} + +// for loading world object at grid loading (Corpses) +class ObjectWorldLoader +{ + public: + explicit ObjectWorldLoader(ObjectGridLoader& gloader) + : i_cell(gloader.i_cell), i_grid(gloader.i_grid), i_map(gloader.i_map), i_corpses (0) + {} + + void Visit(CorpseMapType &m); + + template void Visit(GridRefManager&) { } + + private: + Cell i_cell; + NGridType &i_grid; + Map* i_map; + public: + uint32 i_corpses; +}; + +template void addUnitState(T* /*obj*/, CellPair const& /*cell_pair*/) +{ +} + +template<> void addUnitState(Creature *obj, CellPair const& cell_pair) +{ + Cell cell(cell_pair); + + obj->SetCurrentCell(cell); + if (obj->isSpiritService()) + obj->setDeathState(DEAD); +} + +template +void AddObjectHelper(CellPair &cell, GridRefManager &m, uint32 &count, Map* map, T *obj) +{ + obj->GetGridRef().link(&m, obj); + addUnitState(obj,cell); + obj->AddToWorld(); + if (obj->isActiveObject()) + map->AddToActive(obj); + + ++count; +} + +template +void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager &m, uint32 &count, Map* map) +{ + for (CellGuidSet::const_iterator i_guid = guid_set.begin(); i_guid != guid_set.end(); ++i_guid) + { + T* obj = new T; + uint32 guid = *i_guid; + //sLog.outString("DEBUG: LoadHelper from table: %s for (guid: %u) Loading",table,guid); + if (!obj->LoadFromDB(guid, map)) + { + delete obj; + continue; + } + + AddObjectHelper(cell, m, count, map, obj); + } +} + +void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType &m, uint32 &count, Map* map) +{ + if (cell_corpses.empty()) + return; + + for (CellCorpseSet::const_iterator itr = cell_corpses.begin(); itr != cell_corpses.end(); ++itr) + { + if (itr->second != map->GetInstanceId()) + continue; + + uint32 player_guid = itr->first; + + Corpse *obj = ObjectAccessor::Instance().GetCorpseForPlayerGUID(player_guid); + if (!obj) + continue; + + // TODO: this is a hack + // corpse's map should be reset when the map is unloaded + // but it may still exist when the grid is unloaded but map is not + // in that case map == currMap + obj->SetMap(map); + + AddObjectHelper(cell, m, count, map, obj); + } +} + +void +ObjectGridLoader::Visit(GameObjectMapType &m) +{ + uint32 x = (i_cell.GridX()*MAX_NUMBER_OF_CELLS) + i_cell.CellX(); + uint32 y = (i_cell.GridY()*MAX_NUMBER_OF_CELLS) + i_cell.CellY(); + CellPair cell_pair(x,y); + uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; + + CellObjectGuids const& cell_guids = objmgr.GetCellObjectGuids(i_map->GetId(), i_map->GetSpawnMode(), cell_id); + + LoadHelper(cell_guids.gameobjects, cell_pair, m, i_gameObjects, i_map); +} + +void +ObjectGridLoader::Visit(CreatureMapType &m) +{ + uint32 x = (i_cell.GridX()*MAX_NUMBER_OF_CELLS) + i_cell.CellX(); + uint32 y = (i_cell.GridY()*MAX_NUMBER_OF_CELLS) + i_cell.CellY(); + CellPair cell_pair(x,y); + uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; + + CellObjectGuids const& cell_guids = objmgr.GetCellObjectGuids(i_map->GetId(), i_map->GetSpawnMode(), cell_id); + + LoadHelper(cell_guids.creatures, cell_pair, m, i_creatures, i_map); +} + +void +ObjectWorldLoader::Visit(CorpseMapType &m) +{ + uint32 x = (i_cell.GridX()*MAX_NUMBER_OF_CELLS) + i_cell.CellX(); + uint32 y = (i_cell.GridY()*MAX_NUMBER_OF_CELLS) + i_cell.CellY(); + CellPair cell_pair(x,y); + uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord; + + // corpses are always added to spawn mode 0 and they are spawned by their instance id + CellObjectGuids const& cell_guids = objmgr.GetCellObjectGuids(i_map->GetId(), 0, cell_id); + LoadHelper(cell_guids.corpses, cell_pair, m, i_corpses, i_map); +} + +void +ObjectGridLoader::Load(GridType &grid) +{ + { + TypeContainerVisitor loader(*this); + grid.Visit(loader); + } + + { + ObjectWorldLoader wloader(*this); + TypeContainerVisitor loader(wloader); + grid.Visit(loader); + i_corpses = wloader.i_corpses; + } +} + +void ObjectGridLoader::LoadN(void) +{ + i_gameObjects = 0; i_creatures = 0; i_corpses = 0; + i_cell.data.Part.cell_y = 0; + for (unsigned int x=0; x < MAX_NUMBER_OF_CELLS; ++x) + { + i_cell.data.Part.cell_x = x; + for (unsigned int y=0; y < MAX_NUMBER_OF_CELLS; ++y) + { + i_cell.data.Part.cell_y = y; + GridLoader loader; + loader.Load(i_grid(x, y), *this); + } + } + sLog.outDebug("%u GameObjects, %u Creatures, and %u Corpses/Bones loaded for grid %u on map %u", i_gameObjects, i_creatures, i_corpses,i_grid.GetGridId(), i_map->GetId()); +} + +void ObjectGridUnloader::MoveToRespawnN() +{ + for (unsigned int x=0; x < MAX_NUMBER_OF_CELLS; ++x) + { + for (unsigned int y=0; y < MAX_NUMBER_OF_CELLS; ++y) + { + ObjectGridRespawnMover mover; + mover.Move(i_grid(x, y)); + } + } +} + +void +ObjectGridUnloader::Unload(GridType &grid) +{ + TypeContainerVisitor unloader(*this); + grid.Visit(unloader); +} + +template +void +ObjectGridUnloader::Visit(GridRefManager &m) +{ + while (!m.isEmpty()) + { + T *obj = m.getFirst()->getSource(); + // if option set then object already saved at this moment + if (!sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY)) + obj->SaveRespawnTime(); + ///- object will get delinked from the manager when deleted + delete obj; + } +} + +void +ObjectGridStoper::Stop(GridType &grid) +{ + TypeContainerVisitor stoper(*this); + grid.Visit(stoper); +} + +void +ObjectGridStoper::Visit(CreatureMapType &m) +{ + // stop any fights at grid de-activation and remove dynobjects created at cast by creatures + for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + { + iter->getSource()->RemoveAllDynObjects(); + if (iter->getSource()->isInCombat()) + { + iter->getSource()->CombatStop(); + iter->getSource()->DeleteThreatList(); + iter->getSource()->AI()->EnterEvadeMode(); + } + } +} + +void +ObjectGridCleaner::Stop(GridType &grid) +{ + TypeContainerVisitor stoper(*this); + grid.Visit(stoper); +} + +void +ObjectGridCleaner::Visit(CreatureMapType &m) +{ + for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + iter->getSource()->CleanupsBeforeDelete(); +} + +template +void +ObjectGridCleaner::Visit(GridRefManager &m) +{ + for (typename GridRefManager::iterator iter = m.begin(); iter != m.end(); ++iter) + iter->getSource()->RemoveFromWorld(); +} + +template void ObjectGridUnloader::Visit(CreatureMapType &); +template void ObjectGridUnloader::Visit(GameObjectMapType &); +template void ObjectGridUnloader::Visit(DynamicObjectMapType &); +template void ObjectGridUnloader::Visit(CorpseMapType &); +template void ObjectGridCleaner::Visit(GameObjectMapType &); +template void ObjectGridCleaner::Visit(DynamicObjectMapType &); +template void ObjectGridCleaner::Visit(CorpseMapType &); diff --git a/src/server/game/Maps/Grid/ObjectGridLoader.h b/src/server/game/Maps/Grid/ObjectGridLoader.h new file mode 100644 index 00000000000..e890bf8d482 --- /dev/null +++ b/src/server/game/Maps/Grid/ObjectGridLoader.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_OBJECTGRIDLOADER_H +#define TRINITY_OBJECTGRIDLOADER_H + +#include "Utilities/TypeList.h" +#include "Platform/Define.h" +#include "GameSystem/GridLoader.h" +#include "GridDefines.h" +#include "Cell.h" + +class ObjectWorldLoader; + +class ObjectGridLoader +{ + friend class ObjectWorldLoader; + + public: + ObjectGridLoader(NGridType &grid, Map* map, const Cell &cell) + : i_cell(cell), i_grid(grid), i_map(map), i_gameObjects(0), i_creatures(0), i_corpses (0) + {} + + void Load(GridType &grid); + void Visit(GameObjectMapType &m); + void Visit(CreatureMapType &m); + void Visit(CorpseMapType &) {} + + void Visit(DynamicObjectMapType&) { } + + void LoadN(void); + + private: + Cell i_cell; + NGridType &i_grid; + Map* i_map; + uint32 i_gameObjects; + uint32 i_creatures; + uint32 i_corpses; +}; + +class ObjectGridUnloader +{ + public: + ObjectGridUnloader(NGridType &grid) : i_grid(grid) {} + + void MoveToRespawnN(); + void UnloadN() + { + for (unsigned int x=0; x < MAX_NUMBER_OF_CELLS; ++x) + { + for (unsigned int y=0; y < MAX_NUMBER_OF_CELLS; ++y) + { + GridLoader loader; + loader.Unload(i_grid(x, y), *this); + } + } + } + + void Unload(GridType &grid); + template void Visit(GridRefManager &m); + private: + NGridType &i_grid; +}; + +class ObjectGridStoper +{ + public: + ObjectGridStoper(NGridType &grid) : i_grid(grid) {} + + void StopN() + { + for (unsigned int x=0; x < MAX_NUMBER_OF_CELLS; ++x) + { + for (unsigned int y=0; y < MAX_NUMBER_OF_CELLS; ++y) + { + GridLoader loader; + loader.Stop(i_grid(x, y), *this); + } + } + } + + void Stop(GridType &grid); + void Visit(CreatureMapType &m); + + template void Visit(GridRefManager &) {} + private: + NGridType &i_grid; +}; + +class ObjectGridCleaner +{ + public: + ObjectGridCleaner(NGridType &grid) : i_grid(grid) {} + + void CleanN() + { + for (unsigned int x=0; x < MAX_NUMBER_OF_CELLS; ++x) + { + for (unsigned int y=0; y < MAX_NUMBER_OF_CELLS; ++y) + { + GridLoader loader; + loader.Stop(i_grid(x, y), *this); + } + } + } + + void Stop(GridType &grid); + void Visit(CreatureMapType &m); + template void Visit(GridRefManager &); + private: + NGridType &i_grid; +}; + +typedef GridLoader GridLoaderType; +#endif + diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp new file mode 100644 index 00000000000..11bfdcd6f99 --- /dev/null +++ b/src/server/game/Maps/Map.cpp @@ -0,0 +1,3936 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MapManager.h" +#include "Player.h" +#include "Vehicle.h" +#include "GridNotifiers.h" +#include "Log.h" +#include "GridStates.h" +#include "CellImpl.h" +#include "InstanceData.h" +#include "Map.h" +#include "GridNotifiersImpl.h" +#include "Config/ConfigEnv.h" +#include "Transports.h" +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "World.h" +#include "Group.h" +#include "MapRefManager.h" +#include "Vehicle.h" +#include "WaypointManager.h" +#include "DBCEnums.h" +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "GossipDef.h" + +#include "MapInstanced.h" +#include "InstanceSaveMgr.h" +#include "VMapFactory.h" + +#define DEFAULT_GRID_EXPIRY 300 +#define MAX_GRID_LOAD_TIME 50 +#define MAX_CREATURE_ATTACK_RADIUS (45.0f * sWorld.getRate(RATE_CREATURE_AGGRO)) + +GridState* si_GridStates[MAX_GRID_STATE]; + +struct ScriptAction +{ + uint64 sourceGUID; + uint64 targetGUID; + uint64 ownerGUID; // owner of source if source is item + ScriptInfo const* script; // pointer to static script data +}; + +Map::~Map() +{ + UnloadAll(); + + while (!i_worldObjects.empty()) + { + WorldObject *obj = *i_worldObjects.begin(); + assert(obj->m_isWorldObject); + //assert(obj->GetTypeId() == TYPEID_CORPSE); + obj->RemoveFromWorld(); + obj->ResetMap(); + } + + if (!m_scriptSchedule.empty()) + sWorld.DecreaseScheduledScriptCount(m_scriptSchedule.size()); +} + +bool Map::ExistMap(uint32 mapid,int gx,int gy) +{ + int len = sWorld.GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1; + char* tmp = new char[len]; + snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),mapid,gx,gy); + + FILE *pf=fopen(tmp,"rb"); + + if (!pf) + { + sLog.outError("Map file '%s': does not exist!",tmp); + delete[] tmp; + return false; + } + + map_fileheader header; + fread(&header, sizeof(header), 1, pf); + if (header.mapMagic != uint32(MAP_MAGIC) || + header.versionMagic != uint32(MAP_VERSION_MAGIC)) + { + sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.",tmp); + delete [] tmp; + fclose(pf); //close file before return + return false; + } + + delete [] tmp; + fclose(pf); + return true; +} + +bool Map::ExistVMap(uint32 mapid,int gx,int gy) +{ + if (VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager()) + { + if (vmgr->isMapLoadingEnabled()) + { + // x and y are swapped !! => fixed now + bool exists = vmgr->existsMap((sWorld.GetDataPath()+ "vmaps").c_str(), mapid, gx,gy); + if (!exists) + { + std::string name = vmgr->getDirFileName(mapid,gx,gy); + sLog.outError("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()); + return false; + } + } + } + + return true; +} + +void Map::LoadVMap(int gx,int gy) +{ + // x and y are swapped !! + int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapManager()->loadMap((sWorld.GetDataPath()+ "vmaps").c_str(), GetId(), gx,gy); + switch(vmapLoadResult) + { + case VMAP::VMAP_LOAD_RESULT_OK: + sLog.outDetail("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: + sLog.outDetail("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: + DEBUG_LOG("Ignored VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx,gy,gx,gy); + break; + } +} + +void Map::LoadMap(int gx,int gy, bool reload) +{ + if (i_InstanceId != 0) + { + if (GridMaps[gx][gy]) + return; + + // load grid map for base map + if (!m_parentMap->GridMaps[gx][gy]) + m_parentMap->EnsureGridCreated(GridPair(63-gx,63-gy)); + + ((MapInstanced*)(m_parentMap))->AddGridMapReference(GridPair(gx,gy)); + GridMaps[gx][gy] = m_parentMap->GridMaps[gx][gy]; + return; + } + + if (GridMaps[gx][gy] && !reload) + return; + + //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]) + { + sLog.outDetail("Unloading previously loaded map %u before reloading.",GetId()); + delete (GridMaps[gx][gy]); + GridMaps[gx][gy]=NULL; + } + + // map file name + char *tmp=NULL; + 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); + sLog.outDetail("Loading map %s",tmp); + // loading data + GridMaps[gx][gy] = new GridMap(); + if (!GridMaps[gx][gy]->loadData(tmp)) + { + sLog.outError("Error loading map file: \n %s\n", tmp); + } + delete [] tmp; +} + +void Map::LoadMapAndVMap(int gx,int gy) +{ + LoadMap(gx,gy); + if (i_InstanceId == 0) + LoadVMap(gx, gy); // Only load the data for the base map +} + +void Map::InitStateMachine() +{ + si_GridStates[GRID_STATE_INVALID] = new InvalidState; + si_GridStates[GRID_STATE_ACTIVE] = new ActiveState; + si_GridStates[GRID_STATE_IDLE] = new IdleState; + si_GridStates[GRID_STATE_REMOVAL] = new RemovalState; +} + +void Map::DeleteStateMachine() +{ + delete si_GridStates[GRID_STATE_INVALID]; + delete si_GridStates[GRID_STATE_ACTIVE]; + delete si_GridStates[GRID_STATE_IDLE]; + delete si_GridStates[GRID_STATE_REMOVAL]; +} + +Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) + : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId), m_unloadTimer(0), + m_activeNonPlayersIter(m_activeNonPlayers.end()), + i_gridExpiry(expiry), m_parentMap(_parent ? _parent : this), + m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), + m_VisibilityNotifyPeriod(DEFAULT_VISIBILITY_NOTIFY_PERIOD), + i_scriptLock(false) +{ + for (unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx) + { + for (unsigned int j=0; j < MAX_NUMBER_OF_GRIDS; ++j) + { + //z code + GridMaps[idx][j] =NULL; + setNGrid(NULL, idx, j); + } + } + + //lets initialize visibility distance for map + Map::InitVisibilityDistance(); +} + +void Map::InitVisibilityDistance() +{ + //init visibility for continents + m_VisibleDistance = World::GetMaxVisibleDistanceOnContinents(); + m_VisibilityNotifyPeriod = World::GetVisibilityNotifyPeriodOnContinents(); +} + +// Template specialization of utility methods +template +void Map::AddToGrid(T* obj, NGridType *grid, Cell const& cell) +{ + if (obj->m_isWorldObject) + (*grid)(cell.CellX(), cell.CellY()).template AddWorldObject(obj); + else + (*grid)(cell.CellX(), cell.CellY()).template AddGridObject(obj); +} + +template<> +void Map::AddToGrid(Creature* obj, NGridType *grid, Cell const& cell) +{ + if (obj->m_isWorldObject) + (*grid)(cell.CellX(), cell.CellY()).AddWorldObject(obj); + else + (*grid)(cell.CellX(), cell.CellY()).AddGridObject(obj); + + obj->SetCurrentCell(cell); +} + +template +void Map::RemoveFromGrid(T* obj, NGridType *grid, Cell const& cell) +{ + if (obj->m_isWorldObject) + (*grid)(cell.CellX(), cell.CellY()).template RemoveWorldObject(obj); + else + (*grid)(cell.CellX(), cell.CellY()).template RemoveGridObject(obj); +} + +template +void Map::SwitchGridContainers(T* obj, bool on) +{ + CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); + if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + { + sLog.outError("Map::SwitchGridContainers: Object " I64FMT " has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUID(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord); + return; + } + + Cell cell(p); + if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) + return; + + DEBUG_LOG("Switch object " I64FMT " from grid[%u,%u] %u", obj->GetGUID(), cell.data.Part.grid_x, cell.data.Part.grid_y, on); + NGridType *ngrid = getNGrid(cell.GridX(), cell.GridY()); + assert(ngrid != NULL); + + GridType &grid = (*ngrid)(cell.CellX(), cell.CellY()); + + if (on) + { + grid.RemoveGridObject(obj); + grid.AddWorldObject(obj); + /*if (!grid.RemoveGridObject(obj, obj->GetGUID()) + || !grid.AddWorldObject(obj, obj->GetGUID())) + { + assert(false); + }*/ + } + else + { + grid.RemoveWorldObject(obj); + grid.AddGridObject(obj); + /*if (!grid.RemoveWorldObject(obj, obj->GetGUID()) + || !grid.AddGridObject(obj, obj->GetGUID())) + { + assert(false); + }*/ + } + obj->m_isWorldObject = on; +} + +template void Map::SwitchGridContainers(Creature *, bool); +//template void Map::SwitchGridContainers(DynamicObject *, bool); + +template +void Map::DeleteFromWorld(T* obj) +{ + // Note: In case resurrectable corpse and pet its removed from global lists in own destructor + delete obj; +} + +template<> +void Map::DeleteFromWorld(Player* pl) +{ + ObjectAccessor::Instance().RemoveObject(pl); + delete pl; +} + +void +Map::EnsureGridCreated(const GridPair &p) +{ + if (!getNGrid(p.x_coord, p.y_coord)) + { + Guard guard(*this); + if (!getNGrid(p.x_coord, p.y_coord)) + { + sLog.outDebug("Creating grid[%u,%u] for map %u instance %u", p.x_coord, p.y_coord, GetId(), i_InstanceId); + + setNGrid(new NGridType(p.x_coord*MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, sWorld.getConfig(CONFIG_GRID_UNLOAD)), + p.x_coord, p.y_coord); + + // build a linkage between this map and NGridType + buildNGridLinkage(getNGrid(p.x_coord, p.y_coord)); + + getNGrid(p.x_coord, p.y_coord)->SetGridState(GRID_STATE_IDLE); + + //z coord + int gx = (MAX_NUMBER_OF_GRIDS - 1) - p.x_coord; + int gy = (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord; + + if (!GridMaps[gx][gy]) + LoadMapAndVMap(gx,gy); + } + } +} + +void +Map::EnsureGridLoadedAtEnter(const Cell &cell, Player *player) +{ + EnsureGridLoaded(cell); + NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); + assert(grid != NULL); + + if (player) + { + DEBUG_LOG("Player %s enter cell[%u,%u] triggers loading of grid[%u,%u] on map %u", player->GetName(), cell.CellX(), cell.CellY(), cell.GridX(), cell.GridY(), GetId()); + } + else + { + DEBUG_LOG("Active object nearby triggers loading of grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), GetId()); + } + + // refresh grid state & timer + if (grid->GetGridState() != GRID_STATE_ACTIVE) + { + ResetGridExpiry(*grid, 0.1f); + grid->SetGridState(GRID_STATE_ACTIVE); + } +} + +bool Map::EnsureGridLoaded(const Cell &cell) +{ + EnsureGridCreated(GridPair(cell.GridX(), cell.GridY())); + NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); + + assert(grid != NULL); + if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY())) + { + sLog.outDebug("Loading grid[%u,%u] for map %u instance %u", cell.GridX(), cell.GridY(), GetId(), i_InstanceId); + + ObjectGridLoader loader(*grid, this, cell); + loader.LoadN(); + + // Add resurrectable corpses to world object list in grid + ObjectAccessor::Instance().AddCorpsesToGrid(GridPair(cell.GridX(),cell.GridY()),(*grid)(cell.CellX(), cell.CellY()), this); + + setGridObjectDataLoaded(true,cell.GridX(), cell.GridY()); + return true; + } + + return false; +} + +void Map::LoadGrid(float x, float y) +{ + CellPair pair = Trinity::ComputeCellPair(x, y); + Cell cell(pair); + EnsureGridLoaded(cell); +} + +bool Map::Add(Player *player) +{ + // Check if we are adding to correct map + assert (player->GetMap() == this); + CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); + if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + { + sLog.outError("Map::Add: Player (GUID: %u) has invalid coordinates X:%f Y:%f grid cell [%u:%u]", player->GetGUIDLow(), player->GetPositionX(), player->GetPositionY(), p.x_coord, p.y_coord); + return false; + } + + player->SetMap(this); + + Cell cell(p); + EnsureGridLoadedAtEnter(cell, player); + NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); + assert(grid != NULL); + AddToGrid(player, grid, cell); + + player->AddToWorld(); + + SendInitSelf(player); + SendInitTransports(player); + + player->m_clientGUIDs.clear(); + player->UpdateObjectVisibility(true); + + return true; +} + +template +void +Map::Add(T *obj) +{ + CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); + if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + { + sLog.outError("Map::Add: Object " UI64FMTD " has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUID(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord); + return; + } + + Cell cell(p); + if (obj->IsInWorld()) // need some clean up later + { + obj->UpdateObjectVisibility(true); + return; + } + + if (obj->isActiveObject()) + EnsureGridLoadedAtEnter(cell); + else + EnsureGridCreated(GridPair(cell.GridX(), cell.GridY())); + + NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); + assert(grid != NULL); + + AddToGrid(obj,grid,cell); + //obj->SetMap(this); + obj->AddToWorld(); + + if (obj->isActiveObject()) + AddToActive(obj); + + DEBUG_LOG("Object %u enters grid[%u,%u]", GUID_LOPART(obj->GetGUID()), cell.GridX(), cell.GridY()); + + //something, such as vehicle, needs to be update immediately + //also, trigger needs to cast spell, if not update, cannot see visual + obj->UpdateObjectVisibility(true); +} + +/* +void Map::MessageBroadcast(Player *player, WorldPacket *msg, bool to_self) +{ + CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); + + if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + { + sLog.outError("Map::MessageBroadcast: Player (GUID: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", player->GetGUIDLow(), player->GetPositionX(), player->GetPositionY(), p.x_coord, p.y_coord); + return; + } + + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) + return; + + Trinity::MessageDeliverer post_man(*player, msg, to_self); + TypeContainerVisitor message(post_man); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, message, *this, *player, GetVisibilityDistance()); +} + +void Map::MessageBroadcast(WorldObject *obj, WorldPacket *msg) +{ + CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); + + if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + { + sLog.outError("Map::MessageBroadcast: Object (GUID: %u TypeId: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUIDLow(), obj->GetTypeId(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord); + return; + } + + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) + return; + + //TODO: currently on continents when Visibility.Distance.InFlight > Visibility.Distance.Continents + //we have alot of blinking mobs because monster move packet send is broken... + Trinity::ObjectMessageDeliverer post_man(*obj,msg); + TypeContainerVisitor message(post_man); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, message, *this, *obj, GetVisibilityDistance()); +} + +void Map::MessageDistBroadcast(Player *player, WorldPacket *msg, float dist, bool to_self, bool own_team_only) +{ + CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); + + if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + { + sLog.outError("Map::MessageBroadcast: Player (GUID: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", player->GetGUIDLow(), player->GetPositionX(), player->GetPositionY(), p.x_coord, p.y_coord); + return; + } + + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) + return; + + Trinity::MessageDistDeliverer post_man(*player, msg, dist, to_self, own_team_only); + TypeContainerVisitor message(post_man); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, message, *this, *player, dist); +} + +void Map::MessageDistBroadcast(WorldObject *obj, WorldPacket *msg, float dist) +{ + CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); + + if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + { + sLog.outError("Map::MessageBroadcast: Object (GUID: %u TypeId: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUIDLow(), obj->GetTypeId(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord); + return; + } + + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) + return; + + Trinity::ObjectMessageDistDeliverer post_man(*obj, msg, dist); + TypeContainerVisitor message(post_man); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, message, *this, *obj, dist); +} +*/ + +bool Map::loaded(const GridPair &p) const +{ + return (getNGrid(p.x_coord, p.y_coord) && isGridObjectDataLoaded(p.x_coord, p.y_coord)); +} + +void Map::Update(const uint32 &t_diff) +{ + /// update players at tick + for (m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter) + { + Player* plr = m_mapRefIter->getSource(); + if (plr && plr->IsInWorld()) + plr->Update(t_diff); + } + + /// update active cells around players and active objects + resetMarkedCells(); + + Trinity::ObjectUpdater updater(t_diff); + // for creature + TypeContainerVisitor grid_object_update(updater); + // for pets + TypeContainerVisitor world_object_update(updater); + + // the player iterator is stored in the map object + // to make sure calls to Map::Remove don't invalidate it + for (m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter) + { + Player* plr = m_mapRefIter->getSource(); + + if (!plr->IsInWorld()) + continue; + + CellPair standing_cell(Trinity::ComputeCellPair(plr->GetPositionX(), plr->GetPositionY())); + + // Check for correctness of standing_cell, it also avoids problems with update_cell + if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + continue; + + // the overloaded operators handle range checking + // so ther's no need for range checking inside the loop + CellPair begin_cell(standing_cell), end_cell(standing_cell); + //lets update mobs/objects in ALL visible cells around player! + CellArea area = Cell::CalculateCellArea(*plr, GetVisibilityDistance()); + area.ResizeBorders(begin_cell, end_cell); + + for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x) + { + for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y) + { + // marked cells are those that have been visited + // don't visit the same cell twice + uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; + if (!isCellMarked(cell_id)) + { + markCell(cell_id); + CellPair pair(x,y); + Cell cell(pair); + cell.data.Part.reserved = CENTER_DISTRICT; + //cell.SetNoCreate(); + cell.Visit(pair, grid_object_update, *this); + cell.Visit(pair, world_object_update, *this); + } + } + } + } + + // non-player active objects + if (!m_activeNonPlayers.empty()) + { + for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end();) + { + // skip not in world + WorldObject* obj = *m_activeNonPlayersIter; + + // step before processing, in this case if Map::Remove remove next object we correctly + // step to next-next, and if we step to end() then newly added objects can wait next update. + ++m_activeNonPlayersIter; + + if (!obj->IsInWorld()) + continue; + + CellPair standing_cell(Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY())); + + // Check for correctness of standing_cell, it also avoids problems with update_cell + if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + continue; + + // the overloaded operators handle range checking + // so ther's no need for range checking inside the loop + CellPair begin_cell(standing_cell), end_cell(standing_cell); + begin_cell << 1; begin_cell -= 1; // upper left + end_cell >> 1; end_cell += 1; // lower right + + for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x) + { + for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y) + { + // marked cells are those that have been visited + // don't visit the same cell twice + uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; + if (!isCellMarked(cell_id)) + { + markCell(cell_id); + CellPair pair(x,y); + Cell cell(pair); + cell.data.Part.reserved = CENTER_DISTRICT; + //cell.SetNoCreate(); + cell.Visit(pair, grid_object_update, *this); + cell.Visit(pair, world_object_update, *this); + } + } + } + } + } + + ///- Process necessary scripts + if (!m_scriptSchedule.empty()) + { + i_scriptLock = true; + ScriptsProcess(); + i_scriptLock = false; + } + + MoveAllCreaturesInMoveList(); + + if (!m_mapRefManager.isEmpty() || !m_activeNonPlayers.empty()) + ProcessRelocationNotifies(t_diff); +} + +struct ResetNotifier +{ + templateinline void resetNotify(GridRefManager &m) + { + for (typename GridRefManager::iterator iter=m.begin(); iter != m.end(); ++iter) + iter->getSource()->ResetAllNotifies(); + } + template void Visit(GridRefManager &) {} + void Visit(CreatureMapType &m) { resetNotify(m);} + void Visit(PlayerMapType &m) { resetNotify(m);} +}; + +void Map::ProcessRelocationNotifies(const uint32 & diff) +{ + for (GridRefManager::iterator i = GridRefManager::begin(); i != GridRefManager::end(); ++i) + { + NGridType *grid = i->getSource(); + + if (grid->GetGridState() != GRID_STATE_ACTIVE) + continue; + + grid->getGridInfoRef()->getRelocationTimer().TUpdate(diff); + if (!grid->getGridInfoRef()->getRelocationTimer().TPassed()) + continue; + + uint32 gx = grid->getX(), gy = grid->getY(); + + CellPair cell_min(gx*MAX_NUMBER_OF_CELLS, gy*MAX_NUMBER_OF_CELLS); + CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS); + + for (uint32 x = cell_min.x_coord; x < cell_max.x_coord; ++x) + { + for (uint32 y = cell_min.y_coord; y < cell_max.y_coord; ++y) + { + uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; + if (!isCellMarked(cell_id)) + continue; + + CellPair pair(x,y); + Cell cell(pair); + cell.SetNoCreate(); + + Trinity::DelayedUnitRelocation cell_relocation(cell, pair, *this, GetVisibilityDistance()); + TypeContainerVisitor grid_object_relocation(cell_relocation); + TypeContainerVisitor world_object_relocation(cell_relocation); + Visit(cell, grid_object_relocation); + Visit(cell, world_object_relocation); + } + } + } + + ResetNotifier reset; + TypeContainerVisitor grid_notifier(reset); + TypeContainerVisitor world_notifier(reset); + for (GridRefManager::iterator i = GridRefManager::begin(); i != GridRefManager::end(); ++i) + { + NGridType *grid = i->getSource(); + + if (grid->GetGridState() != GRID_STATE_ACTIVE) + continue; + + if (!grid->getGridInfoRef()->getRelocationTimer().TPassed()) + continue; + + grid->getGridInfoRef()->getRelocationTimer().TReset(diff, m_VisibilityNotifyPeriod); + + uint32 gx = grid->getX(), gy = grid->getY(); + + CellPair cell_min(gx*MAX_NUMBER_OF_CELLS, gy*MAX_NUMBER_OF_CELLS); + CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS); + + for (uint32 x = cell_min.x_coord; x < cell_max.x_coord; ++x) + { + for (uint32 y = cell_min.y_coord; y < cell_max.y_coord; ++y) + { + uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; + if (!isCellMarked(cell_id)) + continue; + + CellPair pair(x,y); + Cell cell(pair); + cell.SetNoCreate(); + Visit(cell, grid_notifier); + Visit(cell, world_notifier); + } + } + } +} + +void Map::Remove(Player *player, bool remove) +{ + player->RemoveFromWorld(); + SendRemoveTransports(player); + + CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); + if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + sLog.outCrash("Map::Remove: Player is in invalid cell!"); + else + { + Cell cell(p); + if (!getNGrid(cell.data.Part.grid_x, cell.data.Part.grid_y)) + sLog.outError("Map::Remove() i_grids was NULL x:%d, y:%d",cell.data.Part.grid_x,cell.data.Part.grid_y); + else + { + DEBUG_LOG("Remove player %s from grid[%u,%u]", player->GetName(), cell.GridX(), cell.GridY()); + NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); + assert(grid != NULL); + + player->UpdateObjectVisibility(true); + RemoveFromGrid(player,grid,cell); + } + } + + if (remove) + DeleteFromWorld(player); +} + +bool Map::RemoveBones(uint64 guid, float x, float y) +{ + if (IsRemovalGrid(x, y)) + { + Corpse * corpse = ObjectAccessor::Instance().GetObjectInWorld(GetId(), x, y, guid, (Corpse*)NULL); + if (corpse && corpse->GetTypeId() == TYPEID_CORPSE && corpse->GetType() == CORPSE_BONES) + corpse->DeleteBonesFromWorld(); + else + return false; + } + return true; +} + +template +void +Map::Remove(T *obj, bool remove) +{ + obj->RemoveFromWorld(); + if (obj->isActiveObject()) + RemoveFromActive(obj); + + CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); + if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + sLog.outError("Map::Remove: Object " I64FMT " has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUID(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord); + else + { + Cell cell(p); + if (loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) + { + DEBUG_LOG("Remove object " I64FMT " from grid[%u,%u]", obj->GetGUID(), cell.data.Part.grid_x, cell.data.Part.grid_y); + NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); + assert(grid != NULL); + + obj->UpdateObjectVisibility(true); + RemoveFromGrid(obj,grid,cell); + } + } + + obj->ResetMap(); + + if (remove) + { + // if option set then object already saved at this moment + if (!sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY)) + obj->SaveRespawnTime(); + DeleteFromWorld(obj); + } +} + +void +Map::PlayerRelocation(Player *player, float x, float y, float z, float orientation) +{ + assert(player); + + CellPair old_val = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); + CellPair new_val = Trinity::ComputeCellPair(x, y); + + Cell old_cell(old_val); + Cell new_cell(new_val); + + player->Relocate(x, y, z, orientation); + + if (old_cell.DiffGrid(new_cell) || old_cell.DiffCell(new_cell)) + { + DEBUG_LOG("Player %s relocation grid[%u,%u]cell[%u,%u]->grid[%u,%u]cell[%u,%u]", player->GetName(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); + + NGridType* oldGrid = getNGrid(old_cell.GridX(), old_cell.GridY()); + RemoveFromGrid(player, oldGrid,old_cell); + + if (old_cell.DiffGrid(new_cell)) + EnsureGridLoadedAtEnter(new_cell, player); + + NGridType* newGrid = getNGrid(new_cell.GridX(), new_cell.GridY()); + AddToGrid(player, newGrid,new_cell); + } + + player->UpdateObjectVisibility(false); +} + +void +Map::CreatureRelocation(Creature *creature, float x, float y, float z, float ang) +{ + assert(CheckGridIntegrity(creature,false)); + + Cell old_cell = creature->GetCurrentCell(); + + CellPair new_val = Trinity::ComputeCellPair(x, y); + Cell new_cell(new_val); + + // delay creature move for grid/cell to grid/cell moves + if (old_cell.DiffCell(new_cell) || old_cell.DiffGrid(new_cell)) + { + #ifdef TRINITY_DEBUG + if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) + sLog.outDebug("Creature (GUID: %u Entry: %u) added to moving list from grid[%u,%u]cell[%u,%u] to grid[%u,%u]cell[%u,%u].", creature->GetGUIDLow(), creature->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); + #endif + AddCreatureToMoveList(creature, x, y, z, ang); + // in diffcell/diffgrid case notifiers called at finishing move creature in Map::MoveAllCreaturesInMoveList + } + else + { + creature->Relocate(x, y, z, ang); + creature->UpdateObjectVisibility(false); + } + + assert(CheckGridIntegrity(creature,true)); +} + +void Map::AddCreatureToMoveList(Creature *c, float x, float y, float z, float ang) +{ + if (!c) + return; + + i_creaturesToMove[c] = CreatureMover(x, y, z, ang); +} + +void Map::MoveAllCreaturesInMoveList() +{ + while (!i_creaturesToMove.empty()) + { + // get data and remove element; + CreatureMoveList::iterator iter = i_creaturesToMove.begin(); + Creature* c = iter->first; + CreatureMover cm = iter->second; + i_creaturesToMove.erase(iter); + + // calculate cells + CellPair new_val = Trinity::ComputeCellPair(cm.x, cm.y); + Cell new_cell(new_val); + + // do move or do move to respawn or remove creature if previous all fail + if (CreatureCellRelocation(c,new_cell)) + { + // update pos + c->Relocate(cm.x, cm.y, cm.z, cm.ang); + //CreatureRelocationNotify(c,new_cell,new_cell.cellPair()); + c->UpdateObjectVisibility(false); + } + else + { + // if creature can't be move in new cell/grid (not loaded) move it to repawn cell/grid + // creature coordinates will be updated and notifiers send + if (!CreatureRespawnRelocation(c)) + { + // ... or unload (if respawn grid also not loaded) + #ifdef TRINITY_DEBUG + if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) + sLog.outDebug("Creature (GUID: %u Entry: %u) cannot be move to unloaded respawn grid.",c->GetGUIDLow(),c->GetEntry()); + #endif + AddObjectToRemoveList(c); + } + } + } +} + +bool Map::CreatureCellRelocation(Creature *c, Cell new_cell) +{ + Cell const& old_cell = c->GetCurrentCell(); + if (!old_cell.DiffGrid(new_cell)) // in same grid + { + // if in same cell then none do + if (old_cell.DiffCell(new_cell)) + { + #ifdef TRINITY_DEBUG + if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) + sLog.outDebug("Creature (GUID: %u Entry: %u) moved in grid[%u,%u] from cell[%u,%u] to cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.CellX(), new_cell.CellY()); + #endif + + RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); + AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); + } + else + { + #ifdef TRINITY_DEBUG + if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) + sLog.outDebug("Creature (GUID: %u Entry: %u) moved in same grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY()); + #endif + } + + return true; + } + + // in diff. grids but active creature + if (c->isActiveObject()) + { + EnsureGridLoadedAtEnter(new_cell); + + #ifdef TRINITY_DEBUG + if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) + sLog.outDebug("Active creature (GUID: %u Entry: %u) moved from grid[%u,%u]cell[%u,%u] to grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); + #endif + + RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); + AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); + + return true; + } + + // in diff. loaded grid normal creature + if (loaded(GridPair(new_cell.GridX(), new_cell.GridY()))) + { + #ifdef TRINITY_DEBUG + if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) + sLog.outDebug("Creature (GUID: %u Entry: %u) moved from grid[%u,%u]cell[%u,%u] to grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); + #endif + + RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); + EnsureGridCreated(GridPair(new_cell.GridX(), new_cell.GridY())); + AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); + + return true; + } + + // fail to move: normal creature attempt move to unloaded grid + #ifdef TRINITY_DEBUG + if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) + sLog.outDebug("Creature (GUID: %u Entry: %u) attempted to move from grid[%u,%u]cell[%u,%u] to unloaded grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); + #endif + return false; +} + +bool Map::CreatureRespawnRelocation(Creature *c) +{ + float resp_x, resp_y, resp_z, resp_o; + c->GetRespawnCoord(resp_x, resp_y, resp_z, &resp_o); + + CellPair resp_val = Trinity::ComputeCellPair(resp_x, resp_y); + Cell resp_cell(resp_val); + + c->CombatStop(); + c->GetMotionMaster()->Clear(); + + #ifdef TRINITY_DEBUG + if ((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES) == 0) + sLog.outDebug("Creature (GUID: %u Entry: %u) moved from grid[%u,%u]cell[%u,%u] to respawn grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), c->GetCurrentCell().GridX(), c->GetCurrentCell().GridY(), c->GetCurrentCell().CellX(), c->GetCurrentCell().CellY(), resp_cell.GridX(), resp_cell.GridY(), resp_cell.CellX(), resp_cell.CellY()); + #endif + + // teleport it to respawn point (like normal respawn if player see) + if (CreatureCellRelocation(c,resp_cell)) + { + c->Relocate(resp_x, resp_y, resp_z, resp_o); + c->GetMotionMaster()->Initialize(); // prevent possible problems with default move generators + //CreatureRelocationNotify(c,resp_cell,resp_cell.cellPair()); + c->UpdateObjectVisibility(false); + return true; + } + else + return false; +} + +bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool unloadAll) +{ + NGridType *grid = getNGrid(x, y); + assert(grid != NULL); + + { + if (!unloadAll && ActiveObjectsNearGrid(x, y)) + return false; + + sLog.outDebug("Unloading grid[%u,%u] for map %u", x,y, GetId()); + + ObjectGridUnloader unloader(*grid); + + if (!unloadAll) + { + // Finish creature moves, remove and delete all creatures with delayed remove before moving to respawn grids + // Must know real mob position before move + MoveAllCreaturesInMoveList(); + + // move creatures to respawn grids if this is diff.grid or to remove list + unloader.MoveToRespawnN(); + + // Finish creature moves, remove and delete all creatures with delayed remove before unload + MoveAllCreaturesInMoveList(); + } + + ObjectGridCleaner cleaner(*grid); + cleaner.CleanN(); + + RemoveAllObjectsInRemoveList(); + + unloader.UnloadN(); + + assert(i_objectsToRemove.empty()); + + delete grid; + setNGrid(NULL, x, y); + } + int gx = (MAX_NUMBER_OF_GRIDS - 1) - x; + int gy = (MAX_NUMBER_OF_GRIDS - 1) - y; + + // delete grid map, but don't delete if it is from parent map (and thus only reference) + //+++if (GridMaps[gx][gy]) don't check for GridMaps[gx][gy], we might have to unload vmaps + { + if (i_InstanceId == 0) + { + if (GridMaps[gx][gy]) + { + GridMaps[gx][gy]->unloadData(); + delete GridMaps[gx][gy]; + } + // x and y are swapped + VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId(), gx, gy); + } + else + ((MapInstanced*)m_parentMap)->RemoveGridMapReference(GridPair(gx, gy)); + + GridMaps[gx][gy] = NULL; + } + DEBUG_LOG("Unloading grid[%u,%u] for map %u finished", x,y, GetId()); + return true; +} + +void Map::RemoveAllPlayers() +{ + if (HavePlayers()) + { + for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + { + Player* plr = itr->getSource(); + if (!plr->IsBeingTeleportedFar()) + { + // this is happening for bg + sLog.outError("Map::UnloadAll: player %s is still in map %u during unload, this should not happen!", plr->GetName(), GetId()); + plr->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation()); + } + } + } +} + +void Map::UnloadAll() +{ + // clear all delayed moves, useless anyway do this moves before map unload. + i_creaturesToMove.clear(); + + for (GridRefManager::iterator i = GridRefManager::begin(); i != GridRefManager::end();) + { + NGridType &grid(*i->getSource()); + ++i; + UnloadGrid(grid.getX(), grid.getY(), true); // deletes the grid and removes it from the GridRefManager + } +} + +//***************************** +// Grid function +//***************************** +GridMap::GridMap() +{ + m_flags = 0; + // Area data + m_gridArea = 0; + m_area_map = NULL; + // Height level data + m_gridHeight = INVALID_HEIGHT; + m_gridGetHeight = &GridMap::getHeightFromFlat; + m_V9 = NULL; + m_V8 = NULL; + // Liquid data + m_liquidType = 0; + m_liquid_offX = 0; + m_liquid_offY = 0; + m_liquid_width = 0; + m_liquid_height = 0; + m_liquidLevel = INVALID_HEIGHT; + m_liquid_type = NULL; + m_liquid_map = NULL; +} + +GridMap::~GridMap() +{ + unloadData(); +} + +bool GridMap::loadData(char *filename) +{ + // Unload old data if exist + unloadData(); + + map_fileheader header; + // Not return error if file not found + FILE *in = fopen(filename, "rb"); + if (!in) + return true; + fread(&header, sizeof(header),1,in); + if (header.mapMagic == uint32(MAP_MAGIC) && + header.versionMagic == uint32(MAP_VERSION_MAGIC)) + { + // loadup area data + if (header.areaMapOffset && !loadAreaData(in, header.areaMapOffset, header.areaMapSize)) + { + sLog.outError("Error loading map area data\n"); + fclose(in); + return false; + } + // loadup height data + if (header.heightMapOffset && !loadHeihgtData(in, header.heightMapOffset, header.heightMapSize)) + { + sLog.outError("Error loading map height data\n"); + fclose(in); + return false; + } + // loadup liquid data + if (header.liquidMapOffset && !loadLiquidData(in, header.liquidMapOffset, header.liquidMapSize)) + { + sLog.outError("Error loading map liquids data\n"); + fclose(in); + return false; + } + fclose(in); + return true; + } + sLog.outError("Map file '%s' is a non-compatible version (outdated?). Please, create new using the ad.exe program.", filename); + fclose(in); + return false; +} + +void GridMap::unloadData() +{ + if (m_area_map) delete[] m_area_map; + if (m_V9) delete[] m_V9; + if (m_V8) delete[] m_V8; + if (m_liquid_type) delete[] m_liquid_type; + if (m_liquid_map) delete[] m_liquid_map; + m_area_map = NULL; + m_V9 = NULL; + m_V8 = NULL; + m_liquid_type = NULL; + m_liquid_map = NULL; + m_gridGetHeight = &GridMap::getHeightFromFlat; +} + +bool GridMap::loadAreaData(FILE *in, uint32 offset, uint32 /*size*/) +{ + map_areaHeader header; + fseek(in, offset, SEEK_SET); + fread(&header, sizeof(header), 1, in); + if (header.fourcc != uint32(MAP_AREA_MAGIC)) + return false; + + m_gridArea = header.gridArea; + if (!(header.flags & MAP_AREA_NO_AREA)) + { + m_area_map = new uint16 [16*16]; + fread(m_area_map, sizeof(uint16), 16*16, in); + } + return true; +} + +bool GridMap::loadHeihgtData(FILE *in, uint32 offset, uint32 /*size*/) +{ + map_heightHeader header; + fseek(in, offset, SEEK_SET); + fread(&header, sizeof(header), 1, in); + if (header.fourcc != uint32(MAP_HEIGHT_MAGIC)) + return false; + + m_gridHeight = header.gridHeight; + if (!(header.flags & MAP_HEIGHT_NO_HEIGHT)) + { + if ((header.flags & MAP_HEIGHT_AS_INT16)) + { + m_uint16_V9 = new uint16 [129*129]; + m_uint16_V8 = new uint16 [128*128]; + fread(m_uint16_V9, sizeof(uint16), 129*129, in); + fread(m_uint16_V8, sizeof(uint16), 128*128, in); + m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 65535; + m_gridGetHeight = &GridMap::getHeightFromUint16; + } + else if ((header.flags & MAP_HEIGHT_AS_INT8)) + { + m_uint8_V9 = new uint8 [129*129]; + m_uint8_V8 = new uint8 [128*128]; + fread(m_uint8_V9, sizeof(uint8), 129*129, in); + fread(m_uint8_V8, sizeof(uint8), 128*128, in); + m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 255; + m_gridGetHeight = &GridMap::getHeightFromUint8; + } + else + { + m_V9 = new float [129*129]; + m_V8 = new float [128*128]; + fread(m_V9, sizeof(float), 129*129, in); + fread(m_V8, sizeof(float), 128*128, in); + m_gridGetHeight = &GridMap::getHeightFromFloat; + } + } + else + m_gridGetHeight = &GridMap::getHeightFromFlat; + return true; +} + +bool GridMap::loadLiquidData(FILE *in, uint32 offset, uint32 /*size*/) +{ + map_liquidHeader header; + fseek(in, offset, SEEK_SET); + fread(&header, sizeof(header), 1, in); + if (header.fourcc != uint32(MAP_LIQUID_MAGIC)) + return false; + + m_liquidType = header.liquidType; + m_liquid_offX = header.offsetX; + m_liquid_offY = header.offsetY; + m_liquid_width = header.width; + m_liquid_height= header.height; + m_liquidLevel = header.liquidLevel; + + if (!(header.flags & MAP_LIQUID_NO_TYPE)) + { + m_liquid_type = new uint8 [16*16]; + fread(m_liquid_type, sizeof(uint8), 16*16, in); + } + if (!(header.flags & MAP_LIQUID_NO_HEIGHT)) + { + m_liquid_map = new float [m_liquid_width*m_liquid_height]; + fread(m_liquid_map, sizeof(float), m_liquid_width*m_liquid_height, in); + } + return true; +} + +uint16 GridMap::getArea(float x, float y) +{ + if (!m_area_map) + return m_gridArea; + + x = 16 * (32 - x/SIZE_OF_GRIDS); + y = 16 * (32 - y/SIZE_OF_GRIDS); + int lx = (int)x & 15; + int ly = (int)y & 15; + return m_area_map[lx*16 + ly]; +} + +float GridMap::getHeightFromFlat(float /*x*/, float /*y*/) const +{ + return m_gridHeight; +} + +float GridMap::getHeightFromFloat(float x, float y) const +{ + if (!m_V8 || !m_V9) + return m_gridHeight; + + x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); + y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); + + int x_int = (int)x; + int y_int = (int)y; + x -= x_int; + y -= y_int; + x_int&=(MAP_RESOLUTION - 1); + y_int&=(MAP_RESOLUTION - 1); + + // Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid + // +--------------> X + // | h1-------h2 Coordinates is: + // | | \ 1 / | h1 0,0 + // | | \ / | h2 0,1 + // | | 2 h5 3 | h3 1,0 + // | | / \ | h4 1,1 + // | | / 4 \ | h5 1/2,1/2 + // | h3-------h4 + // V Y + // For find height need + // 1 - detect triangle + // 2 - solve linear equation from triangle points + // Calculate coefficients for solve h = a*x + b*y + c + + float a,b,c; + // Select triangle: + if (x+y < 1) + { + if (x > y) + { + // 1 triangle (h1, h2, h5 points) + float h1 = m_V9[(x_int)*129 + y_int]; + float h2 = m_V9[(x_int+1)*129 + y_int]; + float h5 = 2 * m_V8[x_int*128 + y_int]; + a = h2-h1; + b = h5-h1-h2; + c = h1; + } + else + { + // 2 triangle (h1, h3, h5 points) + float h1 = m_V9[x_int*129 + y_int ]; + float h3 = m_V9[x_int*129 + y_int+1]; + float h5 = 2 * m_V8[x_int*128 + y_int]; + a = h5 - h1 - h3; + b = h3 - h1; + c = h1; + } + } + else + { + if (x > y) + { + // 3 triangle (h2, h4, h5 points) + float h2 = m_V9[(x_int+1)*129 + y_int ]; + float h4 = m_V9[(x_int+1)*129 + y_int+1]; + float h5 = 2 * m_V8[x_int*128 + y_int]; + a = h2 + h4 - h5; + b = h4 - h2; + c = h5 - h4; + } + else + { + // 4 triangle (h3, h4, h5 points) + float h3 = m_V9[(x_int)*129 + y_int+1]; + float h4 = m_V9[(x_int+1)*129 + y_int+1]; + float h5 = 2 * m_V8[x_int*128 + y_int]; + a = h4 - h3; + b = h3 + h4 - h5; + c = h5 - h4; + } + } + // Calculate height + return a * x + b * y + c; +} + +float GridMap::getHeightFromUint8(float x, float y) const +{ + if (!m_uint8_V8 || !m_uint8_V9) + return m_gridHeight; + + x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); + y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); + + int x_int = (int)x; + int y_int = (int)y; + x -= x_int; + y -= y_int; + x_int&=(MAP_RESOLUTION - 1); + y_int&=(MAP_RESOLUTION - 1); + + int32 a, b, c; + uint8 *V9_h1_ptr = &m_uint8_V9[x_int*128 + x_int + y_int]; + if (x+y < 1) + { + if (x > y) + { + // 1 triangle (h1, h2, h5 points) + int32 h1 = V9_h1_ptr[ 0]; + int32 h2 = V9_h1_ptr[129]; + int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int]; + a = h2-h1; + b = h5-h1-h2; + c = h1; + } + else + { + // 2 triangle (h1, h3, h5 points) + int32 h1 = V9_h1_ptr[0]; + int32 h3 = V9_h1_ptr[1]; + int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int]; + a = h5 - h1 - h3; + b = h3 - h1; + c = h1; + } + } + else + { + if (x > y) + { + // 3 triangle (h2, h4, h5 points) + int32 h2 = V9_h1_ptr[129]; + int32 h4 = V9_h1_ptr[130]; + int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int]; + a = h2 + h4 - h5; + b = h4 - h2; + c = h5 - h4; + } + else + { + // 4 triangle (h3, h4, h5 points) + int32 h3 = V9_h1_ptr[ 1]; + int32 h4 = V9_h1_ptr[130]; + int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int]; + a = h4 - h3; + b = h3 + h4 - h5; + c = h5 - h4; + } + } + // Calculate height + return (float)((a * x) + (b * y) + c)*m_gridIntHeightMultiplier + m_gridHeight; +} + +float GridMap::getHeightFromUint16(float x, float y) const +{ + if (!m_uint16_V8 || !m_uint16_V9) + return m_gridHeight; + + x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); + y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); + + int x_int = (int)x; + int y_int = (int)y; + x -= x_int; + y -= y_int; + x_int&=(MAP_RESOLUTION - 1); + y_int&=(MAP_RESOLUTION - 1); + + int32 a, b, c; + uint16 *V9_h1_ptr = &m_uint16_V9[x_int*128 + x_int + y_int]; + if (x+y < 1) + { + if (x > y) + { + // 1 triangle (h1, h2, h5 points) + int32 h1 = V9_h1_ptr[ 0]; + int32 h2 = V9_h1_ptr[129]; + int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int]; + a = h2-h1; + b = h5-h1-h2; + c = h1; + } + else + { + // 2 triangle (h1, h3, h5 points) + int32 h1 = V9_h1_ptr[0]; + int32 h3 = V9_h1_ptr[1]; + int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int]; + a = h5 - h1 - h3; + b = h3 - h1; + c = h1; + } + } + else + { + if (x > y) + { + // 3 triangle (h2, h4, h5 points) + int32 h2 = V9_h1_ptr[129]; + int32 h4 = V9_h1_ptr[130]; + int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int]; + a = h2 + h4 - h5; + b = h4 - h2; + c = h5 - h4; + } + else + { + // 4 triangle (h3, h4, h5 points) + int32 h3 = V9_h1_ptr[ 1]; + int32 h4 = V9_h1_ptr[130]; + int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int]; + a = h4 - h3; + b = h3 + h4 - h5; + c = h5 - h4; + } + } + // Calculate height + return (float)((a * x) + (b * y) + c)*m_gridIntHeightMultiplier + m_gridHeight; +} + +float GridMap::getLiquidLevel(float x, float y) +{ + if (!m_liquid_map) + return m_liquidLevel; + + x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); + y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); + + int cx_int = ((int)x & (MAP_RESOLUTION-1)) - m_liquid_offY; + int cy_int = ((int)y & (MAP_RESOLUTION-1)) - m_liquid_offX; + + if (cx_int < 0 || cx_int >=m_liquid_height) + return INVALID_HEIGHT; + if (cy_int < 0 || cy_int >=m_liquid_width) + return INVALID_HEIGHT; + + return m_liquid_map[cx_int*m_liquid_width + cy_int]; +} + +uint8 GridMap::getTerrainType(float x, float y) +{ + if (!m_liquid_type) + return m_liquidType; + + x = 16 * (32 - x/SIZE_OF_GRIDS); + y = 16 * (32 - y/SIZE_OF_GRIDS); + int lx = (int)x & 15; + int ly = (int)y & 15; + return m_liquid_type[lx*16 + ly]; +} + +// Get water state on map +inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data) +{ + // Check water type (if no water return) + if (!m_liquid_type && !m_liquidType) + return LIQUID_MAP_NO_WATER; + + // Get cell + float cx = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); + float cy = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); + + int x_int = (int)cx & (MAP_RESOLUTION-1); + int y_int = (int)cy & (MAP_RESOLUTION-1); + + // Check water type in cell + uint8 type = m_liquid_type ? m_liquid_type[(x_int>>3)*16 + (y_int>>3)] : m_liquidType; + if (type == 0) + return LIQUID_MAP_NO_WATER; + + // Check req liquid type mask + if (ReqLiquidType && !(ReqLiquidType&type)) + return LIQUID_MAP_NO_WATER; + + // Check water level: + // Check water height map + int lx_int = x_int - m_liquid_offY; + int ly_int = y_int - m_liquid_offX; + if (lx_int < 0 || lx_int >=m_liquid_height) + return LIQUID_MAP_NO_WATER; + if (ly_int < 0 || ly_int >=m_liquid_width) + return LIQUID_MAP_NO_WATER; + + // Get water level + float liquid_level = m_liquid_map ? m_liquid_map[lx_int*m_liquid_width + ly_int] : m_liquidLevel; + // Get ground level (sub 0.2 for fix some errors) + float ground_level = getHeight(x, y); + + // Check water level and ground level + if (liquid_level < ground_level || z < ground_level - 2) + return LIQUID_MAP_NO_WATER; + + // All ok in water -> store data + if (data) + { + data->type = type; + data->level = liquid_level; + data->depth_level = ground_level; + } + + // For speed check as int values + int delta = int((liquid_level - z) * 10); + + // Get position delta + if (delta > 20) // Under water + return LIQUID_MAP_UNDER_WATER; + if (delta > 0) // In water + return LIQUID_MAP_IN_WATER; + if (delta > -1) // Walk on water + return LIQUID_MAP_WATER_WALK; + // Above water + return LIQUID_MAP_ABOVE_WATER; +} + +inline GridMap *Map::GetGrid(float x, float y) +{ + // half opt method + int gx=(int)(32-x/SIZE_OF_GRIDS); //grid x + int gy=(int)(32-y/SIZE_OF_GRIDS); //grid y + + // ensure GridMap is loaded + EnsureGridCreated(GridPair(63-gx,63-gy)); + + return GridMaps[gx][gy]; +} + +float Map::GetHeight(float x, float y, float z, bool pUseVmaps) const +{ + // find raw .map surface under Z coordinates + float mapHeight; + if (GridMap *gmap = const_cast(this)->GetGrid(x, y)) + { + float _mapheight = gmap->getHeight(x,y); + + // look from a bit higher pos to find the floor, ignore under surface case + if (z + 2.0f > _mapheight) + mapHeight = _mapheight; + else + mapHeight = VMAP_INVALID_HEIGHT_VALUE; + } + else + mapHeight = VMAP_INVALID_HEIGHT_VALUE; + + float vmapHeight; + if (pUseVmaps) + { + VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); + if (vmgr->isHeightCalcEnabled()) + { + // look from a bit higher pos to find the floor + vmapHeight = vmgr->getHeight(GetId(), x, y, z + 2.0f); + } + else + vmapHeight = VMAP_INVALID_HEIGHT_VALUE; + } + else + vmapHeight = VMAP_INVALID_HEIGHT_VALUE; + + // mapHeight set for any above raw ground Z or <= INVALID_HEIGHT + // vmapheight set for any under Z value or <= INVALID_HEIGHT + + if (vmapHeight > INVALID_HEIGHT) + { + if (mapHeight > INVALID_HEIGHT) + { + // we have mapheight and vmapheight and must select more appropriate + + // we are already under the surface or vmap height above map heigt + // or if the distance of the vmap height is less the land height distance + if (z < mapHeight || vmapHeight > mapHeight || fabs(mapHeight-z) > fabs(vmapHeight-z)) + return vmapHeight; + else + return mapHeight; // better use .map surface height + + } + else + return vmapHeight; // we have only vmapHeight (if have) + } + else + { + if (!pUseVmaps) + return mapHeight; // explicitly use map data (if have) + else if (mapHeight > INVALID_HEIGHT && (z < mapHeight + 2 || z == MAX_HEIGHT)) + return mapHeight; // explicitly use map data if original z < mapHeight but map found (z+2 > mapHeight) + else + return VMAP_INVALID_HEIGHT_VALUE; // we not have any height + } +} + +inline bool IsOutdoorWMO(uint32 mogpFlags, int32 adtId, int32 rootId, int32 groupId, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry) +{ + bool outdoor = true; + + if(wmoEntry && atEntry) + { + if(atEntry->flags & AREA_FLAG_OUTSIDE) + return true; + if(atEntry->flags & AREA_FLAG_INSIDE) + return false; + } + + outdoor = mogpFlags&0x8; + + if(wmoEntry) + { + if(wmoEntry->Flags & 4) + return true; + if((wmoEntry->Flags & 2)!=0) + outdoor = false; + } + return outdoor; +} + +bool Map::IsOutdoors(float x, float y, float z) const +{ + uint32 mogpFlags; + int32 adtId, rootId, groupId; + + // no wmo found? -> outside by default + if(!GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId)) + return true; + + AreaTableEntry const* atEntry = 0; + WMOAreaTableEntry const* wmoEntry= GetWMOAreaTableEntryByTripple(rootId, adtId, groupId); + if(wmoEntry) + { + DEBUG_LOG("Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId); + atEntry = GetAreaEntryByAreaID(wmoEntry->areaId); + } + return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry); +} + +bool Map::GetAreaInfo(float x, float y, float z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const +{ + float vmap_z = z; + VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); + if (vmgr->getAreaInfo(GetId(), x, y, vmap_z, flags, adtId, rootId, groupId)) + { + // check if there's terrain between player height and object height + if(GridMap *gmap = const_cast(this)->GetGrid(x, y)) + { + float _mapheight = gmap->getHeight(x,y); + // z + 2.0f condition taken from GetHeight(), not sure if it's such a great choice... + if(z + 2.0f > _mapheight && _mapheight > vmap_z) + return false; + } + return true; + } + return false; +} + +uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const +{ + uint32 mogpFlags; + int32 adtId, rootId, groupId; + WMOAreaTableEntry const* wmoEntry = 0; + AreaTableEntry const* atEntry = 0; + bool haveAreaInfo = false; + + if (GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId)) + { + haveAreaInfo = true; + if (wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId)) + atEntry = GetAreaEntryByAreaID(wmoEntry->areaId); + } + + uint16 areaflag; + + if (atEntry) + areaflag = atEntry->exploreFlag; + else + { + if (GridMap *gmap = const_cast(this)->GetGrid(x, y)) + areaflag = gmap->getArea(x, y); + // this used while not all *.map files generated (instances) + else + areaflag = GetAreaFlagByMapId(i_mapEntry->MapID); + } + + if (isOutdoors) + { + if (haveAreaInfo) + *isOutdoors = IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry); + else + *isOutdoors = true; + } + return areaflag; + } + +uint8 Map::GetTerrainType(float x, float y) const +{ + if (GridMap *gmap = const_cast(this)->GetGrid(x, y)) + return gmap->getTerrainType(x, y); + else + return 0; +} + +ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data) const +{ + ZLiquidStatus result = LIQUID_MAP_NO_WATER; + VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); + float liquid_level, ground_level = INVALID_HEIGHT; + uint32 liquid_type; + if (vmgr->GetLiquidLevel(GetId(), x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type)) + { + sLog.outDebug("getLiquidStatus(): vmap liquid level: %f ground: %f type: %u", liquid_level, ground_level, liquid_type); + // Check water level and ground level + if (liquid_level > ground_level && z > ground_level - 2) + { + // All ok in water -> store data + if (data) + { + data->type = liquid_type; + data->level = liquid_level; + data->depth_level = ground_level; + } + + // For speed check as int values + int delta = int((liquid_level - z) * 10); + + // Get position delta + if (delta > 20) // Under water + return LIQUID_MAP_UNDER_WATER; + if (delta > 0 ) // In water + return LIQUID_MAP_IN_WATER; + if (delta > -1) // Walk on water + return LIQUID_MAP_WATER_WALK; + result = LIQUID_MAP_ABOVE_WATER; + } + } + + if(GridMap* gmap = const_cast(this)->GetGrid(x, y)) + { + LiquidData map_data; + ZLiquidStatus map_result = gmap->getLiquidStatus(x, y, z, ReqLiquidType, &map_data); + // Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER: + if (map_result != LIQUID_MAP_NO_WATER && (map_data.level > ground_level)) + { + if (data) + *data = map_data; + return map_result; + } + } + return result; +} + +float Map::GetWaterLevel(float x, float y) const +{ + if (GridMap* gmap = const_cast(this)->GetGrid(x, y)) + return gmap->getLiquidLevel(x, y); + else + return 0; +} + +uint32 Map::GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id) +{ + AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); + + if (entry) + return entry->ID; + else + return 0; +} + +uint32 Map::GetZoneIdByAreaFlag(uint16 areaflag,uint32 map_id) +{ + AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); + + if (entry) + return (entry->zone != 0) ? entry->zone : entry->ID; + else + return 0; +} + +void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag,uint32 map_id) +{ + AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); + + areaid = entry ? entry->ID : 0; + zoneid = entry ? ((entry->zone != 0) ? entry->zone : entry->ID) : 0; +} + +bool Map::IsInWater(float x, float y, float pZ, LiquidData *data) const +{ + // Check surface in x, y point for liquid + if (const_cast(this)->GetGrid(x, y)) + { + LiquidData liquid_status; + LiquidData *liquid_ptr = data ? data : &liquid_status; + if (getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, liquid_ptr)) + return true; + } + return false; +} + +bool Map::IsUnderWater(float x, float y, float z) const +{ + if (const_cast(this)->GetGrid(x, y)) + { + if (getLiquidStatus(x, y, z, MAP_LIQUID_TYPE_WATER|MAP_LIQUID_TYPE_OCEAN)&LIQUID_MAP_UNDER_WATER) + return true; + } + return false; +} + +bool Map::CheckGridIntegrity(Creature* c, bool moved) const +{ + Cell const& cur_cell = c->GetCurrentCell(); + + CellPair xy_val = Trinity::ComputeCellPair(c->GetPositionX(), c->GetPositionY()); + Cell xy_cell(xy_val); + if (xy_cell != cur_cell) + { + sLog.outDebug("Creature (GUID: %u) X: %f Y: %f (%s) is in grid[%u,%u]cell[%u,%u] instead of grid[%u,%u]cell[%u,%u]", + c->GetGUIDLow(), + c->GetPositionX(),c->GetPositionY(),(moved ? "final" : "original"), + cur_cell.GridX(), cur_cell.GridY(), cur_cell.CellX(), cur_cell.CellY(), + xy_cell.GridX(), xy_cell.GridY(), xy_cell.CellX(), xy_cell.CellY()); + return true; // not crash at error, just output error in debug mode + } + + return true; +} + +const char* Map::GetMapName() const +{ + return i_mapEntry ? i_mapEntry->name[sWorld.GetDefaultDbcLocale()] : "UNNAMEDMAP\x0"; +} + +void Map::UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair) +{ + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + Trinity::VisibleChangesNotifier notifier(*obj); + TypeContainerVisitor player_notifier(notifier); + cell.Visit(cellpair, player_notifier, *this, *obj, GetVisibilityDistance()); +} + +void Map::UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpair) +{ + Trinity::VisibleNotifier notifier(*player); + + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + TypeContainerVisitor world_notifier(notifier); + TypeContainerVisitor grid_notifier(notifier); + cell.Visit(cellpair, world_notifier, *this, *player, GetVisibilityDistance()); + cell.Visit(cellpair, grid_notifier, *this, *player, GetVisibilityDistance()); + + // send data + notifier.SendToSelf(); +} +/* +void Map::PlayerRelocationNotify(Player* player, Cell cell, CellPair cellpair) +{ + Trinity::PlayerRelocationNotifier relocationNotifier(*player); + cell.data.Part.reserved = ALL_DISTRICT; + + TypeContainerVisitor p2grid_relocation(relocationNotifier); + TypeContainerVisitor p2world_relocation(relocationNotifier); + + cell.Visit(cellpair, p2grid_relocation, *this, *player, MAX_CREATURE_ATTACK_RADIUS); + cell.Visit(cellpair, p2world_relocation, *this, *player, MAX_CREATURE_ATTACK_RADIUS); +} + +void Map::CreatureRelocationNotify(Creature *creature, Cell cell, CellPair cellpair) +{ + Trinity::CreatureRelocationNotifier relocationNotifier(*creature); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); // not trigger load unloaded grids at notifier call + + TypeContainerVisitor c2world_relocation(relocationNotifier); + TypeContainerVisitor c2grid_relocation(relocationNotifier); + + cell.Visit(cellpair, c2world_relocation, *this, *creature, MAX_CREATURE_ATTACK_RADIUS); + cell.Visit(cellpair, c2grid_relocation, *this, *creature, MAX_CREATURE_ATTACK_RADIUS); +} +*/ + +void Map::SendInitSelf(Player * player) +{ + sLog.outDetail("Creating player data for himself %u", player->GetGUIDLow()); + + UpdateData data; + + // attach to player data current transport data + if (Transport* transport = player->GetTransport()) + { + transport->BuildCreateUpdateBlockForPlayer(&data, player); + } + + // build data for self presence in world at own client (one time for map) + player->BuildCreateUpdateBlockForPlayer(&data, player); + + // build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map + if (Transport* transport = player->GetTransport()) + { + for (Transport::PlayerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr) + { + if (player != (*itr) && player->HaveAtClient(*itr)) + { + (*itr)->BuildCreateUpdateBlockForPlayer(&data, player); + } + } + } + + WorldPacket packet; + data.BuildPacket(&packet); + player->GetSession()->SendPacket(&packet); +} + +void Map::SendInitTransports(Player * player) +{ + // Hack to send out transports + MapManager::TransportMap& tmap = MapManager::Instance().m_TransportsByMap; + + // no transports at map + if (tmap.find(player->GetMapId()) == tmap.end()) + return; + + UpdateData transData; + + MapManager::TransportSet& tset = tmap[player->GetMapId()]; + + for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i) + { + // send data for current transport in other place + if ((*i) != player->GetTransport() && (*i)->GetMapId() == GetId()) + { + (*i)->BuildCreateUpdateBlockForPlayer(&transData, player); + } + } + + WorldPacket packet; + transData.BuildPacket(&packet); + player->GetSession()->SendPacket(&packet); +} + +void Map::SendRemoveTransports(Player * player) +{ + // Hack to send out transports + MapManager::TransportMap& tmap = MapManager::Instance().m_TransportsByMap; + + // no transports at map + if (tmap.find(player->GetMapId()) == tmap.end()) + return; + + UpdateData transData; + + MapManager::TransportSet& tset = tmap[player->GetMapId()]; + + // except used transport + for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i) + if ((*i) != player->GetTransport() && (*i)->GetMapId() != GetId()) + (*i)->BuildOutOfRangeUpdateBlock(&transData); + + WorldPacket packet; + transData.BuildPacket(&packet); + player->GetSession()->SendPacket(&packet); +} + +inline void Map::setNGrid(NGridType *grid, uint32 x, uint32 y) +{ + if (x >= MAX_NUMBER_OF_GRIDS || y >= MAX_NUMBER_OF_GRIDS) + { + sLog.outError("map::setNGrid() Invalid grid coordinates found: %d, %d!",x,y); + assert(false); + } + i_grids[x][y] = grid; +} + +void Map::DelayedUpdate(const uint32 t_diff) +{ + RemoveAllObjectsInRemoveList(); + + // Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load ! + // This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended + if (!IsBattleGroundOrArena()) + { + for (GridRefManager::iterator i = GridRefManager::begin(); i != GridRefManager::end();) + { + NGridType *grid = i->getSource(); + GridInfo *info = i->getSource()->getGridInfoRef(); + ++i; // The update might delete the map and we need the next map before the iterator gets invalid + assert(grid->GetGridState() >= 0 && grid->GetGridState() < MAX_GRID_STATE); + si_GridStates[grid->GetGridState()]->Update(*this, *grid, *info, grid->getX(), grid->getY(), t_diff); + } + } +} + +void Map::AddObjectToRemoveList(WorldObject *obj) +{ + assert(obj->GetMapId() == GetId() && obj->GetInstanceId() == GetInstanceId()); + + obj->CleanupsBeforeDelete(false); // remove or simplify at least cross referenced links + + i_objectsToRemove.insert(obj); + //sLog.outDebug("Object (GUID: %u TypeId: %u) added to removing list.",obj->GetGUIDLow(),obj->GetTypeId()); +} + +void Map::AddObjectToSwitchList(WorldObject *obj, bool on) +{ + assert(obj->GetMapId() == GetId() && obj->GetInstanceId() == GetInstanceId()); + + std::map::iterator itr = i_objectsToSwitch.find(obj); + if (itr == i_objectsToSwitch.end()) + i_objectsToSwitch.insert(itr, std::make_pair(obj, on)); + else if (itr->second != on) + i_objectsToSwitch.erase(itr); + else + assert(false); +} + +void Map::RemoveAllObjectsInRemoveList() +{ + while (!i_objectsToSwitch.empty()) + { + std::map::iterator itr = i_objectsToSwitch.begin(); + WorldObject *obj = itr->first; + bool on = itr->second; + i_objectsToSwitch.erase(itr); + + switch(obj->GetTypeId()) + { + case TYPEID_UNIT: + if (!obj->ToCreature()->isPet()) + SwitchGridContainers(obj->ToCreature(), on); + break; + } + } + + //sLog.outDebug("Object remover 1 check."); + while (!i_objectsToRemove.empty()) + { + std::set::iterator itr = i_objectsToRemove.begin(); + WorldObject* obj = *itr; + + switch(obj->GetTypeId()) + { + case TYPEID_CORPSE: + { + Corpse* corpse = ObjectAccessor::Instance().GetCorpse(*obj, obj->GetGUID()); + if (!corpse) + sLog.outError("Tried to delete corpse/bones %u that is not in map.", obj->GetGUIDLow()); + else + Remove(corpse,true); + break; + } + case TYPEID_DYNAMICOBJECT: + Remove((DynamicObject*)obj,true); + break; + case TYPEID_GAMEOBJECT: + Remove((GameObject*)obj,true); + break; + case TYPEID_UNIT: + // in case triggered sequence some spell can continue casting after prev CleanupsBeforeDelete call + // make sure that like sources auras/etc removed before destructor start + obj->ToCreature()->CleanupsBeforeDelete(); + Remove(obj->ToCreature(),true); + break; + default: + sLog.outError("Non-grid object (TypeId: %u) is in grid object remove list, ignored.",obj->GetTypeId()); + break; + } + + i_objectsToRemove.erase(itr); + } + + //sLog.outDebug("Object remover 2 check."); +} + +uint32 Map::GetPlayersCountExceptGMs() const +{ + uint32 count = 0; + for (MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + if (!itr->getSource()->isGameMaster()) + ++count; + return count; +} + +void Map::SendToPlayers(WorldPacket const* data) const +{ + for (MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + itr->getSource()->GetSession()->SendPacket(data); +} + +bool Map::ActiveObjectsNearGrid(uint32 x, uint32 y) const +{ + ASSERT(x < MAX_NUMBER_OF_GRIDS); + ASSERT(y < MAX_NUMBER_OF_GRIDS); + + CellPair cell_min(x*MAX_NUMBER_OF_CELLS, y*MAX_NUMBER_OF_CELLS); + CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS); + + //we must find visible range in cells so we unload only non-visible cells... + float viewDist = GetVisibilityDistance(); + int cell_range = (int)ceilf(viewDist / SIZE_OF_GRID_CELL) + 1; + + cell_min << cell_range; + cell_min -= cell_range; + cell_max >> cell_range; + cell_max += cell_range; + + for (MapRefManager::const_iterator iter = m_mapRefManager.begin(); iter != m_mapRefManager.end(); ++iter) + { + Player* plr = iter->getSource(); + + CellPair p = Trinity::ComputeCellPair(plr->GetPositionX(), plr->GetPositionY()); + if ((cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) && + (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord)) + return true; + } + + for (ActiveNonPlayers::const_iterator iter = m_activeNonPlayers.begin(); iter != m_activeNonPlayers.end(); ++iter) + { + WorldObject* obj = *iter; + + CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); + if ((cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) && + (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord)) + return true; + } + + return false; +} + +void Map::AddToActive(Creature* c) +{ + AddToActiveHelper(c); + + // also not allow unloading spawn grid to prevent creating creature clone at load + if (!c->isPet() && c->GetDBTableGUIDLow()) + { + float x,y,z; + c->GetRespawnCoord(x,y,z); + GridPair p = Trinity::ComputeGridPair(x, y); + if (getNGrid(p.x_coord, p.y_coord)) + getNGrid(p.x_coord, p.y_coord)->incUnloadActiveLock(); + else + { + GridPair p2 = Trinity::ComputeGridPair(c->GetPositionX(), c->GetPositionY()); + sLog.outError("Active creature (GUID: %u Entry: %u) added to grid[%u,%u] but spawn grid[%u,%u] was not loaded.", + c->GetGUIDLow(), c->GetEntry(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord); + } + } +} + +void Map::RemoveFromActive(Creature* c) +{ + RemoveFromActiveHelper(c); + + // also allow unloading spawn grid + if (!c->isPet() && c->GetDBTableGUIDLow()) + { + float x,y,z; + c->GetRespawnCoord(x,y,z); + GridPair p = Trinity::ComputeGridPair(x, y); + if (getNGrid(p.x_coord, p.y_coord)) + getNGrid(p.x_coord, p.y_coord)->decUnloadActiveLock(); + else + { + GridPair p2 = Trinity::ComputeGridPair(c->GetPositionX(), c->GetPositionY()); + sLog.outError("Active creature (GUID: %u Entry: %u) removed from grid[%u,%u] but spawn grid[%u,%u] was not loaded.", + c->GetGUIDLow(), c->GetEntry(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord); + } + } +} + +template void Map::Add(Corpse *); +template void Map::Add(Creature *); +template void Map::Add(GameObject *); +template void Map::Add(DynamicObject *); + +template void Map::Remove(Corpse *,bool); +template void Map::Remove(Creature *,bool); +template void Map::Remove(GameObject *, bool); +template void Map::Remove(DynamicObject *, bool); + +/* ******* Dungeon Instance Maps ******* */ + +InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) + : Map(id, expiry, InstanceId, SpawnMode, _parent), + m_resetAfterUnload(false), m_unloadWhenEmpty(false), + i_data(NULL), i_script_id(0) +{ + //lets initialize visibility distance for dungeons + InstanceMap::InitVisibilityDistance(); + + // the timer is started by default, and stopped when the first player joins + // this make sure it gets unloaded if for some reason no player joins + m_unloadTimer = std::max(sWorld.getConfig(CONFIG_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY); +} + +InstanceMap::~InstanceMap() +{ + if (i_data) + { + delete i_data; + i_data = NULL; + } +} + +void InstanceMap::InitVisibilityDistance() +{ + //init visibility distance for instances + m_VisibleDistance = World::GetMaxVisibleDistanceInInstances(); + m_VisibilityNotifyPeriod = World::GetVisibilityNotifyPeriodInInstances(); +} + +/* + Do map specific checks to see if the player can enter +*/ +bool InstanceMap::CanEnter(Player *player) +{ + if (player->GetMapRef().getTarget() == this) + { + sLog.outError("InstanceMap::CanEnter - player %s(%u) already in map %d,%d,%d!", player->GetName(), player->GetGUIDLow(), GetId(), GetInstanceId(), GetSpawnMode()); + assert(false); + return false; + } + + // allow GM's to enter + if (player->isGameMaster()) + return Map::CanEnter(player); + + // cannot enter if the instance is full (player cap), GMs don't count + uint32 maxPlayers = GetMaxPlayers(); + if (GetPlayersCountExceptGMs() >= maxPlayers) + { + sLog.outDetail("MAP: Instance '%u' of map '%s' cannot have more than '%u' players. Player '%s' rejected", GetInstanceId(), GetMapName(), maxPlayers, player->GetName()); + player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAX_PLAYERS); + return false; + } + + // cannot enter while an encounter is in progress on raids + /*Group *pGroup = player->GetGroup(); + if (!player->isGameMaster() && pGroup && pGroup->InCombatToInstance(GetInstanceId()) && player->GetMapId() != GetId())*/ + if (IsRaid() && GetInstanceData() && GetInstanceData()->IsEncounterInProgress()) + { + player->SendTransferAborted(GetId(), TRANSFER_ABORT_ZONE_IN_COMBAT); + return false; + } + + return Map::CanEnter(player); +} + +/* + Do map specific checks and add the player to the map if successful. +*/ +bool InstanceMap::Add(Player *player) +{ + // TODO: Not sure about checking player level: already done in HandleAreaTriggerOpcode + // GMs still can teleport player in instance. + // Is it needed? + + { + Guard guard(*this); + // Check moved to void WorldSession::HandleMoveWorldportAckOpcode() + //if (!CanEnter(player)) + //return false; + + // Dungeon only code + if (IsDungeon()) + { + // get or create an instance save for the map + InstanceSave *mapSave = sInstanceSaveManager.GetInstanceSave(GetInstanceId()); + if (!mapSave) + { + sLog.outDetail("InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId()); + mapSave = sInstanceSaveManager.AddInstanceSave(GetId(), GetInstanceId(), Difficulty(GetSpawnMode()), 0, true); + } + + // check for existing instance binds + InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), Difficulty(GetSpawnMode())); + if (playerBind && playerBind->perm) + { + // cannot enter other instances if bound permanently + if (playerBind->save != mapSave) + { + sLog.outError("InstanceMap::Add: player %s(%d) is permanently bound to instance %d,%d,%d,%d,%d,%d but he is being put into instance %d,%d,%d,%d,%d,%d", player->GetName(), player->GetGUIDLow(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset()); + return false; + } + } + else + { + Group *pGroup = player->GetGroup(); + if (pGroup) + { + // solo saves should be reset when entering a group + InstanceGroupBind *groupBind = pGroup->GetBoundInstance(this); + if (playerBind) + { + sLog.outError("InstanceMap::Add: player %s(%d) is being put into instance %d,%d,%d,%d,%d,%d but he is in group %d and is bound to instance %d,%d,%d,%d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), GUID_LOPART(pGroup->GetLeaderGUID()), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset()); + if (groupBind) sLog.outError("InstanceMap::Add: the group is bound to the instance %d,%d,%d,%d,%d,%d", groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty(), groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset()); + //assert(false); + return false; + } + // bind to the group or keep using the group save + if (!groupBind) + pGroup->BindToInstance(mapSave, false); + else + { + // cannot jump to a different instance without resetting it + if (groupBind->save != mapSave) + { + sLog.outError("InstanceMap::Add: player %s(%d) is being put into instance %d,%d,%d but he is in group %d which is bound to instance %d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), GUID_LOPART(pGroup->GetLeaderGUID()), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), groupBind->save->GetDifficulty()); + if (mapSave) + sLog.outError("MapSave players: %d, group count: %d", mapSave->GetPlayerCount(), mapSave->GetGroupCount()); + else + sLog.outError("MapSave NULL"); + if (groupBind->save) + sLog.outError("GroupBind save players: %d, group count: %d", groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount()); + else + sLog.outError("GroupBind save NULL"); + return false; + } + // if the group/leader is permanently bound to the instance + // players also become permanently bound when they enter + if (groupBind->perm) + { + WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4); + data << uint32(0); + player->GetSession()->SendPacket(&data); + player->BindToInstance(mapSave, true); + } + } + } + else + { + // set up a solo bind or continue using it + if (!playerBind) + player->BindToInstance(mapSave, false); + else + // cannot jump to a different instance without resetting it + assert(playerBind->save == mapSave); + } + } + } + + // for normal instances cancel the reset schedule when the + // first player enters (no players yet) + SetResetSchedule(false); + + sLog.outDetail("MAP: Player '%s' entered instance '%u' of map '%s'", player->GetName(), GetInstanceId(), GetMapName()); + // initialize unload state + m_unloadTimer = 0; + m_resetAfterUnload = false; + m_unloadWhenEmpty = false; + } + + // this will acquire the same mutex so it cannot be in the previous block + Map::Add(player); + + if (i_data) + i_data->OnPlayerEnter(player); + + return true; +} + +void InstanceMap::Update(const uint32& t_diff) +{ + Map::Update(t_diff); + + if (i_data) + i_data->Update(t_diff); +} + +void InstanceMap::Remove(Player *player, bool remove) +{ + sLog.outDetail("MAP: Removing player '%s' from instance '%u' of map '%s' before relocating to another map", player->GetName(), 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.getConfig(CONFIG_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY); + Map::Remove(player, remove); + // for normal instances schedule the reset after all players have left + SetResetSchedule(true); +} + +void InstanceMap::CreateInstanceData(bool load) +{ + if (i_data != NULL) + return; + + InstanceTemplate const* mInstance = objmgr.GetInstanceTemplate(GetId()); + if (mInstance) + { + i_script_id = mInstance->script_id; + i_data = sScriptMgr.CreateInstanceData(this); + } + + if (!i_data) + return; + + i_data->Initialize(); + + if (load) + { + // TODO: make a global storage for this + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT data FROM instance WHERE map = '%u' AND id = '%u'", GetId(), i_InstanceId); + if (result) + { + Field* fields = result->Fetch(); + std::string data = fields[0].GetString(); + if (data != "") + { + sLog.outDebug("Loading instance data for `%s` with id %u", objmgr.GetScriptName(i_script_id), i_InstanceId); + i_data->Load(data.c_str()); + } + } + } +} + +/* + Returns true if there are no players in the instance +*/ +bool InstanceMap::Reset(uint8 method) +{ + // note: since the map may not be loaded when the instance needs to be reset + // the instance must be deleted from the DB by InstanceSaveManager + + if (HavePlayers()) + { + if (method == INSTANCE_RESET_ALL) + { + // notify the players to leave the instance so it can be reset + for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + itr->getSource()->SendResetFailedNotify(GetId()); + } + else + { + if (method == INSTANCE_RESET_GLOBAL) + // set the homebind timer for players inside (1 minute) + for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + itr->getSource()->m_InstanceValid = false; + + // the unload timer is not started + // instead the map will unload immediately after the players have left + m_unloadWhenEmpty = true; + m_resetAfterUnload = true; + } + } + else + { + // unloaded at next update + m_unloadTimer = MIN_UNLOAD_DELAY; + m_resetAfterUnload = true; + } + + return m_mapRefManager.isEmpty(); +} + +void InstanceMap::PermBindAllPlayers(Player *player) +{ + if (!IsDungeon()) + return; + + InstanceSave *save = sInstanceSaveManager.GetInstanceSave(GetInstanceId()); + if (!save) + { + sLog.outError("Cannot bind players, no instance save available for map!"); + return; + } + + Group *group = player->GetGroup(); + // group members outside the instance group don't get bound + for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + { + Player* plr = itr->getSource(); + // players inside an instance cannot be bound to other instances + // some players may already be permanently bound, in this case nothing happens + InstancePlayerBind *bind = plr->GetBoundInstance(save->GetMapId(), save->GetDifficulty()); + if (!bind || !bind->perm) + { + plr->BindToInstance(save, true); + WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4); + data << uint32(0); + plr->GetSession()->SendPacket(&data); + } + + // if the leader is not in the instance the group will not get a perm bind + if (group && group->GetLeaderGUID() == plr->GetGUID()) + group->BindToInstance(save, true); + } +} + +void InstanceMap::UnloadAll() +{ + assert(!HavePlayers()); + + if (m_resetAfterUnload == true) + objmgr.DeleteRespawnTimeForInstance(GetInstanceId()); + + Map::UnloadAll(); +} + +void InstanceMap::SendResetWarnings(uint32 timeLeft) const +{ + for (MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + itr->getSource()->SendInstanceResetWarning(GetId(), itr->getSource()->GetDifficulty(IsRaid()), timeLeft); +} + +void InstanceMap::SetResetSchedule(bool on) +{ + // only for normal instances + // the reset time is only scheduled when there are no payers inside + // it is assumed that the reset time will rarely (if ever) change while the reset is scheduled + if (IsDungeon() && !HavePlayers() && !IsRaidOrHeroicDungeon()) + { + InstanceSave *save = sInstanceSaveManager.GetInstanceSave(GetInstanceId()); + if (!save) sLog.outError("InstanceMap::SetResetSchedule: cannot turn schedule %s, no save available for instance %d of %d", on ? "on" : "off", GetInstanceId(), GetId()); + else sInstanceSaveManager.ScheduleReset(on, save->GetResetTime(), InstanceSaveManager::InstResetEvent(0, GetId(), Difficulty(GetSpawnMode()), GetInstanceId())); + } +} + +MapDifficulty const* Map::GetMapDifficulty() const +{ + return GetMapDifficultyData(GetId(),GetDifficulty()); +} + +uint32 InstanceMap::GetMaxPlayers() const +{ + if (MapDifficulty const* mapDiff = GetMapDifficulty()) + { + if (mapDiff->maxPlayers || IsRegularDifficulty()) // Normal case (expect that regular difficulty always have correct maxplayers) + return mapDiff->maxPlayers; + else // DBC have 0 maxplayers for heroic instances with expansion < 2 + { // The heroic entry exists, so we don't have to check anything, simply return normal max players + MapDifficulty const* normalDiff = GetMapDifficultyData(GetId(), REGULAR_DIFFICULTY); + return normalDiff ? normalDiff->maxPlayers : 0; + } + } + else // I'd rather assert(false); + return 0; +} + +uint32 InstanceMap::GetMaxResetDelay() const +{ + MapDifficulty const* mapDiff = GetMapDifficulty(); + return mapDiff ? mapDiff->resetTime : 0; +} + +/* ******* Battleground Instance Maps ******* */ + +BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent, uint8 spawnMode) + : Map(id, expiry, InstanceId, spawnMode, _parent) +{ + //lets initialize visibility distance for BG/Arenas + BattleGroundMap::InitVisibilityDistance(); +} + +BattleGroundMap::~BattleGroundMap() +{ +} + +void BattleGroundMap::InitVisibilityDistance() +{ + //init visibility distance for BG/Arenas + m_VisibleDistance = World::GetMaxVisibleDistanceInBGArenas(); + m_VisibilityNotifyPeriod = World::GetVisibilityNotifyPeriodInBGArenas(); +} + +bool BattleGroundMap::CanEnter(Player * player) +{ + if (player->GetMapRef().getTarget() == this) + { + sLog.outError("BGMap::CanEnter - player %u is already in map!", player->GetGUIDLow()); + assert(false); + return false; + } + + if (player->GetBattleGroundId() != GetInstanceId()) + return false; + + // player number limit is checked in bgmgr, no need to do it here + + return Map::CanEnter(player); +} + +bool BattleGroundMap::Add(Player * player) +{ + { + Guard guard(*this); + //Check moved to void WorldSession::HandleMoveWorldportAckOpcode() + //if (!CanEnter(player)) + //return false; + // reset instance validity, battleground maps do not homebind + player->m_InstanceValid = true; + } + return Map::Add(player); +} + +void BattleGroundMap::Remove(Player *player, bool remove) +{ + sLog.outDetail("MAP: Removing player '%s' from bg '%u' of map '%s' before relocating to another map", player->GetName(), GetInstanceId(), GetMapName()); + Map::Remove(player, remove); +} + +void BattleGroundMap::SetUnload() +{ + m_unloadTimer = MIN_UNLOAD_DELAY; +} + +void BattleGroundMap::RemoveAllPlayers() +{ + if (HavePlayers()) + for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + if (Player* plr = itr->getSource()) + if (!plr->IsBeingTeleportedFar()) + plr->TeleportTo(plr->GetBattleGroundEntryPoint()); + +} + +/// Put scripts in the execution queue +void Map::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, Object* target) +{ + ///- Find the script map + ScriptMapMap::const_iterator s = scripts.find(id); + if (s == scripts.end()) + return; + + // prepare static data + uint64 sourceGUID = source ? source->GetGUID() : (uint64)0; //some script commands doesn't have source + uint64 targetGUID = target ? target->GetGUID() : (uint64)0; + uint64 ownerGUID = (source->GetTypeId() == TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0; + + ///- Schedule script execution for all scripts in the script map + ScriptMap const *s2 = &(s->second); + bool immedScript = false; + for (ScriptMap::const_iterator iter = s2->begin(); iter != s2->end(); ++iter) + { + ScriptAction sa; + sa.sourceGUID = sourceGUID; + sa.targetGUID = targetGUID; + sa.ownerGUID = ownerGUID; + + sa.script = &iter->second; + m_scriptSchedule.insert(std::pair(time_t(sWorld.GetGameTime() + iter->first), sa)); + if (iter->first == 0) + immedScript = true; + + sWorld.IncreaseScheduledScriptsCount(); + } + ///- If one of the effects should be immediate, launch the script execution + if (/*start &&*/ immedScript && !i_scriptLock) + { + i_scriptLock = true; + ScriptsProcess(); + i_scriptLock = false; + } +} + +void Map::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target) +{ + // NOTE: script record _must_ exist until command executed + + // prepare static data + uint64 sourceGUID = source ? source->GetGUID() : (uint64)0; + uint64 targetGUID = target ? target->GetGUID() : (uint64)0; + uint64 ownerGUID = (source->GetTypeId() == TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0; + + ScriptAction sa; + sa.sourceGUID = sourceGUID; + sa.targetGUID = targetGUID; + sa.ownerGUID = ownerGUID; + + sa.script = &script; + m_scriptSchedule.insert(std::pair(time_t(sWorld.GetGameTime() + delay), sa)); + + sWorld.IncreaseScheduledScriptsCount(); + + ///- If effects should be immediate, launch the script execution + if (delay == 0 && !i_scriptLock) + { + i_scriptLock = true; + ScriptsProcess(); + i_scriptLock = false; + } +} + +/// Process queued scripts +void Map::ScriptsProcess() +{ + if (m_scriptSchedule.empty()) + return; + + ///- Process overdue queued scripts + std::multimap::iterator iter = m_scriptSchedule.begin(); + // ok as multimap is a *sorted* associative container + while (!m_scriptSchedule.empty() && (iter->first <= sWorld.GetGameTime())) + { + ScriptAction const& step = iter->second; + + Object* source = NULL; + + if (step.sourceGUID) + { + switch (GUID_HIPART(step.sourceGUID)) + { + case HIGHGUID_ITEM: + // case HIGHGUID_CONTAINER: == HIGHGUID_ITEM + { + Player* player = HashMapHolder::Find(step.ownerGUID); + if (player) + source = player->GetItemByGuid(step.sourceGUID); + break; + } + case HIGHGUID_UNIT: + source = HashMapHolder::Find(step.sourceGUID); + break; + case HIGHGUID_PET: + source = HashMapHolder::Find(step.sourceGUID); + break; + //case HIGHGUID_VEHICLE: + // source = HashMapHolder::Find(step.sourceGUID); + // break; + case HIGHGUID_PLAYER: + source = HashMapHolder::Find(step.sourceGUID); + break; + case HIGHGUID_GAMEOBJECT: + source = HashMapHolder::Find(step.sourceGUID); + break; + case HIGHGUID_CORPSE: + source = HashMapHolder::Find(step.sourceGUID); + break; + case HIGHGUID_MO_TRANSPORT: + for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter) + { + if ((*iter)->GetGUID() == step.sourceGUID) + { + source = reinterpret_cast(*iter); + break; + } + } + break; + default: + sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.sourceGUID)); + break; + } + } + + //if (source && !source->IsInWorld()) source = NULL; + + Object* target = NULL; + + if (step.targetGUID) + { + switch (GUID_HIPART(step.targetGUID)) + { + case HIGHGUID_UNIT: + target = HashMapHolder::Find(step.targetGUID); + break; + case HIGHGUID_PET: + target = HashMapHolder::Find(step.targetGUID); + break; + //case HIGHGUID_VEHICLE: + // target = HashMapHolder::Find(step.targetGUID); + // break; + case HIGHGUID_PLAYER: // empty GUID case also + target = HashMapHolder::Find(step.targetGUID); + break; + case HIGHGUID_GAMEOBJECT: + target = HashMapHolder::Find(step.targetGUID); + break; + case HIGHGUID_CORPSE: + target = HashMapHolder::Find(step.targetGUID); + break; + default: + sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.targetGUID)); + break; + } + } + + //if (target && !target->IsInWorld()) target = NULL; + + switch (step.script->command) + { + case SCRIPT_COMMAND_TALK: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_TALK (script id: %u) call for NULL source.", step.script->id); + break; + } + + Creature* cSource = NULL; + cSource = source->ToCreature() != NULL ? source->ToCreature() : target->ToCreature(); + + if (!cSource) + { + sLog.outError("SCRIPT_COMMAND_TALK (script id: %u) call for non supported source (TypeId: %u, Entry: %u, GUID: %u), skipping.", + step.script->id, source->GetTypeId(), source->GetEntry(), source->GetGUIDLow()); + break; + } + + if (step.script->datalong > CHAT_TYPE_WHISPER) + { + sLog.outError("SCRIPT_COMMAND_TALK (script id: %u) invalid chat type (%u), skipping.", step.script->id, step.script->datalong); + break; + } + + uint64 unit_target = target ? target->GetGUID() : 0; + + //datalong 0=normal say, 1=whisper, 2=yell, 3=emote text, 4=boss emote text + //TODO: Update for more chat types + switch (step.script->datalong) + { + case CHAT_TYPE_SAY: // Say + cSource->Say(step.script->dataint, LANG_UNIVERSAL, unit_target); + break; + case CHAT_TYPE_YELL: // Yell + cSource->Yell(step.script->dataint, LANG_UNIVERSAL, unit_target); + break; + case CHAT_TYPE_TEXT_EMOTE: // Emote text + cSource->TextEmote(step.script->dataint, unit_target); + break; + case CHAT_TYPE_BOSS_EMOTE: // Boss Emote text + cSource->MonsterTextEmote(step.script->dataint, unit_target, true); + break; + case CHAT_TYPE_WHISPER: // Whisper + if (!unit_target || !IS_PLAYER_GUID(unit_target)) + { + sLog.outError("SCRIPT_COMMAND_TALK (script id: %u) attempt to whisper (%u) NULL, skipping.", step.script->id, + step.script->datalong); + break; + } + cSource->Whisper(step.script->dataint,unit_target); + break; + default: + break; // must be already checked at load + } + break; + } + + case SCRIPT_COMMAND_EMOTE: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_EMOTE (script id: %u) call for NULL source.", step.script->id); + break; + } + + Creature* cSource = NULL; + cSource = source->ToCreature() != NULL ? source->ToCreature() : target->ToCreature(); + + if (!cSource) + { + sLog.outError("SCRIPT_COMMAND_TALK (script id: %u) call for non supported source (TypeId: %u, Entry: %u, GUID: %u), skipping.", + step.script->id, source->GetTypeId(), source->GetEntry(), source->GetGUIDLow()); + break; + } + + if (step.script->datalong2) + cSource->SetUInt32Value(UNIT_NPC_EMOTESTATE, step.script->datalong); + else + cSource->HandleEmoteCommand(step.script->datalong); + break; + } + + case SCRIPT_COMMAND_FIELD_SET: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_FIELD_SET (script id: %u) call for NULL source.", step.script->id); + break; + } + + Creature* cSource = source->ToCreature() != NULL ? source->ToCreature() : target->ToCreature(); + if (!cSource) + { + sLog.outError("SCRIPT_COMMAND_FIELD_SET (script id: %u) call for non-creature source.", step.script->id); + break; + } + + if (step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= cSource->GetValuesCount()) + { + sLog.outError("SCRIPT_COMMAND_FIELD_SET (script id: %u) call for wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u).", + step.script->id, step.script->datalong,source->GetValuesCount(),source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); + break; + } + + cSource->SetUInt32Value(step.script->datalong, step.script->datalong2); + break; + } + + case SCRIPT_COMMAND_MOVE_TO: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_MOVE_TO (script id: %u) call for NULL creature.", step.script->id); + break; + } + + Creature* cSource = source->ToCreature() != NULL ? source->ToCreature() : target->ToCreature(); + if (!cSource) + { + sLog.outError("SCRIPT_COMMAND_MOVE_TO (script id: %u) call for non-creature (TypeId: %u, Entry: %u, GUID: %u), skipping.", + step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); + break; + } + + cSource->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, step.script->datalong2); + cSource->GetMap()->CreatureRelocation(cSource, step.script->x, step.script->y, step.script->z, 0); + break; + } + + case SCRIPT_COMMAND_FLAG_SET: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_FLAG_SET (script id: %u) call for NULL object.", step.script->id); + break; + } + + Creature* cSource = source->ToCreature() != NULL ? source->ToCreature() : target->ToCreature(); + if (!cSource) + { + sLog.outError("SCRIPT_COMMAND_FLAG_SET (script id: %u) call for non-creature source.", step.script->id); + break; + } + + if (step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= cSource->GetValuesCount()) + { + sLog.outError("SCRIPT_COMMAND_FLAG_SET (script id: %u) call for wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u).", + step.script->id, step.script->datalong,source->GetValuesCount(),source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); + break; + } + + cSource->SetFlag(step.script->datalong, step.script->datalong2); + break; + } + + case SCRIPT_COMMAND_FLAG_REMOVE: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE (script id: %u) call for NULL object.", step.script->id); + break; + } + + Creature* cSource = source->ToCreature() != NULL ? source->ToCreature() : target->ToCreature(); + if (!cSource) + { + sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE (script id: %u) call for non-creature source.", step.script->id); + break; + } + + if (step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= cSource->GetValuesCount()) + { + sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE (script id: %u) call for wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u).", + step.script->id, step.script->datalong,source->GetValuesCount(),source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); + break; + } + + cSource->RemoveFlag(step.script->datalong, step.script->datalong2); + break; + } + + case SCRIPT_COMMAND_TELEPORT_TO: + { + // accept object in any one from target/source arg + if (!target && !source) + { + sLog.outError("SCRIPT_COMMAND_TELEPORT_TO (script id: %u) call for NULL object.", step.script->id); + break; + } + + if (step.script->datalong2 == 0) + { + Player* pSource = target->ToPlayer() != NULL ? target->ToPlayer() : source->ToPlayer(); + // must be only Player + if (!pSource) + { + sLog.outError("SCRIPT_COMMAND_TELEPORT_TO (script id: %u) call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", + step.script->id, source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0); + break; + } + + pSource->TeleportTo(step.script->datalong, step.script->x, step.script->y, step.script->z, step.script->o); + } + else if (step.script->datalong2 == 1) + { + Creature *cSource = target->ToCreature() != NULL ? target->ToCreature() : source->ToCreature(); + // must be only Creature + if (!cSource) + { + sLog.outError("SCRIPT_COMMAND_TELEPORT_TO (script id: %u) call for non-creature (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", + step.script->id, source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0); + break; + } + + cSource->NearTeleportTo(step.script->x, step.script->y, step.script->z, step.script->o); + } + break; + } + + case SCRIPT_COMMAND_KILL_CREDIT: + { + // accept player in any one from target/source arg + if (!target && !source) + { + sLog.outError("SCRIPT_COMMAND_KILL_CREDIT (script id: %u) call for NULL object.", step.script->id); + break; + } + + Player* pSource = target->ToPlayer() != NULL ? target->ToPlayer() : source->ToPlayer(); + // must be only Player + if (!pSource) + { + sLog.outError("SCRIPT_COMMAND_KILL_CREDIT (script id: %u) call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", + step.script->id, source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0); + break; + } + + if (step.script->datalong2) + pSource->RewardPlayerAndGroupAtEvent(step.script->datalong, pSource); + else + pSource->KilledMonsterCredit(step.script->datalong, 0); + + break; + } + + case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: + { + if (!step.script->datalong) // creature not specified + { + sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE (script id: %u) call with no creature parameter.", step.script->id); + break; + } + + if (!source) + { + sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE (script id: %u) call for NULL source object.", step.script->id); + break; + } + + WorldObject* summoner = dynamic_cast(source); + + if (!summoner) + { + sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE (script id: %u) call for non-WorldObject (TypeId: %u, Entry: %u, GUID: %u), skipping.", + step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); + break; + } + + float x = step.script->x; + float y = step.script->y; + float z = step.script->z; + float o = step.script->o; + + Creature* pCreature = summoner->SummonCreature(step.script->datalong, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,step.script->datalong2); + if (!pCreature) + { + sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON (script id: %u) failed for creature (entry: %u).", step.script->id, step.script->datalong); + break; + } + + break; + } + + case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: + { + if (!step.script->datalong) // gameobject not specified + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT (script id: %u) call with no gameobject parameter.", step.script->id); + break; + } + + if (!source) + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT (script id: %u) call for NULL source object.", step.script->id); + break; + } + + WorldObject* summoner = dynamic_cast(source); + + if (!summoner) + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT (script id: %u) call for non-WorldObject (TypeId: %u, Entry: %u, GUID: %u), skipping.", + step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); + break; + } + + GameObject *go = NULL; + int32 time_to_despawn = step.script->datalong2<5 ? 5 : (int32)step.script->datalong2; + + CellPair p(Trinity::ComputeCellPair(summoner->GetPositionX(), summoner->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + Trinity::GameObjectWithDbGUIDCheck go_check(*summoner,step.script->datalong); + Trinity::GameObjectSearcher checker(summoner, go,go_check); + + TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); + cell.Visit(p, object_checker, *summoner->GetMap()); + + if (!go) + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT (script id: %u) failed for gameobject(guid: %u).", step.script->id, step.script->datalong); + break; + } + + if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE || + go->GetGoType() == GAMEOBJECT_TYPE_DOOR || + go->GetGoType() == GAMEOBJECT_TYPE_BUTTON || + go->GetGoType() == GAMEOBJECT_TYPE_TRAP) + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT (script id: %u) can not be used with gameobject of type %u (guid: %u).", + step.script->id, uint32(go->GetGoType()), step.script->datalong); + break; + } + + if (go->isSpawned()) + break; //gameobject already spawned + + go->SetLootState(GO_READY); + go->SetRespawnTime(time_to_despawn); //despawn object in ? seconds + + go->GetMap()->Add(go); + break; + } + case SCRIPT_COMMAND_OPEN_DOOR: + { + if (!step.script->datalong) // door not specified + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR (script id: %u) call for NULL target door.", step.script->id); + break; + } + + if (!source) + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR (script id: %u) call for NULL source unit.", step.script->id); + break; + } + + if (!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player) + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR (script id: %u) call for non-unit (TypeId: %u, Entry: %u, GUID: %u), skipping.", + step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); + break; + } + + GameObject *door = NULL; + WorldObject* wSource = (WorldObject*)source; + + int32 time_to_close = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2; + + CellPair p(Trinity::ComputeCellPair(wSource->GetPositionX(), wSource->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + Trinity::GameObjectWithDbGUIDCheck go_check(*wSource, step.script->datalong); + Trinity::GameObjectSearcher checker(wSource, door, go_check); + + TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); + cell.Visit(p, object_checker, *wSource->GetMap()); + + if (!door) + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR (script id: %u) failed for gameobject(guid: %u).", step.script->id, step.script->datalong); + break; + } + if (door->GetGoType() != GAMEOBJECT_TYPE_DOOR) + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR (script id: %u) failed for non-door(GoType: %u, Entry: %u, GUID: %u).", + step.script->id, door->GetGoType(),door->GetEntry(),door->GetGUIDLow()); + break; + } + + if (door->GetGoState() != GO_STATE_READY) + break; //door already open + + door->UseDoorOrButton(time_to_close); + + if (target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType() == GAMEOBJECT_TYPE_BUTTON) + ((GameObject*)target)->UseDoorOrButton(time_to_close); + break; + } + case SCRIPT_COMMAND_CLOSE_DOOR: + { + if (!step.script->datalong) // guid for door not specified + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR (script id: %u) call for NULL door.", step.script->id); + break; + } + + if (!source) + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR (script id: %u) call for NULL unit.", step.script->id); + break; + } + + if (!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player) + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR (script id: %u) call for non-unit (TypeId: %u, Entry: %u, GUID: %u), skipping.", + step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); + break; + } + + GameObject *door = NULL; + WorldObject* wSource = (WorldObject*)source; + + int32 time_to_open = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2; + + CellPair p(Trinity::ComputeCellPair(wSource->GetPositionX(), wSource->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + Trinity::GameObjectWithDbGUIDCheck go_check(*wSource, step.script->datalong); + Trinity::GameObjectSearcher checker(wSource, door, go_check); + + TypeContainerVisitor, GridTypeMapContainer > object_checker(checker); + cell.Visit(p, object_checker, *wSource->GetMap()); + + if (!door) + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR (script id: %u) failed for gameobject(guid: %u).", step.script->id, step.script->datalong); + break; + } + if (door->GetGoType() != GAMEOBJECT_TYPE_DOOR) + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR (script id: %u) failed for non-door(GoType: %u, Entry: %u, GUID: %u).", + step.script->id, door->GetGoType(),door->GetEntry(),door->GetGUIDLow()); + break; + } + + if (door->GetGoState() == GO_STATE_READY) + break; //door already closed + + door->UseDoorOrButton(time_to_open); + + if (target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType() == GAMEOBJECT_TYPE_BUTTON) + ((GameObject*)target)->UseDoorOrButton(time_to_open); + + break; + } + case SCRIPT_COMMAND_QUEST_EXPLORED: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED (script id %u) call for NULL source.", step.script->id); + break; + } + + if (!target) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED (script id %u) call for NULL target.", step.script->id); + break; + } + + // when script called for item spell casting then target == (unit or GO) and source is player + WorldObject* worldObject; + Player* pTarget; + + pTarget = target->ToPlayer(); + if (pTarget) + { + if (source->GetTypeId() != TYPEID_UNIT && source->GetTypeId() != TYPEID_GAMEOBJECT && source->GetTypeId() != TYPEID_PLAYER) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED (script id %u) call for non-creature, non-gameobject or non-player (TypeId: %u), skipping.", + step.script->id, source->GetTypeId()); + break; + } + + worldObject = (WorldObject*)source; + } + else + { + if (target->GetTypeId() != TYPEID_UNIT && target->GetTypeId() != TYPEID_GAMEOBJECT && target->GetTypeId() != TYPEID_PLAYER) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED (script id %u) call for non-creature, non-gameobject or non-player (TypeId: %u), skipping.", + step.script->id, target->GetTypeId()); + break; + } + + pTarget = source->ToPlayer(); + if (!pTarget) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED (script id %u) call for non-player (TypeId: %u), skipping.", step.script->id, source->GetTypeId()); + break; + } + + worldObject = (WorldObject*)target; + } + + // quest id and flags checked at script loading + if ((worldObject->GetTypeId() != TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) && + (step.script->datalong2 == 0 || worldObject->IsWithinDistInMap(pTarget, float(step.script->datalong2)))) + pTarget->AreaExploredOrEventHappens(step.script->datalong); + else + pTarget->FailQuest(step.script->datalong); + + break; + } + + case SCRIPT_COMMAND_ACTIVATE_OBJECT: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT (script id: %u) must have source caster.", step.script->id); + break; + } + + if (!source->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT (script id: %u) source caster isn't unit (TypeId: %u, Entry: %u, GUID: %u), skipping.", + step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); + break; + } + + if (!target) + { + sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT (script id: %u) call for NULL gameobject.", step.script->id); + break; + } + + if (target->GetTypeId() != TYPEID_GAMEOBJECT) + { + sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT (script id: %u) call for non-gameobject (TypeId: %u, Entry: %u, GUID: %u), skipping.", + step.script->id, target->GetTypeId(),target->GetEntry(),target->GetGUIDLow()); + break; + } + + Unit* caster = (Unit*)source; + + GameObject *go = (GameObject*)target; + + go->Use(caster); + break; + } + + case SCRIPT_COMMAND_REMOVE_AURA: + { + Object* cmdTarget = step.script->datalong2 ? source : target; + + if (!cmdTarget) + { + sLog.outError("SCRIPT_COMMAND_REMOVE_AURA (script id: %u) call for NULL %s.", step.script->id, step.script->datalong2 ? "source" : "target"); + break; + } + + if (!cmdTarget->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_REMOVE_AURA (script id: %u) %s isn't unit (TypeId: %u, Entry: %u, GUID: %u), skipping.", + step.script->id, step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId(),cmdTarget->GetEntry(),cmdTarget->GetGUIDLow()); + break; + } + + ((Unit*)cmdTarget)->RemoveAurasDueToSpell(step.script->datalong); + break; + } + + case SCRIPT_COMMAND_CAST_SPELL: + { + // TODO: Allow gameobjects to be targets and casters + if (!source) + { + sLog.outError("SCRIPT_COMMAND_CAST_SPELL (script id: %u) must have source caster.", step.script->id); + break; + } + + Unit* uSource = NULL; + Unit* uTarget = NULL; + // source/target cast spell at target/source (script->datalong2: 0: s->t 1: s->s 2: t->t 3: t->s + switch (step.script->datalong2) + { + case 0: // source -> target + uSource = dynamic_cast(source); + uTarget = dynamic_cast(target); + break; + case 1: // source -> source + uSource = dynamic_cast(source); + uTarget = dynamic_cast(source); + break; + case 2: // target -> target + uSource = dynamic_cast(target); + uTarget = dynamic_cast(target); + break; + case 3: // target -> source + uSource = dynamic_cast(target); + uTarget = dynamic_cast(source); + break; + case 4: // creature + uSource = dynamic_cast(source); + uTarget = GetClosestCreatureWithEntry(uSource, step.script->dataint, step.script->x); + break; + } + + if (!uSource || !uSource->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_CAST_SPELL (script id: %u) no source unit found for spell %u", step.script->id, step.script->datalong); + break; + } + + if (!uTarget || !uTarget->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_CAST_SPELL (script id: %u) no target unit found for spell %u", step.script->id, step.script->datalong); + break; + } + + uSource->CastSpell(uTarget, step.script->datalong, false); + break; + } + + case SCRIPT_COMMAND_PLAY_SOUND: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_PLAY_SOUND (script id: %u) call for NULL creature.", step.script->id); + break; + } + + WorldObject* pSource = dynamic_cast(source); + if (!pSource) + { + sLog.outError("SCRIPT_COMMAND_PLAY_SOUND (script id: %u) call for non-world object (TypeId: %u, Entry: %u, GUID: %u), skipping.", + step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); + break; + } + + // bitmask: 0/1=anyone/target, 0/2=with distance dependent + Player* pTarget; + if (step.script->datalong2 & 1) + { + if (!target) + { + sLog.outError("SCRIPT_COMMAND_PLAY_SOUND (script id: %u) in targeted mode call for NULL target.", step.script->id); + break; + } + + pTarget = target->ToPlayer(); + if (!pTarget) + { + sLog.outError("SCRIPT_COMMAND_PLAY_SOUND (script id: %u) in targeted mode call for non-player (TypeId: %u, Entry: %u, GUID: %u), skipping.", + step.script->id, target->GetTypeId(),target->GetEntry(),target->GetGUIDLow()); + break; + } + } + + // bitmask: 0/1=anyone/target, 0/2=with distance dependent + if (step.script->datalong2 & 2) + pSource->PlayDistanceSound(step.script->datalong, pTarget); + else + pSource->PlayDirectSound(step.script->datalong, pTarget); + break; + } + + case SCRIPT_COMMAND_CREATE_ITEM: + { + if (!target && !source) + { + sLog.outError("SCRIPT_COMMAND_CREATE_ITEM (script id: %u) call for NULL object.", step.script->id); + break; + } + + Player *pReceiver = target->ToPlayer() != NULL ? target->ToPlayer() : source->ToPlayer(); + // only Player + if (!pReceiver) + { + sLog.outError("SCRIPT_COMMAND_CREATE_ITEM (script id: %u) call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", + step.script->id, source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0); + break; + } + + ItemPosCountVec dest; + uint8 msg = pReceiver->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, step.script->datalong, step.script->datalong2); + if (msg == EQUIP_ERR_OK) + { + if (Item* item = pReceiver->StoreNewItem(dest, step.script->datalong, true)) + pReceiver->SendNewItem(item, step.script->datalong2, false, true); + } + else + pReceiver->SendEquipError(msg,NULL,NULL); + + break; + } + + case SCRIPT_COMMAND_DESPAWN_SELF: + { + if (!target && !source) + { + sLog.outError("SCRIPT_COMMAND_DESPAWN_SELF (script id: %u) call for NULL object.", step.script->id); + break; + } + + Creature* cSource = target->ToCreature(); + // only creature + if (!cSource) + { + sLog.outError("SCRIPT_COMMAND_DESPAWN_SELF (script id: %u) call for non-creature (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", + step.script->id, source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0); + break; + } + + cSource->ForcedDespawn(step.script->datalong); + break; + } + + case SCRIPT_COMMAND_LOAD_PATH: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_START_MOVE (script id: %u) cannot be applied to NON-existing unit.", step.script->id); + break; + } + + if (!source->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_START_MOVE (script id: %u) source mover isn't unit (TypeId: %u, Entry: %u, GUID: %u), skipping.", + step.script->id, source->GetTypeId(),source->GetEntry(),source->GetGUIDLow()); + break; + } + + if (!sWaypointMgr->GetPath(step.script->datalong)) + { + sLog.outError("SCRIPT_COMMAND_START_MOVE (script id: %u) source mover has an invalid path, skipping.", step.script->id, step.script->datalong2); + break; + } + + ((Unit*)source)->GetMotionMaster()->MovePath(step.script->datalong, step.script->datalong2); + break; + } + + case SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT: + { + if (!step.script->datalong || !step.script->datalong2) + { + sLog.outError("SCRIPT_COMMAND_CALLSCRIPT (script id: %u) calls invalid db_script_id or lowguid not present: skipping.", step.script->id); + break; + } + + Creature* cTarget; + if (source) //using grid searcher + { + WorldObject* wSource = (WorldObject*)source; + CellPair p(Trinity::ComputeCellPair(wSource->GetPositionX(), wSource->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + Trinity::CreatureWithDbGUIDCheck target_check(wSource, step.script->datalong); + Trinity::CreatureSearcher checker(wSource, cTarget, target_check); + + TypeContainerVisitor, GridTypeMapContainer > unit_checker(checker); + cell.Visit(p, unit_checker, *wSource->GetMap()); + } + else //check hashmap holders + { + if (CreatureData const* data = objmgr.GetCreatureData(step.script->datalong)) + cTarget = ObjectAccessor::GetObjectInWorld(data->mapid, data->posX, data->posY, MAKE_NEW_GUID(step.script->datalong, data->id, HIGHGUID_UNIT), cTarget); + } + + if (!cTarget) + { + sLog.outError("SCRIPT_COMMAND_CALLSCRIPT (script id: %u) target not found, creature entry %u", step.script->id, step.script->datalong); + break; + } + + //Lets choose our ScriptMap map + ScriptMapMap *datamap = NULL; + switch (step.script->dataint) + { + case 1: //QUEST END SCRIPTMAP + datamap = &sQuestEndScripts; + break; + case 2: //QUEST START SCRIPTMAP + datamap = &sQuestStartScripts; + break; + case 3: //SPELLS SCRIPTMAP + datamap = &sSpellScripts; + break; + case 4: //GAMEOBJECTS SCRIPTMAP + datamap = &sGameObjectScripts; + break; + case 5: //EVENTS SCRIPTMAP + datamap = &sEventScripts; + break; + case 6: //WAYPOINTS SCRIPTMAP + datamap = &sWaypointScripts; + break; + default: + sLog.outError("SCRIPT_COMMAND_CALLSCRIPT ERROR: no scriptmap present... ignoring"); + break; + } + //if no scriptmap present... + if (!datamap) + break; + + uint32 script_id = step.script->datalong2; + //insert script into schedule but do not start it + ScriptsStart(*datamap, script_id, cTarget, NULL/*, false*/); + break; + } + + case SCRIPT_COMMAND_KILL: + { + // TODO: Allow to kill objects other than self? + if (!source) + break; + + Creature* cSource = source->ToCreature(); + if (!cSource) + break; + + if (cSource->isDead()) + { + sLog.outError("SCRIPT_COMMAND_KILL (script id: %u) called for already dead creature, entry %u, guidLow %u", + step.script->id, cSource->GetEntry(), cSource->GetGUIDLow()); + break; + } + + cSource->setDeathState(JUST_DIED); + if (step.script->dataint == 1) + cSource->RemoveCorpse(); + + break; + } + + case SCRIPT_COMMAND_ORIENTATION: + { + if (!source || !source->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_ORIENTATION (script id: %u) call for NULL or non-unit source.", step.script->id); + break; + } + + Unit* uSource = (Unit*)source; + + if (!step.script->datalong) + uSource->SetOrientation(step.script->o); + else + { + if (!target || !target->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_ORIENTATION (script id: %u) call for NULL or non-unit target.", step.script->id); + break; + } + uSource->SetInFront((Unit*)target); + } + + uSource->SendMovementFlagUpdate(); + break; + } + case SCRIPT_COMMAND_EQUIP: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_EQUIP (script id: %u) call for NULL source.", step.script->id); + break; + } + + Creature* cSource = source->ToCreature(); + if (!cSource) + { + sLog.outError("SCRIPT_COMMAND_EQUIP (script id: %u) call, source is non-creature.", step.script->id); + break; + } + + cSource->LoadEquipment(step.script->datalong); + break; + } + case SCRIPT_COMMAND_MODEL: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_EQUIP (script id: %u) call for NULL source.", step.script->id); + break; + } + + Creature* cSource = source->ToCreature(); + if (!cSource) + { + sLog.outError("SCRIPT_COMMAND_EQUIP (script id: %u) call, source is non-creature.", step.script->id); + break; + } + + cSource->SetDisplayId(step.script->datalong); + break; + } + + case SCRIPT_COMMAND_CLOSE_GOSSIP: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_CLOSE_GOSSIP (script id: %u) for null source", step.script->id); + break; + } + + Player *pSource = source->ToPlayer(); + if (!pSource) + { + sLog.outError("SCRIPT_COMMAND_CLOSE_GOSSIP (script id: %u) for non-player source.", step.script->id); + break; + } + + pSource->PlayerTalkClass->CloseGossip(); + break; + } + + case SCRIPT_COMMAND_PLAYMOVIE: + { + if (!source) + { + sLog.outError("SCRIPT_COMMAND_PLAYMOVIE (script id: %u) call for NULL source.", step.script->id); + break; + } + + Player* pSource = source->ToPlayer(); + if (!pSource) + { + sLog.outError("SCRIPT_COMMAND_PLAYMOVIE (script id: %u) call for non-player source.", step.script->id); + break; + } + pSource->SendMovieStart(step.script->datalong); + break; + } + + default: + sLog.outError("Unknown script command %u called.", step.script->command); + break; + } + + m_scriptSchedule.erase(iter); + sWorld.DecreaseScheduledScriptCount(); + + iter = m_scriptSchedule.begin(); + } +} + +Creature* +Map::GetCreature(uint64 guid) +{ + Creature * ret = NULL; + if (IS_CRE_OR_VEH_GUID(guid)) + ret = ObjectAccessor::GetObjectInWorld(guid, (Creature*)NULL); + + if (!ret) + return NULL; + + if (ret->GetMapId() != GetId()) + return NULL; + + if (ret->GetInstanceId() != GetInstanceId()) + return NULL; + + return ret; +} + +GameObject* +Map::GetGameObject(uint64 guid) +{ + GameObject * ret = ObjectAccessor::GetObjectInWorld(guid, (GameObject*)NULL); + if (!ret) + return NULL; + if (ret->GetMapId() != GetId()) + return NULL; + if (ret->GetInstanceId() != GetInstanceId()) + return NULL; + return ret; +} + +DynamicObject* +Map::GetDynamicObject(uint64 guid) +{ + DynamicObject * ret = ObjectAccessor::GetObjectInWorld(guid, (DynamicObject*)NULL); + if (!ret) + return NULL; + if (ret->GetMapId() != GetId()) + return NULL; + if (ret->GetInstanceId() != GetInstanceId()) + return NULL; + return ret; +} + +void Map::UpdateIteratorBack(Player *player) +{ + if (m_mapRefIter == player->GetMapRef()) + m_mapRefIter = m_mapRefIter->nocheck_prev(); +} diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h new file mode 100644 index 00000000000..ceb526b8244 --- /dev/null +++ b/src/server/game/Maps/Map.h @@ -0,0 +1,689 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_MAP_H +#define TRINITY_MAP_H + +#include "Platform/Define.h" +#include "Policies/ThreadingModel.h" +#include "ace/RW_Thread_Mutex.h" +#include "ace/Thread_Mutex.h" + +#include "DBCStructure.h" +#include "GridDefines.h" +#include "Cell.h" +#include "Timer.h" +#include "SharedDefines.h" +#include "GameSystem/GridRefManager.h" +#include "MapRefManager.h" +#include "mersennetwister/MersenneTwister.h" + +#include +#include + +class Unit; +class WorldPacket; +class InstanceData; +class Group; +class InstanceSave; +class Object; +class WorldObject; +class TempSummon; +class Player; +class CreatureGroup; +struct ScriptInfo; +struct ScriptAction; +struct Position; +class BattleGround; + +//****************************************** +// Map file format defines +//****************************************** +#define MAP_MAGIC 'SPAM' +#define MAP_VERSION_MAGIC '0.1w' +#define MAP_AREA_MAGIC 'AERA' +#define MAP_HEIGHT_MAGIC 'TGHM' +#define MAP_LIQUID_MAGIC 'QILM' + +struct map_fileheader +{ + uint32 mapMagic; + uint32 versionMagic; + uint32 areaMapOffset; + uint32 areaMapSize; + uint32 heightMapOffset; + uint32 heightMapSize; + uint32 liquidMapOffset; + uint32 liquidMapSize; +}; + +#define MAP_AREA_NO_AREA 0x0001 + +struct map_areaHeader +{ + uint32 fourcc; + uint16 flags; + uint16 gridArea; +}; + +#define MAP_HEIGHT_NO_HEIGHT 0x0001 +#define MAP_HEIGHT_AS_INT16 0x0002 +#define MAP_HEIGHT_AS_INT8 0x0004 + +struct map_heightHeader +{ + uint32 fourcc; + uint32 flags; + float gridHeight; + float gridMaxHeight; +}; + +#define MAP_LIQUID_NO_TYPE 0x0001 +#define MAP_LIQUID_NO_HEIGHT 0x0002 + +struct map_liquidHeader +{ + uint32 fourcc; + uint16 flags; + uint16 liquidType; + uint8 offsetX; + uint8 offsetY; + uint8 width; + uint8 height; + float liquidLevel; +}; + +enum ZLiquidStatus +{ + LIQUID_MAP_NO_WATER = 0x00000000, + LIQUID_MAP_ABOVE_WATER = 0x00000001, + LIQUID_MAP_WATER_WALK = 0x00000002, + LIQUID_MAP_IN_WATER = 0x00000004, + LIQUID_MAP_UNDER_WATER = 0x00000008 +}; + +#define MAP_LIQUID_TYPE_NO_WATER 0x00 +#define MAP_LIQUID_TYPE_WATER 0x01 +#define MAP_LIQUID_TYPE_OCEAN 0x02 +#define MAP_LIQUID_TYPE_MAGMA 0x04 +#define MAP_LIQUID_TYPE_SLIME 0x08 + +#define MAP_ALL_LIQUIDS (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN | MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME) + +#define MAP_LIQUID_TYPE_DARK_WATER 0x10 +#define MAP_LIQUID_TYPE_WMO_WATER 0x20 + +struct LiquidData +{ + uint32 type; + float level; + float depth_level; +}; + +class GridMap +{ + uint32 m_flags; + // Area data + uint16 m_gridArea; + uint16 *m_area_map; + // Height level data + float m_gridHeight; + float m_gridIntHeightMultiplier; + union{ + float *m_V9; + uint16 *m_uint16_V9; + uint8 *m_uint8_V9; + }; + union{ + float *m_V8; + uint16 *m_uint16_V8; + uint8 *m_uint8_V8; + }; + // Liquid data + uint16 m_liquidType; + uint8 m_liquid_offX; + uint8 m_liquid_offY; + uint8 m_liquid_width; + uint8 m_liquid_height; + float m_liquidLevel; + uint8 *m_liquid_type; + float *m_liquid_map; + + bool loadAreaData(FILE *in, uint32 offset, uint32 size); + bool loadHeihgtData(FILE *in, uint32 offset, uint32 size); + bool loadLiquidData(FILE *in, uint32 offset, uint32 size); + + // Get height functions and pointers + typedef float (GridMap::*pGetHeightPtr) (float x, float y) const; + pGetHeightPtr m_gridGetHeight; + float getHeightFromFloat(float x, float y) const; + float getHeightFromUint16(float x, float y) const; + float getHeightFromUint8(float x, float y) const; + float getHeightFromFlat(float x, float y) const; + +public: + GridMap(); + ~GridMap(); + bool loadData(char *filaname); + void unloadData(); + + uint16 getArea(float x, float y); + inline float getHeight(float x, float y) {return (this->*m_gridGetHeight)(x, y);} + float getLiquidLevel(float x, float y); + uint8 getTerrainType(float x, float y); + ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data = 0); +}; + +struct CreatureMover +{ + CreatureMover() : x(0), y(0), z(0), ang(0) {} + CreatureMover(float _x, float _y, float _z, float _ang) : x(_x), y(_y), z(_z), ang(_ang) {} + + float x, y, z, ang; +}; + +// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform +#if defined(__GNUC__) +#pragma pack(1) +#else +#pragma pack(push,1) +#endif + +struct InstanceTemplate +{ + uint32 map; + uint32 parent; + uint32 access_id; + float startLocX; + float startLocY; + float startLocZ; + float startLocO; + uint32 script_id; + bool allowMount; +}; + +enum LevelRequirementVsMode +{ + LEVELREQUIREMENT_HEROIC = 70 +}; + +#if defined(__GNUC__) +#pragma pack() +#else +#pragma pack(pop) +#endif + +typedef UNORDERED_MAP CreatureMoveList; + +#define MAX_HEIGHT 100000.0f // can be use for find ground height at surface +#define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE +#define MIN_UNLOAD_DELAY 1 // immediate unload + +typedef std::map CreatureGroupHolderType; + +class Map : public GridRefManager, public Trinity::ObjectLevelLockable +{ + friend class MapReference; + public: + Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent = NULL); + virtual ~Map(); + + // currently unused for normal maps + bool CanUnload(uint32 diff) + { + if (!m_unloadTimer) return false; + if (m_unloadTimer <= diff) return true; + m_unloadTimer -= diff; + return false; + } + + virtual bool Add(Player *); + virtual void Remove(Player *, bool); + template void Add(T *); + template void Remove(T *, bool); + + virtual void Update(const uint32&); + + /* + void MessageBroadcast(Player *, WorldPacket *, bool to_self); + void MessageBroadcast(WorldObject *, WorldPacket *); + void MessageDistBroadcast(Player *, WorldPacket *, float dist, bool to_self, bool own_team_only = false); + void MessageDistBroadcast(WorldObject *, WorldPacket *, float dist); + */ + + float GetVisibilityDistance() const { return m_VisibleDistance; } + //function for setting up visibility distance for maps on per-type/per-Id basis + virtual void InitVisibilityDistance(); + + void PlayerRelocation(Player *, float x, float y, float z, float orientation); + void CreatureRelocation(Creature *creature, float x, float y, float z, float ang); + + template void Visit(const Cell& cell, TypeContainerVisitor &visitor); + + bool IsRemovalGrid(float x, float y) const + { + GridPair p = Trinity::ComputeGridPair(x, y); + return !getNGrid(p.x_coord, p.y_coord) || getNGrid(p.x_coord, p.y_coord)->GetGridState() == GRID_STATE_REMOVAL; + } + + bool IsLoaded(float x, float y) const + { + GridPair p = Trinity::ComputeGridPair(x, y); + return loaded(p); + } + + bool GetUnloadLock(const GridPair &p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); } + void SetUnloadLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); } + void LoadGrid(float x, float y); + bool UnloadGrid(const uint32 &x, const uint32 &y, bool pForce); + virtual void UnloadAll(); + + void ResetGridExpiry(NGridType &grid, float factor = 1) const + { + grid.ResetTimeTracker(time_t(float(i_gridExpiry)*factor)); + } + + time_t GetGridExpiry(void) const { return i_gridExpiry; } + uint32 GetId(void) const { return i_mapEntry->MapID; } + + static bool ExistMap(uint32 mapid, int gx, int gy); + static bool ExistVMap(uint32 mapid, int gx, int gy); + + static void InitStateMachine(); + static void DeleteStateMachine(); + + Map const * GetParent() const { return m_parentMap; } + + // some calls like isInWater should not use vmaps due to processor power + // can return INVALID_HEIGHT if under z+2 z coord not found height + float GetHeight(float x, float y, float z, bool pCheckVMap=true) const; + + ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data = 0) const; + + uint16 GetAreaFlag(float x, float y, float z, bool *isOutdoors=0) const; + bool GetAreaInfo(float x, float y, float z, uint32 &mogpflags, int32 &adtId, int32 &rootId, int32 &groupId) const; + + bool IsOutdoors(float x, float y, float z) const; + + uint8 GetTerrainType(float x, float y) const; + float GetWaterLevel(float x, float y) const; + bool IsInWater(float x, float y, float z, LiquidData *data = 0) const; + bool IsUnderWater(float x, float y, float z) const; + + static uint32 GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id); + static uint32 GetZoneIdByAreaFlag(uint16 areaflag,uint32 map_id); + static void GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag,uint32 map_id); + + uint32 GetAreaId(float x, float y, float z) const + { + return GetAreaIdByAreaFlag(GetAreaFlag(x,y,z),GetId()); + } + + uint32 GetZoneId(float x, float y, float z) const + { + return GetZoneIdByAreaFlag(GetAreaFlag(x,y,z),GetId()); + } + + void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const + { + GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(x,y,z),GetId()); + } + + void MoveAllCreaturesInMoveList(); + void RemoveAllObjectsInRemoveList(); + virtual void RemoveAllPlayers(); + + bool CreatureRespawnRelocation(Creature *c); // used only in MoveAllCreaturesInMoveList and ObjectGridUnloader + + // assert print helper + bool CheckGridIntegrity(Creature* c, bool moved) const; + + uint32 GetInstanceId() const { return i_InstanceId; } + uint8 GetSpawnMode() const { return (i_spawnMode); } + virtual bool CanEnter(Player* /*player*/) { return true; } + const char* GetMapName() const; + + // have meaning only for instanced map (that have set real difficulty) + Difficulty GetDifficulty() const { return Difficulty(GetSpawnMode()); } + bool IsRegularDifficulty() const { return GetDifficulty() == REGULAR_DIFFICULTY; } + MapDifficulty const* GetMapDifficulty() const; + + bool Instanceable() const { return i_mapEntry && i_mapEntry->Instanceable(); } + // NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable + bool IsDungeon() const { return i_mapEntry && i_mapEntry->IsDungeon(); } + bool IsNonRaidDungeon() const { return i_mapEntry && i_mapEntry->IsNonRaidDungeon(); } + bool IsRaid() const { return i_mapEntry && i_mapEntry->IsRaid(); } + bool IsRaidOrHeroicDungeon() const { return IsRaid() || i_spawnMode > DUNGEON_DIFFICULTY_NORMAL; } + bool IsHeroic() const { return IsRaid() ? i_spawnMode >= RAID_DIFFICULTY_10MAN_HEROIC : i_spawnMode >= DUNGEON_DIFFICULTY_HEROIC; } + bool IsBattleGround() const { return i_mapEntry && i_mapEntry->IsBattleGround(); } + bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); } + bool IsBattleGroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattleGroundOrArena(); } + bool GetEntrancePos(int32 &mapid, float &x, float &y) + { + if (!i_mapEntry) + return false; + return i_mapEntry->GetEntrancePos(mapid, x, y); + } + + void AddObjectToRemoveList(WorldObject *obj); + void AddObjectToSwitchList(WorldObject *obj, bool on); + virtual void DelayedUpdate(const uint32 diff); + + virtual bool RemoveBones(uint64 guid, float x, float y); + + void UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair); + void UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpair); + + void resetMarkedCells() { marked_cells.reset(); } + bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); } + void markCell(uint32 pCellId) { marked_cells.set(pCellId); } + + bool HavePlayers() const { return !m_mapRefManager.isEmpty(); } + uint32 GetPlayersCountExceptGMs() const; + bool ActiveObjectsNearGrid(uint32 x, uint32 y) const; + + void AddWorldObject(WorldObject *obj) { i_worldObjects.insert(obj); } + void RemoveWorldObject(WorldObject *obj) { i_worldObjects.erase(obj); } + + void SendToPlayers(WorldPacket const* data) const; + + typedef MapRefManager PlayerList; + PlayerList const& GetPlayers() const { return m_mapRefManager; } + + //per-map script storage + void ScriptsStart(std::map > const& scripts, uint32 id, Object* source, Object* target); + void ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target); + + // must called with AddToWorld + template + void AddToActive(T* obj) { AddToActiveHelper(obj); } + + void AddToActive(Creature* obj); + + // must called with RemoveFromWorld + template + void RemoveFromActive(T* obj) { RemoveFromActiveHelper(obj); } + + void RemoveFromActive(Creature* obj); + + template void SwitchGridContainers(T* obj, bool active); + template void VisitAll(const float &x, const float &y, float radius, NOTIFIER ¬ifier); + template void VisitWorld(const float &x, const float &y, float radius, NOTIFIER ¬ifier); + template void VisitGrid(const float &x, const float &y, float radius, NOTIFIER ¬ifier); + CreatureGroupHolderType CreatureGroupHolder; + + void UpdateIteratorBack(Player *player); + +#ifdef MAP_BASED_RAND_GEN + MTRand mtRand; + int32 irand(int32 min, int32 max) { return int32 (mtRand.randInt(max - min)) + min; } + uint32 urand(uint32 min, uint32 max) { return mtRand.randInt(max - min) + min; } + int32 rand32() { return mtRand.randInt(); } + double rand_norm() { return mtRand.randExc(); } + double rand_chance() { return mtRand.randExc(100.0); } +#endif + + TempSummon *SummonCreature(uint32 entry, const Position &pos, SummonPropertiesEntry const *properties = NULL, uint32 duration = 0, Unit *summoner = NULL, uint32 vehId = 0); + Creature* GetCreature(uint64 guid); + GameObject* GetGameObject(uint64 guid); + DynamicObject* GetDynamicObject(uint64 guid); + private: + void LoadMapAndVMap(int gx, int gy); + void LoadVMap(int gx, int gy); + void LoadMap(int gx,int gy, bool reload = false); + GridMap *GetGrid(float x, float y); + + void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; } + + void SendInitSelf(Player * player); + + void SendInitTransports(Player * player); + void SendRemoveTransports(Player * player); + + bool CreatureCellRelocation(Creature *creature, Cell new_cell); + + void AddCreatureToMoveList(Creature *c, float x, float y, float z, float ang); + CreatureMoveList i_creaturesToMove; + + bool loaded(const GridPair &) const; + void EnsureGridCreated(const GridPair &); + bool EnsureGridLoaded(Cell const&); + void EnsureGridLoadedAtEnter(Cell const&, Player* player = NULL); + + void buildNGridLinkage(NGridType* pNGridType) { pNGridType->link(this); } + + template void AddType(T *obj); + template void RemoveType(T *obj, bool); + + NGridType* getNGrid(uint32 x, uint32 y) const + { + ASSERT(x < MAX_NUMBER_OF_GRIDS); + ASSERT(y < MAX_NUMBER_OF_GRIDS); + return i_grids[x][y]; + } + + bool isGridObjectDataLoaded(uint32 x, uint32 y) const { return getNGrid(x,y)->isGridObjectDataLoaded(); } + void setGridObjectDataLoaded(bool pLoaded, uint32 x, uint32 y) { getNGrid(x,y)->setGridObjectDataLoaded(pLoaded); } + + void setNGrid(NGridType* grid, uint32 x, uint32 y); + void ScriptsProcess(); + + void UpdateActiveCells(const float &x, const float &y, const uint32 &t_diff); + protected: + void SetUnloadReferenceLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); } + + typedef Trinity::ObjectLevelLockable::Lock Guard; + + MapEntry const* i_mapEntry; + uint8 i_spawnMode; + uint32 i_InstanceId; + uint32 m_unloadTimer; + float m_VisibleDistance; + + MapRefManager m_mapRefManager; + MapRefManager::iterator m_mapRefIter; + + int32 m_VisibilityNotifyPeriod; + + typedef std::set ActiveNonPlayers; + ActiveNonPlayers m_activeNonPlayers; + ActiveNonPlayers::iterator m_activeNonPlayersIter; + + private: + time_t i_gridExpiry; + + //used for fast base_map (e.g. MapInstanced class object) search for + //InstanceMaps and BattleGroundMaps... + Map* m_parentMap; + + NGridType* i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; + GridMap *GridMaps[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; + std::bitset marked_cells; + + //these functions used to process player/mob aggro reactions and + //visibility calculations. Highly optimized for massive calculations + void ProcessRelocationNotifies(const uint32 &diff); + + bool i_scriptLock; + std::set i_objectsToRemove; + std::map i_objectsToSwitch; + std::set i_worldObjects; + std::multimap m_scriptSchedule; + + // Type specific code for add/remove to/from grid + template + void AddToGrid(T*, NGridType *, Cell const&); + + template + void RemoveFromGrid(T*, NGridType *, Cell const&); + + template + void DeleteFromWorld(T*); + + template + void AddToActiveHelper(T* obj) + { + m_activeNonPlayers.insert(obj); + } + + template + void RemoveFromActiveHelper(T* obj) + { + // Map::Update for active object in proccess + if (m_activeNonPlayersIter != m_activeNonPlayers.end()) + { + ActiveNonPlayers::iterator itr = m_activeNonPlayers.find(obj); + if (itr == m_activeNonPlayers.end()) + return; + if (itr == m_activeNonPlayersIter) + ++m_activeNonPlayersIter; + m_activeNonPlayers.erase(itr); + } + else + m_activeNonPlayers.erase(obj); + } +}; + +enum InstanceResetMethod +{ + INSTANCE_RESET_ALL, + INSTANCE_RESET_CHANGE_DIFFICULTY, + INSTANCE_RESET_GLOBAL, + INSTANCE_RESET_GROUP_DISBAND, + INSTANCE_RESET_GROUP_JOIN, + INSTANCE_RESET_RESPAWN_DELAY +}; + +class InstanceMap : public Map +{ + public: + InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent); + ~InstanceMap(); + bool Add(Player *); + void Remove(Player *, bool); + void Update(const uint32&); + void CreateInstanceData(bool load); + bool Reset(uint8 method); + uint32 GetScriptId() { return i_script_id; } + InstanceData* GetInstanceData() { return i_data; } + void PermBindAllPlayers(Player *player); + void UnloadAll(); + bool CanEnter(Player* player); + void SendResetWarnings(uint32 timeLeft) const; + void SetResetSchedule(bool on); + + uint32 GetMaxPlayers() const; + uint32 GetMaxResetDelay() const; + + virtual void InitVisibilityDistance(); + private: + bool m_resetAfterUnload; + bool m_unloadWhenEmpty; + InstanceData* i_data; + uint32 i_script_id; +}; + +class BattleGroundMap : public Map +{ + public: + BattleGroundMap(uint32 id, time_t, uint32 InstanceId, Map* _parent, uint8 spawnMode); + ~BattleGroundMap(); + + bool Add(Player *); + void Remove(Player *, bool); + bool CanEnter(Player* player); + void SetUnload(); + //void UnloadAll(bool pForce); + void RemoveAllPlayers(); + + virtual void InitVisibilityDistance(); + BattleGround* GetBG() { return m_bg; } + void SetBG(BattleGround* bg) { m_bg = bg; } + private: + BattleGround* m_bg; +}; + +/*inline +uint64 +Map::CalculateGridMask(const uint32 &y) const +{ + uint64 mask = 1; + mask <<= y; + return mask; +} +*/ + +template +inline void +Map::Visit(const Cell& cell, TypeContainerVisitor &visitor) +{ + const uint32 x = cell.GridX(); + const uint32 y = cell.GridY(); + const uint32 cell_x = cell.CellX(); + const uint32 cell_y = cell.CellY(); + + if (!cell.NoCreate() || loaded(GridPair(x,y))) + { + EnsureGridLoaded(cell); + getNGrid(x, y)->Visit(cell_x, cell_y, visitor); + } +} + +template +inline void +Map::VisitAll(const float &x, const float &y, float radius, NOTIFIER ¬ifier) +{ + CellPair p(Trinity::ComputeCellPair(x, y)); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + TypeContainerVisitor world_object_notifier(notifier); + cell.Visit(p, world_object_notifier, *this, radius, x, y); + TypeContainerVisitor grid_object_notifier(notifier); + cell.Visit(p, grid_object_notifier, *this, radius, x, y); +} + +template +inline void +Map::VisitWorld(const float &x, const float &y, float radius, NOTIFIER ¬ifier) +{ + CellPair p(Trinity::ComputeCellPair(x, y)); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + TypeContainerVisitor world_object_notifier(notifier); + cell.Visit(p, world_object_notifier, *this, radius, x, y); +} + +template +inline void +Map::VisitGrid(const float &x, const float &y, float radius, NOTIFIER ¬ifier) +{ + CellPair p(Trinity::ComputeCellPair(x, y)); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + TypeContainerVisitor grid_object_notifier(notifier); + cell.Visit(p, grid_object_notifier, *this, radius, x, y); +} +#endif diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp new file mode 100644 index 00000000000..0736bfa6fb3 --- /dev/null +++ b/src/server/game/Maps/MapInstanced.cpp @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MapInstanced.h" +#include "ObjectMgr.h" +#include "MapManager.h" +#include "BattleGround.h" +#include "VMapFactory.h" +#include "InstanceSaveMgr.h" +#include "World.h" + +MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, DUNGEON_DIFFICULTY_NORMAL) +{ + // initialize instanced maps list + m_InstancedMaps.clear(); + // fill with zero + memset(&GridMapReference, 0, MAX_NUMBER_OF_GRIDS*MAX_NUMBER_OF_GRIDS*sizeof(uint16)); +} + +void MapInstanced::InitVisibilityDistance() +{ + if (m_InstancedMaps.empty()) + return; + //initialize visibility distances for all instance copies + for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) + { + (*i).second->InitVisibilityDistance(); + } +} + +void MapInstanced::Update(const uint32& t) +{ + // take care of loaded GridMaps (when unused, unload it!) + Map::Update(t); + + // update the instanced maps + InstancedMaps::iterator i = m_InstancedMaps.begin(); + + while (i != m_InstancedMaps.end()) + { + if (i->second->CanUnload(t)) + { + if (!DestroyInstance(i)) // iterator incremented + { + //m_unloadTimer + } + } + else + { + // update only here, because it may schedule some bad things before delete + i->second->Update(t); + ++i; + } + } +} + +void MapInstanced::DelayedUpdate(const uint32 diff) +{ + for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) + i->second->DelayedUpdate(diff); + + Map::DelayedUpdate(diff); // this may be removed +} + +/* +void MapInstanced::RelocationNotify() +{ + for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) + i->second->RelocationNotify(); +} +*/ + +bool MapInstanced::RemoveBones(uint64 guid, float x, float y) +{ + bool remove_result = false; + + for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) + { + remove_result = remove_result || i->second->RemoveBones(guid, x, y); + } + + return remove_result || Map::RemoveBones(guid,x,y); +} + +void MapInstanced::UnloadAll() +{ + // Unload instanced maps + for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) + i->second->UnloadAll(); + + // Delete the maps only after everything is unloaded to prevent crashes + for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) + delete i->second; + + m_InstancedMaps.clear(); + + // Unload own grids (just dummy(placeholder) grids, neccesary to unload GridMaps!) + Map::UnloadAll(); +} + +/* +- return the right instance for the object, based on its InstanceId +- create the instance if it's not created already +- the player is not actually added to the instance (only in InstanceMap::Add) +*/ +Map* MapInstanced::CreateInstance(const uint32 mapId, Player * player) +{ + if (GetId() != mapId || !player) + return NULL; + + Map* map = NULL; + uint32 NewInstanceId = 0; // instanceId of the resulting map + + if (IsBattleGroundOrArena()) + { + // instantiate or find existing bg map for player + // the instance id is set in battlegroundid + NewInstanceId = player->GetBattleGroundId(); + if (!NewInstanceId) return NULL; + map = _FindMap(NewInstanceId); + if (!map) + map = CreateBattleGround(NewInstanceId, player->GetBattleGround()); + } + else + { + InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty(IsRaid())); + InstanceSave *pSave = pBind ? pBind->save : NULL; + + // the player's permanent player bind is taken into consideration first + // then the player's group bind and finally the solo bind. + if (!pBind || !pBind->perm) + { + InstanceGroupBind *groupBind = NULL; + Group *group = player->GetGroup(); + // use the player's difficulty setting (it may not be the same as the group's) + if (group) + { + groupBind = group->GetBoundInstance(this); + if (groupBind) + pSave = groupBind->save; + } + } + if (pSave) + { + // solo/perm/group + NewInstanceId = pSave->GetInstanceId(); + map = _FindMap(NewInstanceId); + // it is possible that the save exists but the map doesn't + if (!map) + map = CreateInstance(NewInstanceId, pSave, pSave->GetDifficulty()); + } + else + { + // if no instanceId via group members or instance saves is found + // the instance will be created for the first time + NewInstanceId = MapManager::Instance().GenerateInstanceId(); + + Difficulty diff = player->GetGroup() ? player->GetGroup()->GetDifficulty(IsRaid()) : player->GetDifficulty(IsRaid()); + map = CreateInstance(NewInstanceId, NULL, diff); + } + } + + return map; +} + +InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, Difficulty difficulty) +{ + // load/create a map + Guard guard(*this); + + // make sure we have a valid map id + const MapEntry* entry = sMapStore.LookupEntry(GetId()); + if (!entry) + { + sLog.outError("CreateInstance: no entry for map %d", GetId()); + assert(false); + } + const InstanceTemplate * iTemplate = objmgr.GetInstanceTemplate(GetId()); + if (!iTemplate) + { + sLog.outError("CreateInstance: no instance template for map %d", GetId()); + assert(false); + } + + // some instances only have one difficulty + MapDifficulty const* mapDiff = GetMapDifficultyData(GetId(),difficulty); + if (!mapDiff) + difficulty = DUNGEON_DIFFICULTY_NORMAL; + + sLog.outDebug("MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal"); + + InstanceMap *map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this); + ASSERT(map->IsDungeon()); + + bool load_data = save != NULL; + map->CreateInstanceData(load_data); + + m_InstancedMaps[InstanceId] = map; + return map; +} + +BattleGroundMap* MapInstanced::CreateBattleGround(uint32 InstanceId, BattleGround* bg) +{ + // load/create a map + Guard guard(*this); + + sLog.outDebug("MapInstanced::CreateBattleGround: map bg %d for %d created.", InstanceId, GetId()); + + PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),bg->GetMinLevel()); + + uint8 spawnMode = bracketEntry ? bracketEntry->difficulty : REGULAR_DIFFICULTY; + + BattleGroundMap *map = new BattleGroundMap(GetId(), GetGridExpiry(), InstanceId, this, spawnMode); + ASSERT(map->IsBattleGroundOrArena()); + map->SetBG(bg); + bg->SetBgMap(map); + + m_InstancedMaps[InstanceId] = map; + return map; +} + +// increments the iterator after erase +bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) +{ + itr->second->RemoveAllPlayers(); + if (itr->second->HavePlayers()) + { + ++itr; + return false; + } + + itr->second->UnloadAll(); + // should only unload VMaps if this is the last instance and grid unloading is enabled + if (m_InstancedMaps.size() <= 1 && sWorld.getConfig(CONFIG_GRID_UNLOAD)) + { + VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(itr->second->GetId()); + // in that case, unload grids of the base map, too + // so in the next map creation, (EnsureGridCreated actually) VMaps will be reloaded + Map::UnloadAll(); + } + // erase map + delete itr->second; + m_InstancedMaps.erase(itr++); + return true; +} + +bool MapInstanced::CanEnter(Player * /*player*/) +{ + //assert(false); + return true; +} diff --git a/src/server/game/Maps/MapInstanced.h b/src/server/game/Maps/MapInstanced.h new file mode 100644 index 00000000000..536257da011 --- /dev/null +++ b/src/server/game/Maps/MapInstanced.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_MAP_INSTANCED_H +#define TRINITY_MAP_INSTANCED_H + +#include "Map.h" +#include "InstanceSaveMgr.h" +#include "DBCEnums.h" + +class MapInstanced : public Map +{ + friend class MapManager; + public: + typedef UNORDERED_MAP< uint32, Map* > InstancedMaps; + + MapInstanced(uint32 id, time_t expiry); + ~MapInstanced() {} + + // functions overwrite Map versions + void Update(const uint32&); + void DelayedUpdate(const uint32 diff); + //void RelocationNotify(); + bool RemoveBones(uint64 guid, float x, float y); + void UnloadAll(); + bool CanEnter(Player* player); + + Map* CreateInstance(const uint32 mapId, Player * player); + Map* FindMap(uint32 InstanceId) const { return _FindMap(InstanceId); } + bool DestroyInstance(InstancedMaps::iterator &itr); + + void AddGridMapReference(const GridPair &p) + { + ++GridMapReference[p.x_coord][p.y_coord]; + SetUnloadReferenceLock(GridPair(63-p.x_coord, 63-p.y_coord), true); + } + + void RemoveGridMapReference(GridPair const& p) + { + --GridMapReference[p.x_coord][p.y_coord]; + if (!GridMapReference[p.x_coord][p.y_coord]) + SetUnloadReferenceLock(GridPair(63-p.x_coord, 63-p.y_coord), false); + } + + InstancedMaps &GetInstancedMaps() { return m_InstancedMaps; } + virtual void InitVisibilityDistance(); + + private: + + InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave *save, Difficulty difficulty); + BattleGroundMap* CreateBattleGround(uint32 InstanceId, BattleGround* bg); + + InstancedMaps m_InstancedMaps; + + Map* _FindMap(uint32 InstanceId) const + { + InstancedMaps::const_iterator i = m_InstancedMaps.find(InstanceId); + return(i == m_InstancedMaps.end() ? NULL : i->second); + } + + uint16 GridMapReference[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; +}; +#endif diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp new file mode 100644 index 00000000000..de3d0ebbaff --- /dev/null +++ b/src/server/game/Maps/MapManager.cpp @@ -0,0 +1,395 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MapManager.h" +#include "InstanceSaveMgr.h" +#include "Policies/SingletonImp.h" +#include "Database/DatabaseEnv.h" +#include "Log.h" +#include "ObjectAccessor.h" +#include "Transports.h" +#include "GridDefines.h" +#include "MapInstanced.h" +#include "InstanceData.h" +#include "DestinationHolderImp.h" +#include "Config/ConfigEnv.h" +#include "World.h" +#include "CellImpl.h" +#include "Corpse.h" +#include "ObjectMgr.h" +#include "Language.h" +#include "WorldPacket.h" + +#define CLASS_LOCK Trinity::ClassLevelLockable +INSTANTIATE_SINGLETON_2(MapManager, CLASS_LOCK); +INSTANTIATE_CLASS_MUTEX(MapManager, ACE_Thread_Mutex); + +extern GridState* si_GridStates[]; // debugging code, should be deleted some day + +MapManager::MapManager() +{ + i_gridCleanUpDelay = sWorld.getConfig(CONFIG_INTERVAL_GRIDCLEAN); + i_timer.SetInterval(sWorld.getConfig(CONFIG_INTERVAL_MAPUPDATE)); +} + +MapManager::~MapManager() +{ + for (MapMapType::iterator iter=i_maps.begin(); iter != i_maps.end(); ++iter) + delete iter->second; + + for (TransportSet::iterator i = m_Transports.begin(); i != m_Transports.end(); ++i) + delete *i; + + Map::DeleteStateMachine(); +} + +void MapManager::Initialize() +{ + Map::InitStateMachine(); + + // debugging code, should be deleted some day + { + for (uint8 i = 0; i < MAX_GRID_STATE; ++i) + i_GridStates[i] = si_GridStates[i]; + + i_GridStateErrorCount = 0; + } + int num_threads(sWorld.getConfig(CONFIG_NUMTHREADS)); + // Start mtmaps if needed. + if (num_threads > 0 && m_updater.activate(num_threads) == -1) + abort(); + + InitMaxInstanceId(); +} + +void MapManager::InitializeVisibilityDistanceInfo() +{ + for (MapMapType::iterator iter=i_maps.begin(); iter != i_maps.end(); ++iter) + (*iter).second->InitVisibilityDistance(); +} + +// debugging code, should be deleted some day +void MapManager::checkAndCorrectGridStatesArray() +{ + bool ok = true; + for (int i=0; icheckMagic()) + { + ok = false; + si_GridStates[i]->setMagic(); + } + #endif + } + if (!ok) + ++i_GridStateErrorCount; +} + +Map* MapManager::_createBaseMap(uint32 id) +{ + Map *m = _findMap(id); + + if (m == NULL) + { + Guard guard(*this); + + const MapEntry* entry = sMapStore.LookupEntry(id); + if (entry && entry->Instanceable()) + { + m = new MapInstanced(id, i_gridCleanUpDelay); + } + else + { + m = new Map(id, i_gridCleanUpDelay, 0, REGULAR_DIFFICULTY); + } + i_maps[id] = m; + } + + assert(m != NULL); + return m; +} + +Map* MapManager::CreateMap(uint32 id, const WorldObject* obj, uint32 /*instanceId*/) +{ + ASSERT(obj); + //if (!obj->IsInWorld()) sLog.outError("GetMap: called for map %d with object (typeid %d, guid %d, mapid %d, instanceid %d) who is not in world!", id, obj->GetTypeId(), obj->GetGUIDLow(), obj->GetMapId(), obj->GetInstanceId()); + Map *m = _createBaseMap(id); + + if (m && (obj->GetTypeId() == TYPEID_PLAYER) && m->Instanceable()) m = ((MapInstanced*)m)->CreateInstance(id, (Player*)obj); + + return m; +} + +Map* MapManager::FindMap(uint32 mapid, uint32 instanceId) const +{ + Map *map = _findMap(mapid); + if (!map) + return NULL; + + if (!map->Instanceable()) + return instanceId == 0 ? map : NULL; + + return ((MapInstanced*)map)->FindMap(instanceId); +} + +bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck) +{ + const MapEntry *entry = sMapStore.LookupEntry(mapid); + if (!entry) + return false; + + if (!entry->IsDungeon()) + return true; + + const char *mapName = entry->name[player->GetSession()->GetSessionDbcLocale()]; + + Group* pGroup = player->GetGroup(); + if (entry->IsRaid()) + { + // can only enter in a raid group + // GMs can avoid raid limitations + if ((!pGroup || !pGroup->isRaidGroup()) && !player->isGameMaster() && !sWorld.getConfig(CONFIG_INSTANCE_IGNORE_RAID)) + { + // probably there must be special opcode, because client has this string constant in GlobalStrings.lua + // TODO: this is not a good place to send the message + player->GetSession()->SendAreaTriggerMessage(player->GetSession()->GetTrinityString(LANG_INSTANCE_RAID_GROUP_ONLY), mapName); + sLog.outDebug("MAP: Player '%s' must be in a raid group to enter instance '%s'", player->GetName(), mapName); + return false; + } + } + + //The player has a heroic mode and tries to enter into instance which has no a heroic mode + MapDifficulty const* mapDiff = GetMapDifficultyData(entry->MapID,player->GetDifficulty(entry->IsRaid())); + if (!mapDiff) + { + bool isNormalTargetMap = entry->IsRaid() + ? (player->GetRaidDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + : (player->GetDungeonDifficulty() == DUNGEON_DIFFICULTY_NORMAL); + + // Send aborted message + // FIX ME: what about absent normal/heroic mode with specific players limit... + player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY, isNormalTargetMap ? DUNGEON_DIFFICULTY_NORMAL : DUNGEON_DIFFICULTY_HEROIC); + return false; + } + + if (!player->isAlive()) + { + if (Corpse *corpse = player->GetCorpse()) + { + // let enter in ghost mode in instance that connected to inner instance with corpse + uint32 instance_map = corpse->GetMapId(); + do + { + if (instance_map == mapid) + break; + + InstanceTemplate const* instance = objmgr.GetInstanceTemplate(instance_map); + instance_map = instance ? instance->parent : 0; + } + while (instance_map); + + if (!instance_map) + { + WorldPacket data(SMSG_CORPSE_NOT_IN_INSTANCE); + player->GetSession()->SendPacket(&data); + sLog.outDebug("MAP: Player '%s' does not have a corpse in instance '%s' and cannot enter.", player->GetName(), mapName); + return false; + } + sLog.outDebug("MAP: Player '%s' has corpse in instance '%s' and can enter.", player->GetName(), mapName); + } + else + sLog.outDebug("Map::CanPlayerEnter - player '%s' is dead but does not have a corpse!", player->GetName()); + } + + InstanceTemplate const* instance = objmgr.GetInstanceTemplate(mapid); + if (!instance) + return false; + + //Get instance where player's group is bound & its map + if (pGroup) + { + InstanceGroupBind* boundedInstance = pGroup->GetBoundInstance(player); + if (boundedInstance && boundedInstance->save) + { + if (Map *boundedMap = MapManager::Instance().FindMap(mapid,boundedInstance->save->GetInstanceId())) + { + // Player permanently bounded to different instance than groups one + InstancePlayerBind* playerBoundedInstance = player->GetBoundInstance(mapid, player->GetDungeonDifficulty()); + if (playerBoundedInstance && playerBoundedInstance->perm && playerBoundedInstance->save && + boundedInstance->save->GetInstanceId() != playerBoundedInstance->save->GetInstanceId()) + { + //TODO: send some kind of error message to the player + return false; + } + + // Encounters in progress + if (!loginCheck && entry->IsRaid() && ((InstanceMap*)boundedMap)->GetInstanceData() && ((InstanceMap*)boundedMap)->GetInstanceData()->IsEncounterInProgress()) + { + sLog.outDebug("MAP: Player '%s' cannot enter instance '%s' while an encounter is in progress.", player->GetName(), mapName); + player->SendTransferAborted(mapid, TRANSFER_ABORT_ZONE_IN_COMBAT); + return false; + } + + // Instance is full + MapDifficulty const* mapDiff = ((InstanceMap*)boundedMap)->GetMapDifficulty(); + int8 maxPlayers = mapDiff ? mapDiff->maxPlayers : 0; + if (maxPlayers != -1) //-1: unlimited access + { + if (boundedMap->GetPlayersCountExceptGMs() >= (loginCheck ? maxPlayers+1 : maxPlayers)) + { + sLog.outDebug("MAP: Player '%s' cannot enter instance '%s' because it is full.", player->GetName(), mapName); + player->SendTransferAborted(mapid, TRANSFER_ABORT_MAX_PLAYERS); + return false; + } + } + } + } + } + + //Other requirements + return player->Satisfy(objmgr.GetAccessRequirement(instance->access_id), mapid, true); +} + +void MapManager::RemoveBonesFromMap(uint32 mapid, uint64 guid, float x, float y) +{ + bool remove_result = _createBaseMap(mapid)->RemoveBones(guid, x, y); + + if (!remove_result) + { + sLog.outDebug("Bones %u not found in world. Delete from DB also.", GUID_LOPART(guid)); + } +} + +void MapManager::Update(uint32 diff) +{ + i_timer.Update(diff); + if (!i_timer.Passed()) + return; + + MapMapType::iterator iter = i_maps.begin(); + for (; iter != i_maps.end(); ++iter) + { + if (m_updater.activated()) + m_updater.schedule_update(*iter->second, i_timer.GetCurrent()); + else + { + iter->second->Update(i_timer.GetCurrent()); + } + } + if (m_updater.activated()) + m_updater.wait(); + + for (iter = i_maps.begin(); iter != i_maps.end(); ++iter) + iter->second->DelayedUpdate(i_timer.GetCurrent()); + + ObjectAccessor::Instance().Update(i_timer.GetCurrent()); + for (TransportSet::iterator iter = m_Transports.begin(); iter != m_Transports.end(); ++iter) + (*iter)->Update(i_timer.GetCurrent()); + + i_timer.SetCurrent(0); +} + +void MapManager::DoDelayedMovesAndRemoves() +{ +} + +bool MapManager::ExistMapAndVMap(uint32 mapid, float x,float y) +{ + GridPair p = Trinity::ComputeGridPair(x,y); + + int gx=63-p.x_coord; + int gy=63-p.y_coord; + + return Map::ExistMap(mapid,gx,gy) && Map::ExistVMap(mapid,gx,gy); +} + +bool MapManager::IsValidMAP(uint32 mapid) +{ + MapEntry const* mEntry = sMapStore.LookupEntry(mapid); + return mEntry && (!mEntry->IsDungeon() || objmgr.GetInstanceTemplate(mapid)); + // TODO: add check for battleground template +} + +void MapManager::UnloadAll() +{ + for (MapMapType::iterator iter=i_maps.begin(); iter != i_maps.end(); ++iter) + iter->second->UnloadAll(); + + while (!i_maps.empty()) + { + delete i_maps.begin()->second; + i_maps.erase(i_maps.begin()); + } + + if (m_updater.activated()) + m_updater.deactivate(); +} + +void MapManager::InitMaxInstanceId() +{ + i_MaxInstanceId = 0; + + QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT MAX(id) FROM instance"); + if (result) + i_MaxInstanceId = result->Fetch()[0].GetUInt32(); +} + +uint32 MapManager::GetNumInstances() +{ + Guard guard(*this); + + uint32 ret = 0; + for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) + { + Map *map = itr->second; + if (!map->Instanceable()) + continue; + MapInstanced::InstancedMaps &maps = ((MapInstanced *)map)->GetInstancedMaps(); + for (MapInstanced::InstancedMaps::iterator mitr = maps.begin(); mitr != maps.end(); ++mitr) + if (mitr->second->IsDungeon()) ret++; + } + return ret; +} + +uint32 MapManager::GetNumPlayersInInstances() +{ + Guard guard(*this); + + uint32 ret = 0; + for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) + { + Map *map = itr->second; + if (!map->Instanceable()) + continue; + MapInstanced::InstancedMaps &maps = ((MapInstanced *)map)->GetInstancedMaps(); + for (MapInstanced::InstancedMaps::iterator mitr = maps.begin(); mitr != maps.end(); ++mitr) + if (mitr->second->IsDungeon()) + ret += ((InstanceMap*)mitr->second)->GetPlayers().getSize(); + } + return ret; +} diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h new file mode 100644 index 00000000000..d94f9fced0e --- /dev/null +++ b/src/server/game/Maps/MapManager.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_MAPMANAGER_H +#define TRINITY_MAPMANAGER_H + +#include "Platform/Define.h" +#include "Policies/Singleton.h" +#include "ace/Thread_Mutex.h" +#include "Common.h" +#include "Map.h" +#include "GridStates.h" +#include "MapUpdater.h" + +class Transport; + +class MapManager : public Trinity::Singleton > +{ + + friend class Trinity::OperatorNew; + typedef UNORDERED_MAP MapMapType; + typedef std::pair::iterator, bool> MapMapPair; + + public: + + Map* CreateMap(uint32, const WorldObject* obj, uint32 instanceId); + Map const* CreateBaseMap(uint32 id) const { return const_cast(this)->_createBaseMap(id); } + Map* FindMap(uint32 mapid, uint32 instanceId = 0) const; + + uint16 GetAreaFlag(uint32 mapid, float x, float y, float z) const + { + Map const* m = CreateBaseMap(mapid); + return m->GetAreaFlag(x, y, z); + } + uint32 GetAreaId(uint32 mapid, float x, float y, float z) const + { + return Map::GetAreaIdByAreaFlag(GetAreaFlag(mapid, x, y, z),mapid); + } + uint32 GetZoneId(uint32 mapid, float x, float y, float z) const + { + return Map::GetZoneIdByAreaFlag(GetAreaFlag(mapid, x, y, z),mapid); + } + void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z) + { + Map::GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(mapid, x, y, z),mapid); + } + + void Initialize(void); + void Update(uint32); + + void SetGridCleanUpDelay(uint32 t) + { + if (t < MIN_GRID_DELAY) + i_gridCleanUpDelay = MIN_GRID_DELAY; + else + i_gridCleanUpDelay = t; + } + + void SetMapUpdateInterval(uint32 t) + { + if (t > MIN_MAP_UPDATE_DELAY) + t = MIN_MAP_UPDATE_DELAY; + + i_timer.SetInterval(t); + i_timer.Reset(); + } + + //void LoadGrid(int mapid, int instId, float x, float y, const WorldObject* obj, bool no_unload = false); + void UnloadAll(); + + static bool ExistMapAndVMap(uint32 mapid, float x, float y); + static bool IsValidMAP(uint32 mapid); + + static bool IsValidMapCoord(uint32 mapid, float x,float y) + { + return IsValidMAP(mapid) && Trinity::IsValidMapCoord(x,y); + } + + static bool IsValidMapCoord(uint32 mapid, float x,float y,float z) + { + return IsValidMAP(mapid) && Trinity::IsValidMapCoord(x,y,z); + } + + static bool IsValidMapCoord(uint32 mapid, float x,float y,float z,float o) + { + return IsValidMAP(mapid) && Trinity::IsValidMapCoord(x,y,z,o); + } + + static bool IsValidMapCoord(WorldLocation const& loc) + { + return IsValidMapCoord(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), loc.GetOrientation()); + } + + void DoDelayedMovesAndRemoves(); + + void LoadTransports(); + + typedef std::set TransportSet; + TransportSet m_Transports; + + typedef std::map TransportMap; + TransportMap m_TransportsByMap; + + bool CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck = false); + void RemoveBonesFromMap(uint32 mapid, uint64 guid, float x, float y); + uint32 GenerateInstanceId() { return ++i_MaxInstanceId; } + void InitMaxInstanceId(); + void InitializeVisibilityDistanceInfo(); + + /* statistics */ + uint32 GetNumInstances(); + uint32 GetNumPlayersInInstances(); + + private: + // debugging code, should be deleted some day + void checkAndCorrectGridStatesArray(); // just for debugging to find some memory overwrites + GridState* i_GridStates[MAX_GRID_STATE]; // shadow entries to the global array in Map.cpp + int i_GridStateErrorCount; + private: + MapManager(); + ~MapManager(); + + MapManager(const MapManager &); + MapManager& operator=(const MapManager &); + + Map* _createBaseMap(uint32 id); + Map* _findMap(uint32 id) const + { + MapMapType::const_iterator iter = i_maps.find(id); + return (iter == i_maps.end() ? NULL : iter->second); + } + + typedef Trinity::ClassLevelLockable::Lock Guard; + uint32 i_gridCleanUpDelay; + MapMapType i_maps; + IntervalTimer i_timer; + + uint32 i_MaxInstanceId; + MapUpdater m_updater; +}; +#endif diff --git a/src/server/game/Maps/MapRefManager.h b/src/server/game/Maps/MapRefManager.h new file mode 100644 index 00000000000..4337aa75fd9 --- /dev/null +++ b/src/server/game/Maps/MapRefManager.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _MAPREFMANAGER +#define _MAPREFMANAGER + +#include "Utilities/LinkedReference/RefManager.h" + +class MapReference; + +class MapRefManager : public RefManager +{ + public: + typedef LinkedListHead::Iterator< MapReference > iterator; + typedef LinkedListHead::Iterator< MapReference const > const_iterator; + + MapReference* getFirst() { return (MapReference*)RefManager::getFirst(); } + MapReference const* getFirst() const { return (MapReference const*)RefManager::getFirst(); } + MapReference* getLast() { return (MapReference*)RefManager::getLast(); } + MapReference const* getLast() const { return (MapReference const*)RefManager::getLast(); } + + iterator begin() { return iterator(getFirst()); } + iterator end() { return iterator(NULL); } + iterator rbegin() { return iterator(getLast()); } + iterator rend() { return iterator(NULL); } + const_iterator begin() const { return const_iterator(getFirst()); } + const_iterator end() const { return const_iterator(NULL); } +}; +#endif + diff --git a/src/server/game/Maps/MapReference.h b/src/server/game/Maps/MapReference.h new file mode 100644 index 00000000000..7cd4fcde76c --- /dev/null +++ b/src/server/game/Maps/MapReference.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _MAPREFERENCE_H +#define _MAPREFERENCE_H + +#include "Utilities/LinkedReference/Reference.h" +#include "Map.h" + +class MapReference : public Reference +{ + protected: + void targetObjectBuildLink() + { + // called from link() + getTarget()->m_mapRefManager.insertFirst(this); + getTarget()->m_mapRefManager.incSize(); + } + void targetObjectDestroyLink() + { + // called from unlink() + if (isValid()) getTarget()->m_mapRefManager.decSize(); + } + void sourceObjectDestroyLink() + { + // called from invalidate() + getTarget()->m_mapRefManager.decSize(); + } + public: + MapReference() : Reference() {} + ~MapReference() { unlink(); } + MapReference *next() { return (MapReference*)Reference::next(); } + MapReference const *next() const { return (MapReference const*)Reference::next(); } + MapReference *nockeck_prev() { return (MapReference*)Reference::nocheck_prev(); } + MapReference const *nocheck_prev() const { return (MapReference const*)Reference::nocheck_prev(); } +}; +#endif + diff --git a/src/server/game/Maps/MapUpdater.cpp b/src/server/game/Maps/MapUpdater.cpp new file mode 100644 index 00000000000..f9bb5e2bbbc --- /dev/null +++ b/src/server/game/Maps/MapUpdater.cpp @@ -0,0 +1,129 @@ +#include "MapUpdater.h" +#include "DelayExecutor.h" +#include "Map.h" +#include "Database/DatabaseEnv.h" + +#include +#include + +class WDBThreadStartReq1 : public ACE_Method_Request +{ + public: + + WDBThreadStartReq1() + { + } + + virtual int call() + { + WorldDatabase.ThreadStart(); + return 0; + } +}; + +class WDBThreadEndReq1 : public ACE_Method_Request +{ + public: + + WDBThreadEndReq1() + { + } + + virtual int call() + { + WorldDatabase.ThreadEnd(); + return 0; + } +}; + +class MapUpdateRequest : public ACE_Method_Request +{ + private: + + Map& m_map; + MapUpdater& m_updater; + ACE_UINT32 m_diff; + + public: + + MapUpdateRequest(Map& m, MapUpdater& u, ACE_UINT32 d) + : m_map(m), m_updater(u), m_diff(d) + { + } + + virtual int call() + { + m_map.Update (m_diff); + m_updater.update_finished (); + return 0; + } +}; + +MapUpdater::MapUpdater() + : m_mutex(), m_condition(m_mutex), m_executor(), pending_requests(0) +{ +} + +MapUpdater::~MapUpdater() +{ + deactivate(); +} + +int MapUpdater::activate(size_t num_threads) +{ + return m_executor.activate((int)num_threads, new WDBThreadStartReq1, new WDBThreadEndReq1); +} + +int MapUpdater::deactivate() +{ + wait(); + + return m_executor.deactivate(); +} + +int MapUpdater::wait() +{ + ACE_GUARD_RETURN(ACE_Thread_Mutex, guard, m_mutex, -1); + + while (pending_requests > 0) + m_condition.wait(); + + return 0; +} + +int MapUpdater::schedule_update(Map& map, ACE_UINT32 diff) +{ + ACE_GUARD_RETURN(ACE_Thread_Mutex, guard, m_mutex, -1); + + ++pending_requests; + + if (m_executor.execute(new MapUpdateRequest(map, *this, diff)) == -1) + { + ACE_DEBUG((LM_ERROR, ACE_TEXT("(%t) \n"), ACE_TEXT("Failed to schedule Map Update"))); + + --pending_requests; + return -1; + } + + return 0; +} + +bool MapUpdater::activated() +{ + return m_executor.activated(); +} + +void MapUpdater::update_finished() +{ + ACE_GUARD(ACE_Thread_Mutex, guard, m_mutex); + + if (pending_requests == 0) + { + ACE_ERROR((LM_ERROR, ACE_TEXT("(%t)\n"), ACE_TEXT("MapUpdater::update_finished BUG, report to devs"))); + return; + } + + --pending_requests; + + m_condition.broadcast(); +} diff --git a/src/server/game/Maps/MapUpdater.h b/src/server/game/Maps/MapUpdater.h new file mode 100644 index 00000000000..f301b15ca2f --- /dev/null +++ b/src/server/game/Maps/MapUpdater.h @@ -0,0 +1,40 @@ +#ifndef _MAP_UPDATER_H_INCLUDED +#define _MAP_UPDATER_H_INCLUDED + +#include +#include + +#include "DelayExecutor.h" + +class Map; + +class MapUpdater +{ + public: + + MapUpdater(); + virtual ~MapUpdater(); + + friend class MapUpdateRequest; + + int schedule_update(Map& map, ACE_UINT32 diff); + + int wait(); + + int activate(size_t num_threads); + + int deactivate(); + + bool activated(); + + private: + + DelayExecutor m_executor; + ACE_Condition_Thread_Mutex m_condition; + ACE_Thread_Mutex m_mutex; + size_t pending_requests; + + void update_finished(); +}; + +#endif //_MAP_UPDATER_H_INCLUDED diff --git a/src/server/game/Maps/ZoneScript.h b/src/server/game/Maps/ZoneScript.h new file mode 100644 index 00000000000..ab74c8aa5d4 --- /dev/null +++ b/src/server/game/Maps/ZoneScript.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ZONE_SCRIPT_H_ +#define ZONE_SCRIPT_H_ + +#include "Common.h" +#include "Creature.h" + +//struct CreatureData; +class Creature; +class GameObject; + +class ZoneScript +{ + public: + explicit ZoneScript() {} + + virtual uint32 GetCreatureEntry(uint32 /*guidlow*/, const CreatureData *data) { return data->id; } + virtual uint32 GetGameObjectEntry(uint32 /*guidlow*/, uint32 entry) { return entry; } + + virtual void OnCreatureCreate(Creature *, bool /*add*/) {} + virtual void OnGameObjectCreate(GameObject * /*go*/, bool /*add*/) {} + + //All-purpose data storage 64 bit + virtual uint64 GetData64(uint32 /*DataId*/) { return 0; } + virtual void SetData64(uint32 /*DataId*/, uint64 /*Value*/) {} + + //All-purpose data storage 32 bit + virtual uint32 GetData(uint32 /*DataId*/) { return 0; } + virtual void SetData(uint32 /*DataId*/, uint32 /*Value*/) {} + + virtual void ProcessEvent(GameObject * /*obj*/, uint32 /*eventId*/) {} +}; + +#endif \ No newline at end of file diff --git a/src/server/game/Miscellaneous/Formulas.h b/src/server/game/Miscellaneous/Formulas.h new file mode 100644 index 00000000000..e5961834a78 --- /dev/null +++ b/src/server/game/Miscellaneous/Formulas.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_FORMULAS_H +#define TRINITY_FORMULAS_H + +#include "World.h" + +namespace Trinity +{ + namespace Honor + { + inline uint32 hk_honor_at_level(uint8 level, uint32 count = 1) + { + return uint32(ceil(count * (33.333f * ((float)level) / 21.50537f))); + } + } + namespace XP + { + enum XPColorChar { RED, ORANGE, YELLOW, GREEN, GRAY }; + + inline uint8 GetGrayLevel(uint8 pl_level) + { + if (pl_level <= 5) + return 0; + else if (pl_level <= 39) + return pl_level - 5 - pl_level/10; + else if (pl_level <= 59) + return pl_level - 1 - pl_level/5; + else + return pl_level - 9; + } + + inline XPColorChar GetColorCode(uint8 pl_level, uint8 mob_level) + { + if (mob_level >= pl_level + 5) + return RED; + else if (mob_level >= pl_level + 3) + return ORANGE; + else if (mob_level >= pl_level - 2) + return YELLOW; + else if (mob_level > GetGrayLevel(pl_level)) + return GREEN; + else + return GRAY; + } + + inline uint8 GetZeroDifference(uint8 pl_level) + { + if (pl_level < 8) return 5; + if (pl_level < 10) return 6; + if (pl_level < 12) return 7; + if (pl_level < 16) return 8; + if (pl_level < 20) return 9; + if (pl_level < 30) return 11; + if (pl_level < 40) return 12; + if (pl_level < 45) return 13; + if (pl_level < 50) return 14; + if (pl_level < 55) return 15; + if (pl_level < 60) return 16; + return 17; + } + + inline uint32 BaseGain(uint8 pl_level, uint8 mob_level, ContentLevels content) + { + uint32 nBaseExp; + switch (content) + { + case CONTENT_1_60: nBaseExp = 45; break; + case CONTENT_61_70: nBaseExp = 235; break; + case CONTENT_71_80: nBaseExp = 580; break; + default: + sLog.outError("BaseGain: Unsupported content level %u",content); + nBaseExp = 45; break; + } + + if (mob_level >= pl_level) + { + uint8 nLevelDiff = mob_level - pl_level; + if (nLevelDiff > 4) + nLevelDiff = 4; + return ((pl_level*5 + nBaseExp) * (20 + nLevelDiff)/10 + 1)/2; + } + else + { + uint8 gray_level = GetGrayLevel(pl_level); + if (mob_level > gray_level) + { + uint8 ZD = GetZeroDifference(pl_level); + return (pl_level*5 + nBaseExp) * (ZD + mob_level - pl_level)/ZD; + } + return 0; + } + } + + inline uint32 Gain(Player *pl, Unit *u) + { + if (u->GetTypeId() == TYPEID_UNIT && ( + ((Creature*)u)->isTotem() || ((Creature*)u)->isPet() || + (((Creature*)u)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL))) + return 0; + + uint32 xp_gain = BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(u->GetMapId(),u->GetZoneId())); + if (xp_gain == 0) + return 0; + + //elites in instances have a 2.75x xp bonus instead of the regular 2x world bonus + if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->isElite()) + { + if(u->GetMap() && u->GetMap()->IsDungeon()) + xp_gain *= 2.75; + else + xp_gain *= 2; + } + + return uint32(xp_gain*sWorld.getRate(RATE_XP_KILL)); + } + + inline float xp_in_group_rate(uint32 count, bool isRaid) + { + if (isRaid) + { + // FIX ME: must apply decrease modifiers dependent from raid size + return 1.0f; + } + else + { + switch (count) + { + case 0: + case 1: + case 2: + return 1.0f; + case 3: + return 1.166f; + case 4: + return 1.3f; + case 5: + default: + return 1.4f; + } + } + } + } +} +#endif + diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h new file mode 100644 index 00000000000..c0c8fc486f3 --- /dev/null +++ b/src/server/game/Miscellaneous/Language.h @@ -0,0 +1,1007 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __TRINITY_LANGUAGE_H +#define __TRINITY_LANGUAGE_H + +enum TrinityStrings +{ + // for chat commands + LANG_SELECT_CHAR_OR_CREATURE = 1, + LANG_SELECT_CREATURE = 2, + + // level 0 chat + LANG_SYSTEMMESSAGE = 3, + LANG_EVENTMESSAGE = 4, + LANG_NO_HELP_CMD = 5, + LANG_NO_CMD = 6, + LANG_NO_SUBCMD = 7, + LANG_SUBCMDS_LIST = 8, + LANG_AVIABLE_CMD = 9, + LANG_CMD_SYNTAX = 10, + LANG_ACCOUNT_LEVEL = 11, + LANG_CONNECTED_USERS = 12, + LANG_UPTIME = 13, + LANG_PLAYER_SAVED = 14, + LANG_PLAYERS_SAVED = 15, + LANG_GMS_ON_SRV = 16, + LANG_GMS_NOT_LOGGED = 17, + LANG_YOU_IN_FLIGHT = 18, + //LANG_YOU_IN_BATTLEGROUND = 19, not used + //LANG_TARGET_IN_FLIGHT = 20, not used + LANG_CHAR_IN_FLIGHT = 21, + LANG_CHAR_NON_MOUNTED = 22, + LANG_YOU_IN_COMBAT = 23, + LANG_YOU_USED_IT_RECENTLY = 24, + LANG_COMMAND_NOTCHANGEPASSWORD = 25, + LANG_COMMAND_PASSWORD = 26, + LANG_COMMAND_WRONGOLDPASSWORD = 27, + LANG_COMMAND_ACCLOCKLOCKED = 28, + LANG_COMMAND_ACCLOCKUNLOCKED = 29, + LANG_SPELL_RANK = 30, + LANG_KNOWN = 31, + LANG_LEARN = 32, + LANG_PASSIVE = 33, + LANG_TALENT = 34, + LANG_ACTIVE = 35, + LANG_COMPLETE = 36, + LANG_OFFLINE = 37, + LANG_ON = 38, + LANG_OFF = 39, + LANG_YOU_ARE = 40, + LANG_VISIBLE = 41, + LANG_INVISIBLE = 42, + LANG_DONE = 43, + LANG_YOU = 44, + LANG_UNKNOWN = 45, + LANG_ERROR = 46, + LANG_NON_EXIST_CHARACTER = 47, + LANG_FRIEND_IGNORE_UNKNOWN = 48, + LANG_LEVEL_MINREQUIRED = 49, + LANG_LEVEL_MINREQUIRED_AND_ITEM = 50, + LANG_NPC_TAINER_HELLO = 51, + LANG_COMMAND_INVALID_ITEM_COUNT = 52, + LANG_COMMAND_MAIL_ITEMS_LIMIT = 53, + LANG_NEW_PASSWORDS_NOT_MATCH = 54, + LANG_PASSWORD_TOO_LONG = 55, + LANG_MOTD_CURRENT = 56, + LANG_USING_WORLD_DB = 57, + LANG_USING_SCRIPT_LIB = 58, + LANG_USING_EVENT_AI = 59, + LANG_CONNECTED_PLAYERS = 60, + LANG_ACCOUNT_ADDON = 61, + // Room for more level 0 62-99 not used + + // level 1 chat + LANG_GLOBAL_NOTIFY = 100, + LANG_MAP_POSITION = 101, + LANG_IS_TELEPORTED = 102, + LANG_CANNOT_SUMMON_TO_INST = 103, + LANG_CANNOT_GO_TO_INST_PARTY = 104, + LANG_CANNOT_GO_TO_INST_GM = 105, + LANG_CANNOT_GO_INST_INST = 106, + LANG_CANNOT_SUMMON_INST_INST = 107, + LANG_SUMMONING = 108, + LANG_SUMMONED_BY = 109, + LANG_TELEPORTING_TO = 110, + LANG_TELEPORTED_TO_BY = 111, + LANG_NO_PLAYER = 112, + LANG_APPEARING_AT = 113, + LANG_APPEARING_TO = 114, + LANG_BAD_VALUE = 115, + LANG_NO_CHAR_SELECTED = 116, + LANG_NOT_IN_GROUP = 117, + + LANG_YOU_CHANGE_HP = 118, + LANG_YOURS_HP_CHANGED = 119, + LANG_YOU_CHANGE_MANA = 120, + LANG_YOURS_MANA_CHANGED = 121, + LANG_YOU_CHANGE_ENERGY = 122, + LANG_YOURS_ENERGY_CHANGED = 123, + + LANG_CURRENT_ENERGY = 124, //log + LANG_YOU_CHANGE_RAGE = 125, + LANG_YOURS_RAGE_CHANGED = 126, + LANG_YOU_CHANGE_LVL = 127, + LANG_CURRENT_FACTION = 128, + LANG_WRONG_FACTION = 129, + LANG_YOU_CHANGE_FACTION = 130, + LANG_YOU_CHANGE_SPELLFLATID = 131, + LANG_YOURS_SPELLFLATID_CHANGED = 132, + LANG_YOU_GIVE_TAXIS = 133, + LANG_YOU_REMOVE_TAXIS = 134, + LANG_YOURS_TAXIS_ADDED = 135, + LANG_YOURS_TAXIS_REMOVED = 136, + + LANG_YOU_CHANGE_ASPEED = 137, + LANG_YOURS_ASPEED_CHANGED = 138, + LANG_YOU_CHANGE_SPEED = 139, + LANG_YOURS_SPEED_CHANGED = 140, + LANG_YOU_CHANGE_SWIM_SPEED = 141, + LANG_YOURS_SWIM_SPEED_CHANGED = 142, + LANG_YOU_CHANGE_BACK_SPEED = 143, + LANG_YOURS_BACK_SPEED_CHANGED = 144, + LANG_YOU_CHANGE_FLY_SPEED = 145, + LANG_YOURS_FLY_SPEED_CHANGED = 146, + + LANG_YOU_CHANGE_SIZE = 147, + LANG_YOURS_SIZE_CHANGED = 148, + LANG_NO_MOUNT = 149, + LANG_YOU_GIVE_MOUNT = 150, + LANG_MOUNT_GIVED = 151, + + LANG_CURRENT_MONEY = 152, + LANG_YOU_TAKE_ALL_MONEY = 153, + LANG_YOURS_ALL_MONEY_GONE = 154, + LANG_YOU_TAKE_MONEY = 155, + LANG_YOURS_MONEY_TAKEN = 156, + LANG_YOU_GIVE_MONEY = 157, + LANG_YOURS_MONEY_GIVEN = 158, + LANG_YOU_HEAR_SOUND = 159, + + LANG_NEW_MONEY = 160, // Log + + LANG_REMOVE_BIT = 161, + LANG_SET_BIT = 162, + LANG_COMMAND_TELE_TABLEEMPTY = 163, + LANG_COMMAND_TELE_NOTFOUND = 164, + LANG_COMMAND_TELE_PARAMETER = 165, + LANG_COMMAND_TELE_NOLOCATION = 166, + // 167 // not used + LANG_COMMAND_TELE_LOCATION = 168, + + LANG_MAIL_SENT = 169, + LANG_SOUND_NOT_EXIST = 170, + LANG_CANT_TELEPORT_SELF = 171, + LANG_CONSOLE_COMMAND = 172, + LANG_YOU_CHANGE_RUNIC_POWER = 173, + LANG_YOURS_RUNIC_POWER_CHANGED = 174, + LANG_LIQUID_STATUS = 175, + // Room for more level 1 176-199 not used + + // level 2 chat + LANG_NO_SELECTION = 200, + LANG_OBJECT_GUID = 201, + LANG_TOO_LONG_NAME = 202, + LANG_CHARS_ONLY = 203, + LANG_TOO_LONG_SUBNAME = 204, + LANG_NOT_IMPLEMENTED = 205, + + LANG_ITEM_ADDED_TO_LIST = 206, + LANG_ITEM_NOT_FOUND = 207, + LANG_ITEM_DELETED_FROM_LIST = 208, + LANG_ITEM_NOT_IN_LIST = 209, + LANG_ITEM_ALREADY_IN_LIST = 210, + + LANG_RESET_SPELLS_ONLINE = 211, + LANG_RESET_SPELLS_OFFLINE = 212, + LANG_RESET_TALENTS_ONLINE = 213, + LANG_RESET_TALENTS_OFFLINE = 214, + LANG_RESET_SPELLS = 215, + LANG_RESET_TALENTS = 216, + + LANG_RESETALL_UNKNOWN_CASE = 217, + LANG_RESETALL_SPELLS = 218, + LANG_RESETALL_TALENTS = 219, + + LANG_WAYPOINT_NOTFOUND = 220, + LANG_WAYPOINT_NOTFOUNDLAST = 221, + LANG_WAYPOINT_NOTFOUNDSEARCH = 222, + LANG_WAYPOINT_NOTFOUNDDBPROBLEM = 223, + LANG_WAYPOINT_CREATSELECTED = 224, + LANG_WAYPOINT_CREATNOTFOUND = 225, + LANG_WAYPOINT_VP_SELECT = 226, + LANG_WAYPOINT_VP_NOTFOUND = 227, + LANG_WAYPOINT_VP_NOTCREATED = 228, + LANG_WAYPOINT_VP_ALLREMOVED = 229, + LANG_WAYPOINT_NOTCREATED = 230, + LANG_WAYPOINT_NOGUID = 231, + LANG_WAYPOINT_NOWAYPOINTGIVEN = 232, + LANG_WAYPOINT_ARGUMENTREQ = 233, + LANG_WAYPOINT_ADDED = 234, + LANG_WAYPOINT_ADDED_NO = 235, + LANG_WAYPOINT_CHANGED = 236, + LANG_WAYPOINT_CHANGED_NO = 237, + LANG_WAYPOINT_EXPORTED = 238, + LANG_WAYPOINT_NOTHINGTOEXPORT = 239, + LANG_WAYPOINT_IMPORTED = 240, + LANG_WAYPOINT_REMOVED = 241, + LANG_WAYPOINT_NOTREMOVED = 242, + LANG_WAYPOINT_TOOFAR1 = 243, + LANG_WAYPOINT_TOOFAR2 = 244, + LANG_WAYPOINT_TOOFAR3 = 245, + LANG_WAYPOINT_INFO_TITLE = 246, + LANG_WAYPOINT_INFO_WAITTIME = 247, + LANG_WAYPOINT_INFO_MODEL = 248, + LANG_WAYPOINT_INFO_EMOTE = 249, + LANG_WAYPOINT_INFO_SPELL = 250, + LANG_WAYPOINT_INFO_TEXT = 251, + LANG_WAYPOINT_INFO_AISCRIPT = 252, + + LANG_RENAME_PLAYER = 253, + LANG_RENAME_PLAYER_GUID = 254, + + LANG_WAYPOINT_WPCREATNOTFOUND = 255, + LANG_WAYPOINT_NPCNOTFOUND = 256, + + LANG_MOVE_TYPE_SET = 257, + LANG_MOVE_TYPE_SET_NODEL = 258, + LANG_USE_BOL = 259, + LANG_VALUE_SAVED = 260, + LANG_VALUE_SAVED_REJOIN = 261, + + LANG_COMMAND_GOAREATRNOTFOUND = 262, + LANG_INVALID_TARGET_COORD = 263, + LANG_INVALID_ZONE_COORD = 264, + LANG_INVALID_ZONE_MAP = 265, + LANG_COMMAND_TARGETOBJNOTFOUND = 266, + LANG_COMMAND_GOOBJNOTFOUND = 267, + LANG_COMMAND_GOCREATNOTFOUND = 268, + LANG_COMMAND_GOCREATMULTIPLE = 269, + LANG_COMMAND_DELCREATMESSAGE = 270, + LANG_COMMAND_CREATUREMOVED = 271, + LANG_COMMAND_CREATUREATSAMEMAP = 272, + LANG_COMMAND_OBJNOTFOUND = 273, + LANG_COMMAND_DELOBJREFERCREATURE = 274, + LANG_COMMAND_DELOBJMESSAGE = 275, + LANG_COMMAND_TURNOBJMESSAGE = 276, + LANG_COMMAND_MOVEOBJMESSAGE = 277, + LANG_COMMAND_VENDORSELECTION = 278, + LANG_COMMAND_NEEDITEMSEND = 279, + LANG_COMMAND_ADDVENDORITEMITEMS = 280, + LANG_COMMAND_KICKSELF = 281, + LANG_COMMAND_KICKMESSAGE = 282, + // 283, not used + LANG_COMMAND_WHISPERACCEPTING = 284, + LANG_COMMAND_WHISPERON = 285, + LANG_COMMAND_WHISPEROFF = 286, + LANG_COMMAND_CREATGUIDNOTFOUND = 287, + // TICKET STRINGS NEED REWRITE // 288-296 FREE + + // END + LANG_COMMAND_SPAWNDIST = 297, + LANG_COMMAND_SPAWNTIME = 298, + LANG_COMMAND_MODIFY_HONOR = 299, + + LANG_YOUR_CHAT_DISABLED = 300, + LANG_YOU_DISABLE_CHAT = 301, + LANG_CHAT_ALREADY_ENABLED = 302, + LANG_YOUR_CHAT_ENABLED = 303, + LANG_YOU_ENABLE_CHAT = 304, + + LANG_COMMAND_MODIFY_REP = 305, + LANG_COMMAND_MODIFY_ARENA = 306, + LANG_COMMAND_FACTION_NOTFOUND = 307, + LANG_COMMAND_FACTION_UNKNOWN = 308, + LANG_COMMAND_FACTION_INVPARAM = 309, + LANG_COMMAND_FACTION_DELTA = 310, + LANG_FACTION_LIST = 311, + LANG_FACTION_VISIBLE = 312, + LANG_FACTION_ATWAR = 313, + LANG_FACTION_PEACE_FORCED = 314, + LANG_FACTION_HIDDEN = 315, + LANG_FACTION_INVISIBLE_FORCED = 316, + LANG_FACTION_INACTIVE = 317, + LANG_REP_HATED = 318, + LANG_REP_HOSTILE = 319, + LANG_REP_UNFRIENDLY = 320, + LANG_REP_NEUTRAL = 321, + LANG_REP_FRIENDLY = 322, + LANG_REP_HONORED = 323, + LANG_REP_REVERED = 324, + LANG_REP_EXALTED = 325, + LANG_COMMAND_FACTION_NOREP_ERROR = 326, + LANG_FACTION_NOREPUTATION = 327, + LANG_LOOKUP_PLAYER_ACCOUNT = 328, + LANG_LOOKUP_PLAYER_CHARACTER = 329, + LANG_NO_PLAYERS_FOUND = 330, + LANG_EXTENDED_COST_NOT_EXIST = 331, + LANG_GM_ON = 332, + LANG_GM_OFF = 333, + LANG_GM_CHAT_ON = 334, + LANG_GM_CHAT_OFF = 335, + LANG_YOU_REPAIR_ITEMS = 336, + LANG_YOUR_ITEMS_REPAIRED = 337, + LANG_YOU_SET_WATERWALK = 338, + LANG_YOUR_WATERWALK_SET = 339, + LANG_CREATURE_FOLLOW_YOU_NOW = 340, + LANG_CREATURE_NOT_FOLLOW_YOU = 341, + LANG_CREATURE_NOT_FOLLOW_YOU_NOW = 342, + LANG_CREATURE_NON_TAMEABLE = 343, + LANG_YOU_ALREADY_HAVE_PET = 344, + LANG_CUSTOMIZE_PLAYER = 345, + LANG_CUSTOMIZE_PLAYER_GUID = 346, + LANG_COMMAND_GOTAXINODENOTFOUND = 347, + LANG_GAMEOBJECT_HAVE_INVALID_DATA = 348, + LANG_TITLE_LIST_CHAT = 349, + LANG_TITLE_LIST_CONSOLE = 350, + LANG_COMMAND_NOTITLEFOUND = 351, + LANG_INVALID_TITLE_ID = 352, + LANG_TITLE_ADD_RES = 353, + LANG_TITLE_REMOVE_RES = 354, + LANG_TITLE_CURRENT_RES = 355, + LANG_CURRENT_TITLE_RESET = 356, + // Room for more level 2 357-399 not used + + // level 3 chat + LANG_SCRIPTS_RELOADED = 400, + LANG_YOU_CHANGE_SECURITY = 401, + LANG_YOURS_SECURITY_CHANGED = 402, + LANG_YOURS_SECURITY_IS_LOW = 403, + LANG_CREATURE_MOVE_DISABLED = 404, + LANG_CREATURE_MOVE_ENABLED = 405, + LANG_NO_WEATHER = 406, + LANG_WEATHER_DISABLED = 407, + + LANG_BAN_YOUBANNED = 408, + LANG_BAN_YOUPERMBANNED = 409, + LANG_BAN_NOTFOUND = 410, + + LANG_UNBAN_UNBANNED = 411, + LANG_UNBAN_ERROR = 412, + + LANG_ACCOUNT_NOT_EXIST = 413, + + LANG_BANINFO_NOCHARACTER = 414, + LANG_BANINFO_NOIP = 415, + LANG_BANINFO_NOACCOUNTBAN = 416, + LANG_BANINFO_BANHISTORY = 417, + LANG_BANINFO_HISTORYENTRY = 418, + LANG_BANINFO_INFINITE = 419, + LANG_BANINFO_NEVER = 420, + LANG_BANINFO_YES = 421, + LANG_BANINFO_NO = 422, + LANG_BANINFO_IPENTRY = 423, + + LANG_BANLIST_NOIP = 424, + LANG_BANLIST_NOACCOUNT = 425, + LANG_BANLIST_NOCHARACTER = 426, + LANG_BANLIST_MATCHINGIP = 427, + LANG_BANLIST_MATCHINGACCOUNT = 428, + + LANG_COMMAND_LEARN_MANY_SPELLS = 429, + LANG_COMMAND_LEARN_CLASS_SPELLS = 430, + LANG_COMMAND_LEARN_CLASS_TALENTS = 431, + LANG_COMMAND_LEARN_ALL_LANG = 432, + LANG_COMMAND_LEARN_ALL_CRAFT = 433, + LANG_COMMAND_COULDNOTFIND = 434, + LANG_COMMAND_ITEMIDINVALID = 435, + LANG_COMMAND_NOITEMFOUND = 436, + LANG_COMMAND_LISTOBJINVALIDID = 437, + LANG_COMMAND_LISTITEMMESSAGE = 438, + LANG_COMMAND_LISTOBJMESSAGE = 439, + LANG_COMMAND_INVALIDCREATUREID = 440, + LANG_COMMAND_LISTCREATUREMESSAGE = 441, + LANG_COMMAND_NOAREAFOUND = 442, + LANG_COMMAND_NOITEMSETFOUND = 443, + LANG_COMMAND_NOSKILLFOUND = 444, + LANG_COMMAND_NOSPELLFOUND = 445, + LANG_COMMAND_NOQUESTFOUND = 446, + LANG_COMMAND_NOCREATUREFOUND = 447, + LANG_COMMAND_NOGAMEOBJECTFOUND = 448, + LANG_COMMAND_GRAVEYARDNOEXIST = 449, + LANG_COMMAND_GRAVEYARDALRLINKED = 450, + LANG_COMMAND_GRAVEYARDLINKED = 451, + LANG_COMMAND_GRAVEYARDWRONGZONE = 452, + // = 453, + LANG_COMMAND_GRAVEYARDERROR = 454, + LANG_COMMAND_GRAVEYARD_NOTEAM = 455, + LANG_COMMAND_GRAVEYARD_ANY = 456, + LANG_COMMAND_GRAVEYARD_ALLIANCE = 457, + LANG_COMMAND_GRAVEYARD_HORDE = 458, + LANG_COMMAND_GRAVEYARDNEAREST = 459, + LANG_COMMAND_ZONENOGRAVEYARDS = 460, + LANG_COMMAND_ZONENOGRAFACTION = 461, + LANG_COMMAND_TP_ALREADYEXIST = 462, + LANG_COMMAND_TP_ADDED = 463, + LANG_COMMAND_TP_ADDEDERR = 464, + LANG_COMMAND_TP_DELETED = 465, + LANG_COMMAND_NOTAXINODEFOUND = 466, + LANG_COMMAND_TARGET_LISTAURAS = 467, + LANG_COMMAND_TARGET_AURADETAIL = 468, + LANG_COMMAND_TARGET_LISTAURATYPE = 469, + LANG_COMMAND_TARGET_AURASIMPLE = 470, + + LANG_COMMAND_QUEST_NOTFOUND = 471, + LANG_COMMAND_QUEST_STARTFROMITEM = 472, + LANG_COMMAND_QUEST_REMOVED = 473, + LANG_COMMAND_QUEST_REWARDED = 474, + LANG_COMMAND_QUEST_COMPLETE = 475, + LANG_COMMAND_QUEST_ACTIVE = 476, + + LANG_COMMAND_FLYMODE_STATUS = 477, + + LANG_COMMAND_OPCODESENT = 478, + + LANG_COMMAND_IMPORT_SUCCESS = 479, + LANG_COMMAND_IMPORT_FAILED = 480, + LANG_COMMAND_EXPORT_SUCCESS = 481, + LANG_COMMAND_EXPORT_FAILED = 482, + + LANG_COMMAND_SPELL_BROKEN = 483, + + LANG_SET_SKILL = 484, + LANG_SET_SKILL_ERROR = 485, + + LANG_INVALID_SKILL_ID = 486, + LANG_LEARNING_GM_SKILLS = 487, + LANG_YOU_KNOWN_SPELL = 488, + LANG_TARGET_KNOWN_SPELL = 489, + LANG_UNKNOWN_SPELL = 490, + LANG_FORGET_SPELL = 491, + LANG_REMOVEALL_COOLDOWN = 492, + LANG_REMOVE_COOLDOWN = 493, + + LANG_ADDITEM = 494, //log + LANG_ADDITEMSET = 495, //log + LANG_REMOVEITEM = 496, + LANG_ITEM_CANNOT_CREATE = 497, + LANG_INSERT_GUILD_NAME = 498, + LANG_PLAYER_NOT_FOUND = 499, + LANG_PLAYER_IN_GUILD = 500, + LANG_GUILD_NOT_CREATED = 501, + LANG_NO_ITEMS_FROM_ITEMSET_FOUND = 502, + + LANG_DISTANCE = 503, + + LANG_ITEM_SLOT = 504, + LANG_ITEM_SLOT_NOT_EXIST = 505, + LANG_ITEM_ADDED_TO_SLOT = 506, + LANG_ITEM_SAVE_FAILED = 507, + LANG_ITEMLIST_SLOT = 508, + LANG_ITEMLIST_MAIL = 509, + LANG_ITEMLIST_AUCTION = 510, + + LANG_WRONG_LINK_TYPE = 511, + LANG_ITEM_LIST_CHAT = 512, + LANG_QUEST_LIST_CHAT = 513, + LANG_CREATURE_ENTRY_LIST_CHAT = 514, + LANG_CREATURE_LIST_CHAT = 515, + LANG_GO_ENTRY_LIST_CHAT = 516, + LANG_GO_LIST_CHAT = 517, + LANG_ITEMSET_LIST_CHAT = 518, + LANG_TELE_LIST = 519, + LANG_SPELL_LIST = 520, + LANG_SKILL_LIST_CHAT = 521, + + LANG_GAMEOBJECT_NOT_EXIST = 522, + + LANG_GAMEOBJECT_CURRENT = 523, //log + LANG_GAMEOBJECT_DETAIL = 524, + LANG_GAMEOBJECT_ADD = 525, + + LANG_MOVEGENS_LIST = 526, + LANG_MOVEGENS_IDLE = 527, + LANG_MOVEGENS_RANDOM = 528, + LANG_MOVEGENS_WAYPOINT = 529, + LANG_MOVEGENS_ANIMAL_RANDOM = 530, + LANG_MOVEGENS_CONFUSED = 531, + LANG_MOVEGENS_TARGETED_PLAYER = 532, + LANG_MOVEGENS_TARGETED_CREATURE = 533, + LANG_MOVEGENS_TARGETED_NULL = 534, + LANG_MOVEGENS_HOME_CREATURE = 535, + LANG_MOVEGENS_HOME_PLAYER = 536, + LANG_MOVEGENS_FLIGHT = 537, + LANG_MOVEGENS_UNKNOWN = 538, + + LANG_NPCINFO_CHAR = 539, + LANG_NPCINFO_LEVEL = 540, + LANG_NPCINFO_HEALTH = 541, + LANG_NPCINFO_FLAGS = 542, + LANG_NPCINFO_LOOT = 543, + LANG_NPCINFO_POSITION = 544, + LANG_NPCINFO_VENDOR = 545, + LANG_NPCINFO_TRAINER = 546, + LANG_NPCINFO_DUNGEON_ID = 547, + + LANG_PINFO_ACCOUNT = 548, + LANG_PINFO_LEVEL = 549, + LANG_PINFO_NO_REP = 550, + + LANG_YOU_SET_EXPLORE_ALL = 551, + LANG_YOU_SET_EXPLORE_NOTHING = 552, + LANG_YOURS_EXPLORE_SET_ALL = 553, + LANG_YOURS_EXPLORE_SET_NOTHING = 554, + + LANG_HOVER_ENABLED = 555, + LANG_HOVER_DISABLED = 556, + LANG_YOURS_LEVEL_UP = 557, + LANG_YOURS_LEVEL_DOWN = 558, + LANG_YOURS_LEVEL_PROGRESS_RESET = 559, + LANG_EXPLORE_AREA = 560, + LANG_UNEXPLORE_AREA = 561, + + LANG_UPDATE = 562, + LANG_UPDATE_CHANGE = 563, + LANG_TOO_BIG_INDEX = 564, + LANG_SET_UINT = 565, //log + LANG_SET_UINT_FIELD = 566, + LANG_SET_FLOAT = 567, //log + LANG_SET_FLOAT_FIELD = 568, + LANG_GET_UINT = 569, //log + LANG_GET_UINT_FIELD = 570, + LANG_GET_FLOAT = 571, //log + LANG_GET_FLOAT_FIELD = 572, + LANG_SET_32BIT = 573, //log + LANG_SET_32BIT_FIELD = 574, + LANG_CHANGE_32BIT = 575, //log + LANG_CHANGE_32BIT_FIELD = 576, + + LANG_INVISIBLE_INVISIBLE = 577, + LANG_INVISIBLE_VISIBLE = 578, + LANG_SELECTED_TARGET_NOT_HAVE_VICTIM = 579, + + LANG_COMMAND_LEARN_ALL_DEFAULT_AND_QUEST = 580, + LANG_COMMAND_NEAROBJMESSAGE = 581, + LANG_COMMAND_RAWPAWNTIMES = 582, + + LANG_EVENT_ENTRY_LIST_CHAT = 583, + LANG_NOEVENTFOUND = 584, + LANG_EVENT_NOT_EXIST = 585, + LANG_EVENT_INFO = 586, + LANG_EVENT_ALREADY_ACTIVE = 587, + LANG_EVENT_NOT_ACTIVE = 588, + + LANG_MOVEGENS_POINT = 589, + LANG_MOVEGENS_FEAR = 590, + LANG_MOVEGENS_DISTRACT = 591, + + LANG_COMMAND_LEARN_ALL_RECIPES = 592, + LANG_BANLIST_ACCOUNTS = 593, + LANG_BANLIST_ACCOUNTS_HEADER = 594, + LANG_BANLIST_IPS = 595, + LANG_BANLIST_IPS_HEADER = 596, + LANG_GMLIST = 597, + LANG_GMLIST_HEADER = 598, + LANG_GMLIST_EMPTY = 599, + // End Level 3 list, continued at 1100 + + // Battleground + LANG_BG_A_WINS = 600, + LANG_BG_H_WINS = 601, + + LANG_BG_WS_START_TWO_MINUTES = 753, + LANG_BG_WS_START_ONE_MINUTE = 602, + LANG_BG_WS_START_HALF_MINUTE = 603, + LANG_BG_WS_HAS_BEGUN = 604, + + LANG_BG_WS_CAPTURED_HF = 605, + LANG_BG_WS_CAPTURED_AF = 606, + LANG_BG_WS_DROPPED_HF = 607, + LANG_BG_WS_DROPPED_AF = 608, + LANG_BG_WS_RETURNED_AF = 609, + LANG_BG_WS_RETURNED_HF = 610, + LANG_BG_WS_PICKEDUP_HF = 611, + LANG_BG_WS_PICKEDUP_AF = 612, + LANG_BG_WS_F_PLACED = 613, + LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED = 614, + LANG_BG_WS_HORDE_FLAG_RESPAWNED = 615, + + LANG_BG_EY_START_TWO_MINUTES = 755, + LANG_BG_EY_START_ONE_MINUTE = 636, + LANG_BG_EY_START_HALF_MINUTE = 637, + LANG_BG_EY_HAS_BEGUN = 638, + + LANG_BG_AB_ALLY = 650, + LANG_BG_AB_HORDE = 651, + LANG_BG_AB_NODE_STABLES = 652, + LANG_BG_AB_NODE_BLACKSMITH = 653, + LANG_BG_AB_NODE_FARM = 654, + LANG_BG_AB_NODE_LUMBER_MILL = 655, + LANG_BG_AB_NODE_GOLD_MINE = 656, + LANG_BG_AB_NODE_TAKEN = 657, + LANG_BG_AB_NODE_DEFENDED = 658, + LANG_BG_AB_NODE_ASSAULTED = 659, + LANG_BG_AB_NODE_CLAIMED = 660, + + LANG_BG_AB_START_TWO_MINUTES = 754, + LANG_BG_AB_START_ONE_MINUTE = 661, + LANG_BG_AB_START_HALF_MINUTE = 662, + LANG_BG_AB_HAS_BEGUN = 663, + LANG_BG_AB_A_NEAR_VICTORY = 664, + LANG_BG_AB_H_NEAR_VICTORY = 665, + LANG_BG_MARK_BY_MAIL = 666, + + LANG_BG_EY_HAS_TAKEN_A_M_TOWER = 667, + LANG_BG_EY_HAS_TAKEN_H_M_TOWER = 668, + LANG_BG_EY_HAS_TAKEN_A_D_RUINS = 669, + LANG_BG_EY_HAS_TAKEN_H_D_RUINS = 670, + LANG_BG_EY_HAS_TAKEN_A_B_TOWER = 671, + LANG_BG_EY_HAS_TAKEN_H_B_TOWER = 672, + LANG_BG_EY_HAS_TAKEN_A_F_RUINS = 673, + LANG_BG_EY_HAS_TAKEN_H_F_RUINS = 674, + LANG_BG_EY_HAS_LOST_A_M_TOWER = 675, + LANG_BG_EY_HAS_LOST_H_M_TOWER = 676, + LANG_BG_EY_HAS_LOST_A_D_RUINS = 677, + LANG_BG_EY_HAS_LOST_H_D_RUINS = 678, + LANG_BG_EY_HAS_LOST_A_B_TOWER = 679, + LANG_BG_EY_HAS_LOST_H_B_TOWER = 680, + LANG_BG_EY_HAS_LOST_A_F_RUINS = 681, + LANG_BG_EY_HAS_LOST_H_F_RUINS = 682, + LANG_BG_EY_HAS_TAKEN_FLAG = 683, + LANG_BG_EY_CAPTURED_FLAG_A = 684, + LANG_BG_EY_CAPTURED_FLAG_H = 685, + LANG_BG_EY_DROPPED_FLAG = 686, + LANG_BG_EY_RESETED_FLAG = 687, + + LANG_ARENA_ONE_TOOLOW = 700, + LANG_ARENA_ONE_MINUTE = 701, + LANG_ARENA_THIRTY_SECONDS = 702, + LANG_ARENA_FIFTEEN_SECONDS = 703, + LANG_ARENA_HAS_BEGUN = 704, + + LANG_WAIT_BEFORE_SPEAKING = 705, + LANG_NOT_EQUIPPED_ITEM = 706, + LANG_PLAYER_DND = 707, + LANG_PLAYER_AFK = 708, + LANG_PLAYER_DND_DEFAULT = 709, + LANG_PLAYER_AFK_DEFAULT = 710, + + LANG_BG_QUEUE_ANNOUNCE_SELF = 711, + LANG_BG_QUEUE_ANNOUNCE_WORLD = 712, + LANG_YOUR_ARENA_LEVEL_REQ_ERROR = 713, +// = 714, not used + LANG_YOUR_BG_LEVEL_REQ_ERROR = 715, +// = 716, not used + LANG_BG_STARTED_ANNOUNCE_WORLD = 717, + LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN= 718, + LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT= 719, + + LANG_BG_GROUP_TOO_LARGE = 720, // "Your group is too large for this battleground. Please regroup to join." + LANG_ARENA_GROUP_TOO_LARGE = 721, // "Your group is too large for this arena. Please regroup to join." + LANG_ARENA_YOUR_TEAM_ONLY = 722, // "Your group has members not in your arena team. Please regroup to join." + LANG_ARENA_NOT_ENOUGH_PLAYERS = 723, // "Your group does not have enough players to join this match." + LANG_ARENA_GOLD_WINS = 724, // "The Gold Team wins!" + LANG_ARENA_GREEN_WINS = 725, // "The Green Team wins!" +// = 726, not used + LANG_BG_GROUP_OFFLINE_MEMBER = 727, // "Your group has an offline member. Please remove him before joining." + LANG_BG_GROUP_MIXED_FACTION = 728, // "Your group has players from the opposing faction. You can't join the battleground as a group." + LANG_BG_GROUP_MIXED_LEVELS = 729, // "Your group has players from different battleground brakets. You can't join as group." + LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE = 730, // "Someone in your party is already in this battleground queue. (S)he must leave it before joining as group." + LANG_BG_GROUP_MEMBER_DESERTER = 731, // "Someone in your party is Deserter. You can't join as group." + LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS = 732, // "Someone in your party is already in three battleground queues. You cannot join as group." + + LANG_CANNOT_TELE_TO_BG = 733, // "You cannot teleport to a battleground or arena map." + LANG_CANNOT_SUMMON_TO_BG = 734, // "You cannot summon players to a battleground or arena map." + LANG_CANNOT_GO_TO_BG_GM = 735, // "You must be in GM mode to teleport to a player in a battleground." + LANG_CANNOT_GO_TO_BG_FROM_BG = 736, // "You cannot teleport to a battleground from another battleground. Please leave the current battleground first." + LANG_DEBUG_ARENA_ON = 737, + LANG_DEBUG_ARENA_OFF = 738, + LANG_DEBUG_BG_ON = 739, + LANG_DEBUG_BG_OFF = 740, + LANG_DIST_ARENA_POINTS_START = 741, + LANG_DIST_ARENA_POINTS_ONLINE_START = 742, + LANG_DIST_ARENA_POINTS_ONLINE_END = 743, + LANG_DIST_ARENA_POINTS_TEAM_START = 744, + LANG_DIST_ARENA_POINTS_TEAM_END = 745, + LANG_DIST_ARENA_POINTS_END = 746, + LANG_BG_DISABLED = 747, + LANG_ARENA_DISABLED = 748, +// = 749, not used + LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 750, // "Not enough players. This game will close in %u mins." + LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS = 751, // "Not enough players. This game will close in %u seconds." +// = 752, not used +// LANG_BG_WS_START_TWO_MINUTES = 753, - defined above +// LANG_BG_AB_START_TWO_MINUTES = 754, - defined above +// LANG_BG_EY_START_TWO_MINUTES = 755, - defined above + + // Room for BG/ARENA = 773-784, 788-799 not used + LANG_ARENA_TESTING = 785, + LANG_AUTO_ANN = 786, + LANG_ANNOUNCE_COLOR = 787, + + // in game strings + LANG_PET_INVALID_NAME = 800, + LANG_NOT_ENOUGH_GOLD = 801, + LANG_NOT_FREE_TRADE_SLOTS = 802, + LANG_NOT_PARTNER_FREE_TRADE_SLOTS = 803, + LANG_YOU_NOT_HAVE_PERMISSION = 804, + LANG_UNKNOWN_LANGUAGE = 805, + LANG_NOT_LEARNED_LANGUAGE = 806, + LANG_NEED_CHARACTER_NAME = 807, + LANG_PLAYER_NOT_EXIST_OR_OFFLINE = 808, + LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND = 809, + LANG_ACHIEVEMENT_EARNED = 810, + LANG_GUILD_MASTER = 811, + LANG_GUILD_OFFICER = 812, + LANG_GUILD_VETERAN = 813, + LANG_GUILD_MEMBER = 814, + LANG_GUILD_INITIATE = 815, + LANG_ZONE_NOFLYZONE = 816, + + LANG_COMMAND_CREATURETEMPLATE_NOTFOUND = 817, + LANG_COMMAND_CREATURESTORAGE_NOTFOUND = 818, + // Room for in-game strings 819-999 not used + + // Level 4 (CLI only commands) + LANG_COMMAND_EXIT = 1000, + LANG_ACCOUNT_DELETED = 1001, + LANG_ACCOUNT_NOT_DELETED_SQL_ERROR = 1002, + LANG_ACCOUNT_NOT_DELETED = 1003, + LANG_ACCOUNT_CREATED = 1004, + LANG_ACCOUNT_TOO_LONG = 1005, + LANG_ACCOUNT_ALREADY_EXIST = 1006, + LANG_ACCOUNT_NOT_CREATED_SQL_ERROR = 1007, + LANG_ACCOUNT_NOT_CREATED = 1008, + LANG_CHARACTER_DELETED = 1009, + LANG_ACCOUNT_LIST_HEADER = 1010, + LANG_ACCOUNT_LIST_ERROR = 1011, + LANG_ACCOUNT_LIST_BAR = 1012, + LANG_ACCOUNT_LIST_LINE = 1013, + LANG_ACCOUNT_LIST_EMPTY = 1014, + LANG_ACCOUNT_LIST_BAR_HEADER = 1015, + // Room for more level 4 1016-1099 not used + + // Level 3 (continue) + LANG_ACCOUNT_SETADDON = 1100, + LANG_MOTD_NEW = 1101, + LANG_SENDMESSAGE = 1102, + LANG_EVENT_ENTRY_LIST_CONSOLE = 1103, + LANG_CREATURE_ENTRY_LIST_CONSOLE = 1104, + LANG_ITEM_LIST_CONSOLE = 1105, + LANG_ITEMSET_LIST_CONSOLE = 1106, + LANG_GO_ENTRY_LIST_CONSOLE = 1107, + LANG_QUEST_LIST_CONSOLE = 1108, + LANG_SKILL_LIST_CONSOLE = 1109, + LANG_CREATURE_LIST_CONSOLE = 1110, + LANG_GO_LIST_CONSOLE = 1111, + LANG_FILE_OPEN_FAIL = 1112, + LANG_ACCOUNT_CHARACTER_LIST_FULL = 1113, + LANG_DUMP_BROKEN = 1114, + LANG_INVALID_CHARACTER_NAME = 1115, + LANG_INVALID_CHARACTER_GUID = 1116, + LANG_CHARACTER_GUID_IN_USE = 1117, + LANG_ITEMLIST_GUILD = 1118, + LANG_MUST_MALE_OR_FEMALE = 1119, + LANG_YOU_CHANGE_GENDER = 1120, + LANG_YOUR_GENDER_CHANGED = 1121, + LANG_SKILL_VALUES = 1122, + LANG_NO_PET_FOUND = 1123, + LANG_WRONG_PET_TYPE = 1124, + LANG_COMMAND_LEARN_PET_TALENTS = 1125, + LANG_RESET_PET_TALENTS = 1126, + LANG_RESET_PET_TALENTS_ONLINE = 1127, + LANG_TAXINODE_ENTRY_LIST_CHAT = 1128, + LANG_TAXINODE_ENTRY_LIST_CONSOLE = 1129, + // Room for more level 3 1130-1199 not used + + // Debug commands + LANG_CINEMATIC_NOT_EXIST = 1200, + LANG_MOVIE_NOT_EXIST = 1201, + // Room for more debug 1202-1299 not used + + // FREE IDS 1300-9999 + + // AV + LANG_BG_AV_ALLY = 1300, + LANG_BG_AV_HORDE = 1301, + LANG_BG_AV_TOWER_TAKEN = 1302, + LANG_BG_AV_TOWER_ASSAULTED = 1303, + LANG_BG_AV_TOWER_DEFENDED = 1304, + LANG_BG_AV_GRAVE_TAKEN = 1305, + LANG_BG_AV_GRAVE_DEFENDED = 1306, + LANG_BG_AV_GRAVE_ASSAULTED = 1307, + + LANG_BG_AV_MINE_TAKEN = 1308, + LANG_BG_AV_MINE_NORTH = 1309, + LANG_BG_AV_MINE_SOUTH = 1310, + + LANG_BG_AV_NODE_GRAVE_STORM_AID = 1311, + LANG_BG_AV_NODE_TOWER_DUN_S = 1312, + LANG_BG_AV_NODE_TOWER_DUN_N = 1313, + LANG_BG_AV_NODE_GRAVE_STORMPIKE = 1314, + LANG_BG_AV_NODE_TOWER_ICEWING = 1315, + LANG_BG_AV_NODE_GRAVE_STONE = 1316, + LANG_BG_AV_NODE_TOWER_STONE = 1317, + LANG_BG_AV_NODE_GRAVE_SNOW = 1318, + LANG_BG_AV_NODE_TOWER_ICE = 1319, + LANG_BG_AV_NODE_GRAVE_ICE = 1320, + LANG_BG_AV_NODE_TOWER_POINT = 1321, + LANG_BG_AV_NODE_GRAVE_FROST = 1322, + LANG_BG_AV_NODE_TOWER_FROST_E = 1323, + LANG_BG_AV_NODE_TOWER_FROST_W = 1324, + LANG_BG_AV_NODE_GRAVE_FROST_HUT = 1325, + + LANG_BG_AV_START_ONE_MINUTE = 1326, + LANG_BG_AV_START_HALF_MINUTE = 1327, + LANG_BG_AV_HAS_BEGUN = 1328, + LANG_BG_AV_A_NEAR_LOSE = 1329, + LANG_BG_AV_H_NEAR_LOSE = 1330, + LANG_BG_AV_H_CAPTAIN_DEAD = 1331, + LANG_BG_AV_A_CAPTAIN_DEAD = 1332, + LANG_BG_AV_START_TWO_MINUTES = 1333, + // FREE IDS 1334-1999 + + // Ticket Strings 2000-2029 + LANG_COMMAND_TICKETNEW = 2000, + LANG_COMMAND_TICKETUPDATED = 2001, + LANG_COMMAND_TICKETPLAYERABANDON = 2002, + LANG_COMMAND_TICKETCLOSED = 2003, + LANG_COMMAND_TICKETDELETED = 2004, + LANG_COMMAND_TICKETNOTEXIST = 2005, + LANG_COMMAND_TICKETCLOSEFIRST = 2006, + LANG_COMMAND_TICKETALREADYASSIGNED = 2007, + LANG_COMMAND_TICKETRELOAD = 2008, + LANG_COMMAND_TICKETSHOWLIST = 2009, + LANG_COMMAND_TICKETSHOWONLINELIST = 2010, + LANG_COMMAND_TICKETSHOWCLOSEDLIST = 2011, + LANG_COMMAND_TICKETASSIGNERROR_A = 2012, + LANG_COMMAND_TICKETASSIGNERROR_B = 2013, + LANG_COMMAND_TICKETNOTASSIGNED = 2014, + LANG_COMMAND_TICKETUNASSIGNSECURITY = 2015, + LANG_COMMAND_TICKETCANNOTCLOSE = 2016, + LANG_COMMAND_TICKETLISTGUID = 2017, + LANG_COMMAND_TICKETLISTNAME = 2018, + LANG_COMMAND_TICKETLISTAGE = 2019, + LANG_COMMAND_TICKETLISTASSIGNEDTO = 2020, + LANG_COMMAND_TICKETLISTUNASSIGNED = 2021, + LANG_COMMAND_TICKETLISTMESSAGE = 2022, + LANG_COMMAND_TICKETLISTCOMMENT = 2023, + LANG_COMMAND_TICKETLISTADDCOMMENT = 2024, + LANG_COMMAND_TICKETLISTAGECREATE = 2025, + + // Trinity strings 5000-9999 + LANG_COMMAND_FREEZE = 5000, + LANG_COMMAND_FREEZE_ERROR = 5001, + LANG_COMMAND_FREEZE_WRONG = 5002, + LANG_COMMAND_UNFREEZE = 5003, + LANG_COMMAND_NO_FROZEN_PLAYERS = 5004, + LANG_COMMAND_LIST_FREEZE = 5005, + LANG_COMMAND_FROZEN_PLAYERS = 5006, + LANG_INSTANCE_RAID_GROUP_ONLY = 5007, + LANG_INSTANCE_CLOSED = 5008, + LANG_COMMAND_PLAYED_TO_ALL = 5009, + LANG_NPCINFO_LINKGUID = 5010, + LANG_TELEPORTED_TO_BY_CONSOLE = 5011, + // for command lookup map + LANG_COMMAND_NOMAPFOUND = 5012, + LANG_CONTINENT = 5013, + LANG_INSTANCE = 5014, + LANG_BATTLEGROUND = 5015, + LANG_ARENA = 5016, + LANG_RAID = 5017, + LANG_HEROIC = 5018, + LANG_MOUNTABLE = 5019, + LANG_NPCINFO_PHASEMASK = 5020, + LANG_NPCINFO_ARMOR = 5021, + LANG_CHANNEL_NOT_PUBLIC = 5022, + LANG_CHANNEL_PUBLIC_CHANGED = 5023, + LANG_GOINFO_ENTRY = 5024, + LANG_GOINFO_TYPE = 5025, + LANG_GOINFO_DISPLAYID = 5026, + LANG_GOINFO_NAME = 5027, + // Room for more Trinity strings 5028-9999 + + // Level requirement notifications + LANG_SAY_REQ = 6604, + LANG_WHISPER_REQ = 6605, + LANG_CHANNEL_REQ = 6606, + LANG_AUCTION_REQ = 6607, + LANG_TICKET_REQ = 6608, + LANG_TRADE_REQ = 6609, + LANG_TRADE_OTHER_REQ = 6610, + LANG_MAIL_SENDER_REQ = 6611, + LANG_MAIL_RECEIVER_REQ = 6612, + + + // Used for GM Announcements + LANG_GM_BROADCAST = 6613, + LANG_GM_NOTIFY = 6614, + LANG_GM_ANNOUNCE_COLOR = 6615, + + LANG_GM_SILENCE = 6616, // "Silence is ON for %s" - Spell 1852 + + LANG_WORLD_CLOSED = 7523, + LANG_WORLD_OPENED = 7524, + + // Use for not-in-offcial-sources patches + // 10000-10999 + // opvp hp + LANG_OPVP_HP_CAPTURE_OVERLOOK_H = 10001, + LANG_OPVP_HP_CAPTURE_OVERLOOK_A = 10002, + LANG_OPVP_HP_CAPTURE_STADIUM_H = 10003, + LANG_OPVP_HP_CAPTURE_STADIUM_A = 10004, + LANG_OPVP_HP_CAPTURE_BROKENHILL_H = 10005, + LANG_OPVP_HP_CAPTURE_BROKENHILL_A = 10006, + LANG_OPVP_HP_LOOSE_OVERLOOK_H = 10007, + LANG_OPVP_HP_LOOSE_OVERLOOK_A = 10008, + LANG_OPVP_HP_LOOSE_STADIUM_H = 10009, + LANG_OPVP_HP_LOOSE_STADIUM_A = 10010, + LANG_OPVP_HP_LOOSE_BROKENHILL_H = 10011, + LANG_OPVP_HP_LOOSE_BROKENHILL_A = 10012, + // opvp zm + LANG_OPVP_ZM_CAPTURE_WEST_H = 10013, + LANG_OPVP_ZM_CAPTURE_WEST_A = 10014, + LANG_OPVP_ZM_CAPTURE_EAST_H = 10015, + LANG_OPVP_ZM_CAPTURE_EAST_A = 10016, + LANG_OPVP_ZM_CAPTURE_GY_H = 10017, + LANG_OPVP_ZM_CAPTURE_GY_A = 10018, + LANG_OPVP_ZM_LOOSE_WEST_H = 10019, + LANG_OPVP_ZM_LOOSE_WEST_A = 10020, + LANG_OPVP_ZM_LOOSE_EAST_H = 10021, + LANG_OPVP_ZM_LOOSE_EAST_A = 10022, + LANG_OPVP_ZM_LOOSE_GY_H = 10023, + LANG_OPVP_ZM_LOOSE_GY_A = 10024, + // opvp na + LANG_OPVP_NA_CAPTURE_H = 10025, + LANG_OPVP_NA_CAPTURE_A = 10026, + LANG_OPVP_NA_LOOSE_H = 10027, + LANG_OPVP_NA_LOOSE_A = 10028, + // opvp tf + LANG_OPVP_TF_CAPTURE_H = 10029, + LANG_OPVP_TF_CAPTURE_A = 10030, + LANG_OPVP_TF_LOOSE_H = 10031, + LANG_OPVP_TF_LOOSE_A = 10032, + // opvp ep + LANG_OPVP_EP_CAPTURE_NPT_H = 10033, + LANG_OPVP_EP_CAPTURE_NPT_A = 10034, + LANG_OPVP_EP_CAPTURE_EWT_H = 10035, + LANG_OPVP_EP_CAPTURE_EWT_A = 10036, + LANG_OPVP_EP_CAPTURE_CGT_H = 10037, + LANG_OPVP_EP_CAPTURE_CGT_A = 10038, + LANG_OPVP_EP_CAPTURE_PWT_H = 10039, + LANG_OPVP_EP_CAPTURE_PWT_A = 10040, + LANG_OPVP_EP_LOOSE_NPT_H = 10041, + LANG_OPVP_EP_LOOSE_NPT_A = 10042, + LANG_OPVP_EP_LOOSE_EWT_H = 10043, + LANG_OPVP_EP_LOOSE_EWT_A = 10044, + LANG_OPVP_EP_LOOSE_CGT_H = 10045, + LANG_OPVP_EP_LOOSE_CGT_A = 10046, + LANG_OPVP_EP_LOOSE_PWT_H = 10047, + LANG_OPVP_EP_LOOSE_PWT_A = 10048, + // opvp si + LANG_OPVP_SI_CAPTURE_H = 10049, + LANG_OPVP_SI_CAPTURE_A = 10050, + // opvp gossips + LANG_OPVP_EP_FLIGHT_NPT = 10051, + LANG_OPVP_EP_FLIGHT_EWT = 10052, + LANG_OPVP_EP_FLIGHT_CGT = 10053, + LANG_OPVP_ZM_GOSSIP_ALLIANCE = 10054, + LANG_OPVP_ZM_GOSSIP_HORDE = 10055, + + LANG_BG_SA_START_TWO_MINUTES = 10056, + LANG_BG_SA_START_ONE_MINUTE = 10057, + LANG_BG_SA_START_HALF_MINUTE = 10058, + LANG_BG_SA_HAS_BEGUN = 10059, + LANG_BG_SA_IS_UNDER_ATTACK = 10060,//The %s is under attack! + LANG_BG_SA_WAS_DESTROYED = 10061,//The %s was destroyed! + LANG_BG_SA_ROUND_ONE_END = 10062,//Round 1 - finished! + LANG_BG_SA_ALLIANCE_CAPTURED_RELIC = 10063,//The Alliance captured the titan portal! + LANG_BG_SA_HORDE_CAPTURED_RELIC = 10064,//The Horde captured the titan portal! + LANG_BG_SA_ROUND_TWO_ONE_MINUTE = 10065,//Round 2 of the Battle for the Strand of the Ancients begins in 1 minute. + LANG_BG_SA_ROUND_TWO_START_HALF_MINUTE = 10066,//Round 2 begins in 30 seconds. Prepare yourselves! + LANG_BG_SA_CHAMBER_BREACHED = 10067,//The chamber has been breached! The titan relic is vulnerable! + LANG_BG_SA_A_GY_SOUTH = 10068,//The Alliance captured the South Graveyard! + LANG_BG_SA_A_GY_WEST = 10069,//The Alliance captured the West Graveyard! + LANG_BG_SA_A_GY_EAST = 10070,//The Alliance captured the East Graveyard! + LANG_BG_SA_H_GY_SOUTH = 10071,//The Horde captured the South Graveyard! + LANG_BG_SA_H_GY_WEST = 10072,//The Horde captured the West Graveyard! + LANG_BG_SA_H_GY_EAST = 10073,//The Horde captured the East Graveyard! + + // Use for custom patches 11000-11999 + LANG_AUTO_BROADCAST = 11000, + LANG_INVALID_REALMID = 11001, + + // NOT RESERVED IDS 12000-1999999999 + // `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID) + // For other tables maybe 2000010000-2147483647 (max index) +}; +#endif + diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h new file mode 100644 index 00000000000..903dd4b09ca --- /dev/null +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -0,0 +1,2772 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_SHAREDDEFINES_H +#define TRINITY_SHAREDDEFINES_H + +#include "Platform/Define.h" +#include + +// loot modes for creatures and gameobjects, bitmask! +enum LootModes +{ + LOOT_MODE_DEFAULT = 1, + LOOT_MODE_HARD_MODE_1 = 2, + LOOT_MODE_HARD_MODE_2 = 4, + LOOT_MODE_HARD_MODE_3 = 8, + LOOT_MODE_HARD_MODE_4 = 16 +}; + +enum Gender +{ + GENDER_MALE = 0, + GENDER_FEMALE = 1, + GENDER_NONE = 2 +}; + +// Race value is index in ChrRaces.dbc +enum Races +{ + RACE_HUMAN = 1, + RACE_ORC = 2, + RACE_DWARF = 3, + RACE_NIGHTELF = 4, + RACE_UNDEAD_PLAYER = 5, + RACE_TAUREN = 6, + RACE_GNOME = 7, + RACE_TROLL = 8, + //RACE_GOBLIN = 9, + RACE_BLOODELF = 10, + RACE_DRAENEI = 11 + //RACE_FEL_ORC = 12, + //RACE_NAGA = 13, + //RACE_BROKEN = 14, + //RACE_SKELETON = 15, + //RACE_VRYKUL = 16, + //RACE_TUSKARR = 17, + //RACE_FOREST_TROLL = 18, + //RACE_TAUNKA = 19, + //RACE_NORTHREND_SKELETON = 20, + //RACE_ICE_TROLL = 21 +}; + +// max+1 for player race +#define MAX_RACES 12 + +#define RACEMASK_ALL_PLAYABLE \ + ((1<<(RACE_HUMAN-1)) |(1<<(RACE_ORC-1)) |(1<<(RACE_DWARF-1)) | \ + (1<<(RACE_NIGHTELF-1))|(1<<(RACE_UNDEAD_PLAYER-1))|(1<<(RACE_TAUREN-1)) | \ + (1<<(RACE_GNOME-1)) |(1<<(RACE_TROLL-1)) |(1<<(RACE_BLOODELF-1))| \ + (1<<(RACE_DRAENEI-1))) + +// Class value is index in ChrClasses.dbc +enum Classes +{ + CLASS_WARRIOR = 1, + CLASS_PALADIN = 2, + CLASS_HUNTER = 3, + CLASS_ROGUE = 4, + CLASS_PRIEST = 5, + CLASS_DEATH_KNIGHT = 6, + CLASS_SHAMAN = 7, + CLASS_MAGE = 8, + CLASS_WARLOCK = 9, + //CLASS_UNK = 10, + CLASS_DRUID = 11 +}; + +// max+1 for player class +#define MAX_CLASSES 12 + +#define CLASSMASK_ALL_PLAYABLE \ + ((1<<(CLASS_WARRIOR-1))|(1<<(CLASS_PALADIN-1))|(1<<(CLASS_HUNTER-1))| \ + (1<<(CLASS_ROGUE-1)) |(1<<(CLASS_PRIEST-1)) |(1<<(CLASS_SHAMAN-1))| \ + (1<<(CLASS_MAGE-1)) |(1<<(CLASS_WARLOCK-1))|(1<<(CLASS_DRUID-1)) | \ + (1<<(CLASS_DEATH_KNIGHT-1))) + +// valid classes for creature_template.unit_class +enum UnitClass +{ + UNIT_CLASS_WARRIOR = 1, + UNIT_CLASS_PALADIN = 2, + UNIT_CLASS_ROGUE = 4, + UNIT_CLASS_MAGE = 8, +}; + +#define CLASSMASK_ALL_CREATURES ((1<<(UNIT_CLASS_WARRIOR-1)) | (1<<(UNIT_CLASS_PALADIN-1)) | (1<<(UNIT_CLASS_ROGUE-1)) | (1<<(UNIT_CLASS_MAGE-1))) + +#define CLASSMASK_WAND_USERS ((1<<(CLASS_PRIEST-1))|(1<<(CLASS_MAGE-1))|(1<<(CLASS_WARLOCK-1))) + +#define PLAYER_MAX_BATTLEGROUND_QUEUES 2 + +enum ReputationRank +{ + REP_HATED = 0, + REP_HOSTILE = 1, + REP_UNFRIENDLY = 2, + REP_NEUTRAL = 3, + REP_FRIENDLY = 4, + REP_HONORED = 5, + REP_REVERED = 6, + REP_EXALTED = 7 +}; + +#define MIN_REPUTATION_RANK (REP_HATED) +#define MAX_REPUTATION_RANK 8 + +enum MoneyConstants +{ + COPPER = 1, + SILVER = COPPER*100, + GOLD = SILVER*100 +}; + +enum Stats +{ + STAT_STRENGTH = 0, + STAT_AGILITY = 1, + STAT_STAMINA = 2, + STAT_INTELLECT = 3, + STAT_SPIRIT = 4 +}; + +#define MAX_STATS 5 + +enum Powers +{ + POWER_MANA = 0, + POWER_RAGE = 1, + POWER_FOCUS = 2, + POWER_ENERGY = 3, + POWER_HAPPINESS = 4, + POWER_RUNE = 5, + POWER_RUNIC_POWER = 6, + MAX_POWERS = 7, + POWER_ALL = 127, // default for class? + POWER_HEALTH = 0xFFFFFFFE // (-2 as signed value) +}; + +enum SpellSchools +{ + SPELL_SCHOOL_NORMAL = 0, + SPELL_SCHOOL_HOLY = 1, + SPELL_SCHOOL_FIRE = 2, + SPELL_SCHOOL_NATURE = 3, + SPELL_SCHOOL_FROST = 4, + SPELL_SCHOOL_SHADOW = 5, + SPELL_SCHOOL_ARCANE = 6 +}; + +#define MAX_SPELL_SCHOOL 7 + +enum SpellSchoolMask +{ + SPELL_SCHOOL_MASK_NONE = 0x00, // not exist + SPELL_SCHOOL_MASK_NORMAL = (1 << SPELL_SCHOOL_NORMAL), // PHYSICAL (Armor) + SPELL_SCHOOL_MASK_HOLY = (1 << SPELL_SCHOOL_HOLY), + SPELL_SCHOOL_MASK_FIRE = (1 << SPELL_SCHOOL_FIRE), + SPELL_SCHOOL_MASK_NATURE = (1 << SPELL_SCHOOL_NATURE), + SPELL_SCHOOL_MASK_FROST = (1 << SPELL_SCHOOL_FROST), + SPELL_SCHOOL_MASK_SHADOW = (1 << SPELL_SCHOOL_SHADOW), + SPELL_SCHOOL_MASK_ARCANE = (1 << SPELL_SCHOOL_ARCANE), + + // unions + + // 124, not include normal and holy damage + SPELL_SCHOOL_MASK_SPELL = (SPELL_SCHOOL_MASK_FIRE | + SPELL_SCHOOL_MASK_NATURE | SPELL_SCHOOL_MASK_FROST | + SPELL_SCHOOL_MASK_SHADOW | SPELL_SCHOOL_MASK_ARCANE), + // 126 + SPELL_SCHOOL_MASK_MAGIC = (SPELL_SCHOOL_MASK_HOLY | SPELL_SCHOOL_MASK_SPELL), + + // 127 + SPELL_SCHOOL_MASK_ALL = (SPELL_SCHOOL_MASK_NORMAL | SPELL_SCHOOL_MASK_MAGIC) +}; + +inline SpellSchools GetFirstSchoolInMask(SpellSchoolMask mask) +{ + for (int i = 0; i < MAX_SPELL_SCHOOL; ++i) + if (mask & (1 << i)) + return SpellSchools(i); + + return SPELL_SCHOOL_NORMAL; +} + +enum ItemQualities +{ + ITEM_QUALITY_POOR = 0, //GREY + ITEM_QUALITY_NORMAL = 1, //WHITE + ITEM_QUALITY_UNCOMMON = 2, //GREEN + ITEM_QUALITY_RARE = 3, //BLUE + ITEM_QUALITY_EPIC = 4, //PURPLE + ITEM_QUALITY_LEGENDARY = 5, //ORANGE + ITEM_QUALITY_ARTIFACT = 6, //LIGHT YELLOW + ITEM_QUALITY_HEIRLOOM = 7 +}; + +#define MAX_ITEM_QUALITY 8 + +enum SpellCategory +{ + SPELL_CATEGORY_FOOD = 11, + SPELL_CATEGORY_DRINK = 59, +}; + +const uint32 ItemQualityColors[MAX_ITEM_QUALITY] = { + 0xff9d9d9d, //GREY + 0xffffffff, //WHITE + 0xff1eff00, //GREEN + 0xff0070dd, //BLUE + 0xffa335ee, //PURPLE + 0xffff8000, //ORANGE + 0xffe6cc80, //LIGHT YELLOW + 0xffe6cc80 //LIGHT YELLOW +}; + +// *********************************** +// Spell Attributes definitions +// *********************************** + +#define SPELL_ATTR_UNK0 0x00000001 // 0 +#define SPELL_ATTR_REQ_AMMO 0x00000002 // 1 +#define SPELL_ATTR_ON_NEXT_SWING 0x00000004 // 2 on next swing +#define SPELL_ATTR_UNK3 0x00000008 // 3 not set in 3.0.3 +#define SPELL_ATTR_UNK4 0x00000010 // 4 +#define SPELL_ATTR_TRADESPELL 0x00000020 // 5 trade spells, will be added by client to a sublist of profession spell +#define SPELL_ATTR_PASSIVE 0x00000040 // 6 Passive spell +#define SPELL_ATTR_UNK7 0x00000080 // 7 visible? +#define SPELL_ATTR_UNK8 0x00000100 // 8 +#define SPELL_ATTR_UNK9 0x00000200 // 9 +#define SPELL_ATTR_UNK10 0x00000400 // 10 on next swing 2 +#define SPELL_ATTR_UNK11 0x00000800 // 11 +#define SPELL_ATTR_DAYTIME_ONLY 0x00001000 // 12 only useable at daytime, not set in 2.4.2 +#define SPELL_ATTR_NIGHT_ONLY 0x00002000 // 13 only useable at night, not set in 2.4.2 +#define SPELL_ATTR_INDOORS_ONLY 0x00004000 // 14 only useable indoors, not set in 2.4.2 +#define SPELL_ATTR_OUTDOORS_ONLY 0x00008000 // 15 Only useable outdoors. +#define SPELL_ATTR_NOT_SHAPESHIFT 0x00010000 // 16 Not while shapeshifted +#define SPELL_ATTR_ONLY_STEALTHED 0x00020000 // 17 Must be in stealth +#define SPELL_ATTR_UNK18 0x00040000 // 18 +#define SPELL_ATTR_LEVEL_DAMAGE_CALCULATION 0x00080000 // 19 spelldamage depends on caster level +#define SPELL_ATTR_STOP_ATTACK_TARGET 0x00100000 // 20 Stop attack after use this spell (and not begin attack if use) +#define SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK 0x00200000 // 21 Cannot be dodged/parried/blocked +#define SPELL_ATTR_UNK22 0x00400000 // 22 shoot spells +#define SPELL_ATTR_CASTABLE_WHILE_DEAD 0x00800000 // 23 castable while dead? +#define SPELL_ATTR_CASTABLE_WHILE_MOUNTED 0x01000000 // 24 castable while mounted +#define SPELL_ATTR_DISABLED_WHILE_ACTIVE 0x02000000 // 25 Activate and start cooldown after aura fade or remove summoned creature or go +#define SPELL_ATTR_NEGATIVE_1 0x04000000 // 26 Many negative spells have this attr +#define SPELL_ATTR_CASTABLE_WHILE_SITTING 0x08000000 // 27 castable while sitting +#define SPELL_ATTR_CANT_USED_IN_COMBAT 0x10000000 // 28 Cannot be used in combat +#define SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY 0x20000000 // 29 unaffected by invulnerability (hmm possible not...) +#define SPELL_ATTR_BREAKABLE_BY_DAMAGE 0x40000000 // 30 +#define SPELL_ATTR_CANT_CANCEL 0x80000000 // 31 positive aura can't be canceled + +#define SPELL_ATTR_EX_DISMISS_PET 0x00000001 // 0 dismiss pet and not allow to summon new one? +#define SPELL_ATTR_EX_DRAIN_ALL_POWER 0x00000002 // 1 use all power (Only paladin Lay of Hands and Bunyanize) +#define SPELL_ATTR_EX_CHANNELED_1 0x00000004 // 2 channeled target +#define SPELL_ATTR_EX_PUT_CASTER_IN_COMBAT 0x00000008 // 3 spells that cause a caster to enter a combat +#define SPELL_ATTR_EX_UNK4 0x00000010 // 4 stealth and whirlwind +#define SPELL_ATTR_EX_NOT_BREAK_STEALTH 0x00000020 // 5 Not break stealth +#define SPELL_ATTR_EX_CHANNELED_2 0x00000040 // 6 channeled self +#define SPELL_ATTR_EX_NEGATIVE 0x00000080 // 7 +#define SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET 0x00000100 // 8 Spell req target not to be in combat state +#define SPELL_ATTR_EX_UNK9 0x00000200 // 9 melee spells +#define SPELL_ATTR_EX_UNK10 0x00000400 // 10 no generates threat on cast 100%? (old NO_INITIAL_AGGRO) +#define SPELL_ATTR_EX_UNK11 0x00000800 // 11 aura +#define SPELL_ATTR_EX_UNK12 0x00001000 // 12 +#define SPELL_ATTR_EX_UNK13 0x00002000 // 13 +#define SPELL_ATTR_EX_STACK_FOR_DIFF_CASTERS 0x00004000 // 14 +#define SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY 0x00008000 // 15 remove auras on immunity +#define SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE 0x00010000 // 16 on immuniy +#define SPELL_ATTR_EX_UNAUTOCASTABLE_BY_PET 0x00020000 // 17 +#define SPELL_ATTR_EX_UNK18 0x00040000 // 18 +#define SPELL_ATTR_EX_CANT_TARGET_SELF 0x00080000 // 19 Applies only to unit target - for example Divine Intervention (19752) +#define SPELL_ATTR_EX_REQ_COMBO_POINTS1 0x00100000 // 20 Req combo points on target +#define SPELL_ATTR_EX_UNK21 0x00200000 // 21 +#define SPELL_ATTR_EX_REQ_COMBO_POINTS2 0x00400000 // 22 Req combo points on target +#define SPELL_ATTR_EX_UNK23 0x00800000 // 23 +#define SPELL_ATTR_EX_UNK24 0x01000000 // 24 Req fishing pole?? +#define SPELL_ATTR_EX_UNK25 0x02000000 // 25 +#define SPELL_ATTR_EX_UNK26 0x04000000 // 26 works correctly with [target=focus] and [target=mouseover] macros? +#define SPELL_ATTR_EX_UNK27 0x08000000 // 27 +#define SPELL_ATTR_EX_IGNORE_IMMUNITY 0x10000000 // 28 removed from Chains of Ice 3.3.0 +#define SPELL_ATTR_EX_UNK29 0x20000000 // 29 +#define SPELL_ATTR_EX_ENABLE_AT_DODGE 0x40000000 // 30 Overpower, Wolverine Bite +#define SPELL_ATTR_EX_UNK31 0x80000000 // 31 + +#define SPELL_ATTR_EX2_UNK0 0x00000001 // 0 +#define SPELL_ATTR_EX2_UNK1 0x00000002 // 1 ? many triggered spells have this flag +#define SPELL_ATTR_EX2_CANT_REFLECTED 0x00000004 // 2 ? used for detect can or not spell reflected +#define SPELL_ATTR_EX2_UNK3 0x00000008 // 3 +#define SPELL_ATTR_EX2_UNK4 0x00000010 // 4 +#define SPELL_ATTR_EX2_AUTOREPEAT_FLAG 0x00000020 // 5 +#define SPELL_ATTR_EX2_UNK6 0x00000040 // 6 +#define SPELL_ATTR_EX2_UNK7 0x00000080 // 7 +#define SPELL_ATTR_EX2_UNK8 0x00000100 // 8 not set in 3.0.3 +#define SPELL_ATTR_EX2_UNK9 0x00000200 // 9 +#define SPELL_ATTR_EX2_UNK10 0x00000400 // 10 +#define SPELL_ATTR_EX2_HEALTH_FUNNEL 0x00000800 // 11 +#define SPELL_ATTR_EX2_UNK12 0x00001000 // 12 +#define SPELL_ATTR_EX2_UNK13 0x00002000 // 13 Items enchanted by spells with this flag preserve the enchant to arenas +#define SPELL_ATTR_EX2_UNK14 0x00004000 // 14 +#define SPELL_ATTR_EX2_UNK15 0x00008000 // 15 not set in 3.0.3 +#define SPELL_ATTR_EX2_TAME_BEAST 0x00010000 // 16 +#define SPELL_ATTR_EX2_NOT_RESET_AUTOSHOT 0x00020000 // 17 Hunters Shot and Stings only have this flag +#define SPELL_ATTR_EX2_UNK18 0x00040000 // 18 Only Revive pet - possible req dead pet +#define SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT 0x00080000 // 19 does not necessarly need shapeshift +#define SPELL_ATTR_EX2_UNK20 0x00100000 // 20 +#define SPELL_ATTR_EX2_DAMAGE_REDUCED_SHIELD 0x00200000 // 21 for ice blocks, pala immunity buffs, priest absorb shields, but used also for other spells -> not sure! +#define SPELL_ATTR_EX2_UNK22 0x00400000 // 22 +#define SPELL_ATTR_EX2_UNK23 0x00800000 // 23 Only mage Arcane Concentration have this flag +#define SPELL_ATTR_EX2_UNK24 0x01000000 // 24 +#define SPELL_ATTR_EX2_UNK25 0x02000000 // 25 +#define SPELL_ATTR_EX2_UNK26 0x04000000 // 26 unaffected by school immunity +#define SPELL_ATTR_EX2_UNK27 0x08000000 // 27 +#define SPELL_ATTR_EX2_UNK28 0x10000000 // 28 no breaks stealth if it fails?? +#define SPELL_ATTR_EX2_CANT_CRIT 0x20000000 // 29 Spell can't crit +#define SPELL_ATTR_EX2_TRIGGERED_CAN_TRIGGER 0x40000000 // 30 spell can trigger even if triggered +#define SPELL_ATTR_EX2_FOOD_BUFF 0x80000000 // 31 Food or Drink Buff (like Well Fed) + +#define SPELL_ATTR_EX3_UNK0 0x00000001 // 0 +#define SPELL_ATTR_EX3_UNK1 0x00000002 // 1 +#define SPELL_ATTR_EX3_UNK2 0x00000004 // 2 +#define SPELL_ATTR_EX3_BLOCKABLE_SPELL 0x00000008 // 3 Only dmg class melee in 3.1.3 +#define SPELL_ATTR_EX3_UNK4 0x00000010 // 4 Druid Rebirth only this spell have this flag +#define SPELL_ATTR_EX3_UNK5 0x00000020 // 5 +#define SPELL_ATTR_EX3_UNK6 0x00000040 // 6 +#define SPELL_ATTR_EX3_STACK_FOR_DIFF_CASTERS 0x00000080 // 7 separate stack for every caster +#define SPELL_ATTR_EX3_PLAYERS_ONLY 0x00000100 // 8 Player only? +#define SPELL_ATTR_EX3_TRIGGERED_CAN_TRIGGER_2 0x00000200 // 9 triggered from effect? +#define SPELL_ATTR_EX3_MAIN_HAND 0x00000400 // 10 Main hand weapon required +#define SPELL_ATTR_EX3_BATTLEGROUND 0x00000800 // 11 Can casted only on battleground +#define SPELL_ATTR_EX3_UNK12 0x00001000 // 12 +#define SPELL_ATTR_EX3_UNK13 0x00002000 // 13 +#define SPELL_ATTR_EX3_UNK14 0x00004000 // 14 "Honorless Target" only this spells have this flag +#define SPELL_ATTR_EX3_UNK15 0x00008000 // 15 Auto Shoot, Shoot, Throw, - this is autoshot flag +#define SPELL_ATTR_EX3_UNK16 0x00010000 // 16 no triggers effects that trigger on casting a spell?? (15290 - 2.2ptr change) +#define SPELL_ATTR_EX3_NO_INITIAL_AGGRO 0x00020000 // 17 Soothe Animal, 39758, Mind Soothe +#define SPELL_ATTR_EX3_UNK18 0x00040000 // 18 added to Explosive Trap Effect 3.3.0, removed from Mutilate 3.3.0 +#define SPELL_ATTR_EX3_DISABLE_PROC 0x00080000 // 19 during aura proc no spells can trigger (20178, 20375) +#define SPELL_ATTR_EX3_DEATH_PERSISTENT 0x00100000 // 20 Death persistent spells +#define SPELL_ATTR_EX3_UNK21 0x00200000 // 21 +#define SPELL_ATTR_EX3_REQ_WAND 0x00400000 // 22 Req wand +#define SPELL_ATTR_EX3_UNK23 0x00800000 // 23 +#define SPELL_ATTR_EX3_REQ_OFFHAND 0x01000000 // 24 Req offhand weapon +#define SPELL_ATTR_EX3_UNK25 0x02000000 // 25 no cause spell pushback ? +#define SPELL_ATTR_EX3_CAN_PROC_TRIGGERED 0x04000000 // 26 +#define SPELL_ATTR_EX3_DRAIN_SOUL 0x08000000 // 27 only drain soul has this flag +#define SPELL_ATTR_EX3_UNK28 0x10000000 // 28 +#define SPELL_ATTR_EX3_NO_DONE_BONUS 0x20000000 // 29 Ignore caster spellpower and done damage mods? +#define SPELL_ATTR_EX3_UNK30 0x40000000 // 30 Shaman's Fire Nova 3.3.0, Sweeping Strikes 3.3.0 +#define SPELL_ATTR_EX3_UNK31 0x80000000 // 31 + +#define SPELL_ATTR_EX4_UNK0 0x00000001 // 0 +#define SPELL_ATTR_EX4_UNK1 0x00000002 // 1 proc on finishing move? +#define SPELL_ATTR_EX4_UNK2 0x00000004 // 2 +#define SPELL_ATTR_EX4_CANT_PROC_FROM_SELFCAST 0x00000008 // 3 +#define SPELL_ATTR_EX4_UNK4 0x00000010 // 4 This will no longer cause guards to attack on use?? +#define SPELL_ATTR_EX4_UNK5 0x00000020 // 5 +#define SPELL_ATTR_EX4_NOT_STEALABLE 0x00000040 // 6 although such auras might be dispellable, they cannot be stolen +#define SPELL_ATTR_EX4_UNK7 0x00000080 // 7 +#define SPELL_ATTR_EX4_FIXED_DAMAGE 0x00000100 // 8 decimate, share damage? +#define SPELL_ATTR_EX4_UNK9 0x00000200 // 9 +#define SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST 0x00000400 // 10 Rogue Shiv have this flag +#define SPELL_ATTR_EX4_UNK11 0x00000800 // 11 +#define SPELL_ATTR_EX4_UNK12 0x00001000 // 12 +#define SPELL_ATTR_EX4_UNK13 0x00002000 // 13 +#define SPELL_ATTR_EX4_UNK14 0x00004000 // 14 +#define SPELL_ATTR_EX4_UNK15 0x00008000 // 15 +#define SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA 0x00010000 // 16 not usable in arena +#define SPELL_ATTR_EX4_USABLE_IN_ARENA 0x00020000 // 17 usable in arena +#define SPELL_ATTR_EX4_UNK18 0x00040000 // 18 +#define SPELL_ATTR_EX4_UNK19 0x00080000 // 19 +#define SPELL_ATTR_EX4_NOT_CHECK_SELFCAST_POWER 0x00100000 // 20 supersedes message "More powerful spell applied" for self casts. +#define SPELL_ATTR_EX4_UNK21 0x00200000 // 21 +#define SPELL_ATTR_EX4_UNK22 0x00400000 // 22 +#define SPELL_ATTR_EX4_UNK23 0x00800000 // 23 +#define SPELL_ATTR_EX4_UNK24 0x01000000 // 24 +#define SPELL_ATTR_EX4_UNK25 0x02000000 // 25 pet scaling auras +#define SPELL_ATTR_EX4_CAST_ONLY_IN_OUTLAND 0x04000000 // 26 Can only be used in Outland. +#define SPELL_ATTR_EX4_UNK27 0x08000000 // 27 +#define SPELL_ATTR_EX4_UNK28 0x10000000 // 28 +#define SPELL_ATTR_EX4_UNK29 0x20000000 // 29 +#define SPELL_ATTR_EX4_UNK30 0x40000000 // 30 +#define SPELL_ATTR_EX4_UNK31 0x80000000 // 31 + +#define SPELL_ATTR_EX5_UNK0 0x00000001 // 0 +#define SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP 0x00000002 // 1 not need reagents if UNIT_FLAG_PREPARATION +#define SPELL_ATTR_EX5_UNK2 0x00000004 // 2 +#define SPELL_ATTR_EX5_USABLE_WHILE_STUNNED 0x00000008 // 3 usable while stunned +#define SPELL_ATTR_EX5_UNK4 0x00000010 // 4 +#define SPELL_ATTR_EX5_SINGLE_TARGET_SPELL 0x00000020 // 5 Only one target can be apply at a time +#define SPELL_ATTR_EX5_UNK6 0x00000040 // 6 +#define SPELL_ATTR_EX5_UNK7 0x00000080 // 7 +#define SPELL_ATTR_EX5_UNK8 0x00000100 // 8 +#define SPELL_ATTR_EX5_START_PERIODIC_AT_APPLY 0x00000200 // 9 begin periodic tick at aura apply +#define SPELL_ATTR_EX5_UNK10 0x00000400 // 10 +#define SPELL_ATTR_EX5_UNK11 0x00000800 // 11 +#define SPELL_ATTR_EX5_UNK12 0x00001000 // 12 +#define SPELL_ATTR_EX5_UNK13 0x00002000 // 13 +#define SPELL_ATTR_EX5_UNK14 0x00004000 // 14 +#define SPELL_ATTR_EX5_UNK15 0x00008000 // 15 +#define SPELL_ATTR_EX5_UNK16 0x00010000 // 16 +#define SPELL_ATTR_EX5_USABLE_WHILE_FEARED 0x00020000 // 17 usable while feared +#define SPELL_ATTR_EX5_USABLE_WHILE_CONFUSED 0x00040000 // 18 usable while confused +#define SPELL_ATTR_EX5_UNK19 0x00080000 // 19 +#define SPELL_ATTR_EX5_UNK20 0x00100000 // 20 +#define SPELL_ATTR_EX5_UNK21 0x00200000 // 21 +#define SPELL_ATTR_EX5_UNK22 0x00400000 // 22 +#define SPELL_ATTR_EX5_UNK23 0x00800000 // 23 +#define SPELL_ATTR_EX5_UNK24 0x01000000 // 24 +#define SPELL_ATTR_EX5_UNK25 0x02000000 // 25 +#define SPELL_ATTR_EX5_UNK26 0x04000000 // 26 +#define SPELL_ATTR_EX5_UNK27 0x08000000 // 27 +#define SPELL_ATTR_EX5_UNK28 0x10000000 // 28 +#define SPELL_ATTR_EX5_UNK29 0x20000000 // 29 +#define SPELL_ATTR_EX5_UNK30 0x40000000 // 30 +#define SPELL_ATTR_EX5_UNK31 0x80000000 // 31 Forces all nearby enemies to focus attacks caster + +#define SPELL_ATTR_EX6_UNK0 0x00000001 // 0 Only Move spell have this flag +#define SPELL_ATTR_EX6_ONLY_IN_ARENA 0x00000002 // 1 only usable in arena +#define SPELL_ATTR_EX6_IGNORE_CASTER_AURAS 0x00000004 // 2 +#define SPELL_ATTR_EX6_UNK3 0x00000008 // 3 +#define SPELL_ATTR_EX6_UNK4 0x00000010 // 4 +#define SPELL_ATTR_EX6_UNK5 0x00000020 // 5 +#define SPELL_ATTR_EX6_UNK6 0x00000040 // 6 +#define SPELL_ATTR_EX6_UNK7 0x00000080 // 7 +#define SPELL_ATTR_EX6_UNK8 0x00000100 // 8 +#define SPELL_ATTR_EX6_UNK9 0x00000200 // 9 +#define SPELL_ATTR_EX6_UNK10 0x00000400 // 10 +#define SPELL_ATTR_EX6_NOT_IN_RAID_INSTANCE 0x00000800 // 11 not usable in raid instance +#define SPELL_ATTR_EX6_UNK12 0x00001000 // 12 +#define SPELL_ATTR_EX6_UNK13 0x00002000 // 13 +#define SPELL_ATTR_EX6_UNK14 0x00004000 // 14 +#define SPELL_ATTR_EX6_UNK15 0x00008000 // 15 not set in 3.0.3 +#define SPELL_ATTR_EX6_UNK16 0x00010000 // 16 +#define SPELL_ATTR_EX6_UNK17 0x00020000 // 17 +#define SPELL_ATTR_EX6_UNK18 0x00040000 // 18 +#define SPELL_ATTR_EX6_UNK19 0x00080000 // 19 +#define SPELL_ATTR_EX6_UNK20 0x00100000 // 20 +#define SPELL_ATTR_EX6_CLIENT_UI_TARGET_EFFECTS 0x00200000 // 21 it's only client-side attribute +#define SPELL_ATTR_EX6_UNK22 0x00400000 // 22 +#define SPELL_ATTR_EX6_UNK23 0x00800000 // 23 not set in 3.0.3 +#define SPELL_ATTR_EX6_UNK24 0x01000000 // 24 not set in 3.0.3 +#define SPELL_ATTR_EX6_UNK25 0x02000000 // 25 not set in 3.0.3 +#define SPELL_ATTR_EX6_UNK26 0x04000000 // 26 not set in 3.0.3 +#define SPELL_ATTR_EX6_UNK27 0x08000000 // 27 not set in 3.0.3 +#define SPELL_ATTR_EX6_UNK28 0x10000000 // 28 not set in 3.0.3 +#define SPELL_ATTR_EX6_UNK29 0x20000000 // 29 not set in 3.0.3 +#define SPELL_ATTR_EX6_UNK30 0x40000000 // 30 not set in 3.0.3 +#define SPELL_ATTR_EX6_UNK31 0x80000000 // 31 not set in 3.0.3 + +#define SPELL_ATTR_EX7_UNK0 0x00000001 // 0 Shaman's new spells (Call of the ...), Feign Death. +#define SPELL_ATTR_EX7_UNK1 0x00000002 // 1 Not set in 3.2.2a. +#define SPELL_ATTR_EX7_REACTIVATE_AT_RESURRECT 0x00000004 // 2 Paladin's auras and 65607 only. +#define SPELL_ATTR_EX7_UNK3 0x00000008 // 3 Only 43574 test spell. +#define SPELL_ATTR_EX7_UNK4 0x00000010 // 4 Only 66109 test spell. +#define SPELL_ATTR_EX7_SUMMON_PLAYER_TOTEM 0x00000020 // 5 Only Shaman player totems. +#define SPELL_ATTR_EX7_UNK6 0x00000040 // 6 Dark Surge, Surge of Light, Burning Breath triggers (boss spells). +#define SPELL_ATTR_EX7_UNK7 0x00000080 // 7 66218 (Launch) spell. +#define SPELL_ATTR_EX7_UNK8 0x00000100 // 8 Teleports, mounts and other spells. +#define SPELL_ATTR_EX7_UNK9 0x00000200 // 9 Teleports, mounts and other spells. +#define SPELL_ATTR_EX7_DISPEL_CHARGES 0x00000400 // 10 Dispel and Spellsteal individual charges instead of whole aura. +#define SPELL_ATTR_EX7_INTERRUPT_ONLY_NONPLAYER 0x00000800 // 11 Only non-player casts interrupt, though Feral Charge - Bear has it. +#define SPELL_ATTR_EX7_UNK12 0x00001000 // 12 Not set in 3.2.2a. +#define SPELL_ATTR_EX7_UNK13 0x00002000 // 13 Not set in 3.2.2a. +#define SPELL_ATTR_EX7_UNK14 0x00004000 // 14 Only 52150 (Raise Dead - Pet) spell. +#define SPELL_ATTR_EX7_UNK15 0x00008000 // 15 Exorcism. Usable on players? 100% crit chance on undead and demons? +#define SPELL_ATTR_EX7_UNK16 0x00010000 // 16 Druid spells (29166, 54833, 64372, 68285). +#define SPELL_ATTR_EX7_UNK17 0x00020000 // 17 Only 27965 (Suicide) spell. +#define SPELL_ATTR_EX7_HAS_CHARGE_EFFECT 0x00040000 // 18 Only spells that have Charge among effects. +#define SPELL_ATTR_EX7_ZONE_TELEPORT 0x00080000 // 19 Teleports to specific zones. + +#define MIN_TALENT_SPEC 0 +#define MAX_TALENT_SPEC 1 +#define MIN_TALENT_SPECS 1 +#define MAX_TALENT_SPECS 2 +#define MAX_GLYPH_SLOT_INDEX 6 + +// Custom values +enum SpellClickUserTypes +{ + SPELL_CLICK_USER_ANY = 0, + SPELL_CLICK_USER_FRIEND = 1, + SPELL_CLICK_USER_RAID = 2, + SPELL_CLICK_USER_PARTY = 3, + SPELL_CLICK_USER_MAX = 4 +}; + +#define NPC_CLICK_CAST_CASTER_PLAYER 0x01 +#define NPC_CLICK_CAST_TARGET_PLAYER 0x02 +#define NPC_CLICK_CAST_ORIG_CASTER_OWNER 0x04 + +enum SheathTypes +{ + SHEATHETYPE_NONE = 0, + SHEATHETYPE_MAINHAND = 1, + SHEATHETYPE_OFFHAND = 2, + SHEATHETYPE_LARGEWEAPONLEFT = 3, + SHEATHETYPE_LARGEWEAPONRIGHT = 4, + SHEATHETYPE_HIPWEAPONLEFT = 5, + SHEATHETYPE_HIPWEAPONRIGHT = 6, + SHEATHETYPE_SHIELD = 7 +}; + +#define MAX_SHEATHETYPE 8 + +enum CharacterSlot +{ + SLOT_HEAD = 0, + SLOT_NECK = 1, + SLOT_SHOULDERS = 2, + SLOT_SHIRT = 3, + SLOT_CHEST = 4, + SLOT_WAIST = 5, + SLOT_LEGS = 6, + SLOT_FEET = 7, + SLOT_WRISTS = 8, + SLOT_HANDS = 9, + SLOT_FINGER1 = 10, + SLOT_FINGER2 = 11, + SLOT_TRINKET1 = 12, + SLOT_TRINKET2 = 13, + SLOT_BACK = 14, + SLOT_MAIN_HAND = 15, + SLOT_OFF_HAND = 16, + SLOT_RANGED = 17, + SLOT_TABARD = 18, + SLOT_EMPTY = 19 +}; + +enum Language +{ + LANG_UNIVERSAL = 0, + LANG_ORCISH = 1, + LANG_DARNASSIAN = 2, + LANG_TAURAHE = 3, + LANG_DWARVISH = 6, + LANG_COMMON = 7, + LANG_DEMONIC = 8, + LANG_TITAN = 9, + LANG_THALASSIAN = 10, + LANG_DRACONIC = 11, + LANG_KALIMAG = 12, + LANG_GNOMISH = 13, + LANG_TROLL = 14, + LANG_GUTTERSPEAK = 33, + LANG_DRAENEI = 35, + LANG_ZOMBIE = 36, + LANG_GNOMISH_BINARY = 37, + LANG_GOBLIN_BINARY = 38, + LANG_ADDON = 0xFFFFFFFF // used by addons, in 2.4.0 not exist, replaced by messagetype? +}; + +#define LANGUAGES_COUNT 19 + +enum TeamId +{ + TEAM_ALLIANCE = 0, + TEAM_HORDE, + TEAM_NEUTRAL, +}; + +enum Team +{ + HORDE = 67, + ALLIANCE = 469, + //TEAM_STEAMWHEEDLE_CARTEL = 169, // not used in code + //TEAM_ALLIANCE_FORCES = 891, + //TEAM_HORDE_FORCES = 892, + //TEAM_SANCTUARY = 936, + //TEAM_OUTLAND = 980, + TEAM_OTHER = 0, // if ReputationListId > 0 && Flags != FACTION_FLAG_TEAM_HEADER +}; + +const Team TeamId2Team[3] = {ALLIANCE, HORDE, TEAM_OTHER}; + +enum SpellEffects +{ + SPELL_EFFECT_INSTAKILL = 1, + SPELL_EFFECT_SCHOOL_DAMAGE = 2, + SPELL_EFFECT_DUMMY = 3, + SPELL_EFFECT_PORTAL_TELEPORT = 4, + SPELL_EFFECT_TELEPORT_UNITS = 5, + SPELL_EFFECT_APPLY_AURA = 6, + SPELL_EFFECT_ENVIRONMENTAL_DAMAGE = 7, + SPELL_EFFECT_POWER_DRAIN = 8, + SPELL_EFFECT_HEALTH_LEECH = 9, + SPELL_EFFECT_HEAL = 10, + SPELL_EFFECT_BIND = 11, + SPELL_EFFECT_PORTAL = 12, + SPELL_EFFECT_RITUAL_BASE = 13, + SPELL_EFFECT_RITUAL_SPECIALIZE = 14, + SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL = 15, + SPELL_EFFECT_QUEST_COMPLETE = 16, + SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL = 17, + SPELL_EFFECT_RESURRECT = 18, + SPELL_EFFECT_ADD_EXTRA_ATTACKS = 19, + SPELL_EFFECT_DODGE = 20, + SPELL_EFFECT_EVADE = 21, + SPELL_EFFECT_PARRY = 22, + SPELL_EFFECT_BLOCK = 23, + SPELL_EFFECT_CREATE_ITEM = 24, + SPELL_EFFECT_WEAPON = 25, + SPELL_EFFECT_DEFENSE = 26, + SPELL_EFFECT_PERSISTENT_AREA_AURA = 27, + SPELL_EFFECT_SUMMON = 28, + SPELL_EFFECT_LEAP = 29, + SPELL_EFFECT_ENERGIZE = 30, + SPELL_EFFECT_WEAPON_PERCENT_DAMAGE = 31, + SPELL_EFFECT_TRIGGER_MISSILE = 32, + SPELL_EFFECT_OPEN_LOCK = 33, + SPELL_EFFECT_SUMMON_CHANGE_ITEM = 34, + SPELL_EFFECT_APPLY_AREA_AURA_PARTY = 35, + SPELL_EFFECT_LEARN_SPELL = 36, + SPELL_EFFECT_SPELL_DEFENSE = 37, + SPELL_EFFECT_DISPEL = 38, + SPELL_EFFECT_LANGUAGE = 39, + SPELL_EFFECT_DUAL_WIELD = 40, + SPELL_EFFECT_JUMP = 41, + SPELL_EFFECT_JUMP2 = 42, + SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER= 43, + SPELL_EFFECT_SKILL_STEP = 44, + SPELL_EFFECT_ADD_HONOR = 45, + SPELL_EFFECT_SPAWN = 46, + SPELL_EFFECT_TRADE_SKILL = 47, + SPELL_EFFECT_STEALTH = 48, + SPELL_EFFECT_DETECT = 49, + SPELL_EFFECT_TRANS_DOOR = 50, + SPELL_EFFECT_FORCE_CRITICAL_HIT = 51, + SPELL_EFFECT_GUARANTEE_HIT = 52, + SPELL_EFFECT_ENCHANT_ITEM = 53, + SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY = 54, + SPELL_EFFECT_TAMECREATURE = 55, + SPELL_EFFECT_SUMMON_PET = 56, + SPELL_EFFECT_LEARN_PET_SPELL = 57, + SPELL_EFFECT_WEAPON_DAMAGE = 58, + SPELL_EFFECT_CREATE_RANDOM_ITEM = 59, + SPELL_EFFECT_PROFICIENCY = 60, + SPELL_EFFECT_SEND_EVENT = 61, + SPELL_EFFECT_POWER_BURN = 62, + SPELL_EFFECT_THREAT = 63, + SPELL_EFFECT_TRIGGER_SPELL = 64, + SPELL_EFFECT_APPLY_AREA_AURA_RAID = 65, + SPELL_EFFECT_CREATE_MANA_GEM = 66, + SPELL_EFFECT_HEAL_MAX_HEALTH = 67, + SPELL_EFFECT_INTERRUPT_CAST = 68, + SPELL_EFFECT_DISTRACT = 69, + SPELL_EFFECT_PULL = 70, + SPELL_EFFECT_PICKPOCKET = 71, + SPELL_EFFECT_ADD_FARSIGHT = 72, + SPELL_EFFECT_UNTRAIN_TALENTS = 73, + SPELL_EFFECT_APPLY_GLYPH = 74, + SPELL_EFFECT_HEAL_MECHANICAL = 75, + SPELL_EFFECT_SUMMON_OBJECT_WILD = 76, + SPELL_EFFECT_SCRIPT_EFFECT = 77, + SPELL_EFFECT_ATTACK = 78, + SPELL_EFFECT_SANCTUARY = 79, + SPELL_EFFECT_ADD_COMBO_POINTS = 80, + SPELL_EFFECT_CREATE_HOUSE = 81, + SPELL_EFFECT_BIND_SIGHT = 82, + SPELL_EFFECT_DUEL = 83, + SPELL_EFFECT_STUCK = 84, + SPELL_EFFECT_SUMMON_PLAYER = 85, + SPELL_EFFECT_ACTIVATE_OBJECT = 86, + SPELL_EFFECT_WMO_DAMAGE = 87, + SPELL_EFFECT_WMO_REPAIR = 88, + SPELL_EFFECT_WMO_CHANGE = 89, + SPELL_EFFECT_KILL_CREDIT = 90, + SPELL_EFFECT_THREAT_ALL = 91, + SPELL_EFFECT_ENCHANT_HELD_ITEM = 92, + SPELL_EFFECT_FORCE_DESELECT = 93, + SPELL_EFFECT_SELF_RESURRECT = 94, + SPELL_EFFECT_SKINNING = 95, + SPELL_EFFECT_CHARGE = 96, + SPELL_EFFECT_CAST_BUTTON = 97, + SPELL_EFFECT_KNOCK_BACK = 98, + SPELL_EFFECT_DISENCHANT = 99, + SPELL_EFFECT_INEBRIATE = 100, + SPELL_EFFECT_FEED_PET = 101, + SPELL_EFFECT_DISMISS_PET = 102, + SPELL_EFFECT_REPUTATION = 103, + SPELL_EFFECT_SUMMON_OBJECT_SLOT1 = 104, + SPELL_EFFECT_SUMMON_OBJECT_SLOT2 = 105, + SPELL_EFFECT_SUMMON_OBJECT_SLOT3 = 106, + SPELL_EFFECT_SUMMON_OBJECT_SLOT4 = 107, + SPELL_EFFECT_DISPEL_MECHANIC = 108, + SPELL_EFFECT_SUMMON_DEAD_PET = 109, + SPELL_EFFECT_DESTROY_ALL_TOTEMS = 110, + SPELL_EFFECT_DURABILITY_DAMAGE = 111, + SPELL_EFFECT_112 = 112, + SPELL_EFFECT_RESURRECT_NEW = 113, + SPELL_EFFECT_ATTACK_ME = 114, + SPELL_EFFECT_DURABILITY_DAMAGE_PCT = 115, + SPELL_EFFECT_SKIN_PLAYER_CORPSE = 116, + SPELL_EFFECT_SPIRIT_HEAL = 117, + SPELL_EFFECT_SKILL = 118, + SPELL_EFFECT_APPLY_AREA_AURA_PET = 119, + SPELL_EFFECT_TELEPORT_GRAVEYARD = 120, + SPELL_EFFECT_NORMALIZED_WEAPON_DMG = 121, + SPELL_EFFECT_122 = 122, + SPELL_EFFECT_SEND_TAXI = 123, + SPELL_EFFECT_PLAYER_PULL = 124, + SPELL_EFFECT_MODIFY_THREAT_PERCENT = 125, + SPELL_EFFECT_STEAL_BENEFICIAL_BUFF = 126, + SPELL_EFFECT_PROSPECTING = 127, + SPELL_EFFECT_APPLY_AREA_AURA_FRIEND = 128, + SPELL_EFFECT_APPLY_AREA_AURA_ENEMY = 129, + SPELL_EFFECT_REDIRECT_THREAT = 130, + SPELL_EFFECT_131 = 131, + SPELL_EFFECT_PLAY_MUSIC = 132, + SPELL_EFFECT_UNLEARN_SPECIALIZATION = 133, + SPELL_EFFECT_KILL_CREDIT2 = 134, + SPELL_EFFECT_CALL_PET = 135, + SPELL_EFFECT_HEAL_PCT = 136, + SPELL_EFFECT_ENERGIZE_PCT = 137, + SPELL_EFFECT_LEAP_BACK = 138, + SPELL_EFFECT_CLEAR_QUEST = 139, + SPELL_EFFECT_FORCE_CAST = 140, + SPELL_EFFECT_141 = 141, + SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE = 142, + SPELL_EFFECT_APPLY_AREA_AURA_OWNER = 143, + SPELL_EFFECT_KNOCK_BACK_2 = 144, + SPELL_EFFECT_145 = 145, + SPELL_EFFECT_ACTIVATE_RUNE = 146, + SPELL_EFFECT_QUEST_FAIL = 147, + SPELL_EFFECT_148 = 148, + SPELL_EFFECT_149 = 149, + SPELL_EFFECT_150 = 150, + SPELL_EFFECT_TRIGGER_SPELL_2 = 151, + SPELL_EFFECT_152 = 152, + SPELL_EFFECT_153 = 153, + SPELL_EFFECT_154 = 154, + SPELL_EFFECT_TITAN_GRIP = 155, + SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC = 156, + SPELL_EFFECT_CREATE_ITEM_2 = 157, + SPELL_EFFECT_MILLING = 158, + SPELL_EFFECT_ALLOW_RENAME_PET = 159, + SPELL_EFFECT_160 = 160, + SPELL_EFFECT_TALENT_SPEC_COUNT = 161, + SPELL_EFFECT_TALENT_SPEC_SELECT = 162, + SPELL_EFFECT_163 = 163, + SPELL_EFFECT_164 = 164, + TOTAL_SPELL_EFFECTS = 165 +}; + +enum SpellCastResult +{ + SPELL_FAILED_SUCCESS = 0, + SPELL_FAILED_AFFECTING_COMBAT = 1, + SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 2, + SPELL_FAILED_ALREADY_AT_FULL_MANA = 3, + SPELL_FAILED_ALREADY_AT_FULL_POWER = 4, + SPELL_FAILED_ALREADY_BEING_TAMED = 5, + SPELL_FAILED_ALREADY_HAVE_CHARM = 6, + SPELL_FAILED_ALREADY_HAVE_SUMMON = 7, + SPELL_FAILED_ALREADY_OPEN = 8, + SPELL_FAILED_AURA_BOUNCED = 9, + SPELL_FAILED_AUTOTRACK_INTERRUPTED = 10, + SPELL_FAILED_BAD_IMPLICIT_TARGETS = 11, + SPELL_FAILED_BAD_TARGETS = 12, + SPELL_FAILED_CANT_BE_CHARMED = 13, + SPELL_FAILED_CANT_BE_DISENCHANTED = 14, + SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 15, + SPELL_FAILED_CANT_BE_MILLED = 16, + SPELL_FAILED_CANT_BE_PROSPECTED = 17, + SPELL_FAILED_CANT_CAST_ON_TAPPED = 18, + SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 19, + SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 20, + SPELL_FAILED_CANT_STEALTH = 21, + SPELL_FAILED_CASTER_AURASTATE = 22, + SPELL_FAILED_CASTER_DEAD = 23, + SPELL_FAILED_CHARMED = 24, + SPELL_FAILED_CHEST_IN_USE = 25, + SPELL_FAILED_CONFUSED = 26, + SPELL_FAILED_DONT_REPORT = 27, + SPELL_FAILED_EQUIPPED_ITEM = 28, + SPELL_FAILED_EQUIPPED_ITEM_CLASS = 29, + SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 30, + SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 31, + SPELL_FAILED_ERROR = 32, + SPELL_FAILED_FIZZLE = 33, + SPELL_FAILED_FLEEING = 34, + SPELL_FAILED_FOOD_LOWLEVEL = 35, + SPELL_FAILED_HIGHLEVEL = 36, + SPELL_FAILED_HUNGER_SATIATED = 37, + SPELL_FAILED_IMMUNE = 38, + SPELL_FAILED_INCORRECT_AREA = 39, + SPELL_FAILED_INTERRUPTED = 40, + SPELL_FAILED_INTERRUPTED_COMBAT = 41, + SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 42, + SPELL_FAILED_ITEM_GONE = 43, + SPELL_FAILED_ITEM_NOT_FOUND = 44, + SPELL_FAILED_ITEM_NOT_READY = 45, + SPELL_FAILED_LEVEL_REQUIREMENT = 46, + SPELL_FAILED_LINE_OF_SIGHT = 47, + SPELL_FAILED_LOWLEVEL = 48, + SPELL_FAILED_LOW_CASTLEVEL = 49, + SPELL_FAILED_MAINHAND_EMPTY = 50, + SPELL_FAILED_MOVING = 51, + SPELL_FAILED_NEED_AMMO = 52, + SPELL_FAILED_NEED_AMMO_POUCH = 53, + SPELL_FAILED_NEED_EXOTIC_AMMO = 54, + SPELL_FAILED_NEED_MORE_ITEMS = 55, + SPELL_FAILED_NOPATH = 56, + SPELL_FAILED_NOT_BEHIND = 57, + SPELL_FAILED_NOT_FISHABLE = 58, + SPELL_FAILED_NOT_FLYING = 59, + SPELL_FAILED_NOT_HERE = 60, + SPELL_FAILED_NOT_INFRONT = 61, + SPELL_FAILED_NOT_IN_CONTROL = 62, + SPELL_FAILED_NOT_KNOWN = 63, + SPELL_FAILED_NOT_MOUNTED = 64, + SPELL_FAILED_NOT_ON_TAXI = 65, + SPELL_FAILED_NOT_ON_TRANSPORT = 66, + SPELL_FAILED_NOT_READY = 67, + SPELL_FAILED_NOT_SHAPESHIFT = 68, + SPELL_FAILED_NOT_STANDING = 69, + SPELL_FAILED_NOT_TRADEABLE = 70, + SPELL_FAILED_NOT_TRADING = 71, + SPELL_FAILED_NOT_UNSHEATHED = 72, + SPELL_FAILED_NOT_WHILE_GHOST = 73, + SPELL_FAILED_NOT_WHILE_LOOTING = 74, + SPELL_FAILED_NO_AMMO = 75, + SPELL_FAILED_NO_CHARGES_REMAIN = 76, + SPELL_FAILED_NO_CHAMPION = 77, + SPELL_FAILED_NO_COMBO_POINTS = 78, + SPELL_FAILED_NO_DUELING = 79, + SPELL_FAILED_NO_ENDURANCE = 80, + SPELL_FAILED_NO_FISH = 81, + SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 82, + SPELL_FAILED_NO_MOUNTS_ALLOWED = 83, + SPELL_FAILED_NO_PET = 84, + SPELL_FAILED_NO_POWER = 85, + SPELL_FAILED_NOTHING_TO_DISPEL = 86, + SPELL_FAILED_NOTHING_TO_STEAL = 87, + SPELL_FAILED_ONLY_ABOVEWATER = 88, + SPELL_FAILED_ONLY_DAYTIME = 89, + SPELL_FAILED_ONLY_INDOORS = 90, + SPELL_FAILED_ONLY_MOUNTED = 91, + SPELL_FAILED_ONLY_NIGHTTIME = 92, + SPELL_FAILED_ONLY_OUTDOORS = 93, + SPELL_FAILED_ONLY_SHAPESHIFT = 94, + SPELL_FAILED_ONLY_STEALTHED = 95, + SPELL_FAILED_ONLY_UNDERWATER = 96, + SPELL_FAILED_OUT_OF_RANGE = 97, + SPELL_FAILED_PACIFIED = 98, + SPELL_FAILED_POSSESSED = 99, + SPELL_FAILED_REAGENTS = 100, + SPELL_FAILED_REQUIRES_AREA = 101, + SPELL_FAILED_REQUIRES_SPELL_FOCUS = 102, + SPELL_FAILED_ROOTED = 103, + SPELL_FAILED_SILENCED = 104, + SPELL_FAILED_SPELL_IN_PROGRESS = 105, + SPELL_FAILED_SPELL_LEARNED = 106, + SPELL_FAILED_SPELL_UNAVAILABLE = 107, + SPELL_FAILED_STUNNED = 108, + SPELL_FAILED_TARGETS_DEAD = 109, + SPELL_FAILED_TARGET_AFFECTING_COMBAT = 110, + SPELL_FAILED_TARGET_AURASTATE = 111, + SPELL_FAILED_TARGET_DUELING = 112, + SPELL_FAILED_TARGET_ENEMY = 113, + SPELL_FAILED_TARGET_ENRAGED = 114, + SPELL_FAILED_TARGET_FRIENDLY = 115, + SPELL_FAILED_TARGET_IN_COMBAT = 116, + SPELL_FAILED_TARGET_IS_PLAYER = 117, + SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 118, + SPELL_FAILED_TARGET_NOT_DEAD = 119, + SPELL_FAILED_TARGET_NOT_IN_PARTY = 120, + SPELL_FAILED_TARGET_NOT_LOOTED = 121, + SPELL_FAILED_TARGET_NOT_PLAYER = 122, + SPELL_FAILED_TARGET_NO_POCKETS = 123, + SPELL_FAILED_TARGET_NO_WEAPONS = 124, + SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 125, + SPELL_FAILED_TARGET_UNSKINNABLE = 126, + SPELL_FAILED_THIRST_SATIATED = 127, + SPELL_FAILED_TOO_CLOSE = 128, + SPELL_FAILED_TOO_MANY_OF_ITEM = 129, + SPELL_FAILED_TOTEM_CATEGORY = 130, + SPELL_FAILED_TOTEMS = 131, + SPELL_FAILED_TRY_AGAIN = 132, + SPELL_FAILED_UNIT_NOT_BEHIND = 133, + SPELL_FAILED_UNIT_NOT_INFRONT = 134, + SPELL_FAILED_WRONG_PET_FOOD = 135, + SPELL_FAILED_NOT_WHILE_FATIGUED = 136, + SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 137, + SPELL_FAILED_NOT_WHILE_TRADING = 138, + SPELL_FAILED_TARGET_NOT_IN_RAID = 139, + SPELL_FAILED_TARGET_FREEFORALL = 140, + SPELL_FAILED_NO_EDIBLE_CORPSES = 141, + SPELL_FAILED_ONLY_BATTLEGROUNDS = 142, + SPELL_FAILED_TARGET_NOT_GHOST = 143, + SPELL_FAILED_TRANSFORM_UNUSABLE = 144, + SPELL_FAILED_WRONG_WEATHER = 145, + SPELL_FAILED_DAMAGE_IMMUNE = 146, + SPELL_FAILED_PREVENTED_BY_MECHANIC = 147, + SPELL_FAILED_PLAY_TIME = 148, + SPELL_FAILED_REPUTATION = 149, + SPELL_FAILED_MIN_SKILL = 150, + SPELL_FAILED_NOT_IN_ARENA = 151, + SPELL_FAILED_NOT_ON_SHAPESHIFT = 152, + SPELL_FAILED_NOT_ON_STEALTHED = 153, + SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 154, + SPELL_FAILED_NOT_ON_MOUNTED = 155, + SPELL_FAILED_TOO_SHALLOW = 156, + SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 157, + SPELL_FAILED_TARGET_IS_TRIVIAL = 158, + SPELL_FAILED_BM_OR_INVISGOD = 159, + SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 160, + SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 161, + SPELL_FAILED_NOT_IDLE = 162, + SPELL_FAILED_NOT_INACTIVE = 163, + SPELL_FAILED_PARTIAL_PLAYTIME = 164, + SPELL_FAILED_NO_PLAYTIME = 165, + SPELL_FAILED_NOT_IN_BATTLEGROUND = 166, + SPELL_FAILED_NOT_IN_RAID_INSTANCE = 167, + SPELL_FAILED_ONLY_IN_ARENA = 168, + SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 169, + SPELL_FAILED_ON_USE_ENCHANT = 170, + SPELL_FAILED_NOT_ON_GROUND = 171, + SPELL_FAILED_CUSTOM_ERROR = 172, + SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 173, + SPELL_FAILED_TOO_MANY_SOCKETS = 174, + SPELL_FAILED_INVALID_GLYPH = 175, + SPELL_FAILED_UNIQUE_GLYPH = 176, + SPELL_FAILED_GLYPH_SOCKET_LOCKED = 177, + SPELL_FAILED_NO_VALID_TARGETS = 178, + SPELL_FAILED_ITEM_AT_MAX_CHARGES = 179, + SPELL_FAILED_NOT_IN_BARBERSHOP = 180, + SPELL_FAILED_FISHING_TOO_LOW = 181, + SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW = 182, + SPELL_FAILED_SUMMON_PENDING = 183, + SPELL_FAILED_MAX_SOCKETS = 184, + SPELL_FAILED_PET_CAN_RENAME = 185, + SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED = 186, + SPELL_FAILED_UNKNOWN = 187, // actually doesn't exist in client + + SPELL_CAST_OK = 255 // custom value, don't must be send to client +}; + +// Spell aura states +enum AuraState +{ // (C) used in caster aura state (T) used in target aura state + // (c) used in caster aura state-not (t) used in target aura state-not + AURA_STATE_NONE = 0, // C | + AURA_STATE_DEFENSE = 1, // C | + AURA_STATE_HEALTHLESS_20_PERCENT = 2, // CcT | + AURA_STATE_BERSERKING = 3, // C T | + AURA_STATE_FROZEN = 4, // c t| frozen target + AURA_STATE_JUDGEMENT = 5, // C | + //AURA_STATE_UNKNOWN6 = 6, // | not used + AURA_STATE_HUNTER_PARRY = 7, // C | + //AURA_STATE_UNKNOWN7 = 7, // c | creature cheap shot / focused bursts spells + //AURA_STATE_UNKNOWN8 = 8, // t| test spells + //AURA_STATE_UNKNOWN9 = 9, // | + AURA_STATE_WARRIOR_VICTORY_RUSH = 10, // C | warrior victory rush + //AURA_STATE_UNKNOWN11 = 11, // C t| 60348 - Maelstrom Ready!, test spells + AURA_STATE_FAERIE_FIRE = 12, // c t| + AURA_STATE_HEALTHLESS_35_PERCENT = 13, // C T | + AURA_STATE_CONFLAGRATE = 14, // T | + AURA_STATE_SWIFTMEND = 15, // T | + AURA_STATE_DEADLY_POISON = 16, // T | + AURA_STATE_ENRAGE = 17, // C | + AURA_STATE_BLEEDING = 18, // T| + //AURA_STATE_UNKNOWN19 = 19, // | not used + //AURA_STATE_UNKNOWN20 = 20, // c | only (45317 Suicide) + //AURA_STATE_UNKNOWN21 = 21, // | not used + //AURA_STATE_UNKNOWN22 = 22, // C t| varius spells (63884, 50240) + AURA_STATE_HEALTH_ABOVE_75_PERCENT = 23, // C | +}; + +#define PER_CASTER_AURA_STATE_MASK (\ + (1<<(AURA_STATE_CONFLAGRATE-1))|(1<<(AURA_STATE_DEADLY_POISON-1))) + +// Spell mechanics +enum Mechanics +{ + MECHANIC_NONE = 0, + MECHANIC_CHARM = 1, + MECHANIC_DISORIENTED = 2, + MECHANIC_DISARM = 3, + MECHANIC_DISTRACT = 4, + MECHANIC_FEAR = 5, + MECHANIC_GRIP = 6, + MECHANIC_ROOT = 7, + MECHANIC_PACIFY = 8, //0 spells use this mechanic + MECHANIC_SILENCE = 9, + MECHANIC_SLEEP = 10, + MECHANIC_SNARE = 11, + MECHANIC_STUN = 12, + MECHANIC_FREEZE = 13, + MECHANIC_KNOCKOUT = 14, + MECHANIC_BLEED = 15, + MECHANIC_BANDAGE = 16, + MECHANIC_POLYMORPH = 17, + MECHANIC_BANISH = 18, + MECHANIC_SHIELD = 19, + MECHANIC_SHACKLE = 20, + MECHANIC_MOUNT = 21, + MECHANIC_INFECTED = 22, + MECHANIC_TURN = 23, + MECHANIC_HORROR = 24, + MECHANIC_INVULNERABILITY = 25, + MECHANIC_INTERRUPT = 26, + MECHANIC_DAZE = 27, + MECHANIC_DISCOVERY = 28, + MECHANIC_IMMUNE_SHIELD = 29, // Divine (Blessing) Shield/Protection and Ice Block + MECHANIC_SAPPED = 30, + MECHANIC_ENRAGED = 31 +}; + +// Used for spell 42292 Immune Movement Impairment and Loss of Control (0x49967da6) +#define IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK (\ + (1<(only this effect in the spell) can't cast to it, +//some aura(related to Mechanics or ImmuneToState) can't apply to it. +enum SpellImmunity +{ + IMMUNITY_EFFECT = 0, // enum SpellEffects + IMMUNITY_STATE = 1, // enum AuraType + IMMUNITY_SCHOOL = 2, // enum SpellSchoolMask + IMMUNITY_DAMAGE = 3, // enum SpellSchoolMask + IMMUNITY_DISPEL = 4, // enum DispelType + IMMUNITY_MECHANIC = 5, // enum Mechanics + IMMUNITY_ID = 6 +}; + +#define MAX_SPELL_IMMUNITY 7 + +enum Targets +{ + TARGET_UNIT_CASTER = 1, + TARGET_UNIT_NEARBY_ENEMY = 2, + TARGET_UNIT_NEARBY_ALLY = 3, + TARGET_UNIT_NEARBY_ALLY_UNK = 4, + TARGET_UNIT_PET = 5, + TARGET_UNIT_TARGET_ENEMY = 6, + TARGET_UNIT_AREA_ENTRY_SRC = 7, + TARGET_UNIT_AREA_ENTRY_DST = 8, + TARGET_DST_HOME = 9, // uses in teleport to innkeeper spells + TARGET_UNIT_TARGET_DEST_CASTER = 11, // teleport target to caster + TARGET_UNIT_AREA_ENEMY_SRC = 15, + TARGET_UNIT_AREA_ENEMY_DST = 16, + TARGET_DST_DB = 17, // uses in teleport spells and some other + TARGET_DST_CASTER = 18, + TARGET_UNIT_PARTY_CASTER = 20, + TARGET_UNIT_TARGET_ALLY = 21, + TARGET_SRC_CASTER = 22, + TARGET_GAMEOBJECT = 23, + //TARGET_OBJECT_OPEN + TARGET_UNIT_CONE_ENEMY = 24, + TARGET_UNIT_TARGET_ANY = 25, + TARGET_GAMEOBJECT_ITEM = 26, + //TARGET_OBJECT_ITEM_PICKLOCK + TARGET_UNIT_MASTER = 27, + TARGET_DEST_DYNOBJ_ENEMY = 28, + TARGET_DEST_DYNOBJ_ALLY = 29, // only for effect 27 + TARGET_UNIT_AREA_ALLY_SRC = 30, // in TargetB used only with TARGET_SRC_CASTER and in self casting range in TargetA + TARGET_UNIT_AREA_ALLY_DST = 31, + TARGET_MINION = 32, + //TARGET_DEST_SUMMON + TARGET_UNIT_AREA_PARTY_SRC = 33, + TARGET_UNIT_AREA_PARTY_DST = 34, // used in Tranquility + TARGET_UNIT_TARGET_PARTY = 35, + TARGET_DEST_CASTER_RANDOM_UNKNOWN = 36, //unknown + TARGET_UNIT_PARTY_TARGET = 37, + TARGET_UNIT_NEARBY_ENTRY = 38, + TARGET_UNIT_CASTER_FISHING = 39, + TARGET_GAMEOBJECT_NEARBY_ENTRY = 40, + TARGET_DEST_CASTER_FRONT_LEFT = 41, //earth totem + TARGET_DEST_CASTER_BACK_LEFT = 42, //water totem + TARGET_DEST_CASTER_BACK_RIGHT = 43, //air totem + TARGET_DEST_CASTER_FRONT_RIGHT = 44, //fire totem + TARGET_UNIT_CHAINHEAL = 45, + TARGET_DST_NEARBY_ENTRY = 46, + TARGET_DEST_CASTER_FRONT = 47, + TARGET_DEST_CASTER_BACK = 48, + TARGET_DEST_CASTER_RIGHT = 49, + TARGET_DEST_CASTER_LEFT = 50, + TARGET_OBJECT_AREA_SRC = 51, + TARGET_OBJECT_AREA_DST = 52, + TARGET_DST_TARGET_ENEMY = 53, // set unit coordinates as dest, only 16 target B imlemented + TARGET_UNIT_CONE_ENEMY_UNKNOWN = 54, // 180 degree, or different angle + TARGET_DEST_CASTER_FRONT_LEAP = 55, // for a leap spell + TARGET_UNIT_RAID_CASTER = 56, + TARGET_UNIT_TARGET_RAID = 57, + TARGET_UNIT_NEARBY_RAID = 58, + TARGET_UNIT_CONE_ALLY = 59, + TARGET_UNIT_CONE_ENTRY = 60, + TARGET_UNIT_CLASS_TARGET = 61, + TARGET_TEST = 62, // for a test spell + TARGET_DEST_TARGET_ANY = 63, + TARGET_DEST_TARGET_FRONT = 64, + TARGET_DEST_TARGET_BACK = 65, // uses in teleport behind spells + TARGET_DEST_TARGET_RIGHT = 66, + TARGET_DEST_TARGET_LEFT = 67, + TARGET_DEST_TARGET_FRONT_LEFT = 68, + TARGET_DEST_TARGET_BACK_LEFT = 69, + TARGET_DEST_TARGET_BACK_RIGHT = 70, + TARGET_DEST_TARGET_FRONT_RIGHT = 71, + TARGET_DEST_CASTER_RANDOM = 72, + TARGET_DEST_CASTER_RADIUS = 73, + TARGET_DEST_TARGET_RANDOM = 74, + TARGET_DEST_TARGET_RADIUS = 75, + TARGET_DEST_CHANNEL = 76, + TARGET_UNIT_CHANNEL = 77, + TARGET_DEST_DEST_FRONT = 78, + TARGET_DEST_DEST_BACK = 79, + TARGET_DEST_DEST_RIGHT = 80, + TARGET_DEST_DEST_LEFT = 81, + TARGET_DEST_DEST_FRONT_LEFT = 82, + TARGET_DEST_DEST_BACK_LEFT = 83, + TARGET_DEST_DEST_BACK_RIGHT = 84, + TARGET_DEST_DEST_FRONT_RIGHT = 85, + TARGET_DEST_DEST_RANDOM = 86, + TARGET_DEST_DEST = 87, + TARGET_DEST_DYNOBJ_NONE = 88, + TARGET_DEST_TRAJ = 89, + TARGET_UNIT_MINIPET = 90, + TARGET_DEST_DEST_RANDOM_DIR_DIST = 91, + TARGET_UNIT_UNK_92 = 92, + TARGET_CORPSE_AREA_ENEMY_PLAYER_SRC= 93, + TARGET_UNIT_VEHICLE = 94, + TARGET_UNIT_DRIVER = 95, + TARGET_UNIT_PASSENGER_0 = 96, + TARGET_UNIT_PASSENGER_1 = 97, + TARGET_UNIT_PASSENGER_2 = 98, + TARGET_UNIT_PASSENGER_3 = 99, + TARGET_UNIT_PASSENGER_4 = 100, + TARGET_UNIT_PASSENGER_5 = 101, + TARGET_UNIT_PASSENGER_6 = 102, + TARGET_UNIT_PASSENGER_7 = 103, + TARGET_UNIT_AREA_PATH = 104, + TARGET_UNIT_UNK_105 = 105, // 1 spell + TARGET_DEST_UNK_110 = 110, // some kind of traj? +}; + +#define TOTAL_SPELL_TARGETS 105 + +enum SpellMissInfo +{ + SPELL_MISS_NONE = 0, + SPELL_MISS_MISS = 1, + SPELL_MISS_RESIST = 2, + SPELL_MISS_DODGE = 3, + SPELL_MISS_PARRY = 4, + SPELL_MISS_BLOCK = 5, + SPELL_MISS_EVADE = 6, + SPELL_MISS_IMMUNE = 7, + SPELL_MISS_IMMUNE2 = 8, + SPELL_MISS_DEFLECT = 9, + SPELL_MISS_ABSORB = 10, + SPELL_MISS_REFLECT = 11 +}; + +enum SpellHitType +{ + SPELL_HIT_TYPE_UNK1 = 0x00001, + SPELL_HIT_TYPE_CRIT = 0x00002, + SPELL_HIT_TYPE_UNK3 = 0x00004, + SPELL_HIT_TYPE_UNK4 = 0x00008, + SPELL_HIT_TYPE_UNK5 = 0x00010, // replace caster? + SPELL_HIT_TYPE_UNK6 = 0x00020 +}; + +enum SpellDmgClass +{ + SPELL_DAMAGE_CLASS_NONE = 0, + SPELL_DAMAGE_CLASS_MAGIC = 1, + SPELL_DAMAGE_CLASS_MELEE = 2, + SPELL_DAMAGE_CLASS_RANGED = 3 +}; + +enum SpellPreventionType +{ + SPELL_PREVENTION_TYPE_NONE = 0, + SPELL_PREVENTION_TYPE_SILENCE = 1, + SPELL_PREVENTION_TYPE_PACIFY = 2 +}; + +enum GameobjectTypes +{ + GAMEOBJECT_TYPE_DOOR = 0, + GAMEOBJECT_TYPE_BUTTON = 1, + GAMEOBJECT_TYPE_QUESTGIVER = 2, + GAMEOBJECT_TYPE_CHEST = 3, + GAMEOBJECT_TYPE_BINDER = 4, + GAMEOBJECT_TYPE_GENERIC = 5, + GAMEOBJECT_TYPE_TRAP = 6, + GAMEOBJECT_TYPE_CHAIR = 7, + GAMEOBJECT_TYPE_SPELL_FOCUS = 8, + GAMEOBJECT_TYPE_TEXT = 9, + GAMEOBJECT_TYPE_GOOBER = 10, + GAMEOBJECT_TYPE_TRANSPORT = 11, + GAMEOBJECT_TYPE_AREADAMAGE = 12, + GAMEOBJECT_TYPE_CAMERA = 13, + GAMEOBJECT_TYPE_MAP_OBJECT = 14, + GAMEOBJECT_TYPE_MO_TRANSPORT = 15, + GAMEOBJECT_TYPE_DUEL_ARBITER = 16, + GAMEOBJECT_TYPE_FISHINGNODE = 17, + GAMEOBJECT_TYPE_SUMMONING_RITUAL = 18, + GAMEOBJECT_TYPE_MAILBOX = 19, + GAMEOBJECT_TYPE_DO_NOT_USE = 20, + GAMEOBJECT_TYPE_GUARDPOST = 21, + GAMEOBJECT_TYPE_SPELLCASTER = 22, + GAMEOBJECT_TYPE_MEETINGSTONE = 23, + GAMEOBJECT_TYPE_FLAGSTAND = 24, + GAMEOBJECT_TYPE_FISHINGHOLE = 25, + GAMEOBJECT_TYPE_FLAGDROP = 26, + GAMEOBJECT_TYPE_MINI_GAME = 27, + GAMEOBJECT_TYPE_DO_NOT_USE_2 = 28, + GAMEOBJECT_TYPE_CAPTURE_POINT = 29, + GAMEOBJECT_TYPE_AURA_GENERATOR = 30, + GAMEOBJECT_TYPE_DUNGEON_DIFFICULTY = 31, + GAMEOBJECT_TYPE_BARBER_CHAIR = 32, + GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING = 33, + GAMEOBJECT_TYPE_GUILD_BANK = 34, + GAMEOBJECT_TYPE_TRAPDOOR = 35 +}; + +#define MAX_GAMEOBJECT_TYPE 36 // sending to client this or greater value can crash client. + +#define GAMEOBJECT_FISHINGNODE_ENTRY 35591 // Better to define it somewhere instead of hardcoding everywhere + +enum GameObjectFlags +{ + GO_FLAG_IN_USE = 0x00000001, //disables interaction while animated + GO_FLAG_LOCKED = 0x00000002, //require key, spell, event, etc to be opened. Makes "Locked" appear in tooltip + GO_FLAG_INTERACT_COND = 0x00000004, //cannot interact (condition to interact) + GO_FLAG_TRANSPORT = 0x00000008, //any kind of transport? Object can transport (elevator, boat, car) + GO_FLAG_UNK1 = 0x00000010, // + GO_FLAG_NODESPAWN = 0x00000020, //never despawn, typically for doors, they just change state + GO_FLAG_TRIGGERED = 0x00000040, //typically, summoned objects. Triggered by spell or other events + GO_FLAG_DAMAGED = 0x00000200, + GO_FLAG_DESTROYED = 0x00000400, +}; + +enum TextEmotes +{ + TEXTEMOTE_AGREE = 1, + TEXTEMOTE_AMAZE = 2, + TEXTEMOTE_ANGRY = 3, + TEXTEMOTE_APOLOGIZE = 4, + TEXTEMOTE_APPLAUD = 5, + TEXTEMOTE_BASHFUL = 6, + TEXTEMOTE_BECKON = 7, + TEXTEMOTE_BEG = 8, + TEXTEMOTE_BITE = 9, + TEXTEMOTE_BLEED = 10, + TEXTEMOTE_BLINK = 11, + TEXTEMOTE_BLUSH = 12, + TEXTEMOTE_BONK = 13, + TEXTEMOTE_BORED = 14, + TEXTEMOTE_BOUNCE = 15, + TEXTEMOTE_BRB = 16, + TEXTEMOTE_BOW = 17, + TEXTEMOTE_BURP = 18, + TEXTEMOTE_BYE = 19, + TEXTEMOTE_CACKLE = 20, + TEXTEMOTE_CHEER = 21, + TEXTEMOTE_CHICKEN = 22, + TEXTEMOTE_CHUCKLE = 23, + TEXTEMOTE_CLAP = 24, + TEXTEMOTE_CONFUSED = 25, + TEXTEMOTE_CONGRATULATE = 26, + TEXTEMOTE_COUGH = 27, + TEXTEMOTE_COWER = 28, + TEXTEMOTE_CRACK = 29, + TEXTEMOTE_CRINGE = 30, + TEXTEMOTE_CRY = 31, + TEXTEMOTE_CURIOUS = 32, + TEXTEMOTE_CURTSEY = 33, + TEXTEMOTE_DANCE = 34, + TEXTEMOTE_DRINK = 35, + TEXTEMOTE_DROOL = 36, + TEXTEMOTE_EAT = 37, + TEXTEMOTE_EYE = 38, + TEXTEMOTE_FART = 39, + TEXTEMOTE_FIDGET = 40, + TEXTEMOTE_FLEX = 41, + TEXTEMOTE_FROWN = 42, + TEXTEMOTE_GASP = 43, + TEXTEMOTE_GAZE = 44, + TEXTEMOTE_GIGGLE = 45, + TEXTEMOTE_GLARE = 46, + TEXTEMOTE_GLOAT = 47, + TEXTEMOTE_GREET = 48, + TEXTEMOTE_GRIN = 49, + TEXTEMOTE_GROAN = 50, + TEXTEMOTE_GROVEL = 51, + TEXTEMOTE_GUFFAW = 52, + TEXTEMOTE_HAIL = 53, + TEXTEMOTE_HAPPY = 54, + TEXTEMOTE_HELLO = 55, + TEXTEMOTE_HUG = 56, + TEXTEMOTE_HUNGRY = 57, + TEXTEMOTE_KISS = 58, + TEXTEMOTE_KNEEL = 59, + TEXTEMOTE_LAUGH = 60, + TEXTEMOTE_LAYDOWN = 61, + TEXTEMOTE_MESSAGE = 62, + TEXTEMOTE_MOAN = 63, + TEXTEMOTE_MOON = 64, + TEXTEMOTE_MOURN = 65, + TEXTEMOTE_NO = 66, + TEXTEMOTE_NOD = 67, + TEXTEMOTE_NOSEPICK = 68, + TEXTEMOTE_PANIC = 69, + TEXTEMOTE_PEER = 70, + TEXTEMOTE_PLEAD = 71, + TEXTEMOTE_POINT = 72, + TEXTEMOTE_POKE = 73, + TEXTEMOTE_PRAY = 74, + TEXTEMOTE_ROAR = 75, + TEXTEMOTE_ROFL = 76, + TEXTEMOTE_RUDE = 77, + TEXTEMOTE_SALUTE = 78, + TEXTEMOTE_SCRATCH = 79, + TEXTEMOTE_SEXY = 80, + TEXTEMOTE_SHAKE = 81, + TEXTEMOTE_SHOUT = 82, + TEXTEMOTE_SHRUG = 83, + TEXTEMOTE_SHY = 84, + TEXTEMOTE_SIGH = 85, + TEXTEMOTE_SIT = 86, + TEXTEMOTE_SLEEP = 87, + TEXTEMOTE_SNARL = 88, + TEXTEMOTE_SPIT = 89, + TEXTEMOTE_STARE = 90, + TEXTEMOTE_SURPRISED = 91, + TEXTEMOTE_SURRENDER = 92, + TEXTEMOTE_TALK = 93, + TEXTEMOTE_TALKEX = 94, + TEXTEMOTE_TALKQ = 95, + TEXTEMOTE_TAP = 96, + TEXTEMOTE_THANK = 97, + TEXTEMOTE_THREATEN = 98, + TEXTEMOTE_TIRED = 99, + TEXTEMOTE_VICTORY = 100, + TEXTEMOTE_WAVE = 101, + TEXTEMOTE_WELCOME = 102, + TEXTEMOTE_WHINE = 103, + TEXTEMOTE_WHISTLE = 104, + TEXTEMOTE_WORK = 105, + TEXTEMOTE_YAWN = 106, + TEXTEMOTE_BOGGLE = 107, + TEXTEMOTE_CALM = 108, + TEXTEMOTE_COLD = 109, + TEXTEMOTE_COMFORT = 110, + TEXTEMOTE_CUDDLE = 111, + TEXTEMOTE_DUCK = 112, + TEXTEMOTE_INSULT = 113, + TEXTEMOTE_INTRODUCE = 114, + TEXTEMOTE_JK = 115, + TEXTEMOTE_LICK = 116, + TEXTEMOTE_LISTEN = 117, + TEXTEMOTE_LOST = 118, + TEXTEMOTE_MOCK = 119, + TEXTEMOTE_PONDER = 120, + TEXTEMOTE_POUNCE = 121, + TEXTEMOTE_PRAISE = 122, + TEXTEMOTE_PURR = 123, + TEXTEMOTE_PUZZLE = 124, + TEXTEMOTE_RAISE = 125, + TEXTEMOTE_READY = 126, + TEXTEMOTE_SHIMMY = 127, + TEXTEMOTE_SHIVER = 128, + TEXTEMOTE_SHOO = 129, + TEXTEMOTE_SLAP = 130, + TEXTEMOTE_SMIRK = 131, + TEXTEMOTE_SNIFF = 132, + TEXTEMOTE_SNUB = 133, + TEXTEMOTE_SOOTHE = 134, + TEXTEMOTE_STINK = 135, + TEXTEMOTE_TAUNT = 136, + TEXTEMOTE_TEASE = 137, + TEXTEMOTE_THIRSTY = 138, + TEXTEMOTE_VETO = 139, + TEXTEMOTE_SNICKER = 140, + TEXTEMOTE_STAND = 141, + TEXTEMOTE_TICKLE = 142, + TEXTEMOTE_VIOLIN = 143, + TEXTEMOTE_SMILE = 163, + TEXTEMOTE_RASP = 183, + TEXTEMOTE_PITY = 203, + TEXTEMOTE_GROWL = 204, + TEXTEMOTE_BARK = 205, + TEXTEMOTE_SCARED = 223, + TEXTEMOTE_FLOP = 224, + TEXTEMOTE_LOVE = 225, + TEXTEMOTE_MOO = 226, + TEXTEMOTE_OPENFIRE = 327, + TEXTEMOTE_FLIRT = 328, + TEXTEMOTE_JOKE = 329, + TEXTEMOTE_COMMEND = 243, + TEXTEMOTE_WINK = 363, + TEXTEMOTE_PAT = 364, + TEXTEMOTE_SERIOUS = 365, + TEXTEMOTE_MOUNTSPECIAL = 366, + TEXTEMOTE_GOODLUCK = 367, + TEXTEMOTE_BLAME = 368, + TEXTEMOTE_BLANK = 369, + TEXTEMOTE_BRANDISH = 370, + TEXTEMOTE_BREATH = 371, + TEXTEMOTE_DISAGREE = 372, + TEXTEMOTE_DOUBT = 373, + TEXTEMOTE_EMBARRASS = 374, + TEXTEMOTE_ENCOURAGE = 375, + TEXTEMOTE_ENEMY = 376, + TEXTEMOTE_EYEBROW = 377, + TEXTEMOTE_TOAST = 378 +}; + +enum Emote +{ + EMOTE_ONESHOT_NONE = 0, + EMOTE_ONESHOT_TALK = 1, + EMOTE_ONESHOT_BOW = 2, + EMOTE_ONESHOT_WAVE = 3, + EMOTE_ONESHOT_CHEER = 4, + EMOTE_ONESHOT_EXCLAMATION = 5, + EMOTE_ONESHOT_QUESTION = 6, + EMOTE_ONESHOT_EAT = 7, + EMOTE_STATE_DANCE = 10, + EMOTE_ONESHOT_LAUGH = 11, + EMOTE_STATE_SLEEP = 12, + EMOTE_STATE_SIT = 13, + EMOTE_ONESHOT_RUDE = 14, + EMOTE_ONESHOT_ROAR = 15, + EMOTE_ONESHOT_KNEEL = 16, + EMOTE_ONESHOT_KISS = 17, + EMOTE_ONESHOT_CRY = 18, + EMOTE_ONESHOT_CHICKEN = 19, + EMOTE_ONESHOT_BEG = 20, + EMOTE_ONESHOT_APPLAUD = 21, + EMOTE_ONESHOT_SHOUT = 22, + EMOTE_ONESHOT_FLEX = 23, + EMOTE_ONESHOT_SHY = 24, + EMOTE_ONESHOT_POINT = 25, + EMOTE_STATE_STAND = 26, + EMOTE_STATE_READYUNARMED = 27, + EMOTE_STATE_WORK_SHEATHED = 28, + EMOTE_STATE_POINT = 29, + EMOTE_STATE_NONE = 30, + EMOTE_ONESHOT_WOUND = 33, + EMOTE_ONESHOT_WOUNDCRITICAL = 34, + EMOTE_ONESHOT_ATTACKUNARMED = 35, + EMOTE_ONESHOT_ATTACK1H = 36, + EMOTE_ONESHOT_ATTACK2HTIGHT = 37, + EMOTE_ONESHOT_ATTACK2HLOOSE = 38, + EMOTE_ONESHOT_PARRYUNARMED = 39, + EMOTE_ONESHOT_PARRYSHIELD = 43, + EMOTE_ONESHOT_READYUNARMED = 44, + EMOTE_ONESHOT_READY1H = 45, + EMOTE_ONESHOT_READYBOW = 48, + EMOTE_ONESHOT_SPELLPRECAST = 50, + EMOTE_ONESHOT_SPELLCAST = 51, + EMOTE_ONESHOT_BATTLEROAR = 53, + EMOTE_ONESHOT_SPECIALATTACK1H = 54, + EMOTE_ONESHOT_KICK = 60, + EMOTE_ONESHOT_ATTACKTHROWN = 61, + EMOTE_STATE_STUN = 64, + EMOTE_STATE_DEAD = 65, + EMOTE_ONESHOT_SALUTE = 66, + EMOTE_STATE_KNEEL = 68, + EMOTE_STATE_USESTANDING = 69, + EMOTE_ONESHOT_WAVE_NOSHEATHE = 70, + EMOTE_ONESHOT_CHEER_NOSHEATHE = 71, + EMOTE_ONESHOT_EAT_NOSHEATHE = 92, + EMOTE_STATE_STUN_NOSHEATHE = 93, + EMOTE_ONESHOT_DANCE = 94, + EMOTE_ONESHOT_SALUTE_NOSHEATH = 113, + EMOTE_STATE_USESTANDING_NOSHEATHE = 133, + EMOTE_ONESHOT_LAUGH_NOSHEATHE = 153, + EMOTE_STATE_WORK = 173, + EMOTE_STATE_SPELLPRECAST = 193, + EMOTE_ONESHOT_READYRIFLE = 213, + EMOTE_STATE_READYRIFLE = 214, + EMOTE_STATE_WORK_MINING = 233, + EMOTE_STATE_WORK_CHOPWOOD = 234, + EMOTE_STATE_APPLAUD = 253, + EMOTE_ONESHOT_LIFTOFF = 254, + EMOTE_ONESHOT_YES = 273, + EMOTE_ONESHOT_NO = 274, + EMOTE_ONESHOT_TRAIN = 275, + EMOTE_ONESHOT_LAND = 293, + EMOTE_STATE_AT_EASE = 313, + EMOTE_STATE_READY1H = 333, + EMOTE_STATE_SPELLKNEELSTART = 353, + EMOTE_STATE_SUBMERGED = 373, + EMOTE_ONESHOT_SUBMERGE = 374, + EMOTE_STATE_READY2H = 375, + EMOTE_STATE_READYBOW = 376, + EMOTE_ONESHOT_MOUNTSPECIAL = 377, + EMOTE_STATE_TALK = 378, + EMOTE_STATE_FISHING = 379, + EMOTE_ONESHOT_FISHING = 380, + EMOTE_ONESHOT_LOOT = 381, + EMOTE_STATE_WHIRLWIND = 382, + EMOTE_STATE_DROWNED = 383, + EMOTE_STATE_HOLD_BOW = 384, + EMOTE_STATE_HOLD_RIFLE = 385, + EMOTE_STATE_HOLD_THROWN = 386, + EMOTE_ONESHOT_DROWN = 387, + EMOTE_ONESHOT_STOMP = 388, + EMOTE_ONESHOT_ATTACKOFF = 389, + EMOTE_ONESHOT_ATTACKOFFPIERCE = 390, + EMOTE_STATE_ROAR = 391, + EMOTE_STATE_LAUGH = 392, + EMOTE_ONESHOT_CREATURE_SPECIAL = 393, + EMOTE_ONESHOT_JUMPLANDRUN = 394, + EMOTE_ONESHOT_JUMPEND = 395, + EMOTE_ONESHOT_TALK_NOSHEATHE = 396, + EMOTE_ONESHOT_POINT_NOSHEATHE = 397, + EMOTE_STATE_CANNIBALIZE = 398, + EMOTE_ONESHOT_JUMPSTART = 399, + EMOTE_STATE_DANCESPECIAL = 400, + EMOTE_ONESHOT_DANCESPECIAL = 401, + EMOTE_ONESHOT_CUSTOMSPELL01 = 402, + EMOTE_ONESHOT_CUSTOMSPELL02 = 403, + EMOTE_ONESHOT_CUSTOMSPELL03 = 404, + EMOTE_ONESHOT_CUSTOMSPELL04 = 405, + EMOTE_ONESHOT_CUSTOMSPELL05 = 406, + EMOTE_ONESHOT_CUSTOMSPELL06 = 407, + EMOTE_ONESHOT_CUSTOMSPELL07 = 408, + EMOTE_ONESHOT_CUSTOMSPELL08 = 409, + EMOTE_ONESHOT_CUSTOMSPELL09 = 410, + EMOTE_ONESHOT_CUSTOMSPELL10 = 411, + EMOTE_STATE_EXCLAIM = 412, + EMOTE_STATE_DANCE_CUSTOM = 413, + EMOTE_STATE_SIT_CHAIR_MED = 415, + EMOTE_STATE_CUSTOM_SPELL_01 = 416, + EMOTE_STATE_CUSTOM_SPELL_02 = 417, + EMOTE_STATE_EAT = 418, + EMOTE_STATE_CUSTOM_SPELL_04 = 419, + EMOTE_STATE_CUSTOM_SPELL_03 = 420, + EMOTE_STATE_CUSTOM_SPELL_05 = 421, + EMOTE_STATE_SPELLEFFECT_HOLD = 422, + EMOTE_STATE_EAT_NO_SHEATHE = 423, + EMOTE_STATE_MOUNT = 424, + EMOTE_STATE_READY2HL = 425, + EMOTE_STATE_SIT_CHAIR_HIGH = 426, + EMOTE_STATE_FALL = 427, + EMOTE_STATE_LOOT = 428, + EMOTE_STATE_SUBMERGED_NEW = 429, + EMOTE_ONESHOT_COWER = 430, + EMOTE_STATE_COWER = 431, + EMOTE_ONESHOT_USESTANDING = 432, + EMOTE_STATE_STEALTH_STAND = 433, + EMOTE_ONESHOT_OMNICAST_GHOUL = 434, + EMOTE_ONESHOT_ATTACKBOW = 435, + EMOTE_ONESHOT_ATTACKRIFLE = 436, + EMOTE_STATE_SWIM_IDLE = 437, + EMOTE_STATE_ATTACK_UNARMED = 438, + EMOTE_ONESHOT_SPELLCAST_W_SOUND = 439, + EMOTE_ONESHOT_DODGE = 440, + EMOTE_ONESHOT_PARRY1H = 441, + EMOTE_ONESHOT_PARRY2H = 442, + EMOTE_ONESHOT_PARRY2HL = 443, + EMOTE_STATE_FLYFALL = 444, + EMOTE_ONESHOT_FLYDEATH = 445, + EMOTE_STATE_FLY_FALL = 446, + EMOTE_ONESHOT_FLY_SIT_GROUND_DOWN = 447, + EMOTE_ONESHOT_FLY_SIT_GROUND_UP = 448, + EMOTE_ONESHOT_EMERGE = 449, + EMOTE_ONESHOT_DRAGONSPIT = 450, + EMOTE_STATE_SPECIALUNARMED = 451, + EMOTE_ONESHOT_FLYGRAB = 452, + EMOTE_STATE_FLYGRABCLOSED = 453, + EMOTE_ONESHOT_FLYGRABTHROWN = 454, + EMOTE_STATE_FLY_SIT_GROUND = 455, + EMOTE_STATE_WALKBACKWARDS = 456, + EMOTE_ONESHOT_FLYTALK = 457, + EMOTE_ONESHOT_FLYATTACK1H = 458, + EMOTE_STATE_CUSTOMSPELL08 = 459, + EMOTE_ONESHOT_FLY_DRAGONSPIT = 460, + EMOTE_STATE_SIT_CHAIR_LOW = 461, + EMOTE_ONE_SHOT_STUN = 462, + EMOTE_ONESHOT_SPELLCAST_OMNI = 463, + EMOTE_STATE_READYTHROWN = 464 +}; + +enum Anim +{ + ANIM_STAND = 0x0, + ANIM_DEATH = 0x1, + ANIM_SPELL = 0x2, + ANIM_STOP = 0x3, + ANIM_WALK = 0x4, + ANIM_RUN = 0x5, + ANIM_DEAD = 0x6, + ANIM_RISE = 0x7, + ANIM_STANDWOUND = 0x8, + ANIM_COMBATWOUND = 0x9, + ANIM_COMBATCRITICAL = 0xA, + ANIM_SHUFFLE_LEFT = 0xB, + ANIM_SHUFFLE_RIGHT = 0xC, + ANIM_WALK_BACKWARDS = 0xD, + ANIM_STUN = 0xE, + ANIM_HANDS_CLOSED = 0xF, + ANIM_ATTACKUNARMED = 0x10, + ANIM_ATTACK1H = 0x11, + ANIM_ATTACK2HTIGHT = 0x12, + ANIM_ATTACK2HLOOSE = 0x13, + ANIM_PARRYUNARMED = 0x14, + ANIM_PARRY1H = 0x15, + ANIM_PARRY2HTIGHT = 0x16, + ANIM_PARRY2HLOOSE = 0x17, + ANIM_PARRYSHIELD = 0x18, + ANIM_READYUNARMED = 0x19, + ANIM_READY1H = 0x1A, + ANIM_READY2HTIGHT = 0x1B, + ANIM_READY2HLOOSE = 0x1C, + ANIM_READYBOW = 0x1D, + ANIM_DODGE = 0x1E, + ANIM_SPELLPRECAST = 0x1F, + ANIM_SPELLCAST = 0x20, + ANIM_SPELLCASTAREA = 0x21, + ANIM_NPCWELCOME = 0x22, + ANIM_NPCGOODBYE = 0x23, + ANIM_BLOCK = 0x24, + ANIM_JUMPSTART = 0x25, + ANIM_JUMP = 0x26, + ANIM_JUMPEND = 0x27, + ANIM_FALL = 0x28, + ANIM_SWIMIDLE = 0x29, + ANIM_SWIM = 0x2A, + ANIM_SWIM_LEFT = 0x2B, + ANIM_SWIM_RIGHT = 0x2C, + ANIM_SWIM_BACKWARDS = 0x2D, + ANIM_ATTACKBOW = 0x2E, + ANIM_FIREBOW = 0x2F, + ANIM_READYRIFLE = 0x30, + ANIM_ATTACKRIFLE = 0x31, + ANIM_LOOT = 0x32, + ANIM_SPELL_PRECAST_DIRECTED = 0x33, + ANIM_SPELL_PRECAST_OMNI = 0x34, + ANIM_SPELL_CAST_DIRECTED = 0x35, + ANIM_SPELL_CAST_OMNI = 0x36, + ANIM_SPELL_BATTLEROAR = 0x37, + ANIM_SPELL_READYABILITY = 0x38, + ANIM_SPELL_SPECIAL1H = 0x39, + ANIM_SPELL_SPECIAL2H = 0x3A, + ANIM_SPELL_SHIELDBASH = 0x3B, + ANIM_EMOTE_TALK = 0x3C, + ANIM_EMOTE_EAT = 0x3D, + ANIM_EMOTE_WORK = 0x3E, + ANIM_EMOTE_USE_STANDING = 0x3F, + ANIM_EMOTE_EXCLAMATION = 0x40, + ANIM_EMOTE_QUESTION = 0x41, + ANIM_EMOTE_BOW = 0x42, + ANIM_EMOTE_WAVE = 0x43, + ANIM_EMOTE_CHEER = 0x44, + ANIM_EMOTE_DANCE = 0x45, + ANIM_EMOTE_LAUGH = 0x46, + ANIM_EMOTE_SLEEP = 0x47, + ANIM_EMOTE_SIT_GROUND = 0x48, + ANIM_EMOTE_RUDE = 0x49, + ANIM_EMOTE_ROAR = 0x4A, + ANIM_EMOTE_KNEEL = 0x4B, + ANIM_EMOTE_KISS = 0x4C, + ANIM_EMOTE_CRY = 0x4D, + ANIM_EMOTE_CHICKEN = 0x4E, + ANIM_EMOTE_BEG = 0x4F, + ANIM_EMOTE_APPLAUD = 0x50, + ANIM_EMOTE_SHOUT = 0x51, + ANIM_EMOTE_FLEX = 0x52, + ANIM_EMOTE_SHY = 0x53, + ANIM_EMOTE_POINT = 0x54, + ANIM_ATTACK1HPIERCE = 0x55, + ANIM_ATTACK2HLOOSEPIERCE = 0x56, + ANIM_ATTACKOFF = 0x57, + ANIM_ATTACKOFFPIERCE = 0x58, + ANIM_SHEATHE = 0x59, + ANIM_HIPSHEATHE = 0x5A, + ANIM_MOUNT = 0x5B, + ANIM_RUN_LEANRIGHT = 0x5C, + ANIM_RUN_LEANLEFT = 0x5D, + ANIM_MOUNT_SPECIAL = 0x5E, + ANIM_KICK = 0x5F, + ANIM_SITDOWN = 0x60, + ANIM_SITTING = 0x61, + ANIM_SITUP = 0x62, + ANIM_SLEEPDOWN = 0x63, + ANIM_SLEEPING = 0x64, + ANIM_SLEEPUP = 0x65, + ANIM_SITCHAIRLOW = 0x66, + ANIM_SITCHAIRMEDIUM = 0x67, + ANIM_SITCHAIRHIGH = 0x68, + ANIM_LOADBOW = 0x69, + ANIM_LOADRIFLE = 0x6A, + ANIM_ATTACKTHROWN = 0x6B, + ANIM_READYTHROWN = 0x6C, + ANIM_HOLDBOW = 0x6D, + ANIM_HOLDRIFLE = 0x6E, + ANIM_HOLDTHROWN = 0x6F, + ANIM_LOADTHROWN = 0x70, + ANIM_EMOTE_SALUTE = 0x71, + ANIM_KNEELDOWN = 0x72, + ANIM_KNEELING = 0x73, + ANIM_KNEELUP = 0x74, + ANIM_ATTACKUNARMEDOFF = 0x75, + ANIM_SPECIALUNARMED = 0x76, + ANIM_STEALTHWALK = 0x77, + ANIM_STEALTHSTAND = 0x78, + ANIM_KNOCKDOWN = 0x79, + ANIM_EATING = 0x7A, + ANIM_USESTANDINGLOOP = 0x7B, + ANIM_CHANNELCASTDIRECTED = 0x7C, + ANIM_CHANNELCASTOMNI = 0x7D, + ANIM_WHIRLWIND = 0x7E, + ANIM_BIRTH = 0x7F, + ANIM_USESTANDINGSTART = 0x80, + ANIM_USESTANDINGEND = 0x81, + ANIM_HOWL = 0x82, + ANIM_DROWN = 0x83, + ANIM_DROWNED = 0x84, + ANIM_FISHINGCAST = 0x85, + ANIM_FISHINGLOOP = 0x86, + ANIM_FLY = 0x87, + ANIM_EMOTE_WORK_NO_SHEATHE = 0x88, + ANIM_EMOTE_STUN_NO_SHEATHE = 0x89, + ANIM_EMOTE_USE_STANDING_NO_SHEATHE= 0x8A, + ANIM_SPELL_SLEEP_DOWN = 0x8B, + ANIM_SPELL_KNEEL_START = 0x8C, + ANIM_SPELL_KNEEL_LOOP = 0x8D, + ANIM_SPELL_KNEEL_END = 0x8E, + ANIM_SPRINT = 0x8F, + ANIM_IN_FIGHT = 0x90, + + ANIM_GAMEOBJ_SPAWN = 145, + ANIM_GAMEOBJ_CLOSE = 146, + ANIM_GAMEOBJ_CLOSED = 147, + ANIM_GAMEOBJ_OPEN = 148, + ANIM_GAMEOBJ_OPENED = 149, + ANIM_GAMEOBJ_DESTROY = 150, + ANIM_GAMEOBJ_DESTROYED = 151, + ANIM_GAMEOBJ_REBUILD = 152, + ANIM_GAMEOBJ_CUSTOM0 = 153, + ANIM_GAMEOBJ_CUSTOM1 = 154, + ANIM_GAMEOBJ_CUSTOM2 = 155, + ANIM_GAMEOBJ_CUSTOM3 = 156, + ANIM_GAMEOBJ_DESPAWN = 157, + ANIM_HOLD = 158, + ANIM_DECAY = 159, + ANIM_BOWPULL = 160, + ANIM_BOWRELEASE = 161, + ANIM_SHIPSTART = 162, + ANIM_SHIPMOVEING = 163, + ANIM_SHIPSTOP = 164, + ANIM_GROUPARROW = 165, + ANIM_ARROW = 166, + ANIM_CORPSEARROW = 167, + ANIM_GUIDEARROW = 168, + ANIM_SWAY = 169, + ANIM_DRUIDCATPOUNCE = 170, + ANIM_DRUIDCATRIP = 171, + ANIM_DRUIDCATRAKE = 172, + ANIM_DRUIDCATRAVAGE = 173, + ANIM_DRUIDCATCLAW = 174, + ANIM_DRUIDCATCOWER = 175, + ANIM_DRUIDBEARSWIPE = 176, + ANIM_DRUIDBEARBITE = 177, + ANIM_DRUIDBEARMAUL = 178, + ANIM_DRUIDBEARBASH = 179, + ANIM_DRAGONTAIL = 180, + ANIM_DRAGONSTOMP = 181, + ANIM_DRAGONSPIT = 182, + ANIM_DRAGONSPITHOVER = 183, + ANIM_DRAGONSPITFLY = 184, + ANIM_EMOTEYES = 185, + ANIM_EMOTENO = 186, + ANIM_JUMPLANDRUN = 187, + ANIM_LOOTHOLD = 188, + ANIM_LOOTUP = 189, + ANIM_STANDHIGH = 190, + ANIM_IMPACT = 191, + ANIM_LIFTOFF = 192, + ANIM_HOVER = 193, + ANIM_SUCCUBUSENTICE = 194, + ANIM_EMOTETRAIN = 195, + ANIM_EMOTEDEAD = 196, + ANIM_EMOTEDANCEONCE = 197, + ANIM_DEFLECT = 198, + ANIM_EMOTEEATNOSHEATHE = 199, + ANIM_LAND = 200, + ANIM_SUBMERGE = 201, + ANIM_SUBMERGED = 202, + ANIM_CANNIBALIZE = 203, + ANIM_ARROWBIRTH = 204, + ANIM_GROURARROWBIRTH = 205, + ANIM_CORPSEARROWBIRTH = 206, + ANIM_GUIDEARROWBIRTH = 207, + ANIM_EMOTETALKNOSHEATHE = 208, + ANIM_EMOTEPOINTNOSHEATHE = 209, + ANIM_EMOTESALUTENOSHEATHE = 210, + ANIM_EMOTEDANCESPECIAL = 211, + ANIM_MUTILATE = 212, + ANIM_CUSTOMSPELL01 = 213, + ANIM_CUSTOMSPELL02 = 214, + ANIM_CUSTOMSPELL03 = 215, + ANIM_CUSTOMSPELL04 = 216, + ANIM_CUSTOMSPELL05 = 217, + ANIM_CUSTOMSPELL06 = 218, + ANIM_CUSTOMSPELL07 = 219, + ANIM_CUSTOMSPELL08 = 220, + ANIM_CUSTOMSPELL09 = 221, + ANIM_CUSTOMSPELL10 = 222, + ANIM_StealthRun = 223 +}; + +enum LockKeyType +{ + LOCK_KEY_NONE = 0, + LOCK_KEY_ITEM = 1, + LOCK_KEY_SKILL = 2 +}; + +enum LockType +{ + LOCKTYPE_PICKLOCK = 1, + LOCKTYPE_HERBALISM = 2, + LOCKTYPE_MINING = 3, + LOCKTYPE_DISARM_TRAP = 4, + LOCKTYPE_OPEN = 5, + LOCKTYPE_TREASURE = 6, + LOCKTYPE_CALCIFIED_ELVEN_GEMS = 7, + LOCKTYPE_CLOSE = 8, + LOCKTYPE_ARM_TRAP = 9, + LOCKTYPE_QUICK_OPEN = 10, + LOCKTYPE_QUICK_CLOSE = 11, + LOCKTYPE_OPEN_TINKERING = 12, + LOCKTYPE_OPEN_KNEELING = 13, + LOCKTYPE_OPEN_ATTACKING = 14, + LOCKTYPE_GAHZRIDIAN = 15, + LOCKTYPE_BLASTING = 16, + LOCKTYPE_SLOW_OPEN = 17, + LOCKTYPE_SLOW_CLOSE = 18, + LOCKTYPE_FISHING = 19, + LOCKTYPE_INSCRIPTION = 20, + LOCKTYPE_OPEN_FROM_VEHICLE = 21 +}; + +enum TrainerType // this is important type for npcs! +{ + TRAINER_TYPE_CLASS = 0, + TRAINER_TYPE_MOUNTS = 1, // on blizz it's 2 + TRAINER_TYPE_TRADESKILLS = 2, + TRAINER_TYPE_PETS = 3 +}; + +#define MAX_TRAINER_TYPE 4 + +// CreatureType.dbc +enum CreatureType +{ + CREATURE_TYPE_BEAST = 1, + CREATURE_TYPE_DRAGONKIN = 2, + CREATURE_TYPE_DEMON = 3, + CREATURE_TYPE_ELEMENTAL = 4, + CREATURE_TYPE_GIANT = 5, + CREATURE_TYPE_UNDEAD = 6, + CREATURE_TYPE_HUMANOID = 7, + CREATURE_TYPE_CRITTER = 8, + CREATURE_TYPE_MECHANICAL = 9, + CREATURE_TYPE_NOT_SPECIFIED = 10, + CREATURE_TYPE_TOTEM = 11, + CREATURE_TYPE_NON_COMBAT_PET = 12, + CREATURE_TYPE_GAS_CLOUD = 13 +}; + +uint32 const CREATURE_TYPEMASK_DEMON_OR_UNDEAD = (1 << (CREATURE_TYPE_DEMON-1)) | (1 << (CREATURE_TYPE_UNDEAD-1)); +uint32 const CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD = (1 << (CREATURE_TYPE_HUMANOID-1)) | (1 << (CREATURE_TYPE_UNDEAD-1)); +uint32 const CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL = (1 << (CREATURE_TYPE_MECHANICAL-1)) | (1 << (CREATURE_TYPE_ELEMENTAL-1)); + +// CreatureFamily.dbc +enum CreatureFamily +{ + CREATURE_FAMILY_WOLF = 1, + CREATURE_FAMILY_CAT = 2, + CREATURE_FAMILY_SPIDER = 3, + CREATURE_FAMILY_BEAR = 4, + CREATURE_FAMILY_BOAR = 5, + CREATURE_FAMILY_CROCOLISK = 6, + CREATURE_FAMILY_CARRION_BIRD = 7, + CREATURE_FAMILY_CRAB = 8, + CREATURE_FAMILY_GORILLA = 9, + CREATURE_FAMILY_HORSE_CUSTOM = 10, // not exist in DBC but used for horse like beasts in DB + CREATURE_FAMILY_RAPTOR = 11, + CREATURE_FAMILY_TALLSTRIDER = 12, + CREATURE_FAMILY_FELHUNTER = 15, + CREATURE_FAMILY_VOIDWALKER = 16, + CREATURE_FAMILY_SUCCUBUS = 17, + CREATURE_FAMILY_DOOMGUARD = 19, + CREATURE_FAMILY_SCORPID = 20, + CREATURE_FAMILY_TURTLE = 21, + CREATURE_FAMILY_IMP = 23, + CREATURE_FAMILY_BAT = 24, + CREATURE_FAMILY_HYENA = 25, + CREATURE_FAMILY_BIRD_OF_PREY = 26, + CREATURE_FAMILY_WIND_SERPENT = 27, + CREATURE_FAMILY_REMOTE_CONTROL = 28, + CREATURE_FAMILY_FELGUARD = 29, + CREATURE_FAMILY_DRAGONHAWK = 30, + CREATURE_FAMILY_RAVAGER = 31, + CREATURE_FAMILY_WARP_STALKER = 32, + CREATURE_FAMILY_SPOREBAT = 33, + CREATURE_FAMILY_NETHER_RAY = 34, + CREATURE_FAMILY_SERPENT = 35, + CREATURE_FAMILY_MOTH = 37, + CREATURE_FAMILY_CHIMAERA = 38, + CREATURE_FAMILY_DEVILSAUR = 39, + CREATURE_FAMILY_GHOUL = 40, + CREATURE_FAMILY_SILITHID = 41, + CREATURE_FAMILY_WORM = 42, + CREATURE_FAMILY_RHINO = 43, + CREATURE_FAMILY_WASP = 44, + CREATURE_FAMILY_CORE_HOUND = 45, + CREATURE_FAMILY_SPIRIT_BEAST = 46 +}; + +enum CreatureTypeFlags +{ + CREATURE_TYPEFLAGS_TAMEABLE = 0x000001, // Tameable by any hunter + CREATURE_TYPEFLAGS_GHOST = 0x000002, // Creature are also visible for not alive player. Allow gossip interaction if npcflag allow? + CREATURE_TYPEFLAGS_UNK3 = 0x000004, + CREATURE_TYPEFLAGS_UNK4 = 0x000008, + CREATURE_TYPEFLAGS_UNK5 = 0x000010, + CREATURE_TYPEFLAGS_UNK6 = 0x000020, + CREATURE_TYPEFLAGS_UNK7 = 0x000040, + CREATURE_TYPEFLAGS_UNK8 = 0x000080, + CREATURE_TYPEFLAGS_HERBLOOT = 0x000100, // Can be looted by herbalist + CREATURE_TYPEFLAGS_MININGLOOT = 0x000200, // Can be looted by miner + CREATURE_TYPEFLAGS_UNK11 = 0x000400, + CREATURE_TYPEFLAGS_UNK12 = 0x000800, // ? Related to mounts in some way. If mounted, fight mounted, mount appear as independant when rider dies? + CREATURE_TYPEFLAGS_UNK13 = 0x001000, // ? Can aid any player in combat if in range? + CREATURE_TYPEFLAGS_UNK14 = 0x002000, + CREATURE_TYPEFLAGS_UNK15 = 0x004000, // ? Possibly not in use + CREATURE_TYPEFLAGS_ENGINEERLOOT = 0x008000, // Can be looted by engineer + CREATURE_TYPEFLAGS_EXOTIC = 0x010000, // Can be tamed by hunter as exotic pet + CREATURE_TYPEFLAGS_UNK18 = 0x020000, // ? Related to vehicles/pvp? + CREATURE_TYPEFLAGS_UNK19 = 0x040000, // ? Related to vehicle/siege weapons? + CREATURE_TYPEFLAGS_UNK20 = 0x080000, + CREATURE_TYPEFLAGS_UNK21 = 0x100000, + CREATURE_TYPEFLAGS_UNK22 = 0x200000, + CREATURE_TYPEFLAGS_UNK23 = 0x400000, + CREATURE_TYPEFLAGS_UNK24 = 0x800000 // ? First seen in 3.2.2. Related to banner/backpack of creature/companion? +}; + +enum CreatureEliteType +{ + CREATURE_ELITE_NORMAL = 0, + CREATURE_ELITE_ELITE = 1, + CREATURE_ELITE_RAREELITE = 2, + CREATURE_ELITE_WORLDBOSS = 3, + CREATURE_ELITE_RARE = 4, + CREATURE_UNKNOWN = 5 // found in 2.2.3 for 2 mobs +}; + +// values based at Holidays.dbc +enum HolidayIds +{ + HOLIDAY_NONE = 0, + + HOLIDAY_FIREWORKS_SPECTACULAR = 62, + HOLIDAY_FEAST_OF_WINTER_VEIL = 141, + HOLIDAY_NOBLEGARDEN = 181, + HOLIDAY_CHILDRENS_WEEK = 201, + HOLIDAY_CALL_TO_ARMS_AV = 283, + HOLIDAY_CALL_TO_ARMS_WS = 284, + HOLIDAY_CALL_TO_ARMS_AB = 285, + HOLIDAY_FISHING_EXTRAVAGANZA = 301, + HOLIDAY_HARVEST_FESTIVAL = 321, + HOLIDAY_HALLOWS_END = 324, + HOLIDAY_LUNAR_FESTIVAL = 327, + HOLIDAY_LOVE_IS_IN_THE_AIR = 335, + HOLIDAY_FIRE_FESTIVAL = 341, + HOLIDAY_CALL_TO_ARMS_EY = 353, + HOLIDAY_BREWFEST = 372, + HOLIDAY_DARKMOON_FAIRE_ELWYNN = 374, + HOLIDAY_DARKMOON_FAIRE_THUNDER = 375, + HOLIDAY_DARKMOON_FAIRE_SHATTRATH = 376, + HOLIDAY_PIRATES_DAY = 398, + HOLIDAY_CALL_TO_ARMS_SA = 400, + HOLIDAY_PILGRIMS_BOUNTY = 404, + HOLIDAY_WOTLK_LAUNCH = 406, + HOLIDAY_DAY_OF_DEAD = 409, + HOLIDAY_CALL_TO_ARMS_ISLE_OF_C = 420 +}; + +// values based at QuestInfo.dbc +enum QuestTypes +{ + QUEST_TYPE_ELITE = 1, + QUEST_TYPE_LIFE = 21, + QUEST_TYPE_PVP = 41, + QUEST_TYPE_RAID = 62, + QUEST_TYPE_DUNGEON = 81, + QUEST_TYPE_WORLD_EVENT = 82, + QUEST_TYPE_LEGENDARY = 83, + QUEST_TYPE_ESCORT = 84, + QUEST_TYPE_HEROIC = 85, + QUEST_TYPE_RAID_10 = 88, + QUEST_TYPE_RAID_25 = 89 +}; + +// values based at QuestSort.dbc +enum QuestSort +{ + QUEST_SORT_EPIC = 1, + QUEST_SORT_WAILING_CAVERNS_OLD = 21, + QUEST_SORT_SEASONAL = 22, + QUEST_SORT_UNDERCITY_OLD = 23, + QUEST_SORT_HERBALISM = 24, + QUEST_SORT_BATTLEGROUNDS = 25, + QUEST_SORT_ULDAMN_OLD = 41, + QUEST_SORT_WARLOCK = 61, + QUEST_SORT_WARRIOR = 81, + QUEST_SORT_SHAMAN = 82, + QUEST_SORT_FISHING = 101, + QUEST_SORT_BLACKSMITHING = 121, + QUEST_SORT_PALADIN = 141, + QUEST_SORT_MAGE = 161, + QUEST_SORT_ROGUE = 162, + QUEST_SORT_ALCHEMY = 181, + QUEST_SORT_LEATHERWORKING = 182, + QUEST_SORT_ENGINERING = 201, + QUEST_SORT_TREASURE_MAP = 221, + QUEST_SORT_SUNKEN_TEMPLE_OLD = 241, + QUEST_SORT_HUNTER = 261, + QUEST_SORT_PRIEST = 262, + QUEST_SORT_DRUID = 263, + QUEST_SORT_TAILORING = 264, + QUEST_SORT_SPECIAL = 284, + QUEST_SORT_COOKING = 304, + QUEST_SORT_FIRST_AID = 324, + QUEST_SORT_LEGENDARY = 344, + QUEST_SORT_DARKMOON_FAIRE = 364, + QUEST_SORT_AHN_QIRAJ_WAR = 365, + QUEST_SORT_LUNAR_FESTIVAL = 366, + QUEST_SORT_REPUTATION = 367, + QUEST_SORT_INVASION = 368, + QUEST_SORT_MIDSUMMER = 369, + QUEST_SORT_BREWFEST = 370, + QUEST_SORT_INSCRIPTION = 371, + QUEST_SORT_DEATH_KNIGHT = 372, + QUEST_SORT_JEWELCRAFTING = 373 +}; + +inline uint8 ClassByQuestSort(int32 QuestSort) +{ + switch(QuestSort) + { + case QUEST_SORT_WARLOCK: return CLASS_WARLOCK; + case QUEST_SORT_WARRIOR: return CLASS_WARRIOR; + case QUEST_SORT_SHAMAN: return CLASS_SHAMAN; + case QUEST_SORT_PALADIN: return CLASS_PALADIN; + case QUEST_SORT_MAGE: return CLASS_MAGE; + case QUEST_SORT_ROGUE: return CLASS_ROGUE; + case QUEST_SORT_HUNTER: return CLASS_HUNTER; + case QUEST_SORT_PRIEST: return CLASS_PRIEST; + case QUEST_SORT_DRUID: return CLASS_DRUID; + case QUEST_SORT_DEATH_KNIGHT: return CLASS_DEATH_KNIGHT; + } + return 0; +} + +enum SkillType +{ + SKILL_NONE = 0, + + SKILL_FROST = 6, + SKILL_FIRE = 8, + SKILL_ARMS = 26, + SKILL_COMBAT = 38, + SKILL_SUBTLETY = 39, + SKILL_SWORDS = 43, + SKILL_AXES = 44, + SKILL_BOWS = 45, + SKILL_GUNS = 46, + SKILL_BEAST_MASTERY = 50, + SKILL_SURVIVAL = 51, + SKILL_MACES = 54, + SKILL_2H_SWORDS = 55, + SKILL_HOLY = 56, + SKILL_SHADOW = 78, + SKILL_DEFENSE = 95, + SKILL_LANG_COMMON = 98, + SKILL_RACIAL_DWARVEN = 101, + SKILL_LANG_ORCISH = 109, + SKILL_LANG_DWARVEN = 111, + SKILL_LANG_DARNASSIAN = 113, + SKILL_LANG_TAURAHE = 115, + SKILL_DUAL_WIELD = 118, + SKILL_RACIAL_TAUREN = 124, + SKILL_ORC_RACIAL = 125, + SKILL_RACIAL_NIGHT_ELF = 126, + SKILL_FIRST_AID = 129, + SKILL_FERAL_COMBAT = 134, + SKILL_STAVES = 136, + SKILL_LANG_THALASSIAN = 137, + SKILL_LANG_DRACONIC = 138, + SKILL_LANG_DEMON_TONGUE = 139, + SKILL_LANG_TITAN = 140, + SKILL_LANG_OLD_TONGUE = 141, + SKILL_SURVIVAL2 = 142, + SKILL_RIDING_HORSE = 148, + SKILL_RIDING_WOLF = 149, + SKILL_RIDING_RAM = 152, + SKILL_RIDING_TIGER = 150, + SKILL_SWIMING = 155, + SKILL_2H_MACES = 160, + SKILL_UNARMED = 162, + SKILL_MARKSMANSHIP = 163, + SKILL_BLACKSMITHING = 164, + SKILL_LEATHERWORKING = 165, + SKILL_ALCHEMY = 171, + SKILL_2H_AXES = 172, + SKILL_DAGGERS = 173, + SKILL_THROWN = 176, + SKILL_HERBALISM = 182, + SKILL_GENERIC_DND = 183, + SKILL_RETRIBUTION = 184, + SKILL_COOKING = 185, + SKILL_MINING = 186, + SKILL_PET_IMP = 188, + SKILL_PET_FELHUNTER = 189, + SKILL_TAILORING = 197, + SKILL_ENGINERING = 202, + SKILL_PET_SPIDER = 203, + SKILL_PET_VOIDWALKER = 204, + SKILL_PET_SUCCUBUS = 205, + SKILL_PET_INFERNAL = 206, + SKILL_PET_DOOMGUARD = 207, + SKILL_PET_WOLF = 208, + SKILL_PET_CAT = 209, + SKILL_PET_BEAR = 210, + SKILL_PET_BOAR = 211, + SKILL_PET_CROCILISK = 212, + SKILL_PET_CARRION_BIRD = 213, + SKILL_PET_CRAB = 214, + SKILL_PET_GORILLA = 215, + SKILL_PET_RAPTOR = 217, + SKILL_PET_TALLSTRIDER = 218, + SKILL_RACIAL_UNDED = 220, + SKILL_CROSSBOWS = 226, + SKILL_WANDS = 228, + SKILL_POLEARMS = 229, + SKILL_PET_SCORPID = 236, + SKILL_ARCANE = 237, + SKILL_PET_TURTLE = 251, + SKILL_ASSASSINATION = 253, + SKILL_FURY = 256, + SKILL_PROTECTION = 257, + SKILL_PROTECTION2 = 267, + SKILL_PET_TALENTS = 270, + SKILL_PLATE_MAIL = 293, + SKILL_LANG_GNOMISH = 313, + SKILL_LANG_TROLL = 315, + SKILL_ENCHANTING = 333, + SKILL_DEMONOLOGY = 354, + SKILL_AFFLICTION = 355, + SKILL_FISHING = 356, + SKILL_ENHANCEMENT = 373, + SKILL_RESTORATION = 374, + SKILL_ELEMENTAL_COMBAT = 375, + SKILL_SKINNING = 393, + SKILL_MAIL = 413, + SKILL_LEATHER = 414, + SKILL_CLOTH = 415, + SKILL_SHIELD = 433, + SKILL_FIST_WEAPONS = 473, + SKILL_RIDING_RAPTOR = 533, + SKILL_RIDING_MECHANOSTRIDER = 553, + SKILL_RIDING_UNDEAD_HORSE = 554, + SKILL_RESTORATION2 = 573, + SKILL_BALANCE = 574, + SKILL_DESTRUCTION = 593, + SKILL_HOLY2 = 594, + SKILL_DISCIPLINE = 613, + SKILL_LOCKPICKING = 633, + SKILL_PET_BAT = 653, + SKILL_PET_HYENA = 654, + SKILL_PET_BIRD_OF_PREY = 655, + SKILL_PET_WIND_SERPENT = 656, + SKILL_LANG_GUTTERSPEAK = 673, + SKILL_RIDING_KODO = 713, + SKILL_RACIAL_TROLL = 733, + SKILL_RACIAL_GNOME = 753, + SKILL_RACIAL_HUMAN = 754, + SKILL_JEWELCRAFTING = 755, + SKILL_RACIAL_BLOODELF = 756, + SKILL_PET_EVENT_RC = 758, + SKILL_LANG_DRAENEI = 759, + SKILL_RACIAL_DRAENEI = 760, + SKILL_PET_FELGUARD = 761, + SKILL_RIDING = 762, + SKILL_PET_DRAGONHAWK = 763, + SKILL_PET_NETHER_RAY = 764, + SKILL_PET_SPOREBAT = 765, + SKILL_PET_WARP_STALKER = 766, + SKILL_PET_RAVAGER = 767, + SKILL_PET_SERPENT = 768, + SKILL_INTERNAL = 769, + SKILL_DK_BLOOD = 770, + SKILL_DK_FROST = 771, + SKILL_DK_UNHOLY = 772, + SKILL_INSCRIPTION = 773, + SKILL_PET_MOTH = 775, + SKILL_RUNEFORGING = 776, + SKILL_MOUNTS = 777, + SKILL_COMPANIONS = 778, + SKILL_PET_EXOTIC_CHIMAERA = 780, + SKILL_PET_EXOTIC_DEVILSAUR = 781, + SKILL_PET_GHOUL = 782, + SKILL_PET_EXOTIC_SILITHID = 783, + SKILL_PET_EXOTIC_WORM = 784, + SKILL_PET_WASP = 785, + SKILL_PET_EXOTIC_RHINO = 786, + SKILL_PET_EXOTIC_CORE_HOUND = 787, + SKILL_PET_EXOTIC_SPIRIT_BEAST = 788 +}; + +#define MAX_SKILL_TYPE 789 + +inline SkillType SkillByLockType(LockType locktype) +{ + switch(locktype) + { + case LOCKTYPE_PICKLOCK: return SKILL_LOCKPICKING; + case LOCKTYPE_HERBALISM: return SKILL_HERBALISM; + case LOCKTYPE_MINING: return SKILL_MINING; + case LOCKTYPE_FISHING: return SKILL_FISHING; + case LOCKTYPE_INSCRIPTION: return SKILL_INSCRIPTION; + default: break; + } + return SKILL_NONE; +} + +inline uint32 SkillByQuestSort(int32 QuestSort) +{ + switch(QuestSort) + { + case QUEST_SORT_HERBALISM: return SKILL_HERBALISM; + case QUEST_SORT_FISHING: return SKILL_FISHING; + case QUEST_SORT_BLACKSMITHING: return SKILL_BLACKSMITHING; + case QUEST_SORT_ALCHEMY: return SKILL_ALCHEMY; + case QUEST_SORT_LEATHERWORKING: return SKILL_LEATHERWORKING; + case QUEST_SORT_ENGINERING: return SKILL_ENGINERING; + case QUEST_SORT_TAILORING: return SKILL_TAILORING; + case QUEST_SORT_COOKING: return SKILL_COOKING; + case QUEST_SORT_FIRST_AID: return SKILL_FIRST_AID; + case QUEST_SORT_JEWELCRAFTING: return SKILL_JEWELCRAFTING; + case QUEST_SORT_INSCRIPTION: return SKILL_INSCRIPTION; + } + return 0; +} + +enum SkillCategory +{ + SKILL_CATEGORY_ATTRIBUTES = 5, + SKILL_CATEGORY_WEAPON = 6, + SKILL_CATEGORY_CLASS = 7, + SKILL_CATEGORY_ARMOR = 8, + SKILL_CATEGORY_SECONDARY = 9, // secondary professions + SKILL_CATEGORY_LANGUAGES = 10, + SKILL_CATEGORY_PROFESSION = 11, // primary professions + SKILL_CATEGORY_GENERIC = 12 +}; + +enum TotemCategory +{ + TC_SKINNING_SKIFE_OLD = 1, + TC_EARTH_TOTEM = 2, + TC_AIR_TOTEM = 3, + TC_FIRE_TOTEM = 4, + TC_WATER_TOTEM = 5, + TC_COPPER_ROD = 6, + TC_SILVER_ROD = 7, + TC_GOLDEN_ROD = 8, + TC_TRUESILVER_ROD = 9, + TC_ARCANITE_ROD = 10, + TC_MINING_PICK_OLD = 11, + TC_PHILOSOPHERS_STONE = 12, + TC_BLACKSMITH_HAMMER_OLD = 13, + TC_ARCLIGHT_SPANNER = 14, + TC_GYROMATIC_MA = 15, + TC_MASTER_TOTEM = 21, + TC_FEL_IRON_ROD = 41, + TC_ADAMANTITE_ROD = 62, + TC_ETERNIUM_ROD = 63, + TC_HOLLOW_QUILL = 81, + TC_RUNED_AZURITE_ROD = 101, + TC_VIRTUOSO_INKING_SET = 121, + TC_DRUMS = 141, + TC_GNOMISH_ARMY_KNIFE = 161, + TC_BLACKSMITH_HAMMER = 162, + TC_MINING_PICK = 165, + TC_SKINNING_KNIFE = 166, + TC_HAMMER_PICK = 167, + TC_BLADED_PICKAXE = 168, + TC_FLINT_AND_TINDER = 169, + TC_RUNED_COBALT_ROD = 189, + TC_RUNED_TITANIUM_ROD = 190 +}; + +enum UnitDynFlags +{ + UNIT_DYNFLAG_NONE = 0x0000, + UNIT_DYNFLAG_LOOTABLE = 0x0001, + UNIT_DYNFLAG_TRACK_UNIT = 0x0002, + UNIT_DYNFLAG_TAPPED = 0x0004, // Lua_UnitIsTapped + UNIT_DYNFLAG_TAPPED_BY_PLAYER = 0x0008, // Lua_UnitIsTappedByPlayer + UNIT_DYNFLAG_SPECIALINFO = 0x0010, + UNIT_DYNFLAG_DEAD = 0x0020, + UNIT_DYNFLAG_REFER_A_FRIEND = 0x0040, + UNIT_DYNFLAG_TAPPED_BY_ALL_THREAT_LIST = 0x0080 // Lua_UnitIsTappedByAllThreatList +}; + +enum CorpseDynFlags +{ + CORPSE_DYNFLAG_LOOTABLE = 0x0001 +}; + +enum WeatherType +{ + WEATHER_TYPE_FINE = 0, + WEATHER_TYPE_RAIN = 1, + WEATHER_TYPE_SNOW = 2, + WEATHER_TYPE_STORM = 3, + WEATHER_TYPE_THUNDERS = 86, + WEATHER_TYPE_BLACKRAIN = 90 +}; + +#define MAX_WEATHER_TYPE 4 + +enum ChatMsg +{ + CHAT_MSG_ADDON = 0xFFFFFFFF, + CHAT_MSG_SYSTEM = 0x00, + CHAT_MSG_SAY = 0x01, + CHAT_MSG_PARTY = 0x02, + CHAT_MSG_RAID = 0x03, + CHAT_MSG_GUILD = 0x04, + CHAT_MSG_OFFICER = 0x05, + CHAT_MSG_YELL = 0x06, + CHAT_MSG_WHISPER = 0x07, + CHAT_MSG_WHISPER_FOREIGN = 0x08, + CHAT_MSG_WHISPER_INFORM = 0x09, + CHAT_MSG_EMOTE = 0x0A, + CHAT_MSG_TEXT_EMOTE = 0x0B, + CHAT_MSG_MONSTER_SAY = 0x0C, + CHAT_MSG_MONSTER_PARTY = 0x0D, + CHAT_MSG_MONSTER_YELL = 0x0E, + CHAT_MSG_MONSTER_WHISPER = 0x0F, + CHAT_MSG_MONSTER_EMOTE = 0x10, + CHAT_MSG_CHANNEL = 0x11, + CHAT_MSG_CHANNEL_JOIN = 0x12, + CHAT_MSG_CHANNEL_LEAVE = 0x13, + CHAT_MSG_CHANNEL_LIST = 0x14, + CHAT_MSG_CHANNEL_NOTICE = 0x15, + CHAT_MSG_CHANNEL_NOTICE_USER = 0x16, + CHAT_MSG_AFK = 0x17, + CHAT_MSG_DND = 0x18, + CHAT_MSG_IGNORED = 0x19, + CHAT_MSG_SKILL = 0x1A, + CHAT_MSG_LOOT = 0x1B, + CHAT_MSG_MONEY = 0x1C, + CHAT_MSG_OPENING = 0x1D, + CHAT_MSG_TRADESKILLS = 0x1E, + CHAT_MSG_PET_INFO = 0x1F, + CHAT_MSG_COMBAT_MISC_INFO = 0x20, + CHAT_MSG_COMBAT_XP_GAIN = 0x21, + CHAT_MSG_COMBAT_HONOR_GAIN = 0x22, + CHAT_MSG_COMBAT_FACTION_CHANGE = 0x23, + CHAT_MSG_BG_SYSTEM_NEUTRAL = 0x24, + CHAT_MSG_BG_SYSTEM_ALLIANCE = 0x25, + CHAT_MSG_BG_SYSTEM_HORDE = 0x26, + CHAT_MSG_RAID_LEADER = 0x27, + CHAT_MSG_RAID_WARNING = 0x28, + CHAT_MSG_RAID_BOSS_EMOTE = 0x29, + CHAT_MSG_RAID_BOSS_WHISPER = 0x2A, + CHAT_MSG_FILTERED = 0x2B, + CHAT_MSG_BATTLEGROUND = 0x2C, + CHAT_MSG_BATTLEGROUND_LEADER = 0x2D, + CHAT_MSG_RESTRICTED = 0x2E, + CHAT_MSG_BATTLENET = 0x2F, + CHAT_MSG_ACHIEVEMENT = 0x30, + CHAT_MSG_GUILD_ACHIEVEMENT = 0x31, + CHAT_MSG_ARENA_POINTS = 0x32, + CHAT_MSG_PARTY_LEADER = 0x33 +}; + +#define MAX_CHAT_MSG_TYPE 0x34 + +enum ChatLinkColors +{ + CHAT_LINK_COLOR_TRADE = 0xffffd000, // orange + CHAT_LINK_COLOR_TALENT = 0xff4e96f7, // blue + CHAT_LINK_COLOR_SPELL = 0xff71d5ff, // bright blue + CHAT_LINK_COLOR_ENCHANT = 0xffffd000, // orange + CHAT_LINK_COLOR_ACHIEVEMENT = 0xffffff00, + CHAT_LINK_COLOR_GLYPH = 0xff66bbff +}; + +// Values from ItemPetFood (power of (value-1) used for compare with CreatureFamilyEntry.petDietMask +enum PetDiet +{ + PET_DIET_MEAT = 1, + PET_DIET_FISH = 2, + PET_DIET_CHEESE = 3, + PET_DIET_BREAD = 4, + PET_DIET_FUNGAS = 5, + PET_DIET_FRUIT = 6, + PET_DIET_RAW_MEAT = 7, + PET_DIET_RAW_FISH = 8 +}; + +#define MAX_PET_DIET 9 + +#define CHAIN_SPELL_JUMP_RADIUS 10 + +// Max values for Guild & Guild Bank +#define GUILD_BANK_MAX_TABS 6 // send by client for money log also +#define GUILD_BANK_MAX_SLOTS 98 +#define GUILD_BANK_MAX_LOGS 25 +#define GUILD_BANK_MONEY_LOGS_TAB 100 // used for money log in DB +#define GUILD_EVENTLOG_MAX_RECORDS 100 +#define GUILD_RANKS_MIN_COUNT 5 +#define GUILD_RANKS_MAX_COUNT 10 + +enum AiReaction +{ + AI_REACTION_ALERT = 0, // pre-aggro (used in client packet handler) + AI_REACTION_FRIENDLY = 1, // (NOT used in client packet handler) + AI_REACTION_HOSTILE = 2, // sent on every attack, triggers aggro sound (used in client packet handler) + AI_REACTION_AFRAID = 3, // seen for polymorph (when AI not in control of self?) (NOT used in client packet handler) + AI_REACTION_DESTROY = 4, // used on object destroy (NOT used in client packet handler) +}; + +// Diminishing Returns Types +enum DiminishingReturnsType +{ + DRTYPE_NONE = 0, // this spell is not diminished, but may have limited it's duration to 10s + DRTYPE_PLAYER = 1, // this spell is diminished only when applied on players + DRTYPE_ALL = 2 // this spell is diminished in every case +}; + +// Diminishing Return Groups +enum DiminishingGroup +{ + // Common Groups + DIMINISHING_NONE = 0, + DIMINISHING_CONTROL_STUN, // Player Controlled stuns + DIMINISHING_TRIGGER_STUN, // By aura proced stuns, usualy chance on hit talents + DIMINISHING_CONTROL_ROOT, // Immobilizing effects from casted spells + DIMINISHING_TRIGGER_ROOT, // Immobilizing effects from triggered spells like Frostbite + DIMINISHING_CHARM, + DIMINISHING_POLYMORPH, // Also: Gouge, Sap, Repentance, Hungering Cold + DIMINISHING_KNOCKOUT, // Sap, Knockout mechanics + DIMINISHING_FEAR_BLIND, // Intimidating Shout, Howl of Terror, Blind + // Warlock Specific + DIMINISHING_DEATHCOIL, // Death Coil Diminish only with another Death Coil + // Druid Specific + DIMINISHING_CYCLONE, // From 2.3.0 + // Shared Class Specific + DIMINISHING_CHEAPSHOT_POUNCE, + DIMINISHING_DISARM, // From 2.3.0 + DIMINISHING_SILENCE, // From 2.3.0 + DIMINISHING_FREEZE_SLEEP, // Hunter's Freezing Trap + DIMINISHING_BANISH, + DIMINISHING_TAUNT, + DIMINISHING_LIMITONLY // Don't Diminish, but limit duration to 10s +}; + +enum SummonCategory +{ + SUMMON_CATEGORY_WILD = 0, + SUMMON_CATEGORY_ALLY = 1, + SUMMON_CATEGORY_PET = 2, + SUMMON_CATEGORY_PUPPET = 3, + SUMMON_CATEGORY_VEHICLE = 4, +}; + +enum SummonType +{ + SUMMON_TYPE_NONE = 0, + SUMMON_TYPE_PET = 1, + SUMMON_TYPE_GUARDIAN = 2, + SUMMON_TYPE_MINION = 3, + SUMMON_TYPE_TOTEM = 4, + SUMMON_TYPE_MINIPET = 5, + SUMMON_TYPE_GUARDIAN2 = 6, + SUMMON_TYPE_WILD2 = 7, + SUMMON_TYPE_WILD3 = 8, + SUMMON_TYPE_VEHICLE = 9, + SUMMON_TYPE_VEHICLE2 = 10, + SUMMON_TYPE_OBJECT = 11, +}; + +enum EventId +{ + EVENT_SPELLCLICK = 1001, + EVENT_FALL_GROUND = 1002, + EVENT_CHARGE = 1003, +}; + +enum ResponseCodes +{ + RESPONSE_SUCCESS = 0x00, + RESPONSE_FAILURE = 0x01, + RESPONSE_CANCELLED = 0x02, + RESPONSE_DISCONNECTED = 0x03, + RESPONSE_FAILED_TO_CONNECT = 0x04, + RESPONSE_CONNECTED = 0x05, + RESPONSE_VERSION_MISMATCH = 0x06, + + CSTATUS_CONNECTING = 0x07, + CSTATUS_NEGOTIATING_SECURITY = 0x08, + CSTATUS_NEGOTIATION_COMPLETE = 0x09, + CSTATUS_NEGOTIATION_FAILED = 0x0A, + CSTATUS_AUTHENTICATING = 0x0B, + + AUTH_OK = 0x0C, + AUTH_FAILED = 0x0D, + AUTH_REJECT = 0x0E, + AUTH_BAD_SERVER_PROOF = 0x0F, + AUTH_UNAVAILABLE = 0x10, + AUTH_SYSTEM_ERROR = 0x11, + AUTH_BILLING_ERROR = 0x12, + AUTH_BILLING_EXPIRED = 0x13, + AUTH_VERSION_MISMATCH = 0x14, + AUTH_UNKNOWN_ACCOUNT = 0x15, + AUTH_INCORRECT_PASSWORD = 0x16, + AUTH_SESSION_EXPIRED = 0x17, + AUTH_SERVER_SHUTTING_DOWN = 0x18, + AUTH_ALREADY_LOGGING_IN = 0x19, + AUTH_LOGIN_SERVER_NOT_FOUND = 0x1A, + AUTH_WAIT_QUEUE = 0x1B, + AUTH_BANNED = 0x1C, + AUTH_ALREADY_ONLINE = 0x1D, + AUTH_NO_TIME = 0x1E, + AUTH_DB_BUSY = 0x1F, + AUTH_SUSPENDED = 0x20, + AUTH_PARENTAL_CONTROL = 0x21, + AUTH_LOCKED_ENFORCED = 0x22, + + REALM_LIST_IN_PROGRESS = 0x23, + REALM_LIST_SUCCESS = 0x24, + REALM_LIST_FAILED = 0x25, + REALM_LIST_INVALID = 0x26, + REALM_LIST_REALM_NOT_FOUND = 0x27, + + ACCOUNT_CREATE_IN_PROGRESS = 0x28, + ACCOUNT_CREATE_SUCCESS = 0x29, + ACCOUNT_CREATE_FAILED = 0x2A, + + CHAR_LIST_RETRIEVING = 0x2B, + CHAR_LIST_RETRIEVED = 0x2C, + CHAR_LIST_FAILED = 0x2D, + + CHAR_CREATE_IN_PROGRESS = 0x2E, + CHAR_CREATE_SUCCESS = 0x2F, + CHAR_CREATE_ERROR = 0x30, + CHAR_CREATE_FAILED = 0x31, + CHAR_CREATE_NAME_IN_USE = 0x32, + CHAR_CREATE_DISABLED = 0x33, + CHAR_CREATE_PVP_TEAMS_VIOLATION = 0x34, + CHAR_CREATE_SERVER_LIMIT = 0x35, + CHAR_CREATE_ACCOUNT_LIMIT = 0x36, + CHAR_CREATE_SERVER_QUEUE = 0x37, + CHAR_CREATE_ONLY_EXISTING = 0x38, + CHAR_CREATE_EXPANSION = 0x39, + CHAR_CREATE_EXPANSION_CLASS = 0x3A, + CHAR_CREATE_LEVEL_REQUIREMENT = 0x3B, + CHAR_CREATE_UNIQUE_CLASS_LIMIT = 0x3C, + CHAR_CREATE_CHARACTER_IN_GUILD = 0x3D, + CHAR_CREATE_RESTRICTED_RACECLASS = 0x3E, + CHAR_CREATE_CHARACTER_CHOOSE_RACE = 0x3F, + CHAR_CREATE_CHARACTER_ARENA_LEADER = 0x40, + CHAR_CREATE_CHARACTER_DELETE_MAIL = 0x41, + CHAR_CREATE_CHARACTER_SWAP_FACTION = 0x42, + CHAR_CREATE_CHARACTER_RACE_ONLY = 0x43, + + CHAR_CREATE_CHARACTER_GOLD_LIMIT = 0x44, + + CHAR_CREATE_FORCE_LOGIN = 0x45, + + CHAR_DELETE_IN_PROGRESS = 0x46, + CHAR_DELETE_SUCCESS = 0x47, + CHAR_DELETE_FAILED = 0x48, + CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 0x49, + CHAR_DELETE_FAILED_GUILD_LEADER = 0x4A, + CHAR_DELETE_FAILED_ARENA_CAPTAIN = 0x4B, + + CHAR_LOGIN_IN_PROGRESS = 0x4C, + CHAR_LOGIN_SUCCESS = 0x4D, + CHAR_LOGIN_NO_WORLD = 0x4E, + CHAR_LOGIN_DUPLICATE_CHARACTER = 0x4F, + CHAR_LOGIN_NO_INSTANCES = 0x50, + CHAR_LOGIN_FAILED = 0x51, + CHAR_LOGIN_DISABLED = 0x52, + CHAR_LOGIN_NO_CHARACTER = 0x53, + CHAR_LOGIN_LOCKED_FOR_TRANSFER = 0x54, + CHAR_LOGIN_LOCKED_BY_BILLING = 0x55, + CHAR_LOGIN_LOCKED_BY_MOBILE_AH = 0x56, + + CHAR_NAME_SUCCESS = 0x57, + CHAR_NAME_FAILURE = 0x58, + CHAR_NAME_NO_NAME = 0x59, + CHAR_NAME_TOO_SHORT = 0x5A, + CHAR_NAME_TOO_LONG = 0x5B, + CHAR_NAME_INVALID_CHARACTER = 0x5C, + CHAR_NAME_MIXED_LANGUAGES = 0x5D, + CHAR_NAME_PROFANE = 0x5E, + CHAR_NAME_RESERVED = 0x5F, + CHAR_NAME_INVALID_APOSTROPHE = 0x60, + CHAR_NAME_MULTIPLE_APOSTROPHES = 0x61, + CHAR_NAME_THREE_CONSECUTIVE = 0x62, + CHAR_NAME_INVALID_SPACE = 0x63, + CHAR_NAME_CONSECUTIVE_SPACES = 0x64, + CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 0x65, + CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 0x66, + CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 0x67 +}; + +/// Ban function modes +enum BanMode +{ + BAN_ACCOUNT, + BAN_CHARACTER, + BAN_IP +}; + +/// Ban function return codes +enum BanReturn +{ + BAN_SUCCESS, + BAN_SYNTAX_ERROR, + BAN_NOTFOUND +}; + +// indexes of BattlemasterList.dbc +enum BattleGroundTypeId +{ + BATTLEGROUND_TYPE_NONE = 0, + BATTLEGROUND_AV = 1, + BATTLEGROUND_WS = 2, + BATTLEGROUND_AB = 3, + BATTLEGROUND_NA = 4, + BATTLEGROUND_BE = 5, + BATTLEGROUND_AA = 6, + BATTLEGROUND_EY = 7, + BATTLEGROUND_RL = 8, + BATTLEGROUND_SA = 9, + BATTLEGROUND_DS = 10, + BATTLEGROUND_RV = 11, + BATTLEGROUND_IC = 30, + BATTLEGROUND_RB = 32 +}; + +#define MAX_BATTLEGROUND_TYPE_ID 33 + +enum MailResponseType +{ + MAIL_SEND = 0, + MAIL_MONEY_TAKEN = 1, + MAIL_ITEM_TAKEN = 2, + MAIL_RETURNED_TO_SENDER = 3, + MAIL_DELETED = 4, + MAIL_MADE_PERMANENT = 5 +}; + +enum MailResponseResult +{ + MAIL_OK = 0, + MAIL_ERR_EQUIP_ERROR = 1, + MAIL_ERR_CANNOT_SEND_TO_SELF = 2, + MAIL_ERR_NOT_ENOUGH_MONEY = 3, + MAIL_ERR_RECIPIENT_NOT_FOUND = 4, + MAIL_ERR_NOT_YOUR_TEAM = 5, + MAIL_ERR_INTERNAL_ERROR = 6, + MAIL_ERR_DISABLED_FOR_TRIAL_ACC = 14, + MAIL_ERR_RECIPIENT_CAP_REACHED = 15, + MAIL_ERR_CANT_SEND_WRAPPED_COD = 16, + MAIL_ERR_MAIL_AND_CHAT_SUSPENDED = 17, + MAIL_ERR_TOO_MANY_ATTACHMENTS = 18, + MAIL_ERR_MAIL_ATTACHMENT_INVALID = 19, + MAIL_ERR_ITEM_HAS_EXPIRED = 21, +}; + +enum SpellFamilyNames +{ + SPELLFAMILY_GENERIC = 0, + SPELLFAMILY_UNK1 = 1, // events, holidays + // 2 - unused + SPELLFAMILY_MAGE = 3, + SPELLFAMILY_WARRIOR = 4, + SPELLFAMILY_WARLOCK = 5, + SPELLFAMILY_PRIEST = 6, + SPELLFAMILY_DRUID = 7, + SPELLFAMILY_ROGUE = 8, + SPELLFAMILY_HUNTER = 9, + SPELLFAMILY_PALADIN = 10, + SPELLFAMILY_SHAMAN = 11, + SPELLFAMILY_UNK2 = 12, // 2 spells (silence resistance) + SPELLFAMILY_POTION = 13, + // 14 - unused + SPELLFAMILY_DEATHKNIGHT = 15, + // 16 - unused + SPELLFAMILY_PET = 17 +}; + +#endif diff --git a/src/server/game/Movement/MovementGenerator.cpp b/src/server/game/Movement/MovementGenerator.cpp new file mode 100644 index 00000000000..2cccf8a76dc --- /dev/null +++ b/src/server/game/Movement/MovementGenerator.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MovementGenerator.h" + +MovementGenerator::~MovementGenerator() +{ +} + + diff --git a/src/server/game/Movement/MovementGenerator.h b/src/server/game/Movement/MovementGenerator.h new file mode 100644 index 00000000000..ab7a52c483e --- /dev/null +++ b/src/server/game/Movement/MovementGenerator.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_MOVEMENTGENERATOR_H +#define TRINITY_MOVEMENTGENERATOR_H + +#include "Platform/Define.h" +#include "Policies/Singleton.h" +#include "Dynamic/ObjectRegistry.h" +#include "Dynamic/FactoryHolder.h" +#include "Common.h" +#include "MotionMaster.h" + +class Unit; + +class MovementGenerator +{ + public: + virtual ~MovementGenerator(); + + virtual void Initialize(Unit &) = 0; + virtual void Finalize(Unit &) = 0; + + virtual void Reset(Unit &) = 0; + + virtual bool Update(Unit &, const uint32 &time_diff) = 0; + + virtual MovementGeneratorType GetMovementGeneratorType() = 0; + + virtual void unitSpeedChanged() { } + + virtual bool GetDestination(float& /*x*/, float& /*y*/, float& /*z*/) const { return false; } +}; + +template +class MovementGeneratorMedium : public MovementGenerator +{ + public: + void Initialize(Unit &u) + { + //u->AssertIsType(); + (static_cast(this))->Initialize(*((T*)&u)); + } + void Finalize(Unit &u) + { + //u->AssertIsType(); + (static_cast(this))->Finalize(*((T*)&u)); + } + void Reset(Unit &u) + { + //u->AssertIsType(); + (static_cast(this))->Reset(*((T*)&u)); + } + bool Update(Unit &u, const uint32 &time_diff) + { + //u->AssertIsType(); + return (static_cast(this))->Update(*((T*)&u), time_diff); + } + public: + // will not link if not overridden in the generators + void Initialize(T &u); + void Finalize(T &u); + void Reset(T &u); + bool Update(T &u, const uint32 &time_diff); +}; + +struct SelectableMovement : public FactoryHolder +{ + SelectableMovement(MovementGeneratorType mgt) : FactoryHolder(mgt) {} +}; + +template +struct MovementGeneratorFactory : public SelectableMovement +{ + MovementGeneratorFactory(MovementGeneratorType mgt) : SelectableMovement(mgt) {} + + MovementGenerator* Create(void *) const; +}; + +typedef FactoryHolder MovementGeneratorCreator; +typedef FactoryHolder::FactoryHolderRegistry MovementGeneratorRegistry; +typedef FactoryHolder::FactoryHolderRepository MovementGeneratorRepository; +#endif + + diff --git a/src/server/game/Movement/MovementGeneratorImpl.h b/src/server/game/Movement/MovementGeneratorImpl.h new file mode 100644 index 00000000000..d2778a5bff8 --- /dev/null +++ b/src/server/game/Movement/MovementGeneratorImpl.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_MOVEMENTGENERATOR_IMPL_H +#define TRINITY_MOVEMENTGENERATOR_IMPL_H + +#include "MovementGenerator.h" + +template +inline MovementGenerator* +MovementGeneratorFactory::Create(void * /*data*/) const +{ + return (new MOVEMENT_GEN()); +} +#endif + + diff --git a/src/server/game/Movement/MovementGenerators/MovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/MovementGenerator.cpp deleted file mode 100644 index 2cccf8a76dc..00000000000 --- a/src/server/game/Movement/MovementGenerators/MovementGenerator.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "MovementGenerator.h" - -MovementGenerator::~MovementGenerator() -{ -} - - diff --git a/src/server/game/Movement/MovementGenerators/MovementGenerator.h b/src/server/game/Movement/MovementGenerators/MovementGenerator.h deleted file mode 100644 index ab7a52c483e..00000000000 --- a/src/server/game/Movement/MovementGenerators/MovementGenerator.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_MOVEMENTGENERATOR_H -#define TRINITY_MOVEMENTGENERATOR_H - -#include "Platform/Define.h" -#include "Policies/Singleton.h" -#include "Dynamic/ObjectRegistry.h" -#include "Dynamic/FactoryHolder.h" -#include "Common.h" -#include "MotionMaster.h" - -class Unit; - -class MovementGenerator -{ - public: - virtual ~MovementGenerator(); - - virtual void Initialize(Unit &) = 0; - virtual void Finalize(Unit &) = 0; - - virtual void Reset(Unit &) = 0; - - virtual bool Update(Unit &, const uint32 &time_diff) = 0; - - virtual MovementGeneratorType GetMovementGeneratorType() = 0; - - virtual void unitSpeedChanged() { } - - virtual bool GetDestination(float& /*x*/, float& /*y*/, float& /*z*/) const { return false; } -}; - -template -class MovementGeneratorMedium : public MovementGenerator -{ - public: - void Initialize(Unit &u) - { - //u->AssertIsType(); - (static_cast(this))->Initialize(*((T*)&u)); - } - void Finalize(Unit &u) - { - //u->AssertIsType(); - (static_cast(this))->Finalize(*((T*)&u)); - } - void Reset(Unit &u) - { - //u->AssertIsType(); - (static_cast(this))->Reset(*((T*)&u)); - } - bool Update(Unit &u, const uint32 &time_diff) - { - //u->AssertIsType(); - return (static_cast(this))->Update(*((T*)&u), time_diff); - } - public: - // will not link if not overridden in the generators - void Initialize(T &u); - void Finalize(T &u); - void Reset(T &u); - bool Update(T &u, const uint32 &time_diff); -}; - -struct SelectableMovement : public FactoryHolder -{ - SelectableMovement(MovementGeneratorType mgt) : FactoryHolder(mgt) {} -}; - -template -struct MovementGeneratorFactory : public SelectableMovement -{ - MovementGeneratorFactory(MovementGeneratorType mgt) : SelectableMovement(mgt) {} - - MovementGenerator* Create(void *) const; -}; - -typedef FactoryHolder MovementGeneratorCreator; -typedef FactoryHolder::FactoryHolderRegistry MovementGeneratorRegistry; -typedef FactoryHolder::FactoryHolderRepository MovementGeneratorRepository; -#endif - - diff --git a/src/server/game/Movement/MovementGenerators/MovementGeneratorImpl.h b/src/server/game/Movement/MovementGenerators/MovementGeneratorImpl.h deleted file mode 100644 index d2778a5bff8..00000000000 --- a/src/server/game/Movement/MovementGenerators/MovementGeneratorImpl.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_MOVEMENTGENERATOR_IMPL_H -#define TRINITY_MOVEMENTGENERATOR_IMPL_H - -#include "MovementGenerator.h" - -template -inline MovementGenerator* -MovementGeneratorFactory::Create(void * /*data*/) const -{ - return (new MOVEMENT_GEN()); -} -#endif - - diff --git a/src/server/game/Movement/MovementHandler.cpp b/src/server/game/Movement/MovementHandler.cpp deleted file mode 100644 index 1148fe174fc..00000000000 --- a/src/server/game/Movement/MovementHandler.cpp +++ /dev/null @@ -1,746 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" -#include "Corpse.h" -#include "Player.h" -#include "Vehicle.h" -#include "SpellAuras.h" -#include "MapManager.h" -#include "Transports.h" -#include "BattleGround.h" -#include "WaypointMovementGenerator.h" -#include "InstanceSaveMgr.h" -#include "ObjectMgr.h" - -void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("WORLD: got MSG_MOVE_WORLDPORT_ACK."); - HandleMoveWorldportAckOpcode(); -} - -void WorldSession::HandleMoveWorldportAckOpcode() -{ - // ignore unexpected far teleports - if (!GetPlayer()->IsBeingTeleportedFar()) - return; - - // get the teleport destination - WorldLocation &loc = GetPlayer()->GetTeleportDest(); - - // possible errors in the coordinate validity check - if (!MapManager::IsValidMapCoord(loc)) - { - LogoutPlayer(false); - return; - } - - // get the destination map entry, not the current one, this will fix homebind and reset greeting - MapEntry const* mEntry = sMapStore.LookupEntry(loc.GetMapId()); - InstanceTemplate const* mInstance = objmgr.GetInstanceTemplate(loc.GetMapId()); - - // reset instance validity, except if going to an instance inside an instance - if (GetPlayer()->m_InstanceValid == false && !mInstance) - GetPlayer()->m_InstanceValid = true; - - GetPlayer()->SetSemaphoreTeleportFar(false); - - Map * oldMap = GetPlayer()->GetMap(); - assert(oldMap); - if (GetPlayer()->IsInWorld()) - { - sLog.outCrash("Player is still in world when teleported from map %u! to new map %u", oldMap->GetId(), loc.GetMapId()); - oldMap->Remove(GetPlayer(), false); - } - - // relocate the player to the teleport destination - Map * newMap = MapManager::Instance().CreateMap(loc.GetMapId(), GetPlayer(), 0); - // the CanEnter checks are done in TeleporTo but conditions may change - // while the player is in transit, for example the map may get full - if (!newMap || !newMap->CanEnter(GetPlayer())) - { - sLog.outError("Map %d could not be created for player %d, porting player to homebind", loc.GetMapId(), GetPlayer()->GetGUIDLow()); - GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation()); - return; - } - else - GetPlayer()->Relocate(&loc); - - GetPlayer()->ResetMap(); - GetPlayer()->SetMap(newMap); - - GetPlayer()->SendInitialPacketsBeforeAddToMap(); - if (!GetPlayer()->GetMap()->Add(GetPlayer())) - { - sLog.outError("WORLD: failed to teleport player %s (%d) to map %d because of unknown reason!", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.GetMapId()); - GetPlayer()->ResetMap(); - GetPlayer()->SetMap(oldMap); - GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation()); - return; - } - - // battleground state prepare (in case join to BG), at relogin/tele player not invited - // only add to bg group and object, if the player was invited (else he entered through command) - if (_player->InBattleGround()) - { - // cleanup setting if outdated - if (!mEntry->IsBattleGroundOrArena()) - { - // We're not in BG - _player->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); - // reset destination bg team - _player->SetBGTeam(0); - } - // join to bg case - else if (BattleGround *bg = _player->GetBattleGround()) - { - if (_player->IsInvitedForBattleGroundInstance(_player->GetBattleGroundId())) - bg->AddPlayer(_player); - } - } - - GetPlayer()->SendInitialPacketsAfterAddToMap(); - - // flight fast teleport case - if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) - { - if (!_player->InBattleGround()) - { - // short preparations to continue flight - FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); - flight->Initialize(*GetPlayer()); - return; - } - - // battleground state prepare, stop flight - GetPlayer()->GetMotionMaster()->MovementExpired(); - GetPlayer()->CleanupAfterTaxiFlight(); - } - - // resurrect character at enter into instance where his corpse exist after add to map - Corpse *corpse = GetPlayer()->GetCorpse(); - if (corpse && corpse->GetType() != CORPSE_BONES && corpse->GetMapId() == GetPlayer()->GetMapId()) - { - if (mEntry->IsDungeon()) - { - GetPlayer()->ResurrectPlayer(0.5f,false); - GetPlayer()->SpawnCorpseBones(); - } - } - - bool allowMount = !mEntry->IsDungeon() || mEntry->IsBattleGroundOrArena(); - if (mInstance) - { - Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid()); - if (MapDifficulty const* mapDiff = GetMapDifficultyData(mEntry->MapID,diff)) - { - if (mapDiff->resetTime) - { - if (uint32 timeReset = sInstanceSaveManager.GetResetTimeFor(mEntry->MapID,diff)) - { - uint32 timeleft = timeReset - time(NULL); - GetPlayer()->SendInstanceResetWarning(mEntry->MapID, diff, timeleft); - } - } - } - allowMount = mInstance->allowMount; - } - - // mount allow check - if (!allowMount) - _player->RemoveAurasByType(SPELL_AURA_MOUNTED); - - // update zone immediately, otherwise leave channel will cause crash in mtmap - uint32 newzone, newarea; - GetPlayer()->GetZoneAndAreaId(newzone, newarea); - GetPlayer()->UpdateZone(newzone, newarea); - - // honorless target - if (GetPlayer()->pvpInfo.inHostileArea) - GetPlayer()->CastSpell(GetPlayer(), 2479, true); - - // resummon pet - GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); - - //lets process all delayed operations on successful teleport - GetPlayer()->ProcessDelayedOperations(); -} - -void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data) -{ - sLog.outDebug("MSG_MOVE_TELEPORT_ACK"); - uint64 guid; - - if (!recv_data.readPackGUID(guid)) - return; - - uint32 flags, time; - recv_data >> flags >> time; - DEBUG_LOG("Guid " UI64FMTD, guid); - DEBUG_LOG("Flags %u, time %u", flags, time/IN_MILISECONDS); - - Unit *mover = _player->m_mover; - Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; - - if (!plMover || !plMover->IsBeingTeleportedNear()) - return; - - if (guid != plMover->GetGUID()) - return; - - plMover->SetSemaphoreTeleportNear(false); - - uint32 old_zone = plMover->GetZoneId(); - - WorldLocation const& dest = plMover->GetTeleportDest(); - - plMover->SetPosition(dest,true); - - uint32 newzone, newarea; - plMover->GetZoneAndAreaId(newzone, newarea); - plMover->UpdateZone(newzone, newarea); - - // new zone - if (old_zone != newzone) - { - // honorless target - if (plMover->pvpInfo.inHostileArea) - plMover->CastSpell(plMover, 2479, true); - } - - // resummon pet - GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); - - //lets process all delayed operations on successful teleport - GetPlayer()->ProcessDelayedOperations(); -} - -void WorldSession::HandleMovementOpcodes(WorldPacket & recv_data) -{ - uint16 opcode = recv_data.GetOpcode(); - //sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); - recv_data.hexlike(); - - Unit *mover = _player->m_mover; - - assert(mover != NULL); // there must always be a mover - - Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; - - // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck - if (plMover && plMover->IsBeingTeleported()) - { - recv_data.rpos(recv_data.wpos()); // prevent warnings spam - return; - } - - /* extract packet */ - uint64 guid; - - if (!recv_data.readPackGUID(guid)) - return; - - MovementInfo movementInfo; - movementInfo.guid = guid; - ReadMovementInfo(recv_data, &movementInfo); - /*----------------*/ - - /* if (recv_data.size() != recv_data.rpos()) - { - sLog.outError("MovementHandler: player %s (guid %d, account %u) sent a packet (opcode %u) that is " SIZEFMTD " bytes larger than it should be. Kicked as cheater.", _player->GetName(), _player->GetGUIDLow(), _player->GetSession()->GetAccountId(), recv_data.GetOpcode(), recv_data.size() - recv_data.rpos()); - KickPlayer();*/ - recv_data.rpos(recv_data.wpos()); // prevent warnings spam - /* return; - }*/ - - if (!Trinity::IsValidMapCoord(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o)) - { - recv_data.rpos(recv_data.wpos()); // prevent warnings spam - return; - } - - /* handle special cases */ - if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) - { - // transports size limited - // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) - if (movementInfo.t_x > 50 || movementInfo.t_y > 50 || movementInfo.t_z > 50) - { - recv_data.rpos(recv_data.wpos()); // prevent warnings spam - return; - } - - if (!Trinity::IsValidMapCoord(movementInfo.x+movementInfo.t_x, movementInfo.y + movementInfo.t_y, - movementInfo.z + movementInfo.t_z, movementInfo.o + movementInfo.t_o)) - { - recv_data.rpos(recv_data.wpos()); // prevent warnings spam - return; - } - - // if we boarded a transport, add us to it - if (plMover && !plMover->GetTransport()) - { - // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list - for (MapManager::TransportSet::const_iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter) - { - if ((*iter)->GetGUID() == movementInfo.t_guid) - { - plMover->m_transport = (*iter); - (*iter)->AddPassenger(plMover); - break; - } - } - } - - if (!mover->GetTransport() && !mover->GetVehicle()) - { - GameObject *go = mover->GetMap()->GetGameObject(movementInfo.t_guid); - if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) - movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; - } - } - else if (plMover && plMover->GetTransport()) // if we were on a transport, leave - { - plMover->m_transport->RemovePassenger(plMover); - plMover->m_transport = NULL; - movementInfo.t_x = 0.0f; - movementInfo.t_y = 0.0f; - movementInfo.t_z = 0.0f; - movementInfo.t_o = 0.0f; - movementInfo.t_time = 0; - movementInfo.t_seat = -1; - } - - // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). - if (opcode == MSG_MOVE_FALL_LAND && plMover && !plMover->isInFlight()) - plMover->HandleFall(movementInfo); - - if (plMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plMover->IsInWater()) - { - // now client not include swimming flag in case jumping under water - plMover->SetInWater(!plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.x, movementInfo.y, movementInfo.z)); - } - - /*----------------------*/ - - /* process position-change */ - WorldPacket data(opcode, recv_data.size()); - movementInfo.time = getMSTime(); - movementInfo.guid = mover->GetGUID(); - WriteMovementInfo(&data, &movementInfo); - mover->SendMessageToSet(&data, _player); - - mover->m_movementInfo = movementInfo; - - // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() - if (mover->GetVehicle()) - { - mover->SetOrientation(movementInfo.o); - return; - } - - mover->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); - - if (plMover) // nothing is charmed, or player charmed - { - plMover->UpdateFallInformationIfNeed(movementInfo, opcode); - - if (movementInfo.z < -500.0f) - { - if (plMover->InBattleGround() - && plMover->GetBattleGround() - && plMover->GetBattleGround()->HandlePlayerUnderMap(_player)) - { - // do nothing, the handle already did if returned true - } - else - { - // NOTE: this is actually called many times while falling - // even after the player has been teleported away - // TODO: discard movement packets after the player is rooted - if (plMover->isAlive()) - { - plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); - // pl can be alive if GM/etc - if (!plMover->isAlive()) - { - // change the death state to CORPSE to prevent the death timer from - // starting in the next player update - plMover->KillPlayer(); - plMover->BuildPlayerRepop(); - } - } - - // cancel the death timer here if started - plMover->RepopAtGraveyard(); - } - } - } - /*else // creature charmed - { - if (mover->canFly()) - { - bool flying = mover->IsFlying(); - if (flying != ((mover->GetByteValue(UNIT_FIELD_BYTES_1, 3) & 0x02) ? true : false)) - mover->SetFlying(flying); - } - }*/ - - //sLog.outString("Receive Movement Packet %s:", opcodeTable[recv_data.GetOpcode()]); - //mover->OutMovementInfo(); -} - -void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recv_data) -{ - uint32 opcode = recv_data.GetOpcode(); - sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); - - /* extract packet */ - uint64 guid; - uint32 unk1; - float newspeed; - - if (!recv_data.readPackGUID(guid)) - return; - - // now can skip not our packet - if (_player->GetGUID() != guid) - { - recv_data.rpos(recv_data.wpos()); // prevent warnings spam - return; - } - - // continue parse packet - - recv_data >> unk1; // counter or moveEvent - - MovementInfo movementInfo; - movementInfo.guid = guid; - ReadMovementInfo(recv_data, &movementInfo); - - recv_data >> newspeed; - /*----------------*/ - - // client ACK send one packet for mounted/run case and need skip all except last from its - // in other cases anti-cheat check can be fail in false case - UnitMoveType move_type; - UnitMoveType force_move_type; - - static char const* move_type_name[MAX_MOVE_TYPE] = { "Walk", "Run", "RunBack", "Swim", "SwimBack", "TurnRate", "Flight", "FlightBack", "PitchRate" }; - - switch(opcode) - { - case CMSG_FORCE_WALK_SPEED_CHANGE_ACK: move_type = MOVE_WALK; force_move_type = MOVE_WALK; break; - case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: move_type = MOVE_RUN; force_move_type = MOVE_RUN; break; - case CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK: move_type = MOVE_RUN_BACK; force_move_type = MOVE_RUN_BACK; break; - case CMSG_FORCE_SWIM_SPEED_CHANGE_ACK: move_type = MOVE_SWIM; force_move_type = MOVE_SWIM; break; - case CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK: move_type = MOVE_SWIM_BACK; force_move_type = MOVE_SWIM_BACK; break; - case CMSG_FORCE_TURN_RATE_CHANGE_ACK: move_type = MOVE_TURN_RATE; force_move_type = MOVE_TURN_RATE; break; - case CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT; force_move_type = MOVE_FLIGHT; break; - case CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT_BACK; force_move_type = MOVE_FLIGHT_BACK; break; - case CMSG_FORCE_PITCH_RATE_CHANGE_ACK: move_type = MOVE_PITCH_RATE; force_move_type = MOVE_PITCH_RATE; break; - default: - sLog.outError("WorldSession::HandleForceSpeedChangeAck: Unknown move type opcode: %u", opcode); - return; - } - - // skip all forced speed changes except last and unexpected - // in run/mounted case used one ACK and it must be skipped.m_forced_speed_changes[MOVE_RUN} store both. - if (_player->m_forced_speed_changes[force_move_type] > 0) - { - --_player->m_forced_speed_changes[force_move_type]; - if (_player->m_forced_speed_changes[force_move_type] > 0) - return; - } - - if (!_player->GetTransport() && fabs(_player->GetSpeed(move_type) - newspeed) > 0.01f) - { - if (_player->GetSpeed(move_type) > newspeed) // must be greater - just correct - { - sLog.outError("%sSpeedChange player %s is NOT correct (must be %f instead %f), force set to correct value", - move_type_name[move_type], _player->GetName(), _player->GetSpeed(move_type), newspeed); - _player->SetSpeed(move_type,_player->GetSpeedRate(move_type),true); - } - else // must be lesser - cheating - { - sLog.outBasic("Player %s from account id %u kicked for incorrect speed (must be %f instead %f)", - _player->GetName(),_player->GetSession()->GetAccountId(),_player->GetSpeed(move_type), newspeed); - _player->GetSession()->KickPlayer(); - } - } -} - -void WorldSession::HandleSetActiveMoverOpcode(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: Recvd CMSG_SET_ACTIVE_MOVER"); - - uint64 guid; - recv_data >> guid; - - if (GetPlayer()->IsInWorld()) - if (Unit *mover = ObjectAccessor::GetUnit(*GetPlayer(), guid)) - { - GetPlayer()->SetMover(mover); - if (mover != GetPlayer() && mover->canFly()) - { - WorldPacket data(SMSG_MOVE_SET_CAN_FLY, 12); - data.append(mover->GetPackGUID()); - data << uint32(0); - SendPacket(&data); - } - } - else - { - sLog.outError("HandleSetActiveMoverOpcode: incorrect mover guid: mover is " UI64FMTD " and should be " UI64FMTD, guid, _player->m_mover->GetGUID()); - GetPlayer()->SetMover(GetPlayer()); - } -} - -void WorldSession::HandleMoveNotActiveMover(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: Recvd CMSG_MOVE_NOT_ACTIVE_MOVER"); - - uint64 old_mover_guid; - if (!recv_data.readPackGUID(old_mover_guid)) - return; - - /*if (_player->m_mover->GetGUID() == old_mover_guid) - { - sLog.outError("HandleMoveNotActiveMover: incorrect mover guid: mover is " I64FMT " and should be " I64FMT " instead of " I64FMT, _player->m_mover->GetGUID(), _player->GetGUID(), old_mover_guid); - recv_data.rpos(recv_data.wpos()); // prevent warnings spam - return; - }*/ - - MovementInfo mi; - mi.guid = old_mover_guid; - ReadMovementInfo(recv_data, &mi); - - //ReadMovementInfo(recv_data, &_player->m_mover->m_movementInfo); - _player->m_movementInfo = mi; -} - -void WorldSession::HandleDismissControlledVehicle(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: Recvd CMSG_DISMISS_CONTROLLED_VEHICLE"); - recv_data.hexlike(); - - uint64 vehicleGUID = _player->GetCharmGUID(); - - if (!vehicleGUID) // something wrong here... - { - recv_data.rpos(recv_data.wpos()); // prevent warnings spam - return; - } - - uint64 guid; - - if (!recv_data.readPackGUID(guid)) - return; - - MovementInfo mi; - mi.guid = guid; - ReadMovementInfo(recv_data, &mi); - - _player->m_movementInfo = mi; - - /* - ReadMovementInfo(recv_data, &_player->m_mover->m_movementInfo);*/ - _player->ExitVehicle(); -} - -void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: Recvd CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE"); - recv_data.hexlike(); - - Unit* vehicle_base = GetPlayer()->GetVehicleBase(); - if (!vehicle_base) - return; - - switch (recv_data.GetOpcode()) - { - case CMSG_REQUEST_VEHICLE_PREV_SEAT: - GetPlayer()->ChangeSeat(-1, false); - break; - case CMSG_REQUEST_VEHICLE_NEXT_SEAT: - GetPlayer()->ChangeSeat(-1, true); - break; - case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: - { - uint64 guid; // current vehicle guid - if (!recv_data.readPackGUID(guid)) - return; - - ReadMovementInfo(recv_data, &vehicle_base->m_movementInfo); - - uint64 accessory; // accessory guid - if (!recv_data.readPackGUID(accessory)) - return; - - int8 seatId; - recv_data >> seatId; - - if (vehicle_base->GetGUID() != guid) - return; - - if (!accessory) - GetPlayer()->ChangeSeat(-1, seatId > 0); // prev/next - else if (Unit *vehUnit = Unit::GetUnit(*GetPlayer(), accessory)) - { - if (Vehicle *vehicle = vehUnit->GetVehicleKit()) - if (vehicle->HasEmptySeat(seatId)) - GetPlayer()->EnterVehicle(vehicle, seatId); - } - } - break; - case CMSG_REQUEST_VEHICLE_SWITCH_SEAT: - { - uint64 guid; // current vehicle guid - if (!recv_data.readPackGUID(guid)) - return; - - int8 seatId; - recv_data >> seatId; - - if (vehicle_base->GetGUID() == guid) - GetPlayer()->ChangeSeat(seatId); - else if (Unit *vehUnit = Unit::GetUnit(*GetPlayer(), guid)) - if (Vehicle *vehicle = vehUnit->GetVehicleKit()) - if (vehicle->HasEmptySeat(seatId)) - GetPlayer()->EnterVehicle(vehicle, seatId); - } - break; - default: - break; - } -} - -void WorldSession::HandleEnterPlayerVehicle(WorldPacket &data) -{ - // Read guid - uint64 guid; - data >> guid; - - if (Player* pl=ObjectAccessor::FindPlayer(guid)) - { - if (!pl->GetVehicleKit()) - return; - if (!pl->IsInRaidWith(_player)) - return; - if (!pl->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) - return; - _player->EnterVehicle(pl); - } -} - -void WorldSession::HandleEjectPasenger(WorldPacket &data) -{ - if (data.GetOpcode() == CMSG_EJECT_PASSENGER) - { - if (Vehicle* Vv= _player->GetVehicleKit()) - { - uint64 guid; - data >> guid; - if (Player* Pl=ObjectAccessor::FindPlayer(guid)) - Pl->ExitVehicle(); - } - } -} - -void WorldSession::HandleRequestVehicleExit(WorldPacket &recv_data) -{ - sLog.outDebug("WORLD: Recvd CMSG_REQUEST_VEHICLE_EXIT"); - recv_data.hexlike(); - GetPlayer()->ExitVehicle(); -} - -void WorldSession::HandleMountSpecialAnimOpcode(WorldPacket& /*recvdata*/) -{ - //sLog.outDebug("WORLD: Recvd CMSG_MOUNTSPECIAL_ANIM"); - - WorldPacket data(SMSG_MOUNTSPECIAL_ANIM, 8); - data << uint64(GetPlayer()->GetGUID()); - - GetPlayer()->SendMessageToSet(&data, false); -} - -void WorldSession::HandleMoveKnockBackAck(WorldPacket & recv_data) -{ - sLog.outDebug("CMSG_MOVE_KNOCK_BACK_ACK"); - - uint64 guid; // guid - unused - if (!recv_data.readPackGUID(guid)) - return; - - recv_data.read_skip(); // unk - - MovementInfo movementInfo; - ReadMovementInfo(recv_data, &movementInfo); -} - -void WorldSession::HandleMoveHoverAck(WorldPacket& recv_data) -{ - sLog.outDebug("CMSG_MOVE_HOVER_ACK"); - - uint64 guid; // guid - unused - if (!recv_data.readPackGUID(guid)) - return; - - recv_data.read_skip(); // unk - - MovementInfo movementInfo; - ReadMovementInfo(recv_data, &movementInfo); - - recv_data.read_skip(); // unk2 -} - -void WorldSession::HandleMoveWaterWalkAck(WorldPacket& recv_data) -{ - sLog.outDebug("CMSG_MOVE_WATER_WALK_ACK"); - - uint64 guid; // guid - unused - if (!recv_data.readPackGUID(guid)) - return; - - recv_data.read_skip(); // unk - - MovementInfo movementInfo; - ReadMovementInfo(recv_data, &movementInfo); - - recv_data.read_skip(); // unk2 -} - -void WorldSession::HandleSummonResponseOpcode(WorldPacket& recv_data) -{ - if (!_player->isAlive() || _player->isInCombat()) - return; - - uint64 summoner_guid; - bool agree; - recv_data >> summoner_guid; - recv_data >> agree; - - _player->SummonIfPossible(agree); -} - diff --git a/src/server/game/Movement/Path.h b/src/server/game/Movement/Path.h deleted file mode 100644 index 9ec079f3c9c..00000000000 --- a/src/server/game/Movement/Path.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITYCORE_PATH_H -#define TRINITYCORE_PATH_H - -#include "Common.h" -#include - -class Path -{ - public: - struct PathNode - { - float x,y,z; - }; - - void SetLength(const unsigned int sz) - { - i_nodes.resize(sz); - } - - unsigned int Size() const { return i_nodes.size(); } - bool Empty() const { return i_nodes.empty(); } - void Resize(unsigned int sz) { i_nodes.resize(sz); } - void Clear(void) { i_nodes.clear(); } - PathNode const* GetNodes(uint32 start = 0) const { return &i_nodes[start]; } - float GetTotalLength() const { return GetTotalLength(0,Size()); } - float GetTotalLength(uint32 start, uint32 end) const - { - float len = 0, xd, yd, zd; - for (unsigned int idx=start+1; idx < end; ++idx) - { - xd = i_nodes[ idx ].x - i_nodes[ idx-1 ].x; - yd = i_nodes[ idx ].y - i_nodes[ idx-1 ].y; - zd = i_nodes[ idx ].z - i_nodes[ idx-1 ].z; - len += sqrtf(xd*xd + yd*yd + zd*zd); - } - return len; - } - - float GetPassedLength(uint32 curnode, float x, float y, float z) - { - float len = 0, xd, yd, zd; - for (unsigned int idx=1; idx < curnode; ++idx) - { - xd = i_nodes[ idx ].x - i_nodes[ idx-1 ].x; - yd = i_nodes[ idx ].y - i_nodes[ idx-1 ].y; - zd = i_nodes[ idx ].z - i_nodes[ idx-1 ].z; - len += sqrtf(xd*xd + yd*yd + zd*zd); - } - - if (curnode > 0) - { - xd = x - i_nodes[curnode-1].x; - yd = y - i_nodes[curnode-1].y; - zd = z - i_nodes[curnode-1].z; - len += sqrtf(xd*xd + yd*yd + zd*zd); - } - - return len; - } - - PathNode& operator[](const unsigned int idx) { return i_nodes[idx]; } - const PathNode& operator()(const unsigned int idx) const { return i_nodes[idx]; } - - protected: - std::vector i_nodes; -}; -#endif - diff --git a/src/server/game/Movement/TaxiHandler.cpp b/src/server/game/Movement/TaxiHandler.cpp deleted file mode 100644 index b0660527f71..00000000000 --- a/src/server/game/Movement/TaxiHandler.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "UpdateMask.h" -#include "Path.h" -#include "WaypointMovementGenerator.h" -#include "DestinationHolderImp.h" - -void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_TAXINODE_STATUS_QUERY"); - - uint64 guid; - - recv_data >> guid; - SendTaxiStatus(guid); -} - -void WorldSession::SendTaxiStatus(uint64 guid) -{ - // cheating checks - Creature *unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - { - sLog.outDebug("WorldSession::SendTaxiStatus - Unit (GUID: %u) not found.", uint32(GUID_LOPART(guid))); - return; - } - - uint32 curloc = objmgr.GetNearestTaxiNode(unit->GetPositionX(),unit->GetPositionY(),unit->GetPositionZ(),unit->GetMapId(),GetPlayer()->GetTeam()); - - // not found nearest - if (curloc == 0) - return; - - sLog.outDebug("WORLD: current location %u ",curloc); - - WorldPacket data(SMSG_TAXINODE_STATUS, 9); - data << guid; - data << uint8(GetPlayer()->m_taxi.IsTaximaskNodeKnown(curloc) ? 1 : 0); - SendPacket(&data); - sLog.outDebug("WORLD: Sent SMSG_TAXINODE_STATUS"); -} - -void WorldSession::HandleTaxiQueryAvailableNodes(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_TAXIQUERYAVAILABLENODES"); - - uint64 guid; - recv_data >> guid; - - // cheating checks - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); - if (!unit) - { - sLog.outDebug("WORLD: HandleTaxiQueryAvailableNodes - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - // unknown taxi node case - if (SendLearnNewTaxiNode(unit)) - return; - - // known taxi node case - SendTaxiMenu(unit); -} - -void WorldSession::SendTaxiMenu(Creature* unit) -{ - // find current node - uint32 curloc = objmgr.GetNearestTaxiNode(unit->GetPositionX(),unit->GetPositionY(),unit->GetPositionZ(),unit->GetMapId(),GetPlayer()->GetTeam()); - - if (curloc == 0) - return; - - bool lastTaxiCheaterState = GetPlayer()->isTaxiCheater(); - if (unit->GetEntry() == 29480) GetPlayer()->SetTaxiCheater(true); // Grimwing in Ebon Hold, special case. NOTE: Not perfect, Zul'Aman should not be included according to WoWhead, and I think taxicheat includes it. - - sLog.outDebug("WORLD: CMSG_TAXINODE_STATUS_QUERY %u ",curloc); - - WorldPacket data(SMSG_SHOWTAXINODES, (4+8+4+8*4)); - data << uint32(1); - data << uint64(unit->GetGUID()); - data << uint32(curloc); - GetPlayer()->m_taxi.AppendTaximaskTo(data,GetPlayer()->isTaxiCheater()); - SendPacket(&data); - - sLog.outDebug("WORLD: Sent SMSG_SHOWTAXINODES"); - - GetPlayer()->SetTaxiCheater(lastTaxiCheaterState); -} - -void WorldSession::SendDoFlight(uint32 mountDisplayId, uint32 path, uint32 pathNode) -{ - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - while (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) - GetPlayer()->GetMotionMaster()->MovementExpired(false); - - if (mountDisplayId) - GetPlayer()->Mount(mountDisplayId); - - GetPlayer()->GetMotionMaster()->MoveTaxiFlight(path,pathNode); -} - -bool WorldSession::SendLearnNewTaxiNode(Creature* unit) -{ - // find current node - uint32 curloc = objmgr.GetNearestTaxiNode(unit->GetPositionX(),unit->GetPositionY(),unit->GetPositionZ(),unit->GetMapId(),GetPlayer()->GetTeam()); - - if (curloc == 0) - return true; // `true` send to avoid WorldSession::SendTaxiMenu call with one more curlock seartch with same false result. - - if (GetPlayer()->m_taxi.SetTaximaskNode(curloc)) - { - WorldPacket msg(SMSG_NEW_TAXI_PATH, 0); - SendPacket(&msg); - - WorldPacket update(SMSG_TAXINODE_STATUS, 9); - update << uint64(unit->GetGUID()); - update << uint8(1); - SendPacket(&update); - - return true; - } - else - return false; -} - -void WorldSession::HandleActivateTaxiExpressOpcode (WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_ACTIVATETAXIEXPRESS"); - - uint64 guid; - uint32 node_count; - - recv_data >> guid >> node_count; - - Creature *npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); - if (!npc) - { - sLog.outDebug("WORLD: HandleActivateTaxiExpressOpcode - Unit (GUID: %u) not found or you can't interact with it.", uint32(GUID_LOPART(guid))); - return; - } - std::vector nodes; - - for (uint32 i = 0; i < node_count; ++i) - { - uint32 node; - recv_data >> node; - nodes.push_back(node); - } - - if (nodes.empty()) - return; - - sLog.outDebug("WORLD: Received CMSG_ACTIVATETAXIEXPRESS from %d to %d" ,nodes.front(),nodes.back()); - - GetPlayer()->ActivateTaxiPathTo(nodes, npc); -} - -void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_MOVE_SPLINE_DONE"); - - uint64 guid; // used only for proper packet read - if (!recv_data.readPackGUID(guid)) - return; - - MovementInfo movementInfo; // used only for proper packet read - ReadMovementInfo(recv_data, &movementInfo); - - recv_data.read_skip(); // unk - - // in taxi flight packet received in 2 case: - // 1) end taxi path in far (multi-node) flight - // 2) switch from one map to other in case multim-map taxi path - // we need process only (1) - - uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination(); - if (!curDest) - return; - - TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest); - - // far teleport case - if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId()) - { - if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) - { - // short preparations to continue flight - FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); - - flight->SetCurrentNodeAfterTeleport(); - Path::PathNode const& node = flight->GetPath()[flight->GetCurrentNode()]; - flight->SkipCurrentNode(); - - GetPlayer()->TeleportTo(curDestNode->map_id,node.x,node.y,node.z,GetPlayer()->GetOrientation()); - } - return; - } - - uint32 destinationnode = GetPlayer()->m_taxi.NextTaxiDestination(); - if (destinationnode > 0) // if more destinations to go - { - // current source node for next destination - uint32 sourcenode = GetPlayer()->m_taxi.GetTaxiSource(); - - // Add to taximask middle hubs in taxicheat mode (to prevent having player with disabled taxicheat and not having back flight path) - if (GetPlayer()->isTaxiCheater()) - { - if (GetPlayer()->m_taxi.SetTaximaskNode(sourcenode)) - { - WorldPacket data(SMSG_NEW_TAXI_PATH, 0); - _player->GetSession()->SendPacket(&data); - } - } - - sLog.outDebug("WORLD: Taxi has to go from %u to %u", sourcenode, destinationnode); - - uint32 mountDisplayId = objmgr.GetTaxiMountDisplayId(sourcenode, GetPlayer()->GetTeam()); - - uint32 path, cost; - objmgr.GetTaxiPath(sourcenode, destinationnode, path, cost); - - if (path && mountDisplayId) - SendDoFlight(mountDisplayId, path, 1); // skip start fly node - else - GetPlayer()->m_taxi.ClearTaxiDestinations(); // clear problematic path and next - return; - } - - GetPlayer()->CleanupAfterTaxiFlight(); - GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ()); - if (GetPlayer()->pvpInfo.inHostileArea) - GetPlayer()->CastSpell(GetPlayer(), 2479, true); -} - -void WorldSession::HandleActivateTaxiOpcode(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Received CMSG_ACTIVATETAXI"); - - uint64 guid; - std::vector nodes; - nodes.resize(2); - - recv_data >> guid >> nodes[0] >> nodes[1]; - sLog.outDebug("WORLD: Received CMSG_ACTIVATETAXI from %d to %d" ,nodes[0],nodes[1]); - Creature *npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); - if (!npc) - { - sLog.outDebug("WORLD: HandleActivateTaxiOpcode - Unit (GUID: %u) not found or you can't interact with it.", uint32(GUID_LOPART(guid))); - return; - } - - GetPlayer()->ActivateTaxiPathTo(nodes, npc); -} diff --git a/src/server/game/Movement/Transports.cpp b/src/server/game/Movement/Transports.cpp deleted file mode 100644 index 444e115f8b9..00000000000 --- a/src/server/game/Movement/Transports.cpp +++ /dev/null @@ -1,589 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" - -#include "Transports.h" -#include "MapManager.h" -#include "ObjectMgr.h" -#include "Path.h" - -#include "WorldPacket.h" -#include "DBCStores.h" -#include "ProgressBar.h" - -#include "World.h" - -void MapManager::LoadTransports() -{ - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, name, period FROM transports"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u transports", count); - return; - } - - barGoLink bar(result->GetRowCount()); - - do - { - bar.step(); - - Transport *t = new Transport; - - Field *fields = result->Fetch(); - - uint32 entry = fields[0].GetUInt32(); - std::string name = fields[1].GetCppString(); - t->m_period = fields[2].GetUInt32(); - - const GameObjectInfo *goinfo = objmgr.GetGameObjectInfo(entry); - - if (!goinfo) - { - sLog.outErrorDb("Transport ID:%u, Name: %s, will not be loaded, gameobject_template missing", entry, name.c_str()); - delete t; - continue; - } - - if (goinfo->type != GAMEOBJECT_TYPE_MO_TRANSPORT) - { - sLog.outErrorDb("Transport ID:%u, Name: %s, will not be loaded, gameobject_template type wrong", entry, name.c_str()); - delete t; - continue; - } - - // sLog.outString("Loading transport %d between %s, %s", entry, name.c_str(), goinfo->name); - - std::set mapsUsed; - - if (!t->GenerateWaypoints(goinfo->moTransport.taxiPathId, mapsUsed)) - // skip transports with empty waypoints list - { - sLog.outErrorDb("Transport (path id %u) path size = 0. Transport ignored, check DBC files or transport GO data0 field.",goinfo->moTransport.taxiPathId); - delete t; - continue; - } - - float x, y, z, o; - uint32 mapid; - x = t->m_WayPoints[0].x; y = t->m_WayPoints[0].y; z = t->m_WayPoints[0].z; mapid = t->m_WayPoints[0].mapid; o = 1; - - // creates the Gameobject - if (!t->Create(entry, mapid, x, y, z, o, 100, 0)) - { - delete t; - continue; - } - - m_Transports.insert(t); - - for (std::set::const_iterator i = mapsUsed.begin(); i != mapsUsed.end(); ++i) - m_TransportsByMap[*i].insert(t); - - //If we someday decide to use the grid to track transports, here: - t->SetMap(MapManager::Instance().CreateMap(mapid, t, 0)); - - //t->GetMap()->Add((GameObject *)t); - ++count; - } while (result->NextRow()); - - sLog.outString(); - sLog.outString(">> Loaded %u transports", count); - - // check transport data DB integrity - result = WorldDatabase.Query("SELECT gameobject.guid,gameobject.id,transports.name FROM gameobject,transports WHERE gameobject.id = transports.entry"); - if (result) // wrong data found - { - do - { - Field *fields = result->Fetch(); - - uint32 guid = fields[0].GetUInt32(); - uint32 entry = fields[1].GetUInt32(); - std::string name = fields[2].GetCppString(); - sLog.outErrorDb("Transport %u '%s' have record (GUID: %u) in `gameobject`. Transports DON'T must have any records in `gameobject` or its behavior will be unpredictable/bugged.",entry,name.c_str(),guid); - } - while (result->NextRow()); - } -} - -Transport::Transport() : GameObject() -{ - m_updateFlag = (UPDATEFLAG_TRANSPORT | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_ROTATION); -} - -bool Transport::Create(uint32 guidlow, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags) -{ - Relocate(x,y,z,ang); - // instance id and phaseMask isn't set to values different from std. - - if (!IsPositionValid()) - { - sLog.outError("Transport (GUID: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", - guidlow,x,y); - return false; - } - - Object::_Create(guidlow, 0, HIGHGUID_MO_TRANSPORT); - - GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(guidlow); - - if (!goinfo) - { - sLog.outErrorDb("Transport not created: entry in `gameobject_template` not found, guidlow: %u map: %u (X: %f Y: %f Z: %f) ang: %f",guidlow, mapid, x, y, z, ang); - return false; - } - - m_goInfo = goinfo; - - SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size); - - SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction); - //SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags); - SetUInt32Value(GAMEOBJECT_FLAGS, MAKE_PAIR32(0x28, 0x64)); - SetUInt32Value(GAMEOBJECT_LEVEL, m_period); - SetEntry(goinfo->id); - - SetUInt32Value(GAMEOBJECT_DISPLAYID, goinfo->displayId); - - SetGoState(GO_STATE_READY); - SetGoType(GameobjectTypes(goinfo->type)); - - SetGoAnimProgress(animprogress); - if (dynflags) - SetUInt32Value(GAMEOBJECT_DYNAMIC, MAKE_PAIR32(0, dynflags)); - - SetName(goinfo->name); - - return true; -} - -struct keyFrame -{ - keyFrame(float _x, float _y, float _z, uint32 _mapid, int _actionflag, int _delay) - { - x = _x; y = _y; z = _z; mapid = _mapid; actionflag = _actionflag; delay = _delay; distFromPrev = -1; distSinceStop = -1; distUntilStop = -1; - tFrom = 0; tTo = 0; - } - - float x; - float y; - float z; - uint32 mapid; - int actionflag; - int delay; - float distSinceStop; - float distUntilStop; - float distFromPrev; - float tFrom, tTo; -}; - -bool Transport::GenerateWaypoints(uint32 pathid, std::set &mapids) -{ - TransportPath path; - objmgr.GetTransportPathNodes(pathid, path); - - if (path.Empty()) - return false; - - std::vector keyFrames; - int mapChange = 0; - mapids.clear(); - for (size_t i = 1; i < path.Size() - 1; ++i) - { - if (mapChange == 0) - { - if ((path[i].mapid == path[i+1].mapid)) - { - keyFrame k(path[i].x, path[i].y, path[i].z, path[i].mapid, path[i].actionFlag, path[i].delay); - keyFrames.push_back(k); - mapids.insert(k.mapid); - } - else - { - mapChange = 1; - } - } - else - { - --mapChange; - } - } - - int lastStop = -1; - int firstStop = -1; - - // first cell is arrived at by teleportation :S - keyFrames[0].distFromPrev = 0; - if (keyFrames[0].actionflag == 2) - { - lastStop = 0; - } - - // find the rest of the distances between key points - for (size_t i = 1; i < keyFrames.size(); ++i) - { - if ((keyFrames[i].actionflag == 1) || (keyFrames[i].mapid != keyFrames[i-1].mapid)) - { - keyFrames[i].distFromPrev = 0; - } - else - { - keyFrames[i].distFromPrev = - sqrt(pow(keyFrames[i].x - keyFrames[i - 1].x, 2) + - pow(keyFrames[i].y - keyFrames[i - 1].y, 2) + - pow(keyFrames[i].z - keyFrames[i - 1].z, 2)); - } - if (keyFrames[i].actionflag == 2) - { - // remember first stop frame - if (firstStop == -1) - firstStop = i; - lastStop = i; - } - } - - float tmpDist = 0; - for (size_t i = 0; i < keyFrames.size(); ++i) - { - int j = (i + lastStop) % keyFrames.size(); - if (keyFrames[j].actionflag == 2) - tmpDist = 0; - else - tmpDist += keyFrames[j].distFromPrev; - keyFrames[j].distSinceStop = tmpDist; - } - - for (int i = int(keyFrames.size()) - 1; i >= 0; i--) - { - int j = (i + (firstStop+1)) % keyFrames.size(); - tmpDist += keyFrames[(j + 1) % keyFrames.size()].distFromPrev; - keyFrames[j].distUntilStop = tmpDist; - if (keyFrames[j].actionflag == 2) - tmpDist = 0; - } - - for (size_t i = 0; i < keyFrames.size(); ++i) - { - if (keyFrames[i].distSinceStop < (30 * 30 * 0.5f)) - keyFrames[i].tFrom = sqrt(2 * keyFrames[i].distSinceStop); - else - keyFrames[i].tFrom = ((keyFrames[i].distSinceStop - (30 * 30 * 0.5f)) / 30) + 30; - - if (keyFrames[i].distUntilStop < (30 * 30 * 0.5f)) - keyFrames[i].tTo = sqrt(2 * keyFrames[i].distUntilStop); - else - keyFrames[i].tTo = ((keyFrames[i].distUntilStop - (30 * 30 * 0.5f)) / 30) + 30; - - keyFrames[i].tFrom *= 1000; - keyFrames[i].tTo *= 1000; - } - - // for (int i = 0; i < keyFrames.size(); ++i) { - // sLog.outString("%f, %f, %f, %f, %f, %f, %f", keyFrames[i].x, keyFrames[i].y, keyFrames[i].distUntilStop, keyFrames[i].distSinceStop, keyFrames[i].distFromPrev, keyFrames[i].tFrom, keyFrames[i].tTo); - // } - - // Now we're completely set up; we can move along the length of each waypoint at 100 ms intervals - // speed = max(30, t) (remember x = 0.5s^2, and when accelerating, a = 1 unit/s^2 - int t = 0; - bool teleport = false; - if (keyFrames[keyFrames.size() - 1].mapid != keyFrames[0].mapid) - teleport = true; - - WayPoint pos(keyFrames[0].mapid, keyFrames[0].x, keyFrames[0].y, keyFrames[0].z, teleport, 0); - m_WayPoints[0] = pos; - t += keyFrames[0].delay * 1000; - - uint32 cM = keyFrames[0].mapid; - for (size_t i = 0; i < keyFrames.size() - 1; ++i) - { - float d = 0; - float tFrom = keyFrames[i].tFrom; - float tTo = keyFrames[i].tTo; - - // keep the generation of all these points; we use only a few now, but may need the others later - if (((d < keyFrames[i + 1].distFromPrev) && (tTo > 0))) - { - while ((d < keyFrames[i + 1].distFromPrev) && (tTo > 0)) - { - tFrom += 100; - tTo -= 100; - - if (d > 0) - { - float newX, newY, newZ; - newX = keyFrames[i].x + (keyFrames[i + 1].x - keyFrames[i].x) * d / keyFrames[i + 1].distFromPrev; - newY = keyFrames[i].y + (keyFrames[i + 1].y - keyFrames[i].y) * d / keyFrames[i + 1].distFromPrev; - newZ = keyFrames[i].z + (keyFrames[i + 1].z - keyFrames[i].z) * d / keyFrames[i + 1].distFromPrev; - - bool teleport = false; - if (keyFrames[i].mapid != cM) - { - teleport = true; - cM = keyFrames[i].mapid; - } - - // sLog.outString("T: %d, D: %f, x: %f, y: %f, z: %f", t, d, newX, newY, newZ); - WayPoint pos(keyFrames[i].mapid, newX, newY, newZ, teleport, i); - if (teleport) - m_WayPoints[t] = pos; - } - - if (tFrom < tTo) // caught in tFrom dock's "gravitational pull" - { - if (tFrom <= 30000) - { - d = 0.5f * (tFrom / 1000) * (tFrom / 1000); - } - else - { - d = 0.5f * 30 * 30 + 30 * ((tFrom - 30000) / 1000); - } - d = d - keyFrames[i].distSinceStop; - } - else - { - if (tTo <= 30000) - { - d = 0.5f * (tTo / 1000) * (tTo / 1000); - } - else - { - d = 0.5f * 30 * 30 + 30 * ((tTo - 30000) / 1000); - } - d = keyFrames[i].distUntilStop - d; - } - t += 100; - } - t -= 100; - } - - if (keyFrames[i + 1].tFrom > keyFrames[i + 1].tTo) - t += 100 - ((long)keyFrames[i + 1].tTo % 100); - else - t += (long)keyFrames[i + 1].tTo % 100; - - bool teleport = false; - if ((keyFrames[i + 1].actionflag == 1) || (keyFrames[i + 1].mapid != keyFrames[i].mapid)) - { - teleport = true; - cM = keyFrames[i + 1].mapid; - } - - WayPoint pos(keyFrames[i + 1].mapid, keyFrames[i + 1].x, keyFrames[i + 1].y, keyFrames[i + 1].z, teleport, i); - - // sLog.outString("T: %d, x: %f, y: %f, z: %f, t:%d", t, pos.x, pos.y, pos.z, teleport); -/* - if (keyFrames[i+1].delay > 5) - pos.delayed = true; -*/ - //if (teleport) - m_WayPoints[t] = pos; - - t += keyFrames[i + 1].delay * 1000; - // sLog.outString("------"); - } - - uint32 timer = t; - - // sLog.outDetail(" Generated %lu waypoints, total time %u.", (unsigned long)m_WayPoints.size(), timer); - - m_curr = m_WayPoints.begin(); - m_curr = GetNextWayPoint(); - m_next = GetNextWayPoint(); - m_pathTime = timer; - - m_nextNodeTime = m_curr->first; - - return true; -} - -Transport::WayPointMap::const_iterator Transport::GetNextWayPoint() -{ - WayPointMap::const_iterator iter = m_curr; - ++iter; - if (iter == m_WayPoints.end()) - iter = m_WayPoints.begin(); - return iter; -} - -void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z) -{ - Map const* oldMap = GetMap(); - Relocate(x, y, z); - - for (PlayerSet::const_iterator itr = m_passengers.begin(); itr != m_passengers.end();) - { - Player *plr = *itr; - ++itr; - - if (plr->isDead() && !plr->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) - { - plr->ResurrectPlayer(1.0); - } - plr->TeleportTo(newMapid, x, y, z, GetOrientation(), TELE_TO_NOT_LEAVE_TRANSPORT); - - //WorldPacket data(SMSG_811, 4); - //data << uint32(0); - //plr->GetSession()->SendPacket(&data); - } - - //we need to create and save new Map object with 'newMapid' because if not done -> lead to invalid Map object reference... - //player far teleport would try to create same instance, but we need it NOW for transport... - //correct me if I'm wrong O.o - //yes, you're right - - ResetMap(); - Map * newMap = MapManager::Instance().CreateMap(newMapid, this, 0); - SetMap(newMap); - assert (GetMap()); - - if (oldMap != newMap) - { - UpdateForMap(oldMap); - UpdateForMap(newMap); - } -} - -bool Transport::AddPassenger(Player* passenger) -{ - if (m_passengers.insert(passenger).second) - sLog.outDetail("Player %s boarded transport %s.", passenger->GetName(), GetName()); - return true; -} - -bool Transport::RemovePassenger(Player* passenger) -{ - if (m_passengers.erase(passenger)) - sLog.outDetail("Player %s removed from transport %s.", passenger->GetName(), GetName()); - return true; -} - -void Transport::CheckForEvent(uint32 entry, uint32 wp_id) -{ - uint32 key = entry*100+wp_id; - if (objmgr.TransportEventMap.find(key) != objmgr.TransportEventMap.end()) - GetMap()->ScriptsStart(sEventScripts, objmgr.TransportEventMap[key], this, NULL); -} - -void Transport::Update(uint32 /*p_time*/) -{ - if (m_WayPoints.size() <= 1) - return; - - m_timer = getMSTime() % m_period; - while (((m_timer - m_curr->first) % m_pathTime) > ((m_next->first - m_curr->first) % m_pathTime)) - { - m_curr = GetNextWayPoint(); - m_next = GetNextWayPoint(); - - // first check help in case client-server transport coordinates de-synchronization - if (m_curr->second.mapid != GetMapId() || m_curr->second.teleport) - { - TeleportTransport(m_curr->second.mapid, m_curr->second.x, m_curr->second.y, m_curr->second.z); - } - else - { - Relocate(m_curr->second.x, m_curr->second.y, m_curr->second.z); - } -/* - if (m_curr->second.delayed) - { - switch (GetEntry()) - { - case 176495: - case 164871: - case 175080: - SendPlaySound(11804, false); break; // ZeppelinDocked - case 20808: - case 181646: - case 176231: - case 176244: - case 176310: - case 177233: - SendPlaySound(5495, false);break; // BoatDockingWarning - default: - SendPlaySound(5154, false); break; // ShipDocked - } - } -*/ - /* - for (PlayerSet::const_iterator itr = m_passengers.begin(); itr != m_passengers.end();) - { - PlayerSet::const_iterator it2 = itr; - ++itr; - //(*it2)->SetPosition(m_curr->second.x + (*it2)->GetTransOffsetX(), m_curr->second.y + (*it2)->GetTransOffsetY(), m_curr->second.z + (*it2)->GetTransOffsetZ(), (*it2)->GetTransOffsetO()); - } - */ - - m_nextNodeTime = m_curr->first; - - if (m_curr == m_WayPoints.begin() && (sLog.getLogFilter() & LOG_FILTER_TRANSPORT_MOVES) == 0) - sLog.outDetail(" ************ BEGIN ************** %s", this->m_name.c_str()); - - if ((sLog.getLogFilter() & LOG_FILTER_TRANSPORT_MOVES) == 0) - sLog.outDetail("%s moved to %d %f %f %f %d", this->m_name.c_str(), m_curr->second.id, m_curr->second.x, m_curr->second.y, m_curr->second.z, m_curr->second.mapid); - - //Transport Event System - CheckForEvent(this->GetEntry(), m_curr->second.id); - } -} - -void Transport::UpdateForMap(Map const* targetMap) -{ - Map::PlayerList const& pl = targetMap->GetPlayers(); - if (pl.isEmpty()) - return; - - if (GetMapId() == targetMap->GetId()) - { - for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) - { - if (this != itr->getSource()->GetTransport()) - { - UpdateData transData; - BuildCreateUpdateBlockForPlayer(&transData, itr->getSource()); - WorldPacket packet; - transData.BuildPacket(&packet); - itr->getSource()->SendDirectMessage(&packet); - } - } - } - else - { - UpdateData transData; - BuildOutOfRangeUpdateBlock(&transData); - WorldPacket out_packet; - transData.BuildPacket(&out_packet); - - for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) - if (this != itr->getSource()->GetTransport()) - itr->getSource()->SendDirectMessage(&out_packet); - } -} - diff --git a/src/server/game/Movement/Transports.h b/src/server/game/Movement/Transports.h deleted file mode 100644 index 25b9ade1461..00000000000 --- a/src/server/game/Movement/Transports.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRANSPORTS_H -#define TRANSPORTS_H - -#include "GameObject.h" - -#include -#include -#include - -class TransportPath -{ - public: - struct PathNode - { - uint32 mapid; - float x,y,z; - uint32 actionFlag; - uint32 delay; - }; - - void SetLength(const unsigned int sz) - { - i_nodes.resize(sz); - } - - unsigned int Size(void) const { return i_nodes.size(); } - bool Empty(void) const { return i_nodes.empty(); } - void Resize(unsigned int sz) { i_nodes.resize(sz); } - void Clear(void) { i_nodes.clear(); } - PathNode* GetNodes(void) { return static_cast(&i_nodes[0]); } - - PathNode& operator[](const unsigned int idx) { return i_nodes[idx]; } - const PathNode& operator()(const unsigned int idx) const { return i_nodes[idx]; } - - protected: - std::vector i_nodes; -}; - -class Transport : public GameObject -{ - public: - explicit Transport(); - - bool Create(uint32 guidlow, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags); - bool GenerateWaypoints(uint32 pathid, std::set &mapids); - void Update(uint32 p_time); - bool AddPassenger(Player* passenger); - bool RemovePassenger(Player* passenger); - void CheckForEvent(uint32 entry, uint32 wp_id); - - typedef std::set PlayerSet; - PlayerSet const& GetPassengers() const { return m_passengers; } - - private: - struct WayPoint - { - WayPoint() : mapid(0), x(0), y(0), z(0), teleport(false), id(0) {} - WayPoint(uint32 _mapid, float _x, float _y, float _z, bool _teleport, uint32 _id) : - mapid(_mapid), x(_x), y(_y), z(_z), teleport(_teleport), id(_id) {} - uint32 mapid; - float x; - float y; - float z; - bool teleport; - uint32 id; - }; - - typedef std::map WayPointMap; - - WayPointMap::const_iterator m_curr; - WayPointMap::const_iterator m_next; - uint32 m_pathTime; - uint32 m_timer; - - PlayerSet m_passengers; - - public: - WayPointMap m_WayPoints; - uint32 m_nextNodeTime; - uint32 m_period; - - private: - void TeleportTransport(uint32 newMapid, float x, float y, float z); - void UpdateForMap(Map const* map); - WayPointMap::const_iterator GetNextWayPoint(); -}; -#endif - diff --git a/src/server/game/Movement/WaypointManager.cpp b/src/server/game/Movement/WaypointManager.cpp deleted file mode 100644 index 0cbdd0bf975..00000000000 --- a/src/server/game/Movement/WaypointManager.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Database/DatabaseEnv.h" -#include "GridDefines.h" -#include "WaypointManager.h" -#include "ProgressBar.h" -#include "MapManager.h" - -void WaypointStore::Free() -{ - for (UNORDERED_MAP::const_iterator itr = waypoint_map.begin(); itr != waypoint_map.end(); ++itr) - { - for (WaypointPath::const_iterator it = itr->second->begin(); it != itr->second->end(); ++it) - delete *it; - itr->second->clear(); - delete itr->second; - } - waypoint_map.clear(); -} - -void WaypointStore::Load() -{ - QueryResult_AutoPtr result = WorldDatabase.Query("SELECT COUNT(id) FROM waypoint_data"); - if (!result) - { - sLog.outError("an error occured while loading the table `waypoint_data` (maybe it doesn't exist ?)"); - exit(1); // Stop server at loading non exited table or not accessable table - } - - records = (*result)[0].GetUInt32(); - - result = WorldDatabase.Query("SELECT id,point,position_x,position_y,position_z,move_flag,delay,action,action_chance FROM waypoint_data ORDER BY id, point"); - if (!result) - { - sLog.outErrorDb("The table `waypoint_data` is empty or corrupted"); - return; - } - - WaypointPath* path_data = NULL; - uint32 total_records = result->GetRowCount(); - - barGoLink bar(total_records); - uint32 count = 0; - Field *fields; - uint32 last_id = 0; - - do - { - fields = result->Fetch(); - uint32 id = fields[0].GetUInt32(); - bar.step(); - count++; - WaypointData *wp = new WaypointData; - - if (last_id != id) - path_data = new WaypointPath; - - float x,y,z; - x = fields[2].GetFloat(); - y = fields[3].GetFloat(); - z = fields[4].GetFloat(); - - Trinity::NormalizeMapCoord(x); - Trinity::NormalizeMapCoord(y); - - wp->id = fields[1].GetUInt32(); - wp->x = x; - wp->y = y; - wp->z = z; - wp->run = fields[5].GetBool(); - wp->delay = fields[6].GetUInt32(); - wp->event_id = fields[7].GetUInt32(); - wp->event_chance = fields[8].GetUInt8(); - - path_data->push_back(wp); - - if (id != last_id) - waypoint_map[id] = path_data; - - last_id = id; - - } while (result->NextRow()) ; - - sLog.outString(); - sLog.outString(">> Loaded %u waypoints", count); -} - -void WaypointStore::UpdatePath(uint32 id) -{ - if (waypoint_map.find(id)!= waypoint_map.end()) - waypoint_map[id]->clear(); - - QueryResult_AutoPtr result; - - result = WorldDatabase.PQuery("SELECT point,position_x,position_y,position_z,move_flag,delay,action,action_chance FROM waypoint_data WHERE id = %u ORDER BY point", id); - - if (!result) - return; - - WaypointPath* path_data; - path_data = new WaypointPath; - Field *fields; - - do - { - fields = result->Fetch(); - - WaypointData *wp = new WaypointData; - - float x,y,z; - x = fields[1].GetFloat(); - y = fields[2].GetFloat(); - z = fields[3].GetFloat(); - - Trinity::NormalizeMapCoord(x); - Trinity::NormalizeMapCoord(y); - - wp->id = fields[0].GetUInt32(); - wp->x = x; - wp->y = y; - wp->z = z; - wp->run = fields[4].GetBool(); - wp->delay = fields[5].GetUInt32(); - wp->event_id = fields[6].GetUInt32(); - wp->event_chance = fields[7].GetUInt8(); - - path_data->push_back(wp); - - } - while (result->NextRow()); - - waypoint_map[id] = path_data; -} - diff --git a/src/server/game/Movement/WaypointManager.h b/src/server/game/Movement/WaypointManager.h deleted file mode 100644 index 7efca558146..00000000000 --- a/src/server/game/Movement/WaypointManager.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TRINITY_WAYPOINTMANAGER_H -#define TRINITY_WAYPOINTMANAGER_H - -#include -#include -#include - -struct WaypointData -{ - uint32 id; - float x,y,z; - bool run; - uint32 delay; - uint32 event_id; - uint8 event_chance; -}; - -typedef std::vector WaypointPath; - -class WaypointStore -{ - private : - uint32 records; - UNORDERED_MAP waypoint_map; - - public: - // Null Mutex is OK because WaypointMgr is initialized in the World thread before World is initialized - static WaypointStore* instance() { return ACE_Singleton::instance(); } - - ~WaypointStore() { Free(); } - void UpdatePath(uint32 id); - void Load(); - void Free(); - - WaypointPath* GetPath(uint32 id) - { - if (waypoint_map.find(id) != waypoint_map.end()) - return waypoint_map[id]; - else return 0; - } - - inline uint32 GetRecordsCount() { return records; } -}; - -#define sWaypointMgr WaypointStore::instance() - -#endif - diff --git a/src/server/game/Movement/Waypoints/Path.h b/src/server/game/Movement/Waypoints/Path.h new file mode 100644 index 00000000000..9ec079f3c9c --- /dev/null +++ b/src/server/game/Movement/Waypoints/Path.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYCORE_PATH_H +#define TRINITYCORE_PATH_H + +#include "Common.h" +#include + +class Path +{ + public: + struct PathNode + { + float x,y,z; + }; + + void SetLength(const unsigned int sz) + { + i_nodes.resize(sz); + } + + unsigned int Size() const { return i_nodes.size(); } + bool Empty() const { return i_nodes.empty(); } + void Resize(unsigned int sz) { i_nodes.resize(sz); } + void Clear(void) { i_nodes.clear(); } + PathNode const* GetNodes(uint32 start = 0) const { return &i_nodes[start]; } + float GetTotalLength() const { return GetTotalLength(0,Size()); } + float GetTotalLength(uint32 start, uint32 end) const + { + float len = 0, xd, yd, zd; + for (unsigned int idx=start+1; idx < end; ++idx) + { + xd = i_nodes[ idx ].x - i_nodes[ idx-1 ].x; + yd = i_nodes[ idx ].y - i_nodes[ idx-1 ].y; + zd = i_nodes[ idx ].z - i_nodes[ idx-1 ].z; + len += sqrtf(xd*xd + yd*yd + zd*zd); + } + return len; + } + + float GetPassedLength(uint32 curnode, float x, float y, float z) + { + float len = 0, xd, yd, zd; + for (unsigned int idx=1; idx < curnode; ++idx) + { + xd = i_nodes[ idx ].x - i_nodes[ idx-1 ].x; + yd = i_nodes[ idx ].y - i_nodes[ idx-1 ].y; + zd = i_nodes[ idx ].z - i_nodes[ idx-1 ].z; + len += sqrtf(xd*xd + yd*yd + zd*zd); + } + + if (curnode > 0) + { + xd = x - i_nodes[curnode-1].x; + yd = y - i_nodes[curnode-1].y; + zd = z - i_nodes[curnode-1].z; + len += sqrtf(xd*xd + yd*yd + zd*zd); + } + + return len; + } + + PathNode& operator[](const unsigned int idx) { return i_nodes[idx]; } + const PathNode& operator()(const unsigned int idx) const { return i_nodes[idx]; } + + protected: + std::vector i_nodes; +}; +#endif + diff --git a/src/server/game/Movement/Waypoints/WaypointManager.cpp b/src/server/game/Movement/Waypoints/WaypointManager.cpp new file mode 100644 index 00000000000..0cbdd0bf975 --- /dev/null +++ b/src/server/game/Movement/Waypoints/WaypointManager.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Database/DatabaseEnv.h" +#include "GridDefines.h" +#include "WaypointManager.h" +#include "ProgressBar.h" +#include "MapManager.h" + +void WaypointStore::Free() +{ + for (UNORDERED_MAP::const_iterator itr = waypoint_map.begin(); itr != waypoint_map.end(); ++itr) + { + for (WaypointPath::const_iterator it = itr->second->begin(); it != itr->second->end(); ++it) + delete *it; + itr->second->clear(); + delete itr->second; + } + waypoint_map.clear(); +} + +void WaypointStore::Load() +{ + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT COUNT(id) FROM waypoint_data"); + if (!result) + { + sLog.outError("an error occured while loading the table `waypoint_data` (maybe it doesn't exist ?)"); + exit(1); // Stop server at loading non exited table or not accessable table + } + + records = (*result)[0].GetUInt32(); + + result = WorldDatabase.Query("SELECT id,point,position_x,position_y,position_z,move_flag,delay,action,action_chance FROM waypoint_data ORDER BY id, point"); + if (!result) + { + sLog.outErrorDb("The table `waypoint_data` is empty or corrupted"); + return; + } + + WaypointPath* path_data = NULL; + uint32 total_records = result->GetRowCount(); + + barGoLink bar(total_records); + uint32 count = 0; + Field *fields; + uint32 last_id = 0; + + do + { + fields = result->Fetch(); + uint32 id = fields[0].GetUInt32(); + bar.step(); + count++; + WaypointData *wp = new WaypointData; + + if (last_id != id) + path_data = new WaypointPath; + + float x,y,z; + x = fields[2].GetFloat(); + y = fields[3].GetFloat(); + z = fields[4].GetFloat(); + + Trinity::NormalizeMapCoord(x); + Trinity::NormalizeMapCoord(y); + + wp->id = fields[1].GetUInt32(); + wp->x = x; + wp->y = y; + wp->z = z; + wp->run = fields[5].GetBool(); + wp->delay = fields[6].GetUInt32(); + wp->event_id = fields[7].GetUInt32(); + wp->event_chance = fields[8].GetUInt8(); + + path_data->push_back(wp); + + if (id != last_id) + waypoint_map[id] = path_data; + + last_id = id; + + } while (result->NextRow()) ; + + sLog.outString(); + sLog.outString(">> Loaded %u waypoints", count); +} + +void WaypointStore::UpdatePath(uint32 id) +{ + if (waypoint_map.find(id)!= waypoint_map.end()) + waypoint_map[id]->clear(); + + QueryResult_AutoPtr result; + + result = WorldDatabase.PQuery("SELECT point,position_x,position_y,position_z,move_flag,delay,action,action_chance FROM waypoint_data WHERE id = %u ORDER BY point", id); + + if (!result) + return; + + WaypointPath* path_data; + path_data = new WaypointPath; + Field *fields; + + do + { + fields = result->Fetch(); + + WaypointData *wp = new WaypointData; + + float x,y,z; + x = fields[1].GetFloat(); + y = fields[2].GetFloat(); + z = fields[3].GetFloat(); + + Trinity::NormalizeMapCoord(x); + Trinity::NormalizeMapCoord(y); + + wp->id = fields[0].GetUInt32(); + wp->x = x; + wp->y = y; + wp->z = z; + wp->run = fields[4].GetBool(); + wp->delay = fields[5].GetUInt32(); + wp->event_id = fields[6].GetUInt32(); + wp->event_chance = fields[7].GetUInt8(); + + path_data->push_back(wp); + + } + while (result->NextRow()); + + waypoint_map[id] = path_data; +} + diff --git a/src/server/game/Movement/Waypoints/WaypointManager.h b/src/server/game/Movement/Waypoints/WaypointManager.h new file mode 100644 index 00000000000..7efca558146 --- /dev/null +++ b/src/server/game/Movement/Waypoints/WaypointManager.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_WAYPOINTMANAGER_H +#define TRINITY_WAYPOINTMANAGER_H + +#include +#include +#include + +struct WaypointData +{ + uint32 id; + float x,y,z; + bool run; + uint32 delay; + uint32 event_id; + uint8 event_chance; +}; + +typedef std::vector WaypointPath; + +class WaypointStore +{ + private : + uint32 records; + UNORDERED_MAP waypoint_map; + + public: + // Null Mutex is OK because WaypointMgr is initialized in the World thread before World is initialized + static WaypointStore* instance() { return ACE_Singleton::instance(); } + + ~WaypointStore() { Free(); } + void UpdatePath(uint32 id); + void Load(); + void Free(); + + WaypointPath* GetPath(uint32 id) + { + if (waypoint_map.find(id) != waypoint_map.end()) + return waypoint_map[id]; + else return 0; + } + + inline uint32 GetRecordsCount() { return records; } +}; + +#define sWaypointMgr WaypointStore::instance() + +#endif + diff --git a/src/server/game/Opcodes/Opcodes.cpp b/src/server/game/Opcodes/Opcodes.cpp deleted file mode 100644 index 0b67199b4ea..00000000000 --- a/src/server/game/Opcodes/Opcodes.cpp +++ /dev/null @@ -1,1338 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** \file - \ingroup u2w -*/ - -#include "Opcodes.h" -#include "WorldSession.h" - -/// Correspondence between opcodes and their names -OpcodeHandler opcodeTable[NUM_MSG_TYPES] = -{ - /*0x000*/ { "MSG_NULL_ACTION", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x001*/ { "CMSG_BOOTME", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x002*/ { "CMSG_DBLOOKUP", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x003*/ { "SMSG_DBLOOKUP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x004*/ { "CMSG_QUERY_OBJECT_POSITION", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x005*/ { "SMSG_QUERY_OBJECT_POSITION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x006*/ { "CMSG_QUERY_OBJECT_ROTATION", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x007*/ { "SMSG_QUERY_OBJECT_ROTATION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x008*/ { "CMSG_WORLD_TELEPORT", STATUS_LOGGEDIN, &WorldSession::HandleWorldTeleportOpcode }, - /*0x009*/ { "CMSG_TELEPORT_TO_UNIT", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, - /*0x00A*/ { "CMSG_ZONE_MAP", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x00B*/ { "SMSG_ZONE_MAP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x00C*/ { "CMSG_DEBUG_CHANGECELLZONE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x00D*/ { "CMSG_MOVE_CHARACTER_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x00E*/ { "SMSG_MOVE_CHARACTER_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x00F*/ { "CMSG_RECHARGE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x010*/ { "CMSG_LEARN_SPELL", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x011*/ { "CMSG_CREATEMONSTER", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x012*/ { "CMSG_DESTROYMONSTER", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x013*/ { "CMSG_CREATEITEM", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x014*/ { "CMSG_CREATEGAMEOBJECT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x015*/ { "SMSG_CHECK_FOR_BOTS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x016*/ { "CMSG_MAKEMONSTERATTACKGUID", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x017*/ { "CMSG_BOT_DETECTED2", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x018*/ { "CMSG_FORCEACTION", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x019*/ { "CMSG_FORCEACTIONONOTHER", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x01A*/ { "CMSG_FORCEACTIONSHOW", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x01B*/ { "SMSG_FORCEACTIONSHOW", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x01C*/ { "CMSG_PETGODMODE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x01D*/ { "SMSG_PETGODMODE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x01E*/ { "SMSG_REFER_A_FRIEND_EXPIRED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x01F*/ { "CMSG_WEATHER_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x020*/ { "CMSG_UNDRESSPLAYER", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x021*/ { "CMSG_BEASTMASTER", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x022*/ { "CMSG_GODMODE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x023*/ { "SMSG_GODMODE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x024*/ { "CMSG_CHEAT_SETMONEY", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x025*/ { "CMSG_LEVEL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x026*/ { "CMSG_PET_LEVEL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x027*/ { "CMSG_SET_WORLDSTATE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x028*/ { "CMSG_COOLDOWN_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x029*/ { "CMSG_USE_SKILL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x02A*/ { "CMSG_FLAG_QUEST", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x02B*/ { "CMSG_FLAG_QUEST_FINISH", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x02C*/ { "CMSG_CLEAR_QUEST", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x02D*/ { "CMSG_SEND_EVENT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x02E*/ { "CMSG_DEBUG_AISTATE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x02F*/ { "SMSG_DEBUG_AISTATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x030*/ { "CMSG_DISABLE_PVP_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x031*/ { "CMSG_ADVANCE_SPAWN_TIME", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x032*/ { "SMSG_DESTRUCTIBLE_BUILDING_DAMAGE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x033*/ { "CMSG_AUTH_SRP6_BEGIN", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x034*/ { "CMSG_AUTH_SRP6_PROOF", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x035*/ { "CMSG_AUTH_SRP6_RECODE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x036*/ { "CMSG_CHAR_CREATE", STATUS_AUTHED, &WorldSession::HandleCharCreateOpcode }, - /*0x037*/ { "CMSG_CHAR_ENUM", STATUS_AUTHED, &WorldSession::HandleCharEnumOpcode }, - /*0x038*/ { "CMSG_CHAR_DELETE", STATUS_AUTHED, &WorldSession::HandleCharDeleteOpcode }, - /*0x039*/ { "SMSG_AUTH_SRP6_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x03A*/ { "SMSG_CHAR_CREATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x03B*/ { "SMSG_CHAR_ENUM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x03C*/ { "SMSG_CHAR_DELETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x03D*/ { "CMSG_PLAYER_LOGIN", STATUS_AUTHED, &WorldSession::HandlePlayerLoginOpcode }, - /*0x03E*/ { "SMSG_NEW_WORLD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x03F*/ { "SMSG_TRANSFER_PENDING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x040*/ { "SMSG_TRANSFER_ABORTED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x041*/ { "SMSG_CHARACTER_LOGIN_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x042*/ { "SMSG_LOGIN_SETTIMESPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x043*/ { "SMSG_GAMETIME_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x044*/ { "CMSG_GAMETIME_SET", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x045*/ { "SMSG_GAMETIME_SET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x046*/ { "CMSG_GAMESPEED_SET", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x047*/ { "SMSG_GAMESPEED_SET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x048*/ { "CMSG_SERVERTIME", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x049*/ { "SMSG_SERVERTIME", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x04A*/ { "CMSG_PLAYER_LOGOUT", STATUS_LOGGEDIN, &WorldSession::HandlePlayerLogoutOpcode }, - /*0x04B*/ { "CMSG_LOGOUT_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleLogoutRequestOpcode }, - /*0x04C*/ { "SMSG_LOGOUT_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x04D*/ { "SMSG_LOGOUT_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x04E*/ { "CMSG_LOGOUT_CANCEL", STATUS_LOGGEDIN, &WorldSession::HandleLogoutCancelOpcode }, - /*0x04F*/ { "SMSG_LOGOUT_CANCEL_ACK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x050*/ { "CMSG_NAME_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleNameQueryOpcode }, - /*0x051*/ { "SMSG_NAME_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x052*/ { "CMSG_PET_NAME_QUERY", STATUS_LOGGEDIN, &WorldSession::HandlePetNameQuery }, - /*0x053*/ { "SMSG_PET_NAME_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x054*/ { "CMSG_GUILD_QUERY", STATUS_AUTHED, &WorldSession::HandleGuildQueryOpcode }, - /*0x055*/ { "SMSG_GUILD_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x056*/ { "CMSG_ITEM_QUERY_SINGLE", STATUS_LOGGEDIN, &WorldSession::HandleItemQuerySingleOpcode }, - /*0x057*/ { "CMSG_ITEM_QUERY_MULTIPLE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x058*/ { "SMSG_ITEM_QUERY_SINGLE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x059*/ { "SMSG_ITEM_QUERY_MULTIPLE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x05A*/ { "CMSG_PAGE_TEXT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandlePageTextQueryOpcode }, - /*0x05B*/ { "SMSG_PAGE_TEXT_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x05C*/ { "CMSG_QUEST_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleQuestQueryOpcode }, - /*0x05D*/ { "SMSG_QUEST_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x05E*/ { "CMSG_GAMEOBJECT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleGameObjectQueryOpcode }, - /*0x05F*/ { "SMSG_GAMEOBJECT_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x060*/ { "CMSG_CREATURE_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleCreatureQueryOpcode }, - /*0x061*/ { "SMSG_CREATURE_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x062*/ { "CMSG_WHO", STATUS_LOGGEDIN, &WorldSession::HandleWhoOpcode }, - /*0x063*/ { "SMSG_WHO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x064*/ { "CMSG_WHOIS", STATUS_LOGGEDIN, &WorldSession::HandleWhoisOpcode }, - /*0x065*/ { "SMSG_WHOIS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x066*/ { "CMSG_CONTACT_LIST", STATUS_LOGGEDIN, &WorldSession::HandleContactListOpcode }, - /*0x067*/ { "SMSG_CONTACT_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x068*/ { "SMSG_FRIEND_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x069*/ { "CMSG_ADD_FRIEND", STATUS_LOGGEDIN, &WorldSession::HandleAddFriendOpcode }, - /*0x06A*/ { "CMSG_DEL_FRIEND", STATUS_LOGGEDIN, &WorldSession::HandleDelFriendOpcode }, - /*0x06B*/ { "CMSG_SET_CONTACT_NOTES", STATUS_LOGGEDIN, &WorldSession::HandleSetContactNotesOpcode }, - /*0x06C*/ { "CMSG_ADD_IGNORE", STATUS_LOGGEDIN, &WorldSession::HandleAddIgnoreOpcode }, - /*0x06D*/ { "CMSG_DEL_IGNORE", STATUS_LOGGEDIN, &WorldSession::HandleDelIgnoreOpcode }, - /*0x06E*/ { "CMSG_GROUP_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleGroupInviteOpcode }, - /*0x06F*/ { "SMSG_GROUP_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x070*/ { "CMSG_GROUP_CANCEL", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, - /*0x071*/ { "SMSG_GROUP_CANCEL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x072*/ { "CMSG_GROUP_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleGroupAcceptOpcode }, - /*0x073*/ { "CMSG_GROUP_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandleGroupDeclineOpcode }, - /*0x074*/ { "SMSG_GROUP_DECLINE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x075*/ { "CMSG_GROUP_UNINVITE", STATUS_LOGGEDIN, &WorldSession::HandleGroupUninviteOpcode }, - /*0x076*/ { "CMSG_GROUP_UNINVITE_GUID", STATUS_LOGGEDIN, &WorldSession::HandleGroupUninviteGuidOpcode }, - /*0x077*/ { "SMSG_GROUP_UNINVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x078*/ { "CMSG_GROUP_SET_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGroupSetLeaderOpcode }, - /*0x079*/ { "SMSG_GROUP_SET_LEADER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x07A*/ { "CMSG_LOOT_METHOD", STATUS_LOGGEDIN, &WorldSession::HandleLootMethodOpcode }, - /*0x07B*/ { "CMSG_GROUP_DISBAND", STATUS_LOGGEDIN, &WorldSession::HandleGroupDisbandOpcode }, - /*0x07C*/ { "SMSG_GROUP_DESTROYED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x07D*/ { "SMSG_GROUP_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x07E*/ { "SMSG_PARTY_MEMBER_STATS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x07F*/ { "SMSG_PARTY_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x080*/ { "UMSG_UPDATE_GROUP_MEMBERS", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x081*/ { "CMSG_GUILD_CREATE", STATUS_LOGGEDIN, &WorldSession::HandleGuildCreateOpcode }, - /*0x082*/ { "CMSG_GUILD_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleGuildInviteOpcode }, - /*0x083*/ { "SMSG_GUILD_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x084*/ { "CMSG_GUILD_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleGuildAcceptOpcode }, - /*0x085*/ { "CMSG_GUILD_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandleGuildDeclineOpcode }, - /*0x086*/ { "SMSG_GUILD_DECLINE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x087*/ { "CMSG_GUILD_INFO", STATUS_LOGGEDIN, &WorldSession::HandleGuildInfoOpcode }, - /*0x088*/ { "SMSG_GUILD_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x089*/ { "CMSG_GUILD_ROSTER", STATUS_LOGGEDIN, &WorldSession::HandleGuildRosterOpcode }, - /*0x08A*/ { "SMSG_GUILD_ROSTER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x08B*/ { "CMSG_GUILD_PROMOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildPromoteOpcode }, - /*0x08C*/ { "CMSG_GUILD_DEMOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildDemoteOpcode }, - /*0x08D*/ { "CMSG_GUILD_LEAVE", STATUS_LOGGEDIN, &WorldSession::HandleGuildLeaveOpcode }, - /*0x08E*/ { "CMSG_GUILD_REMOVE", STATUS_LOGGEDIN, &WorldSession::HandleGuildRemoveOpcode }, - /*0x08F*/ { "CMSG_GUILD_DISBAND", STATUS_LOGGEDIN, &WorldSession::HandleGuildDisbandOpcode }, - /*0x090*/ { "CMSG_GUILD_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGuildLeaderOpcode }, - /*0x091*/ { "CMSG_GUILD_MOTD", STATUS_LOGGEDIN, &WorldSession::HandleGuildMOTDOpcode }, - /*0x092*/ { "SMSG_GUILD_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x093*/ { "SMSG_GUILD_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x094*/ { "UMSG_UPDATE_GUILD", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x095*/ { "CMSG_MESSAGECHAT", STATUS_LOGGEDIN, &WorldSession::HandleMessagechatOpcode }, - /*0x096*/ { "SMSG_MESSAGECHAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x097*/ { "CMSG_JOIN_CHANNEL", STATUS_LOGGEDIN, &WorldSession::HandleJoinChannel }, - /*0x098*/ { "CMSG_LEAVE_CHANNEL", STATUS_LOGGEDIN, &WorldSession::HandleLeaveChannel }, - /*0x099*/ { "SMSG_CHANNEL_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x09A*/ { "CMSG_CHANNEL_LIST", STATUS_LOGGEDIN, &WorldSession::HandleChannelList }, - /*0x09B*/ { "SMSG_CHANNEL_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x09C*/ { "CMSG_CHANNEL_PASSWORD", STATUS_LOGGEDIN, &WorldSession::HandleChannelPassword }, - /*0x09D*/ { "CMSG_CHANNEL_SET_OWNER", STATUS_LOGGEDIN, &WorldSession::HandleChannelSetOwner }, - /*0x09E*/ { "CMSG_CHANNEL_OWNER", STATUS_LOGGEDIN, &WorldSession::HandleChannelOwner }, - /*0x09F*/ { "CMSG_CHANNEL_MODERATOR", STATUS_LOGGEDIN, &WorldSession::HandleChannelModerator }, - /*0x0A0*/ { "CMSG_CHANNEL_UNMODERATOR", STATUS_LOGGEDIN, &WorldSession::HandleChannelUnmoderator }, - /*0x0A1*/ { "CMSG_CHANNEL_MUTE", STATUS_LOGGEDIN, &WorldSession::HandleChannelMute }, - /*0x0A2*/ { "CMSG_CHANNEL_UNMUTE", STATUS_LOGGEDIN, &WorldSession::HandleChannelUnmute }, - /*0x0A3*/ { "CMSG_CHANNEL_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleChannelInvite }, - /*0x0A4*/ { "CMSG_CHANNEL_KICK", STATUS_LOGGEDIN, &WorldSession::HandleChannelKick }, - /*0x0A5*/ { "CMSG_CHANNEL_BAN", STATUS_LOGGEDIN, &WorldSession::HandleChannelBan }, - /*0x0A6*/ { "CMSG_CHANNEL_UNBAN", STATUS_LOGGEDIN, &WorldSession::HandleChannelUnban }, - /*0x0A7*/ { "CMSG_CHANNEL_ANNOUNCEMENTS", STATUS_LOGGEDIN, &WorldSession::HandleChannelAnnouncements }, - /*0x0A8*/ { "CMSG_CHANNEL_MODERATE", STATUS_LOGGEDIN, &WorldSession::HandleChannelModerate }, - /*0x0A9*/ { "SMSG_UPDATE_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0AA*/ { "SMSG_DESTROY_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0AB*/ { "CMSG_USE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleUseItemOpcode }, - /*0x0AC*/ { "CMSG_OPEN_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleOpenItemOpcode }, - /*0x0AD*/ { "CMSG_READ_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleReadItem }, - /*0x0AE*/ { "SMSG_READ_ITEM_OK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0AF*/ { "SMSG_READ_ITEM_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0B0*/ { "SMSG_ITEM_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0B1*/ { "CMSG_GAMEOBJ_USE", STATUS_LOGGEDIN, &WorldSession::HandleGameObjectUseOpcode }, - /*0x0B2*/ { "CMSG_DESTROY_ITEMS", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0B3*/ { "SMSG_GAMEOBJECT_CUSTOM_ANIM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0B4*/ { "CMSG_AREATRIGGER", STATUS_LOGGEDIN, &WorldSession::HandleAreaTriggerOpcode }, - /*0x0B5*/ { "MSG_MOVE_START_FORWARD", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0B6*/ { "MSG_MOVE_START_BACKWARD", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0B7*/ { "MSG_MOVE_STOP", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0B8*/ { "MSG_MOVE_START_STRAFE_LEFT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0B9*/ { "MSG_MOVE_START_STRAFE_RIGHT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0BA*/ { "MSG_MOVE_STOP_STRAFE", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0BB*/ { "MSG_MOVE_JUMP", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0BC*/ { "MSG_MOVE_START_TURN_LEFT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0BD*/ { "MSG_MOVE_START_TURN_RIGHT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0BE*/ { "MSG_MOVE_STOP_TURN", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0BF*/ { "MSG_MOVE_START_PITCH_UP", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0C0*/ { "MSG_MOVE_START_PITCH_DOWN", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0C1*/ { "MSG_MOVE_STOP_PITCH", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0C2*/ { "MSG_MOVE_SET_RUN_MODE", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0C3*/ { "MSG_MOVE_SET_WALK_MODE", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0C4*/ { "MSG_MOVE_TOGGLE_LOGGING", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0C5*/ { "MSG_MOVE_TELEPORT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0C6*/ { "MSG_MOVE_TELEPORT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0C7*/ { "MSG_MOVE_TELEPORT_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveTeleportAck }, - /*0x0C8*/ { "MSG_MOVE_TOGGLE_FALL_LOGGING", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0C9*/ { "MSG_MOVE_FALL_LAND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0CA*/ { "MSG_MOVE_START_SWIM", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0CB*/ { "MSG_MOVE_STOP_SWIM", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0CC*/ { "MSG_MOVE_SET_RUN_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0CD*/ { "MSG_MOVE_SET_RUN_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0CE*/ { "MSG_MOVE_SET_RUN_BACK_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0CF*/ { "MSG_MOVE_SET_RUN_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0D0*/ { "MSG_MOVE_SET_WALK_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0D1*/ { "MSG_MOVE_SET_WALK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0D2*/ { "MSG_MOVE_SET_SWIM_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0D3*/ { "MSG_MOVE_SET_SWIM_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0D4*/ { "MSG_MOVE_SET_SWIM_BACK_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0D5*/ { "MSG_MOVE_SET_SWIM_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0D6*/ { "MSG_MOVE_SET_ALL_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0D7*/ { "MSG_MOVE_SET_TURN_RATE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0D8*/ { "MSG_MOVE_SET_TURN_RATE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0D9*/ { "MSG_MOVE_TOGGLE_COLLISION_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0DA*/ { "MSG_MOVE_SET_FACING", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0DB*/ { "MSG_MOVE_SET_PITCH", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0DC*/ { "MSG_MOVE_WORLDPORT_ACK", STATUS_TRANSFER, &WorldSession::HandleMoveWorldportAckOpcode }, - /*0x0DD*/ { "SMSG_MONSTER_MOVE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0DE*/ { "SMSG_MOVE_WATER_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0DF*/ { "SMSG_MOVE_LAND_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0E0*/ { "MSG_MOVE_SET_RAW_POSITION_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0E1*/ { "CMSG_MOVE_SET_RAW_POSITION", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0E2*/ { "SMSG_FORCE_RUN_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0E3*/ { "CMSG_FORCE_RUN_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, - /*0x0E4*/ { "SMSG_FORCE_RUN_BACK_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0E5*/ { "CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, - /*0x0E6*/ { "SMSG_FORCE_SWIM_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0E7*/ { "CMSG_FORCE_SWIM_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, - /*0x0E8*/ { "SMSG_FORCE_MOVE_ROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0E9*/ { "CMSG_FORCE_MOVE_ROOT_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveRootAck }, - /*0x0EA*/ { "SMSG_FORCE_MOVE_UNROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0EB*/ { "CMSG_FORCE_MOVE_UNROOT_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveUnRootAck }, - /*0x0EC*/ { "MSG_MOVE_ROOT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0ED*/ { "MSG_MOVE_UNROOT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0EE*/ { "MSG_MOVE_HEARTBEAT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x0EF*/ { "SMSG_MOVE_KNOCK_BACK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0F0*/ { "CMSG_MOVE_KNOCK_BACK_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveKnockBackAck }, - /*0x0F1*/ { "MSG_MOVE_KNOCK_BACK", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0F2*/ { "SMSG_MOVE_FEATHER_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0F3*/ { "SMSG_MOVE_NORMAL_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0F4*/ { "SMSG_MOVE_SET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0F5*/ { "SMSG_MOVE_UNSET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0F6*/ { "CMSG_MOVE_HOVER_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveHoverAck }, - /*0x0F7*/ { "MSG_MOVE_HOVER", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0F8*/ { "CMSG_TRIGGER_CINEMATIC_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0F9*/ { "CMSG_OPENING_CINEMATIC", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x0FA*/ { "SMSG_TRIGGER_CINEMATIC", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0FB*/ { "CMSG_NEXT_CINEMATIC_CAMERA", STATUS_LOGGEDIN, &WorldSession::HandleNextCinematicCamera }, - /*0x0FC*/ { "CMSG_COMPLETE_CINEMATIC", STATUS_LOGGEDIN, &WorldSession::HandleCompleteCinematic }, - /*0x0FD*/ { "SMSG_TUTORIAL_FLAGS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x0FE*/ { "CMSG_TUTORIAL_FLAG", STATUS_LOGGEDIN, &WorldSession::HandleTutorialFlag }, - /*0x0FF*/ { "CMSG_TUTORIAL_CLEAR", STATUS_LOGGEDIN, &WorldSession::HandleTutorialClear }, - /*0x100*/ { "CMSG_TUTORIAL_RESET", STATUS_LOGGEDIN, &WorldSession::HandleTutorialReset }, - /*0x101*/ { "CMSG_STANDSTATECHANGE", STATUS_LOGGEDIN, &WorldSession::HandleStandStateChangeOpcode }, - /*0x102*/ { "CMSG_EMOTE", STATUS_LOGGEDIN, &WorldSession::HandleEmoteOpcode }, - /*0x103*/ { "SMSG_EMOTE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x104*/ { "CMSG_TEXT_EMOTE", STATUS_LOGGEDIN, &WorldSession::HandleTextEmoteOpcode }, - /*0x105*/ { "SMSG_TEXT_EMOTE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x106*/ { "CMSG_AUTOEQUIP_GROUND_ITEM", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x107*/ { "CMSG_AUTOSTORE_GROUND_ITEM", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x108*/ { "CMSG_AUTOSTORE_LOOT_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutostoreLootItemOpcode }, - /*0x109*/ { "CMSG_STORE_LOOT_IN_SLOT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x10A*/ { "CMSG_AUTOEQUIP_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoEquipItemOpcode }, - /*0x10B*/ { "CMSG_AUTOSTORE_BAG_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoStoreBagItemOpcode }, - /*0x10C*/ { "CMSG_SWAP_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSwapItem }, - /*0x10D*/ { "CMSG_SWAP_INV_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSwapInvItemOpcode }, - /*0x10E*/ { "CMSG_SPLIT_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSplitItemOpcode }, - /*0x10F*/ { "CMSG_AUTOEQUIP_ITEM_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleAutoEquipItemSlotOpcode }, - /*0x110*/ { "OBSOLETE_DROP_ITEM", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x111*/ { "CMSG_DESTROYITEM", STATUS_LOGGEDIN, &WorldSession::HandleDestroyItemOpcode }, - /*0x112*/ { "SMSG_INVENTORY_CHANGE_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x113*/ { "SMSG_OPEN_CONTAINER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x114*/ { "CMSG_INSPECT", STATUS_LOGGEDIN, &WorldSession::HandleInspectOpcode }, - /*0x115*/ { "SMSG_INSPECT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x116*/ { "CMSG_INITIATE_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleInitiateTradeOpcode }, - /*0x117*/ { "CMSG_BEGIN_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleBeginTradeOpcode }, - /*0x118*/ { "CMSG_BUSY_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleBusyTradeOpcode }, - /*0x119*/ { "CMSG_IGNORE_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleIgnoreTradeOpcode }, - /*0x11A*/ { "CMSG_ACCEPT_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleAcceptTradeOpcode }, - /*0x11B*/ { "CMSG_UNACCEPT_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleUnacceptTradeOpcode }, - /*0x11C*/ { "CMSG_CANCEL_TRADE", STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, &WorldSession::HandleCancelTradeOpcode}, - /*0x11D*/ { "CMSG_SET_TRADE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSetTradeItemOpcode }, - /*0x11E*/ { "CMSG_CLEAR_TRADE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleClearTradeItemOpcode }, - /*0x11F*/ { "CMSG_SET_TRADE_GOLD", STATUS_LOGGEDIN, &WorldSession::HandleSetTradeGoldOpcode }, - /*0x120*/ { "SMSG_TRADE_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x121*/ { "SMSG_TRADE_STATUS_EXTENDED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x122*/ { "SMSG_INITIALIZE_FACTIONS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x123*/ { "SMSG_SET_FACTION_VISIBLE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x124*/ { "SMSG_SET_FACTION_STANDING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x125*/ { "CMSG_SET_FACTION_ATWAR", STATUS_LOGGEDIN, &WorldSession::HandleSetFactionAtWar }, - /*0x126*/ { "CMSG_SET_FACTION_CHEAT", STATUS_LOGGEDIN, &WorldSession::HandleSetFactionCheat }, - /*0x127*/ { "SMSG_SET_PROFICIENCY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x128*/ { "CMSG_SET_ACTION_BUTTON", STATUS_LOGGEDIN, &WorldSession::HandleSetActionButtonOpcode }, - /*0x129*/ { "SMSG_ACTION_BUTTONS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x12A*/ { "SMSG_INITIAL_SPELLS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x12B*/ { "SMSG_LEARNED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x12C*/ { "SMSG_SUPERCEDED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x12D*/ { "CMSG_NEW_SPELL_SLOT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x12E*/ { "CMSG_CAST_SPELL", STATUS_LOGGEDIN, &WorldSession::HandleCastSpellOpcode }, - /*0x12F*/ { "CMSG_CANCEL_CAST", STATUS_LOGGEDIN, &WorldSession::HandleCancelCastOpcode }, - /*0x130*/ { "SMSG_CAST_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x131*/ { "SMSG_SPELL_START", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x132*/ { "SMSG_SPELL_GO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x133*/ { "SMSG_SPELL_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x134*/ { "SMSG_SPELL_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x135*/ { "SMSG_COOLDOWN_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x136*/ { "CMSG_CANCEL_AURA", STATUS_LOGGEDIN, &WorldSession::HandleCancelAuraOpcode }, - /*0x137*/ { "SMSG_EQUIPMENT_SET_SAVED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x138*/ { "SMSG_PET_CAST_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x139*/ { "MSG_CHANNEL_START", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x13A*/ { "MSG_CHANNEL_UPDATE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x13B*/ { "CMSG_CANCEL_CHANNELLING", STATUS_LOGGEDIN, &WorldSession::HandleCancelChanneling }, - /*0x13C*/ { "SMSG_AI_REACTION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x13D*/ { "CMSG_SET_SELECTION", STATUS_LOGGEDIN, &WorldSession::HandleSetSelectionOpcode }, - /*0x13E*/ { "CMSG_EQUIPMENT_SET_DELETE", STATUS_LOGGEDIN, &WorldSession::HandleEquipmentSetDelete }, - /*0x13F*/ { "CMSG_INSTANCE_LOCK_WARNING_RESPONSE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x140*/ { "CMSG_UNUSED2", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x141*/ { "CMSG_ATTACKSWING", STATUS_LOGGEDIN, &WorldSession::HandleAttackSwingOpcode }, - /*0x142*/ { "CMSG_ATTACKSTOP", STATUS_LOGGEDIN, &WorldSession::HandleAttackStopOpcode }, - /*0x143*/ { "SMSG_ATTACKSTART", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x144*/ { "SMSG_ATTACKSTOP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x145*/ { "SMSG_ATTACKSWING_NOTINRANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x146*/ { "SMSG_ATTACKSWING_BADFACING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x147*/ { "SMSG_INSTANCE_LOCK_WARNING_QUERY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x148*/ { "SMSG_ATTACKSWING_DEADTARGET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x149*/ { "SMSG_ATTACKSWING_CANT_ATTACK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x14A*/ { "SMSG_ATTACKERSTATEUPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x14B*/ { "SMSG_BATTLEFIELD_PORT_DENIED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x14C*/ { "SMSG_DAMAGE_DONE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x14D*/ { "SMSG_DAMAGE_TAKEN_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x14E*/ { "SMSG_CANCEL_COMBAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x14F*/ { "SMSG_SPELLBREAKLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x150*/ { "SMSG_SPELLHEALLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x151*/ { "SMSG_SPELLENERGIZELOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x152*/ { "SMSG_BREAK_TARGET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x153*/ { "CMSG_SAVE_PLAYER", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x154*/ { "CMSG_SETDEATHBINDPOINT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x155*/ { "SMSG_BINDPOINTUPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x156*/ { "CMSG_GETDEATHBINDZONE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x157*/ { "SMSG_BINDZONEREPLY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x158*/ { "SMSG_PLAYERBOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x159*/ { "SMSG_CLIENT_CONTROL_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x15A*/ { "CMSG_REPOP_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleRepopRequestOpcode }, - /*0x15B*/ { "SMSG_RESURRECT_REQUEST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x15C*/ { "CMSG_RESURRECT_RESPONSE", STATUS_LOGGEDIN, &WorldSession::HandleResurrectResponseOpcode }, - /*0x15D*/ { "CMSG_LOOT", STATUS_LOGGEDIN, &WorldSession::HandleLootOpcode }, - /*0x15E*/ { "CMSG_LOOT_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleLootMoneyOpcode }, - /*0x15F*/ { "CMSG_LOOT_RELEASE", STATUS_LOGGEDIN, &WorldSession::HandleLootReleaseOpcode }, - /*0x160*/ { "SMSG_LOOT_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x161*/ { "SMSG_LOOT_RELEASE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x162*/ { "SMSG_LOOT_REMOVED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x163*/ { "SMSG_LOOT_MONEY_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x164*/ { "SMSG_LOOT_ITEM_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x165*/ { "SMSG_LOOT_CLEAR_MONEY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x166*/ { "SMSG_ITEM_PUSH_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x167*/ { "SMSG_DUEL_REQUESTED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x168*/ { "SMSG_DUEL_OUTOFBOUNDS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x169*/ { "SMSG_DUEL_INBOUNDS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x16A*/ { "SMSG_DUEL_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x16B*/ { "SMSG_DUEL_WINNER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x16C*/ { "CMSG_DUEL_ACCEPTED", STATUS_LOGGEDIN, &WorldSession::HandleDuelAcceptedOpcode }, - /*0x16D*/ { "CMSG_DUEL_CANCELLED", STATUS_LOGGEDIN, &WorldSession::HandleDuelCancelledOpcode }, - /*0x16E*/ { "SMSG_MOUNTRESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x16F*/ { "SMSG_DISMOUNTRESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x170*/ { "SMSG_PUREMOUNT_CANCELLED_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x171*/ { "CMSG_MOUNTSPECIAL_ANIM", STATUS_LOGGEDIN, &WorldSession::HandleMountSpecialAnimOpcode }, - /*0x172*/ { "SMSG_MOUNTSPECIAL_ANIM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x173*/ { "SMSG_PET_TAME_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x174*/ { "CMSG_PET_SET_ACTION", STATUS_LOGGEDIN, &WorldSession::HandlePetSetAction }, - /*0x175*/ { "CMSG_PET_ACTION", STATUS_LOGGEDIN, &WorldSession::HandlePetAction }, - /*0x176*/ { "CMSG_PET_ABANDON", STATUS_LOGGEDIN, &WorldSession::HandlePetAbandon }, - /*0x177*/ { "CMSG_PET_RENAME", STATUS_LOGGEDIN, &WorldSession::HandlePetRename }, - /*0x178*/ { "SMSG_PET_NAME_INVALID", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x179*/ { "SMSG_PET_SPELLS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x17A*/ { "SMSG_PET_MODE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x17B*/ { "CMSG_GOSSIP_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleGossipHelloOpcode }, - /*0x17C*/ { "CMSG_GOSSIP_SELECT_OPTION", STATUS_LOGGEDIN, &WorldSession::HandleGossipSelectOptionOpcode }, - /*0x17D*/ { "SMSG_GOSSIP_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x17E*/ { "SMSG_GOSSIP_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x17F*/ { "CMSG_NPC_TEXT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleNpcTextQueryOpcode }, - /*0x180*/ { "SMSG_NPC_TEXT_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x181*/ { "SMSG_NPC_WONT_TALK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x182*/ { "CMSG_QUESTGIVER_STATUS_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverStatusQueryOpcode}, - /*0x183*/ { "SMSG_QUESTGIVER_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x184*/ { "CMSG_QUESTGIVER_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverHelloOpcode }, - /*0x185*/ { "SMSG_QUESTGIVER_QUEST_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x186*/ { "CMSG_QUESTGIVER_QUERY_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverQueryQuestOpcode}, - /*0x187*/ { "CMSG_QUESTGIVER_QUEST_AUTOLAUNCH", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverQuestAutoLaunch }, - /*0x188*/ { "SMSG_QUESTGIVER_QUEST_DETAILS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x189*/ { "CMSG_QUESTGIVER_ACCEPT_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverAcceptQuestOpcode}, - /*0x18A*/ { "CMSG_QUESTGIVER_COMPLETE_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverCompleteQuest }, - /*0x18B*/ { "SMSG_QUESTGIVER_REQUEST_ITEMS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x18C*/ { "CMSG_QUESTGIVER_REQUEST_REWARD", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverRequestRewardOpcode}, - /*0x18D*/ { "SMSG_QUESTGIVER_OFFER_REWARD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x18E*/ { "CMSG_QUESTGIVER_CHOOSE_REWARD", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverChooseRewardOpcode}, - /*0x18F*/ { "SMSG_QUESTGIVER_QUEST_INVALID", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x190*/ { "CMSG_QUESTGIVER_CANCEL", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverCancel }, - /*0x191*/ { "SMSG_QUESTGIVER_QUEST_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x192*/ { "SMSG_QUESTGIVER_QUEST_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x193*/ { "CMSG_QUESTLOG_SWAP_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestLogSwapQuest }, - /*0x194*/ { "CMSG_QUESTLOG_REMOVE_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestLogRemoveQuest }, - /*0x195*/ { "SMSG_QUESTLOG_FULL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x196*/ { "SMSG_QUESTUPDATE_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x197*/ { "SMSG_QUESTUPDATE_FAILEDTIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x198*/ { "SMSG_QUESTUPDATE_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x199*/ { "SMSG_QUESTUPDATE_ADD_KILL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x19A*/ { "SMSG_QUESTUPDATE_ADD_ITEM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x19B*/ { "CMSG_QUEST_CONFIRM_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleQuestConfirmAccept }, - /*0x19C*/ { "SMSG_QUEST_CONFIRM_ACCEPT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x19D*/ { "CMSG_PUSHQUESTTOPARTY", STATUS_LOGGEDIN, &WorldSession::HandlePushQuestToParty }, - /*0x19E*/ { "CMSG_LIST_INVENTORY", STATUS_LOGGEDIN, &WorldSession::HandleListInventoryOpcode }, - /*0x19F*/ { "SMSG_LIST_INVENTORY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1A0*/ { "CMSG_SELL_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSellItemOpcode }, - /*0x1A1*/ { "SMSG_SELL_ITEM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1A2*/ { "CMSG_BUY_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleBuyItemOpcode }, - /*0x1A3*/ { "CMSG_BUY_ITEM_IN_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleBuyItemInSlotOpcode }, - /*0x1A4*/ { "SMSG_BUY_ITEM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1A5*/ { "SMSG_BUY_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1A6*/ { "CMSG_TAXICLEARALLNODES", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x1A7*/ { "CMSG_TAXIENABLEALLNODES", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x1A8*/ { "CMSG_TAXISHOWNODES", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x1A9*/ { "SMSG_SHOWTAXINODES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1AA*/ { "CMSG_TAXINODE_STATUS_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleTaxiNodeStatusQueryOpcode }, - /*0x1AB*/ { "SMSG_TAXINODE_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1AC*/ { "CMSG_TAXIQUERYAVAILABLENODES", STATUS_LOGGEDIN, &WorldSession::HandleTaxiQueryAvailableNodes }, - /*0x1AD*/ { "CMSG_ACTIVATETAXI", STATUS_LOGGEDIN, &WorldSession::HandleActivateTaxiOpcode }, - /*0x1AE*/ { "SMSG_ACTIVATETAXIREPLY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1AF*/ { "SMSG_NEW_TAXI_PATH", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1B0*/ { "CMSG_TRAINER_LIST", STATUS_LOGGEDIN, &WorldSession::HandleTrainerListOpcode }, - /*0x1B1*/ { "SMSG_TRAINER_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1B2*/ { "CMSG_TRAINER_BUY_SPELL", STATUS_LOGGEDIN, &WorldSession::HandleTrainerBuySpellOpcode }, - /*0x1B3*/ { "SMSG_TRAINER_BUY_SUCCEEDED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1B4*/ { "SMSG_TRAINER_BUY_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1B5*/ { "CMSG_BINDER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleBinderActivateOpcode }, - /*0x1B6*/ { "SMSG_PLAYERBINDERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1B7*/ { "CMSG_BANKER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleBankerActivateOpcode }, - /*0x1B8*/ { "SMSG_SHOW_BANK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1B9*/ { "CMSG_BUY_BANK_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleBuyBankSlotOpcode }, - /*0x1BA*/ { "SMSG_BUY_BANK_SLOT_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1BB*/ { "CMSG_PETITION_SHOWLIST", STATUS_LOGGEDIN, &WorldSession::HandlePetitionShowListOpcode }, - /*0x1BC*/ { "SMSG_PETITION_SHOWLIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1BD*/ { "CMSG_PETITION_BUY", STATUS_LOGGEDIN, &WorldSession::HandlePetitionBuyOpcode }, - /*0x1BE*/ { "CMSG_PETITION_SHOW_SIGNATURES", STATUS_LOGGEDIN, &WorldSession::HandlePetitionShowSignOpcode }, - /*0x1BF*/ { "SMSG_PETITION_SHOW_SIGNATURES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1C0*/ { "CMSG_PETITION_SIGN", STATUS_LOGGEDIN, &WorldSession::HandlePetitionSignOpcode }, - /*0x1C1*/ { "SMSG_PETITION_SIGN_RESULTS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1C2*/ { "MSG_PETITION_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandlePetitionDeclineOpcode }, - /*0x1C3*/ { "CMSG_OFFER_PETITION", STATUS_LOGGEDIN, &WorldSession::HandleOfferPetitionOpcode }, - /*0x1C4*/ { "CMSG_TURN_IN_PETITION", STATUS_LOGGEDIN, &WorldSession::HandleTurnInPetitionOpcode }, - /*0x1C5*/ { "SMSG_TURN_IN_PETITION_RESULTS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1C6*/ { "CMSG_PETITION_QUERY", STATUS_LOGGEDIN, &WorldSession::HandlePetitionQueryOpcode }, - /*0x1C7*/ { "SMSG_PETITION_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1C8*/ { "SMSG_FISH_NOT_HOOKED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1C9*/ { "SMSG_FISH_ESCAPED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1CA*/ { "CMSG_BUG", STATUS_LOGGEDIN, &WorldSession::HandleBugOpcode }, - /*0x1CB*/ { "SMSG_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1CC*/ { "CMSG_PLAYED_TIME", STATUS_LOGGEDIN, &WorldSession::HandlePlayedTime }, - /*0x1CD*/ { "SMSG_PLAYED_TIME", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1CE*/ { "CMSG_QUERY_TIME", STATUS_LOGGEDIN, &WorldSession::HandleQueryTimeOpcode }, - /*0x1CF*/ { "SMSG_QUERY_TIME_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1D0*/ { "SMSG_LOG_XPGAIN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1D1*/ { "SMSG_AURACASTLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1D2*/ { "CMSG_RECLAIM_CORPSE", STATUS_LOGGEDIN, &WorldSession::HandleReclaimCorpseOpcode }, - /*0x1D3*/ { "CMSG_WRAP_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleWrapItemOpcode }, - /*0x1D4*/ { "SMSG_LEVELUP_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1D5*/ { "MSG_MINIMAP_PING", STATUS_LOGGEDIN, &WorldSession::HandleMinimapPingOpcode }, - /*0x1D6*/ { "SMSG_RESISTLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1D7*/ { "SMSG_ENCHANTMENTLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1D8*/ { "CMSG_SET_SKILL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x1D9*/ { "SMSG_START_MIRROR_TIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1DA*/ { "SMSG_PAUSE_MIRROR_TIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1DB*/ { "SMSG_STOP_MIRROR_TIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1DC*/ { "CMSG_PING", STATUS_NEVER, &WorldSession::Handle_EarlyProccess }, - /*0x1DD*/ { "SMSG_PONG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1DE*/ { "SMSG_CLEAR_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1DF*/ { "SMSG_GAMEOBJECT_PAGETEXT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1E0*/ { "CMSG_SETSHEATHED", STATUS_LOGGEDIN, &WorldSession::HandleSetSheathedOpcode }, - /*0x1E1*/ { "SMSG_COOLDOWN_CHEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1E2*/ { "SMSG_SPELL_DELAYED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1E3*/ { "CMSG_QUEST_POI_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleQuestPOIQuery }, - /*0x1E4*/ { "SMSG_QUEST_POI_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1E5*/ { "CMSG_GHOST", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x1E6*/ { "CMSG_GM_INVIS", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x1E7*/ { "SMSG_INVALID_PROMOTION_CODE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1E8*/ { "MSG_GM_BIND_OTHER", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x1E9*/ { "MSG_GM_SUMMON", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x1EA*/ { "SMSG_ITEM_TIME_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1EB*/ { "SMSG_ITEM_ENCHANT_TIME_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1EC*/ { "SMSG_AUTH_CHALLENGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1ED*/ { "CMSG_AUTH_SESSION", STATUS_NEVER, &WorldSession::Handle_EarlyProccess }, - /*0x1EE*/ { "SMSG_AUTH_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1EF*/ { "MSG_GM_SHOWLABEL", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x1F0*/ { "CMSG_PET_CAST_SPELL", STATUS_LOGGEDIN, &WorldSession::HandlePetCastSpellOpcode }, - /*0x1F1*/ { "MSG_SAVE_GUILD_EMBLEM", STATUS_LOGGEDIN, &WorldSession::HandleSaveGuildEmblemOpcode }, - /*0x1F2*/ { "MSG_TABARDVENDOR_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleTabardVendorActivateOpcode}, - /*0x1F3*/ { "SMSG_PLAY_SPELL_VISUAL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1F4*/ { "CMSG_ZONEUPDATE", STATUS_LOGGEDIN, &WorldSession::HandleZoneUpdateOpcode }, - /*0x1F5*/ { "SMSG_PARTYKILLLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1F6*/ { "SMSG_COMPRESSED_UPDATE_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1F7*/ { "SMSG_PLAY_SPELL_IMPACT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1F8*/ { "SMSG_EXPLORATION_EXPERIENCE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1F9*/ { "CMSG_GM_SET_SECURITY_GROUP", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x1FA*/ { "CMSG_GM_NUKE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x1FB*/ { "MSG_RANDOM_ROLL", STATUS_LOGGEDIN, &WorldSession::HandleRandomRollOpcode }, - /*0x1FC*/ { "SMSG_ENVIRONMENTALDAMAGELOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1FD*/ { "CMSG_PLAYER_DIFFICULTY_CHANGE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x1FE*/ { "SMSG_RWHOIS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x1FF*/ { "SMSG_LFG_PLAYER_REWARD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x200*/ { "SMSG_LFG_TELEPORT_DENIED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x201*/ { "CMSG_UNLEARN_SPELL", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x202*/ { "CMSG_UNLEARN_SKILL", STATUS_LOGGEDIN, &WorldSession::HandleUnlearnSkillOpcode }, - /*0x203*/ { "SMSG_REMOVED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x204*/ { "CMSG_DECHARGE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x205*/ { "CMSG_GMTICKET_CREATE", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketCreateOpcode }, - /*0x206*/ { "SMSG_GMTICKET_CREATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x207*/ { "CMSG_GMTICKET_UPDATETEXT", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketUpdateOpcode }, - /*0x208*/ { "SMSG_GMTICKET_UPDATETEXT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x209*/ { "SMSG_ACCOUNT_DATA_TIMES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x20A*/ { "CMSG_REQUEST_ACCOUNT_DATA", STATUS_AUTHED, &WorldSession::HandleRequestAccountData }, - /*0x20B*/ { "CMSG_UPDATE_ACCOUNT_DATA", STATUS_AUTHED, &WorldSession::HandleUpdateAccountData }, - /*0x20C*/ { "SMSG_UPDATE_ACCOUNT_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x20D*/ { "SMSG_CLEAR_FAR_SIGHT_IMMEDIATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x20E*/ { "SMSG_PLAYER_DIFFICULTY_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x20F*/ { "CMSG_GM_TEACH", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x210*/ { "CMSG_GM_CREATE_ITEM_TARGET", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x211*/ { "CMSG_GMTICKET_GETTICKET", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketGetTicketOpcode }, - /*0x212*/ { "SMSG_GMTICKET_GETTICKET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x213*/ { "CMSG_UNLEARN_TALENTS", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x214*/ { "SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x215*/ { "SMSG_GAMEOBJECT_DESPAWN_ANIM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x216*/ { "MSG_CORPSE_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleCorpseQueryOpcode }, - /*0x217*/ { "CMSG_GMTICKET_DELETETICKET", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketDeleteOpcode }, - /*0x218*/ { "SMSG_GMTICKET_DELETETICKET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x219*/ { "SMSG_CHAT_WRONG_FACTION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x21A*/ { "CMSG_GMTICKET_SYSTEMSTATUS", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketSystemStatusOpcode}, - /*0x21B*/ { "SMSG_GMTICKET_SYSTEMSTATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x21C*/ { "CMSG_SPIRIT_HEALER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleSpiritHealerActivateOpcode}, - /*0x21D*/ { "CMSG_SET_STAT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x21E*/ { "SMSG_SET_REST_START_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x21F*/ { "CMSG_SKILL_BUY_STEP", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x220*/ { "CMSG_SKILL_BUY_RANK", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x221*/ { "CMSG_XP_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x222*/ { "SMSG_SPIRIT_HEALER_CONFIRM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x223*/ { "CMSG_CHARACTER_POINT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x224*/ { "SMSG_GOSSIP_POI", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x225*/ { "CMSG_CHAT_IGNORED", STATUS_LOGGEDIN, &WorldSession::HandleChatIgnoredOpcode }, - /*0x226*/ { "CMSG_GM_VISION", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x227*/ { "CMSG_SERVER_COMMAND", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x228*/ { "CMSG_GM_SILENCE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x229*/ { "CMSG_GM_REVEALTO", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x22A*/ { "CMSG_GM_RESURRECT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x22B*/ { "CMSG_GM_SUMMONMOB", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x22C*/ { "CMSG_GM_MOVECORPSE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x22D*/ { "CMSG_GM_FREEZE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x22E*/ { "CMSG_GM_UBERINVIS", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x22F*/ { "CMSG_GM_REQUEST_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x230*/ { "SMSG_GM_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x231*/ { "CMSG_GUILD_RANK", STATUS_LOGGEDIN, &WorldSession::HandleGuildRankOpcode }, - /*0x232*/ { "CMSG_GUILD_ADD_RANK", STATUS_LOGGEDIN, &WorldSession::HandleGuildAddRankOpcode }, - /*0x233*/ { "CMSG_GUILD_DEL_RANK", STATUS_LOGGEDIN, &WorldSession::HandleGuildDelRankOpcode }, - /*0x234*/ { "CMSG_GUILD_SET_PUBLIC_NOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildSetPublicNoteOpcode }, - /*0x235*/ { "CMSG_GUILD_SET_OFFICER_NOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildSetOfficerNoteOpcode }, - /*0x236*/ { "SMSG_LOGIN_VERIFY_WORLD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x237*/ { "CMSG_CLEAR_EXPLORATION", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x238*/ { "CMSG_SEND_MAIL", STATUS_LOGGEDIN, &WorldSession::HandleSendMail }, - /*0x239*/ { "SMSG_SEND_MAIL_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x23A*/ { "CMSG_GET_MAIL_LIST", STATUS_LOGGEDIN, &WorldSession::HandleGetMailList }, - /*0x23B*/ { "SMSG_MAIL_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x23C*/ { "CMSG_BATTLEFIELD_LIST", STATUS_LOGGEDIN, &WorldSession::HandleBattlefieldListOpcode }, - /*0x23D*/ { "SMSG_BATTLEFIELD_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x23E*/ { "CMSG_BATTLEFIELD_JOIN", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x23F*/ { "SMSG_BATTLEFIELD_WIN_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x240*/ { "SMSG_BATTLEFIELD_LOSE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x241*/ { "CMSG_TAXICLEARNODE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x242*/ { "CMSG_TAXIENABLENODE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x243*/ { "CMSG_ITEM_TEXT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleItemTextQuery }, - /*0x244*/ { "SMSG_ITEM_TEXT_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x245*/ { "CMSG_MAIL_TAKE_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleMailTakeMoney }, - /*0x246*/ { "CMSG_MAIL_TAKE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleMailTakeItem }, - /*0x247*/ { "CMSG_MAIL_MARK_AS_READ", STATUS_LOGGEDIN, &WorldSession::HandleMailMarkAsRead }, - /*0x248*/ { "CMSG_MAIL_RETURN_TO_SENDER", STATUS_LOGGEDIN, &WorldSession::HandleMailReturnToSender }, - /*0x249*/ { "CMSG_MAIL_DELETE", STATUS_LOGGEDIN, &WorldSession::HandleMailDelete }, - /*0x24A*/ { "CMSG_MAIL_CREATE_TEXT_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleMailCreateTextItem }, - /*0x24B*/ { "SMSG_SPELLLOGMISS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x24C*/ { "SMSG_SPELLLOGEXECUTE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x24D*/ { "SMSG_DEBUGAURAPROC", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x24E*/ { "SMSG_PERIODICAURALOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x24F*/ { "SMSG_SPELLDAMAGESHIELD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x250*/ { "SMSG_SPELLNONMELEEDAMAGELOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x251*/ { "CMSG_LEARN_TALENT", STATUS_LOGGEDIN, &WorldSession::HandleLearnTalentOpcode }, - /*0x252*/ { "SMSG_RESURRECT_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x253*/ { "CMSG_TOGGLE_PVP", STATUS_LOGGEDIN, &WorldSession::HandleTogglePvP }, - /*0x254*/ { "SMSG_ZONE_UNDER_ATTACK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x255*/ { "MSG_AUCTION_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleAuctionHelloOpcode }, - /*0x256*/ { "CMSG_AUCTION_SELL_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAuctionSellItem }, - /*0x257*/ { "CMSG_AUCTION_REMOVE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAuctionRemoveItem }, - /*0x258*/ { "CMSG_AUCTION_LIST_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListItems }, - /*0x259*/ { "CMSG_AUCTION_LIST_OWNER_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListOwnerItems }, - /*0x25A*/ { "CMSG_AUCTION_PLACE_BID", STATUS_LOGGEDIN, &WorldSession::HandleAuctionPlaceBid }, - /*0x25B*/ { "SMSG_AUCTION_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x25C*/ { "SMSG_AUCTION_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x25D*/ { "SMSG_AUCTION_OWNER_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x25E*/ { "SMSG_AUCTION_BIDDER_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x25F*/ { "SMSG_AUCTION_OWNER_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x260*/ { "SMSG_PROCRESIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x261*/ { "SMSG_STANDSTATE_CHANGE_FAILURE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x262*/ { "SMSG_DISPEL_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x263*/ { "SMSG_SPELLORDAMAGE_IMMUNE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x264*/ { "CMSG_AUCTION_LIST_BIDDER_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListBidderItems }, - /*0x265*/ { "SMSG_AUCTION_BIDDER_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x266*/ { "SMSG_SET_FLAT_SPELL_MODIFIER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x267*/ { "SMSG_SET_PCT_SPELL_MODIFIER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x268*/ { "CMSG_SET_AMMO", STATUS_LOGGEDIN, &WorldSession::HandleSetAmmoOpcode }, - /*0x269*/ { "SMSG_CORPSE_RECLAIM_DELAY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x26A*/ { "CMSG_SET_ACTIVE_MOVER", STATUS_LOGGEDIN, &WorldSession::HandleSetActiveMoverOpcode }, - /*0x26B*/ { "CMSG_PET_CANCEL_AURA", STATUS_LOGGEDIN, &WorldSession::HandlePetCancelAuraOpcode }, - /*0x26C*/ { "CMSG_PLAYER_AI_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x26D*/ { "CMSG_CANCEL_AUTO_REPEAT_SPELL", STATUS_LOGGEDIN, &WorldSession::HandleCancelAutoRepeatSpellOpcode}, - /*0x26E*/ { "MSG_GM_ACCOUNT_ONLINE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x26F*/ { "MSG_LIST_STABLED_PETS", STATUS_LOGGEDIN, &WorldSession::HandleListStabledPetsOpcode }, - /*0x270*/ { "CMSG_STABLE_PET", STATUS_LOGGEDIN, &WorldSession::HandleStablePet }, - /*0x271*/ { "CMSG_UNSTABLE_PET", STATUS_LOGGEDIN, &WorldSession::HandleUnstablePet }, - /*0x272*/ { "CMSG_BUY_STABLE_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleBuyStableSlot }, - /*0x273*/ { "SMSG_STABLE_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x274*/ { "CMSG_STABLE_REVIVE_PET", STATUS_LOGGEDIN, &WorldSession::HandleStableRevivePet }, - /*0x275*/ { "CMSG_STABLE_SWAP_PET", STATUS_LOGGEDIN, &WorldSession::HandleStableSwapPet }, - /*0x276*/ { "MSG_QUEST_PUSH_RESULT", STATUS_LOGGEDIN, &WorldSession::HandleQuestPushResult }, - /*0x277*/ { "SMSG_PLAY_MUSIC", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x278*/ { "SMSG_PLAY_OBJECT_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x279*/ { "CMSG_REQUEST_PET_INFO", STATUS_LOGGEDIN, &WorldSession::HandleRequestPetInfoOpcode }, - /*0x27A*/ { "CMSG_FAR_SIGHT", STATUS_LOGGEDIN, &WorldSession::HandleFarSightOpcode }, - /*0x27B*/ { "SMSG_SPELLDISPELLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x27C*/ { "SMSG_DAMAGE_CALC_LOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x27D*/ { "CMSG_ENABLE_DAMAGE_LOG", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x27E*/ { "CMSG_GROUP_CHANGE_SUB_GROUP", STATUS_LOGGEDIN, &WorldSession::HandleGroupChangeSubGroupOpcode }, - /*0x27F*/ { "CMSG_REQUEST_PARTY_MEMBER_STATS", STATUS_LOGGEDIN, &WorldSession::HandleRequestPartyMemberStatsOpcode}, - /*0x280*/ { "CMSG_GROUP_SWAP_SUB_GROUP", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x281*/ { "CMSG_RESET_FACTION_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x282*/ { "CMSG_AUTOSTORE_BANK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoStoreBankItemOpcode }, - /*0x283*/ { "CMSG_AUTOBANK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoBankItemOpcode }, - /*0x284*/ { "MSG_QUERY_NEXT_MAIL_TIME", STATUS_LOGGEDIN, &WorldSession::HandleQueryNextMailTime }, - /*0x285*/ { "SMSG_RECEIVED_MAIL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x286*/ { "SMSG_RAID_GROUP_ONLY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x287*/ { "CMSG_SET_DURABILITY_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x288*/ { "CMSG_SET_PVP_RANK_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x289*/ { "CMSG_ADD_PVP_MEDAL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x28A*/ { "CMSG_DEL_PVP_MEDAL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x28B*/ { "CMSG_SET_PVP_TITLE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x28C*/ { "SMSG_PVP_CREDIT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x28D*/ { "SMSG_AUCTION_REMOVED_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x28E*/ { "CMSG_GROUP_RAID_CONVERT", STATUS_LOGGEDIN, &WorldSession::HandleGroupRaidConvertOpcode }, - /*0x28F*/ { "CMSG_GROUP_ASSISTANT_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGroupAssistantLeaderOpcode}, - /*0x290*/ { "CMSG_BUYBACK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleBuybackItem }, - /*0x291*/ { "SMSG_SERVER_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x292*/ { "CMSG_SET_SAVED_INSTANCE_EXTEND", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x293*/ { "SMSG_LFG_OFFER_CONTINUE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x294*/ { "CMSG_MEETINGSTONE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x295*/ { "SMSG_MEETINGSTONE_SETQUEUE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x296*/ { "CMSG_MEETINGSTONE_INFO", STATUS_LOGGEDIN, &WorldSession::HandleMeetingStoneInfo }, - /*0x297*/ { "SMSG_MEETINGSTONE_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x298*/ { "SMSG_MEETINGSTONE_IN_PROGRESS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x299*/ { "SMSG_MEETINGSTONE_MEMBER_ADDED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x29A*/ { "CMSG_GMTICKETSYSTEM_TOGGLE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x29B*/ { "CMSG_CANCEL_GROWTH_AURA", STATUS_LOGGEDIN, &WorldSession::HandleCancelGrowthAuraOpcode }, - /*0x29C*/ { "SMSG_CANCEL_AUTO_REPEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x29D*/ { "SMSG_STANDSTATE_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x29E*/ { "SMSG_LOOT_ALL_PASSED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x29F*/ { "SMSG_LOOT_ROLL_WON", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2A0*/ { "CMSG_LOOT_ROLL", STATUS_LOGGEDIN, &WorldSession::HandleLootRoll }, - /*0x2A1*/ { "SMSG_LOOT_START_ROLL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2A2*/ { "SMSG_LOOT_ROLL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2A3*/ { "CMSG_LOOT_MASTER_GIVE", STATUS_LOGGEDIN, &WorldSession::HandleLootMasterGiveOpcode }, - /*0x2A4*/ { "SMSG_LOOT_MASTER_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2A5*/ { "SMSG_SET_FORCED_REACTIONS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2A6*/ { "SMSG_SPELL_FAILED_OTHER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2A7*/ { "SMSG_GAMEOBJECT_RESET_STATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2A8*/ { "CMSG_REPAIR_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleRepairItemOpcode }, - /*0x2A9*/ { "SMSG_CHAT_PLAYER_NOT_FOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2AA*/ { "MSG_TALENT_WIPE_CONFIRM", STATUS_LOGGEDIN, &WorldSession::HandleTalentWipeConfirmOpcode }, - /*0x2AB*/ { "SMSG_SUMMON_REQUEST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2AC*/ { "CMSG_SUMMON_RESPONSE", STATUS_LOGGEDIN, &WorldSession::HandleSummonResponseOpcode }, - /*0x2AD*/ { "MSG_MOVE_TOGGLE_GRAVITY_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x2AE*/ { "SMSG_MONSTER_MOVE_TRANSPORT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2AF*/ { "SMSG_PET_BROKEN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2B0*/ { "MSG_MOVE_FEATHER_FALL", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x2B1*/ { "MSG_MOVE_WATER_WALK", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x2B2*/ { "CMSG_SERVER_BROADCAST", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x2B3*/ { "CMSG_SELF_RES", STATUS_LOGGEDIN, &WorldSession::HandleSelfResOpcode }, - /*0x2B4*/ { "SMSG_FEIGN_DEATH_RESISTED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2B5*/ { "CMSG_RUN_SCRIPT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x2B6*/ { "SMSG_SCRIPT_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2B7*/ { "SMSG_DUEL_COUNTDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2B8*/ { "SMSG_AREA_TRIGGER_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2B9*/ { "CMSG_SHOWING_HELM", STATUS_LOGGEDIN, &WorldSession::HandleShowingHelmOpcode }, - /*0x2BA*/ { "CMSG_SHOWING_CLOAK", STATUS_LOGGEDIN, &WorldSession::HandleShowingCloakOpcode }, - /*0x2BB*/ { "SMSG_LFG_ROLE_CHOSEN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2BC*/ { "SMSG_PLAYER_SKINNED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2BD*/ { "SMSG_DURABILITY_DAMAGE_DEATH", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2BE*/ { "CMSG_SET_EXPLORATION", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x2BF*/ { "CMSG_SET_ACTIONBAR_TOGGLES", STATUS_AUTHED, &WorldSession::HandleSetActionBarToggles }, - /*0x2C0*/ { "UMSG_DELETE_GUILD_CHARTER", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x2C1*/ { "MSG_PETITION_RENAME", STATUS_LOGGEDIN, &WorldSession::HandlePetitionRenameOpcode }, - /*0x2C2*/ { "SMSG_INIT_WORLD_STATES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2C3*/ { "SMSG_UPDATE_WORLD_STATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2C4*/ { "CMSG_ITEM_NAME_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleItemNameQueryOpcode }, - /*0x2C5*/ { "SMSG_ITEM_NAME_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2C6*/ { "SMSG_PET_ACTION_FEEDBACK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2C7*/ { "CMSG_CHAR_RENAME", STATUS_AUTHED, &WorldSession::HandleCharRenameOpcode }, - /*0x2C8*/ { "SMSG_CHAR_RENAME", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2C9*/ { "CMSG_MOVE_SPLINE_DONE", STATUS_LOGGEDIN, &WorldSession::HandleMoveSplineDoneOpcode }, - /*0x2CA*/ { "CMSG_MOVE_FALL_RESET", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x2CB*/ { "SMSG_INSTANCE_SAVE_CREATED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2CC*/ { "SMSG_RAID_INSTANCE_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2CD*/ { "CMSG_REQUEST_RAID_INFO", STATUS_LOGGEDIN, &WorldSession::HandleRequestRaidInfoOpcode }, - /*0x2CE*/ { "CMSG_MOVE_TIME_SKIPPED", STATUS_LOGGEDIN, &WorldSession::HandleMoveTimeSkippedOpcode }, - /*0x2CF*/ { "CMSG_MOVE_FEATHER_FALL_ACK", STATUS_LOGGEDIN, &WorldSession::HandleFeatherFallAck }, - /*0x2D0*/ { "CMSG_MOVE_WATER_WALK_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveWaterWalkAck }, - /*0x2D1*/ { "CMSG_MOVE_NOT_ACTIVE_MOVER", STATUS_LOGGEDIN, &WorldSession::HandleMoveNotActiveMover }, - /*0x2D2*/ { "SMSG_PLAY_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2D3*/ { "CMSG_BATTLEFIELD_STATUS", STATUS_LOGGEDIN, &WorldSession::HandleBattlefieldStatusOpcode }, - /*0x2D4*/ { "SMSG_BATTLEFIELD_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2D5*/ { "CMSG_BATTLEFIELD_PORT", STATUS_LOGGEDIN, &WorldSession::HandleBattleFieldPortOpcode }, - /*0x2D6*/ { "MSG_INSPECT_HONOR_STATS", STATUS_LOGGEDIN, &WorldSession::HandleInspectHonorStatsOpcode }, - /*0x2D7*/ { "CMSG_BATTLEMASTER_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleBattlemasterHelloOpcode }, - /*0x2D8*/ { "CMSG_MOVE_START_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x2D9*/ { "CMSG_MOVE_STOP_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x2DA*/ { "SMSG_FORCE_WALK_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2DB*/ { "CMSG_FORCE_WALK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, - /*0x2DC*/ { "SMSG_FORCE_SWIM_BACK_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2DD*/ { "CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, - /*0x2DE*/ { "SMSG_FORCE_TURN_RATE_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2DF*/ { "CMSG_FORCE_TURN_RATE_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, - /*0x2E0*/ { "MSG_PVP_LOG_DATA", STATUS_LOGGEDIN, &WorldSession::HandlePVPLogDataOpcode }, - /*0x2E1*/ { "CMSG_LEAVE_BATTLEFIELD", STATUS_LOGGEDIN, &WorldSession::HandleLeaveBattlefieldOpcode }, - /*0x2E2*/ { "CMSG_AREA_SPIRIT_HEALER_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleAreaSpiritHealerQueryOpcode}, - /*0x2E3*/ { "CMSG_AREA_SPIRIT_HEALER_QUEUE", STATUS_LOGGEDIN, &WorldSession::HandleAreaSpiritHealerQueueOpcode}, - /*0x2E4*/ { "SMSG_AREA_SPIRIT_HEALER_TIME", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2E5*/ { "CMSG_GM_UNTEACH", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x2E6*/ { "SMSG_WARDEN_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2E7*/ { "CMSG_WARDEN_DATA", STATUS_LOGGEDIN, &WorldSession::HandleWardenDataOpcode }, - /*0x2E8*/ { "SMSG_GROUP_JOINED_BATTLEGROUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2E9*/ { "MSG_BATTLEGROUND_PLAYER_POSITIONS", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundPlayerPositionsOpcode}, - /*0x2EA*/ { "CMSG_PET_STOP_ATTACK", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x2EB*/ { "SMSG_BINDER_CONFIRM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2EC*/ { "SMSG_BATTLEGROUND_PLAYER_JOINED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2ED*/ { "SMSG_BATTLEGROUND_PLAYER_LEFT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2EE*/ { "CMSG_BATTLEMASTER_JOIN", STATUS_LOGGEDIN, &WorldSession::HandleBattlemasterJoinOpcode }, - /*0x2EF*/ { "SMSG_ADDON_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2F0*/ { "CMSG_PET_UNLEARN", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, - /*0x2F1*/ { "SMSG_PET_UNLEARN_CONFIRM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2F2*/ { "SMSG_PARTY_MEMBER_STATS_FULL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2F3*/ { "CMSG_PET_SPELL_AUTOCAST", STATUS_LOGGEDIN, &WorldSession::HandlePetSpellAutocastOpcode }, - /*0x2F4*/ { "SMSG_WEATHER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2F5*/ { "SMSG_PLAY_TIME_WARNING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2F6*/ { "SMSG_MINIGAME_SETUP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2F7*/ { "SMSG_MINIGAME_STATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2F8*/ { "CMSG_MINIGAME_MOVE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x2F9*/ { "SMSG_MINIGAME_MOVE_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2FA*/ { "SMSG_RAID_INSTANCE_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2FB*/ { "SMSG_COMPRESSED_MOVES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2FC*/ { "CMSG_GUILD_INFO_TEXT", STATUS_LOGGEDIN, &WorldSession::HandleGuildChangeInfoTextOpcode }, - /*0x2FD*/ { "SMSG_CHAT_RESTRICTED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2FE*/ { "SMSG_SPLINE_SET_RUN_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x2FF*/ { "SMSG_SPLINE_SET_RUN_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x300*/ { "SMSG_SPLINE_SET_SWIM_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x301*/ { "SMSG_SPLINE_SET_WALK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x302*/ { "SMSG_SPLINE_SET_SWIM_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x303*/ { "SMSG_SPLINE_SET_TURN_RATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x304*/ { "SMSG_SPLINE_MOVE_UNROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x305*/ { "SMSG_SPLINE_MOVE_FEATHER_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x306*/ { "SMSG_SPLINE_MOVE_NORMAL_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x307*/ { "SMSG_SPLINE_MOVE_SET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x308*/ { "SMSG_SPLINE_MOVE_UNSET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x309*/ { "SMSG_SPLINE_MOVE_WATER_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x30A*/ { "SMSG_SPLINE_MOVE_LAND_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x30B*/ { "SMSG_SPLINE_MOVE_START_SWIM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x30C*/ { "SMSG_SPLINE_MOVE_STOP_SWIM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x30D*/ { "SMSG_SPLINE_MOVE_SET_RUN_MODE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x30E*/ { "SMSG_SPLINE_MOVE_SET_WALK_MODE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x30F*/ { "CMSG_GM_NUKE_ACCOUNT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x310*/ { "MSG_GM_DESTROY_CORPSE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x311*/ { "CMSG_GM_DESTROY_ONLINE_CORPSE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x312*/ { "CMSG_ACTIVATETAXIEXPRESS", STATUS_LOGGEDIN, &WorldSession::HandleActivateTaxiExpressOpcode }, - /*0x313*/ { "SMSG_SET_FACTION_ATWAR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x314*/ { "SMSG_GAMETIMEBIAS_SET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x315*/ { "CMSG_DEBUG_ACTIONS_START", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x316*/ { "CMSG_DEBUG_ACTIONS_STOP", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x317*/ { "CMSG_SET_FACTION_INACTIVE", STATUS_LOGGEDIN, &WorldSession::HandleSetFactionInactiveOpcode }, - /*0x318*/ { "CMSG_SET_WATCHED_FACTION", STATUS_LOGGEDIN, &WorldSession::HandleSetWatchedFactionOpcode }, - /*0x319*/ { "MSG_MOVE_TIME_SKIPPED", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x31A*/ { "SMSG_SPLINE_MOVE_ROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x31B*/ { "CMSG_SET_EXPLORATION_ALL", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x31C*/ { "SMSG_INVALIDATE_PLAYER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x31D*/ { "CMSG_RESET_INSTANCES", STATUS_LOGGEDIN, &WorldSession::HandleResetInstancesOpcode }, - /*0x31E*/ { "SMSG_INSTANCE_RESET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x31F*/ { "SMSG_INSTANCE_RESET_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x320*/ { "SMSG_UPDATE_LAST_INSTANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x321*/ { "MSG_RAID_TARGET_UPDATE", STATUS_LOGGEDIN, &WorldSession::HandleRaidTargetUpdateOpcode }, - /*0x322*/ { "MSG_RAID_READY_CHECK", STATUS_LOGGEDIN, &WorldSession::HandleRaidReadyCheckOpcode }, - /*0x323*/ { "CMSG_LUA_USAGE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x324*/ { "SMSG_PET_ACTION_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x325*/ { "SMSG_PET_DISMISS_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x326*/ { "SMSG_GHOSTEE_GONE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x327*/ { "CMSG_GM_UPDATE_TICKET_STATUS", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x328*/ { "SMSG_GM_TICKET_STATUS_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x329*/ { "MSG_SET_DUNGEON_DIFFICULTY", STATUS_LOGGEDIN, &WorldSession::HandleSetDungeonDifficultyOpcode}, - /*0x32A*/ { "CMSG_GMSURVEY_SUBMIT", STATUS_NEVER, &WorldSession::Handle_NULL },//LOGGEDIN, &WorldSession::HandleGMSurveySubmit }, - /*0x32B*/ { "SMSG_UPDATE_INSTANCE_OWNERSHIP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x32C*/ { "CMSG_IGNORE_KNOCKBACK_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x32D*/ { "SMSG_CHAT_PLAYER_AMBIGUOUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x32E*/ { "MSG_DELAY_GHOST_TELEPORT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x32F*/ { "SMSG_SPELLINSTAKILLLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x330*/ { "SMSG_SPELL_UPDATE_CHAIN_TARGETS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x331*/ { "CMSG_CHAT_FILTERED", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x332*/ { "SMSG_EXPECTED_SPAM_RECORDS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x333*/ { "SMSG_SPELLSTEALLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x334*/ { "CMSG_LOTTERY_QUERY_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x335*/ { "SMSG_LOTTERY_QUERY_RESULT_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x336*/ { "CMSG_BUY_LOTTERY_TICKET_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x337*/ { "SMSG_LOTTERY_RESULT_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x338*/ { "SMSG_CHARACTER_PROFILE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x339*/ { "SMSG_CHARACTER_PROFILE_REALM_CONNECTED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x33A*/ { "SMSG_DEFENSE_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x33B*/ { "SMSG_INSTANCE_DIFFICULTY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x33C*/ { "MSG_GM_RESETINSTANCELIMIT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x33D*/ { "SMSG_MOTD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x33E*/ { "SMSG_MOVE_SET_FLIGHT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x33F*/ { "SMSG_MOVE_UNSET_FLIGHT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x340*/ { "CMSG_MOVE_FLIGHT_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x341*/ { "MSG_MOVE_START_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x342*/ { "MSG_MOVE_STOP_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x343*/ { "SMSG_MOVE_SET_CAN_FLY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x344*/ { "SMSG_MOVE_UNSET_CAN_FLY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x345*/ { "CMSG_MOVE_SET_CAN_FLY_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveSetCanFlyAckOpcode }, - /*0x346*/ { "CMSG_MOVE_SET_FLY", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x347*/ { "CMSG_SOCKET_GEMS", STATUS_LOGGEDIN, &WorldSession::HandleSocketOpcode }, - /*0x348*/ { "CMSG_ARENA_TEAM_CREATE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x349*/ { "SMSG_ARENA_TEAM_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x34A*/ { "UMSG_UPDATE_ARENA_TEAM_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x34B*/ { "CMSG_ARENA_TEAM_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamQueryOpcode }, - /*0x34C*/ { "SMSG_ARENA_TEAM_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x34D*/ { "CMSG_ARENA_TEAM_ROSTER", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamRosterOpcode }, - /*0x34E*/ { "SMSG_ARENA_TEAM_ROSTER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x34F*/ { "CMSG_ARENA_TEAM_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamInviteOpcode }, - /*0x350*/ { "SMSG_ARENA_TEAM_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x351*/ { "CMSG_ARENA_TEAM_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamAcceptOpcode }, - /*0x352*/ { "CMSG_ARENA_TEAM_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamDeclineOpcode }, - /*0x353*/ { "CMSG_ARENA_TEAM_LEAVE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamLeaveOpcode }, - /*0x354*/ { "CMSG_ARENA_TEAM_REMOVE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamRemoveOpcode }, - /*0x355*/ { "CMSG_ARENA_TEAM_DISBAND", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamDisbandOpcode }, - /*0x356*/ { "CMSG_ARENA_TEAM_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamLeaderOpcode }, - /*0x357*/ { "SMSG_ARENA_TEAM_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x358*/ { "CMSG_BATTLEMASTER_JOIN_ARENA", STATUS_LOGGEDIN, &WorldSession::HandleBattlemasterJoinArena }, - /*0x359*/ { "MSG_MOVE_START_ASCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x35A*/ { "MSG_MOVE_STOP_ASCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x35B*/ { "SMSG_ARENA_TEAM_STATS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x35C*/ { "CMSG_LFG_JOIN", STATUS_LOGGEDIN, &WorldSession::HandleLfgJoinOpcode }, - /*0x35D*/ { "CMSG_LFG_LEAVE", STATUS_LOGGEDIN, &WorldSession::HandleLfgLeaveOpcode }, - /*0x35E*/ { "CMSG_SEARCH_LFG_JOIN", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, - /*0x35F*/ { "CMSG_SEARCH_LFG_LEAVE", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, - /*0x360*/ { "SMSG_UPDATE_LFG_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x361*/ { "SMSG_LFG_PROPOSAL_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x362*/ { "CMSG_LFG_PROPOSAL_RESULT", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, - /*0x363*/ { "SMSG_LFG_ROLE_CHECK_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x364*/ { "SMSG_LFG_JOIN_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x365*/ { "SMSG_LFG_QUEUE_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x366*/ { "CMSG_SET_LFG_COMMENT", STATUS_LOGGEDIN, &WorldSession::HandleSetLfgCommentOpcode }, - /*0x367*/ { "SMSG_LFG_UPDATE_PLAYER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x368*/ { "SMSG_LFG_UPDATE_PARTY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x369*/ { "SMSG_LFG_UPDATE_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x36A*/ { "CMSG_LFG_SET_ROLES", STATUS_LOGGEDIN, &WorldSession::HandleLfgSetRolesOpcode }, - /*0x36B*/ { "CMSG_LFG_SET_NEEDS", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, - /*0x36C*/ { "CMSG_LFG_SET_BOOT_VOTE", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, - /*0x36D*/ { "SMSG_LFG_BOOT_PROPOSAL_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x36E*/ { "CMSG_LFD_PLAYER_LOCK_INFO_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleLfgPlayerLockInfoRequestOpcode}, - /*0x36F*/ { "SMSG_LFG_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x370*/ { "CMSG_LFG_TELEPORT", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, - /*0x371*/ { "CMSG_LFD_PARTY_LOCK_INFO_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleLfgPartyLockInfoRequestOpcode}, - /*0x372*/ { "SMSG_LFG_PARTY_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x373*/ { "SMSG_TITLE_EARNED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x374*/ { "CMSG_SET_TITLE", STATUS_LOGGEDIN, &WorldSession::HandleSetTitleOpcode }, - /*0x375*/ { "CMSG_CANCEL_MOUNT_AURA", STATUS_LOGGEDIN, &WorldSession::HandleCancelMountAuraOpcode }, - /*0x376*/ { "SMSG_ARENA_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x377*/ { "MSG_INSPECT_ARENA_TEAMS", STATUS_LOGGEDIN, &WorldSession::HandleInspectArenaTeamsOpcode }, - /*0x378*/ { "SMSG_DEATH_RELEASE_LOC", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x379*/ { "CMSG_CANCEL_TEMP_ENCHANTMENT", STATUS_LOGGEDIN, &WorldSession::HandleCancelTempEnchantmentOpcode}, - /*0x37A*/ { "SMSG_FORCED_DEATH_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x37B*/ { "CMSG_CHEAT_SET_HONOR_CURRENCY", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x37C*/ { "CMSG_CHEAT_SET_ARENA_CURRENCY", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x37D*/ { "MSG_MOVE_SET_FLIGHT_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x37E*/ { "MSG_MOVE_SET_FLIGHT_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x37F*/ { "MSG_MOVE_SET_FLIGHT_BACK_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x380*/ { "MSG_MOVE_SET_FLIGHT_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x381*/ { "SMSG_FORCE_FLIGHT_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x382*/ { "CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, - /*0x383*/ { "SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x384*/ { "CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, - /*0x385*/ { "SMSG_SPLINE_SET_FLIGHT_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x386*/ { "SMSG_SPLINE_SET_FLIGHT_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x387*/ { "CMSG_MAELSTROM_INVALIDATE_CACHE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x388*/ { "SMSG_FLIGHT_SPLINE_SYNC", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x389*/ { "CMSG_SET_TAXI_BENCHMARK_MODE", STATUS_AUTHED, &WorldSession::HandleSetTaxiBenchmarkOpcode }, - /*0x38A*/ { "SMSG_JOINED_BATTLEGROUND_QUEUE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x38B*/ { "SMSG_REALM_SPLIT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x38C*/ { "CMSG_REALM_SPLIT", STATUS_AUTHED, &WorldSession::HandleRealmSplitOpcode }, - /*0x38D*/ { "CMSG_MOVE_CHNG_TRANSPORT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x38E*/ { "MSG_PARTY_ASSIGNMENT", STATUS_LOGGEDIN, &WorldSession::HandlePartyAssignmentOpcode }, - /*0x38F*/ { "SMSG_OFFER_PETITION_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x390*/ { "SMSG_TIME_SYNC_REQ", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x391*/ { "CMSG_TIME_SYNC_RESP", STATUS_LOGGEDIN, &WorldSession::HandleTimeSyncResp }, - /*0x392*/ { "CMSG_SEND_LOCAL_EVENT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x393*/ { "CMSG_SEND_GENERAL_TRIGGER", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x394*/ { "CMSG_SEND_COMBAT_TRIGGER", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x395*/ { "CMSG_MAELSTROM_GM_SENT_MAIL", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x396*/ { "SMSG_RESET_FAILED_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x397*/ { "SMSG_REAL_GROUP_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x398*/ { "SMSG_LFG_DISABLED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x399*/ { "CMSG_ACTIVE_PVP_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x39A*/ { "CMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x39B*/ { "SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x39C*/ { "SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE_WRITE_FILE",STATUS_NEVER,&WorldSession::Handle_ServerSide }, - /*0x39D*/ { "SMSG_UPDATE_COMBO_POINTS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x39E*/ { "SMSG_VOICE_SESSION_ROSTER_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x39F*/ { "SMSG_VOICE_SESSION_LEAVE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3A0*/ { "SMSG_VOICE_SESSION_ADJUST_PRIORITY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3A1*/ { "CMSG_VOICE_SET_TALKER_MUTED_REQUEST", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3A2*/ { "SMSG_VOICE_SET_TALKER_MUTED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3A3*/ { "SMSG_INIT_EXTRA_AURA_INFO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3A4*/ { "SMSG_SET_EXTRA_AURA_INFO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3A5*/ { "SMSG_SET_EXTRA_AURA_INFO_NEED_UPDATE_OBSOLETE",STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3A6*/ { "SMSG_CLEAR_EXTRA_AURA_INFO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3A7*/ { "MSG_MOVE_START_DESCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, - /*0x3A8*/ { "CMSG_IGNORE_REQUIREMENTS_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3A9*/ { "SMSG_IGNORE_REQUIREMENTS_CHEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3AA*/ { "SMSG_SPELL_CHANCE_PROC_LOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3AB*/ { "CMSG_MOVE_SET_RUN_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3AC*/ { "SMSG_DISMOUNT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3AD*/ { "MSG_MOVE_UPDATE_CAN_FLY", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3AE*/ { "MSG_RAID_READY_CHECK_CONFIRM", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3AF*/ { "CMSG_VOICE_SESSION_ENABLE", STATUS_AUTHED, &WorldSession::HandleVoiceSessionEnableOpcode }, - /*0x3B0*/ { "SMSG_VOICE_SESSION_ENABLE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3B1*/ { "SMSG_VOICE_PARENTAL_CONTROLS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3B2*/ { "CMSG_GM_WHISPER", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3B3*/ { "SMSG_GM_MESSAGECHAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3B4*/ { "MSG_GM_GEARRATING", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3B5*/ { "CMSG_COMMENTATOR_ENABLE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3B6*/ { "SMSG_COMMENTATOR_STATE_CHANGED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3B7*/ { "CMSG_COMMENTATOR_GET_MAP_INFO", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3B8*/ { "SMSG_COMMENTATOR_MAP_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3B9*/ { "CMSG_COMMENTATOR_GET_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3BA*/ { "SMSG_COMMENTATOR_GET_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3BB*/ { "SMSG_COMMENTATOR_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3BC*/ { "CMSG_COMMENTATOR_ENTER_INSTANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3BD*/ { "CMSG_COMMENTATOR_EXIT_INSTANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3BE*/ { "CMSG_COMMENTATOR_INSTANCE_COMMAND", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3BF*/ { "SMSG_CLEAR_TARGET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3C0*/ { "CMSG_BOT_DETECTED", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3C1*/ { "SMSG_CROSSED_INEBRIATION_THRESHOLD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3C2*/ { "CMSG_CHEAT_PLAYER_LOGIN", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3C3*/ { "CMSG_CHEAT_PLAYER_LOOKUP", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3C4*/ { "SMSG_CHEAT_PLAYER_LOOKUP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3C5*/ { "SMSG_KICK_REASON", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3C6*/ { "MSG_RAID_READY_CHECK_FINISHED", STATUS_LOGGEDIN, &WorldSession::HandleRaidReadyCheckFinishedOpcode}, - /*0x3C7*/ { "CMSG_COMPLAIN", STATUS_LOGGEDIN, &WorldSession::HandleComplainOpcode }, - /*0x3C8*/ { "SMSG_COMPLAIN_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3C9*/ { "SMSG_FEATURE_SYSTEM_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3CA*/ { "CMSG_GM_SHOW_COMPLAINTS", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3CB*/ { "CMSG_GM_UNSQUELCH", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3CC*/ { "CMSG_CHANNEL_SILENCE_VOICE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3CD*/ { "CMSG_CHANNEL_SILENCE_ALL", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3CE*/ { "CMSG_CHANNEL_UNSILENCE_VOICE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3CF*/ { "CMSG_CHANNEL_UNSILENCE_ALL", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3D0*/ { "CMSG_TARGET_CAST", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3D1*/ { "CMSG_TARGET_SCRIPT_CAST", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3D2*/ { "CMSG_CHANNEL_DISPLAY_LIST", STATUS_LOGGEDIN, &WorldSession::HandleChannelDisplayListQuery }, - /*0x3D3*/ { "CMSG_SET_ACTIVE_VOICE_CHANNEL", STATUS_AUTHED, &WorldSession::HandleSetActiveVoiceChannel }, - /*0x3D4*/ { "CMSG_GET_CHANNEL_MEMBER_COUNT", STATUS_LOGGEDIN, &WorldSession::HandleGetChannelMemberCount }, - /*0x3D5*/ { "SMSG_CHANNEL_MEMBER_COUNT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3D6*/ { "CMSG_CHANNEL_VOICE_ON", STATUS_LOGGEDIN, &WorldSession::HandleChannelVoiceOnOpcode }, - /*0x3D7*/ { "CMSG_CHANNEL_VOICE_OFF", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3D8*/ { "CMSG_DEBUG_LIST_TARGETS", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3D9*/ { "SMSG_DEBUG_LIST_TARGETS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3DA*/ { "SMSG_AVAILABLE_VOICE_CHANNEL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3DB*/ { "CMSG_ADD_VOICE_IGNORE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3DC*/ { "CMSG_DEL_VOICE_IGNORE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3DD*/ { "CMSG_PARTY_SILENCE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3DE*/ { "CMSG_PARTY_UNSILENCE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3DF*/ { "MSG_NOTIFY_PARTY_SQUELCH", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3E0*/ { "SMSG_COMSAT_RECONNECT_TRY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3E1*/ { "SMSG_COMSAT_DISCONNECT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3E2*/ { "SMSG_COMSAT_CONNECT_FAIL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3E3*/ { "SMSG_VOICE_CHAT_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3E4*/ { "CMSG_REPORT_PVP_AFK", STATUS_LOGGEDIN, &WorldSession::HandleReportPvPAFK }, - /*0x3E5*/ { "SMSG_REPORT_PVP_AFK_RESULT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3E6*/ { "CMSG_GUILD_BANKER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankerActivate }, - /*0x3E7*/ { "CMSG_GUILD_BANK_QUERY_TAB", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankQueryTab }, - /*0x3E8*/ { "SMSG_GUILD_BANK_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3E9*/ { "CMSG_GUILD_BANK_SWAP_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankSwapItems }, - /*0x3EA*/ { "CMSG_GUILD_BANK_BUY_TAB", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankBuyTab }, - /*0x3EB*/ { "CMSG_GUILD_BANK_UPDATE_TAB", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankUpdateTab }, - /*0x3EC*/ { "CMSG_GUILD_BANK_DEPOSIT_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankDepositMoney }, - /*0x3ED*/ { "CMSG_GUILD_BANK_WITHDRAW_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankWithdrawMoney }, - /*0x3EE*/ { "MSG_GUILD_BANK_LOG_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankLogQuery }, - /*0x3EF*/ { "CMSG_SET_CHANNEL_WATCH", STATUS_LOGGEDIN, &WorldSession::HandleSetChannelWatch }, - /*0x3F0*/ { "SMSG_USERLIST_ADD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3F1*/ { "SMSG_USERLIST_REMOVE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3F2*/ { "SMSG_USERLIST_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3F3*/ { "CMSG_CLEAR_CHANNEL_WATCH", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3F4*/ { "SMSG_INSPECT_TALENT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3F5*/ { "SMSG_GOGOGO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3F6*/ { "SMSG_ECHO_PARTY_SQUELCH", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3F7*/ { "CMSG_SET_TITLE_SUFFIX", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3F8*/ { "CMSG_SPELLCLICK", STATUS_LOGGEDIN, &WorldSession::HandleSpellClick }, - /*0x3F9*/ { "SMSG_LOOT_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3FA*/ { "CMSG_GM_CHARACTER_RESTORE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3FB*/ { "CMSG_GM_CHARACTER_SAVE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x3FC*/ { "SMSG_VOICESESSION_FULL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x3FD*/ { "MSG_GUILD_PERMISSIONS", STATUS_LOGGEDIN, &WorldSession::HandleGuildPermissions }, - /*0x3FE*/ { "MSG_GUILD_BANK_MONEY_WITHDRAWN", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankMoneyWithdrawn }, - /*0x3FF*/ { "MSG_GUILD_EVENT_LOG_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleGuildEventLogQueryOpcode }, - /*0x400*/ { "CMSG_MAELSTROM_RENAME_GUILD", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x401*/ { "CMSG_GET_MIRRORIMAGE_DATA", STATUS_LOGGEDIN, &WorldSession::HandleMirrrorImageDataRequest }, - /*0x402*/ { "SMSG_MIRRORIMAGE_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x403*/ { "SMSG_FORCE_DISPLAY_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x404*/ { "SMSG_SPELL_CHANCE_RESIST_PUSHBACK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x405*/ { "CMSG_IGNORE_DIMINISHING_RETURNS_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x406*/ { "SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x407*/ { "CMSG_KEEP_ALIVE", STATUS_NEVER, &WorldSession::Handle_EarlyProccess }, - /*0x408*/ { "SMSG_RAID_READY_CHECK_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x409*/ { "CMSG_OPT_OUT_OF_LOOT", STATUS_AUTHED, &WorldSession::HandleOptOutOfLootOpcode }, - /*0x40A*/ { "MSG_QUERY_GUILD_BANK_TEXT", STATUS_LOGGEDIN, &WorldSession::HandleQueryGuildBankTabText }, - /*0x40B*/ { "CMSG_SET_GUILD_BANK_TEXT", STATUS_LOGGEDIN, &WorldSession::HandleSetGuildBankTabText }, - /*0x40C*/ { "CMSG_SET_GRANTABLE_LEVELS", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x40D*/ { "CMSG_GRANT_LEVEL", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x40E*/ { "CMSG_REFER_A_FRIEND", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x40F*/ { "CMSG_DECLINE_CHANNEL_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleChannelDeclineInvite }, - /*0x410*/ { "CMSG_DECLINE_CHANNEL_INVITE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x411*/ { "SMSG_GROUPACTION_THROTTLED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x412*/ { "SMSG_OVERRIDE_LIGHT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x413*/ { "SMSG_TOTEM_CREATED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x414*/ { "CMSG_TOTEM_DESTROYED", STATUS_LOGGEDIN, &WorldSession::HandleTotemDestroyed }, - /*0x415*/ { "CMSG_EXPIRE_RAID_INSTANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x416*/ { "CMSG_NO_SPELL_VARIANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x417*/ { "CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverStatusMultipleQuery}, - /*0x418*/ { "SMSG_QUESTGIVER_STATUS_MULTIPLE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x419*/ { "CMSG_SET_PLAYER_DECLINED_NAMES", STATUS_AUTHED, &WorldSession::HandleSetPlayerDeclinedNames }, - /*0x41A*/ { "SMSG_SET_PLAYER_DECLINED_NAMES_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x41B*/ { "CMSG_QUERY_SERVER_BUCK_DATA", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x41C*/ { "CMSG_CLEAR_SERVER_BUCK_DATA", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x41D*/ { "SMSG_SERVER_BUCK_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x41E*/ { "SMSG_SEND_UNLEARN_SPELLS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x41F*/ { "SMSG_PROPOSE_LEVEL_GRANT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x420*/ { "CMSG_ACCEPT_LEVEL_GRANT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x421*/ { "SMSG_REFER_A_FRIEND_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x422*/ { "SMSG_SPLINE_MOVE_SET_FLYING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x423*/ { "SMSG_SPLINE_MOVE_UNSET_FLYING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x424*/ { "SMSG_SUMMON_CANCEL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x425*/ { "CMSG_CHANGE_PERSONAL_ARENA_RATING", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x426*/ { "CMSG_ALTER_APPEARANCE", STATUS_LOGGEDIN, &WorldSession::HandleAlterAppearance }, - /*0x427*/ { "SMSG_ENABLE_BARBER_SHOP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x428*/ { "SMSG_BARBER_SHOP_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x429*/ { "CMSG_CALENDAR_GET_CALENDAR", STATUS_LOGGEDIN, &WorldSession::HandleCalendarGetCalendar }, - /*0x42A*/ { "CMSG_CALENDAR_GET_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarGetEvent }, - /*0x42B*/ { "CMSG_CALENDAR_GUILD_FILTER", STATUS_LOGGEDIN, &WorldSession::HandleCalendarGuildFilter }, - /*0x42C*/ { "CMSG_CALENDAR_ARENA_TEAM", STATUS_LOGGEDIN, &WorldSession::HandleCalendarArenaTeam }, - /*0x42D*/ { "CMSG_CALENDAR_ADD_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarAddEvent }, - /*0x42E*/ { "CMSG_CALENDAR_UPDATE_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarUpdateEvent }, - /*0x42F*/ { "CMSG_CALENDAR_REMOVE_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarRemoveEvent }, - /*0x430*/ { "CMSG_CALENDAR_COPY_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarCopyEvent }, - /*0x431*/ { "CMSG_CALENDAR_EVENT_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventInvite }, - /*0x432*/ { "CMSG_CALENDAR_EVENT_RSVP", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventRsvp }, - /*0x433*/ { "CMSG_CALENDAR_EVENT_REMOVE_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventRemoveInvite }, - /*0x434*/ { "CMSG_CALENDAR_EVENT_STATUS", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventStatus }, - /*0x435*/ { "CMSG_CALENDAR_EVENT_MODERATOR_STATUS", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventModeratorStatus}, - /*0x436*/ { "SMSG_CALENDAR_SEND_CALENDAR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x437*/ { "SMSG_CALENDAR_SEND_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x438*/ { "SMSG_CALENDAR_FILTER_GUILD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x439*/ { "SMSG_CALENDAR_ARENA_TEAM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x43A*/ { "SMSG_CALENDAR_EVENT_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x43B*/ { "SMSG_CALENDAR_EVENT_INVITE_REMOVED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x43C*/ { "SMSG_CALENDAR_EVENT_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x43D*/ { "SMSG_CALENDAR_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x43E*/ { "SMSG_CALENDAR_RAID_LOCKOUT_ADDED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x43F*/ { "SMSG_CALENDAR_RAID_LOCKOUT_REMOVED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x440*/ { "SMSG_CALENDAR_EVENT_INVITE_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x441*/ { "SMSG_CALENDAR_EVENT_INVITE_REMOVED_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x442*/ { "SMSG_CALENDAR_EVENT_INVITE_STATUS_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x443*/ { "SMSG_CALENDAR_EVENT_REMOVED_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x444*/ { "SMSG_CALENDAR_EVENT_UPDATED_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x445*/ { "SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x446*/ { "CMSG_CALENDAR_COMPLAIN", STATUS_LOGGEDIN, &WorldSession::HandleCalendarComplain }, - /*0x447*/ { "CMSG_CALENDAR_GET_NUM_PENDING", STATUS_LOGGEDIN, &WorldSession::HandleCalendarGetNumPending }, - /*0x448*/ { "SMSG_CALENDAR_SEND_NUM_PENDING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x449*/ { "CMSG_SAVE_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x44A*/ { "SMSG_NOTIFY_DANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x44B*/ { "CMSG_PLAY_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x44C*/ { "SMSG_PLAY_DANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x44D*/ { "CMSG_LOAD_DANCES", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x44E*/ { "CMSG_STOP_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x44F*/ { "SMSG_STOP_DANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x450*/ { "CMSG_SYNC_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x451*/ { "CMSG_DANCE_QUERY", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x452*/ { "SMSG_DANCE_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x453*/ { "SMSG_INVALIDATE_DANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x454*/ { "CMSG_DELETE_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x455*/ { "SMSG_LEARNED_DANCE_MOVES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x456*/ { "CMSG_LEARN_DANCE_MOVE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x457*/ { "CMSG_UNLEARN_DANCE_MOVE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x458*/ { "CMSG_SET_RUNE_COUNT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x459*/ { "CMSG_SET_RUNE_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x45A*/ { "MSG_MOVE_SET_PITCH_RATE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x45B*/ { "MSG_MOVE_SET_PITCH_RATE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x45C*/ { "SMSG_FORCE_PITCH_RATE_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x45D*/ { "CMSG_FORCE_PITCH_RATE_CHANGE_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x45E*/ { "SMSG_SPLINE_SET_PITCH_RATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x45F*/ { "SMSG_MOVE_ABANDON_TRANSPORT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x460*/ { "MSG_MOVE_ABANDON_TRANSPORT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x461*/ { "CMSG_MOVE_ABANDON_TRANSPORT_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x462*/ { "CMSG_UPDATE_MISSILE_TRAJECTORY", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x463*/ { "SMSG_UPDATE_ACCOUNT_DATA_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x464*/ { "SMSG_TRIGGER_MOVIE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x465*/ { "CMSG_COMPLETE_MOVIE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x466*/ { "CMSG_SET_GLYPH_SLOT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x467*/ { "CMSG_SET_GLYPH", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x468*/ { "SMSG_ACHIEVEMENT_EARNED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x469*/ { "SMSG_DYNAMIC_DROP_ROLL_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x46A*/ { "SMSG_CRITERIA_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x46B*/ { "CMSG_QUERY_INSPECT_ACHIEVEMENTS", STATUS_LOGGEDIN, &WorldSession::HandleQueryInspectAchievements }, - /*0x46C*/ { "SMSG_RESPOND_INSPECT_ACHIEVEMENTS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x46D*/ { "CMSG_DISMISS_CONTROLLED_VEHICLE", STATUS_LOGGEDIN, &WorldSession::HandleDismissControlledVehicle }, - /*0x46E*/ { "CMSG_COMPLETE_ACHIEVEMENT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x46F*/ { "SMSG_QUESTUPDATE_ADD_PVP_KILL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x470*/ { "CMSG_SET_CRITERIA_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x471*/ { "SMSG_GROUP_SWAP_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x472*/ { "CMSG_UNITANIMTIER_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x473*/ { "CMSG_CHAR_CUSTOMIZE", STATUS_AUTHED, &WorldSession::HandleCharCustomize }, - /*0x474*/ { "SMSG_CHAR_CUSTOMIZE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x475*/ { "SMSG_PET_RENAMEABLE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x476*/ { "CMSG_REQUEST_VEHICLE_EXIT", STATUS_LOGGEDIN, &WorldSession::HandleRequestVehicleExit }, - /*0x477*/ { "CMSG_REQUEST_VEHICLE_PREV_SEAT", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle}, - /*0x478*/ { "CMSG_REQUEST_VEHICLE_NEXT_SEAT", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle}, - /*0x479*/ { "CMSG_REQUEST_VEHICLE_SWITCH_SEAT", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle}, - /*0x47A*/ { "CMSG_PET_LEARN_TALENT", STATUS_LOGGEDIN, &WorldSession::HandlePetLearnTalent }, - /*0x47B*/ { "CMSG_PET_UNLEARN_TALENTS", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x47C*/ { "SMSG_SET_PHASE_SHIFT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x47D*/ { "SMSG_ALL_ACHIEVEMENT_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x47E*/ { "CMSG_FORCE_SAY_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x47F*/ { "SMSG_HEALTH_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x480*/ { "SMSG_POWER_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x481*/ { "CMSG_GAMEOBJ_REPORT_USE", STATUS_LOGGEDIN, &WorldSession::HandleGameobjectReportUse }, - /*0x482*/ { "SMSG_HIGHEST_THREAT_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x483*/ { "SMSG_THREAT_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x484*/ { "SMSG_THREAT_REMOVE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x485*/ { "SMSG_THREAT_CLEAR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x486*/ { "SMSG_CONVERT_RUNE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x487*/ { "SMSG_RESYNC_RUNES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x488*/ { "SMSG_ADD_RUNE_POWER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x489*/ { "CMSG_START_QUEST", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x48A*/ { "CMSG_REMOVE_GLYPH", STATUS_LOGGEDIN, &WorldSession::HandleRemoveGlyph }, - /*0x48B*/ { "CMSG_DUMP_OBJECTS", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x48C*/ { "SMSG_DUMP_OBJECTS_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x48D*/ { "CMSG_DISMISS_CRITTER", STATUS_LOGGEDIN, &WorldSession::HandleDismissCritter }, - /*0x48E*/ { "SMSG_NOTIFY_DEST_LOC_SPELL_CAST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x48F*/ { "CMSG_AUCTION_LIST_PENDING_SALES", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListPendingSales }, - /*0x490*/ { "SMSG_AUCTION_LIST_PENDING_SALES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x491*/ { "SMSG_MODIFY_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x492*/ { "SMSG_PET_UPDATE_COMBO_POINTS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x493*/ { "CMSG_ENABLETAXI", STATUS_LOGGEDIN, &WorldSession::HandleTaxiQueryAvailableNodes }, - /*0x494*/ { "SMSG_PRE_RESURRECT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x495*/ { "SMSG_AURA_UPDATE_ALL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x496*/ { "SMSG_AURA_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x497*/ { "CMSG_FLOOD_GRACE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x498*/ { "SMSG_SERVER_FIRST_ACHIEVEMENT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x499*/ { "SMSG_PET_LEARNED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x49A*/ { "SMSG_PET_REMOVED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x49B*/ { "CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle}, - /*0x49C*/ { "CMSG_HEARTH_AND_RESURRECT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x49D*/ { "SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x49E*/ { "SMSG_CRITERIA_DELETED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x49F*/ { "SMSG_ACHIEVEMENT_DELETED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4A0*/ { "CMSG_SERVER_INFO_QUERY", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4A1*/ { "SMSG_SERVER_INFO_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4A2*/ { "CMSG_CHECK_LOGIN_CRITERIA", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4A3*/ { "SMSG_SERVER_BUCK_DATA_START", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4A4*/ { "CMSG_QUERY_VEHICLE_STATUS", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4A5*/ { "UMSG_UNKNOWN_1189", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4A6*/ { "SMSG_BATTLEGROUND_INFO_THROTTLED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4A7*/ { "SMSG_PLAYER_VEHICLE_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4A8*/ { "CMSG_PLAYER_VEHICLE_ENTER", STATUS_LOGGEDIN, &WorldSession::HandleEnterPlayerVehicle }, - /*0x4A9*/ { "CMSG_EJECT_PASSENGER", STATUS_LOGGEDIN, &WorldSession::HandleEjectPasenger }, - /*0x4AA*/ { "SMSG_PET_GUIDS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4AB*/ { "SMSG_CLIENTCACHE_VERSION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4AC*/ { "UMSG_UNKNOWN_1196", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4AD*/ { "UMSG_UNKNOWN_1197", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4AE*/ { "UMSG_UNKNOWN_1198", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4AF*/ { "UMSG_UNKNOWN_1199", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4B0*/ { "UMSG_UNKNOWN_1200", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4B1*/ { "UMSG_UNKNOWN_1201", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4B2*/ { "SMSG_ITEM_REFUND_INFO_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4B3*/ { "CMSG_ITEM_REFUND_INFO", STATUS_LOGGEDIN, &WorldSession::HandleItemRefundInfoRequest }, - /*0x4B4*/ { "CMSG_ITEM_REFUND", STATUS_LOGGEDIN, &WorldSession::HandleItemRefund }, - /*0x4B5*/ { "SMSG_ITEM_REFUND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4B6*/ { "CMSG_CORPSE_MAP_POSITION_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleCorpseMapPositionQuery }, - /*0x4B7*/ { "SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4B8*/ { "CMSG_LFG_SET_ROLES_2", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, - /*0x4B9*/ { "UMSG_UNKNOWN_1209", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4BA*/ { "CMSG_CALENDAR_CONTEXT_EVENT_SIGNUP", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4BB*/ { "SMSG_CALENDAR_ACTION_PENDING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4BC*/ { "SMSG_EQUIPMENT_SET_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4BD*/ { "CMSG_EQUIPMENT_SET_SAVE", STATUS_LOGGEDIN, &WorldSession::HandleEquipmentSetSave }, - /*0x4BE*/ { "CMSG_UPDATE_PROJECTILE_POSITION", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4BF*/ { "SMSG_SET_PROJECTILE_POSITION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4C0*/ { "SMSG_TALENTS_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4C1*/ { "CMSG_LEARN_PREVIEW_TALENTS", STATUS_LOGGEDIN, &WorldSession::HandleLearnPreviewTalents }, - /*0x4C2*/ { "CMSG_LEARN_PREVIEW_TALENTS_PET", STATUS_LOGGEDIN, &WorldSession::HandleLearnPreviewTalentsPet }, - /*0x4C3*/ { "UMSG_UNKNOWN_1219", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4C4*/ { "UMSG_UNKNOWN_1220", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4C5*/ { "UMSG_UNKNOWN_1221", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4C6*/ { "UMSG_UNKNOWN_1222", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4C7*/ { "SMSG_ARENA_OPPONENT_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4C8*/ { "SMSG_ARENA_TEAM_CHANGE_FAILED_QUEUED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4C9*/ { "UMSG_UNKNOWN_1225", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4CA*/ { "UMSG_UNKNOWN_1226", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4CB*/ { "UMSG_UNKNOWN_1227", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4CC*/ { "UMSG_UNKNOWN_1228", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4CD*/ { "SMSG_MULTIPLE_PACKETS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4CE*/ { "SMSG_UNKNOWN_1230", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4CF*/ { "CMSG_UNKNOWN_1231_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4D0*/ { "SMSG_UNKNOWN_1232", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4D1*/ { "CMSG_UNKNOWN_1233_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4D2*/ { "SMSG_UNKNOWN_1234", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4D3*/ { "SMSG_UNKNOWN_1235", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4D4*/ { "SMSG_UNKNOWN_1236", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4D5*/ { "CMSG_EQUIPMENT_SET_USE", STATUS_LOGGEDIN, &WorldSession::HandleEquipmentSetUse }, - /*0x4D6*/ { "SMSG_EQUIPMENT_SET_USE_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4D7*/ { "UMSG_UNKNOWN_1239", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4D8*/ { "SMSG_UNKNOWN_1240", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4D9*/ { "CMSG_CHAR_FACTION_CHANGE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4DA*/ { "SMSG_CHAR_FACTION_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4DB*/ { "UMSG_UNKNOWN_1243", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4DC*/ { "UMSG_UNKNOWN_1244", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4DD*/ { "UMSG_UNKNOWN_1245", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4DE*/ { "SMSG_BATTLEFIELD_MGR_ENTRY_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4DF*/ { "CMSG_BATTLEFIELD_MGR_ENTRY_INVITE_RESPONS", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4E0*/ { "SMSG_BATTLEFIELD_MGR_ENTERED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4E1*/ { "SMSG_BATTLEFIELD_MGR_QUEUE_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4E2*/ { "CMSG_BATTLEFIELD_MGR_QUEUE_INVITE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4E3*/ { "CMSG_BATTLEFIELD_MGR_QUEUE_REQUEST", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4E4*/ { "SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4E5*/ { "SMSG_BATTLEFIELD_MGR_EJECT_PENDING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4E6*/ { "SMSG_BATTLEFIELD_MGR_EJECTED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4E7*/ { "CMSG_BATTLEFIELD_MGR_EXIT_REQUEST", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4E8*/ { "SMSG_BATTLEFIELD_MGR_STATE_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4E9*/ { "UMSG_UNKNOWN_1257", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4EA*/ { "UMSG_UNKNOWN_1258", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4EB*/ { "MSG_SET_RAID_DIFFICULTY", STATUS_LOGGEDIN, &WorldSession::HandleSetRaidDifficultyOpcode }, - /*0x4EC*/ { "UMSG_UNKNOWN_1260", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4ED*/ { "SMSG_TOGGLE_XP_GAIN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4EE*/ { "SMSG_GMRESPONSE_DB_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4EF*/ { "SMSG_GMRESPONSE_RECEIVED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4F0*/ { "CMSG_GMRESPONSE_RESOLVE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4F1*/ { "SMSG_GMRESPONSE_STATUS_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4F2*/ { "UMSG_UNKNOWN_1266", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4F3*/ { "UMSG_UNKNOWN_1267", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4F4*/ { "UMSG_UNKNOWN_1268", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4F5*/ { "UMSG_UNKNOWN_1269", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4F6*/ { "CMSG_WORLD_STATE_UI_TIMER_UPDATE", STATUS_LOGGEDIN, &WorldSession::HandleWorldStateUITimerUpdate }, - /*0x4F7*/ { "SMSG_WORLD_STATE_UI_TIMER_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4F8*/ { "CMSG_CHAR_RACE_CHANGE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4F9*/ { "UMSG_UNKNOWN_1273", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4FA*/ { "SMSG_TALENTS_INVOLUNTARILY_RESET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4FB*/ { "UMSG_UNKNOWN_1275", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4FC*/ { "SMSG_UNKNOWN_1276", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4FD*/ { "SMSG_LOOT_SLOT_CHANGED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4FE*/ { "UMSG_UNKNOWN_1278", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4FF*/ { "CMSG_READY_FOR_ACCOUNT_DATA_TIMES", STATUS_AUTHED, &WorldSession::HandleReadyForAccountDataTimes }, - /*0x500*/ { "CMSG_QUERY_QUESTS_COMPLETED", STATUS_LOGGEDIN, &WorldSession::HandleQueryQuestsCompleted }, - /*0x501*/ { "SMSG_QUERY_QUESTS_COMPLETED_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x502*/ { "CMSG_GM_REPORT_LAG", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x503*/ { "UMSG_UNKNOWN_1283", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x504*/ { "UMSG_UNKNOWN_1284", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x505*/ { "UMSG_UNKNOWN_1285", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x506*/ { "SMSG_CORPSE_NOT_IN_INSTANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x507*/ { "UMSG_UNKNOWN_1287", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x508*/ { "CMSG_SET_ALLOW_LOW_LEVEL_RAID1", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x509*/ { "CMSG_SET_ALLOW_LOW_LEVEL_RAID2", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x50A*/ { "SMSG_CAMERA_SHAKE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x50B*/ { "SMSG_UPDATE_ITEM_ENCHANTMENTS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x50C*/ { "UMSG_UNKNOWN_1292", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x50D*/ { "SMSG_REDIRECT_CLIENT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x50E*/ { "CMSG_REDIRECTION_FAILED", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x50F*/ { "SMSG_UNKNOWN_1295", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x510*/ { "CMSG_UNKNOWN_1296", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x511*/ { "SMSG_FORCE_SEND_QUEUED_PACKETS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x512*/ { "CMSG_REDIRECTION_AUTH_PROOF", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x513*/ { "UMSG_UNKNOWN_1299", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x514*/ { "SMSG_COMBAT_LOG_MULTIPLE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x515*/ { "SMSG_LFG_OPEN_FROM_GOSSIP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x516*/ { "SMSG_UNKNOWN_1302", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x517*/ { "CMSG_UNKNOWN_1303", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x518*/ { "SMSG_UNKNOWN_1304", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x519*/ { "UMSG_UNKNOWN_1305", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x51A*/ { "UMSG_UNKNOWN_1306", STATUS_NEVER, &WorldSession::Handle_NULL }, -}; diff --git a/src/server/game/Opcodes/Opcodes.h b/src/server/game/Opcodes/Opcodes.h deleted file mode 100644 index 4ae6931c3f5..00000000000 --- a/src/server/game/Opcodes/Opcodes.h +++ /dev/null @@ -1,1378 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/// \addtogroup u2w -/// @{ -/// \file - -#ifndef _OPCODES_H -#define _OPCODES_H - -#include "Common.h" - -// Note: this include need for be sure have full definition of class WorldSession -// if this class definition not complite then VS for x64 release use different size for -// struct OpcodeHandler in this header and Opcode.cpp and get totally wrong data from -// table opcodeTable in source when Opcode.h included but WorldSession.h not included -#include "WorldSession.h" - -/// List of Opcodes -enum Opcodes -{ - MSG_NULL_ACTION = 0x000, - CMSG_BOOTME = 0x001, - CMSG_DBLOOKUP = 0x002, - SMSG_DBLOOKUP = 0x003, - CMSG_QUERY_OBJECT_POSITION = 0x004, - SMSG_QUERY_OBJECT_POSITION = 0x005, - CMSG_QUERY_OBJECT_ROTATION = 0x006, - SMSG_QUERY_OBJECT_ROTATION = 0x007, - CMSG_WORLD_TELEPORT = 0x008, - CMSG_TELEPORT_TO_UNIT = 0x009, - CMSG_ZONE_MAP = 0x00A, - SMSG_ZONE_MAP = 0x00B, - CMSG_DEBUG_CHANGECELLZONE = 0x00C, - CMSG_MOVE_CHARACTER_CHEAT = 0x00D, - SMSG_MOVE_CHARACTER_CHEAT = 0x00E, - CMSG_RECHARGE = 0x00F, - CMSG_LEARN_SPELL = 0x010, - CMSG_CREATEMONSTER = 0x011, - CMSG_DESTROYMONSTER = 0x012, - CMSG_CREATEITEM = 0x013, - CMSG_CREATEGAMEOBJECT = 0x014, - SMSG_CHECK_FOR_BOTS = 0x015, - CMSG_MAKEMONSTERATTACKGUID = 0x016, - CMSG_BOT_DETECTED2 = 0x017, - CMSG_FORCEACTION = 0x018, - CMSG_FORCEACTIONONOTHER = 0x019, - CMSG_FORCEACTIONSHOW = 0x01A, - SMSG_FORCEACTIONSHOW = 0x01B, - CMSG_PETGODMODE = 0x01C, - SMSG_PETGODMODE = 0x01D, - SMSG_REFER_A_FRIEND_EXPIRED = 0x01E, - CMSG_WEATHER_SPEED_CHEAT = 0x01F, - CMSG_UNDRESSPLAYER = 0x020, - CMSG_BEASTMASTER = 0x021, - CMSG_GODMODE = 0x022, - SMSG_GODMODE = 0x023, - CMSG_CHEAT_SETMONEY = 0x024, - CMSG_LEVEL_CHEAT = 0x025, - CMSG_PET_LEVEL_CHEAT = 0x026, - CMSG_SET_WORLDSTATE = 0x027, - CMSG_COOLDOWN_CHEAT = 0x028, - CMSG_USE_SKILL_CHEAT = 0x029, - CMSG_FLAG_QUEST = 0x02A, - CMSG_FLAG_QUEST_FINISH = 0x02B, - CMSG_CLEAR_QUEST = 0x02C, - CMSG_SEND_EVENT = 0x02D, - CMSG_DEBUG_AISTATE = 0x02E, - SMSG_DEBUG_AISTATE = 0x02F, - CMSG_DISABLE_PVP_CHEAT = 0x030, - CMSG_ADVANCE_SPAWN_TIME = 0x031, - SMSG_DESTRUCTIBLE_BUILDING_DAMAGE = 0x032, - CMSG_AUTH_SRP6_BEGIN = 0x033, - CMSG_AUTH_SRP6_PROOF = 0x034, - CMSG_AUTH_SRP6_RECODE = 0x035, - CMSG_CHAR_CREATE = 0x036, - CMSG_CHAR_ENUM = 0x037, - CMSG_CHAR_DELETE = 0x038, - SMSG_AUTH_SRP6_RESPONSE = 0x039, - SMSG_CHAR_CREATE = 0x03A, - SMSG_CHAR_ENUM = 0x03B, - SMSG_CHAR_DELETE = 0x03C, - CMSG_PLAYER_LOGIN = 0x03D, - SMSG_NEW_WORLD = 0x03E, - SMSG_TRANSFER_PENDING = 0x03F, - SMSG_TRANSFER_ABORTED = 0x040, - SMSG_CHARACTER_LOGIN_FAILED = 0x041, - SMSG_LOGIN_SETTIMESPEED = 0x042, - SMSG_GAMETIME_UPDATE = 0x043, - CMSG_GAMETIME_SET = 0x044, - SMSG_GAMETIME_SET = 0x045, - CMSG_GAMESPEED_SET = 0x046, - SMSG_GAMESPEED_SET = 0x047, - CMSG_SERVERTIME = 0x048, - SMSG_SERVERTIME = 0x049, - CMSG_PLAYER_LOGOUT = 0x04A, - CMSG_LOGOUT_REQUEST = 0x04B, - SMSG_LOGOUT_RESPONSE = 0x04C, - SMSG_LOGOUT_COMPLETE = 0x04D, - CMSG_LOGOUT_CANCEL = 0x04E, - SMSG_LOGOUT_CANCEL_ACK = 0x04F, - CMSG_NAME_QUERY = 0x050, - SMSG_NAME_QUERY_RESPONSE = 0x051, - CMSG_PET_NAME_QUERY = 0x052, - SMSG_PET_NAME_QUERY_RESPONSE = 0x053, - CMSG_GUILD_QUERY = 0x054, - SMSG_GUILD_QUERY_RESPONSE = 0x055, - CMSG_ITEM_QUERY_SINGLE = 0x056, - CMSG_ITEM_QUERY_MULTIPLE = 0x057, - SMSG_ITEM_QUERY_SINGLE_RESPONSE = 0x058, - SMSG_ITEM_QUERY_MULTIPLE_RESPONSE = 0x059, - CMSG_PAGE_TEXT_QUERY = 0x05A, - SMSG_PAGE_TEXT_QUERY_RESPONSE = 0x05B, - CMSG_QUEST_QUERY = 0x05C, - SMSG_QUEST_QUERY_RESPONSE = 0x05D, - CMSG_GAMEOBJECT_QUERY = 0x05E, - SMSG_GAMEOBJECT_QUERY_RESPONSE = 0x05F, - CMSG_CREATURE_QUERY = 0x060, - SMSG_CREATURE_QUERY_RESPONSE = 0x061, - CMSG_WHO = 0x062, - SMSG_WHO = 0x063, - CMSG_WHOIS = 0x064, - SMSG_WHOIS = 0x065, - CMSG_CONTACT_LIST = 0x066, - SMSG_CONTACT_LIST = 0x067, - SMSG_FRIEND_STATUS = 0x068, - CMSG_ADD_FRIEND = 0x069, - CMSG_DEL_FRIEND = 0x06A, - CMSG_SET_CONTACT_NOTES = 0x06B, - CMSG_ADD_IGNORE = 0x06C, - CMSG_DEL_IGNORE = 0x06D, - CMSG_GROUP_INVITE = 0x06E, - SMSG_GROUP_INVITE = 0x06F, - CMSG_GROUP_CANCEL = 0x070, - SMSG_GROUP_CANCEL = 0x071, - CMSG_GROUP_ACCEPT = 0x072, - CMSG_GROUP_DECLINE = 0x073, - SMSG_GROUP_DECLINE = 0x074, - CMSG_GROUP_UNINVITE = 0x075, - CMSG_GROUP_UNINVITE_GUID = 0x076, - SMSG_GROUP_UNINVITE = 0x077, - CMSG_GROUP_SET_LEADER = 0x078, - SMSG_GROUP_SET_LEADER = 0x079, - CMSG_LOOT_METHOD = 0x07A, - CMSG_GROUP_DISBAND = 0x07B, - SMSG_GROUP_DESTROYED = 0x07C, - SMSG_GROUP_LIST = 0x07D, - SMSG_PARTY_MEMBER_STATS = 0x07E, - SMSG_PARTY_COMMAND_RESULT = 0x07F, - UMSG_UPDATE_GROUP_MEMBERS = 0x080, - CMSG_GUILD_CREATE = 0x081, - CMSG_GUILD_INVITE = 0x082, - SMSG_GUILD_INVITE = 0x083, - CMSG_GUILD_ACCEPT = 0x084, - CMSG_GUILD_DECLINE = 0x085, - SMSG_GUILD_DECLINE = 0x086, - CMSG_GUILD_INFO = 0x087, - SMSG_GUILD_INFO = 0x088, - CMSG_GUILD_ROSTER = 0x089, - SMSG_GUILD_ROSTER = 0x08A, - CMSG_GUILD_PROMOTE = 0x08B, - CMSG_GUILD_DEMOTE = 0x08C, - CMSG_GUILD_LEAVE = 0x08D, - CMSG_GUILD_REMOVE = 0x08E, - CMSG_GUILD_DISBAND = 0x08F, - CMSG_GUILD_LEADER = 0x090, - CMSG_GUILD_MOTD = 0x091, - SMSG_GUILD_EVENT = 0x092, - SMSG_GUILD_COMMAND_RESULT = 0x093, - UMSG_UPDATE_GUILD = 0x094, - CMSG_MESSAGECHAT = 0x095, - SMSG_MESSAGECHAT = 0x096, - CMSG_JOIN_CHANNEL = 0x097, - CMSG_LEAVE_CHANNEL = 0x098, - SMSG_CHANNEL_NOTIFY = 0x099, - CMSG_CHANNEL_LIST = 0x09A, - SMSG_CHANNEL_LIST = 0x09B, - CMSG_CHANNEL_PASSWORD = 0x09C, - CMSG_CHANNEL_SET_OWNER = 0x09D, - CMSG_CHANNEL_OWNER = 0x09E, - CMSG_CHANNEL_MODERATOR = 0x09F, - CMSG_CHANNEL_UNMODERATOR = 0x0A0, - CMSG_CHANNEL_MUTE = 0x0A1, - CMSG_CHANNEL_UNMUTE = 0x0A2, - CMSG_CHANNEL_INVITE = 0x0A3, - CMSG_CHANNEL_KICK = 0x0A4, - CMSG_CHANNEL_BAN = 0x0A5, - CMSG_CHANNEL_UNBAN = 0x0A6, - CMSG_CHANNEL_ANNOUNCEMENTS = 0x0A7, - CMSG_CHANNEL_MODERATE = 0x0A8, - SMSG_UPDATE_OBJECT = 0x0A9, - SMSG_DESTROY_OBJECT = 0x0AA, - CMSG_USE_ITEM = 0x0AB, - CMSG_OPEN_ITEM = 0x0AC, - CMSG_READ_ITEM = 0x0AD, - SMSG_READ_ITEM_OK = 0x0AE, - SMSG_READ_ITEM_FAILED = 0x0AF, - SMSG_ITEM_COOLDOWN = 0x0B0, - CMSG_GAMEOBJ_USE = 0x0B1, - CMSG_DESTROY_ITEMS = 0x0B2, - SMSG_GAMEOBJECT_CUSTOM_ANIM = 0x0B3, - CMSG_AREATRIGGER = 0x0B4, - MSG_MOVE_START_FORWARD = 0x0B5, - MSG_MOVE_START_BACKWARD = 0x0B6, - MSG_MOVE_STOP = 0x0B7, - MSG_MOVE_START_STRAFE_LEFT = 0x0B8, - MSG_MOVE_START_STRAFE_RIGHT = 0x0B9, - MSG_MOVE_STOP_STRAFE = 0x0BA, - MSG_MOVE_JUMP = 0x0BB, - MSG_MOVE_START_TURN_LEFT = 0x0BC, - MSG_MOVE_START_TURN_RIGHT = 0x0BD, - MSG_MOVE_STOP_TURN = 0x0BE, - MSG_MOVE_START_PITCH_UP = 0x0BF, - MSG_MOVE_START_PITCH_DOWN = 0x0C0, - MSG_MOVE_STOP_PITCH = 0x0C1, - MSG_MOVE_SET_RUN_MODE = 0x0C2, - MSG_MOVE_SET_WALK_MODE = 0x0C3, - MSG_MOVE_TOGGLE_LOGGING = 0x0C4, - MSG_MOVE_TELEPORT = 0x0C5, - MSG_MOVE_TELEPORT_CHEAT = 0x0C6, - MSG_MOVE_TELEPORT_ACK = 0x0C7, - MSG_MOVE_TOGGLE_FALL_LOGGING = 0x0C8, - MSG_MOVE_FALL_LAND = 0x0C9, - MSG_MOVE_START_SWIM = 0x0CA, - MSG_MOVE_STOP_SWIM = 0x0CB, - MSG_MOVE_SET_RUN_SPEED_CHEAT = 0x0CC, - MSG_MOVE_SET_RUN_SPEED = 0x0CD, - MSG_MOVE_SET_RUN_BACK_SPEED_CHEAT = 0x0CE, - MSG_MOVE_SET_RUN_BACK_SPEED = 0x0CF, - MSG_MOVE_SET_WALK_SPEED_CHEAT = 0x0D0, - MSG_MOVE_SET_WALK_SPEED = 0x0D1, - MSG_MOVE_SET_SWIM_SPEED_CHEAT = 0x0D2, - MSG_MOVE_SET_SWIM_SPEED = 0x0D3, - MSG_MOVE_SET_SWIM_BACK_SPEED_CHEAT = 0x0D4, - MSG_MOVE_SET_SWIM_BACK_SPEED = 0x0D5, - MSG_MOVE_SET_ALL_SPEED_CHEAT = 0x0D6, - MSG_MOVE_SET_TURN_RATE_CHEAT = 0x0D7, - MSG_MOVE_SET_TURN_RATE = 0x0D8, - MSG_MOVE_TOGGLE_COLLISION_CHEAT = 0x0D9, - MSG_MOVE_SET_FACING = 0x0DA, - MSG_MOVE_SET_PITCH = 0x0DB, - MSG_MOVE_WORLDPORT_ACK = 0x0DC, - SMSG_MONSTER_MOVE = 0x0DD, - SMSG_MOVE_WATER_WALK = 0x0DE, - SMSG_MOVE_LAND_WALK = 0x0DF, - MSG_MOVE_SET_RAW_POSITION_ACK = 0x0E0, - CMSG_MOVE_SET_RAW_POSITION = 0x0E1, - SMSG_FORCE_RUN_SPEED_CHANGE = 0x0E2, - CMSG_FORCE_RUN_SPEED_CHANGE_ACK = 0x0E3, - SMSG_FORCE_RUN_BACK_SPEED_CHANGE = 0x0E4, - CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK = 0x0E5, - SMSG_FORCE_SWIM_SPEED_CHANGE = 0x0E6, - CMSG_FORCE_SWIM_SPEED_CHANGE_ACK = 0x0E7, - SMSG_FORCE_MOVE_ROOT = 0x0E8, - CMSG_FORCE_MOVE_ROOT_ACK = 0x0E9, - SMSG_FORCE_MOVE_UNROOT = 0x0EA, - CMSG_FORCE_MOVE_UNROOT_ACK = 0x0EB, - MSG_MOVE_ROOT = 0x0EC, - MSG_MOVE_UNROOT = 0x0ED, - MSG_MOVE_HEARTBEAT = 0x0EE, - SMSG_MOVE_KNOCK_BACK = 0x0EF, - CMSG_MOVE_KNOCK_BACK_ACK = 0x0F0, - MSG_MOVE_KNOCK_BACK = 0x0F1, - SMSG_MOVE_FEATHER_FALL = 0x0F2, - SMSG_MOVE_NORMAL_FALL = 0x0F3, - SMSG_MOVE_SET_HOVER = 0x0F4, - SMSG_MOVE_UNSET_HOVER = 0x0F5, - CMSG_MOVE_HOVER_ACK = 0x0F6, - MSG_MOVE_HOVER = 0x0F7, - CMSG_TRIGGER_CINEMATIC_CHEAT = 0x0F8, - CMSG_OPENING_CINEMATIC = 0x0F9, - SMSG_TRIGGER_CINEMATIC = 0x0FA, - CMSG_NEXT_CINEMATIC_CAMERA = 0x0FB, - CMSG_COMPLETE_CINEMATIC = 0x0FC, - SMSG_TUTORIAL_FLAGS = 0x0FD, - CMSG_TUTORIAL_FLAG = 0x0FE, - CMSG_TUTORIAL_CLEAR = 0x0FF, - CMSG_TUTORIAL_RESET = 0x100, - CMSG_STANDSTATECHANGE = 0x101, - CMSG_EMOTE = 0x102, - SMSG_EMOTE = 0x103, - CMSG_TEXT_EMOTE = 0x104, - SMSG_TEXT_EMOTE = 0x105, - CMSG_AUTOEQUIP_GROUND_ITEM = 0x106, - CMSG_AUTOSTORE_GROUND_ITEM = 0x107, - CMSG_AUTOSTORE_LOOT_ITEM = 0x108, - CMSG_STORE_LOOT_IN_SLOT = 0x109, - CMSG_AUTOEQUIP_ITEM = 0x10A, - CMSG_AUTOSTORE_BAG_ITEM = 0x10B, - CMSG_SWAP_ITEM = 0x10C, - CMSG_SWAP_INV_ITEM = 0x10D, - CMSG_SPLIT_ITEM = 0x10E, - CMSG_AUTOEQUIP_ITEM_SLOT = 0x10F, - OBSOLETE_DROP_ITEM = 0x110, - CMSG_DESTROYITEM = 0x111, - SMSG_INVENTORY_CHANGE_FAILURE = 0x112, - SMSG_OPEN_CONTAINER = 0x113, - CMSG_INSPECT = 0x114, - SMSG_INSPECT = 0x115, - CMSG_INITIATE_TRADE = 0x116, - CMSG_BEGIN_TRADE = 0x117, - CMSG_BUSY_TRADE = 0x118, - CMSG_IGNORE_TRADE = 0x119, - CMSG_ACCEPT_TRADE = 0x11A, - CMSG_UNACCEPT_TRADE = 0x11B, - CMSG_CANCEL_TRADE = 0x11C, - CMSG_SET_TRADE_ITEM = 0x11D, - CMSG_CLEAR_TRADE_ITEM = 0x11E, - CMSG_SET_TRADE_GOLD = 0x11F, - SMSG_TRADE_STATUS = 0x120, - SMSG_TRADE_STATUS_EXTENDED = 0x121, - SMSG_INITIALIZE_FACTIONS = 0x122, - SMSG_SET_FACTION_VISIBLE = 0x123, - SMSG_SET_FACTION_STANDING = 0x124, - CMSG_SET_FACTION_ATWAR = 0x125, - CMSG_SET_FACTION_CHEAT = 0x126, - SMSG_SET_PROFICIENCY = 0x127, - CMSG_SET_ACTION_BUTTON = 0x128, - SMSG_ACTION_BUTTONS = 0x129, - SMSG_INITIAL_SPELLS = 0x12A, - SMSG_LEARNED_SPELL = 0x12B, - SMSG_SUPERCEDED_SPELL = 0x12C, - CMSG_NEW_SPELL_SLOT = 0x12D, - CMSG_CAST_SPELL = 0x12E, - CMSG_CANCEL_CAST = 0x12F, - SMSG_CAST_FAILED = 0x130, - SMSG_SPELL_START = 0x131, - SMSG_SPELL_GO = 0x132, - SMSG_SPELL_FAILURE = 0x133, - SMSG_SPELL_COOLDOWN = 0x134, - SMSG_COOLDOWN_EVENT = 0x135, - CMSG_CANCEL_AURA = 0x136, - SMSG_EQUIPMENT_SET_SAVED = 0x137, - SMSG_PET_CAST_FAILED = 0x138, - MSG_CHANNEL_START = 0x139, - MSG_CHANNEL_UPDATE = 0x13A, - CMSG_CANCEL_CHANNELLING = 0x13B, - SMSG_AI_REACTION = 0x13C, - CMSG_SET_SELECTION = 0x13D, - CMSG_EQUIPMENT_SET_DELETE = 0x13E, - CMSG_INSTANCE_LOCK_WARNING_RESPONSE = 0x13F, - CMSG_UNUSED2 = 0x140, - CMSG_ATTACKSWING = 0x141, - CMSG_ATTACKSTOP = 0x142, - SMSG_ATTACKSTART = 0x143, - SMSG_ATTACKSTOP = 0x144, - SMSG_ATTACKSWING_NOTINRANGE = 0x145, - SMSG_ATTACKSWING_BADFACING = 0x146, - SMSG_INSTANCE_LOCK_WARNING_QUERY = 0x147, - SMSG_ATTACKSWING_DEADTARGET = 0x148, - SMSG_ATTACKSWING_CANT_ATTACK = 0x149, - SMSG_ATTACKERSTATEUPDATE = 0x14A, - SMSG_BATTLEFIELD_PORT_DENIED = 0x14B, - SMSG_DAMAGE_DONE_OBSOLETE = 0x14C, - SMSG_UNIT_SPELLCAST_START = 0x14D, - SMSG_CANCEL_COMBAT = 0x14E, - SMSG_SPELLBREAKLOG = 0x14F, - SMSG_SPELLHEALLOG = 0x150, - SMSG_SPELLENERGIZELOG = 0x151, - SMSG_BREAK_TARGET = 0x152, - CMSG_SAVE_PLAYER = 0x153, - CMSG_SETDEATHBINDPOINT = 0x154, - SMSG_BINDPOINTUPDATE = 0x155, - CMSG_GETDEATHBINDZONE = 0x156, - SMSG_BINDZONEREPLY = 0x157, - SMSG_PLAYERBOUND = 0x158, - SMSG_CLIENT_CONTROL_UPDATE = 0x159, - CMSG_REPOP_REQUEST = 0x15A, - SMSG_RESURRECT_REQUEST = 0x15B, - CMSG_RESURRECT_RESPONSE = 0x15C, - CMSG_LOOT = 0x15D, - CMSG_LOOT_MONEY = 0x15E, - CMSG_LOOT_RELEASE = 0x15F, - SMSG_LOOT_RESPONSE = 0x160, - SMSG_LOOT_RELEASE_RESPONSE = 0x161, - SMSG_LOOT_REMOVED = 0x162, - SMSG_LOOT_MONEY_NOTIFY = 0x163, - SMSG_LOOT_ITEM_NOTIFY = 0x164, - SMSG_LOOT_CLEAR_MONEY = 0x165, - SMSG_ITEM_PUSH_RESULT = 0x166, - SMSG_DUEL_REQUESTED = 0x167, - SMSG_DUEL_OUTOFBOUNDS = 0x168, - SMSG_DUEL_INBOUNDS = 0x169, - SMSG_DUEL_COMPLETE = 0x16A, - SMSG_DUEL_WINNER = 0x16B, - CMSG_DUEL_ACCEPTED = 0x16C, - CMSG_DUEL_CANCELLED = 0x16D, - SMSG_MOUNTRESULT = 0x16E, - SMSG_DISMOUNTRESULT = 0x16F, - SMSG_PUREMOUNT_CANCELLED_OBSOLETE = 0x170, // ERR_REMOVE_FROM_PVP_QUEUE_* events - CMSG_MOUNTSPECIAL_ANIM = 0x171, - SMSG_MOUNTSPECIAL_ANIM = 0x172, - SMSG_PET_TAME_FAILURE = 0x173, - CMSG_PET_SET_ACTION = 0x174, - CMSG_PET_ACTION = 0x175, - CMSG_PET_ABANDON = 0x176, - CMSG_PET_RENAME = 0x177, - SMSG_PET_NAME_INVALID = 0x178, - SMSG_PET_SPELLS = 0x179, - SMSG_PET_MODE = 0x17A, - CMSG_GOSSIP_HELLO = 0x17B, - CMSG_GOSSIP_SELECT_OPTION = 0x17C, - SMSG_GOSSIP_MESSAGE = 0x17D, - SMSG_GOSSIP_COMPLETE = 0x17E, - CMSG_NPC_TEXT_QUERY = 0x17F, - SMSG_NPC_TEXT_UPDATE = 0x180, - SMSG_NPC_WONT_TALK = 0x181, - CMSG_QUESTGIVER_STATUS_QUERY = 0x182, - SMSG_QUESTGIVER_STATUS = 0x183, - CMSG_QUESTGIVER_HELLO = 0x184, - SMSG_QUESTGIVER_QUEST_LIST = 0x185, - CMSG_QUESTGIVER_QUERY_QUEST = 0x186, - CMSG_QUESTGIVER_QUEST_AUTOLAUNCH = 0x187, - SMSG_QUESTGIVER_QUEST_DETAILS = 0x188, - CMSG_QUESTGIVER_ACCEPT_QUEST = 0x189, - CMSG_QUESTGIVER_COMPLETE_QUEST = 0x18A, - SMSG_QUESTGIVER_REQUEST_ITEMS = 0x18B, - CMSG_QUESTGIVER_REQUEST_REWARD = 0x18C, - SMSG_QUESTGIVER_OFFER_REWARD = 0x18D, - CMSG_QUESTGIVER_CHOOSE_REWARD = 0x18E, - SMSG_QUESTGIVER_QUEST_INVALID = 0x18F, - CMSG_QUESTGIVER_CANCEL = 0x190, - SMSG_QUESTGIVER_QUEST_COMPLETE = 0x191, - SMSG_QUESTGIVER_QUEST_FAILED = 0x192, - CMSG_QUESTLOG_SWAP_QUEST = 0x193, - CMSG_QUESTLOG_REMOVE_QUEST = 0x194, - SMSG_QUESTLOG_FULL = 0x195, - SMSG_QUESTUPDATE_FAILED = 0x196, - SMSG_QUESTUPDATE_FAILEDTIMER = 0x197, - SMSG_QUESTUPDATE_COMPLETE = 0x198, - SMSG_QUESTUPDATE_ADD_KILL = 0x199, - SMSG_QUESTUPDATE_ADD_ITEM = 0x19A, - CMSG_QUEST_CONFIRM_ACCEPT = 0x19B, - SMSG_QUEST_CONFIRM_ACCEPT = 0x19C, - CMSG_PUSHQUESTTOPARTY = 0x19D, - CMSG_LIST_INVENTORY = 0x19E, - SMSG_LIST_INVENTORY = 0x19F, - CMSG_SELL_ITEM = 0x1A0, - SMSG_SELL_ITEM = 0x1A1, - CMSG_BUY_ITEM = 0x1A2, - CMSG_BUY_ITEM_IN_SLOT = 0x1A3, - SMSG_BUY_ITEM = 0x1A4, - SMSG_BUY_FAILED = 0x1A5, - CMSG_TAXICLEARALLNODES = 0x1A6, - CMSG_TAXIENABLEALLNODES = 0x1A7, - CMSG_TAXISHOWNODES = 0x1A8, - SMSG_SHOWTAXINODES = 0x1A9, - CMSG_TAXINODE_STATUS_QUERY = 0x1AA, - SMSG_TAXINODE_STATUS = 0x1AB, - CMSG_TAXIQUERYAVAILABLENODES = 0x1AC, - CMSG_ACTIVATETAXI = 0x1AD, - SMSG_ACTIVATETAXIREPLY = 0x1AE, - SMSG_NEW_TAXI_PATH = 0x1AF, - CMSG_TRAINER_LIST = 0x1B0, - SMSG_TRAINER_LIST = 0x1B1, - CMSG_TRAINER_BUY_SPELL = 0x1B2, - SMSG_TRAINER_BUY_SUCCEEDED = 0x1B3, - SMSG_TRAINER_BUY_FAILED = 0x1B4, - CMSG_BINDER_ACTIVATE = 0x1B5, - SMSG_PLAYERBINDERROR = 0x1B6, - CMSG_BANKER_ACTIVATE = 0x1B7, - SMSG_SHOW_BANK = 0x1B8, - CMSG_BUY_BANK_SLOT = 0x1B9, - SMSG_BUY_BANK_SLOT_RESULT = 0x1BA, - CMSG_PETITION_SHOWLIST = 0x1BB, - SMSG_PETITION_SHOWLIST = 0x1BC, - CMSG_PETITION_BUY = 0x1BD, - CMSG_PETITION_SHOW_SIGNATURES = 0x1BE, - SMSG_PETITION_SHOW_SIGNATURES = 0x1BF, - CMSG_PETITION_SIGN = 0x1C0, - SMSG_PETITION_SIGN_RESULTS = 0x1C1, - MSG_PETITION_DECLINE = 0x1C2, - CMSG_OFFER_PETITION = 0x1C3, - CMSG_TURN_IN_PETITION = 0x1C4, - SMSG_TURN_IN_PETITION_RESULTS = 0x1C5, - CMSG_PETITION_QUERY = 0x1C6, - SMSG_PETITION_QUERY_RESPONSE = 0x1C7, - SMSG_FISH_NOT_HOOKED = 0x1C8, - SMSG_FISH_ESCAPED = 0x1C9, - CMSG_BUG = 0x1CA, - SMSG_NOTIFICATION = 0x1CB, - CMSG_PLAYED_TIME = 0x1CC, - SMSG_PLAYED_TIME = 0x1CD, - CMSG_QUERY_TIME = 0x1CE, - SMSG_QUERY_TIME_RESPONSE = 0x1CF, - SMSG_LOG_XPGAIN = 0x1D0, - SMSG_AURACASTLOG = 0x1D1, - CMSG_RECLAIM_CORPSE = 0x1D2, - CMSG_WRAP_ITEM = 0x1D3, - SMSG_LEVELUP_INFO = 0x1D4, - MSG_MINIMAP_PING = 0x1D5, - SMSG_RESISTLOG = 0x1D6, - SMSG_ENCHANTMENTLOG = 0x1D7, - CMSG_SET_SKILL_CHEAT = 0x1D8, - SMSG_START_MIRROR_TIMER = 0x1D9, - SMSG_PAUSE_MIRROR_TIMER = 0x1DA, - SMSG_STOP_MIRROR_TIMER = 0x1DB, - CMSG_PING = 0x1DC, - SMSG_PONG = 0x1DD, - SMSG_CLEAR_COOLDOWN = 0x1DE, - SMSG_GAMEOBJECT_PAGETEXT = 0x1DF, - CMSG_SETSHEATHED = 0x1E0, - SMSG_COOLDOWN_CHEAT = 0x1E1, - SMSG_SPELL_DELAYED = 0x1E2, - CMSG_QUEST_POI_QUERY = 0x1E3, - SMSG_QUEST_POI_QUERY_RESPONSE = 0x1E4, - CMSG_GHOST = 0x1E5, - CMSG_GM_INVIS = 0x1E6, - SMSG_INVALID_PROMOTION_CODE = 0x1E7, - MSG_GM_BIND_OTHER = 0x1E8, - MSG_GM_SUMMON = 0x1E9, - SMSG_ITEM_TIME_UPDATE = 0x1EA, - SMSG_ITEM_ENCHANT_TIME_UPDATE = 0x1EB, - SMSG_AUTH_CHALLENGE = 0x1EC, - CMSG_AUTH_SESSION = 0x1ED, - SMSG_AUTH_RESPONSE = 0x1EE, - MSG_GM_SHOWLABEL = 0x1EF, - CMSG_PET_CAST_SPELL = 0x1F0, - MSG_SAVE_GUILD_EMBLEM = 0x1F1, - MSG_TABARDVENDOR_ACTIVATE = 0x1F2, - SMSG_PLAY_SPELL_VISUAL = 0x1F3, - CMSG_ZONEUPDATE = 0x1F4, - SMSG_PARTYKILLLOG = 0x1F5, - SMSG_COMPRESSED_UPDATE_OBJECT = 0x1F6, - SMSG_PLAY_SPELL_IMPACT = 0x1F7, - SMSG_EXPLORATION_EXPERIENCE = 0x1F8, - CMSG_GM_SET_SECURITY_GROUP = 0x1F9, - CMSG_GM_NUKE = 0x1FA, - MSG_RANDOM_ROLL = 0x1FB, - SMSG_ENVIRONMENTALDAMAGELOG = 0x1FC, - CMSG_PLAYER_DIFFICULTY_CHANGE = 0x1FD, - SMSG_RWHOIS = 0x1FE, - SMSG_LFG_PLAYER_REWARD = 0x1FF, // uint32, uint8, uint32, uint32, uint32, uint32, uint32, uint8, for (uint8) {uint32,uint32,uint32} - SMSG_LFG_TELEPORT_DENIED = 0x200, // uint32 (1,2,4,6;0,5,7) - CMSG_UNLEARN_SPELL = 0x201, - CMSG_UNLEARN_SKILL = 0x202, - SMSG_REMOVED_SPELL = 0x203, - CMSG_DECHARGE = 0x204, - CMSG_GMTICKET_CREATE = 0x205, - SMSG_GMTICKET_CREATE = 0x206, - CMSG_GMTICKET_UPDATETEXT = 0x207, - SMSG_GMTICKET_UPDATETEXT = 0x208, - SMSG_ACCOUNT_DATA_TIMES = 0x209, - CMSG_REQUEST_ACCOUNT_DATA = 0x20A, - CMSG_UPDATE_ACCOUNT_DATA = 0x20B, - SMSG_UPDATE_ACCOUNT_DATA = 0x20C, - SMSG_CLEAR_FAR_SIGHT_IMMEDIATE = 0x20D, - SMSG_PLAYER_DIFFICULTY_CHANGE = 0x20E, - CMSG_GM_TEACH = 0x20F, - CMSG_GM_CREATE_ITEM_TARGET = 0x210, - CMSG_GMTICKET_GETTICKET = 0x211, - SMSG_GMTICKET_GETTICKET = 0x212, - CMSG_UNLEARN_TALENTS = 0x213, - SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE = 0x214, - SMSG_GAMEOBJECT_DESPAWN_ANIM = 0x215, - MSG_CORPSE_QUERY = 0x216, - CMSG_GMTICKET_DELETETICKET = 0x217, - SMSG_GMTICKET_DELETETICKET = 0x218, - SMSG_CHAT_WRONG_FACTION = 0x219, - CMSG_GMTICKET_SYSTEMSTATUS = 0x21A, - SMSG_GMTICKET_SYSTEMSTATUS = 0x21B, - CMSG_SPIRIT_HEALER_ACTIVATE = 0x21C, - CMSG_SET_STAT_CHEAT = 0x21D, - SMSG_QUEST_FORCE_REMOVE = 0x21E, // uint32 questid - CMSG_SKILL_BUY_STEP = 0x21F, - CMSG_SKILL_BUY_RANK = 0x220, - CMSG_XP_CHEAT = 0x221, - SMSG_SPIRIT_HEALER_CONFIRM = 0x222, - CMSG_CHARACTER_POINT_CHEAT = 0x223, - SMSG_GOSSIP_POI = 0x224, - CMSG_CHAT_IGNORED = 0x225, - CMSG_GM_VISION = 0x226, - CMSG_SERVER_COMMAND = 0x227, - CMSG_GM_SILENCE = 0x228, - CMSG_GM_REVEALTO = 0x229, - CMSG_GM_RESURRECT = 0x22A, - CMSG_GM_SUMMONMOB = 0x22B, - CMSG_GM_MOVECORPSE = 0x22C, - CMSG_GM_FREEZE = 0x22D, - CMSG_GM_UBERINVIS = 0x22E, - CMSG_GM_REQUEST_PLAYER_INFO = 0x22F, - SMSG_GM_PLAYER_INFO = 0x230, - CMSG_GUILD_RANK = 0x231, - CMSG_GUILD_ADD_RANK = 0x232, - CMSG_GUILD_DEL_RANK = 0x233, - CMSG_GUILD_SET_PUBLIC_NOTE = 0x234, - CMSG_GUILD_SET_OFFICER_NOTE = 0x235, - SMSG_LOGIN_VERIFY_WORLD = 0x236, - CMSG_CLEAR_EXPLORATION = 0x237, - CMSG_SEND_MAIL = 0x238, - SMSG_SEND_MAIL_RESULT = 0x239, - CMSG_GET_MAIL_LIST = 0x23A, - SMSG_MAIL_LIST_RESULT = 0x23B, - CMSG_BATTLEFIELD_LIST = 0x23C, - SMSG_BATTLEFIELD_LIST = 0x23D, - CMSG_BATTLEFIELD_JOIN = 0x23E, - SMSG_BATTLEFIELD_WIN_OBSOLETE = 0x23F, - SMSG_BATTLEFIELD_LOSE_OBSOLETE = 0x240, - CMSG_TAXICLEARNODE = 0x241, - CMSG_TAXIENABLENODE = 0x242, - CMSG_ITEM_TEXT_QUERY = 0x243, - SMSG_ITEM_TEXT_QUERY_RESPONSE = 0x244, - CMSG_MAIL_TAKE_MONEY = 0x245, - CMSG_MAIL_TAKE_ITEM = 0x246, - CMSG_MAIL_MARK_AS_READ = 0x247, - CMSG_MAIL_RETURN_TO_SENDER = 0x248, - CMSG_MAIL_DELETE = 0x249, - CMSG_MAIL_CREATE_TEXT_ITEM = 0x24A, - SMSG_SPELLLOGMISS = 0x24B, - SMSG_SPELLLOGEXECUTE = 0x24C, - SMSG_DEBUGAURAPROC = 0x24D, - SMSG_PERIODICAURALOG = 0x24E, - SMSG_SPELLDAMAGESHIELD = 0x24F, - SMSG_SPELLNONMELEEDAMAGELOG = 0x250, - CMSG_LEARN_TALENT = 0x251, - SMSG_RESURRECT_FAILED = 0x252, - CMSG_TOGGLE_PVP = 0x253, - SMSG_ZONE_UNDER_ATTACK = 0x254, - MSG_AUCTION_HELLO = 0x255, - CMSG_AUCTION_SELL_ITEM = 0x256, - CMSG_AUCTION_REMOVE_ITEM = 0x257, - CMSG_AUCTION_LIST_ITEMS = 0x258, - CMSG_AUCTION_LIST_OWNER_ITEMS = 0x259, - CMSG_AUCTION_PLACE_BID = 0x25A, - SMSG_AUCTION_COMMAND_RESULT = 0x25B, - SMSG_AUCTION_LIST_RESULT = 0x25C, - SMSG_AUCTION_OWNER_LIST_RESULT = 0x25D, - SMSG_AUCTION_BIDDER_NOTIFICATION = 0x25E, - SMSG_AUCTION_OWNER_NOTIFICATION = 0x25F, - SMSG_PROCRESIST = 0x260, - SMSG_STANDSTATE_CHANGE_FAILURE_OBSOLETE = 0x261, - SMSG_DISPEL_FAILED = 0x262, - SMSG_SPELLORDAMAGE_IMMUNE = 0x263, - CMSG_AUCTION_LIST_BIDDER_ITEMS = 0x264, - SMSG_AUCTION_BIDDER_LIST_RESULT = 0x265, - SMSG_SET_FLAT_SPELL_MODIFIER = 0x266, - SMSG_SET_PCT_SPELL_MODIFIER = 0x267, - CMSG_SET_AMMO = 0x268, - SMSG_CORPSE_RECLAIM_DELAY = 0x269, - CMSG_SET_ACTIVE_MOVER = 0x26A, - CMSG_PET_CANCEL_AURA = 0x26B, - CMSG_PLAYER_AI_CHEAT = 0x26C, - CMSG_CANCEL_AUTO_REPEAT_SPELL = 0x26D, - MSG_GM_ACCOUNT_ONLINE = 0x26E, - MSG_LIST_STABLED_PETS = 0x26F, - CMSG_STABLE_PET = 0x270, - CMSG_UNSTABLE_PET = 0x271, - CMSG_BUY_STABLE_SLOT = 0x272, - SMSG_STABLE_RESULT = 0x273, - CMSG_STABLE_REVIVE_PET = 0x274, - CMSG_STABLE_SWAP_PET = 0x275, - MSG_QUEST_PUSH_RESULT = 0x276, - SMSG_PLAY_MUSIC = 0x277, - SMSG_PLAY_OBJECT_SOUND = 0x278, - CMSG_REQUEST_PET_INFO = 0x279, - CMSG_FAR_SIGHT = 0x27A, - SMSG_SPELLDISPELLOG = 0x27B, - SMSG_DAMAGE_CALC_LOG = 0x27C, - CMSG_ENABLE_DAMAGE_LOG = 0x27D, - CMSG_GROUP_CHANGE_SUB_GROUP = 0x27E, - CMSG_REQUEST_PARTY_MEMBER_STATS = 0x27F, - CMSG_GROUP_SWAP_SUB_GROUP = 0x280, - CMSG_RESET_FACTION_CHEAT = 0x281, - CMSG_AUTOSTORE_BANK_ITEM = 0x282, - CMSG_AUTOBANK_ITEM = 0x283, - MSG_QUERY_NEXT_MAIL_TIME = 0x284, - SMSG_RECEIVED_MAIL = 0x285, - SMSG_RAID_GROUP_ONLY = 0x286, - CMSG_SET_DURABILITY_CHEAT = 0x287, - CMSG_SET_PVP_RANK_CHEAT = 0x288, - CMSG_ADD_PVP_MEDAL_CHEAT = 0x289, - CMSG_DEL_PVP_MEDAL_CHEAT = 0x28A, - CMSG_SET_PVP_TITLE = 0x28B, - SMSG_PVP_CREDIT = 0x28C, - SMSG_AUCTION_REMOVED_NOTIFICATION = 0x28D, - CMSG_GROUP_RAID_CONVERT = 0x28E, - CMSG_GROUP_ASSISTANT_LEADER = 0x28F, - CMSG_BUYBACK_ITEM = 0x290, - SMSG_SERVER_MESSAGE = 0x291, - CMSG_SET_SAVED_INSTANCE_EXTEND = 0x292, // lua: SetSavedInstanceExtend - SMSG_LFG_OFFER_CONTINUE = 0x293, - CMSG_MEETINGSTONE_CHEAT = 0x294, // not found 3.3 - SMSG_MEETINGSTONE_SETQUEUE = 0x295, // string, showed in console - CMSG_MEETINGSTONE_INFO = 0x296, // EVENT_LFG_UPDATE - SMSG_MEETINGSTONE_COMPLETE = 0x297, // EVENT_MAIL_SHOW - SMSG_MEETINGSTONE_IN_PROGRESS = 0x298, // uint32, some UPDATE_COOLDOWN events - SMSG_MEETINGSTONE_MEMBER_ADDED = 0x299, // uint32, errors: ERR_NOT_IN_GROUP (2,51) and ERR_NOT_IN_RAID (3,39,40) - CMSG_GMTICKETSYSTEM_TOGGLE = 0x29A, - CMSG_CANCEL_GROWTH_AURA = 0x29B, - SMSG_CANCEL_AUTO_REPEAT = 0x29C, - SMSG_STANDSTATE_UPDATE = 0x29D, - SMSG_LOOT_ALL_PASSED = 0x29E, - SMSG_LOOT_ROLL_WON = 0x29F, - CMSG_LOOT_ROLL = 0x2A0, - SMSG_LOOT_START_ROLL = 0x2A1, - SMSG_LOOT_ROLL = 0x2A2, - CMSG_LOOT_MASTER_GIVE = 0x2A3, - SMSG_LOOT_MASTER_LIST = 0x2A4, - SMSG_SET_FORCED_REACTIONS = 0x2A5, - SMSG_SPELL_FAILED_OTHER = 0x2A6, - SMSG_GAMEOBJECT_RESET_STATE = 0x2A7, - CMSG_REPAIR_ITEM = 0x2A8, - SMSG_CHAT_PLAYER_NOT_FOUND = 0x2A9, - MSG_TALENT_WIPE_CONFIRM = 0x2AA, - SMSG_SUMMON_REQUEST = 0x2AB, - CMSG_SUMMON_RESPONSE = 0x2AC, - MSG_MOVE_TOGGLE_GRAVITY_CHEAT = 0x2AD, - SMSG_MONSTER_MOVE_TRANSPORT = 0x2AE, - SMSG_PET_BROKEN = 0x2AF, - MSG_MOVE_FEATHER_FALL = 0x2B0, - MSG_MOVE_WATER_WALK = 0x2B1, - CMSG_SERVER_BROADCAST = 0x2B2, - CMSG_SELF_RES = 0x2B3, - SMSG_FEIGN_DEATH_RESISTED = 0x2B4, - CMSG_RUN_SCRIPT = 0x2B5, - SMSG_SCRIPT_MESSAGE = 0x2B6, - SMSG_DUEL_COUNTDOWN = 0x2B7, - SMSG_AREA_TRIGGER_MESSAGE = 0x2B8, - CMSG_SHOWING_HELM = 0x2B9, - CMSG_SHOWING_CLOAK = 0x2BA, - SMSG_LFG_ROLE_CHOSEN = 0x2BB, - SMSG_PLAYER_SKINNED = 0x2BC, - SMSG_DURABILITY_DAMAGE_DEATH = 0x2BD, - CMSG_SET_EXPLORATION = 0x2BE, - CMSG_SET_ACTIONBAR_TOGGLES = 0x2BF, - UMSG_DELETE_GUILD_CHARTER = 0x2C0, - MSG_PETITION_RENAME = 0x2C1, - SMSG_INIT_WORLD_STATES = 0x2C2, - SMSG_UPDATE_WORLD_STATE = 0x2C3, - CMSG_ITEM_NAME_QUERY = 0x2C4, - SMSG_ITEM_NAME_QUERY_RESPONSE = 0x2C5, - SMSG_PET_ACTION_FEEDBACK = 0x2C6, - CMSG_CHAR_RENAME = 0x2C7, - SMSG_CHAR_RENAME = 0x2C8, - CMSG_MOVE_SPLINE_DONE = 0x2C9, - CMSG_MOVE_FALL_RESET = 0x2CA, - SMSG_INSTANCE_SAVE_CREATED = 0x2CB, - SMSG_RAID_INSTANCE_INFO = 0x2CC, - CMSG_REQUEST_RAID_INFO = 0x2CD, - CMSG_MOVE_TIME_SKIPPED = 0x2CE, - CMSG_MOVE_FEATHER_FALL_ACK = 0x2CF, - CMSG_MOVE_WATER_WALK_ACK = 0x2D0, - CMSG_MOVE_NOT_ACTIVE_MOVER = 0x2D1, - SMSG_PLAY_SOUND = 0x2D2, - CMSG_BATTLEFIELD_STATUS = 0x2D3, - SMSG_BATTLEFIELD_STATUS = 0x2D4, - CMSG_BATTLEFIELD_PORT = 0x2D5, - MSG_INSPECT_HONOR_STATS = 0x2D6, - CMSG_BATTLEMASTER_HELLO = 0x2D7, - CMSG_MOVE_START_SWIM_CHEAT = 0x2D8, - CMSG_MOVE_STOP_SWIM_CHEAT = 0x2D9, - SMSG_FORCE_WALK_SPEED_CHANGE = 0x2DA, - CMSG_FORCE_WALK_SPEED_CHANGE_ACK = 0x2DB, - SMSG_FORCE_SWIM_BACK_SPEED_CHANGE = 0x2DC, - CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK = 0x2DD, - SMSG_FORCE_TURN_RATE_CHANGE = 0x2DE, - CMSG_FORCE_TURN_RATE_CHANGE_ACK = 0x2DF, - MSG_PVP_LOG_DATA = 0x2E0, - CMSG_LEAVE_BATTLEFIELD = 0x2E1, - CMSG_AREA_SPIRIT_HEALER_QUERY = 0x2E2, - CMSG_AREA_SPIRIT_HEALER_QUEUE = 0x2E3, - SMSG_AREA_SPIRIT_HEALER_TIME = 0x2E4, - CMSG_GM_UNTEACH = 0x2E5, - SMSG_WARDEN_DATA = 0x2E6, - CMSG_WARDEN_DATA = 0x2E7, - SMSG_GROUP_JOINED_BATTLEGROUND = 0x2E8, - MSG_BATTLEGROUND_PLAYER_POSITIONS = 0x2E9, - CMSG_PET_STOP_ATTACK = 0x2EA, - SMSG_BINDER_CONFIRM = 0x2EB, - SMSG_BATTLEGROUND_PLAYER_JOINED = 0x2EC, - SMSG_BATTLEGROUND_PLAYER_LEFT = 0x2ED, - CMSG_BATTLEMASTER_JOIN = 0x2EE, - SMSG_ADDON_INFO = 0x2EF, - CMSG_PET_UNLEARN = 0x2F0, // Deprecated 3.x - SMSG_PET_UNLEARN_CONFIRM = 0x2F1, // Deprecated 3.x - SMSG_PARTY_MEMBER_STATS_FULL = 0x2F2, - CMSG_PET_SPELL_AUTOCAST = 0x2F3, - SMSG_WEATHER = 0x2F4, - SMSG_PLAY_TIME_WARNING = 0x2F5, - SMSG_MINIGAME_SETUP = 0x2F6, - SMSG_MINIGAME_STATE = 0x2F7, - CMSG_MINIGAME_MOVE = 0x2F8, - SMSG_MINIGAME_MOVE_FAILED = 0x2F9, - SMSG_RAID_INSTANCE_MESSAGE = 0x2FA, - SMSG_COMPRESSED_MOVES = 0x2FB, - CMSG_GUILD_INFO_TEXT = 0x2FC, - SMSG_CHAT_RESTRICTED = 0x2FD, - SMSG_SPLINE_SET_RUN_SPEED = 0x2FE, - SMSG_SPLINE_SET_RUN_BACK_SPEED = 0x2FF, - SMSG_SPLINE_SET_SWIM_SPEED = 0x300, - SMSG_SPLINE_SET_WALK_SPEED = 0x301, - SMSG_SPLINE_SET_SWIM_BACK_SPEED = 0x302, - SMSG_SPLINE_SET_TURN_RATE = 0x303, - SMSG_SPLINE_MOVE_UNROOT = 0x304, - SMSG_SPLINE_MOVE_FEATHER_FALL = 0x305, - SMSG_SPLINE_MOVE_NORMAL_FALL = 0x306, - SMSG_SPLINE_MOVE_SET_HOVER = 0x307, - SMSG_SPLINE_MOVE_UNSET_HOVER = 0x308, - SMSG_SPLINE_MOVE_WATER_WALK = 0x309, - SMSG_SPLINE_MOVE_LAND_WALK = 0x30A, - SMSG_SPLINE_MOVE_START_SWIM = 0x30B, - SMSG_SPLINE_MOVE_STOP_SWIM = 0x30C, - SMSG_SPLINE_MOVE_SET_RUN_MODE = 0x30D, - SMSG_SPLINE_MOVE_SET_WALK_MODE = 0x30E, - CMSG_GM_NUKE_ACCOUNT = 0x30F, - MSG_GM_DESTROY_CORPSE = 0x310, - CMSG_GM_DESTROY_ONLINE_CORPSE = 0x311, - CMSG_ACTIVATETAXIEXPRESS = 0x312, - SMSG_SET_FACTION_ATWAR = 0x313, - SMSG_GAMETIMEBIAS_SET = 0x314, - CMSG_DEBUG_ACTIONS_START = 0x315, - CMSG_DEBUG_ACTIONS_STOP = 0x316, - CMSG_SET_FACTION_INACTIVE = 0x317, - CMSG_SET_WATCHED_FACTION = 0x318, - MSG_MOVE_TIME_SKIPPED = 0x319, - SMSG_SPLINE_MOVE_ROOT = 0x31A, - CMSG_SET_EXPLORATION_ALL = 0x31B, - SMSG_INVALIDATE_PLAYER = 0x31C, - CMSG_RESET_INSTANCES = 0x31D, - SMSG_INSTANCE_RESET = 0x31E, - SMSG_INSTANCE_RESET_FAILED = 0x31F, - SMSG_UPDATE_LAST_INSTANCE = 0x320, - MSG_RAID_TARGET_UPDATE = 0x321, - MSG_RAID_READY_CHECK = 0x322, - CMSG_LUA_USAGE = 0x323, - SMSG_PET_ACTION_SOUND = 0x324, - SMSG_PET_DISMISS_SOUND = 0x325, - SMSG_GHOSTEE_GONE = 0x326, - CMSG_GM_UPDATE_TICKET_STATUS = 0x327, - SMSG_GM_TICKET_STATUS_UPDATE = 0x328, - MSG_SET_DUNGEON_DIFFICULTY = 0x329, - CMSG_GMSURVEY_SUBMIT = 0x32A, - SMSG_UPDATE_INSTANCE_OWNERSHIP = 0x32B, - CMSG_IGNORE_KNOCKBACK_CHEAT = 0x32C, - SMSG_CHAT_PLAYER_AMBIGUOUS = 0x32D, - MSG_DELAY_GHOST_TELEPORT = 0x32E, - SMSG_SPELLINSTAKILLLOG = 0x32F, - SMSG_SPELL_UPDATE_CHAIN_TARGETS = 0x330, - CMSG_CHAT_FILTERED = 0x331, - SMSG_EXPECTED_SPAM_RECORDS = 0x332, - SMSG_SPELLSTEALLOG = 0x333, - CMSG_LOTTERY_QUERY_OBSOLETE = 0x334, - SMSG_LOTTERY_QUERY_RESULT_OBSOLETE = 0x335, - CMSG_BUY_LOTTERY_TICKET_OBSOLETE = 0x336, - SMSG_LOTTERY_RESULT_OBSOLETE = 0x337, - SMSG_CHARACTER_PROFILE = 0x338, - SMSG_CHARACTER_PROFILE_REALM_CONNECTED = 0x339, - SMSG_DEFENSE_MESSAGE = 0x33A, - SMSG_INSTANCE_DIFFICULTY = 0x33B, - MSG_GM_RESETINSTANCELIMIT = 0x33C, - SMSG_MOTD = 0x33D, - SMSG_MOVE_SET_FLIGHT = 0x33E, - SMSG_MOVE_UNSET_FLIGHT = 0x33F, - CMSG_MOVE_FLIGHT_ACK = 0x340, - MSG_MOVE_START_SWIM_CHEAT = 0x341, - MSG_MOVE_STOP_SWIM_CHEAT = 0x342, - SMSG_MOVE_SET_CAN_FLY = 0x343, - SMSG_MOVE_UNSET_CAN_FLY = 0x344, - CMSG_MOVE_SET_CAN_FLY_ACK = 0x345, - CMSG_MOVE_SET_FLY = 0x346, - CMSG_SOCKET_GEMS = 0x347, - CMSG_ARENA_TEAM_CREATE = 0x348, - SMSG_ARENA_TEAM_COMMAND_RESULT = 0x349, - UMSG_UPDATE_ARENA_TEAM_OBSOLETE = 0x34A, - CMSG_ARENA_TEAM_QUERY = 0x34B, - SMSG_ARENA_TEAM_QUERY_RESPONSE = 0x34C, - CMSG_ARENA_TEAM_ROSTER = 0x34D, - SMSG_ARENA_TEAM_ROSTER = 0x34E, - CMSG_ARENA_TEAM_INVITE = 0x34F, - SMSG_ARENA_TEAM_INVITE = 0x350, - CMSG_ARENA_TEAM_ACCEPT = 0x351, - CMSG_ARENA_TEAM_DECLINE = 0x352, - CMSG_ARENA_TEAM_LEAVE = 0x353, - CMSG_ARENA_TEAM_REMOVE = 0x354, - CMSG_ARENA_TEAM_DISBAND = 0x355, - CMSG_ARENA_TEAM_LEADER = 0x356, - SMSG_ARENA_TEAM_EVENT = 0x357, - CMSG_BATTLEMASTER_JOIN_ARENA = 0x358, - MSG_MOVE_START_ASCEND = 0x359, - MSG_MOVE_STOP_ASCEND = 0x35A, - SMSG_ARENA_TEAM_STATS = 0x35B, - CMSG_LFG_JOIN = 0x35C, // CMSG JoinLFG - CMSG_LFG_LEAVE = 0x35D, // CMSG LeaveLFG - CMSG_SEARCH_LFG_JOIN = 0x35E, // CMSG SearchLFGJoin - CMSG_SEARCH_LFG_LEAVE = 0x35F, // CMSG SearchLFGLeave - SMSG_UPDATE_LFG_LIST = 0x360, // SMSG uint32, uint32, if (uint8) { uint32 count, for (count) { uint64} }, uint32 count2, uint32, for (count2) { uint64, uint32 flags, if (flags & 0x2) {string}, if (flags & 0x10) {for (3) uint8}, if (flags & 0x80) {uint64, uint32}}, uint32 count3, uint32, for (count3) {uint64, uint32 flags, if (flags & 0x1) {uint8, uint8, uint8, for (3) uint8, uint32, uint32, uint32, uint32, uint32, uint32, float, float, uint32, uint32, uint32, uint32, uint32, float, uint32, uint32, uint32, uint32, uint32, uint32}, if (flags&0x2) string, if (flags&0x4) uint8, if (flags&0x8) uint64, if (flags&0x10) uint8, if (flags&0x20) uint32, if (flags&0x40) uint8, if (flags& 0x80) {uint64, uint32}} - SMSG_LFG_PROPOSAL_UPDATE = 0x361, // SMSG uint32, uint8, uint32, uint32, uint8, for (uint8) {uint32,uint8,uint8,uint8,uint8} - CMSG_LFG_PROPOSAL_RESULT = 0x362, // CMSG AcceptProposal, RejectProposal - SMSG_LFG_ROLE_CHECK_UPDATE = 0x363, // SMSG uint32, uint8, for (uint8) uint32, uint8, for (uint8) { uint64, uint8, uint32, uint8, } - SMSG_LFG_JOIN_RESULT = 0x364, // SMSG uint32 unk, uint32, if (unk == 6) { uint8 count, for (count) uint64 } - SMSG_LFG_QUEUE_STATUS = 0x365, // SMSG uint32 dungeon, uint32 lfgtype, uint32, uint32, uint32, uint32, uint8, uint8, uint8, uint8 - CMSG_SET_LFG_COMMENT = 0x366, // CMSG SetLFGComment - SMSG_LFG_UPDATE_PLAYER = 0x367, // SMSG uint8, if (uint8) { uint8, uint8, uint8, uint8, if (uint8) for (uint8) uint32, string} - SMSG_LFG_UPDATE_PARTY = 0x368, // SMSG uint8, if (uint8) { uint8, uint8, uint8, for (3) uint8, uint8, if (uint8) for (uint8) uint32, string} - SMSG_LFG_UPDATE_SEARCH = 0x369, // SMSG uint8 - CMSG_LFG_SET_ROLES = 0x36A, // CMSG SetLFGRoles - CMSG_LFG_SET_NEEDS = 0x36B, // CMSG SetLFGNeeds - CMSG_LFG_SET_BOOT_VOTE = 0x36C, // CMSG SetLFGBootVote - SMSG_LFG_BOOT_PLAYER = 0x36D, // SMSG uint8, uint8, uint8, uint64, uint32, uint32, uint32, uint32 - CMSG_LFD_PLAYER_LOCK_INFO_REQUEST = 0x36E, // CMSG RequestLFDPlayerLockInfo - SMSG_LFG_PLAYER_INFO = 0x36F, // SMSG uint8, for (uint8) { uint32, uint8, uint32, uint32, uint32, uint32, uint8, for (uint8) {uint32,uint32, uint32}}, uint32, for (uint32) {uint32,uint32} - CMSG_LFG_TELEPORT = 0x370, // CMSG LFGTeleport - CMSG_LFD_PARTY_LOCK_INFO_REQUEST = 0x371, // CMSG RequestLFDPartyLockInfo - SMSG_LFG_PARTY_INFO = 0x372, // SMSG uint8, for (uint8) uint64 - SMSG_TITLE_EARNED = 0x373, - CMSG_SET_TITLE = 0x374, - CMSG_CANCEL_MOUNT_AURA = 0x375, - SMSG_ARENA_ERROR = 0x376, - MSG_INSPECT_ARENA_TEAMS = 0x377, - SMSG_DEATH_RELEASE_LOC = 0x378, - CMSG_CANCEL_TEMP_ENCHANTMENT = 0x379, - SMSG_FORCED_DEATH_UPDATE = 0x37A, - CMSG_CHEAT_SET_HONOR_CURRENCY = 0x37B, - CMSG_CHEAT_SET_ARENA_CURRENCY = 0x37C, - MSG_MOVE_SET_FLIGHT_SPEED_CHEAT = 0x37D, - MSG_MOVE_SET_FLIGHT_SPEED = 0x37E, - MSG_MOVE_SET_FLIGHT_BACK_SPEED_CHEAT = 0x37F, - MSG_MOVE_SET_FLIGHT_BACK_SPEED = 0x380, - SMSG_FORCE_FLIGHT_SPEED_CHANGE = 0x381, - CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK = 0x382, - SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE = 0x383, - CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK = 0x384, - SMSG_SPLINE_SET_FLIGHT_SPEED = 0x385, - SMSG_SPLINE_SET_FLIGHT_BACK_SPEED = 0x386, - CMSG_MAELSTROM_INVALIDATE_CACHE = 0x387, - SMSG_FLIGHT_SPLINE_SYNC = 0x388, - CMSG_SET_TAXI_BENCHMARK_MODE = 0x389, - SMSG_JOINED_BATTLEGROUND_QUEUE = 0x38A, - SMSG_REALM_SPLIT = 0x38B, - CMSG_REALM_SPLIT = 0x38C, - CMSG_MOVE_CHNG_TRANSPORT = 0x38D, - MSG_PARTY_ASSIGNMENT = 0x38E, - SMSG_OFFER_PETITION_ERROR = 0x38F, - SMSG_TIME_SYNC_REQ = 0x390, - CMSG_TIME_SYNC_RESP = 0x391, - CMSG_SEND_LOCAL_EVENT = 0x392, - CMSG_SEND_GENERAL_TRIGGER = 0x393, - CMSG_SEND_COMBAT_TRIGGER = 0x394, - CMSG_MAELSTROM_GM_SENT_MAIL = 0x395, - SMSG_RESET_FAILED_NOTIFY = 0x396, - SMSG_REAL_GROUP_UPDATE = 0x397, - SMSG_LFG_DISABLED = 0x398, - CMSG_ACTIVE_PVP_CHEAT = 0x399, - CMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY = 0x39A, - SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE = 0x39B, - SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE_WRITE_FILE = 0x39C, - SMSG_UPDATE_COMBO_POINTS = 0x39D, - SMSG_VOICE_SESSION_ROSTER_UPDATE = 0x39E, - SMSG_VOICE_SESSION_LEAVE = 0x39F, - SMSG_VOICE_SESSION_ADJUST_PRIORITY = 0x3A0, - CMSG_VOICE_SET_TALKER_MUTED_REQUEST = 0x3A1, - SMSG_VOICE_SET_TALKER_MUTED = 0x3A2, - SMSG_INIT_EXTRA_AURA_INFO_OBSOLETE = 0x3A3, - SMSG_SET_EXTRA_AURA_INFO_OBSOLETE = 0x3A4, - SMSG_SET_EXTRA_AURA_INFO_NEED_UPDATE_OBSOLETE = 0x3A5, - SMSG_CLEAR_EXTRA_AURA_INFO_OBSOLETE = 0x3A6, - MSG_MOVE_START_DESCEND = 0x3A7, - CMSG_IGNORE_REQUIREMENTS_CHEAT = 0x3A8, - SMSG_IGNORE_REQUIREMENTS_CHEAT = 0x3A9, - SMSG_SPELL_CHANCE_PROC_LOG = 0x3AA, - CMSG_MOVE_SET_RUN_SPEED = 0x3AB, - SMSG_DISMOUNT = 0x3AC, - MSG_MOVE_UPDATE_CAN_FLY = 0x3AD, - MSG_RAID_READY_CHECK_CONFIRM = 0x3AE, - CMSG_VOICE_SESSION_ENABLE = 0x3AF, - SMSG_VOICE_SESSION_ENABLE = 0x3B0, - SMSG_VOICE_PARENTAL_CONTROLS = 0x3B1, - CMSG_GM_WHISPER = 0x3B2, - SMSG_GM_MESSAGECHAT = 0x3B3, - MSG_GM_GEARRATING = 0x3B4, - CMSG_COMMENTATOR_ENABLE = 0x3B5, - SMSG_COMMENTATOR_STATE_CHANGED = 0x3B6, - CMSG_COMMENTATOR_GET_MAP_INFO = 0x3B7, - SMSG_COMMENTATOR_MAP_INFO = 0x3B8, - CMSG_COMMENTATOR_GET_PLAYER_INFO = 0x3B9, - SMSG_COMMENTATOR_GET_PLAYER_INFO = 0x3BA, - SMSG_COMMENTATOR_PLAYER_INFO = 0x3BB, - CMSG_COMMENTATOR_ENTER_INSTANCE = 0x3BC, - CMSG_COMMENTATOR_EXIT_INSTANCE = 0x3BD, - CMSG_COMMENTATOR_INSTANCE_COMMAND = 0x3BE, - SMSG_CLEAR_TARGET = 0x3BF, - CMSG_BOT_DETECTED = 0x3C0, - SMSG_CROSSED_INEBRIATION_THRESHOLD = 0x3C1, - CMSG_CHEAT_PLAYER_LOGIN = 0x3C2, - CMSG_CHEAT_PLAYER_LOOKUP = 0x3C3, - SMSG_CHEAT_PLAYER_LOOKUP = 0x3C4, - SMSG_KICK_REASON = 0x3C5, - MSG_RAID_READY_CHECK_FINISHED = 0x3C6, - CMSG_COMPLAIN = 0x3C7, - SMSG_COMPLAIN_RESULT = 0x3C8, - SMSG_FEATURE_SYSTEM_STATUS = 0x3C9, - CMSG_GM_SHOW_COMPLAINTS = 0x3CA, - CMSG_GM_UNSQUELCH = 0x3CB, - CMSG_CHANNEL_SILENCE_VOICE = 0x3CC, - CMSG_CHANNEL_SILENCE_ALL = 0x3CD, - CMSG_CHANNEL_UNSILENCE_VOICE = 0x3CE, - CMSG_CHANNEL_UNSILENCE_ALL = 0x3CF, - CMSG_TARGET_CAST = 0x3D0, - CMSG_TARGET_SCRIPT_CAST = 0x3D1, - CMSG_CHANNEL_DISPLAY_LIST = 0x3D2, - CMSG_SET_ACTIVE_VOICE_CHANNEL = 0x3D3, - CMSG_GET_CHANNEL_MEMBER_COUNT = 0x3D4, - SMSG_CHANNEL_MEMBER_COUNT = 0x3D5, - CMSG_CHANNEL_VOICE_ON = 0x3D6, - CMSG_CHANNEL_VOICE_OFF = 0x3D7, - CMSG_DEBUG_LIST_TARGETS = 0x3D8, - SMSG_DEBUG_LIST_TARGETS = 0x3D9, - SMSG_AVAILABLE_VOICE_CHANNEL = 0x3DA, - CMSG_ADD_VOICE_IGNORE = 0x3DB, - CMSG_DEL_VOICE_IGNORE = 0x3DC, - CMSG_PARTY_SILENCE = 0x3DD, - CMSG_PARTY_UNSILENCE = 0x3DE, - MSG_NOTIFY_PARTY_SQUELCH = 0x3DF, - SMSG_COMSAT_RECONNECT_TRY = 0x3E0, - SMSG_COMSAT_DISCONNECT = 0x3E1, - SMSG_COMSAT_CONNECT_FAIL = 0x3E2, - SMSG_VOICE_CHAT_STATUS = 0x3E3, - CMSG_REPORT_PVP_AFK = 0x3E4, - SMSG_REPORT_PVP_AFK_RESULT = 0x3E5, // SMSG? - CMSG_GUILD_BANKER_ACTIVATE = 0x3E6, - CMSG_GUILD_BANK_QUERY_TAB = 0x3E7, - SMSG_GUILD_BANK_LIST = 0x3E8, - CMSG_GUILD_BANK_SWAP_ITEMS = 0x3E9, - CMSG_GUILD_BANK_BUY_TAB = 0x3EA, - CMSG_GUILD_BANK_UPDATE_TAB = 0x3EB, - CMSG_GUILD_BANK_DEPOSIT_MONEY = 0x3EC, - CMSG_GUILD_BANK_WITHDRAW_MONEY = 0x3ED, - MSG_GUILD_BANK_LOG_QUERY = 0x3EE, - CMSG_SET_CHANNEL_WATCH = 0x3EF, - SMSG_USERLIST_ADD = 0x3F0, - SMSG_USERLIST_REMOVE = 0x3F1, - SMSG_USERLIST_UPDATE = 0x3F2, - CMSG_CLEAR_CHANNEL_WATCH = 0x3F3, - SMSG_INSPECT_TALENT = 0x3F4, - SMSG_GOGOGO_OBSOLETE = 0x3F5, - SMSG_ECHO_PARTY_SQUELCH = 0x3F6, - CMSG_SET_TITLE_SUFFIX = 0x3F7, - CMSG_SPELLCLICK = 0x3F8, - SMSG_LOOT_LIST = 0x3F9, - CMSG_GM_CHARACTER_RESTORE = 0x3FA, - CMSG_GM_CHARACTER_SAVE = 0x3FB, - SMSG_VOICESESSION_FULL = 0x3FC, - MSG_GUILD_PERMISSIONS = 0x3FD, - MSG_GUILD_BANK_MONEY_WITHDRAWN = 0x3FE, - MSG_GUILD_EVENT_LOG_QUERY = 0x3FF, - CMSG_MAELSTROM_RENAME_GUILD = 0x400, - CMSG_GET_MIRRORIMAGE_DATA = 0x401, - SMSG_MIRRORIMAGE_DATA = 0x402, - SMSG_FORCE_DISPLAY_UPDATE = 0x403, - SMSG_SPELL_CHANCE_RESIST_PUSHBACK = 0x404, - CMSG_IGNORE_DIMINISHING_RETURNS_CHEAT = 0x405, - SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT = 0x406, - CMSG_KEEP_ALIVE = 0x407, - SMSG_RAID_READY_CHECK_ERROR = 0x408, - CMSG_OPT_OUT_OF_LOOT = 0x409, - MSG_QUERY_GUILD_BANK_TEXT = 0x40A, - CMSG_SET_GUILD_BANK_TEXT = 0x40B, - CMSG_SET_GRANTABLE_LEVELS = 0x40C, - CMSG_GRANT_LEVEL = 0x40D, - CMSG_REFER_A_FRIEND = 0x40E, - MSG_GM_CHANGE_ARENA_RATING = 0x40F, - CMSG_DECLINE_CHANNEL_INVITE = 0x410, - SMSG_GROUPACTION_THROTTLED = 0x411, // SMSG? - SMSG_OVERRIDE_LIGHT = 0x412, - SMSG_TOTEM_CREATED = 0x413, - CMSG_TOTEM_DESTROYED = 0x414, - CMSG_EXPIRE_RAID_INSTANCE = 0x415, - CMSG_NO_SPELL_VARIANCE = 0x416, - CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY = 0x417, - SMSG_QUESTGIVER_STATUS_MULTIPLE = 0x418, - CMSG_SET_PLAYER_DECLINED_NAMES = 0x419, - SMSG_SET_PLAYER_DECLINED_NAMES_RESULT = 0x41A, - CMSG_QUERY_SERVER_BUCK_DATA = 0x41B, - CMSG_CLEAR_SERVER_BUCK_DATA = 0x41C, - SMSG_SERVER_BUCK_DATA = 0x41D, - SMSG_SEND_UNLEARN_SPELLS = 0x41E, - SMSG_PROPOSE_LEVEL_GRANT = 0x41F, - CMSG_ACCEPT_LEVEL_GRANT = 0x420, - SMSG_REFER_A_FRIEND_FAILURE = 0x421, - SMSG_SPLINE_MOVE_SET_FLYING = 0x422, - SMSG_SPLINE_MOVE_UNSET_FLYING = 0x423, - SMSG_SUMMON_CANCEL = 0x424, - CMSG_CHANGE_PERSONAL_ARENA_RATING = 0x425, - CMSG_ALTER_APPEARANCE = 0x426, - SMSG_ENABLE_BARBER_SHOP = 0x427, - SMSG_BARBER_SHOP_RESULT = 0x428, - CMSG_CALENDAR_GET_CALENDAR = 0x429, - CMSG_CALENDAR_GET_EVENT = 0x42A, - CMSG_CALENDAR_GUILD_FILTER = 0x42B, - CMSG_CALENDAR_ARENA_TEAM = 0x42C, - CMSG_CALENDAR_ADD_EVENT = 0x42D, - CMSG_CALENDAR_UPDATE_EVENT = 0x42E, - CMSG_CALENDAR_REMOVE_EVENT = 0x42F, - CMSG_CALENDAR_COPY_EVENT = 0x430, - CMSG_CALENDAR_EVENT_INVITE = 0x431, - CMSG_CALENDAR_EVENT_RSVP = 0x432, - CMSG_CALENDAR_EVENT_REMOVE_INVITE = 0x433, - CMSG_CALENDAR_EVENT_STATUS = 0x434, - CMSG_CALENDAR_EVENT_MODERATOR_STATUS = 0x435, - SMSG_CALENDAR_SEND_CALENDAR = 0x436, - SMSG_CALENDAR_SEND_EVENT = 0x437, - SMSG_CALENDAR_FILTER_GUILD = 0x438, - SMSG_CALENDAR_ARENA_TEAM = 0x439, - SMSG_CALENDAR_EVENT_INVITE = 0x43A, - SMSG_CALENDAR_EVENT_INVITE_REMOVED = 0x43B, - SMSG_CALENDAR_EVENT_STATUS = 0x43C, - SMSG_CALENDAR_COMMAND_RESULT = 0x43D, - SMSG_CALENDAR_RAID_LOCKOUT_ADDED = 0x43E, - SMSG_CALENDAR_RAID_LOCKOUT_REMOVED = 0x43F, - SMSG_CALENDAR_EVENT_INVITE_ALERT = 0x440, - SMSG_CALENDAR_EVENT_INVITE_REMOVED_ALERT = 0x441, - SMSG_CALENDAR_EVENT_INVITE_STATUS_ALERT = 0x442, - SMSG_CALENDAR_EVENT_REMOVED_ALERT = 0x443, - SMSG_CALENDAR_EVENT_UPDATED_ALERT = 0x444, - SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT = 0x445, - CMSG_CALENDAR_COMPLAIN = 0x446, - CMSG_CALENDAR_GET_NUM_PENDING = 0x447, - SMSG_CALENDAR_SEND_NUM_PENDING = 0x448, - CMSG_SAVE_DANCE = 0x449, - SMSG_NOTIFY_DANCE = 0x44A, - CMSG_PLAY_DANCE = 0x44B, - SMSG_PLAY_DANCE = 0x44C, - CMSG_LOAD_DANCES = 0x44D, - CMSG_STOP_DANCE = 0x44E, - SMSG_STOP_DANCE = 0x44F, - CMSG_SYNC_DANCE = 0x450, - CMSG_DANCE_QUERY = 0x451, - SMSG_DANCE_QUERY_RESPONSE = 0x452, - SMSG_INVALIDATE_DANCE = 0x453, - CMSG_DELETE_DANCE = 0x454, - SMSG_LEARNED_DANCE_MOVES = 0x455, - CMSG_LEARN_DANCE_MOVE = 0x456, - CMSG_UNLEARN_DANCE_MOVE = 0x457, - CMSG_SET_RUNE_COUNT = 0x458, - CMSG_SET_RUNE_COOLDOWN = 0x459, - MSG_MOVE_SET_PITCH_RATE_CHEAT = 0x45A, - MSG_MOVE_SET_PITCH_RATE = 0x45B, - SMSG_FORCE_PITCH_RATE_CHANGE = 0x45C, - CMSG_FORCE_PITCH_RATE_CHANGE_ACK = 0x45D, - SMSG_SPLINE_SET_PITCH_RATE = 0x45E, - SMSG_MOVE_ABANDON_TRANSPORT = 0x45F, - SMSG_CALENDAR_UPDATE_INVITE_LIST = 0x460, - SMSG_CALENDAR_UPDATE_INVITE_LIST2 = 0x461, - CMSG_UPDATE_MISSILE_TRAJECTORY = 0x462, - SMSG_UPDATE_ACCOUNT_DATA_COMPLETE = 0x463, - SMSG_TRIGGER_MOVIE = 0x464, - CMSG_COMPLETE_MOVIE = 0x465, - CMSG_SET_GLYPH_SLOT = 0x466, - CMSG_SET_GLYPH = 0x467, - SMSG_ACHIEVEMENT_EARNED = 0x468, - SMSG_DYNAMIC_DROP_ROLL_RESULT = 0x469, - SMSG_CRITERIA_UPDATE = 0x46A, - CMSG_QUERY_INSPECT_ACHIEVEMENTS = 0x46B, - SMSG_RESPOND_INSPECT_ACHIEVEMENTS = 0x46C, - CMSG_DISMISS_CONTROLLED_VEHICLE = 0x46D, - CMSG_COMPLETE_ACHIEVEMENT_CHEAT = 0x46E, - SMSG_QUESTUPDATE_ADD_PVP_KILL = 0x46F, - CMSG_SET_CRITERIA_CHEAT = 0x470, - SMSG_CALENDAR_UPDATE_INVITE_LIST3 = 0x471, - CMSG_UNITANIMTIER_CHEAT = 0x472, - CMSG_CHAR_CUSTOMIZE = 0x473, - SMSG_CHAR_CUSTOMIZE = 0x474, - SMSG_PET_RENAMEABLE = 0x475, - CMSG_REQUEST_VEHICLE_EXIT = 0x476, - CMSG_REQUEST_VEHICLE_PREV_SEAT = 0x477, - CMSG_REQUEST_VEHICLE_NEXT_SEAT = 0x478, - CMSG_REQUEST_VEHICLE_SWITCH_SEAT = 0x479, - CMSG_PET_LEARN_TALENT = 0x47A, - CMSG_PET_UNLEARN_TALENTS = 0x47B, - SMSG_SET_PHASE_SHIFT = 0x47C, - SMSG_ALL_ACHIEVEMENT_DATA = 0x47D, - CMSG_FORCE_SAY_CHEAT = 0x47E, - SMSG_HEALTH_UPDATE = 0x47F, - SMSG_POWER_UPDATE = 0x480, - CMSG_GAMEOBJ_REPORT_USE = 0x481, - SMSG_HIGHEST_THREAT_UPDATE = 0x482, - SMSG_THREAT_UPDATE = 0x483, - SMSG_THREAT_REMOVE = 0x484, - SMSG_THREAT_CLEAR = 0x485, - SMSG_CONVERT_RUNE = 0x486, - SMSG_RESYNC_RUNES = 0x487, - SMSG_ADD_RUNE_POWER = 0x488, - CMSG_START_QUEST = 0x489, - CMSG_REMOVE_GLYPH = 0x48A, - CMSG_DUMP_OBJECTS = 0x48B, - SMSG_DUMP_OBJECTS_DATA = 0x48C, - CMSG_DISMISS_CRITTER = 0x48D, - SMSG_NOTIFY_DEST_LOC_SPELL_CAST = 0x48E, - CMSG_AUCTION_LIST_PENDING_SALES = 0x48F, - SMSG_AUCTION_LIST_PENDING_SALES = 0x490, - SMSG_MODIFY_COOLDOWN = 0x491, - SMSG_PET_UPDATE_COMBO_POINTS = 0x492, - CMSG_ENABLETAXI = 0x493, - SMSG_PRE_RESURRECT = 0x494, - SMSG_AURA_UPDATE_ALL = 0x495, - SMSG_AURA_UPDATE = 0x496, - CMSG_FLOOD_GRACE_CHEAT = 0x497, - SMSG_SERVER_FIRST_ACHIEVEMENT = 0x498, - SMSG_PET_LEARNED_SPELL = 0x499, - SMSG_PET_REMOVED_SPELL = 0x49A, - CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE = 0x49B, - CMSG_HEARTH_AND_RESURRECT = 0x49C, // not changed in 3.1 - SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA = 0x49D, // not changed 9626 - SMSG_CRITERIA_DELETED = 0x49E, // not changed 9626 - SMSG_ACHIEVEMENT_DELETED = 0x49F, // not changed 9626 - CMSG_SERVER_INFO_QUERY = 0x4A0, // not found - SMSG_SERVER_INFO_RESPONSE = 0x4A1, // not found - CMSG_CHECK_LOGIN_CRITERIA = 0x4A2, // not found - SMSG_SERVER_BUCK_DATA_START = 0x4A3, // not found - CMSG_QUERY_VEHICLE_STATUS = 0x4A4, // not found - UMSG_UNKNOWN_1189 = 0x4A5, // not found, old SMSG_PET_GUIDS - SMSG_BATTLEGROUND_INFO_THROTTLED = 0x4A6, // empty, "You can't do that yet" - SMSG_PLAYER_VEHICLE_DATA = 0x4A7, // smsg guid+uint32 (vehicle) - CMSG_PLAYER_VEHICLE_ENTER = 0x4A8, // cmsg uint64 - CMSG_EJECT_PASSENGER = 0x4A9, // cmsg uint64 - SMSG_PET_GUIDS = 0x4AA, // shifted+5 - SMSG_CLIENTCACHE_VERSION = 0x4AB, // shifted+5 - UMSG_UNKNOWN_1196 = 0x4AC, // not found - UMSG_UNKNOWN_1197 = 0x4AD, // not found - UMSG_UNKNOWN_1198 = 0x4AE, // not found - UMSG_UNKNOWN_1199 = 0x4AF, // not found - UMSG_UNKNOWN_1200 = 0x4B0, // not found - UMSG_UNKNOWN_1201 = 0x4B1, // not found - SMSG_ITEM_REFUND_INFO_RESPONSE = 0x4B2, // refund item info - CMSG_ITEM_REFUND_INFO = 0x4B3, // refund request? - CMSG_ITEM_REFUND = 0x4B4, // lua: ContainerRefundItemPurchase - SMSG_ITEM_REFUND_RESULT = 0x4B5, // refund item result - CMSG_CORPSE_MAP_POSITION_QUERY = 0x4B6, // CMSG, uint32 - SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE = 0x4B7, // SMSG, 3*float+float - UMSG_UNKNOWN_1208 = 0x4B8, // not found - UMSG_UNKNOWN_1209 = 0x4B9, // not found - CMSG_CALENDAR_CONTEXT_EVENT_SIGNUP = 0x4BA, // CMSG, uint64, lua: CalendarContextEventSignUp - SMSG_CALENDAR_ACTION_PENDING = 0x4BB, // SMSG, calendar related EVENT_CALENDAR_ACTION_PENDING - SMSG_EQUIPMENT_SET_LIST = 0x4BC, // SMSG, equipment manager list? - CMSG_EQUIPMENT_SET_SAVE = 0x4BD, // CMSG, lua: SaveEquipmentSet - CMSG_UPDATE_PROJECTILE_POSITION = 0x4BE, // CMSG, uint64 caster, uint32 spellId, uint8 castId, vector3 position - SMSG_SET_PROJECTILE_POSITION = 0x4BF, // SMSG, uint64 caster, uint8 castId, vector3 position - SMSG_TALENTS_INFO = 0x4C0, // SMSG, talents related - CMSG_LEARN_PREVIEW_TALENTS = 0x4C1, // CMSG, lua: LearnPreviewTalents (for player?) - CMSG_LEARN_PREVIEW_TALENTS_PET = 0x4C2, // CMSG, lua: LearnPreviewTalents (for pet?) - UMSG_UNKNOWN_1219 = 0x4C3, // not found 3.2 - UMSG_UNKNOWN_1220 = 0x4C4, // not found 3.2 - UMSG_UNKNOWN_1221 = 0x4C5, // not found 3.2 - UMSG_UNKNOWN_1222 = 0x4C6, // not found 3.2 - SMSG_ARENA_OPPONENT_UPDATE = 0x4C7, // uint64, EVENT_ARENA_OPPONENT_UPDATE - SMSG_ARENA_TEAM_CHANGE_FAILED_QUEUED = 0x4C8, // uint32 "Can't modify arena team while queued or in a match." 3.2 - UMSG_UNKNOWN_1225 = 0x4C9, // not found 3.2 - UMSG_UNKNOWN_1226 = 0x4CA, // not found 3.2 - UMSG_UNKNOWN_1227 = 0x4CB, // not found 3.2 - UMSG_UNKNOWN_1228 = 0x4CC, // not found 3.2 - SMSG_MULTIPLE_PACKETS = 0x4CD, // SMSG, handles any opcode - SMSG_FORCE_UNK1_SPEED_CHANGE = 0x4CE, // SMSG, movement related - CMSG_FORCE_UNK1_SPEED_CHANGE_ACK = 0x4CF, // movement related - SMSG_FORCE_UNK2_SPEED_CHANGE = 0x4D0, // SMSG, movement related - CMSG_FORCE_UNK2_SPEED_CHANGE_ACK = 0x4D1, // movement related - MSG_MOVE_UNKNOWN_1234 = 0x4D2, // SMSG, movement related - SMSG_SPLINE_MOVE_UNKNOWN_1235 = 0x4D3, // SMSG, movement related - SMSG_SPLINE_MOVE_UNKNOWN_1236 = 0x4D4, // SMSG, movement related - CMSG_EQUIPMENT_SET_USE = 0x4D5, // CMSG, lua: UseEquipmentSet - SMSG_EQUIPMENT_SET_USE_RESULT = 0x4D6, // SMSG, UseEquipmentSetResult? - UMSG_UNKNOWN_1239 = 0x4D7, // not found 3.2 - SMSG_UNKNOWN_1240 = 0x4D8, // SMSG, uint64, string, doing nothing - CMSG_CHAR_FACTION_CHANGE = 0x4D9, // lua: CreateCharacter (PFC client response) - SMSG_CHAR_FACTION_CHANGE = 0x4DA, // response to 1241 (PFC server response) - UMSG_UNKNOWN_1243 = 0x4DB, // not found 3.2 - UMSG_UNKNOWN_1244 = 0x4DC, // not found 3.2 - UMSG_UNKNOWN_1245 = 0x4DD, // not found 3.2 - SMSG_BATTLEFIELD_MGR_ENTRY_INVITE = 0x4DE, // uint32, EVENT_BATTLEFIELD_MGR_ENTRY_INVITE - CMSG_BATTLEFIELD_MGR_ENTRY_INVITE_RESPONSE = 0x4DF, // lua: BattlefieldMgrEntryInviteResponse - SMSG_BATTLEFIELD_MGR_ENTERED = 0x4E0, // uint32, uint8, uint8 EVENT_BATTLEFIELD_MGR_ENTERED - SMSG_BATTLEFIELD_MGR_QUEUE_INVITE = 0x4E1, // uint32 EVENT_BATTLEFIELD_MGR_QUEUE_INVITE - CMSG_BATTLEFIELD_MGR_QUEUE_INVITE_RESPONSE = 0x4E2, // lua: BattlefieldMgrQueueInviteResponse - CMSG_BATTLEFIELD_MGR_QUEUE_REQUEST = 0x4E3, // lua: BattlefieldMgrQueueRequest - SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE = 0x4E4, // uint32, uint8 EVENT_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE - SMSG_BATTLEFIELD_MGR_EJECT_PENDING = 0x4E5, // uint32 EVENT_BATTLEFIELD_MGR_EJECT_PENDING - SMSG_BATTLEFIELD_MGR_EJECTED = 0x4E6, // uint32, uint32, uint8 EVENT_BATTLEFIELD_MGR_EJECTED - CMSG_BATTLEFIELD_MGR_EXIT_REQUEST = 0x4E7, // lua: BattlefieldMgrExitRequest - SMSG_BATTLEFIELD_MGR_STATE_CHANGE = 0x4E8, // uint32, uint32 EVENT_BATTLEFIELD_MGR_STATE_CHANGE - UMSG_UNKNOWN_1257 = 0x4E9, // not found 3.2 - UMSG_UNKNOWN_1258 = 0x4EA, // not found 3.2 - MSG_SET_RAID_DIFFICULTY = 0x4EB, // lua: SetRaidDifficulty - UMSG_UNKNOWN_1260 = 0x4EC, // not found 3.2 - SMSG_TOGGLE_XP_GAIN = 0x4ED, // enable/disable XP gain console message - SMSG_GMRESPONSE_DB_ERROR = 0x4EE, // empty - SMSG_GMRESPONSE_RECEIVED = 0x4EF, // uint32, uint32, string[2000], string[4000][4] - CMSG_GMRESPONSE_RESOLVE = 0x4F0, // lua: GMResponseResolve - SMSG_GMRESPONSE_STATUS_UPDATE = 0x4F1, // uint8 (1 - EVENT_GMSURVEY_DISPLAY, 0 - EVENT_UPDATE_TICKET) - UMSG_UNKNOWN_1266 = 0x4F2, // not found 3.2 - UMSG_UNKNOWN_1267 = 0x4F3, // not found 3.2 - UMSG_UNKNOWN_1268 = 0x4F4, // not found 3.2 - UMSG_UNKNOWN_1269 = 0x4F5, // not found 3.2 - CMSG_WORLD_STATE_UI_TIMER_UPDATE = 0x4F6, - SMSG_WORLD_STATE_UI_TIMER_UPDATE = 0x4F7, - CMSG_CHAR_RACE_CHANGE = 0x4F8, // called from lua: CreateCharacter, paid race change - UMSG_UNKNOWN_1273 = 0x4F9, // not found 10554 - SMSG_TALENTS_INVOLUNTARILY_RESET = 0x4FA, // uint8 EVENT_TALENTS_INVOLUNTARILY_RESET - UMSG_UNKNOWN_1275 = 0x4FB, // not found 10554 - SMSG_UNKNOWN_1276 = 0x4FC, // does nothing in 10554 - SMSG_LOOT_SLOT_CHANGED = 0x4FD, // EVENT_LOOT_SLOT_CHANGED - UMSG_UNKNOWN_1278 = 0x4FE, // not found 10596 - CMSG_READY_FOR_ACCOUNT_DATA_TIMES = 0x4FF, // lua: ReadyForAccountDataTimes - CMSG_QUERY_QUESTS_COMPLETED = 0x500, // lua: QueryQuestsCompleted - SMSG_QUERY_QUESTS_COMPLETED_RESPONSE = 0x501, // response to 0x500 - CMSG_GM_REPORT_LAG = 0x502, // lua: GMReportLag - UMSG_UNKNOWN_1283 = 0x503, - UMSG_UNKNOWN_1284 = 0x504, - UMSG_UNKNOWN_1285 = 0x505, - SMSG_CORPSE_NOT_IN_INSTANCE = 0x506, - UMSG_UNKNOWN_1287 = 0x507, // not found - CMSG_SET_ALLOW_LOW_LEVEL_RAID1 = 0x508, // lua: SetAllowLowLevelRaid - CMSG_SET_ALLOW_LOW_LEVEL_RAID2 = 0x509, // lua: SetAllowLowLevelRaid - SMSG_CAMERA_SHAKE = 0x50A, // uint32 SpellEffectCameraShakes.dbc index, uint32 - SMSG_UPDATE_ITEM_ENCHANTMENTS = 0x50B, // some item update packet? - UMSG_UNKNOWN_1292 = 0x50C, // not found - SMSG_REDIRECT_CLIENT = 0x50D, // uint32 ip, uint16 port, uint32 unk, uint8[20] hash (ip + port, seed=sessionkey) - CMSG_REDIRECTION_FAILED = 0x50E, // something with networking - SMSG_UNKNOWN_1295 = 0x50F, // not found - disconnect - CMSG_UNKNOWN_1296 = 0x510, // something with networking - SMSG_FORCE_SEND_QUEUED_PACKETS = 0x511, // not found - crash - CMSG_REDIRECTION_AUTH_PROOF = 0x512, // something with networking - UMSG_UNKNOWN_1299 = 0x513, // not found - SMSG_UNKNOWN_1300 = 0x514, // SMSG - SMSG_UNKNOWN_1301 = 0x515, // event 0x204 (opens dungeon finder, probably for outdoor bosses) - SMSG_UNKNOWN_1302 = 0x516, // something with player movement (move event 58?) - CMSG_UNKNOWN_1303 = 0x517, // something with player movement (move event 58?) - SMSG_UNKNOWN_1304 = 0x518, // something with player movement (move event 58?), speed packet - UMSG_UNKNOWN_1305 = 0x519, // not found - UMSG_UNKNOWN_1306 = 0x51A, // not found - NUM_MSG_TYPES = 0x51B -}; - -/// Player state -enum SessionStatus -{ - STATUS_AUTHED = 0, ///< Player authenticated (_player == NULL, m_playerRecentlyLogout = false or will be reset before handler call, m_GUID have garbage) - STATUS_LOGGEDIN, ///< Player in game (_player != NULL, m_GUID == _player->GetGUID(), inWorld()) - STATUS_TRANSFER, ///< Player transferring to another map (_player != NULL, m_GUID == _player->GetGUID(), !inWorld()) - STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, ///< _player!= NULL or _player == NULL && m_playerRecentlyLogout, m_GUID store last _player guid) - STATUS_NEVER ///< Opcode not accepted from client (deprecated or server side only) -}; - -class WorldPacket; - -struct OpcodeHandler -{ - char const* name; - SessionStatus status; - void (WorldSession::*handler)(WorldPacket& recvPacket); -}; - -extern OpcodeHandler opcodeTable[NUM_MSG_TYPES]; - -/// Lookup opcode name for human understandable logging -inline const char* LookupOpcodeName(uint16 id) -{ - if (id >= NUM_MSG_TYPES) - return "Received unknown opcode, it's more than max!"; - return opcodeTable[id].name; -} -#endif -/// @} diff --git a/src/server/game/OutdoorPvP/OutdoorPvPEP.cpp b/src/server/game/OutdoorPvP/OutdoorPvPEP.cpp deleted file mode 100644 index 5691a3ce8be..00000000000 --- a/src/server/game/OutdoorPvP/OutdoorPvPEP.cpp +++ /dev/null @@ -1,765 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "OutdoorPvPEP.h" -#include "WorldPacket.h" -#include "Player.h" -#include "GameObject.h" -#include "ObjectMgr.h" -#include "ObjectAccessor.h" -#include "OutdoorPvPMgr.h" -#include "Creature.h" -#include "Language.h" -#include "World.h" -#include "GossipDef.h" - -OPvPCapturePointEP_EWT::OPvPCapturePointEP_EWT(OutdoorPvP *pvp) -: OPvPCapturePoint(pvp), m_TowerState(EP_TS_N), m_UnitsSummonedSide(0) -{ - SetCapturePointData(EPCapturePoints[EP_EWT].entry,EPCapturePoints[EP_EWT].map,EPCapturePoints[EP_EWT].x,EPCapturePoints[EP_EWT].y,EPCapturePoints[EP_EWT].z,EPCapturePoints[EP_EWT].o,EPCapturePoints[EP_EWT].rot0,EPCapturePoints[EP_EWT].rot1,EPCapturePoints[EP_EWT].rot2,EPCapturePoints[EP_EWT].rot3); - AddObject(EP_EWT_FLAGS,EPTowerFlags[EP_EWT].entry,EPTowerFlags[EP_EWT].map,EPTowerFlags[EP_EWT].x,EPTowerFlags[EP_EWT].y,EPTowerFlags[EP_EWT].z,EPTowerFlags[EP_EWT].o,EPTowerFlags[EP_EWT].rot0,EPTowerFlags[EP_EWT].rot1,EPTowerFlags[EP_EWT].rot2,EPTowerFlags[EP_EWT].rot3); -} - -void OPvPCapturePointEP_EWT::ChangeState() -{ - if (fabs(m_value) == m_maxValue) // state won't change, only phase when maxed out! - { - // if changing from controlling alliance to horde or vice versa - if (m_OldState == OBJECTIVESTATE_ALLIANCE && m_OldState != m_State) - { - sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_EWT_A)); - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_EWT] = 0; - } - else if (m_OldState == OBJECTIVESTATE_HORDE && m_OldState != m_State) - { - sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_EWT_H)); - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_EWT] = 0; - } - - uint32 artkit = 21; - - switch(m_State) - { - case OBJECTIVESTATE_ALLIANCE: - if (m_value == m_maxValue) - m_TowerState = EP_TS_A; - else - m_TowerState = EP_TS_A_P; - artkit = 2; - SummonSupportUnitAtNorthpassTower(ALLIANCE); - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_EWT] = ALLIANCE; - if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_EWT_A)); - break; - case OBJECTIVESTATE_HORDE: - if (m_value == -m_maxValue) - m_TowerState = EP_TS_H; - else - m_TowerState = EP_TS_H_P; - artkit = 1; - SummonSupportUnitAtNorthpassTower(HORDE); - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_EWT] = HORDE; - if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_EWT_H)); - break; - case OBJECTIVESTATE_NEUTRAL: - m_TowerState = EP_TS_N; - break; - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - m_TowerState = EP_TS_N_A; - break; - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - m_TowerState = EP_TS_N_H; - break; - } - - GameObject* flag = HashMapHolder::Find(m_capturePointGUID); - GameObject* flag2 = HashMapHolder::Find(m_Objects[EP_EWT_FLAGS]); - if (flag) - { - flag->SetGoArtKit(artkit); - } - if (flag2) - { - flag2->SetGoArtKit(artkit); - } - - UpdateTowerState(); - - // complete quest objective - if (m_TowerState == EP_TS_A || m_TowerState == EP_TS_H) - SendObjectiveComplete(EP_EWT_CM, 0); - } -} - -void OPvPCapturePointEP_EWT::SendChangePhase() -{ - // send this too, sometimes the slider disappears, dunno why :( - SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); - // send these updates to only the ones in this objective - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); - // send this too, sometimes it resets :S - SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); -} - -void OPvPCapturePointEP_EWT::FillInitialWorldStates(WorldPacket &data) -{ - data << EP_EWT_A << uint32(bool(m_TowerState & EP_TS_A)); - data << EP_EWT_H << uint32(bool(m_TowerState & EP_TS_H)); - data << EP_EWT_A_P << uint32(bool(m_TowerState & EP_TS_A_P)); - data << EP_EWT_H_P << uint32(bool(m_TowerState & EP_TS_H_P)); - data << EP_EWT_N_A << uint32(bool(m_TowerState & EP_TS_N_A)); - data << EP_EWT_N_H << uint32(bool(m_TowerState & EP_TS_N_H)); - data << EP_EWT_N << uint32(bool(m_TowerState & EP_TS_N)); -} - -void OPvPCapturePointEP_EWT::UpdateTowerState() -{ - m_PvP->SendUpdateWorldState(EP_EWT_A , bool(m_TowerState & EP_TS_A)); - m_PvP->SendUpdateWorldState(EP_EWT_H , bool(m_TowerState & EP_TS_H)); - m_PvP->SendUpdateWorldState(EP_EWT_A_P , bool(m_TowerState & EP_TS_A_P)); - m_PvP->SendUpdateWorldState(EP_EWT_H_P , bool(m_TowerState & EP_TS_H_P)); - m_PvP->SendUpdateWorldState(EP_EWT_N_A , bool(m_TowerState & EP_TS_N_A)); - m_PvP->SendUpdateWorldState(EP_EWT_N_H , bool(m_TowerState & EP_TS_N_H)); - m_PvP->SendUpdateWorldState(EP_EWT_N , bool(m_TowerState & EP_TS_N)); -} - -bool OPvPCapturePointEP_EWT::HandlePlayerEnter(Player *plr) -{ - if (OPvPCapturePoint::HandlePlayerEnter(plr)) - { - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); - return true; - } - return false; -} - -void OPvPCapturePointEP_EWT::HandlePlayerLeave(Player *plr) -{ - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 0); - OPvPCapturePoint::HandlePlayerLeave(plr); -} - -void OPvPCapturePointEP_EWT::SummonSupportUnitAtNorthpassTower(uint32 team) -{ - if (m_UnitsSummonedSide != team) - { - m_UnitsSummonedSide = team; - const creature_type * ct = NULL; - if (team == ALLIANCE) - ct=EP_EWT_Summons_A; - else - ct=EP_EWT_Summons_H; - - for (int i = 0; i < EP_EWT_NUM_CREATURES; ++i) - { - DelCreature(i); - AddCreature(i,ct[i].entry,ct[i].teamval,ct[i].map,ct[i].x,ct[i].y,ct[i].z,ct[i].o,1000000); - } - } -} - -// NPT -OPvPCapturePointEP_NPT::OPvPCapturePointEP_NPT(OutdoorPvP *pvp) -: OPvPCapturePoint(pvp), m_TowerState(EP_TS_N), m_SummonedGOSide(0) -{ - SetCapturePointData(EPCapturePoints[EP_NPT].entry,EPCapturePoints[EP_NPT].map,EPCapturePoints[EP_NPT].x,EPCapturePoints[EP_NPT].y,EPCapturePoints[EP_NPT].z,EPCapturePoints[EP_NPT].o,EPCapturePoints[EP_NPT].rot0,EPCapturePoints[EP_NPT].rot1,EPCapturePoints[EP_NPT].rot2,EPCapturePoints[EP_NPT].rot3); - AddObject(EP_NPT_FLAGS,EPTowerFlags[EP_NPT].entry,EPTowerFlags[EP_NPT].map,EPTowerFlags[EP_NPT].x,EPTowerFlags[EP_NPT].y,EPTowerFlags[EP_NPT].z,EPTowerFlags[EP_NPT].o,EPTowerFlags[EP_NPT].rot0,EPTowerFlags[EP_NPT].rot1,EPTowerFlags[EP_NPT].rot2,EPTowerFlags[EP_NPT].rot3); -} - -void OPvPCapturePointEP_NPT::ChangeState() -{ - if (fabs(m_value) == m_maxValue) // state won't change, only phase when maxed out! - { - // if changing from controlling alliance to horde or vice versa - if (m_OldState == OBJECTIVESTATE_ALLIANCE && m_OldState != m_State) - { - sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_NPT_A)); - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_NPT] = 0; - } - else if (m_OldState == OBJECTIVESTATE_HORDE && m_OldState != m_State) - { - sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_NPT_H)); - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_NPT] = 0; - } - - uint32 artkit = 21; - - switch(m_State) - { - case OBJECTIVESTATE_ALLIANCE: - if (m_value == m_maxValue) - m_TowerState = EP_TS_A; - else - m_TowerState = EP_TS_A_P; - artkit = 2; - SummonGO(ALLIANCE); - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_NPT] = ALLIANCE; - if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_NPT_A)); - break; - case OBJECTIVESTATE_HORDE: - if (m_value == -m_maxValue) - m_TowerState = EP_TS_H; - else - m_TowerState = EP_TS_H_P; - artkit = 1; - SummonGO(HORDE); - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_NPT] = HORDE; - if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_NPT_H)); - break; - case OBJECTIVESTATE_NEUTRAL: - m_TowerState = EP_TS_N; - m_SummonedGOSide = 0; - DelObject(EP_NPT_BUFF); - break; - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - m_TowerState = EP_TS_N_A; - break; - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - m_TowerState = EP_TS_N_H; - break; - } - - GameObject* flag = HashMapHolder::Find(m_capturePointGUID); - GameObject* flag2 = HashMapHolder::Find(m_Objects[EP_NPT_FLAGS]); - if (flag) - { - flag->SetGoArtKit(artkit); - } - if (flag2) - { - flag2->SetGoArtKit(artkit); - } - - UpdateTowerState(); - - // complete quest objective - if (m_TowerState == EP_TS_A || m_TowerState == EP_TS_H) - SendObjectiveComplete(EP_NPT_CM, 0); - } -} - -void OPvPCapturePointEP_NPT::SendChangePhase() -{ - // send this too, sometimes the slider disappears, dunno why :( - SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); - // send these updates to only the ones in this objective - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); - // send this too, sometimes it resets :S - SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); -} - -void OPvPCapturePointEP_NPT::FillInitialWorldStates(WorldPacket &data) -{ - data << EP_NPT_A << uint32(bool(m_TowerState & EP_TS_A)); - data << EP_NPT_H << uint32(bool(m_TowerState & EP_TS_H)); - data << EP_NPT_A_P << uint32(bool(m_TowerState & EP_TS_A_P)); - data << EP_NPT_H_P << uint32(bool(m_TowerState & EP_TS_H_P)); - data << EP_NPT_N_A << uint32(bool(m_TowerState & EP_TS_N_A)); - data << EP_NPT_N_H << uint32(bool(m_TowerState & EP_TS_N_H)); - data << EP_NPT_N << uint32(bool(m_TowerState & EP_TS_N)); -} - -void OPvPCapturePointEP_NPT::UpdateTowerState() -{ - m_PvP->SendUpdateWorldState(EP_NPT_A , bool(m_TowerState & EP_TS_A)); - m_PvP->SendUpdateWorldState(EP_NPT_H , bool(m_TowerState & EP_TS_H)); - m_PvP->SendUpdateWorldState(EP_NPT_A_P , bool(m_TowerState & EP_TS_A_P)); - m_PvP->SendUpdateWorldState(EP_NPT_H_P , bool(m_TowerState & EP_TS_H_P)); - m_PvP->SendUpdateWorldState(EP_NPT_N_A , bool(m_TowerState & EP_TS_N_A)); - m_PvP->SendUpdateWorldState(EP_NPT_N_H , bool(m_TowerState & EP_TS_N_H)); - m_PvP->SendUpdateWorldState(EP_NPT_N , bool(m_TowerState & EP_TS_N)); -} - -bool OPvPCapturePointEP_NPT::HandlePlayerEnter(Player *plr) -{ - if (OPvPCapturePoint::HandlePlayerEnter(plr)) - { - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); - return true; - } - return false; -} - -void OPvPCapturePointEP_NPT::HandlePlayerLeave(Player *plr) -{ - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 0); - OPvPCapturePoint::HandlePlayerLeave(plr); -} - -void OPvPCapturePointEP_NPT::SummonGO(uint32 team) -{ - if (m_SummonedGOSide != team) - { - m_SummonedGOSide = team; - DelObject(EP_NPT_BUFF); - AddObject(EP_NPT_BUFF,EP_NPT_LordaeronShrine.entry,EP_NPT_LordaeronShrine.map,EP_NPT_LordaeronShrine.x,EP_NPT_LordaeronShrine.y,EP_NPT_LordaeronShrine.z,EP_NPT_LordaeronShrine.o,EP_NPT_LordaeronShrine.rot0,EP_NPT_LordaeronShrine.rot1,EP_NPT_LordaeronShrine.rot2,EP_NPT_LordaeronShrine.rot3); - GameObject * go = HashMapHolder::Find(m_Objects[EP_NPT_BUFF]); - if (go) - go->SetUInt32Value(GAMEOBJECT_FACTION,(team == ALLIANCE ? 84 : 83)); - } -} - -// CGT -OPvPCapturePointEP_CGT::OPvPCapturePointEP_CGT(OutdoorPvP *pvp) -: OPvPCapturePoint(pvp), m_TowerState(EP_TS_N), m_GraveyardSide(0) -{ - SetCapturePointData(EPCapturePoints[EP_CGT].entry,EPCapturePoints[EP_CGT].map,EPCapturePoints[EP_CGT].x,EPCapturePoints[EP_CGT].y,EPCapturePoints[EP_CGT].z,EPCapturePoints[EP_CGT].o,EPCapturePoints[EP_CGT].rot0,EPCapturePoints[EP_CGT].rot1,EPCapturePoints[EP_CGT].rot2,EPCapturePoints[EP_CGT].rot3); - AddObject(EP_CGT_FLAGS,EPTowerFlags[EP_CGT].entry,EPTowerFlags[EP_CGT].map,EPTowerFlags[EP_CGT].x,EPTowerFlags[EP_CGT].y,EPTowerFlags[EP_CGT].z,EPTowerFlags[EP_CGT].o,EPTowerFlags[EP_CGT].rot0,EPTowerFlags[EP_CGT].rot1,EPTowerFlags[EP_CGT].rot2,EPTowerFlags[EP_CGT].rot3); -} - -void OPvPCapturePointEP_CGT::ChangeState() -{ - if (fabs(m_value) == m_maxValue) // state won't change, only phase when maxed out! - { - // if changing from controlling alliance to horde or vice versa - if (m_OldState == OBJECTIVESTATE_ALLIANCE && m_OldState != m_State) - { - sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_CGT_A)); - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_CGT] = 0; - } - else if (m_OldState == OBJECTIVESTATE_HORDE && m_OldState != m_State) - { - sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_CGT_H)); - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_CGT] = 0; - } - - uint32 artkit = 21; - - switch(m_State) - { - case OBJECTIVESTATE_ALLIANCE: - if (m_value == m_maxValue) - m_TowerState = EP_TS_A; - else - m_TowerState = EP_TS_A_P; - artkit = 2; - LinkGraveYard(ALLIANCE); - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_CGT] = ALLIANCE; - if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_CGT_A)); - break; - case OBJECTIVESTATE_HORDE: - if (m_value == -m_maxValue) - m_TowerState = EP_TS_H; - else - m_TowerState = EP_TS_H_P; - artkit = 1; - LinkGraveYard(HORDE); - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_CGT] = HORDE; - if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_CGT_H)); - break; - case OBJECTIVESTATE_NEUTRAL: - m_TowerState = EP_TS_N; - break; - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - m_TowerState = EP_TS_N_A; - break; - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - m_TowerState = EP_TS_N_H; - break; - } - - GameObject* flag = HashMapHolder::Find(m_capturePointGUID); - GameObject* flag2 = HashMapHolder::Find(m_Objects[EP_CGT_FLAGS]); - if (flag) - { - flag->SetGoArtKit(artkit); - } - if (flag2) - { - flag2->SetGoArtKit(artkit); - } - - UpdateTowerState(); - - // complete quest objective - if (m_TowerState == EP_TS_A || m_TowerState == EP_TS_H) - SendObjectiveComplete(EP_CGT_CM, 0); - } -} - -void OPvPCapturePointEP_CGT::SendChangePhase() -{ - // send this too, sometimes the slider disappears, dunno why :( - SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); - // send these updates to only the ones in this objective - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); - // send this too, sometimes it resets :S - SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); -} - -void OPvPCapturePointEP_CGT::FillInitialWorldStates(WorldPacket &data) -{ - data << EP_CGT_A << uint32(bool(m_TowerState & EP_TS_A)); - data << EP_CGT_H << uint32(bool(m_TowerState & EP_TS_H)); - data << EP_CGT_A_P << uint32(bool(m_TowerState & EP_TS_A_P)); - data << EP_CGT_H_P << uint32(bool(m_TowerState & EP_TS_H_P)); - data << EP_CGT_N_A << uint32(bool(m_TowerState & EP_TS_N_A)); - data << EP_CGT_N_H << uint32(bool(m_TowerState & EP_TS_N_H)); - data << EP_CGT_N << uint32(bool(m_TowerState & EP_TS_N)); -} - -void OPvPCapturePointEP_CGT::UpdateTowerState() -{ - m_PvP->SendUpdateWorldState(EP_CGT_A , bool(m_TowerState & EP_TS_A)); - m_PvP->SendUpdateWorldState(EP_CGT_H , bool(m_TowerState & EP_TS_H)); - m_PvP->SendUpdateWorldState(EP_CGT_A_P , bool(m_TowerState & EP_TS_A_P)); - m_PvP->SendUpdateWorldState(EP_CGT_H_P , bool(m_TowerState & EP_TS_H_P)); - m_PvP->SendUpdateWorldState(EP_CGT_N_A , bool(m_TowerState & EP_TS_N_A)); - m_PvP->SendUpdateWorldState(EP_CGT_N_H , bool(m_TowerState & EP_TS_N_H)); - m_PvP->SendUpdateWorldState(EP_CGT_N , bool(m_TowerState & EP_TS_N)); -} - -bool OPvPCapturePointEP_CGT::HandlePlayerEnter(Player *plr) -{ - if (OPvPCapturePoint::HandlePlayerEnter(plr)) - { - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); - return true; - } - return false; -} - -void OPvPCapturePointEP_CGT::HandlePlayerLeave(Player *plr) -{ - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 0); - OPvPCapturePoint::HandlePlayerLeave(plr); -} - -void OPvPCapturePointEP_CGT::LinkGraveYard(uint32 team) -{ - if (m_GraveyardSide != team) - { - m_GraveyardSide = team; - objmgr.RemoveGraveYardLink(EP_GraveYardId,EP_GraveYardZone,team,false); - objmgr.AddGraveYardLink(EP_GraveYardId,EP_GraveYardZone,team,false); - } -} - -// PWT -OPvPCapturePointEP_PWT::OPvPCapturePointEP_PWT(OutdoorPvP *pvp) -: OPvPCapturePoint(pvp), m_TowerState(EP_TS_N), m_FlightMasterSpawned(0) -{ - SetCapturePointData(EPCapturePoints[EP_PWT].entry,EPCapturePoints[EP_PWT].map,EPCapturePoints[EP_PWT].x,EPCapturePoints[EP_PWT].y,EPCapturePoints[EP_PWT].z,EPCapturePoints[EP_PWT].o,EPCapturePoints[EP_PWT].rot0,EPCapturePoints[EP_PWT].rot1,EPCapturePoints[EP_PWT].rot2,EPCapturePoints[EP_PWT].rot3); - AddObject(EP_PWT_FLAGS,EPTowerFlags[EP_PWT].entry,EPTowerFlags[EP_PWT].map,EPTowerFlags[EP_PWT].x,EPTowerFlags[EP_PWT].y,EPTowerFlags[EP_PWT].z,EPTowerFlags[EP_PWT].o,EPTowerFlags[EP_PWT].rot0,EPTowerFlags[EP_PWT].rot1,EPTowerFlags[EP_PWT].rot2,EPTowerFlags[EP_PWT].rot3); -} - -void OPvPCapturePointEP_PWT::ChangeState() -{ - if (fabs(m_value) == m_maxValue) // state won't change, only phase when maxed out! - { - // if changing from controlling alliance to horde or vice versa - if (m_OldState == OBJECTIVESTATE_ALLIANCE && m_OldState != m_State) - { - sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_PWT_A)); - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_PWT] = 0; - } - else if (m_OldState == OBJECTIVESTATE_HORDE && m_OldState != m_State) - { - sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_PWT_H)); - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_PWT] = 0; - } - - uint32 artkit = 21; - - switch(m_State) - { - case OBJECTIVESTATE_ALLIANCE: - if (m_value == m_maxValue) - m_TowerState = EP_TS_A; - else - m_TowerState = EP_TS_A_P; - SummonFlightMaster(ALLIANCE); - artkit = 2; - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_PWT] = ALLIANCE; - if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_PWT_A)); - break; - case OBJECTIVESTATE_HORDE: - if (m_value == -m_maxValue) - m_TowerState = EP_TS_H; - else - m_TowerState = EP_TS_H_P; - SummonFlightMaster(HORDE); - artkit = 1; - ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_PWT] = HORDE; - if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_PWT_H)); - break; - case OBJECTIVESTATE_NEUTRAL: - m_TowerState = EP_TS_N; - DelCreature(EP_PWT_FLIGHTMASTER); - m_FlightMasterSpawned = 0; - break; - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - m_TowerState = EP_TS_N_A; - break; - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - m_TowerState = EP_TS_N_H; - break; - } - - GameObject* flag = HashMapHolder::Find(m_capturePointGUID); - GameObject* flag2 = HashMapHolder::Find(m_Objects[EP_PWT_FLAGS]); - if (flag) - { - flag->SetGoArtKit(artkit); - } - if (flag2) - { - flag2->SetGoArtKit(artkit); - } - - UpdateTowerState(); - - // complete quest objective - if (m_TowerState == EP_TS_A || m_TowerState == EP_TS_H) - SendObjectiveComplete(EP_PWT_CM, 0); - } -} - -void OPvPCapturePointEP_PWT::SendChangePhase() -{ - // send this too, sometimes the slider disappears, dunno why :( - SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); - // send these updates to only the ones in this objective - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); - // send this too, sometimes it resets :S - SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); -} - -void OPvPCapturePointEP_PWT::FillInitialWorldStates(WorldPacket &data) -{ - data << EP_PWT_A << uint32(bool(m_TowerState & EP_TS_A)); - data << EP_PWT_H << uint32(bool(m_TowerState & EP_TS_H)); - data << EP_PWT_A_P << uint32(bool(m_TowerState & EP_TS_A_P)); - data << EP_PWT_H_P << uint32(bool(m_TowerState & EP_TS_H_P)); - data << EP_PWT_N_A << uint32(bool(m_TowerState & EP_TS_N_A)); - data << EP_PWT_N_H << uint32(bool(m_TowerState & EP_TS_N_H)); - data << EP_PWT_N << uint32(bool(m_TowerState & EP_TS_N)); -} - -void OPvPCapturePointEP_PWT::UpdateTowerState() -{ - m_PvP->SendUpdateWorldState(EP_PWT_A , bool(m_TowerState & EP_TS_A)); - m_PvP->SendUpdateWorldState(EP_PWT_H , bool(m_TowerState & EP_TS_H)); - m_PvP->SendUpdateWorldState(EP_PWT_A_P , bool(m_TowerState & EP_TS_A_P)); - m_PvP->SendUpdateWorldState(EP_PWT_H_P , bool(m_TowerState & EP_TS_H_P)); - m_PvP->SendUpdateWorldState(EP_PWT_N_A , bool(m_TowerState & EP_TS_N_A)); - m_PvP->SendUpdateWorldState(EP_PWT_N_H , bool(m_TowerState & EP_TS_N_H)); - m_PvP->SendUpdateWorldState(EP_PWT_N , bool(m_TowerState & EP_TS_N)); -} - -bool OPvPCapturePointEP_PWT::HandlePlayerEnter(Player *plr) -{ - if (OPvPCapturePoint::HandlePlayerEnter(plr)) - { - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); - return true; - } - return false; -} - -void OPvPCapturePointEP_PWT::HandlePlayerLeave(Player *plr) -{ - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 0); - OPvPCapturePoint::HandlePlayerLeave(plr); -} - -void OPvPCapturePointEP_PWT::SummonFlightMaster(uint32 team) -{ - if (m_FlightMasterSpawned != team) - { - m_FlightMasterSpawned = team; - DelCreature(EP_PWT_FLIGHTMASTER); - AddCreature(EP_PWT_FLIGHTMASTER,EP_PWT_FlightMaster.entry,team,EP_PWT_FlightMaster.map,EP_PWT_FlightMaster.x,EP_PWT_FlightMaster.y,EP_PWT_FlightMaster.z,EP_PWT_FlightMaster.o); - } -} - -// ep -OutdoorPvPEP::OutdoorPvPEP() -{ - m_TypeId = OUTDOOR_PVP_EP; - memset(EP_Controls,0,sizeof(EP_Controls)); - m_AllianceTowersControlled = 0; - m_HordeTowersControlled = 0; -} - -bool OutdoorPvPEP::SetupOutdoorPvP() -{ - for (int i = 0; i < EPBuffZonesNum; ++i) - RegisterZone(EPBuffZones[i]); - - AddCapturePoint(new OPvPCapturePointEP_EWT(this)); - AddCapturePoint(new OPvPCapturePointEP_PWT(this)); - AddCapturePoint(new OPvPCapturePointEP_CGT(this)); - AddCapturePoint(new OPvPCapturePointEP_NPT(this)); - return true; -} - -bool OutdoorPvPEP::Update(uint32 diff) -{ - if (OutdoorPvP::Update(diff)) - { - m_AllianceTowersControlled = 0; - m_HordeTowersControlled = 0; - for (int i = 0; i < EP_TOWER_NUM; ++i) - { - if (EP_Controls[i] == ALLIANCE) - ++m_AllianceTowersControlled; - else if (EP_Controls[i] == HORDE) - ++m_HordeTowersControlled; - SendUpdateWorldState(EP_UI_TOWER_COUNT_A,m_AllianceTowersControlled); - SendUpdateWorldState(EP_UI_TOWER_COUNT_H,m_HordeTowersControlled); - BuffTeams(); - } - return true; - } - return false; -} - -void OutdoorPvPEP::HandlePlayerEnterZone(Player * plr, uint32 zone) -{ - // add buffs - if (plr->GetTeam() == ALLIANCE) - { - if (m_AllianceTowersControlled && m_AllianceTowersControlled < 5) - plr->CastSpell(plr,EP_AllianceBuffs[m_AllianceTowersControlled-1],true); - } - else - { - if (m_HordeTowersControlled && m_HordeTowersControlled < 5) - plr->CastSpell(plr,EP_HordeBuffs[m_HordeTowersControlled-1],true); - } - OutdoorPvP::HandlePlayerEnterZone(plr,zone); -} - -void OutdoorPvPEP::HandlePlayerLeaveZone(Player * plr, uint32 zone) -{ - // remove buffs - if (plr->GetTeam() == ALLIANCE) - { - for (int i = 0; i < 4; ++i) - plr->RemoveAurasDueToSpell(EP_AllianceBuffs[i]); - } - else - { - for (int i = 0; i < 4; ++i) - plr->RemoveAurasDueToSpell(EP_HordeBuffs[i]); - } - OutdoorPvP::HandlePlayerLeaveZone(plr, zone); -} - -void OutdoorPvPEP::BuffTeams() -{ - for (PlayerSet::iterator itr = m_players[0].begin(); itr != m_players[0].end(); ++itr) - { - Player * plr = *itr; - { - for (int i = 0; i < 4; ++i) - plr->RemoveAurasDueToSpell(EP_AllianceBuffs[i]); - if (m_AllianceTowersControlled && m_AllianceTowersControlled < 5) - plr->CastSpell(plr,EP_AllianceBuffs[m_AllianceTowersControlled-1],true); - } - } - for (PlayerSet::iterator itr = m_players[1].begin(); itr != m_players[1].end(); ++itr) - { - Player * plr = *itr; - { - for (int i = 0; i < 4; ++i) - plr->RemoveAurasDueToSpell(EP_HordeBuffs[i]); - if (m_HordeTowersControlled && m_HordeTowersControlled < 5) - plr->CastSpell(plr,EP_HordeBuffs[m_HordeTowersControlled-1],true); - } - } -} - -void OutdoorPvPEP::FillInitialWorldStates(WorldPacket & data) -{ - data << EP_UI_TOWER_COUNT_A << m_AllianceTowersControlled; - data << EP_UI_TOWER_COUNT_H << m_HordeTowersControlled; - data << EP_UI_TOWER_SLIDER_DISPLAY << uint32(0); - data << EP_UI_TOWER_SLIDER_POS << uint32(50); - data << EP_UI_TOWER_SLIDER_N << uint32(100); - for (OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - { - itr->second->FillInitialWorldStates(data); - } -} - -void OutdoorPvPEP::SendRemoveWorldStates(Player *plr) -{ - plr->SendUpdateWorldState(EP_UI_TOWER_COUNT_A,0); - plr->SendUpdateWorldState(EP_UI_TOWER_COUNT_H,0); - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY,0); - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS,0); - plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_N,0); - - plr->SendUpdateWorldState(EP_EWT_A,0); - plr->SendUpdateWorldState(EP_EWT_H,0); - plr->SendUpdateWorldState(EP_EWT_N,0); - plr->SendUpdateWorldState(EP_EWT_A_P,0); - plr->SendUpdateWorldState(EP_EWT_H_P,0); - plr->SendUpdateWorldState(EP_EWT_N_A,0); - plr->SendUpdateWorldState(EP_EWT_N_H,0); - - plr->SendUpdateWorldState(EP_PWT_A,0); - plr->SendUpdateWorldState(EP_PWT_H,0); - plr->SendUpdateWorldState(EP_PWT_N,0); - plr->SendUpdateWorldState(EP_PWT_A_P,0); - plr->SendUpdateWorldState(EP_PWT_H_P,0); - plr->SendUpdateWorldState(EP_PWT_N_A,0); - plr->SendUpdateWorldState(EP_PWT_N_H,0); - - plr->SendUpdateWorldState(EP_NPT_A,0); - plr->SendUpdateWorldState(EP_NPT_H,0); - plr->SendUpdateWorldState(EP_NPT_N,0); - plr->SendUpdateWorldState(EP_NPT_A_P,0); - plr->SendUpdateWorldState(EP_NPT_H_P,0); - plr->SendUpdateWorldState(EP_NPT_N_A,0); - plr->SendUpdateWorldState(EP_NPT_N_H,0); - - plr->SendUpdateWorldState(EP_CGT_A,0); - plr->SendUpdateWorldState(EP_CGT_H,0); - plr->SendUpdateWorldState(EP_CGT_N,0); - plr->SendUpdateWorldState(EP_CGT_A_P,0); - plr->SendUpdateWorldState(EP_CGT_H_P,0); - plr->SendUpdateWorldState(EP_CGT_N_A,0); - plr->SendUpdateWorldState(EP_CGT_N_H,0); -} - diff --git a/src/server/game/OutdoorPvP/OutdoorPvPEP.h b/src/server/game/OutdoorPvP/OutdoorPvPEP.h deleted file mode 100644 index 071d6bcde2d..00000000000 --- a/src/server/game/OutdoorPvP/OutdoorPvPEP.h +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OUTDOOR_PVP_EP_ -#define OUTDOOR_PVP_EP_ - -#include "OutdoorPvPImpl.h" - -#include "DBCStructure.h" - -const uint32 EP_AllianceBuffs[4] = {11413, 11414, 11415, 1386}; - -const uint32 EP_HordeBuffs[4] = {30880, 30683, 30682, 29520}; - -const uint32 EP_GraveYardZone = 139; - -const uint32 EP_GraveYardId = 927; - -const uint32 EPBuffZonesNum = 3; - -const uint32 EP_EWT_CM = 17690; -const uint32 EP_CGT_CM = 17689; -const uint32 EP_NPT_CM = 17696; -const uint32 EP_PWT_CM = 17698; - -const uint32 EPBuffZones[EPBuffZonesNum] = {139, 2017, 2057}; - -enum EP_TaxiNodes { - EP_CGT_Taxi = 87, - EP_EWT_Taxi = 86, - EP_NPT_Taxi = 85, - EP_PWT_Taxi = 84 -}; - -enum EP_EastwallTowerWorldStates { - EP_EWT_A = 2354, - EP_EWT_H = 2356, - EP_EWT_A_P = 2357, // ally progressing - EP_EWT_H_P = 2358, - EP_EWT_N_A = 2359, // ally conquested - EP_EWT_N_H = 2360, - EP_EWT_N = 2361 -}; - -enum EP_NorthpassTowerWorldStates { - EP_NPT_N = 2352, - EP_NPT_N_A = 2362, - EP_NPT_N_H = 2363, - EP_NPT_A_P = 2364, - EP_NPT_H_P = 2365, - EP_NPT_A = 2372, - EP_NPT_H = 2373 -}; - -enum EP_PlagewoodTowerWorldStates { - EP_PWT_N_A = 2366, - EP_PWT_N_H = 2353, //2367 not present! use neutral! - EP_PWT_A_P = 2368, - EP_PWT_H_P = 2369, - EP_PWT_A = 2370, - EP_PWT_H = 2371, - EP_PWT_N = 2353 -}; - -enum EP_CrownGuardTowerWorldStates { - EP_CGT_N_A = 2374, - EP_CGT_N_H = 2375, - EP_CGT_A_P = 2376, - EP_CGT_H_P = 2377, - EP_CGT_A = 2378, - EP_CGT_H = 2379, - EP_CGT_N = 2355 -}; - -enum EP_WorldStates { - EP_UI_TOWER_SLIDER_DISPLAY = 2426, - EP_UI_TOWER_SLIDER_POS = 2427, - EP_UI_TOWER_SLIDER_N = 2428, - - EP_UI_TOWER_COUNT_A = 2327, - EP_UI_TOWER_COUNT_H = 2328 -}; - -enum EP_Summons { - EP_EWT_COMMANDER = 0, - EP_EWT_SOLDIER1, - EP_EWT_SOLDIER2, - EP_EWT_SOLDIER3, - EP_EWT_SOLDIER4, - EP_PWT_FLIGHTMASTER, -}; - -enum EP_GoSummons { - EP_NPT_BUFF = 0, - EP_NPT_FLAGS, - EP_EWT_FLAGS, - EP_CGT_FLAGS, - EP_PWT_FLAGS -}; - -enum EP_Towers { - EP_EWT = 0, // plaguelands 03 - EP_NPT,// plaguelands 01 - EP_PWT,// plaguelands 04 - EP_CGT,// plaguelands 02 - EP_TOWER_NUM -}; - -const go_type EPCapturePoints[EP_TOWER_NUM] = { - {182097,0,2574.51,-4794.89,144.704,-1.45003,-0.097056,0.095578,-0.656229,0.742165}, - {181899,0,3181.08,-4379.36,174.123,-2.03472,-0.065392,0.119494,-0.842275,0.521553}, - {182098,0,2962.71,-3042.31,154.789,2.08426,-0.074807,-0.113837,0.855928,0.49883}, - {182096,0,1860.85,-3731.23,196.716,-2.53214,0.033967,-0.131914,0.944741,-0.298177} -}; - -const go_type EPTowerFlags[EP_TOWER_NUM] = { - {182106,0,2569.60,-4772.93,115.399,2.72271,0,0,0.978148,0.207912}, - {182106,0,3148.17,-4365.51,145.029,1.53589,0,0,0.694658,0.71934}, - {182106,0,2992.63,-3022.95,125.593,3.03687,0,0,0.99863,0.052336}, - {182106,0,1838.42,-3703.56,167.713,0.890118,0,0,0.430511,0.902585} -}; - -const uint32 EPTowerPlayerEnterEvents[EP_TOWER_NUM] = {10691,10699,10701,10705}; - -const uint32 EPTowerPlayerLeaveEvents[EP_TOWER_NUM] = {10692,10698,10700,10704}; - -const uint32 EP_NUM_CREATURES = 6; -const uint32 EP_EWT_NUM_CREATURES = 5; - -// one lordaeron commander, 4 soldiers -// should be spawned at EWT and follow a path, but trans-grid pathing isn't safe, so summon them directly at NPT -const creature_type EP_EWT_Summons_A[EP_EWT_NUM_CREATURES] = { - {17635,469,0, 3167.61,-4352.09,138.20,4.5811}, - {17647,469,0, 3172.74,-4352.99,139.14,4.9873}, - {17647,469,0, 3165.89,-4354.46,138.67,3.7244}, - {17647,469,0, 3164.65,-4350.26,138.22,2.4794}, - {17647,469,0, 3169.91,-4349.68,138.37,0.7444} -}; - -const creature_type EP_EWT_Summons_H[EP_EWT_NUM_CREATURES] = { - {17995,67,0, 3167.61,-4352.09,138.20,4.5811}, - {17996,67,0, 3172.74,-4352.99,139.14,4.9873}, - {17996,67,0, 3165.89,-4354.46,138.67,3.7244}, - {17996,67,0, 3164.65,-4350.26,138.22,2.4794}, - {17996,67,0, 3169.91,-4349.68,138.37,0.7444} -}; - -enum EP_TowerStates { - EP_TS_N = 1, - EP_TS_N_A = 2, - EP_TS_N_H = 4, - EP_TS_A_P = 8, - EP_TS_H_P = 16, - EP_TS_A = 32, - EP_TS_H = 64 -}; - -// when spawning, pay attention at setting the faction manually! -const creature_type EP_PWT_FlightMaster = {17209,0,0,2987.5,-3049.11,120.126,5.75959}; - -// after spawning, modify the faction so that only the controller will be able to use it with SetUInt32Value(GAMEOBJECT_FACTION, faction_id); -const go_type EP_NPT_LordaeronShrine = {181682,0,3167.72,-4355.91,138.785,1.69297,0,0,0.748956,0.66262}; - -class OutdoorPvPEP; - -class OPvPCapturePointEP_EWT : public OPvPCapturePoint -{ -friend class OutdoorPvPEP; -public: - OPvPCapturePointEP_EWT(OutdoorPvP * pvp); - void ChangeState(); - void SendChangePhase(); - void FillInitialWorldStates(WorldPacket & data); - // used when player is activated/inactivated in the area - bool HandlePlayerEnter(Player * plr); - void HandlePlayerLeave(Player * plr); -protected: - void SummonSupportUnitAtNorthpassTower(uint32 team); - void UpdateTowerState(); -protected: - uint32 m_TowerState; - uint32 m_UnitsSummonedSide; -}; - -class OPvPCapturePointEP_NPT : public OPvPCapturePoint -{ -friend class OutdoorPvPEP; -public: - OPvPCapturePointEP_NPT(OutdoorPvP * pvp); - void ChangeState(); - void SendChangePhase(); - void FillInitialWorldStates(WorldPacket & data); - // used when player is activated/inactivated in the area - bool HandlePlayerEnter(Player * plr); - void HandlePlayerLeave(Player * plr); -protected: - void SummonGO(uint32 team); - void UpdateTowerState(); -protected: - uint32 m_TowerState; - uint32 m_SummonedGOSide; -}; - -class OPvPCapturePointEP_CGT : public OPvPCapturePoint -{ -friend class OutdoorPvPEP; -public: - OPvPCapturePointEP_CGT(OutdoorPvP * pvp); - void ChangeState(); - void SendChangePhase(); - void FillInitialWorldStates(WorldPacket & data); - // used when player is activated/inactivated in the area - bool HandlePlayerEnter(Player * plr); - void HandlePlayerLeave(Player * plr); -protected: - void LinkGraveYard(uint32 team); - void UpdateTowerState(); -protected: - uint32 m_TowerState; - uint32 m_GraveyardSide; -}; - -class OPvPCapturePointEP_PWT : public OPvPCapturePoint -{ -friend class OutdoorPvPEP; -public: - OPvPCapturePointEP_PWT(OutdoorPvP * pvp); - void ChangeState(); - void SendChangePhase(); - void FillInitialWorldStates(WorldPacket & data); - // used when player is activated/inactivated in the area - bool HandlePlayerEnter(Player * plr); - void HandlePlayerLeave(Player * plr); -protected: - void SummonFlightMaster(uint32 team); - void UpdateTowerState(); -protected: - uint32 m_FlightMasterSpawned; - uint32 m_TowerState; -}; - -class OutdoorPvPEP : public OutdoorPvP -{ -friend class OPvPCapturePointEP_EWT; -friend class OPvPCapturePointEP_NPT; -friend class OPvPCapturePointEP_PWT; -friend class OPvPCapturePointEP_CGT; -public: - OutdoorPvPEP(); - bool SetupOutdoorPvP(); - void HandlePlayerEnterZone(Player *plr, uint32 zone); - void HandlePlayerLeaveZone(Player *plr, uint32 zone); - bool Update(uint32 diff); - void FillInitialWorldStates(WorldPacket &data); - void SendRemoveWorldStates(Player * plr); - void BuffTeams(); -private: - // how many towers are controlled - uint32 EP_Controls[EP_TOWER_NUM]; - uint32 m_AllianceTowersControlled; - uint32 m_HordeTowersControlled; -}; - -#endif - diff --git a/src/server/game/OutdoorPvP/OutdoorPvPHP.cpp b/src/server/game/OutdoorPvP/OutdoorPvPHP.cpp deleted file mode 100644 index f4f73d015ce..00000000000 --- a/src/server/game/OutdoorPvP/OutdoorPvPHP.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "OutdoorPvPHP.h" -#include "OutdoorPvP.h" -#include "OutdoorPvPMgr.h" -#include "Player.h" -#include "WorldPacket.h" -#include "World.h" -#include "ObjectMgr.h" -#include "Language.h" - -const uint32 HP_LANG_LOOSE_A[HP_TOWER_NUM] = {LANG_OPVP_HP_LOOSE_BROKENHILL_A,LANG_OPVP_HP_LOOSE_OVERLOOK_A,LANG_OPVP_HP_LOOSE_STADIUM_A}; - -const uint32 HP_LANG_LOOSE_H[HP_TOWER_NUM] = {LANG_OPVP_HP_LOOSE_BROKENHILL_H,LANG_OPVP_HP_LOOSE_OVERLOOK_H,LANG_OPVP_HP_LOOSE_STADIUM_H}; - -const uint32 HP_LANG_CAPTURE_A[HP_TOWER_NUM] = {LANG_OPVP_HP_CAPTURE_BROKENHILL_A,LANG_OPVP_HP_CAPTURE_OVERLOOK_A,LANG_OPVP_HP_CAPTURE_STADIUM_A}; - -const uint32 HP_LANG_CAPTURE_H[HP_TOWER_NUM] = {LANG_OPVP_HP_CAPTURE_BROKENHILL_H,LANG_OPVP_HP_CAPTURE_OVERLOOK_H,LANG_OPVP_HP_CAPTURE_STADIUM_H}; - -OPvPCapturePointHP::OPvPCapturePointHP(OutdoorPvP *pvp,OutdoorPvPHPTowerType type) -: OPvPCapturePoint(pvp), m_TowerType(type) -{ - SetCapturePointData(HPCapturePoints[type].entry, - HPCapturePoints[type].map, - HPCapturePoints[type].x, - HPCapturePoints[type].y, - HPCapturePoints[type].z, - HPCapturePoints[type].o, - HPCapturePoints[type].rot0, - HPCapturePoints[type].rot1, - HPCapturePoints[type].rot2, - HPCapturePoints[type].rot3); - AddObject(type, - HPTowerFlags[type].entry, - HPTowerFlags[type].map, - HPTowerFlags[type].x, - HPTowerFlags[type].y, - HPTowerFlags[type].z, - HPTowerFlags[type].o, - HPTowerFlags[type].rot0, - HPTowerFlags[type].rot1, - HPTowerFlags[type].rot2, - HPTowerFlags[type].rot3); -} - -OutdoorPvPHP::OutdoorPvPHP() -{ - m_TypeId = OUTDOOR_PVP_HP; -} - -bool OutdoorPvPHP::SetupOutdoorPvP() -{ - m_AllianceTowersControlled = 0; - m_HordeTowersControlled = 0; - // add the zones affected by the pvp buff - for (int i = 0; i < OutdoorPvPHPBuffZonesNum; ++i) - RegisterZone(OutdoorPvPHPBuffZones[i]); - - AddCapturePoint(new OPvPCapturePointHP(this,HP_TOWER_BROKEN_HILL)); - - AddCapturePoint(new OPvPCapturePointHP(this,HP_TOWER_OVERLOOK)); - - AddCapturePoint(new OPvPCapturePointHP(this,HP_TOWER_STADIUM)); - - return true; -} - -void OutdoorPvPHP::HandlePlayerEnterZone(Player * plr, uint32 zone) -{ - // add buffs - if (plr->GetTeam() == ALLIANCE) - { - if (m_AllianceTowersControlled >=3) - plr->CastSpell(plr,AllianceBuff,true); - } - else - { - if (m_HordeTowersControlled >=3) - plr->CastSpell(plr,HordeBuff,true); - } - OutdoorPvP::HandlePlayerEnterZone(plr,zone); -} - -void OutdoorPvPHP::HandlePlayerLeaveZone(Player * plr, uint32 zone) -{ - // remove buffs - if (plr->GetTeam() == ALLIANCE) - { - plr->RemoveAurasDueToSpell(AllianceBuff); - } - else - { - plr->RemoveAurasDueToSpell(HordeBuff); - } - OutdoorPvP::HandlePlayerLeaveZone(plr, zone); -} - -bool OutdoorPvPHP::Update(uint32 diff) -{ - bool changed = OutdoorPvP::Update(diff); - if (changed) - { - if (m_AllianceTowersControlled == 3) - TeamApplyBuff(TEAM_ALLIANCE, AllianceBuff, HordeBuff); - else if (m_HordeTowersControlled == 3) - TeamApplyBuff(TEAM_HORDE, HordeBuff, AllianceBuff); - else - { - TeamCastSpell(TEAM_ALLIANCE, -AllianceBuff); - TeamCastSpell(TEAM_HORDE, -HordeBuff); - } - SendUpdateWorldState(HP_UI_TOWER_COUNT_A, m_AllianceTowersControlled); - SendUpdateWorldState(HP_UI_TOWER_COUNT_H, m_HordeTowersControlled); - } - return changed; -} - -void OutdoorPvPHP::SendRemoveWorldStates(Player *plr) -{ - plr->SendUpdateWorldState(HP_UI_TOWER_DISPLAY_A,0); - plr->SendUpdateWorldState(HP_UI_TOWER_DISPLAY_H,0); - plr->SendUpdateWorldState(HP_UI_TOWER_COUNT_H,0); - plr->SendUpdateWorldState(HP_UI_TOWER_COUNT_A,0); - plr->SendUpdateWorldState(HP_UI_TOWER_SLIDER_N,0); - plr->SendUpdateWorldState(HP_UI_TOWER_SLIDER_POS,0); - plr->SendUpdateWorldState(HP_UI_TOWER_SLIDER_DISPLAY,0); - for (int i = 0; i < HP_TOWER_NUM; ++i) - { - plr->SendUpdateWorldState(HP_MAP_N[i],0); - plr->SendUpdateWorldState(HP_MAP_A[i],0); - plr->SendUpdateWorldState(HP_MAP_H[i],0); - } -} - -void OutdoorPvPHP::FillInitialWorldStates(WorldPacket &data) -{ - data << uint32(HP_UI_TOWER_DISPLAY_A) << uint32(1); - data << uint32(HP_UI_TOWER_DISPLAY_H) << uint32(1); - data << uint32(HP_UI_TOWER_COUNT_A) << uint32(m_AllianceTowersControlled); - data << uint32(HP_UI_TOWER_COUNT_H) << uint32(m_HordeTowersControlled); - data << uint32(HP_UI_TOWER_SLIDER_DISPLAY) << uint32(0); - data << uint32(HP_UI_TOWER_SLIDER_POS) << uint32(50); - data << uint32(HP_UI_TOWER_SLIDER_N) << uint32(100); - for (OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - { - itr->second->FillInitialWorldStates(data); - } -} - -void OPvPCapturePointHP::ChangeState() -{ - uint32 field = 0; - switch(m_OldState) - { - case OBJECTIVESTATE_NEUTRAL: - field = HP_MAP_N[m_TowerType]; - break; - case OBJECTIVESTATE_ALLIANCE: - field = HP_MAP_A[m_TowerType]; - if (((OutdoorPvPHP*)m_PvP)->m_AllianceTowersControlled) - ((OutdoorPvPHP*)m_PvP)->m_AllianceTowersControlled--; - sWorld.SendZoneText(OutdoorPvPHPBuffZones[0],objmgr.GetTrinityStringForDBCLocale(HP_LANG_LOOSE_A[m_TowerType])); - break; - case OBJECTIVESTATE_HORDE: - field = HP_MAP_H[m_TowerType]; - if (((OutdoorPvPHP*)m_PvP)->m_HordeTowersControlled) - ((OutdoorPvPHP*)m_PvP)->m_HordeTowersControlled--; - sWorld.SendZoneText(OutdoorPvPHPBuffZones[0],objmgr.GetTrinityStringForDBCLocale(HP_LANG_LOOSE_H[m_TowerType])); - break; - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - field = HP_MAP_N[m_TowerType]; - break; - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - field = HP_MAP_N[m_TowerType]; - break; - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - field = HP_MAP_A[m_TowerType]; - break; - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - field = HP_MAP_H[m_TowerType]; - break; - } - - // send world state update - if (field) - { - m_PvP->SendUpdateWorldState(field, 0); - field = 0; - } - uint32 artkit = 21; - uint32 artkit2 = HP_TowerArtKit_N[m_TowerType]; - switch(m_State) - { - case OBJECTIVESTATE_NEUTRAL: - field = HP_MAP_N[m_TowerType]; - break; - case OBJECTIVESTATE_ALLIANCE: - field = HP_MAP_A[m_TowerType]; - artkit = 2; - artkit2 = HP_TowerArtKit_A[m_TowerType]; - if (((OutdoorPvPHP*)m_PvP)->m_AllianceTowersControlled<3) - ((OutdoorPvPHP*)m_PvP)->m_AllianceTowersControlled++; - sWorld.SendZoneText(OutdoorPvPHPBuffZones[0],objmgr.GetTrinityStringForDBCLocale(HP_LANG_CAPTURE_A[m_TowerType])); - break; - case OBJECTIVESTATE_HORDE: - field = HP_MAP_H[m_TowerType]; - artkit = 1; - artkit2 = HP_TowerArtKit_H[m_TowerType]; - if (((OutdoorPvPHP*)m_PvP)->m_HordeTowersControlled<3) - ((OutdoorPvPHP*)m_PvP)->m_HordeTowersControlled++; - sWorld.SendZoneText(OutdoorPvPHPBuffZones[0],objmgr.GetTrinityStringForDBCLocale(HP_LANG_CAPTURE_H[m_TowerType])); - break; - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - field = HP_MAP_N[m_TowerType]; - break; - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - field = HP_MAP_N[m_TowerType]; - break; - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - field = HP_MAP_A[m_TowerType]; - artkit = 2; - artkit2 = HP_TowerArtKit_A[m_TowerType]; - break; - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - field = HP_MAP_H[m_TowerType]; - artkit = 1; - artkit2 = HP_TowerArtKit_H[m_TowerType]; - break; - } - - GameObject* flag = HashMapHolder::Find(m_capturePointGUID); - GameObject* flag2 = HashMapHolder::Find(m_Objects[m_TowerType]); - if (flag) - { - flag->SetGoArtKit(artkit); - } - if (flag2) - { - flag2->SetGoArtKit(artkit2); - } - - // send world state update - if (field) - m_PvP->SendUpdateWorldState(field, 1); - - // complete quest objective - if (m_State == OBJECTIVESTATE_ALLIANCE || m_State == OBJECTIVESTATE_HORDE) - SendObjectiveComplete(HP_CREDITMARKER[m_TowerType], 0); -} - -void OPvPCapturePointHP::SendChangePhase() -{ - SendUpdateWorldState(HP_UI_TOWER_SLIDER_N, m_neutralValuePct); - // send these updates to only the ones in this objective - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - SendUpdateWorldState(HP_UI_TOWER_SLIDER_POS, phase); - // send this too, sometimes the slider disappears, dunno why :( - SendUpdateWorldState(HP_UI_TOWER_SLIDER_DISPLAY, 1); -} - -void OPvPCapturePointHP::FillInitialWorldStates(WorldPacket &data) -{ - switch(m_State) - { - case OBJECTIVESTATE_ALLIANCE: - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - data << uint32(HP_MAP_N[m_TowerType]) << uint32(0); - data << uint32(HP_MAP_A[m_TowerType]) << uint32(1); - data << uint32(HP_MAP_H[m_TowerType]) << uint32(0); - break; - case OBJECTIVESTATE_HORDE: - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - data << uint32(HP_MAP_N[m_TowerType]) << uint32(0); - data << uint32(HP_MAP_A[m_TowerType]) << uint32(0); - data << uint32(HP_MAP_H[m_TowerType]) << uint32(1); - break; - case OBJECTIVESTATE_NEUTRAL: - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - default: - data << uint32(HP_MAP_N[m_TowerType]) << uint32(1); - data << uint32(HP_MAP_A[m_TowerType]) << uint32(0); - data << uint32(HP_MAP_H[m_TowerType]) << uint32(0); - break; - } -} - -bool OPvPCapturePointHP::HandlePlayerEnter(Player *plr) -{ - if (OPvPCapturePoint::HandlePlayerEnter(plr)) - { - plr->SendUpdateWorldState(HP_UI_TOWER_SLIDER_DISPLAY, 1); - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - plr->SendUpdateWorldState(HP_UI_TOWER_SLIDER_POS, phase); - plr->SendUpdateWorldState(HP_UI_TOWER_SLIDER_N, m_neutralValuePct); - return true; - } - return false; -} - -void OPvPCapturePointHP::HandlePlayerLeave(Player *plr) -{ - plr->SendUpdateWorldState(HP_UI_TOWER_SLIDER_DISPLAY, 0); - OPvPCapturePoint::HandlePlayerLeave(plr); -} - -void OutdoorPvPHP::HandleKillImpl(Player *plr, Unit * killed) -{ - if (killed->GetTypeId() != TYPEID_PLAYER) - return; - - if (plr->GetTeam() == ALLIANCE && killed->ToPlayer()->GetTeam() != ALLIANCE) - plr->CastSpell(plr,AlliancePlayerKillReward,true); - else if (plr->GetTeam() == HORDE && killed->ToPlayer()->GetTeam() != HORDE) - plr->CastSpell(plr,HordePlayerKillReward,true); -} diff --git a/src/server/game/OutdoorPvP/OutdoorPvPHP.h b/src/server/game/OutdoorPvP/OutdoorPvPHP.h deleted file mode 100644 index e23eb1f9369..00000000000 --- a/src/server/game/OutdoorPvP/OutdoorPvPHP.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OUTDOOR_PVP_HP_ -#define OUTDOOR_PVP_HP_ - -#include "OutdoorPvPImpl.h" - -#define OutdoorPvPHPBuffZonesNum 6 - // HP, citadel, ramparts, blood furnace, shattered halls, mag's lair -const uint32 OutdoorPvPHPBuffZones[OutdoorPvPHPBuffZonesNum] = { 3483, 3563, 3562, 3713, 3714, 3836 }; - -enum OutdoorPvPHPSpells -{ - AlliancePlayerKillReward = 32155, - HordePlayerKillReward = 32158, - AllianceBuff = 32071, - HordeBuff = 32049 -}; - -enum OutdoorPvPHPTowerType{ - HP_TOWER_BROKEN_HILL = 0, - HP_TOWER_OVERLOOK = 1, - HP_TOWER_STADIUM = 2, - HP_TOWER_NUM = 3 -}; - -const uint32 HP_CREDITMARKER[HP_TOWER_NUM] = {19032,19028,19029}; - -const uint32 HP_CapturePointEvent_Enter[HP_TOWER_NUM] = {11404,11396,11388}; - -const uint32 HP_CapturePointEvent_Leave[HP_TOWER_NUM] = {11403,11395,11387}; - -enum OutdoorPvPHPWorldStates{ - HP_UI_TOWER_DISPLAY_A = 0x9ba, - HP_UI_TOWER_DISPLAY_H = 0x9b9, - - HP_UI_TOWER_COUNT_H = 0x9ae, - HP_UI_TOWER_COUNT_A = 0x9ac, - - HP_UI_TOWER_SLIDER_N = 2475, - HP_UI_TOWER_SLIDER_POS = 2474, - HP_UI_TOWER_SLIDER_DISPLAY = 2473 -}; - -const uint32 HP_MAP_N[HP_TOWER_NUM] = {0x9b5,0x9b2,0x9a8}; - -const uint32 HP_MAP_A[HP_TOWER_NUM] = {0x9b3,0x9b0,0x9a7}; - -const uint32 HP_MAP_H[HP_TOWER_NUM] = {0x9b4,0x9b1,0x9a6}; - -const uint32 HP_TowerArtKit_A[HP_TOWER_NUM] = {65,62,67}; - -const uint32 HP_TowerArtKit_H[HP_TOWER_NUM] = {64,61,68}; - -const uint32 HP_TowerArtKit_N[HP_TOWER_NUM] = {66,63,69}; - -const go_type HPCapturePoints[HP_TOWER_NUM] = { - {182175,530,-471.462,3451.09,34.6432,0.174533,0,0,0.087156,0.996195}, // 0 - Broken Hill - {182174,530,-184.889,3476.93,38.205,-0.017453,0,0,0.008727,-0.999962}, // 1 - Overlook - {182173,530,-290.016,3702.42,56.6729,0.034907,0,0,0.017452,0.999848} // 2 - Stadium -}; - -const go_type HPTowerFlags[HP_TOWER_NUM] = { - {183514,530,-467.078,3528.17,64.7121,3.14159,0,0,1,0}, // 0 broken hill - {182525,530,-187.887,3459.38,60.0403,-3.12414,0,0,0.999962,-0.008727}, // 1 overlook - {183515,530,-289.610,3696.83,75.9447,3.12414,0,0,0.999962,0.008727} // 2 stadium -}; - -class OPvPCapturePointHP : public OPvPCapturePoint -{ -public: - OPvPCapturePointHP(OutdoorPvP * pvp, OutdoorPvPHPTowerType type); - void ChangeState(); - void SendChangePhase(); - void FillInitialWorldStates(WorldPacket & data); - // used when player is activated/inactivated in the area - bool HandlePlayerEnter(Player * plr); - void HandlePlayerLeave(Player * plr); -private: - OutdoorPvPHPTowerType m_TowerType; -}; - -class OutdoorPvPHP : public OutdoorPvP -{ -friend class OPvPCapturePointHP; -public: - OutdoorPvPHP(); - bool SetupOutdoorPvP(); - void HandlePlayerEnterZone(Player *plr, uint32 zone); - void HandlePlayerLeaveZone(Player *plr, uint32 zone); - bool Update(uint32 diff); - void FillInitialWorldStates(WorldPacket &data); - void SendRemoveWorldStates(Player * plr); - void HandleKillImpl(Player * plr, Unit * killed); -private: - // how many towers are controlled - uint32 m_AllianceTowersControlled; - uint32 m_HordeTowersControlled; -}; - -#endif - diff --git a/src/server/game/OutdoorPvP/OutdoorPvPNA.cpp b/src/server/game/OutdoorPvP/OutdoorPvPNA.cpp deleted file mode 100644 index 2360c1e0fb0..00000000000 --- a/src/server/game/OutdoorPvP/OutdoorPvPNA.cpp +++ /dev/null @@ -1,664 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "OutdoorPvPNA.h" -#include "Player.h" -#include "ObjectMgr.h" -#include "OutdoorPvPMgr.h" -#include "WorldPacket.h" -#include "Language.h" -#include "World.h" - -OutdoorPvPNA::OutdoorPvPNA() -{ - m_TypeId = OUTDOOR_PVP_NA; -} - -void OutdoorPvPNA::HandleKillImpl(Player *plr, Unit * killed) -{ - if (killed->GetTypeId() == TYPEID_PLAYER && plr->GetTeam() != killed->ToPlayer()->GetTeam()) - { - plr->KilledMonsterCredit(NA_CREDIT_MARKER,0); // 0 guid, btw it isn't even used in killedmonster function :S - if (plr->GetTeam() == ALLIANCE) - plr->CastSpell(plr,NA_KILL_TOKEN_ALLIANCE,true); - else - plr->CastSpell(plr,NA_KILL_TOKEN_HORDE,true); - } -} - -uint32 OPvPCapturePointNA::GetAliveGuardsCount() -{ - uint32 cnt = 0; - for (std::map::iterator itr = m_Creatures.begin(); itr != m_Creatures.end(); ++itr) - { - switch(itr->first) - { - case NA_NPC_GUARD_01: - case NA_NPC_GUARD_02: - case NA_NPC_GUARD_03: - case NA_NPC_GUARD_04: - case NA_NPC_GUARD_05: - case NA_NPC_GUARD_06: - case NA_NPC_GUARD_07: - case NA_NPC_GUARD_08: - case NA_NPC_GUARD_09: - case NA_NPC_GUARD_10: - case NA_NPC_GUARD_11: - case NA_NPC_GUARD_12: - case NA_NPC_GUARD_13: - case NA_NPC_GUARD_14: - case NA_NPC_GUARD_15: - { - if (Creature * cr = HashMapHolder::Find(itr->second)) - { - if (cr->isAlive()) - ++cnt; - } - else if (CreatureData const * cd = objmgr.GetCreatureData(GUID_LOPART(itr->second))) - { - if (!cd->is_dead) - ++cnt; - } - } - break; - default: - break; - } - } - return cnt; -} - -void OPvPCapturePointNA::SpawnNPCsForTeam(uint32 team) -{ - const creature_type * creatures = NULL; - if (team == ALLIANCE) - creatures=AllianceControlNPCs; - else if (team == HORDE) - creatures=HordeControlNPCs; - else - return; - for (int i = 0; i < NA_CONTROL_NPC_NUM; ++i) - AddCreature(i,creatures[i].entry,creatures[i].teamval,creatures[i].map,creatures[i].x,creatures[i].y,creatures[i].z,creatures[i].o,1000000); -} - -void OPvPCapturePointNA::DeSpawnNPCs() -{ - for (int i = 0; i < NA_CONTROL_NPC_NUM; ++i) - DelCreature(i); -} - -void OPvPCapturePointNA::SpawnGOsForTeam(uint32 team) -{ - const go_type * gos = NULL; - if (team == ALLIANCE) - gos=AllianceControlGOs; - else if (team == HORDE) - gos=HordeControlGOs; - else - return; - for (int i = 0; i < NA_CONTROL_GO_NUM; ++i) - { - if (i == NA_ROOST_S || - i == NA_ROOST_W || - i == NA_ROOST_N || - i == NA_ROOST_E || - i == NA_BOMB_WAGON_S || - i == NA_BOMB_WAGON_W || - i == NA_BOMB_WAGON_N || - i == NA_BOMB_WAGON_E) - continue; // roosts and bomb wagons are spawned when someone uses the matching destroyed roost - AddObject(i,gos[i].entry,gos[i].map,gos[i].x,gos[i].y,gos[i].z,gos[i].o,gos[i].rot0,gos[i].rot1,gos[i].rot2,gos[i].rot3); - } -} - -void OPvPCapturePointNA::DeSpawnGOs() -{ - for (int i = 0; i < NA_CONTROL_GO_NUM; ++i) - { - DelObject(i); - } -} - -void OPvPCapturePointNA::FactionTakeOver(uint32 team) -{ - if (m_ControllingFaction) - objmgr.RemoveGraveYardLink(NA_HALAA_GRAVEYARD,NA_HALAA_GRAVEYARD_ZONE,m_ControllingFaction,false); - if (m_ControllingFaction == ALLIANCE) - sWorld.SendZoneText(NA_HALAA_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_NA_LOOSE_A)); - else if (m_ControllingFaction == HORDE) - sWorld.SendZoneText(NA_HALAA_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_NA_LOOSE_H)); - - m_ControllingFaction = team; - if (m_ControllingFaction) - objmgr.AddGraveYardLink(NA_HALAA_GRAVEYARD,NA_HALAA_GRAVEYARD_ZONE,m_ControllingFaction,false); - DeSpawnGOs(); - DeSpawnNPCs(); - SpawnGOsForTeam(team); - SpawnNPCsForTeam(team); - m_GuardsAlive = NA_GUARDS_MAX; - m_capturable = false; - this->UpdateHalaaWorldState(); - if (team == ALLIANCE) - { - m_WyvernStateSouth = WYVERN_NEU_HORDE; - m_WyvernStateNorth = WYVERN_NEU_HORDE; - m_WyvernStateEast = WYVERN_NEU_HORDE; - m_WyvernStateWest = WYVERN_NEU_HORDE; - m_PvP->TeamApplyBuff(TEAM_ALLIANCE, NA_CAPTURE_BUFF); - m_PvP->SendUpdateWorldState(NA_UI_HORDE_GUARDS_SHOW, 0); - m_PvP->SendUpdateWorldState(NA_UI_ALLIANCE_GUARDS_SHOW, 1); - m_PvP->SendUpdateWorldState(NA_UI_GUARDS_LEFT, m_GuardsAlive); - sWorld.SendZoneText(NA_HALAA_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_NA_CAPTURE_A)); - } - else - { - m_WyvernStateSouth = WYVERN_NEU_ALLIANCE; - m_WyvernStateNorth = WYVERN_NEU_ALLIANCE; - m_WyvernStateEast = WYVERN_NEU_ALLIANCE; - m_WyvernStateWest = WYVERN_NEU_ALLIANCE; - m_PvP->TeamApplyBuff(TEAM_HORDE, NA_CAPTURE_BUFF); - m_PvP->SendUpdateWorldState(NA_UI_HORDE_GUARDS_SHOW, 1); - m_PvP->SendUpdateWorldState(NA_UI_ALLIANCE_GUARDS_SHOW, 0); - m_PvP->SendUpdateWorldState(NA_UI_GUARDS_LEFT, m_GuardsAlive); - sWorld.SendZoneText(NA_HALAA_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_NA_CAPTURE_H)); - } - UpdateWyvernRoostWorldState(NA_ROOST_S); - UpdateWyvernRoostWorldState(NA_ROOST_N); - UpdateWyvernRoostWorldState(NA_ROOST_W); - UpdateWyvernRoostWorldState(NA_ROOST_E); -} - -bool OPvPCapturePointNA::HandlePlayerEnter(Player *plr) -{ - if (OPvPCapturePoint::HandlePlayerEnter(plr)) - { - plr->SendUpdateWorldState(NA_UI_TOWER_SLIDER_DISPLAY, 1); - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - plr->SendUpdateWorldState(NA_UI_TOWER_SLIDER_POS, phase); - plr->SendUpdateWorldState(NA_UI_TOWER_SLIDER_N, m_neutralValuePct); - return true; - } - return false; -} - -void OPvPCapturePointNA::HandlePlayerLeave(Player *plr) -{ - plr->SendUpdateWorldState(NA_UI_TOWER_SLIDER_DISPLAY, 0); - OPvPCapturePoint::HandlePlayerLeave(plr); -} - -OPvPCapturePointNA::OPvPCapturePointNA(OutdoorPvP *pvp) : -OPvPCapturePoint(pvp), m_capturable(true), m_GuardsAlive(0), m_ControllingFaction(0), -m_HalaaState(HALAA_N), m_WyvernStateSouth(0), m_WyvernStateNorth(0), m_WyvernStateWest(0), -m_WyvernStateEast(0), m_RespawnTimer(NA_RESPAWN_TIME), m_GuardCheckTimer(NA_GUARD_CHECK_TIME) -{ - SetCapturePointData(182210,530,-1572.57,7945.3,-22.475,2.05949,0,0,0.857167,0.515038); -} - -bool OutdoorPvPNA::SetupOutdoorPvP() -{ -// m_TypeId = OUTDOOR_PVP_NA; _MUST_ be set in ctor, because of spawns cleanup - // add the zones affected by the pvp buff - RegisterZone(NA_BUFF_ZONE); - - // halaa - m_obj = new OPvPCapturePointNA(this); - if (!m_obj) - return false; - AddCapturePoint(m_obj); - - return true; -} - -void OutdoorPvPNA::HandlePlayerEnterZone(Player * plr, uint32 zone) -{ - // add buffs - if (plr->GetTeam() == m_obj->m_ControllingFaction) - plr->CastSpell(plr,NA_CAPTURE_BUFF,true); - OutdoorPvP::HandlePlayerEnterZone(plr,zone); -} - -void OutdoorPvPNA::HandlePlayerLeaveZone(Player * plr, uint32 zone) -{ - // remove buffs - plr->RemoveAurasDueToSpell(NA_CAPTURE_BUFF); - OutdoorPvP::HandlePlayerLeaveZone(plr, zone); -} - -void OutdoorPvPNA::FillInitialWorldStates(WorldPacket &data) -{ - m_obj->FillInitialWorldStates(data); -} - -void OPvPCapturePointNA::FillInitialWorldStates(WorldPacket &data) -{ - if (m_ControllingFaction == ALLIANCE) - { - data << NA_UI_HORDE_GUARDS_SHOW << uint32(0); - data << NA_UI_ALLIANCE_GUARDS_SHOW << uint32(1); - } - else if (m_ControllingFaction == HORDE) - { - data << NA_UI_HORDE_GUARDS_SHOW << uint32(1); - data << NA_UI_ALLIANCE_GUARDS_SHOW << uint32(0); - } - else - { - data << NA_UI_HORDE_GUARDS_SHOW << uint32(0); - data << NA_UI_ALLIANCE_GUARDS_SHOW << uint32(0); - } - - data << NA_UI_GUARDS_MAX << NA_GUARDS_MAX; - data << NA_UI_GUARDS_LEFT << uint32(m_GuardsAlive); - - data << NA_UI_TOWER_SLIDER_DISPLAY << uint32(0); - data << NA_UI_TOWER_SLIDER_POS << uint32(50); - data << NA_UI_TOWER_SLIDER_N << uint32(100); - - data << NA_MAP_WYVERN_NORTH_NEU_H << uint32(bool(m_WyvernStateNorth & WYVERN_NEU_HORDE)); - data << NA_MAP_WYVERN_NORTH_NEU_A << uint32(bool(m_WyvernStateNorth & WYVERN_NEU_ALLIANCE)); - data << NA_MAP_WYVERN_NORTH_H << uint32(bool(m_WyvernStateNorth & WYVERN_HORDE)); - data << NA_MAP_WYVERN_NORTH_A << uint32(bool(m_WyvernStateNorth & WYVERN_ALLIANCE)); - - data << NA_MAP_WYVERN_SOUTH_NEU_H << uint32(bool(m_WyvernStateSouth & WYVERN_NEU_HORDE)); - data << NA_MAP_WYVERN_SOUTH_NEU_A << uint32(bool(m_WyvernStateSouth & WYVERN_NEU_ALLIANCE)); - data << NA_MAP_WYVERN_SOUTH_H << uint32(bool(m_WyvernStateSouth & WYVERN_HORDE)); - data << NA_MAP_WYVERN_SOUTH_A << uint32(bool(m_WyvernStateSouth & WYVERN_ALLIANCE)); - - data << NA_MAP_WYVERN_WEST_NEU_H << uint32(bool(m_WyvernStateWest & WYVERN_NEU_HORDE)); - data << NA_MAP_WYVERN_WEST_NEU_A << uint32(bool(m_WyvernStateWest & WYVERN_NEU_ALLIANCE)); - data << NA_MAP_WYVERN_WEST_H << uint32(bool(m_WyvernStateWest & WYVERN_HORDE)); - data << NA_MAP_WYVERN_WEST_A << uint32(bool(m_WyvernStateWest & WYVERN_ALLIANCE)); - - data << NA_MAP_WYVERN_EAST_NEU_H << uint32(bool(m_WyvernStateEast & WYVERN_NEU_HORDE)); - data << NA_MAP_WYVERN_EAST_NEU_A << uint32(bool(m_WyvernStateEast & WYVERN_NEU_ALLIANCE)); - data << NA_MAP_WYVERN_EAST_H << uint32(bool(m_WyvernStateEast & WYVERN_HORDE)); - data << NA_MAP_WYVERN_EAST_A << uint32(bool(m_WyvernStateEast & WYVERN_ALLIANCE)); - - data << NA_MAP_HALAA_NEUTRAL << uint32(bool(m_HalaaState & HALAA_N)); - data << NA_MAP_HALAA_NEU_A << uint32(bool(m_HalaaState & HALAA_N_A)); - data << NA_MAP_HALAA_NEU_H << uint32(bool(m_HalaaState & HALAA_N_H)); - data << NA_MAP_HALAA_HORDE << uint32(bool(m_HalaaState & HALAA_H)); - data << NA_MAP_HALAA_ALLIANCE << uint32(bool(m_HalaaState & HALAA_A)); -} - -void OutdoorPvPNA::SendRemoveWorldStates(Player *plr) -{ - plr->SendUpdateWorldState(NA_UI_HORDE_GUARDS_SHOW,0); - plr->SendUpdateWorldState(NA_UI_ALLIANCE_GUARDS_SHOW,0); - plr->SendUpdateWorldState(NA_UI_GUARDS_MAX,0); - plr->SendUpdateWorldState(NA_UI_GUARDS_LEFT,0); - plr->SendUpdateWorldState(NA_UI_TOWER_SLIDER_DISPLAY,0); - plr->SendUpdateWorldState(NA_UI_TOWER_SLIDER_POS,0); - plr->SendUpdateWorldState(NA_UI_TOWER_SLIDER_N,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_NEU_H,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_NEU_A,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_H,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_A,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_NEU_H,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_NEU_A,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_H,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_A,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_WEST_NEU_H,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_WEST_NEU_A,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_WEST_H,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_WEST_A,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_EAST_NEU_H,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_EAST_NEU_A,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_EAST_H,0); - plr->SendUpdateWorldState(NA_MAP_WYVERN_EAST_A,0); - plr->SendUpdateWorldState(NA_MAP_HALAA_NEUTRAL,0); - plr->SendUpdateWorldState(NA_MAP_HALAA_NEU_A,0); - plr->SendUpdateWorldState(NA_MAP_HALAA_NEU_H,0); - plr->SendUpdateWorldState(NA_MAP_HALAA_HORDE,0); - plr->SendUpdateWorldState(NA_MAP_HALAA_ALLIANCE,0); -} - -bool OutdoorPvPNA::Update(uint32 diff) -{ - return m_obj->Update(diff); -} - -bool OPvPCapturePointNA::HandleCustomSpell(Player * plr, uint32 spellId, GameObject * /*go*/) -{ - std::vector nodes; - nodes.resize(2); - bool retval = false; - switch(spellId) - { - case NA_SPELL_FLY_NORTH: - nodes[0] = FlightPathStartNodes[NA_ROOST_N]; - nodes[1] = FlightPathEndNodes[NA_ROOST_N]; - plr->ActivateTaxiPathTo(nodes); - plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); - plr->UpdatePvP(true,true); - retval = true; - break; - case NA_SPELL_FLY_SOUTH: - nodes[0] = FlightPathStartNodes[NA_ROOST_S]; - nodes[1] = FlightPathEndNodes[NA_ROOST_S]; - plr->ActivateTaxiPathTo(nodes); - plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); - plr->UpdatePvP(true,true); - retval = true; - break; - case NA_SPELL_FLY_WEST: - nodes[0] = FlightPathStartNodes[NA_ROOST_W]; - nodes[1] = FlightPathEndNodes[NA_ROOST_W]; - plr->ActivateTaxiPathTo(nodes); - plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); - plr->UpdatePvP(true,true); - retval = true; - break; - case NA_SPELL_FLY_EAST: - nodes[0] = FlightPathStartNodes[NA_ROOST_E]; - nodes[1] = FlightPathEndNodes[NA_ROOST_E]; - plr->ActivateTaxiPathTo(nodes); - plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); - plr->UpdatePvP(true,true); - retval = true; - break; - default: - break; - } - - if (retval) - { - //Adding items - uint32 noSpaceForCount = 0; - - // check space and find places - ItemPosCountVec dest; - - int32 count = 10; - uint32 itemid = 24538; - // bomb id count - uint8 msg = plr->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemid, count, &noSpaceForCount); - if (msg != EQUIP_ERR_OK) // convert to possible store amount - count -= noSpaceForCount; - - if (count == 0 || dest.empty()) // can't add any - { - return true; - } - - Item* item = plr->StoreNewItem(dest, itemid, true); - - if (count > 0 && item) - { - plr->SendNewItem(item,count,true,false); - } - - return true; - } - return false; -} - -int32 OPvPCapturePointNA::HandleOpenGo(Player *plr, uint64 guid) -{ - uint32 retval = OPvPCapturePoint::HandleOpenGo(plr, guid); - if (retval >= 0) - { - const go_type * gos = NULL; - if (m_ControllingFaction == ALLIANCE) - gos=AllianceControlGOs; - else if (m_ControllingFaction == HORDE) - gos=HordeControlGOs; - else - return -1; - - int32 del = -1; - int32 del2 = -1; - int32 add = -1; - int32 add2 = -1; - - switch(retval) - { - case NA_DESTROYED_ROOST_S: - del = NA_DESTROYED_ROOST_S; - add = NA_ROOST_S; - add2 = NA_BOMB_WAGON_S; - if (m_ControllingFaction == HORDE) - m_WyvernStateSouth = WYVERN_ALLIANCE; - else - m_WyvernStateSouth = WYVERN_HORDE; - UpdateWyvernRoostWorldState(NA_ROOST_S); - break; - case NA_DESTROYED_ROOST_N: - del = NA_DESTROYED_ROOST_N; - add = NA_ROOST_N; - add2 = NA_BOMB_WAGON_N; - if (m_ControllingFaction == HORDE) - m_WyvernStateNorth = WYVERN_ALLIANCE; - else - m_WyvernStateNorth = WYVERN_HORDE; - UpdateWyvernRoostWorldState(NA_ROOST_N); - break; - case NA_DESTROYED_ROOST_W: - del = NA_DESTROYED_ROOST_W; - add = NA_ROOST_W; - add2 = NA_BOMB_WAGON_W; - if (m_ControllingFaction == HORDE) - m_WyvernStateWest = WYVERN_ALLIANCE; - else - m_WyvernStateWest = WYVERN_HORDE; - UpdateWyvernRoostWorldState(NA_ROOST_W); - break; - case NA_DESTROYED_ROOST_E: - del = NA_DESTROYED_ROOST_E; - add = NA_ROOST_E; - add2 = NA_BOMB_WAGON_E; - if (m_ControllingFaction == HORDE) - m_WyvernStateEast = WYVERN_ALLIANCE; - else - m_WyvernStateEast = WYVERN_HORDE; - UpdateWyvernRoostWorldState(NA_ROOST_E); - break; - case NA_BOMB_WAGON_S: - del = NA_BOMB_WAGON_S; - del2 = NA_ROOST_S; - add = NA_DESTROYED_ROOST_S; - if (m_ControllingFaction == HORDE) - m_WyvernStateSouth = WYVERN_NEU_ALLIANCE; - else - m_WyvernStateSouth = WYVERN_NEU_HORDE; - UpdateWyvernRoostWorldState(NA_ROOST_S); - break; - case NA_BOMB_WAGON_N: - del = NA_BOMB_WAGON_N; - del2 = NA_ROOST_N; - add = NA_DESTROYED_ROOST_N; - if (m_ControllingFaction == HORDE) - m_WyvernStateNorth = WYVERN_NEU_ALLIANCE; - else - m_WyvernStateNorth = WYVERN_NEU_HORDE; - UpdateWyvernRoostWorldState(NA_ROOST_N); - break; - case NA_BOMB_WAGON_W: - del = NA_BOMB_WAGON_W; - del2 = NA_ROOST_W; - add = NA_DESTROYED_ROOST_W; - if (m_ControllingFaction == HORDE) - m_WyvernStateWest = WYVERN_NEU_ALLIANCE; - else - m_WyvernStateWest = WYVERN_NEU_HORDE; - UpdateWyvernRoostWorldState(NA_ROOST_W); - break; - case NA_BOMB_WAGON_E: - del = NA_BOMB_WAGON_E; - del2 = NA_ROOST_E; - add = NA_DESTROYED_ROOST_E; - if (m_ControllingFaction == HORDE) - m_WyvernStateEast = WYVERN_NEU_ALLIANCE; - else - m_WyvernStateEast = WYVERN_NEU_HORDE; - UpdateWyvernRoostWorldState(NA_ROOST_E); - break; - default: - return -1; - break; - } - - if (del>-1) - DelObject(del); - - if (del2>-1) - DelObject(del2); - - if (add>-1) - AddObject(add,gos[add].entry,gos[add].map,gos[add].x,gos[add].y,gos[add].z,gos[add].o,gos[add].rot0,gos[add].rot1,gos[add].rot2,gos[add].rot3); - - if (add2>-1) - AddObject(add2,gos[add2].entry,gos[add2].map,gos[add2].x,gos[add2].y,gos[add2].z,gos[add2].o,gos[add2].rot0,gos[add2].rot1,gos[add2].rot2,gos[add2].rot3); - - return retval; - } - return -1; -} - -bool OPvPCapturePointNA::Update(uint32 diff) -{ - // let the controlling faction advance in phase - bool capturable = false; - if (m_ControllingFaction == ALLIANCE && m_activePlayers[0].size() > m_activePlayers[1].size()) - capturable = true; - else if (m_ControllingFaction == HORDE && m_activePlayers[0].size() < m_activePlayers[1].size()) - capturable = true; - - if (m_GuardCheckTimer < diff) - { - m_GuardCheckTimer = NA_GUARD_CHECK_TIME; - uint32 cnt = GetAliveGuardsCount(); - if (cnt != m_GuardsAlive) - { - m_GuardsAlive = cnt; - if (m_GuardsAlive == 0) - m_capturable = true; - // update the guard count for the players in zone - m_PvP->SendUpdateWorldState(NA_UI_GUARDS_LEFT,m_GuardsAlive); - } - } else m_GuardCheckTimer -= diff; - - if (m_capturable || capturable) - { - if (m_RespawnTimer < diff) - { - // if the guards have been killed, then the challenger has one hour to take over halaa. - // in case they fail to do it, the guards are respawned, and they have to start again. - if (m_ControllingFaction) - FactionTakeOver(m_ControllingFaction); - m_RespawnTimer = NA_RESPAWN_TIME; - } else m_RespawnTimer -= diff; - - return OPvPCapturePoint::Update(diff); - } - return false; -} - -void OPvPCapturePointNA::ChangeState() -{ - uint32 artkit = 21; - switch(m_State) - { - case OBJECTIVESTATE_NEUTRAL: - m_HalaaState = HALAA_N; - break; - case OBJECTIVESTATE_ALLIANCE: - m_HalaaState = HALAA_A; - FactionTakeOver(ALLIANCE); - artkit = 2; - break; - case OBJECTIVESTATE_HORDE: - m_HalaaState = HALAA_H; - FactionTakeOver(HORDE); - artkit = 1; - break; - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - m_HalaaState = HALAA_N_A; - break; - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - m_HalaaState = HALAA_N_H; - break; - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - m_HalaaState = HALAA_N_A; - artkit = 2; - break; - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - m_HalaaState = HALAA_N_H; - artkit = 1; - break; - } - - GameObject* flag = HashMapHolder::Find(m_capturePointGUID); - if (flag) - { - flag->SetGoArtKit(artkit); - } - - UpdateHalaaWorldState(); -} - -void OPvPCapturePointNA::SendChangePhase() -{ - // send this too, sometimes the slider disappears, dunno why :( - SendUpdateWorldState(NA_UI_TOWER_SLIDER_DISPLAY, 1); - // send these updates to only the ones in this objective - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - SendUpdateWorldState(NA_UI_TOWER_SLIDER_POS, phase); - SendUpdateWorldState(NA_UI_TOWER_SLIDER_N, m_neutralValuePct); -} - -void OPvPCapturePointNA::UpdateHalaaWorldState() -{ - m_PvP->SendUpdateWorldState(NA_MAP_HALAA_NEUTRAL ,uint32(bool(m_HalaaState & HALAA_N))); - m_PvP->SendUpdateWorldState(NA_MAP_HALAA_NEU_A ,uint32(bool(m_HalaaState & HALAA_N_A))); - m_PvP->SendUpdateWorldState(NA_MAP_HALAA_NEU_H ,uint32(bool(m_HalaaState & HALAA_N_H))); - m_PvP->SendUpdateWorldState(NA_MAP_HALAA_HORDE ,uint32(bool(m_HalaaState & HALAA_H))); - m_PvP->SendUpdateWorldState(NA_MAP_HALAA_ALLIANCE ,uint32(bool(m_HalaaState & HALAA_A))); -} - -void OPvPCapturePointNA::UpdateWyvernRoostWorldState(uint32 roost) -{ - switch(roost) - { - case NA_ROOST_S: - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_NEU_H,uint32(bool(m_WyvernStateSouth & WYVERN_NEU_HORDE))); - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_NEU_A,uint32(bool(m_WyvernStateSouth & WYVERN_NEU_ALLIANCE))); - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_H,uint32(bool(m_WyvernStateSouth & WYVERN_HORDE))); - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_A,uint32(bool(m_WyvernStateSouth & WYVERN_ALLIANCE))); - break; - case NA_ROOST_N: - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_NEU_H,uint32(bool(m_WyvernStateNorth & WYVERN_NEU_HORDE))); - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_NEU_A,uint32(bool(m_WyvernStateNorth & WYVERN_NEU_ALLIANCE))); - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_H,uint32(bool(m_WyvernStateNorth & WYVERN_HORDE))); - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_A,uint32(bool(m_WyvernStateNorth & WYVERN_ALLIANCE))); - break; - case NA_ROOST_W: - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_WEST_NEU_H,uint32(bool(m_WyvernStateWest & WYVERN_NEU_HORDE))); - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_WEST_NEU_A,uint32(bool(m_WyvernStateWest & WYVERN_NEU_ALLIANCE))); - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_WEST_H,uint32(bool(m_WyvernStateWest & WYVERN_HORDE))); - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_WEST_A,uint32(bool(m_WyvernStateWest & WYVERN_ALLIANCE))); - break; - case NA_ROOST_E: - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_EAST_NEU_H,uint32(bool(m_WyvernStateEast & WYVERN_NEU_HORDE))); - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_EAST_NEU_A,uint32(bool(m_WyvernStateEast & WYVERN_NEU_ALLIANCE))); - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_EAST_H,uint32(bool(m_WyvernStateEast & WYVERN_HORDE))); - m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_EAST_A,uint32(bool(m_WyvernStateEast & WYVERN_ALLIANCE))); - break; - } -} diff --git a/src/server/game/OutdoorPvP/OutdoorPvPNA.h b/src/server/game/OutdoorPvP/OutdoorPvPNA.h deleted file mode 100644 index 124f51e8040..00000000000 --- a/src/server/game/OutdoorPvP/OutdoorPvPNA.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OUTDOOR_PVP_NA_ -#define OUTDOOR_PVP_NA_ - -// TODO: "sometimes" set to neutral - -#include "OutdoorPvPImpl.h" -enum OutdoorPvPNASpells -{ - NA_KILL_TOKEN_ALLIANCE = 33005, - NA_KILL_TOKEN_HORDE = 33004, - NA_CAPTURE_BUFF = 33795 // strength of the halaani -}; -// kill credit for pks -const uint32 NA_CREDIT_MARKER = 24867; -const uint32 NA_GUARDS_MAX = 15; - -const uint32 NA_BUFF_ZONE = 3518; - -const uint32 NA_HALAA_GRAVEYARD = 993; - -const uint32 NA_HALAA_GRAVEYARD_ZONE = 3518; // need to add zone id, not area id - -const uint32 NA_RESPAWN_TIME = 3600000; // one hour to capture after defeating all guards - -const uint32 NA_GUARD_CHECK_TIME = 500; // every half second - -enum OutdoorPvPNAWorldStates{ - NA_UI_HORDE_GUARDS_SHOW = 2503, - NA_UI_ALLIANCE_GUARDS_SHOW = 2502, - NA_UI_GUARDS_MAX = 2493, - NA_UI_GUARDS_LEFT = 2491, - - NA_UI_TOWER_SLIDER_DISPLAY = 2495, - NA_UI_TOWER_SLIDER_POS = 2494, - NA_UI_TOWER_SLIDER_N = 2497, - - NA_MAP_WYVERN_NORTH_NEU_H = 2762, - NA_MAP_WYVERN_NORTH_NEU_A = 2662, - NA_MAP_WYVERN_NORTH_H = 2663, - NA_MAP_WYVERN_NORTH_A = 2664, - - NA_MAP_WYVERN_SOUTH_NEU_H = 2760, - NA_MAP_WYVERN_SOUTH_NEU_A = 2670, - NA_MAP_WYVERN_SOUTH_H = 2668, - NA_MAP_WYVERN_SOUTH_A = 2669, - - NA_MAP_WYVERN_WEST_NEU_H = 2761, - NA_MAP_WYVERN_WEST_NEU_A = 2667, - NA_MAP_WYVERN_WEST_H = 2665, - NA_MAP_WYVERN_WEST_A = 2666, - - NA_MAP_WYVERN_EAST_NEU_H = 2763, - NA_MAP_WYVERN_EAST_NEU_A = 2659, - NA_MAP_WYVERN_EAST_H = 2660, - NA_MAP_WYVERN_EAST_A = 2661, - - NA_MAP_HALAA_NEUTRAL = 2671, - NA_MAP_HALAA_NEU_A = 2676, - NA_MAP_HALAA_NEU_H = 2677, - NA_MAP_HALAA_HORDE = 2672, - NA_MAP_HALAA_ALLIANCE = 2673 -}; - -const uint32 FLIGHT_NODES_NUM = 4; - -// used to access the elements of Horde/AllyControlGOs -enum ControlGOTypes{ - NA_ROOST_S = 0, - NA_ROOST_W = 1, - NA_ROOST_N = 2, - NA_ROOST_E = 3, - - NA_BOMB_WAGON_S = 4, - NA_BOMB_WAGON_W = 5, - NA_BOMB_WAGON_N = 6, - NA_BOMB_WAGON_E = 7, - - NA_DESTROYED_ROOST_S = 8, - NA_DESTROYED_ROOST_W = 9, - NA_DESTROYED_ROOST_N = 10, - NA_DESTROYED_ROOST_E = 11, - - NA_CONTROL_GO_NUM = 12 -}; - -const uint32 FlightPathStartNodes[FLIGHT_NODES_NUM] = {103,105,107,109}; -const uint32 FlightPathEndNodes[FLIGHT_NODES_NUM] = {104,106,108,110}; - -enum FlightSpellsNA{ - NA_SPELL_FLY_SOUTH = 32059, - NA_SPELL_FLY_WEST = 32068, - NA_SPELL_FLY_NORTH = 32075, - NA_SPELL_FLY_EAST = 32081 -}; - -// spawned when the alliance is attacking, horde is in control -const go_type HordeControlGOs[NA_CONTROL_GO_NUM] = { - {182267,530,-1815.8,8036.51,-26.2354,-2.89725,0,0,0.992546,-0.121869}, //ALLY_ROOST_SOUTH - {182280,530,-1507.95,8132.1,-19.5585,-1.3439,0,0,0.622515,-0.782608}, //ALLY_ROOST_WEST - {182281,530,-1384.52,7779.33,-11.1663,-0.575959,0,0,0.284015,-0.95882}, //ALLY_ROOST_NORTH - {182282,530,-1650.11,7732.56,-15.4505,-2.80998,0,0,0.986286,-0.165048}, //ALLY_ROOST_EAST - - {182222,530,-1825.4022,8039.2602,-26.08,-2.89725,0,0,0.992546,-0.121869}, //HORDE_BOMB_WAGON_SOUTH - {182272,530,-1515.37,8136.91,-20.42,-1.3439,0,0,0.622515,-0.782608}, //HORDE_BOMB_WAGON_WEST - {182273,530,-1377.95,7773.44,-10.31,-0.575959,0,0,0.284015,-0.95882}, //HORDE_BOMB_WAGON_NORTH - {182274,530,-1659.87,7733.15,-15.75,-2.80998,0,0,0.986286,-0.165048}, //HORDE_BOMB_WAGON_EAST - - {182266,530,-1815.8,8036.51,-26.2354,-2.89725,0,0,0.992546,-0.121869}, //DESTROYED_ALLY_ROOST_SOUTH - {182275,530,-1507.95,8132.1,-19.5585,-1.3439,0,0,0.622515,-0.782608}, //DESTROYED_ALLY_ROOST_WEST - {182276,530,-1384.52,7779.33,-11.1663,-0.575959,0,0,0.284015,-0.95882}, //DESTROYED_ALLY_ROOST_NORTH - {182277,530,-1650.11,7732.56,-15.4505,-2.80998,0,0,0.986286,-0.165048} //DESTROYED_ALLY_ROOST_EAST -}; - -// spawned when the horde is attacking, alliance is in control -const go_type AllianceControlGOs[NA_CONTROL_GO_NUM] = { - {182301,530,-1815.8,8036.51,-26.2354,-2.89725,0,0,0.992546,-0.121869}, //HORDE_ROOST_SOUTH - {182302,530,-1507.95,8132.1,-19.5585,-1.3439,0,0,0.622515,-0.782608}, //HORDE_ROOST_WEST - {182303,530,-1384.52,7779.33,-11.1663,-0.575959,0,0,0.284015,-0.95882}, //HORDE_ROOST_NORTH - {182304,530,-1650.11,7732.56,-15.4505,-2.80998,0,0,0.986286,-0.165048}, //HORDE_ROOST_EAST - - {182305,530,-1825.4022,8039.2602,-26.08,-2.89725,0,0,0.992546,-0.121869}, //ALLY_BOMB_WAGON_SOUTH - {182306,530,-1515.37,8136.91,-20.42,-1.3439,0,0,0.622515,-0.782608}, //ALLY_BOMB_WAGON_WEST - {182307,530,-1377.95,7773.44,-10.31,-0.575959,0,0,0.284015,-0.95882}, //ALLY_BOMB_WAGON_NORTH - {182308,530,-1659.87,7733.15,-15.75,-2.80998,0,0,0.986286,-0.165048}, //ALLY_BOMB_WAGON_EAST - - {182297,530,-1815.8,8036.51,-26.2354,-2.89725,0,0,0.992546,-0.121869}, //DESTROYED_HORDE_ROOST_SOUTH - {182298,530,-1507.95,8132.1,-19.5585,-1.3439,0,0,0.622515,-0.782608}, //DESTROYED_HORDE_ROOST_WEST - {182299,530,-1384.52,7779.33,-11.1663,-0.575959,0,0,0.284015,-0.95882}, //DESTROYED_HORDE_ROOST_NORTH - {182300,530,-1650.11,7732.56,-15.4505,-2.80998,0,0,0.986286,-0.165048} //DESTROYED_HORDE_ROOST_EAST -}; - -enum ControlNPCTypes{ - NA_NPC_RESEARCHER = 0, - NA_NPC_QUARTERMASTER, - NA_NPC_BLADE_MERCHANT, - NA_NPC_FOOD_MERCHANT, - NA_NPC_AMMO, - - NA_NPC_GUARD_01, - NA_NPC_GUARD_02, - NA_NPC_GUARD_03, - NA_NPC_GUARD_04, - NA_NPC_GUARD_05, - NA_NPC_GUARD_06, - NA_NPC_GUARD_07, - NA_NPC_GUARD_08, - NA_NPC_GUARD_09, - NA_NPC_GUARD_10, - NA_NPC_GUARD_11, - NA_NPC_GUARD_12, - NA_NPC_GUARD_13, - NA_NPC_GUARD_14, - NA_NPC_GUARD_15, - - NA_CONTROL_NPC_NUM -}; - -const creature_type HordeControlNPCs[NA_CONTROL_NPC_NUM] = { - {18816,67,530,-1523.92,7951.76,-17.6942,3.51172}, - {18821,67,530,-1527.75,7952.46,-17.6948,3.99317}, - {21474,67,530,-1520.14,7927.11,-20.2527,3.39389}, - {21484,67,530,-1524.84,7930.34,-20.182,3.6405}, - {21483,67,530,-1570.01,7993.8,-22.4505,5.02655}, - {18192,67,530,-1654.06,8000.46,-26.59,3.37}, - {18192,67,530,-1487.18,7899.1,-19.53,0.954}, - {18192,67,530,-1480.88,7908.79,-19.19,4.485}, - {18192,67,530,-1540.56,7995.44,-20.45,0.947}, - {18192,67,530,-1546.95,8000.85,-20.72,6.035}, - {18192,67,530,-1595.31,7860.53,-21.51,3.747}, - {18192,67,530,-1642.31,7995.59,-25.8,3.317}, - {18192,67,530,-1545.46,7995.35,-20.63,1.094}, - {18192,67,530,-1487.58,7907.99,-19.27,5.567}, - {18192,67,530,-1651.54,7988.56,-26.5289,2.98451}, - {18192,67,530,-1602.46,7866.43,-22.1177,4.74729}, - {18192,67,530,-1591.22,7875.29,-22.3536,4.34587}, - {18192,67,530,-1550.6,7944.45,-21.63,3.559}, - {18192,67,530,-1545.57,7935.83,-21.13,3.448}, - {18192,67,530,-1550.86,7937.56,-21.7,3.801} -}; - -const creature_type AllianceControlNPCs[NA_CONTROL_NPC_NUM] = { - {18817,469,530,-1591.18,8020.39,-22.2042,4.59022}, - {18822,469,530,-1588.0,8019.0,-22.2042,4.06662}, - {21485,469,530,-1521.93,7927.37,-20.2299,3.24631}, - {21487,469,530,-1540.33,7971.95,-20.7186,3.07178}, - {21488,469,530,-1570.01,7993.8,-22.4505,5.02655}, - {18256,469,530,-1654.06,8000.46,-26.59,3.37}, - {18256,469,530,-1487.18,7899.1,-19.53,0.954}, - {18256,469,530,-1480.88,7908.79,-19.19,4.485}, - {18256,469,530,-1540.56,7995.44,-20.45,0.947}, - {18256,469,530,-1546.95,8000.85,-20.72,6.035}, - {18256,469,530,-1595.31,7860.53,-21.51,3.747}, - {18256,469,530,-1642.31,7995.59,-25.8,3.317}, - {18256,469,530,-1545.46,7995.35,-20.63,1.094}, - {18256,469,530,-1487.58,7907.99,-19.27,5.567}, - {18256,469,530,-1651.54,7988.56,-26.5289,2.98451}, - {18256,469,530,-1602.46,7866.43,-22.1177,4.74729}, - {18256,469,530,-1591.22,7875.29,-22.3536,4.34587}, - {18256,469,530,-1603.75,8000.36,-24.18,4.516}, - {18256,469,530,-1585.73,7994.68,-23.29,4.439}, - {18256,469,530,-1595.5,7991.27,-23.53,4.738} -}; - -enum WyvernStates{ - WYVERN_NEU_HORDE = 1, - WYVERN_NEU_ALLIANCE = 2, - WYVERN_HORDE = 4, - WYVERN_ALLIANCE = 8 -}; - -enum HalaaStates{ - HALAA_N = 1, - HALAA_N_A = 2, - HALAA_A = 4, - HALAA_N_H = 8, - HALAA_H = 16 -}; - -class Unit; -class Creature; -class OutdoorPvPNA; -class OPvPCapturePointNA : public OPvPCapturePoint -{ -friend class OutdoorPvPNA; -public: - OPvPCapturePointNA(OutdoorPvP * pvp); - bool Update(uint32 diff); - void ChangeState(); - void SendChangePhase(); - void FillInitialWorldStates(WorldPacket & data); - // used when player is activated/inactivated in the area - bool HandlePlayerEnter(Player * plr); - void HandlePlayerLeave(Player * plr); - bool HandleCustomSpell(Player *plr, uint32 spellId, GameObject * go); - int32 HandleOpenGo(Player *plr, uint64 guid); - uint32 GetAliveGuardsCount(); -protected: - // called when a faction takes control - void FactionTakeOver(uint32 team); - - void DeSpawnNPCs(); - void DeSpawnGOs(); - void SpawnNPCsForTeam(uint32 team); - void SpawnGOsForTeam(uint32 team); - - void UpdateWyvernRoostWorldState(uint32 roost); - void UpdateHalaaWorldState(); - -private: - bool m_capturable; - uint32 m_GuardsAlive; - uint32 m_ControllingFaction; - uint32 m_WyvernStateNorth; - uint32 m_WyvernStateSouth; - uint32 m_WyvernStateEast; - uint32 m_WyvernStateWest; - uint32 m_HalaaState; - uint32 m_RespawnTimer; - uint32 m_GuardCheckTimer; -}; - -class OutdoorPvPNA : public OutdoorPvP -{ -friend class OPvPCapturePointNA; -public: - OutdoorPvPNA(); - bool SetupOutdoorPvP(); - void HandlePlayerEnterZone(Player *plr, uint32 zone); - void HandlePlayerLeaveZone(Player *plr, uint32 zone); - bool Update(uint32 diff); - void FillInitialWorldStates(WorldPacket &data); - void SendRemoveWorldStates(Player * plr); - void HandleKillImpl(Player * plr, Unit * killed); -private: - OPvPCapturePointNA * m_obj; -}; - -#endif - diff --git a/src/server/game/OutdoorPvP/OutdoorPvPSI.cpp b/src/server/game/OutdoorPvP/OutdoorPvPSI.cpp deleted file mode 100644 index 408901f9d06..00000000000 --- a/src/server/game/OutdoorPvP/OutdoorPvPSI.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "OutdoorPvPSI.h" -#include "WorldPacket.h" -#include "Player.h" -#include "GameObject.h" -#include "MapManager.h" -#include "ObjectMgr.h" -#include "OutdoorPvPMgr.h" -#include "Language.h" -#include "World.h" - -OutdoorPvPSI::OutdoorPvPSI() -{ - m_TypeId = OUTDOOR_PVP_SI; - m_Gathered_A = 0; - m_Gathered_H = 0; - m_LastController = 0; -} - -void OutdoorPvPSI::FillInitialWorldStates(WorldPacket &data) -{ - data << SI_GATHERED_A << m_Gathered_A; - data << SI_GATHERED_H << m_Gathered_H; - data << SI_SILITHYST_MAX << SI_MAX_RESOURCES; -} - -void OutdoorPvPSI::SendRemoveWorldStates(Player *plr) -{ - plr->SendUpdateWorldState(SI_GATHERED_A,0); - plr->SendUpdateWorldState(SI_GATHERED_H,0); - plr->SendUpdateWorldState(SI_SILITHYST_MAX,0); -} - -void OutdoorPvPSI::UpdateWorldState() -{ - SendUpdateWorldState(SI_GATHERED_A,m_Gathered_A); - SendUpdateWorldState(SI_GATHERED_H,m_Gathered_H); - SendUpdateWorldState(SI_SILITHYST_MAX,SI_MAX_RESOURCES); -} - -bool OutdoorPvPSI::SetupOutdoorPvP() -{ - for (int i = 0; i < OutdoorPvPSIBuffZonesNum; ++i) - RegisterZone(OutdoorPvPSIBuffZones[i]); - return true; -} - -bool OutdoorPvPSI::Update(uint32 /*diff*/) -{ - return false; -} - -void OutdoorPvPSI::HandlePlayerEnterZone(Player * plr, uint32 zone) -{ - if (plr->GetTeam() == m_LastController) - plr->CastSpell(plr,SI_CENARION_FAVOR,true); - OutdoorPvP::HandlePlayerEnterZone(plr,zone); -} - -void OutdoorPvPSI::HandlePlayerLeaveZone(Player * plr, uint32 zone) -{ - // remove buffs - plr->RemoveAurasDueToSpell(SI_CENARION_FAVOR); - OutdoorPvP::HandlePlayerLeaveZone(plr, zone); -} - -bool OutdoorPvPSI::HandleAreaTrigger(Player *plr, uint32 trigger) -{ - switch(trigger) - { - case SI_AREATRIGGER_A: - if (plr->GetTeam() == ALLIANCE && plr->HasAura(SI_SILITHYST_FLAG)) - { - // remove aura - plr->RemoveAurasDueToSpell(SI_SILITHYST_FLAG); - ++ m_Gathered_A; - if (m_Gathered_A >= SI_MAX_RESOURCES) - { - TeamApplyBuff(TEAM_ALLIANCE, SI_CENARION_FAVOR); - sWorld.SendZoneText(OutdoorPvPSIBuffZones[0],objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_SI_CAPTURE_A)); - m_LastController = ALLIANCE; - m_Gathered_A = 0; - m_Gathered_H = 0; - } - UpdateWorldState(); - // reward player - plr->CastSpell(plr,SI_TRACES_OF_SILITHYST,true); - // add 19 honor - plr->RewardHonor(NULL,1,19); - // add 20 cenarion circle repu - plr->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(609),20); - // complete quest - plr->KilledMonsterCredit(SI_TURNIN_QUEST_CM_A,0); - } - return true; - case SI_AREATRIGGER_H: - if (plr->GetTeam() == HORDE && plr->HasAura(SI_SILITHYST_FLAG)) - { - // remove aura - plr->RemoveAurasDueToSpell(SI_SILITHYST_FLAG); - ++ m_Gathered_H; - if (m_Gathered_H >= SI_MAX_RESOURCES) - { - TeamApplyBuff(TEAM_HORDE, SI_CENARION_FAVOR); - sWorld.SendZoneText(OutdoorPvPSIBuffZones[0],objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_SI_CAPTURE_H)); - m_LastController = HORDE; - m_Gathered_A = 0; - m_Gathered_H = 0; - } - UpdateWorldState(); - // reward player - plr->CastSpell(plr,SI_TRACES_OF_SILITHYST,true); - // add 19 honor - plr->RewardHonor(NULL,1,19); - // add 20 cenarion circle repu - plr->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(609),20); - // complete quest - plr->KilledMonsterCredit(SI_TURNIN_QUEST_CM_H,0); - } - return true; - } - return false; -} - -bool OutdoorPvPSI::HandleDropFlag(Player *plr, uint32 spellId) -{ - if (spellId == SI_SILITHYST_FLAG) - { - // if it was dropped away from the player's turn-in point, then create a silithyst mound, if it was dropped near the areatrigger, then it was dispelled by the outdoorpvp, so do nothing - switch(plr->GetTeam()) - { - case ALLIANCE: - { - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(SI_AREATRIGGER_A); - if (atEntry) - { - // 5.0f is safe-distance - if (plr->GetDistance(atEntry->x,atEntry->y,atEntry->z) > 5.0f + atEntry->radius) - { - // he dropped it further, summon mound - GameObject * go = new GameObject; - Map * map = plr->GetMap(); - if (!map) - { - delete go; - return true; - } - - if (!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),SI_SILITHYST_MOUND, map, plr->GetPhaseMask(), plr->GetPositionX(),plr->GetPositionY(),plr->GetPositionZ(),plr->GetOrientation(),0,0,0,0,100,GO_STATE_READY)) - { - delete go; - } - else - { - go->SetRespawnTime(0); - map->Add(go); - } - } - } - } - break; - case HORDE: - { - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(SI_AREATRIGGER_H); - if (atEntry) - { - // 5.0f is safe-distance - if (plr->GetDistance(atEntry->x,atEntry->y,atEntry->z) > 5.0f + atEntry->radius) - { - // he dropped it further, summon mound - GameObject * go = new GameObject; - Map * map = plr->GetMap(); - if (!map) - { - delete go; - return true; - } - if (!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),SI_SILITHYST_MOUND, map, plr->GetPhaseMask() ,plr->GetPositionX(),plr->GetPositionY(),plr->GetPositionZ(),plr->GetOrientation(),0,0,0,0,100,GO_STATE_READY)) - { - delete go; - } - else - { - go->SetRespawnTime(0); - map->Add(go); - } - } - } - } - break; - } - return true; - } - return false; -} - -bool OutdoorPvPSI::HandleCustomSpell(Player *plr, uint32 spellId, GameObject *go) -{ - if (!go || spellId != SI_SILITHYST_FLAG_GO_SPELL) - return false; - plr->CastSpell(plr,SI_SILITHYST_FLAG,true); - if (go->GetGOInfo()->id == SI_SILITHYST_MOUND) - { - // despawn go - go->SetRespawnTime(0); - go->Delete(); - } - return true; -} - diff --git a/src/server/game/OutdoorPvP/OutdoorPvPSI.h b/src/server/game/OutdoorPvP/OutdoorPvPSI.h deleted file mode 100644 index 3176669c42c..00000000000 --- a/src/server/game/OutdoorPvP/OutdoorPvPSI.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OUTDOOR_PVP_SI_ -#define OUTDOOR_PVP_SI_ - -#include "OutdoorPvPImpl.h" - -enum OutdoorPvPSISpells -{ - SI_SILITHYST_FLAG_GO_SPELL = 29518, - SI_SILITHYST_FLAG = 29519, - SI_TRACES_OF_SILITHYST = 29534, - SI_CENARION_FAVOR = 30754 -}; - -const uint32 SI_MAX_RESOURCES = 200; - -const uint32 OutdoorPvPSIBuffZonesNum = 3; - -const uint32 OutdoorPvPSIBuffZones[OutdoorPvPSIBuffZonesNum] = { 1377, 3428, 3429 }; - -const uint32 SI_AREATRIGGER_H = 4168; - -const uint32 SI_AREATRIGGER_A = 4162; - -const uint32 SI_TURNIN_QUEST_CM_A = 17090; - -const uint32 SI_TURNIN_QUEST_CM_H = 18199; - -const uint32 SI_SILITHYST_MOUND = 181597; - -enum SI_WorldStates{ - SI_GATHERED_A = 2313, - SI_GATHERED_H = 2314, - SI_SILITHYST_MAX = 2317 -}; - -class OutdoorPvPSI : public OutdoorPvP -{ -public: - OutdoorPvPSI(); - bool SetupOutdoorPvP(); - void HandlePlayerEnterZone(Player *plr, uint32 zone); - void HandlePlayerLeaveZone(Player *plr, uint32 zone); - bool Update(uint32 diff); - void FillInitialWorldStates(WorldPacket &data); - void SendRemoveWorldStates(Player * plr); - bool HandleAreaTrigger(Player * plr, uint32 trigger); - bool HandleDropFlag(Player * plr, uint32 spellId); - bool HandleCustomSpell(Player * plr, uint32 spellId, GameObject *go); - void UpdateWorldState(); -private: - uint32 m_Gathered_A; - uint32 m_Gathered_H; - uint32 m_LastController; -}; - -#endif - diff --git a/src/server/game/OutdoorPvP/OutdoorPvPTF.cpp b/src/server/game/OutdoorPvP/OutdoorPvPTF.cpp deleted file mode 100644 index 4d5682bf1d6..00000000000 --- a/src/server/game/OutdoorPvP/OutdoorPvPTF.cpp +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "OutdoorPvPTF.h" -#include "OutdoorPvPMgr.h" -#include "WorldPacket.h" -#include "Player.h" -#include "ObjectMgr.h" -#include "Language.h" -#include "World.h" - -OutdoorPvPTF::OutdoorPvPTF() -{ - m_TypeId = OUTDOOR_PVP_TF; -} - -OPvPCapturePointTF::OPvPCapturePointTF(OutdoorPvP *pvp, OutdoorPvPTF_TowerType type) -: OPvPCapturePoint(pvp), m_TowerType(type), m_TowerState(TF_TOWERSTATE_N) -{ - SetCapturePointData(TFCapturePoints[type].entry,TFCapturePoints[type].map,TFCapturePoints[type].x,TFCapturePoints[type].y,TFCapturePoints[type].z,TFCapturePoints[type].o,TFCapturePoints[type].rot0,TFCapturePoints[type].rot1,TFCapturePoints[type].rot2,TFCapturePoints[type].rot3); -} - -void OPvPCapturePointTF::FillInitialWorldStates(WorldPacket &data) -{ - data << uint32(TFTowerWorldStates[m_TowerType].n) << uint32(bool(m_TowerState & TF_TOWERSTATE_N)); - data << uint32(TFTowerWorldStates[m_TowerType].h) << uint32(bool(m_TowerState & TF_TOWERSTATE_H)); - data << uint32(TFTowerWorldStates[m_TowerType].a) << uint32(bool(m_TowerState & TF_TOWERSTATE_A)); -} - -void OutdoorPvPTF::FillInitialWorldStates(WorldPacket &data) -{ - data << TF_UI_TOWER_SLIDER_POS << uint32(50); - data << TF_UI_TOWER_SLIDER_N << uint32(100); - data << TF_UI_TOWER_SLIDER_DISPLAY << uint32(0); - - data << TF_UI_TOWER_COUNT_H << m_HordeTowersControlled; - data << TF_UI_TOWER_COUNT_A << m_AllianceTowersControlled; - data << TF_UI_TOWERS_CONTROLLED_DISPLAY << uint32(!m_IsLocked); - - data << TF_UI_LOCKED_TIME_MINUTES_FIRST_DIGIT << first_digit; - data << TF_UI_LOCKED_TIME_MINUTES_SECOND_DIGIT << second_digit; - data << TF_UI_LOCKED_TIME_HOURS << hours_left; - - data << TF_UI_LOCKED_DISPLAY_NEUTRAL << uint32(m_IsLocked && !m_HordeTowersControlled && !m_AllianceTowersControlled); - data << TF_UI_LOCKED_DISPLAY_HORDE << uint32(m_IsLocked && (m_HordeTowersControlled > m_AllianceTowersControlled)); - data << TF_UI_LOCKED_DISPLAY_ALLIANCE << uint32(m_IsLocked && (m_HordeTowersControlled < m_AllianceTowersControlled)); - - for (OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - { - itr->second->FillInitialWorldStates(data); - } -} - -void OutdoorPvPTF::SendRemoveWorldStates(Player * plr) -{ - plr->SendUpdateWorldState(TF_UI_TOWER_SLIDER_POS,uint32(0)); - plr->SendUpdateWorldState(TF_UI_TOWER_SLIDER_N,uint32(0)); - plr->SendUpdateWorldState(TF_UI_TOWER_SLIDER_DISPLAY,uint32(0)); - - plr->SendUpdateWorldState(TF_UI_TOWER_COUNT_H,uint32(0)); - plr->SendUpdateWorldState(TF_UI_TOWER_COUNT_A,uint32(0)); - plr->SendUpdateWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY,uint32(0)); - - plr->SendUpdateWorldState(TF_UI_LOCKED_TIME_MINUTES_FIRST_DIGIT,uint32(0)); - plr->SendUpdateWorldState(TF_UI_LOCKED_TIME_MINUTES_SECOND_DIGIT,uint32(0)); - plr->SendUpdateWorldState(TF_UI_LOCKED_TIME_HOURS,uint32(0)); - - plr->SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL,uint32(0)); - plr->SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE,uint32(0)); - plr->SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE,uint32(0)); - - for (int i = 0; i < TF_TOWER_NUM; ++i) - { - plr->SendUpdateWorldState(uint32(TFTowerWorldStates[i].n),uint32(0)); - plr->SendUpdateWorldState(uint32(TFTowerWorldStates[i].h),uint32(0)); - plr->SendUpdateWorldState(uint32(TFTowerWorldStates[i].a),uint32(0)); - } -} - -void OPvPCapturePointTF::UpdateTowerState() -{ - m_PvP->SendUpdateWorldState(uint32(TFTowerWorldStates[m_TowerType].n),uint32(bool(m_TowerState & TF_TOWERSTATE_N))); - m_PvP->SendUpdateWorldState(uint32(TFTowerWorldStates[m_TowerType].h),uint32(bool(m_TowerState & TF_TOWERSTATE_H))); - m_PvP->SendUpdateWorldState(uint32(TFTowerWorldStates[m_TowerType].a),uint32(bool(m_TowerState & TF_TOWERSTATE_A))); -} - -bool OPvPCapturePointTF::HandlePlayerEnter(Player *plr) -{ - if (OPvPCapturePoint::HandlePlayerEnter(plr)) - { - plr->SendUpdateWorldState(TF_UI_TOWER_SLIDER_DISPLAY, 1); - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - plr->SendUpdateWorldState(TF_UI_TOWER_SLIDER_POS, phase); - plr->SendUpdateWorldState(TF_UI_TOWER_SLIDER_N, m_neutralValuePct); - return true; - } - return false; -} - -void OPvPCapturePointTF::HandlePlayerLeave(Player *plr) -{ - plr->SendUpdateWorldState(TF_UI_TOWER_SLIDER_DISPLAY, 0); - OPvPCapturePoint::HandlePlayerLeave(plr); -} - -bool OutdoorPvPTF::Update(uint32 diff) -{ - bool changed = OutdoorPvP::Update(diff); - - if (changed) - { - if (m_AllianceTowersControlled == TF_TOWER_NUM) - { - TeamApplyBuff(TEAM_ALLIANCE, TF_CAPTURE_BUFF); - m_IsLocked = true; - SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL,uint32(0)); - SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE,uint32(0)); - SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE,uint32(1)); - SendUpdateWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, uint32(0)); - } - else if (m_HordeTowersControlled == TF_TOWER_NUM) - { - TeamApplyBuff(TEAM_HORDE, TF_CAPTURE_BUFF); - m_IsLocked = true; - SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL,uint32(0)); - SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE,uint32(1)); - SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE,uint32(0)); - SendUpdateWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, uint32(0)); - } - else - { - TeamCastSpell(TEAM_ALLIANCE, -TF_CAPTURE_BUFF); - TeamCastSpell(TEAM_HORDE, -TF_CAPTURE_BUFF); - } - SendUpdateWorldState(TF_UI_TOWER_COUNT_A, m_AllianceTowersControlled); - SendUpdateWorldState(TF_UI_TOWER_COUNT_H, m_HordeTowersControlled); - } - if (m_IsLocked) - { - // lock timer is down, release lock - if (m_LockTimer < diff) - { - m_LockTimer = TF_LOCK_TIME; - m_LockTimerUpdate = 0; - m_IsLocked = false; - SendUpdateWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, uint32(1)); - SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL,uint32(0)); - SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE,uint32(0)); - SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE,uint32(0)); - } - else - { - // worldstateui update timer is down, update ui with new time data - if (m_LockTimerUpdate < diff) - { - m_LockTimerUpdate = TF_LOCK_TIME_UPDATE; - uint32 minutes_left = m_LockTimer / 60000; - hours_left = minutes_left / 60; - minutes_left -= hours_left * 60; - second_digit = minutes_left % 10; - first_digit = minutes_left / 10; - - SendUpdateWorldState(TF_UI_LOCKED_TIME_MINUTES_FIRST_DIGIT,first_digit); - SendUpdateWorldState(TF_UI_LOCKED_TIME_MINUTES_SECOND_DIGIT,second_digit); - SendUpdateWorldState(TF_UI_LOCKED_TIME_HOURS,hours_left); - } else m_LockTimerUpdate -= diff; - m_LockTimer -= diff; - } - } - return changed; -} - -void OutdoorPvPTF::HandlePlayerEnterZone(Player * plr, uint32 zone) -{ - if (plr->GetTeam() == ALLIANCE) - { - if (m_AllianceTowersControlled >= TF_TOWER_NUM) - plr->CastSpell(plr,TF_CAPTURE_BUFF,true); - } - else - { - if (m_HordeTowersControlled >= TF_TOWER_NUM) - plr->CastSpell(plr,TF_CAPTURE_BUFF,true); - } - OutdoorPvP::HandlePlayerEnterZone(plr,zone); -} - -void OutdoorPvPTF::HandlePlayerLeaveZone(Player * plr, uint32 zone) -{ - // remove buffs - plr->RemoveAurasDueToSpell(TF_CAPTURE_BUFF); - OutdoorPvP::HandlePlayerLeaveZone(plr, zone); -} - -bool OutdoorPvPTF::SetupOutdoorPvP() -{ - m_AllianceTowersControlled = 0; - m_HordeTowersControlled = 0; - - m_IsLocked = false; - m_LockTimer = TF_LOCK_TIME; - m_LockTimerUpdate = 0; - hours_left = 6; - second_digit = 0; - first_digit = 0; - - // add the zones affected by the pvp buff - for (int i = 0; i < OutdoorPvPTFBuffZonesNum; ++i) - RegisterZone(OutdoorPvPTFBuffZones[i]); - - AddCapturePoint(new OPvPCapturePointTF(this,TF_TOWER_NW)); - AddCapturePoint(new OPvPCapturePointTF(this,TF_TOWER_N)); - AddCapturePoint(new OPvPCapturePointTF(this,TF_TOWER_NE)); - AddCapturePoint(new OPvPCapturePointTF(this,TF_TOWER_SE)); - AddCapturePoint(new OPvPCapturePointTF(this,TF_TOWER_S)); - - return true; -} - -bool OPvPCapturePointTF::Update(uint32 diff) -{ - // can update even in locked state if gathers the controlling faction - bool canupdate = ((((OutdoorPvPTF*)m_PvP)->m_AllianceTowersControlled > 0) && m_activePlayers[0].size() > m_activePlayers[1].size()) || - ((((OutdoorPvPTF*)m_PvP)->m_HordeTowersControlled > 0) && m_activePlayers[0].size() < m_activePlayers[1].size()); - // if gathers the other faction, then only update if the pvp is unlocked - canupdate = canupdate || !((OutdoorPvPTF*)m_PvP)->m_IsLocked; - return canupdate && OPvPCapturePoint::Update(diff); -} - -void OPvPCapturePointTF::ChangeState() -{ - // if changing from controlling alliance to horde - if (m_OldState == OBJECTIVESTATE_ALLIANCE) - { - if (((OutdoorPvPTF*)m_PvP)->m_AllianceTowersControlled) - ((OutdoorPvPTF*)m_PvP)->m_AllianceTowersControlled--; - sWorld.SendZoneText(OutdoorPvPTFBuffZones[0],objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_TF_LOOSE_A)); - } - // if changing from controlling horde to alliance - else if (m_OldState == OBJECTIVESTATE_HORDE) - { - if (((OutdoorPvPTF*)m_PvP)->m_HordeTowersControlled) - ((OutdoorPvPTF*)m_PvP)->m_HordeTowersControlled--; - sWorld.SendZoneText(OutdoorPvPTFBuffZones[0],objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_TF_LOOSE_H)); - } - - uint32 artkit = 21; - - switch(m_State) - { - case OBJECTIVESTATE_ALLIANCE: - m_TowerState = TF_TOWERSTATE_A; - artkit = 2; - if (((OutdoorPvPTF*)m_PvP)->m_AllianceTowersControlledm_AllianceTowersControlled++; - sWorld.SendZoneText(OutdoorPvPTFBuffZones[0],objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_TF_CAPTURE_A)); - for (PlayerSet::iterator itr = m_activePlayers[0].begin(); itr != m_activePlayers[0].end(); ++itr) - (*itr)->AreaExploredOrEventHappens(TF_ALLY_QUEST); - break; - case OBJECTIVESTATE_HORDE: - m_TowerState = TF_TOWERSTATE_H; - artkit = 1; - if (((OutdoorPvPTF*)m_PvP)->m_HordeTowersControlledm_HordeTowersControlled++; - sWorld.SendZoneText(OutdoorPvPTFBuffZones[0],objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_TF_CAPTURE_H)); - for (PlayerSet::iterator itr = m_activePlayers[1].begin(); itr != m_activePlayers[1].end(); ++itr) - (*itr)->AreaExploredOrEventHappens(TF_HORDE_QUEST); - break; - case OBJECTIVESTATE_NEUTRAL: - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - m_TowerState = TF_TOWERSTATE_N; - break; - } - - GameObject* flag = HashMapHolder::Find(m_capturePointGUID); - if (flag) - flag->SetGoArtKit(artkit); - - UpdateTowerState(); -} - -void OPvPCapturePointTF::SendChangePhase() -{ - // send this too, sometimes the slider disappears, dunno why :( - SendUpdateWorldState(TF_UI_TOWER_SLIDER_DISPLAY, 1); - // send these updates to only the ones in this objective - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - SendUpdateWorldState(TF_UI_TOWER_SLIDER_POS, phase); - // send this too, sometimes it resets :S - SendUpdateWorldState(TF_UI_TOWER_SLIDER_N, m_neutralValuePct); -} - diff --git a/src/server/game/OutdoorPvP/OutdoorPvPTF.h b/src/server/game/OutdoorPvP/OutdoorPvPTF.h deleted file mode 100644 index 3a88b7fd309..00000000000 --- a/src/server/game/OutdoorPvP/OutdoorPvPTF.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef OUTDOOR_PVP_TF_ -#define OUTDOOR_PVP_TF_ - -#include "OutdoorPvPImpl.h" - -const uint32 OutdoorPvPTFBuffZonesNum = 5; - -const uint32 OutdoorPvPTFBuffZones[OutdoorPvPTFBuffZonesNum] = { 3519 /*Terokkar Forest*/, 3791 /*Sethekk Halls*/, 3789 /*Shadow Labyrinth*/, 3792 /*Mana-Tombs*/, 3790 /*Auchenai Crypts*/ }; - -// locked for 6 hours after capture -const uint32 TF_LOCK_TIME = 3600 * 6 * 1000; -// update lock timer every 1/4 minute (overkill, but this way it's sure the timer won't "jump" 2 minutes at once.) -const uint32 TF_LOCK_TIME_UPDATE = 15000; - -// blessing of auchindoun -#define TF_CAPTURE_BUFF 33377 - -const uint32 TF_ALLY_QUEST = 11505; -const uint32 TF_HORDE_QUEST = 11506; - -enum OutdoorPvPTF_TowerType{ - TF_TOWER_NW = 0, - TF_TOWER_N, - TF_TOWER_NE, - TF_TOWER_SE, - TF_TOWER_S, - TF_TOWER_NUM -}; - -const go_type TFCapturePoints[TF_TOWER_NUM] = { - {183104,530,-3081.65,5335.03,17.1853,-2.14675,0,0,0.878817,-0.477159}, - {183411,530,-2939.9,4788.73,18.987,2.77507,0,0,0.983255,0.182236}, - {183412,530,-3174.94,4440.97,16.2281,1.86750,0,0.803857,0.594823}, - {183413,530,-3603.31,4529.15,20.9077,0.994838,0,0,0.477159,0.878817}, - {183414,530,-3812.37,4899.3,17.7249,0.087266,0,0,0.043619,0.999048} -}; - -struct tf_tower_world_state{ - uint32 n; - uint32 h; - uint32 a; -}; - -const tf_tower_world_state TFTowerWorldStates[TF_TOWER_NUM] = { - {0xa79,0xa7a,0xa7b}, - {0xa7e,0xa7d,0xa7c}, - {0xa82,0xa81,0xa80}, - {0xa88,0xa87,0xa86}, - {0xa85,0xa84,0xa83} -}; - -const uint32 TFTowerPlayerEnterEvents[TF_TOWER_NUM] = {12226, 12497, 12486, 12499, 12501}; - -const uint32 TFTowerPlayerLeaveEvents[TF_TOWER_NUM] = {12225, 12496, 12487, 12498, 12500}; - -enum TFWorldStates{ - TF_UI_TOWER_SLIDER_POS = 0xa41, - TF_UI_TOWER_SLIDER_N = 0xa40, - TF_UI_TOWER_SLIDER_DISPLAY = 0xa3f, - - TF_UI_TOWER_COUNT_H = 0xa3e, - TF_UI_TOWER_COUNT_A = 0xa3d, - TF_UI_TOWERS_CONTROLLED_DISPLAY = 0xa3c, - - TF_UI_LOCKED_TIME_MINUTES_FIRST_DIGIT = 0x9d0, - TF_UI_LOCKED_TIME_MINUTES_SECOND_DIGIT = 0x9ce, - TF_UI_LOCKED_TIME_HOURS = 0x9cd, - TF_UI_LOCKED_DISPLAY_NEUTRAL = 0x9cc, - TF_UI_LOCKED_DISPLAY_HORDE = 0xad0, - TF_UI_LOCKED_DISPLAY_ALLIANCE = 0xacf -}; - -enum TFTowerStates { - TF_TOWERSTATE_N = 1, - TF_TOWERSTATE_H = 2, - TF_TOWERSTATE_A = 4 -}; - -class OPvPCapturePointTF : public OPvPCapturePoint -{ -public: - OPvPCapturePointTF(OutdoorPvP * pvp, OutdoorPvPTF_TowerType type); - bool Update(uint32 diff); - void ChangeState(); - void SendChangePhase(); - void FillInitialWorldStates(WorldPacket & data); - // used when player is activated/inactivated in the area - bool HandlePlayerEnter(Player * plr); - void HandlePlayerLeave(Player * plr); - void UpdateTowerState(); -protected: - OutdoorPvPTF_TowerType m_TowerType; - uint32 m_TowerState; -}; - -class OutdoorPvPTF : public OutdoorPvP -{ -friend class OPvPCapturePointTF; -public: - OutdoorPvPTF(); - bool SetupOutdoorPvP(); - void HandlePlayerEnterZone(Player *plr, uint32 zone); - void HandlePlayerLeaveZone(Player *plr, uint32 zone); - bool Update(uint32 diff); - void FillInitialWorldStates(WorldPacket &data); - void SendRemoveWorldStates(Player * plr); -private: - bool m_IsLocked; - uint32 m_LockTimer; - uint32 m_LockTimerUpdate; - uint32 m_AllianceTowersControlled; - uint32 m_HordeTowersControlled; - uint32 hours_left, second_digit, first_digit; -}; - -#endif - diff --git a/src/server/game/OutdoorPvP/OutdoorPvPZM.cpp b/src/server/game/OutdoorPvP/OutdoorPvPZM.cpp deleted file mode 100644 index fb548816c3a..00000000000 --- a/src/server/game/OutdoorPvP/OutdoorPvPZM.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "OutdoorPvPZM.h" -#include "ObjectMgr.h" -#include "OutdoorPvPMgr.h" -#include "Player.h" -#include "Creature.h" -#include "ObjectAccessor.h" -#include "WorldPacket.h" -#include "GossipDef.h" -#include "World.h" - -OPvPCapturePointZM_Beacon::OPvPCapturePointZM_Beacon(OutdoorPvP *pvp, ZM_BeaconType type) -: OPvPCapturePoint(pvp), m_TowerType(type), m_TowerState(ZM_TOWERSTATE_N) -{ - SetCapturePointData(ZMCapturePoints[type].entry,ZMCapturePoints[type].map,ZMCapturePoints[type].x,ZMCapturePoints[type].y,ZMCapturePoints[type].z,ZMCapturePoints[type].o,ZMCapturePoints[type].rot0,ZMCapturePoints[type].rot1,ZMCapturePoints[type].rot2,ZMCapturePoints[type].rot3); -} - -void OPvPCapturePointZM_Beacon::FillInitialWorldStates(WorldPacket &data) -{ - data << uint32(ZMBeaconInfo[m_TowerType].ui_tower_n) << uint32(bool(m_TowerState & ZM_TOWERSTATE_N)); - data << uint32(ZMBeaconInfo[m_TowerType].map_tower_n) << uint32(bool(m_TowerState & ZM_TOWERSTATE_N)); - data << uint32(ZMBeaconInfo[m_TowerType].ui_tower_a) << uint32(bool(m_TowerState & ZM_TOWERSTATE_A)); - data << uint32(ZMBeaconInfo[m_TowerType].map_tower_a) << uint32(bool(m_TowerState & ZM_TOWERSTATE_A)); - data << uint32(ZMBeaconInfo[m_TowerType].ui_tower_h) << uint32(bool(m_TowerState & ZM_TOWERSTATE_H)); - data << uint32(ZMBeaconInfo[m_TowerType].map_tower_h) << uint32(bool(m_TowerState & ZM_TOWERSTATE_H)); -} - -void OPvPCapturePointZM_Beacon::UpdateTowerState() -{ - m_PvP->SendUpdateWorldState(uint32(ZMBeaconInfo[m_TowerType].ui_tower_n),uint32(bool(m_TowerState & ZM_TOWERSTATE_N))); - m_PvP->SendUpdateWorldState(uint32(ZMBeaconInfo[m_TowerType].map_tower_n),uint32(bool(m_TowerState & ZM_TOWERSTATE_N))); - m_PvP->SendUpdateWorldState(uint32(ZMBeaconInfo[m_TowerType].ui_tower_a),uint32(bool(m_TowerState & ZM_TOWERSTATE_A))); - m_PvP->SendUpdateWorldState(uint32(ZMBeaconInfo[m_TowerType].map_tower_a),uint32(bool(m_TowerState & ZM_TOWERSTATE_A))); - m_PvP->SendUpdateWorldState(uint32(ZMBeaconInfo[m_TowerType].ui_tower_h),uint32(bool(m_TowerState & ZM_TOWERSTATE_H))); - m_PvP->SendUpdateWorldState(uint32(ZMBeaconInfo[m_TowerType].map_tower_h),uint32(bool(m_TowerState & ZM_TOWERSTATE_H))); -} - -bool OPvPCapturePointZM_Beacon::HandlePlayerEnter(Player *plr) -{ - if (OPvPCapturePoint::HandlePlayerEnter(plr)) - { - plr->SendUpdateWorldState(ZMBeaconInfo[m_TowerType].slider_disp, 1); - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - plr->SendUpdateWorldState(ZMBeaconInfo[m_TowerType].slider_pos, phase); - plr->SendUpdateWorldState(ZMBeaconInfo[m_TowerType].slider_n, m_neutralValuePct); - return true; - } - return false; -} - -void OPvPCapturePointZM_Beacon::HandlePlayerLeave(Player *plr) -{ - plr->SendUpdateWorldState(ZMBeaconInfo[m_TowerType].slider_disp, 0); - OPvPCapturePoint::HandlePlayerLeave(plr); -} - -void OPvPCapturePointZM_Beacon::ChangeState() -{ - // if changing from controlling alliance to horde - if (m_OldState == OBJECTIVESTATE_ALLIANCE) - { - if (((OutdoorPvPZM*)m_PvP)->m_AllianceTowersControlled) - ((OutdoorPvPZM*)m_PvP)->m_AllianceTowersControlled--; - sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(ZMBeaconLooseA[m_TowerType])); - } - // if changing from controlling horde to alliance - else if (m_OldState == OBJECTIVESTATE_HORDE) - { - if (((OutdoorPvPZM*)m_PvP)->m_HordeTowersControlled) - ((OutdoorPvPZM*)m_PvP)->m_HordeTowersControlled--; - sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(ZMBeaconLooseH[m_TowerType])); - } - - switch(m_State) - { - case OBJECTIVESTATE_ALLIANCE: - m_TowerState = ZM_TOWERSTATE_A; - if (((OutdoorPvPZM*)m_PvP)->m_AllianceTowersControlledm_AllianceTowersControlled++; - sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(ZMBeaconCaptureA[m_TowerType])); - break; - case OBJECTIVESTATE_HORDE: - m_TowerState = ZM_TOWERSTATE_H; - if (((OutdoorPvPZM*)m_PvP)->m_HordeTowersControlledm_HordeTowersControlled++; - sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(ZMBeaconCaptureH[m_TowerType])); - break; - case OBJECTIVESTATE_NEUTRAL: - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - m_TowerState = ZM_TOWERSTATE_N; - break; - } - - UpdateTowerState(); -} - -void OPvPCapturePointZM_Beacon::SendChangePhase() -{ - // send this too, sometimes the slider disappears, dunno why :( - SendUpdateWorldState(ZMBeaconInfo[m_TowerType].slider_disp, 1); - // send these updates to only the ones in this objective - uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); - SendUpdateWorldState(ZMBeaconInfo[m_TowerType].slider_pos, phase); - SendUpdateWorldState(ZMBeaconInfo[m_TowerType].slider_n, m_neutralValuePct); -} - -bool OutdoorPvPZM::Update(uint32 diff) -{ - bool changed = OutdoorPvP::Update(diff); - if (changed) - { - if (m_AllianceTowersControlled == ZM_NUM_BEACONS) - m_GraveYard->SetBeaconState(ALLIANCE); - else if (m_HordeTowersControlled == ZM_NUM_BEACONS) - m_GraveYard->SetBeaconState(HORDE); - else - m_GraveYard->SetBeaconState(0); - } - return changed; -} - -void OutdoorPvPZM::HandlePlayerEnterZone(Player * plr, uint32 zone) -{ - if (plr->GetTeam() == ALLIANCE) - { - if (m_GraveYard->m_GraveYardState & ZM_GRAVEYARD_A) - plr->CastSpell(plr,ZM_CAPTURE_BUFF,true); - } - else - { - if (m_GraveYard->m_GraveYardState & ZM_GRAVEYARD_H) - plr->CastSpell(plr,ZM_CAPTURE_BUFF,true); - } - OutdoorPvP::HandlePlayerEnterZone(plr,zone); -} - -void OutdoorPvPZM::HandlePlayerLeaveZone(Player * plr, uint32 zone) -{ - // remove buffs - plr->RemoveAurasDueToSpell(ZM_CAPTURE_BUFF); - // remove flag - plr->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_A); - plr->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_H); - OutdoorPvP::HandlePlayerLeaveZone(plr, zone); -} - -OutdoorPvPZM::OutdoorPvPZM() -{ - m_TypeId = OUTDOOR_PVP_ZM; - m_GraveYard = NULL; - m_AllianceTowersControlled = 0; - m_HordeTowersControlled = 0; - -} - -bool OutdoorPvPZM::SetupOutdoorPvP() -{ - m_AllianceTowersControlled = 0; - m_HordeTowersControlled = 0; - - // add the zones affected by the pvp buff - for (int i = 0; i < OutdoorPvPZMBuffZonesNum; ++i) - RegisterZone(OutdoorPvPZMBuffZones[i]); - - AddCapturePoint(new OPvPCapturePointZM_Beacon(this,ZM_BEACON_WEST)); - AddCapturePoint(new OPvPCapturePointZM_Beacon(this,ZM_BEACON_EAST)); - m_GraveYard = new OPvPCapturePointZM_GraveYard(this); - AddCapturePoint(m_GraveYard); // though the update function isn't used, the handleusego is! - - return true; -} - -void OutdoorPvPZM::HandleKillImpl(Player *plr, Unit * killed) -{ - if (killed->GetTypeId() != TYPEID_PLAYER) - return; - - if (plr->GetTeam() == ALLIANCE && killed->ToPlayer()->GetTeam() != ALLIANCE) - plr->CastSpell(plr,ZM_AlliancePlayerKillReward,true); - else if (plr->GetTeam() == HORDE && killed->ToPlayer()->GetTeam() != HORDE) - plr->CastSpell(plr,ZM_HordePlayerKillReward,true); -} - -bool OPvPCapturePointZM_GraveYard::Update(uint32 /*diff*/) -{ - bool retval = m_State != m_OldState; - m_State = m_OldState; - return retval; -} - -int32 OPvPCapturePointZM_GraveYard::HandleOpenGo(Player *plr, uint64 guid) -{ - uint32 retval = OPvPCapturePoint::HandleOpenGo(plr, guid); - if (retval >= 0) - { - if (plr->HasAura(ZM_BATTLE_STANDARD_A) && m_GraveYardState != ZM_GRAVEYARD_A) - { - if (m_GraveYardState == ZM_GRAVEYARD_H) - sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_ZM_LOOSE_GY_H)); - m_GraveYardState = ZM_GRAVEYARD_A; - DelObject(0); // only one gotype is used in the whole outdoor pvp, no need to call it a constant - AddObject(0,ZM_Banner_A.entry,ZM_Banner_A.map,ZM_Banner_A.x,ZM_Banner_A.y,ZM_Banner_A.z,ZM_Banner_A.o,ZM_Banner_A.rot0,ZM_Banner_A.rot1,ZM_Banner_A.rot2,ZM_Banner_A.rot3); - objmgr.RemoveGraveYardLink(ZM_GRAVEYARD_ID, ZM_GRAVEYARD_ZONE, HORDE); // rem gy - objmgr.AddGraveYardLink(ZM_GRAVEYARD_ID, ZM_GRAVEYARD_ZONE, ALLIANCE, false); // add gy - m_PvP->TeamApplyBuff(TEAM_ALLIANCE, ZM_CAPTURE_BUFF); - plr->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_A); - sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_ZM_CAPTURE_GY_A)); - } - else if (plr->HasAura(ZM_BATTLE_STANDARD_H) && m_GraveYardState != ZM_GRAVEYARD_H) - { - if (m_GraveYardState == ZM_GRAVEYARD_A) - sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_ZM_LOOSE_GY_A)); - m_GraveYardState = ZM_GRAVEYARD_H; - DelObject(0); // only one gotype is used in the whole outdoor pvp, no need to call it a constant - AddObject(0,ZM_Banner_H.entry,ZM_Banner_H.map,ZM_Banner_H.x,ZM_Banner_H.y,ZM_Banner_H.z,ZM_Banner_H.o,ZM_Banner_H.rot0,ZM_Banner_H.rot1,ZM_Banner_H.rot2,ZM_Banner_H.rot3); - objmgr.RemoveGraveYardLink(ZM_GRAVEYARD_ID, ZM_GRAVEYARD_ZONE, ALLIANCE); // rem gy - objmgr.AddGraveYardLink(ZM_GRAVEYARD_ID, ZM_GRAVEYARD_ZONE, HORDE, false); // add gy - m_PvP->TeamApplyBuff(TEAM_HORDE, ZM_CAPTURE_BUFF); - plr->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_H); - sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_ZM_CAPTURE_GY_H)); - } - UpdateTowerState(); - } - return retval; -} - -OPvPCapturePointZM_GraveYard::OPvPCapturePointZM_GraveYard(OutdoorPvP *pvp) -: OPvPCapturePoint(pvp) -{ - m_BothControllingFaction = 0; - m_GraveYardState = ZM_GRAVEYARD_N; - m_FlagCarrierGUID = 0; - // add field scouts here - AddCreature(ZM_ALLIANCE_FIELD_SCOUT,ZM_AllianceFieldScout.entry,ZM_AllianceFieldScout.teamval,ZM_AllianceFieldScout.map,ZM_AllianceFieldScout.x,ZM_AllianceFieldScout.y,ZM_AllianceFieldScout.z,ZM_AllianceFieldScout.o); - AddCreature(ZM_HORDE_FIELD_SCOUT,ZM_HordeFieldScout.entry,ZM_HordeFieldScout.teamval,ZM_HordeFieldScout.map,ZM_HordeFieldScout.x,ZM_HordeFieldScout.y,ZM_HordeFieldScout.z,ZM_HordeFieldScout.o); - // add neutral banner - AddObject(0,ZM_Banner_N.entry,ZM_Banner_N.map,ZM_Banner_N.x,ZM_Banner_N.y,ZM_Banner_N.z,ZM_Banner_N.o,ZM_Banner_N.rot0,ZM_Banner_N.rot1,ZM_Banner_N.rot2,ZM_Banner_N.rot3); -} - -void OPvPCapturePointZM_GraveYard::UpdateTowerState() -{ - m_PvP->SendUpdateWorldState(ZM_MAP_GRAVEYARD_N,uint32(bool(m_GraveYardState & ZM_GRAVEYARD_N))); - m_PvP->SendUpdateWorldState(ZM_MAP_GRAVEYARD_H,uint32(bool(m_GraveYardState & ZM_GRAVEYARD_H))); - m_PvP->SendUpdateWorldState(ZM_MAP_GRAVEYARD_A,uint32(bool(m_GraveYardState & ZM_GRAVEYARD_A))); - - m_PvP->SendUpdateWorldState(ZM_MAP_ALLIANCE_FLAG_READY,uint32(m_BothControllingFaction == ALLIANCE)); - m_PvP->SendUpdateWorldState(ZM_MAP_ALLIANCE_FLAG_NOT_READY,uint32(m_BothControllingFaction != ALLIANCE)); - m_PvP->SendUpdateWorldState(ZM_MAP_HORDE_FLAG_READY,uint32(m_BothControllingFaction == HORDE)); - m_PvP->SendUpdateWorldState(ZM_MAP_HORDE_FLAG_NOT_READY,uint32(m_BothControllingFaction != HORDE)); -} - -void OPvPCapturePointZM_GraveYard::FillInitialWorldStates(WorldPacket &data) -{ - data << ZM_MAP_GRAVEYARD_N << uint32(bool(m_GraveYardState & ZM_GRAVEYARD_N)); - data << ZM_MAP_GRAVEYARD_H << uint32(bool(m_GraveYardState & ZM_GRAVEYARD_H)); - data << ZM_MAP_GRAVEYARD_A << uint32(bool(m_GraveYardState & ZM_GRAVEYARD_A)); - - data << ZM_MAP_ALLIANCE_FLAG_READY << uint32(m_BothControllingFaction == ALLIANCE); - data << ZM_MAP_ALLIANCE_FLAG_NOT_READY << uint32(m_BothControllingFaction != ALLIANCE); - data << ZM_MAP_HORDE_FLAG_READY << uint32(m_BothControllingFaction == HORDE); - data << ZM_MAP_HORDE_FLAG_NOT_READY << uint32(m_BothControllingFaction != HORDE); -} - -void OPvPCapturePointZM_GraveYard::SetBeaconState(uint32 controlling_faction) -{ - // nothing to do here - if (m_BothControllingFaction == controlling_faction) - return; - m_BothControllingFaction = controlling_faction; - - switch(controlling_faction) - { - case ALLIANCE: - // if ally already controls the gy and taken back both beacons, return, nothing to do for us - if (m_GraveYardState & ZM_GRAVEYARD_A) - return; - // ally doesn't control the gy, but controls the side beacons -> add gossip option, add neutral banner - break; - case HORDE: - // if horde already controls the gy and taken back both beacons, return, nothing to do for us - if (m_GraveYardState & ZM_GRAVEYARD_H) - return; - // horde doesn't control the gy, but controls the side beacons -> add gossip option, add neutral banner - break; - default: - // if the graveyard is not neutral, then leave it that way - // if the graveyard is neutral, then we have to dispel the buff from the flag carrier - if (m_GraveYardState & ZM_GRAVEYARD_N) - { - // gy was neutral, thus neutral banner was spawned, it is possible that someone was taking the flag to the gy - if (m_FlagCarrierGUID) - { - // remove flag from carrier, reset flag carrier guid - Player * p = objmgr.GetPlayer(m_FlagCarrierGUID); - if (p) - { - p->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_A); - p->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_H); - } - m_FlagCarrierGUID = 0; - } - } - break; - } - // send worldstateupdate - UpdateTowerState(); -} - -bool OPvPCapturePointZM_GraveYard::CanTalkTo(Player * plr, Creature * c, GossipMenuItems gso) -{ - uint64 guid = c->GetGUID(); - std::map::iterator itr = m_CreatureTypes.find(guid); - if (itr != m_CreatureTypes.end()) - { - if (itr->second == ZM_ALLIANCE_FIELD_SCOUT && plr->GetTeam() == ALLIANCE && m_BothControllingFaction == ALLIANCE && !m_FlagCarrierGUID && m_GraveYardState != ZM_GRAVEYARD_A) - return true; - else if (itr->second == ZM_HORDE_FIELD_SCOUT && plr->GetTeam() == HORDE && m_BothControllingFaction == HORDE && !m_FlagCarrierGUID && m_GraveYardState != ZM_GRAVEYARD_H) - return true; - } - return false; -} - -bool OPvPCapturePointZM_GraveYard::HandleGossipOption(Player *plr, uint64 guid, uint32 /*gossipid*/) -{ - std::map::iterator itr = m_CreatureTypes.find(guid); - if (itr != m_CreatureTypes.end()) - { - Creature * cr = HashMapHolder::Find(guid); - if (!cr) - return true; - // if the flag is already taken, then return - if (m_FlagCarrierGUID) - return true; - if (itr->second == ZM_ALLIANCE_FIELD_SCOUT) - { - cr->CastSpell(plr,ZM_BATTLE_STANDARD_A,true); - m_FlagCarrierGUID = plr->GetGUID(); - } - else if (itr->second == ZM_HORDE_FIELD_SCOUT) - { - cr->CastSpell(plr,ZM_BATTLE_STANDARD_H,true); - m_FlagCarrierGUID = plr->GetGUID(); - } - UpdateTowerState(); - plr->PlayerTalkClass->CloseGossip(); - return true; - } - return false; -} - -bool OPvPCapturePointZM_GraveYard::HandleDropFlag(Player * /*plr*/, uint32 spellId) -{ - switch(spellId) - { - case ZM_BATTLE_STANDARD_A: - m_FlagCarrierGUID = 0; - return true; - case ZM_BATTLE_STANDARD_H: - m_FlagCarrierGUID = 0; - return true; - } - return false; -} - -void OutdoorPvPZM::FillInitialWorldStates(WorldPacket &data) -{ - data << ZM_WORLDSTATE_UNK_1 << uint32(1); - for (OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - { - itr->second->FillInitialWorldStates(data); - } -} - -void OutdoorPvPZM::SendRemoveWorldStates(Player *plr) -{ - plr->SendUpdateWorldState(ZM_UI_TOWER_SLIDER_N_W,0); - plr->SendUpdateWorldState(ZM_UI_TOWER_SLIDER_POS_W,0); - plr->SendUpdateWorldState(ZM_UI_TOWER_SLIDER_DISPLAY_W,0); - plr->SendUpdateWorldState(ZM_UI_TOWER_SLIDER_N_E,0); - plr->SendUpdateWorldState(ZM_UI_TOWER_SLIDER_POS_E,0); - plr->SendUpdateWorldState(ZM_UI_TOWER_SLIDER_DISPLAY_E,0); - plr->SendUpdateWorldState(ZM_WORLDSTATE_UNK_1,1); - plr->SendUpdateWorldState(ZM_UI_TOWER_EAST_N,0); - plr->SendUpdateWorldState(ZM_UI_TOWER_EAST_H,0); - plr->SendUpdateWorldState(ZM_UI_TOWER_EAST_A,0); - plr->SendUpdateWorldState(ZM_UI_TOWER_WEST_N,0); - plr->SendUpdateWorldState(ZM_UI_TOWER_WEST_H,0); - plr->SendUpdateWorldState(ZM_UI_TOWER_WEST_A,0); - plr->SendUpdateWorldState(ZM_MAP_TOWER_EAST_N,0); - plr->SendUpdateWorldState(ZM_MAP_TOWER_EAST_H,0); - plr->SendUpdateWorldState(ZM_MAP_TOWER_EAST_A,0); - plr->SendUpdateWorldState(ZM_MAP_GRAVEYARD_H,0); - plr->SendUpdateWorldState(ZM_MAP_GRAVEYARD_A,0); - plr->SendUpdateWorldState(ZM_MAP_GRAVEYARD_N,0); - plr->SendUpdateWorldState(ZM_MAP_TOWER_WEST_N,0); - plr->SendUpdateWorldState(ZM_MAP_TOWER_WEST_H,0); - plr->SendUpdateWorldState(ZM_MAP_TOWER_WEST_A,0); - plr->SendUpdateWorldState(ZM_MAP_HORDE_FLAG_READY,0); - plr->SendUpdateWorldState(ZM_MAP_HORDE_FLAG_NOT_READY,0); - plr->SendUpdateWorldState(ZM_MAP_ALLIANCE_FLAG_NOT_READY,0); - plr->SendUpdateWorldState(ZM_MAP_ALLIANCE_FLAG_READY,0); -} - diff --git a/src/server/game/OutdoorPvP/OutdoorPvPZM.h b/src/server/game/OutdoorPvP/OutdoorPvPZM.h deleted file mode 100644 index cd26e6bb527..00000000000 --- a/src/server/game/OutdoorPvP/OutdoorPvPZM.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef OUTDOOR_PVP_ZM_ -#define OUTDOOR_PVP_ZM_ - -#include "OutdoorPvPImpl.h" -#include "Language.h" - -const uint32 OutdoorPvPZMBuffZonesNum = 5; -// the buff is cast in these zones -const uint32 OutdoorPvPZMBuffZones[OutdoorPvPZMBuffZonesNum] = {3521,3607,3717,3715,3716}; -// linked when the central tower is controlled -const uint32 ZM_GRAVEYARD_ZONE = 3521; -// linked when the central tower is controlled -const uint32 ZM_GRAVEYARD_ID = 969; - -enum OutdoorPvPZMSpells -{ - // cast on the players of the controlling faction - ZM_CAPTURE_BUFF = 33779, // twin spire blessing - // spell that the field scout casts on the player to carry the flag - ZM_BATTLE_STANDARD_A = 32430, - // spell that the field scout casts on the player to carry the flag - ZM_BATTLE_STANDARD_H = 32431, - // token create spell - ZM_AlliancePlayerKillReward = 32155, - // token create spell - ZM_HordePlayerKillReward = 32158 -}; - -// banners 182527, 182528, 182529, gotta check them ingame -const go_type ZM_Banner_A = { 182527,530,253.54,7083.81,36.7728,-0.017453,0,0,0.008727,-0.999962 }; -const go_type ZM_Banner_H = { 182528,530,253.54,7083.81,36.7728,-0.017453,0,0,0.008727,-0.999962 }; -const go_type ZM_Banner_N = { 182529,530,253.54,7083.81,36.7728,-0.017453,0,0,0.008727,-0.999962 }; - -// horde field scout spawn data -const creature_type ZM_HordeFieldScout = {18564,67,530,296.625,7818.4,42.6294,5.18363}; -// alliance field scout spawn data -const creature_type ZM_AllianceFieldScout = {18581,469,530,374.395,6230.08,22.8351,0.593412}; - -enum ZMCreatureTypes{ - ZM_ALLIANCE_FIELD_SCOUT = 0, - ZM_HORDE_FIELD_SCOUT, - ZM_CREATURE_NUM -}; - -struct zm_beacon { - uint32 slider_disp; - uint32 slider_n; - uint32 slider_pos; - uint32 ui_tower_n; - uint32 ui_tower_h; - uint32 ui_tower_a; - uint32 map_tower_n; - uint32 map_tower_h; - uint32 map_tower_a; - uint32 event_enter; - uint32 event_leave; -}; - -enum ZM_BeaconType{ - ZM_BEACON_EAST = 0, - ZM_BEACON_WEST, - ZM_NUM_BEACONS -}; - -const zm_beacon ZMBeaconInfo[ZM_NUM_BEACONS] = { - {2533,2535,2534,2560,2559,2558,2652,2651,2650,11807,11806}, - {2527,2529,2528,2557,2556,2555,2646,2645,2644,11805,11804} -}; - -const uint32 ZMBeaconCaptureA[ZM_NUM_BEACONS] = { - LANG_OPVP_ZM_CAPTURE_EAST_A, - LANG_OPVP_ZM_CAPTURE_WEST_A -}; - -const uint32 ZMBeaconCaptureH[ZM_NUM_BEACONS] = { - LANG_OPVP_ZM_CAPTURE_EAST_H, - LANG_OPVP_ZM_CAPTURE_WEST_H -}; - -const uint32 ZMBeaconLooseA[ZM_NUM_BEACONS] = { - LANG_OPVP_ZM_LOOSE_EAST_A, - LANG_OPVP_ZM_LOOSE_WEST_A -}; - -const uint32 ZMBeaconLooseH[ZM_NUM_BEACONS] = { - LANG_OPVP_ZM_LOOSE_EAST_H, - LANG_OPVP_ZM_LOOSE_WEST_H -}; - -const go_type ZMCapturePoints[ZM_NUM_BEACONS] = { - {182523,530,303.243,6841.36,40.1245,-1.58825,0,0,0.71325,-0.700909}, - {182522,530,336.466,7340.26,41.4984,-1.58825,0,0,0.71325,-0.700909} -}; - -enum OutdoorPvPZMWorldStates -{ - ZM_UI_TOWER_SLIDER_N_W = 2529, - ZM_UI_TOWER_SLIDER_POS_W = 2528, - ZM_UI_TOWER_SLIDER_DISPLAY_W = 2527, - - ZM_UI_TOWER_SLIDER_N_E = 2535, - ZM_UI_TOWER_SLIDER_POS_E = 2534, - ZM_UI_TOWER_SLIDER_DISPLAY_E = 2533, - - ZM_WORLDSTATE_UNK_1 = 2653, - - ZM_UI_TOWER_EAST_N = 2560, - ZM_UI_TOWER_EAST_H = 2559, - ZM_UI_TOWER_EAST_A = 2558, - ZM_UI_TOWER_WEST_N = 2557, - ZM_UI_TOWER_WEST_H = 2556, - ZM_UI_TOWER_WEST_A = 2555, - - ZM_MAP_TOWER_EAST_N = 2652, - ZM_MAP_TOWER_EAST_H = 2651, - ZM_MAP_TOWER_EAST_A = 2650, - ZM_MAP_GRAVEYARD_H = 2649, - ZM_MAP_GRAVEYARD_A = 2648, - ZM_MAP_GRAVEYARD_N = 2647, - ZM_MAP_TOWER_WEST_N = 2646, - ZM_MAP_TOWER_WEST_H = 2645, - ZM_MAP_TOWER_WEST_A = 2644, - - ZM_MAP_HORDE_FLAG_READY = 2658, - ZM_MAP_HORDE_FLAG_NOT_READY = 2657, - ZM_MAP_ALLIANCE_FLAG_NOT_READY = 2656, - ZM_MAP_ALLIANCE_FLAG_READY = 2655 -}; - -enum ZM_TowerStateMask{ - ZM_TOWERSTATE_N = 1, - ZM_TOWERSTATE_A = 2, - ZM_TOWERSTATE_H = 4 -}; - -class OutdoorPvPZM; -class OPvPCapturePointZM_Beacon : public OPvPCapturePoint -{ -friend class OutdoorPvPZM; -public: - OPvPCapturePointZM_Beacon(OutdoorPvP * pvp, ZM_BeaconType type); - void ChangeState(); - void SendChangePhase(); - void FillInitialWorldStates(WorldPacket & data); - // used when player is activated/inactivated in the area - bool HandlePlayerEnter(Player * plr); - void HandlePlayerLeave(Player * plr); - void UpdateTowerState(); -protected: - ZM_BeaconType m_TowerType; - uint32 m_TowerState; -}; - -enum ZM_GraveYardState{ - ZM_GRAVEYARD_N = 1, - ZM_GRAVEYARD_A = 2, - ZM_GRAVEYARD_H = 4 -}; - -class OPvPCapturePointZM_GraveYard : public OPvPCapturePoint -{ -friend class OutdoorPvPZM; -public: - OPvPCapturePointZM_GraveYard(OutdoorPvP * pvp); - bool Update(uint32 diff); - void ChangeState() {} - void FillInitialWorldStates(WorldPacket & data); - void UpdateTowerState(); - int32 HandleOpenGo(Player *plr, uint64 guid); - void SetBeaconState(uint32 controlling_team); // not good atm - bool HandleGossipOption(Player * plr, uint64 guid, uint32 gossipid); - bool HandleDropFlag(Player * plr, uint32 spellId); - bool CanTalkTo(Player * plr, Creature * c, GossipMenuItems gso); -private: - uint32 m_GraveYardState; -protected: - uint32 m_BothControllingFaction; - uint64 m_FlagCarrierGUID; -}; - -class OutdoorPvPZM : public OutdoorPvP -{ -friend class OPvPCapturePointZM_Beacon; -public: - OutdoorPvPZM(); - bool SetupOutdoorPvP(); - void HandlePlayerEnterZone(Player *plr, uint32 zone); - void HandlePlayerLeaveZone(Player *plr, uint32 zone); - bool Update(uint32 diff); - void FillInitialWorldStates(WorldPacket &data); - void SendRemoveWorldStates(Player * plr); - void HandleKillImpl(Player * plr, Unit * killed); -private: - OPvPCapturePointZM_GraveYard * m_GraveYard; - uint32 m_AllianceTowersControlled; - uint32 m_HordeTowersControlled; -}; - -// todo: flag carrier death/leave/mount/activitychange should give back the gossip options -#endif - diff --git a/src/server/game/OutdoorPvP/Zones/OutdoorPvPEP.cpp b/src/server/game/OutdoorPvP/Zones/OutdoorPvPEP.cpp new file mode 100644 index 00000000000..5691a3ce8be --- /dev/null +++ b/src/server/game/OutdoorPvP/Zones/OutdoorPvPEP.cpp @@ -0,0 +1,765 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OutdoorPvPEP.h" +#include "WorldPacket.h" +#include "Player.h" +#include "GameObject.h" +#include "ObjectMgr.h" +#include "ObjectAccessor.h" +#include "OutdoorPvPMgr.h" +#include "Creature.h" +#include "Language.h" +#include "World.h" +#include "GossipDef.h" + +OPvPCapturePointEP_EWT::OPvPCapturePointEP_EWT(OutdoorPvP *pvp) +: OPvPCapturePoint(pvp), m_TowerState(EP_TS_N), m_UnitsSummonedSide(0) +{ + SetCapturePointData(EPCapturePoints[EP_EWT].entry,EPCapturePoints[EP_EWT].map,EPCapturePoints[EP_EWT].x,EPCapturePoints[EP_EWT].y,EPCapturePoints[EP_EWT].z,EPCapturePoints[EP_EWT].o,EPCapturePoints[EP_EWT].rot0,EPCapturePoints[EP_EWT].rot1,EPCapturePoints[EP_EWT].rot2,EPCapturePoints[EP_EWT].rot3); + AddObject(EP_EWT_FLAGS,EPTowerFlags[EP_EWT].entry,EPTowerFlags[EP_EWT].map,EPTowerFlags[EP_EWT].x,EPTowerFlags[EP_EWT].y,EPTowerFlags[EP_EWT].z,EPTowerFlags[EP_EWT].o,EPTowerFlags[EP_EWT].rot0,EPTowerFlags[EP_EWT].rot1,EPTowerFlags[EP_EWT].rot2,EPTowerFlags[EP_EWT].rot3); +} + +void OPvPCapturePointEP_EWT::ChangeState() +{ + if (fabs(m_value) == m_maxValue) // state won't change, only phase when maxed out! + { + // if changing from controlling alliance to horde or vice versa + if (m_OldState == OBJECTIVESTATE_ALLIANCE && m_OldState != m_State) + { + sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_EWT_A)); + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_EWT] = 0; + } + else if (m_OldState == OBJECTIVESTATE_HORDE && m_OldState != m_State) + { + sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_EWT_H)); + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_EWT] = 0; + } + + uint32 artkit = 21; + + switch(m_State) + { + case OBJECTIVESTATE_ALLIANCE: + if (m_value == m_maxValue) + m_TowerState = EP_TS_A; + else + m_TowerState = EP_TS_A_P; + artkit = 2; + SummonSupportUnitAtNorthpassTower(ALLIANCE); + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_EWT] = ALLIANCE; + if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_EWT_A)); + break; + case OBJECTIVESTATE_HORDE: + if (m_value == -m_maxValue) + m_TowerState = EP_TS_H; + else + m_TowerState = EP_TS_H_P; + artkit = 1; + SummonSupportUnitAtNorthpassTower(HORDE); + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_EWT] = HORDE; + if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_EWT_H)); + break; + case OBJECTIVESTATE_NEUTRAL: + m_TowerState = EP_TS_N; + break; + case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: + case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: + m_TowerState = EP_TS_N_A; + break; + case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: + case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: + m_TowerState = EP_TS_N_H; + break; + } + + GameObject* flag = HashMapHolder::Find(m_capturePointGUID); + GameObject* flag2 = HashMapHolder::Find(m_Objects[EP_EWT_FLAGS]); + if (flag) + { + flag->SetGoArtKit(artkit); + } + if (flag2) + { + flag2->SetGoArtKit(artkit); + } + + UpdateTowerState(); + + // complete quest objective + if (m_TowerState == EP_TS_A || m_TowerState == EP_TS_H) + SendObjectiveComplete(EP_EWT_CM, 0); + } +} + +void OPvPCapturePointEP_EWT::SendChangePhase() +{ + // send this too, sometimes the slider disappears, dunno why :( + SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); + // send these updates to only the ones in this objective + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); + // send this too, sometimes it resets :S + SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); +} + +void OPvPCapturePointEP_EWT::FillInitialWorldStates(WorldPacket &data) +{ + data << EP_EWT_A << uint32(bool(m_TowerState & EP_TS_A)); + data << EP_EWT_H << uint32(bool(m_TowerState & EP_TS_H)); + data << EP_EWT_A_P << uint32(bool(m_TowerState & EP_TS_A_P)); + data << EP_EWT_H_P << uint32(bool(m_TowerState & EP_TS_H_P)); + data << EP_EWT_N_A << uint32(bool(m_TowerState & EP_TS_N_A)); + data << EP_EWT_N_H << uint32(bool(m_TowerState & EP_TS_N_H)); + data << EP_EWT_N << uint32(bool(m_TowerState & EP_TS_N)); +} + +void OPvPCapturePointEP_EWT::UpdateTowerState() +{ + m_PvP->SendUpdateWorldState(EP_EWT_A , bool(m_TowerState & EP_TS_A)); + m_PvP->SendUpdateWorldState(EP_EWT_H , bool(m_TowerState & EP_TS_H)); + m_PvP->SendUpdateWorldState(EP_EWT_A_P , bool(m_TowerState & EP_TS_A_P)); + m_PvP->SendUpdateWorldState(EP_EWT_H_P , bool(m_TowerState & EP_TS_H_P)); + m_PvP->SendUpdateWorldState(EP_EWT_N_A , bool(m_TowerState & EP_TS_N_A)); + m_PvP->SendUpdateWorldState(EP_EWT_N_H , bool(m_TowerState & EP_TS_N_H)); + m_PvP->SendUpdateWorldState(EP_EWT_N , bool(m_TowerState & EP_TS_N)); +} + +bool OPvPCapturePointEP_EWT::HandlePlayerEnter(Player *plr) +{ + if (OPvPCapturePoint::HandlePlayerEnter(plr)) + { + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); + return true; + } + return false; +} + +void OPvPCapturePointEP_EWT::HandlePlayerLeave(Player *plr) +{ + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 0); + OPvPCapturePoint::HandlePlayerLeave(plr); +} + +void OPvPCapturePointEP_EWT::SummonSupportUnitAtNorthpassTower(uint32 team) +{ + if (m_UnitsSummonedSide != team) + { + m_UnitsSummonedSide = team; + const creature_type * ct = NULL; + if (team == ALLIANCE) + ct=EP_EWT_Summons_A; + else + ct=EP_EWT_Summons_H; + + for (int i = 0; i < EP_EWT_NUM_CREATURES; ++i) + { + DelCreature(i); + AddCreature(i,ct[i].entry,ct[i].teamval,ct[i].map,ct[i].x,ct[i].y,ct[i].z,ct[i].o,1000000); + } + } +} + +// NPT +OPvPCapturePointEP_NPT::OPvPCapturePointEP_NPT(OutdoorPvP *pvp) +: OPvPCapturePoint(pvp), m_TowerState(EP_TS_N), m_SummonedGOSide(0) +{ + SetCapturePointData(EPCapturePoints[EP_NPT].entry,EPCapturePoints[EP_NPT].map,EPCapturePoints[EP_NPT].x,EPCapturePoints[EP_NPT].y,EPCapturePoints[EP_NPT].z,EPCapturePoints[EP_NPT].o,EPCapturePoints[EP_NPT].rot0,EPCapturePoints[EP_NPT].rot1,EPCapturePoints[EP_NPT].rot2,EPCapturePoints[EP_NPT].rot3); + AddObject(EP_NPT_FLAGS,EPTowerFlags[EP_NPT].entry,EPTowerFlags[EP_NPT].map,EPTowerFlags[EP_NPT].x,EPTowerFlags[EP_NPT].y,EPTowerFlags[EP_NPT].z,EPTowerFlags[EP_NPT].o,EPTowerFlags[EP_NPT].rot0,EPTowerFlags[EP_NPT].rot1,EPTowerFlags[EP_NPT].rot2,EPTowerFlags[EP_NPT].rot3); +} + +void OPvPCapturePointEP_NPT::ChangeState() +{ + if (fabs(m_value) == m_maxValue) // state won't change, only phase when maxed out! + { + // if changing from controlling alliance to horde or vice versa + if (m_OldState == OBJECTIVESTATE_ALLIANCE && m_OldState != m_State) + { + sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_NPT_A)); + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_NPT] = 0; + } + else if (m_OldState == OBJECTIVESTATE_HORDE && m_OldState != m_State) + { + sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_NPT_H)); + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_NPT] = 0; + } + + uint32 artkit = 21; + + switch(m_State) + { + case OBJECTIVESTATE_ALLIANCE: + if (m_value == m_maxValue) + m_TowerState = EP_TS_A; + else + m_TowerState = EP_TS_A_P; + artkit = 2; + SummonGO(ALLIANCE); + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_NPT] = ALLIANCE; + if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_NPT_A)); + break; + case OBJECTIVESTATE_HORDE: + if (m_value == -m_maxValue) + m_TowerState = EP_TS_H; + else + m_TowerState = EP_TS_H_P; + artkit = 1; + SummonGO(HORDE); + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_NPT] = HORDE; + if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_NPT_H)); + break; + case OBJECTIVESTATE_NEUTRAL: + m_TowerState = EP_TS_N; + m_SummonedGOSide = 0; + DelObject(EP_NPT_BUFF); + break; + case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: + case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: + m_TowerState = EP_TS_N_A; + break; + case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: + case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: + m_TowerState = EP_TS_N_H; + break; + } + + GameObject* flag = HashMapHolder::Find(m_capturePointGUID); + GameObject* flag2 = HashMapHolder::Find(m_Objects[EP_NPT_FLAGS]); + if (flag) + { + flag->SetGoArtKit(artkit); + } + if (flag2) + { + flag2->SetGoArtKit(artkit); + } + + UpdateTowerState(); + + // complete quest objective + if (m_TowerState == EP_TS_A || m_TowerState == EP_TS_H) + SendObjectiveComplete(EP_NPT_CM, 0); + } +} + +void OPvPCapturePointEP_NPT::SendChangePhase() +{ + // send this too, sometimes the slider disappears, dunno why :( + SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); + // send these updates to only the ones in this objective + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); + // send this too, sometimes it resets :S + SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); +} + +void OPvPCapturePointEP_NPT::FillInitialWorldStates(WorldPacket &data) +{ + data << EP_NPT_A << uint32(bool(m_TowerState & EP_TS_A)); + data << EP_NPT_H << uint32(bool(m_TowerState & EP_TS_H)); + data << EP_NPT_A_P << uint32(bool(m_TowerState & EP_TS_A_P)); + data << EP_NPT_H_P << uint32(bool(m_TowerState & EP_TS_H_P)); + data << EP_NPT_N_A << uint32(bool(m_TowerState & EP_TS_N_A)); + data << EP_NPT_N_H << uint32(bool(m_TowerState & EP_TS_N_H)); + data << EP_NPT_N << uint32(bool(m_TowerState & EP_TS_N)); +} + +void OPvPCapturePointEP_NPT::UpdateTowerState() +{ + m_PvP->SendUpdateWorldState(EP_NPT_A , bool(m_TowerState & EP_TS_A)); + m_PvP->SendUpdateWorldState(EP_NPT_H , bool(m_TowerState & EP_TS_H)); + m_PvP->SendUpdateWorldState(EP_NPT_A_P , bool(m_TowerState & EP_TS_A_P)); + m_PvP->SendUpdateWorldState(EP_NPT_H_P , bool(m_TowerState & EP_TS_H_P)); + m_PvP->SendUpdateWorldState(EP_NPT_N_A , bool(m_TowerState & EP_TS_N_A)); + m_PvP->SendUpdateWorldState(EP_NPT_N_H , bool(m_TowerState & EP_TS_N_H)); + m_PvP->SendUpdateWorldState(EP_NPT_N , bool(m_TowerState & EP_TS_N)); +} + +bool OPvPCapturePointEP_NPT::HandlePlayerEnter(Player *plr) +{ + if (OPvPCapturePoint::HandlePlayerEnter(plr)) + { + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); + return true; + } + return false; +} + +void OPvPCapturePointEP_NPT::HandlePlayerLeave(Player *plr) +{ + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 0); + OPvPCapturePoint::HandlePlayerLeave(plr); +} + +void OPvPCapturePointEP_NPT::SummonGO(uint32 team) +{ + if (m_SummonedGOSide != team) + { + m_SummonedGOSide = team; + DelObject(EP_NPT_BUFF); + AddObject(EP_NPT_BUFF,EP_NPT_LordaeronShrine.entry,EP_NPT_LordaeronShrine.map,EP_NPT_LordaeronShrine.x,EP_NPT_LordaeronShrine.y,EP_NPT_LordaeronShrine.z,EP_NPT_LordaeronShrine.o,EP_NPT_LordaeronShrine.rot0,EP_NPT_LordaeronShrine.rot1,EP_NPT_LordaeronShrine.rot2,EP_NPT_LordaeronShrine.rot3); + GameObject * go = HashMapHolder::Find(m_Objects[EP_NPT_BUFF]); + if (go) + go->SetUInt32Value(GAMEOBJECT_FACTION,(team == ALLIANCE ? 84 : 83)); + } +} + +// CGT +OPvPCapturePointEP_CGT::OPvPCapturePointEP_CGT(OutdoorPvP *pvp) +: OPvPCapturePoint(pvp), m_TowerState(EP_TS_N), m_GraveyardSide(0) +{ + SetCapturePointData(EPCapturePoints[EP_CGT].entry,EPCapturePoints[EP_CGT].map,EPCapturePoints[EP_CGT].x,EPCapturePoints[EP_CGT].y,EPCapturePoints[EP_CGT].z,EPCapturePoints[EP_CGT].o,EPCapturePoints[EP_CGT].rot0,EPCapturePoints[EP_CGT].rot1,EPCapturePoints[EP_CGT].rot2,EPCapturePoints[EP_CGT].rot3); + AddObject(EP_CGT_FLAGS,EPTowerFlags[EP_CGT].entry,EPTowerFlags[EP_CGT].map,EPTowerFlags[EP_CGT].x,EPTowerFlags[EP_CGT].y,EPTowerFlags[EP_CGT].z,EPTowerFlags[EP_CGT].o,EPTowerFlags[EP_CGT].rot0,EPTowerFlags[EP_CGT].rot1,EPTowerFlags[EP_CGT].rot2,EPTowerFlags[EP_CGT].rot3); +} + +void OPvPCapturePointEP_CGT::ChangeState() +{ + if (fabs(m_value) == m_maxValue) // state won't change, only phase when maxed out! + { + // if changing from controlling alliance to horde or vice versa + if (m_OldState == OBJECTIVESTATE_ALLIANCE && m_OldState != m_State) + { + sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_CGT_A)); + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_CGT] = 0; + } + else if (m_OldState == OBJECTIVESTATE_HORDE && m_OldState != m_State) + { + sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_CGT_H)); + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_CGT] = 0; + } + + uint32 artkit = 21; + + switch(m_State) + { + case OBJECTIVESTATE_ALLIANCE: + if (m_value == m_maxValue) + m_TowerState = EP_TS_A; + else + m_TowerState = EP_TS_A_P; + artkit = 2; + LinkGraveYard(ALLIANCE); + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_CGT] = ALLIANCE; + if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_CGT_A)); + break; + case OBJECTIVESTATE_HORDE: + if (m_value == -m_maxValue) + m_TowerState = EP_TS_H; + else + m_TowerState = EP_TS_H_P; + artkit = 1; + LinkGraveYard(HORDE); + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_CGT] = HORDE; + if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_CGT_H)); + break; + case OBJECTIVESTATE_NEUTRAL: + m_TowerState = EP_TS_N; + break; + case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: + case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: + m_TowerState = EP_TS_N_A; + break; + case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: + case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: + m_TowerState = EP_TS_N_H; + break; + } + + GameObject* flag = HashMapHolder::Find(m_capturePointGUID); + GameObject* flag2 = HashMapHolder::Find(m_Objects[EP_CGT_FLAGS]); + if (flag) + { + flag->SetGoArtKit(artkit); + } + if (flag2) + { + flag2->SetGoArtKit(artkit); + } + + UpdateTowerState(); + + // complete quest objective + if (m_TowerState == EP_TS_A || m_TowerState == EP_TS_H) + SendObjectiveComplete(EP_CGT_CM, 0); + } +} + +void OPvPCapturePointEP_CGT::SendChangePhase() +{ + // send this too, sometimes the slider disappears, dunno why :( + SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); + // send these updates to only the ones in this objective + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); + // send this too, sometimes it resets :S + SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); +} + +void OPvPCapturePointEP_CGT::FillInitialWorldStates(WorldPacket &data) +{ + data << EP_CGT_A << uint32(bool(m_TowerState & EP_TS_A)); + data << EP_CGT_H << uint32(bool(m_TowerState & EP_TS_H)); + data << EP_CGT_A_P << uint32(bool(m_TowerState & EP_TS_A_P)); + data << EP_CGT_H_P << uint32(bool(m_TowerState & EP_TS_H_P)); + data << EP_CGT_N_A << uint32(bool(m_TowerState & EP_TS_N_A)); + data << EP_CGT_N_H << uint32(bool(m_TowerState & EP_TS_N_H)); + data << EP_CGT_N << uint32(bool(m_TowerState & EP_TS_N)); +} + +void OPvPCapturePointEP_CGT::UpdateTowerState() +{ + m_PvP->SendUpdateWorldState(EP_CGT_A , bool(m_TowerState & EP_TS_A)); + m_PvP->SendUpdateWorldState(EP_CGT_H , bool(m_TowerState & EP_TS_H)); + m_PvP->SendUpdateWorldState(EP_CGT_A_P , bool(m_TowerState & EP_TS_A_P)); + m_PvP->SendUpdateWorldState(EP_CGT_H_P , bool(m_TowerState & EP_TS_H_P)); + m_PvP->SendUpdateWorldState(EP_CGT_N_A , bool(m_TowerState & EP_TS_N_A)); + m_PvP->SendUpdateWorldState(EP_CGT_N_H , bool(m_TowerState & EP_TS_N_H)); + m_PvP->SendUpdateWorldState(EP_CGT_N , bool(m_TowerState & EP_TS_N)); +} + +bool OPvPCapturePointEP_CGT::HandlePlayerEnter(Player *plr) +{ + if (OPvPCapturePoint::HandlePlayerEnter(plr)) + { + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); + return true; + } + return false; +} + +void OPvPCapturePointEP_CGT::HandlePlayerLeave(Player *plr) +{ + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 0); + OPvPCapturePoint::HandlePlayerLeave(plr); +} + +void OPvPCapturePointEP_CGT::LinkGraveYard(uint32 team) +{ + if (m_GraveyardSide != team) + { + m_GraveyardSide = team; + objmgr.RemoveGraveYardLink(EP_GraveYardId,EP_GraveYardZone,team,false); + objmgr.AddGraveYardLink(EP_GraveYardId,EP_GraveYardZone,team,false); + } +} + +// PWT +OPvPCapturePointEP_PWT::OPvPCapturePointEP_PWT(OutdoorPvP *pvp) +: OPvPCapturePoint(pvp), m_TowerState(EP_TS_N), m_FlightMasterSpawned(0) +{ + SetCapturePointData(EPCapturePoints[EP_PWT].entry,EPCapturePoints[EP_PWT].map,EPCapturePoints[EP_PWT].x,EPCapturePoints[EP_PWT].y,EPCapturePoints[EP_PWT].z,EPCapturePoints[EP_PWT].o,EPCapturePoints[EP_PWT].rot0,EPCapturePoints[EP_PWT].rot1,EPCapturePoints[EP_PWT].rot2,EPCapturePoints[EP_PWT].rot3); + AddObject(EP_PWT_FLAGS,EPTowerFlags[EP_PWT].entry,EPTowerFlags[EP_PWT].map,EPTowerFlags[EP_PWT].x,EPTowerFlags[EP_PWT].y,EPTowerFlags[EP_PWT].z,EPTowerFlags[EP_PWT].o,EPTowerFlags[EP_PWT].rot0,EPTowerFlags[EP_PWT].rot1,EPTowerFlags[EP_PWT].rot2,EPTowerFlags[EP_PWT].rot3); +} + +void OPvPCapturePointEP_PWT::ChangeState() +{ + if (fabs(m_value) == m_maxValue) // state won't change, only phase when maxed out! + { + // if changing from controlling alliance to horde or vice versa + if (m_OldState == OBJECTIVESTATE_ALLIANCE && m_OldState != m_State) + { + sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_PWT_A)); + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_PWT] = 0; + } + else if (m_OldState == OBJECTIVESTATE_HORDE && m_OldState != m_State) + { + sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_LOOSE_PWT_H)); + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_PWT] = 0; + } + + uint32 artkit = 21; + + switch(m_State) + { + case OBJECTIVESTATE_ALLIANCE: + if (m_value == m_maxValue) + m_TowerState = EP_TS_A; + else + m_TowerState = EP_TS_A_P; + SummonFlightMaster(ALLIANCE); + artkit = 2; + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_PWT] = ALLIANCE; + if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_PWT_A)); + break; + case OBJECTIVESTATE_HORDE: + if (m_value == -m_maxValue) + m_TowerState = EP_TS_H; + else + m_TowerState = EP_TS_H_P; + SummonFlightMaster(HORDE); + artkit = 1; + ((OutdoorPvPEP*)m_PvP)->EP_Controls[EP_PWT] = HORDE; + if (m_OldState != m_State) sWorld.SendZoneText(EP_GraveYardZone,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_EP_CAPTURE_PWT_H)); + break; + case OBJECTIVESTATE_NEUTRAL: + m_TowerState = EP_TS_N; + DelCreature(EP_PWT_FLIGHTMASTER); + m_FlightMasterSpawned = 0; + break; + case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: + case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: + m_TowerState = EP_TS_N_A; + break; + case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: + case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: + m_TowerState = EP_TS_N_H; + break; + } + + GameObject* flag = HashMapHolder::Find(m_capturePointGUID); + GameObject* flag2 = HashMapHolder::Find(m_Objects[EP_PWT_FLAGS]); + if (flag) + { + flag->SetGoArtKit(artkit); + } + if (flag2) + { + flag2->SetGoArtKit(artkit); + } + + UpdateTowerState(); + + // complete quest objective + if (m_TowerState == EP_TS_A || m_TowerState == EP_TS_H) + SendObjectiveComplete(EP_PWT_CM, 0); + } +} + +void OPvPCapturePointEP_PWT::SendChangePhase() +{ + // send this too, sometimes the slider disappears, dunno why :( + SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); + // send these updates to only the ones in this objective + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); + // send this too, sometimes it resets :S + SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); +} + +void OPvPCapturePointEP_PWT::FillInitialWorldStates(WorldPacket &data) +{ + data << EP_PWT_A << uint32(bool(m_TowerState & EP_TS_A)); + data << EP_PWT_H << uint32(bool(m_TowerState & EP_TS_H)); + data << EP_PWT_A_P << uint32(bool(m_TowerState & EP_TS_A_P)); + data << EP_PWT_H_P << uint32(bool(m_TowerState & EP_TS_H_P)); + data << EP_PWT_N_A << uint32(bool(m_TowerState & EP_TS_N_A)); + data << EP_PWT_N_H << uint32(bool(m_TowerState & EP_TS_N_H)); + data << EP_PWT_N << uint32(bool(m_TowerState & EP_TS_N)); +} + +void OPvPCapturePointEP_PWT::UpdateTowerState() +{ + m_PvP->SendUpdateWorldState(EP_PWT_A , bool(m_TowerState & EP_TS_A)); + m_PvP->SendUpdateWorldState(EP_PWT_H , bool(m_TowerState & EP_TS_H)); + m_PvP->SendUpdateWorldState(EP_PWT_A_P , bool(m_TowerState & EP_TS_A_P)); + m_PvP->SendUpdateWorldState(EP_PWT_H_P , bool(m_TowerState & EP_TS_H_P)); + m_PvP->SendUpdateWorldState(EP_PWT_N_A , bool(m_TowerState & EP_TS_N_A)); + m_PvP->SendUpdateWorldState(EP_PWT_N_H , bool(m_TowerState & EP_TS_N_H)); + m_PvP->SendUpdateWorldState(EP_PWT_N , bool(m_TowerState & EP_TS_N)); +} + +bool OPvPCapturePointEP_PWT::HandlePlayerEnter(Player *plr) +{ + if (OPvPCapturePoint::HandlePlayerEnter(plr)) + { + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 1); + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS, phase); + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_N, m_neutralValuePct); + return true; + } + return false; +} + +void OPvPCapturePointEP_PWT::HandlePlayerLeave(Player *plr) +{ + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY, 0); + OPvPCapturePoint::HandlePlayerLeave(plr); +} + +void OPvPCapturePointEP_PWT::SummonFlightMaster(uint32 team) +{ + if (m_FlightMasterSpawned != team) + { + m_FlightMasterSpawned = team; + DelCreature(EP_PWT_FLIGHTMASTER); + AddCreature(EP_PWT_FLIGHTMASTER,EP_PWT_FlightMaster.entry,team,EP_PWT_FlightMaster.map,EP_PWT_FlightMaster.x,EP_PWT_FlightMaster.y,EP_PWT_FlightMaster.z,EP_PWT_FlightMaster.o); + } +} + +// ep +OutdoorPvPEP::OutdoorPvPEP() +{ + m_TypeId = OUTDOOR_PVP_EP; + memset(EP_Controls,0,sizeof(EP_Controls)); + m_AllianceTowersControlled = 0; + m_HordeTowersControlled = 0; +} + +bool OutdoorPvPEP::SetupOutdoorPvP() +{ + for (int i = 0; i < EPBuffZonesNum; ++i) + RegisterZone(EPBuffZones[i]); + + AddCapturePoint(new OPvPCapturePointEP_EWT(this)); + AddCapturePoint(new OPvPCapturePointEP_PWT(this)); + AddCapturePoint(new OPvPCapturePointEP_CGT(this)); + AddCapturePoint(new OPvPCapturePointEP_NPT(this)); + return true; +} + +bool OutdoorPvPEP::Update(uint32 diff) +{ + if (OutdoorPvP::Update(diff)) + { + m_AllianceTowersControlled = 0; + m_HordeTowersControlled = 0; + for (int i = 0; i < EP_TOWER_NUM; ++i) + { + if (EP_Controls[i] == ALLIANCE) + ++m_AllianceTowersControlled; + else if (EP_Controls[i] == HORDE) + ++m_HordeTowersControlled; + SendUpdateWorldState(EP_UI_TOWER_COUNT_A,m_AllianceTowersControlled); + SendUpdateWorldState(EP_UI_TOWER_COUNT_H,m_HordeTowersControlled); + BuffTeams(); + } + return true; + } + return false; +} + +void OutdoorPvPEP::HandlePlayerEnterZone(Player * plr, uint32 zone) +{ + // add buffs + if (plr->GetTeam() == ALLIANCE) + { + if (m_AllianceTowersControlled && m_AllianceTowersControlled < 5) + plr->CastSpell(plr,EP_AllianceBuffs[m_AllianceTowersControlled-1],true); + } + else + { + if (m_HordeTowersControlled && m_HordeTowersControlled < 5) + plr->CastSpell(plr,EP_HordeBuffs[m_HordeTowersControlled-1],true); + } + OutdoorPvP::HandlePlayerEnterZone(plr,zone); +} + +void OutdoorPvPEP::HandlePlayerLeaveZone(Player * plr, uint32 zone) +{ + // remove buffs + if (plr->GetTeam() == ALLIANCE) + { + for (int i = 0; i < 4; ++i) + plr->RemoveAurasDueToSpell(EP_AllianceBuffs[i]); + } + else + { + for (int i = 0; i < 4; ++i) + plr->RemoveAurasDueToSpell(EP_HordeBuffs[i]); + } + OutdoorPvP::HandlePlayerLeaveZone(plr, zone); +} + +void OutdoorPvPEP::BuffTeams() +{ + for (PlayerSet::iterator itr = m_players[0].begin(); itr != m_players[0].end(); ++itr) + { + Player * plr = *itr; + { + for (int i = 0; i < 4; ++i) + plr->RemoveAurasDueToSpell(EP_AllianceBuffs[i]); + if (m_AllianceTowersControlled && m_AllianceTowersControlled < 5) + plr->CastSpell(plr,EP_AllianceBuffs[m_AllianceTowersControlled-1],true); + } + } + for (PlayerSet::iterator itr = m_players[1].begin(); itr != m_players[1].end(); ++itr) + { + Player * plr = *itr; + { + for (int i = 0; i < 4; ++i) + plr->RemoveAurasDueToSpell(EP_HordeBuffs[i]); + if (m_HordeTowersControlled && m_HordeTowersControlled < 5) + plr->CastSpell(plr,EP_HordeBuffs[m_HordeTowersControlled-1],true); + } + } +} + +void OutdoorPvPEP::FillInitialWorldStates(WorldPacket & data) +{ + data << EP_UI_TOWER_COUNT_A << m_AllianceTowersControlled; + data << EP_UI_TOWER_COUNT_H << m_HordeTowersControlled; + data << EP_UI_TOWER_SLIDER_DISPLAY << uint32(0); + data << EP_UI_TOWER_SLIDER_POS << uint32(50); + data << EP_UI_TOWER_SLIDER_N << uint32(100); + for (OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) + { + itr->second->FillInitialWorldStates(data); + } +} + +void OutdoorPvPEP::SendRemoveWorldStates(Player *plr) +{ + plr->SendUpdateWorldState(EP_UI_TOWER_COUNT_A,0); + plr->SendUpdateWorldState(EP_UI_TOWER_COUNT_H,0); + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_DISPLAY,0); + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_POS,0); + plr->SendUpdateWorldState(EP_UI_TOWER_SLIDER_N,0); + + plr->SendUpdateWorldState(EP_EWT_A,0); + plr->SendUpdateWorldState(EP_EWT_H,0); + plr->SendUpdateWorldState(EP_EWT_N,0); + plr->SendUpdateWorldState(EP_EWT_A_P,0); + plr->SendUpdateWorldState(EP_EWT_H_P,0); + plr->SendUpdateWorldState(EP_EWT_N_A,0); + plr->SendUpdateWorldState(EP_EWT_N_H,0); + + plr->SendUpdateWorldState(EP_PWT_A,0); + plr->SendUpdateWorldState(EP_PWT_H,0); + plr->SendUpdateWorldState(EP_PWT_N,0); + plr->SendUpdateWorldState(EP_PWT_A_P,0); + plr->SendUpdateWorldState(EP_PWT_H_P,0); + plr->SendUpdateWorldState(EP_PWT_N_A,0); + plr->SendUpdateWorldState(EP_PWT_N_H,0); + + plr->SendUpdateWorldState(EP_NPT_A,0); + plr->SendUpdateWorldState(EP_NPT_H,0); + plr->SendUpdateWorldState(EP_NPT_N,0); + plr->SendUpdateWorldState(EP_NPT_A_P,0); + plr->SendUpdateWorldState(EP_NPT_H_P,0); + plr->SendUpdateWorldState(EP_NPT_N_A,0); + plr->SendUpdateWorldState(EP_NPT_N_H,0); + + plr->SendUpdateWorldState(EP_CGT_A,0); + plr->SendUpdateWorldState(EP_CGT_H,0); + plr->SendUpdateWorldState(EP_CGT_N,0); + plr->SendUpdateWorldState(EP_CGT_A_P,0); + plr->SendUpdateWorldState(EP_CGT_H_P,0); + plr->SendUpdateWorldState(EP_CGT_N_A,0); + plr->SendUpdateWorldState(EP_CGT_N_H,0); +} + diff --git a/src/server/game/OutdoorPvP/Zones/OutdoorPvPEP.h b/src/server/game/OutdoorPvP/Zones/OutdoorPvPEP.h new file mode 100644 index 00000000000..071d6bcde2d --- /dev/null +++ b/src/server/game/OutdoorPvP/Zones/OutdoorPvPEP.h @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OUTDOOR_PVP_EP_ +#define OUTDOOR_PVP_EP_ + +#include "OutdoorPvPImpl.h" + +#include "DBCStructure.h" + +const uint32 EP_AllianceBuffs[4] = {11413, 11414, 11415, 1386}; + +const uint32 EP_HordeBuffs[4] = {30880, 30683, 30682, 29520}; + +const uint32 EP_GraveYardZone = 139; + +const uint32 EP_GraveYardId = 927; + +const uint32 EPBuffZonesNum = 3; + +const uint32 EP_EWT_CM = 17690; +const uint32 EP_CGT_CM = 17689; +const uint32 EP_NPT_CM = 17696; +const uint32 EP_PWT_CM = 17698; + +const uint32 EPBuffZones[EPBuffZonesNum] = {139, 2017, 2057}; + +enum EP_TaxiNodes { + EP_CGT_Taxi = 87, + EP_EWT_Taxi = 86, + EP_NPT_Taxi = 85, + EP_PWT_Taxi = 84 +}; + +enum EP_EastwallTowerWorldStates { + EP_EWT_A = 2354, + EP_EWT_H = 2356, + EP_EWT_A_P = 2357, // ally progressing + EP_EWT_H_P = 2358, + EP_EWT_N_A = 2359, // ally conquested + EP_EWT_N_H = 2360, + EP_EWT_N = 2361 +}; + +enum EP_NorthpassTowerWorldStates { + EP_NPT_N = 2352, + EP_NPT_N_A = 2362, + EP_NPT_N_H = 2363, + EP_NPT_A_P = 2364, + EP_NPT_H_P = 2365, + EP_NPT_A = 2372, + EP_NPT_H = 2373 +}; + +enum EP_PlagewoodTowerWorldStates { + EP_PWT_N_A = 2366, + EP_PWT_N_H = 2353, //2367 not present! use neutral! + EP_PWT_A_P = 2368, + EP_PWT_H_P = 2369, + EP_PWT_A = 2370, + EP_PWT_H = 2371, + EP_PWT_N = 2353 +}; + +enum EP_CrownGuardTowerWorldStates { + EP_CGT_N_A = 2374, + EP_CGT_N_H = 2375, + EP_CGT_A_P = 2376, + EP_CGT_H_P = 2377, + EP_CGT_A = 2378, + EP_CGT_H = 2379, + EP_CGT_N = 2355 +}; + +enum EP_WorldStates { + EP_UI_TOWER_SLIDER_DISPLAY = 2426, + EP_UI_TOWER_SLIDER_POS = 2427, + EP_UI_TOWER_SLIDER_N = 2428, + + EP_UI_TOWER_COUNT_A = 2327, + EP_UI_TOWER_COUNT_H = 2328 +}; + +enum EP_Summons { + EP_EWT_COMMANDER = 0, + EP_EWT_SOLDIER1, + EP_EWT_SOLDIER2, + EP_EWT_SOLDIER3, + EP_EWT_SOLDIER4, + EP_PWT_FLIGHTMASTER, +}; + +enum EP_GoSummons { + EP_NPT_BUFF = 0, + EP_NPT_FLAGS, + EP_EWT_FLAGS, + EP_CGT_FLAGS, + EP_PWT_FLAGS +}; + +enum EP_Towers { + EP_EWT = 0, // plaguelands 03 + EP_NPT,// plaguelands 01 + EP_PWT,// plaguelands 04 + EP_CGT,// plaguelands 02 + EP_TOWER_NUM +}; + +const go_type EPCapturePoints[EP_TOWER_NUM] = { + {182097,0,2574.51,-4794.89,144.704,-1.45003,-0.097056,0.095578,-0.656229,0.742165}, + {181899,0,3181.08,-4379.36,174.123,-2.03472,-0.065392,0.119494,-0.842275,0.521553}, + {182098,0,2962.71,-3042.31,154.789,2.08426,-0.074807,-0.113837,0.855928,0.49883}, + {182096,0,1860.85,-3731.23,196.716,-2.53214,0.033967,-0.131914,0.944741,-0.298177} +}; + +const go_type EPTowerFlags[EP_TOWER_NUM] = { + {182106,0,2569.60,-4772.93,115.399,2.72271,0,0,0.978148,0.207912}, + {182106,0,3148.17,-4365.51,145.029,1.53589,0,0,0.694658,0.71934}, + {182106,0,2992.63,-3022.95,125.593,3.03687,0,0,0.99863,0.052336}, + {182106,0,1838.42,-3703.56,167.713,0.890118,0,0,0.430511,0.902585} +}; + +const uint32 EPTowerPlayerEnterEvents[EP_TOWER_NUM] = {10691,10699,10701,10705}; + +const uint32 EPTowerPlayerLeaveEvents[EP_TOWER_NUM] = {10692,10698,10700,10704}; + +const uint32 EP_NUM_CREATURES = 6; +const uint32 EP_EWT_NUM_CREATURES = 5; + +// one lordaeron commander, 4 soldiers +// should be spawned at EWT and follow a path, but trans-grid pathing isn't safe, so summon them directly at NPT +const creature_type EP_EWT_Summons_A[EP_EWT_NUM_CREATURES] = { + {17635,469,0, 3167.61,-4352.09,138.20,4.5811}, + {17647,469,0, 3172.74,-4352.99,139.14,4.9873}, + {17647,469,0, 3165.89,-4354.46,138.67,3.7244}, + {17647,469,0, 3164.65,-4350.26,138.22,2.4794}, + {17647,469,0, 3169.91,-4349.68,138.37,0.7444} +}; + +const creature_type EP_EWT_Summons_H[EP_EWT_NUM_CREATURES] = { + {17995,67,0, 3167.61,-4352.09,138.20,4.5811}, + {17996,67,0, 3172.74,-4352.99,139.14,4.9873}, + {17996,67,0, 3165.89,-4354.46,138.67,3.7244}, + {17996,67,0, 3164.65,-4350.26,138.22,2.4794}, + {17996,67,0, 3169.91,-4349.68,138.37,0.7444} +}; + +enum EP_TowerStates { + EP_TS_N = 1, + EP_TS_N_A = 2, + EP_TS_N_H = 4, + EP_TS_A_P = 8, + EP_TS_H_P = 16, + EP_TS_A = 32, + EP_TS_H = 64 +}; + +// when spawning, pay attention at setting the faction manually! +const creature_type EP_PWT_FlightMaster = {17209,0,0,2987.5,-3049.11,120.126,5.75959}; + +// after spawning, modify the faction so that only the controller will be able to use it with SetUInt32Value(GAMEOBJECT_FACTION, faction_id); +const go_type EP_NPT_LordaeronShrine = {181682,0,3167.72,-4355.91,138.785,1.69297,0,0,0.748956,0.66262}; + +class OutdoorPvPEP; + +class OPvPCapturePointEP_EWT : public OPvPCapturePoint +{ +friend class OutdoorPvPEP; +public: + OPvPCapturePointEP_EWT(OutdoorPvP * pvp); + void ChangeState(); + void SendChangePhase(); + void FillInitialWorldStates(WorldPacket & data); + // used when player is activated/inactivated in the area + bool HandlePlayerEnter(Player * plr); + void HandlePlayerLeave(Player * plr); +protected: + void SummonSupportUnitAtNorthpassTower(uint32 team); + void UpdateTowerState(); +protected: + uint32 m_TowerState; + uint32 m_UnitsSummonedSide; +}; + +class OPvPCapturePointEP_NPT : public OPvPCapturePoint +{ +friend class OutdoorPvPEP; +public: + OPvPCapturePointEP_NPT(OutdoorPvP * pvp); + void ChangeState(); + void SendChangePhase(); + void FillInitialWorldStates(WorldPacket & data); + // used when player is activated/inactivated in the area + bool HandlePlayerEnter(Player * plr); + void HandlePlayerLeave(Player * plr); +protected: + void SummonGO(uint32 team); + void UpdateTowerState(); +protected: + uint32 m_TowerState; + uint32 m_SummonedGOSide; +}; + +class OPvPCapturePointEP_CGT : public OPvPCapturePoint +{ +friend class OutdoorPvPEP; +public: + OPvPCapturePointEP_CGT(OutdoorPvP * pvp); + void ChangeState(); + void SendChangePhase(); + void FillInitialWorldStates(WorldPacket & data); + // used when player is activated/inactivated in the area + bool HandlePlayerEnter(Player * plr); + void HandlePlayerLeave(Player * plr); +protected: + void LinkGraveYard(uint32 team); + void UpdateTowerState(); +protected: + uint32 m_TowerState; + uint32 m_GraveyardSide; +}; + +class OPvPCapturePointEP_PWT : public OPvPCapturePoint +{ +friend class OutdoorPvPEP; +public: + OPvPCapturePointEP_PWT(OutdoorPvP * pvp); + void ChangeState(); + void SendChangePhase(); + void FillInitialWorldStates(WorldPacket & data); + // used when player is activated/inactivated in the area + bool HandlePlayerEnter(Player * plr); + void HandlePlayerLeave(Player * plr); +protected: + void SummonFlightMaster(uint32 team); + void UpdateTowerState(); +protected: + uint32 m_FlightMasterSpawned; + uint32 m_TowerState; +}; + +class OutdoorPvPEP : public OutdoorPvP +{ +friend class OPvPCapturePointEP_EWT; +friend class OPvPCapturePointEP_NPT; +friend class OPvPCapturePointEP_PWT; +friend class OPvPCapturePointEP_CGT; +public: + OutdoorPvPEP(); + bool SetupOutdoorPvP(); + void HandlePlayerEnterZone(Player *plr, uint32 zone); + void HandlePlayerLeaveZone(Player *plr, uint32 zone); + bool Update(uint32 diff); + void FillInitialWorldStates(WorldPacket &data); + void SendRemoveWorldStates(Player * plr); + void BuffTeams(); +private: + // how many towers are controlled + uint32 EP_Controls[EP_TOWER_NUM]; + uint32 m_AllianceTowersControlled; + uint32 m_HordeTowersControlled; +}; + +#endif + diff --git a/src/server/game/OutdoorPvP/Zones/OutdoorPvPHP.cpp b/src/server/game/OutdoorPvP/Zones/OutdoorPvPHP.cpp new file mode 100644 index 00000000000..f4f73d015ce --- /dev/null +++ b/src/server/game/OutdoorPvP/Zones/OutdoorPvPHP.cpp @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OutdoorPvPHP.h" +#include "OutdoorPvP.h" +#include "OutdoorPvPMgr.h" +#include "Player.h" +#include "WorldPacket.h" +#include "World.h" +#include "ObjectMgr.h" +#include "Language.h" + +const uint32 HP_LANG_LOOSE_A[HP_TOWER_NUM] = {LANG_OPVP_HP_LOOSE_BROKENHILL_A,LANG_OPVP_HP_LOOSE_OVERLOOK_A,LANG_OPVP_HP_LOOSE_STADIUM_A}; + +const uint32 HP_LANG_LOOSE_H[HP_TOWER_NUM] = {LANG_OPVP_HP_LOOSE_BROKENHILL_H,LANG_OPVP_HP_LOOSE_OVERLOOK_H,LANG_OPVP_HP_LOOSE_STADIUM_H}; + +const uint32 HP_LANG_CAPTURE_A[HP_TOWER_NUM] = {LANG_OPVP_HP_CAPTURE_BROKENHILL_A,LANG_OPVP_HP_CAPTURE_OVERLOOK_A,LANG_OPVP_HP_CAPTURE_STADIUM_A}; + +const uint32 HP_LANG_CAPTURE_H[HP_TOWER_NUM] = {LANG_OPVP_HP_CAPTURE_BROKENHILL_H,LANG_OPVP_HP_CAPTURE_OVERLOOK_H,LANG_OPVP_HP_CAPTURE_STADIUM_H}; + +OPvPCapturePointHP::OPvPCapturePointHP(OutdoorPvP *pvp,OutdoorPvPHPTowerType type) +: OPvPCapturePoint(pvp), m_TowerType(type) +{ + SetCapturePointData(HPCapturePoints[type].entry, + HPCapturePoints[type].map, + HPCapturePoints[type].x, + HPCapturePoints[type].y, + HPCapturePoints[type].z, + HPCapturePoints[type].o, + HPCapturePoints[type].rot0, + HPCapturePoints[type].rot1, + HPCapturePoints[type].rot2, + HPCapturePoints[type].rot3); + AddObject(type, + HPTowerFlags[type].entry, + HPTowerFlags[type].map, + HPTowerFlags[type].x, + HPTowerFlags[type].y, + HPTowerFlags[type].z, + HPTowerFlags[type].o, + HPTowerFlags[type].rot0, + HPTowerFlags[type].rot1, + HPTowerFlags[type].rot2, + HPTowerFlags[type].rot3); +} + +OutdoorPvPHP::OutdoorPvPHP() +{ + m_TypeId = OUTDOOR_PVP_HP; +} + +bool OutdoorPvPHP::SetupOutdoorPvP() +{ + m_AllianceTowersControlled = 0; + m_HordeTowersControlled = 0; + // add the zones affected by the pvp buff + for (int i = 0; i < OutdoorPvPHPBuffZonesNum; ++i) + RegisterZone(OutdoorPvPHPBuffZones[i]); + + AddCapturePoint(new OPvPCapturePointHP(this,HP_TOWER_BROKEN_HILL)); + + AddCapturePoint(new OPvPCapturePointHP(this,HP_TOWER_OVERLOOK)); + + AddCapturePoint(new OPvPCapturePointHP(this,HP_TOWER_STADIUM)); + + return true; +} + +void OutdoorPvPHP::HandlePlayerEnterZone(Player * plr, uint32 zone) +{ + // add buffs + if (plr->GetTeam() == ALLIANCE) + { + if (m_AllianceTowersControlled >=3) + plr->CastSpell(plr,AllianceBuff,true); + } + else + { + if (m_HordeTowersControlled >=3) + plr->CastSpell(plr,HordeBuff,true); + } + OutdoorPvP::HandlePlayerEnterZone(plr,zone); +} + +void OutdoorPvPHP::HandlePlayerLeaveZone(Player * plr, uint32 zone) +{ + // remove buffs + if (plr->GetTeam() == ALLIANCE) + { + plr->RemoveAurasDueToSpell(AllianceBuff); + } + else + { + plr->RemoveAurasDueToSpell(HordeBuff); + } + OutdoorPvP::HandlePlayerLeaveZone(plr, zone); +} + +bool OutdoorPvPHP::Update(uint32 diff) +{ + bool changed = OutdoorPvP::Update(diff); + if (changed) + { + if (m_AllianceTowersControlled == 3) + TeamApplyBuff(TEAM_ALLIANCE, AllianceBuff, HordeBuff); + else if (m_HordeTowersControlled == 3) + TeamApplyBuff(TEAM_HORDE, HordeBuff, AllianceBuff); + else + { + TeamCastSpell(TEAM_ALLIANCE, -AllianceBuff); + TeamCastSpell(TEAM_HORDE, -HordeBuff); + } + SendUpdateWorldState(HP_UI_TOWER_COUNT_A, m_AllianceTowersControlled); + SendUpdateWorldState(HP_UI_TOWER_COUNT_H, m_HordeTowersControlled); + } + return changed; +} + +void OutdoorPvPHP::SendRemoveWorldStates(Player *plr) +{ + plr->SendUpdateWorldState(HP_UI_TOWER_DISPLAY_A,0); + plr->SendUpdateWorldState(HP_UI_TOWER_DISPLAY_H,0); + plr->SendUpdateWorldState(HP_UI_TOWER_COUNT_H,0); + plr->SendUpdateWorldState(HP_UI_TOWER_COUNT_A,0); + plr->SendUpdateWorldState(HP_UI_TOWER_SLIDER_N,0); + plr->SendUpdateWorldState(HP_UI_TOWER_SLIDER_POS,0); + plr->SendUpdateWorldState(HP_UI_TOWER_SLIDER_DISPLAY,0); + for (int i = 0; i < HP_TOWER_NUM; ++i) + { + plr->SendUpdateWorldState(HP_MAP_N[i],0); + plr->SendUpdateWorldState(HP_MAP_A[i],0); + plr->SendUpdateWorldState(HP_MAP_H[i],0); + } +} + +void OutdoorPvPHP::FillInitialWorldStates(WorldPacket &data) +{ + data << uint32(HP_UI_TOWER_DISPLAY_A) << uint32(1); + data << uint32(HP_UI_TOWER_DISPLAY_H) << uint32(1); + data << uint32(HP_UI_TOWER_COUNT_A) << uint32(m_AllianceTowersControlled); + data << uint32(HP_UI_TOWER_COUNT_H) << uint32(m_HordeTowersControlled); + data << uint32(HP_UI_TOWER_SLIDER_DISPLAY) << uint32(0); + data << uint32(HP_UI_TOWER_SLIDER_POS) << uint32(50); + data << uint32(HP_UI_TOWER_SLIDER_N) << uint32(100); + for (OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) + { + itr->second->FillInitialWorldStates(data); + } +} + +void OPvPCapturePointHP::ChangeState() +{ + uint32 field = 0; + switch(m_OldState) + { + case OBJECTIVESTATE_NEUTRAL: + field = HP_MAP_N[m_TowerType]; + break; + case OBJECTIVESTATE_ALLIANCE: + field = HP_MAP_A[m_TowerType]; + if (((OutdoorPvPHP*)m_PvP)->m_AllianceTowersControlled) + ((OutdoorPvPHP*)m_PvP)->m_AllianceTowersControlled--; + sWorld.SendZoneText(OutdoorPvPHPBuffZones[0],objmgr.GetTrinityStringForDBCLocale(HP_LANG_LOOSE_A[m_TowerType])); + break; + case OBJECTIVESTATE_HORDE: + field = HP_MAP_H[m_TowerType]; + if (((OutdoorPvPHP*)m_PvP)->m_HordeTowersControlled) + ((OutdoorPvPHP*)m_PvP)->m_HordeTowersControlled--; + sWorld.SendZoneText(OutdoorPvPHPBuffZones[0],objmgr.GetTrinityStringForDBCLocale(HP_LANG_LOOSE_H[m_TowerType])); + break; + case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: + field = HP_MAP_N[m_TowerType]; + break; + case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: + field = HP_MAP_N[m_TowerType]; + break; + case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: + field = HP_MAP_A[m_TowerType]; + break; + case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: + field = HP_MAP_H[m_TowerType]; + break; + } + + // send world state update + if (field) + { + m_PvP->SendUpdateWorldState(field, 0); + field = 0; + } + uint32 artkit = 21; + uint32 artkit2 = HP_TowerArtKit_N[m_TowerType]; + switch(m_State) + { + case OBJECTIVESTATE_NEUTRAL: + field = HP_MAP_N[m_TowerType]; + break; + case OBJECTIVESTATE_ALLIANCE: + field = HP_MAP_A[m_TowerType]; + artkit = 2; + artkit2 = HP_TowerArtKit_A[m_TowerType]; + if (((OutdoorPvPHP*)m_PvP)->m_AllianceTowersControlled<3) + ((OutdoorPvPHP*)m_PvP)->m_AllianceTowersControlled++; + sWorld.SendZoneText(OutdoorPvPHPBuffZones[0],objmgr.GetTrinityStringForDBCLocale(HP_LANG_CAPTURE_A[m_TowerType])); + break; + case OBJECTIVESTATE_HORDE: + field = HP_MAP_H[m_TowerType]; + artkit = 1; + artkit2 = HP_TowerArtKit_H[m_TowerType]; + if (((OutdoorPvPHP*)m_PvP)->m_HordeTowersControlled<3) + ((OutdoorPvPHP*)m_PvP)->m_HordeTowersControlled++; + sWorld.SendZoneText(OutdoorPvPHPBuffZones[0],objmgr.GetTrinityStringForDBCLocale(HP_LANG_CAPTURE_H[m_TowerType])); + break; + case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: + field = HP_MAP_N[m_TowerType]; + break; + case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: + field = HP_MAP_N[m_TowerType]; + break; + case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: + field = HP_MAP_A[m_TowerType]; + artkit = 2; + artkit2 = HP_TowerArtKit_A[m_TowerType]; + break; + case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: + field = HP_MAP_H[m_TowerType]; + artkit = 1; + artkit2 = HP_TowerArtKit_H[m_TowerType]; + break; + } + + GameObject* flag = HashMapHolder::Find(m_capturePointGUID); + GameObject* flag2 = HashMapHolder::Find(m_Objects[m_TowerType]); + if (flag) + { + flag->SetGoArtKit(artkit); + } + if (flag2) + { + flag2->SetGoArtKit(artkit2); + } + + // send world state update + if (field) + m_PvP->SendUpdateWorldState(field, 1); + + // complete quest objective + if (m_State == OBJECTIVESTATE_ALLIANCE || m_State == OBJECTIVESTATE_HORDE) + SendObjectiveComplete(HP_CREDITMARKER[m_TowerType], 0); +} + +void OPvPCapturePointHP::SendChangePhase() +{ + SendUpdateWorldState(HP_UI_TOWER_SLIDER_N, m_neutralValuePct); + // send these updates to only the ones in this objective + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + SendUpdateWorldState(HP_UI_TOWER_SLIDER_POS, phase); + // send this too, sometimes the slider disappears, dunno why :( + SendUpdateWorldState(HP_UI_TOWER_SLIDER_DISPLAY, 1); +} + +void OPvPCapturePointHP::FillInitialWorldStates(WorldPacket &data) +{ + switch(m_State) + { + case OBJECTIVESTATE_ALLIANCE: + case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: + data << uint32(HP_MAP_N[m_TowerType]) << uint32(0); + data << uint32(HP_MAP_A[m_TowerType]) << uint32(1); + data << uint32(HP_MAP_H[m_TowerType]) << uint32(0); + break; + case OBJECTIVESTATE_HORDE: + case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: + data << uint32(HP_MAP_N[m_TowerType]) << uint32(0); + data << uint32(HP_MAP_A[m_TowerType]) << uint32(0); + data << uint32(HP_MAP_H[m_TowerType]) << uint32(1); + break; + case OBJECTIVESTATE_NEUTRAL: + case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: + case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: + default: + data << uint32(HP_MAP_N[m_TowerType]) << uint32(1); + data << uint32(HP_MAP_A[m_TowerType]) << uint32(0); + data << uint32(HP_MAP_H[m_TowerType]) << uint32(0); + break; + } +} + +bool OPvPCapturePointHP::HandlePlayerEnter(Player *plr) +{ + if (OPvPCapturePoint::HandlePlayerEnter(plr)) + { + plr->SendUpdateWorldState(HP_UI_TOWER_SLIDER_DISPLAY, 1); + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + plr->SendUpdateWorldState(HP_UI_TOWER_SLIDER_POS, phase); + plr->SendUpdateWorldState(HP_UI_TOWER_SLIDER_N, m_neutralValuePct); + return true; + } + return false; +} + +void OPvPCapturePointHP::HandlePlayerLeave(Player *plr) +{ + plr->SendUpdateWorldState(HP_UI_TOWER_SLIDER_DISPLAY, 0); + OPvPCapturePoint::HandlePlayerLeave(plr); +} + +void OutdoorPvPHP::HandleKillImpl(Player *plr, Unit * killed) +{ + if (killed->GetTypeId() != TYPEID_PLAYER) + return; + + if (plr->GetTeam() == ALLIANCE && killed->ToPlayer()->GetTeam() != ALLIANCE) + plr->CastSpell(plr,AlliancePlayerKillReward,true); + else if (plr->GetTeam() == HORDE && killed->ToPlayer()->GetTeam() != HORDE) + plr->CastSpell(plr,HordePlayerKillReward,true); +} diff --git a/src/server/game/OutdoorPvP/Zones/OutdoorPvPHP.h b/src/server/game/OutdoorPvP/Zones/OutdoorPvPHP.h new file mode 100644 index 00000000000..e23eb1f9369 --- /dev/null +++ b/src/server/game/OutdoorPvP/Zones/OutdoorPvPHP.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OUTDOOR_PVP_HP_ +#define OUTDOOR_PVP_HP_ + +#include "OutdoorPvPImpl.h" + +#define OutdoorPvPHPBuffZonesNum 6 + // HP, citadel, ramparts, blood furnace, shattered halls, mag's lair +const uint32 OutdoorPvPHPBuffZones[OutdoorPvPHPBuffZonesNum] = { 3483, 3563, 3562, 3713, 3714, 3836 }; + +enum OutdoorPvPHPSpells +{ + AlliancePlayerKillReward = 32155, + HordePlayerKillReward = 32158, + AllianceBuff = 32071, + HordeBuff = 32049 +}; + +enum OutdoorPvPHPTowerType{ + HP_TOWER_BROKEN_HILL = 0, + HP_TOWER_OVERLOOK = 1, + HP_TOWER_STADIUM = 2, + HP_TOWER_NUM = 3 +}; + +const uint32 HP_CREDITMARKER[HP_TOWER_NUM] = {19032,19028,19029}; + +const uint32 HP_CapturePointEvent_Enter[HP_TOWER_NUM] = {11404,11396,11388}; + +const uint32 HP_CapturePointEvent_Leave[HP_TOWER_NUM] = {11403,11395,11387}; + +enum OutdoorPvPHPWorldStates{ + HP_UI_TOWER_DISPLAY_A = 0x9ba, + HP_UI_TOWER_DISPLAY_H = 0x9b9, + + HP_UI_TOWER_COUNT_H = 0x9ae, + HP_UI_TOWER_COUNT_A = 0x9ac, + + HP_UI_TOWER_SLIDER_N = 2475, + HP_UI_TOWER_SLIDER_POS = 2474, + HP_UI_TOWER_SLIDER_DISPLAY = 2473 +}; + +const uint32 HP_MAP_N[HP_TOWER_NUM] = {0x9b5,0x9b2,0x9a8}; + +const uint32 HP_MAP_A[HP_TOWER_NUM] = {0x9b3,0x9b0,0x9a7}; + +const uint32 HP_MAP_H[HP_TOWER_NUM] = {0x9b4,0x9b1,0x9a6}; + +const uint32 HP_TowerArtKit_A[HP_TOWER_NUM] = {65,62,67}; + +const uint32 HP_TowerArtKit_H[HP_TOWER_NUM] = {64,61,68}; + +const uint32 HP_TowerArtKit_N[HP_TOWER_NUM] = {66,63,69}; + +const go_type HPCapturePoints[HP_TOWER_NUM] = { + {182175,530,-471.462,3451.09,34.6432,0.174533,0,0,0.087156,0.996195}, // 0 - Broken Hill + {182174,530,-184.889,3476.93,38.205,-0.017453,0,0,0.008727,-0.999962}, // 1 - Overlook + {182173,530,-290.016,3702.42,56.6729,0.034907,0,0,0.017452,0.999848} // 2 - Stadium +}; + +const go_type HPTowerFlags[HP_TOWER_NUM] = { + {183514,530,-467.078,3528.17,64.7121,3.14159,0,0,1,0}, // 0 broken hill + {182525,530,-187.887,3459.38,60.0403,-3.12414,0,0,0.999962,-0.008727}, // 1 overlook + {183515,530,-289.610,3696.83,75.9447,3.12414,0,0,0.999962,0.008727} // 2 stadium +}; + +class OPvPCapturePointHP : public OPvPCapturePoint +{ +public: + OPvPCapturePointHP(OutdoorPvP * pvp, OutdoorPvPHPTowerType type); + void ChangeState(); + void SendChangePhase(); + void FillInitialWorldStates(WorldPacket & data); + // used when player is activated/inactivated in the area + bool HandlePlayerEnter(Player * plr); + void HandlePlayerLeave(Player * plr); +private: + OutdoorPvPHPTowerType m_TowerType; +}; + +class OutdoorPvPHP : public OutdoorPvP +{ +friend class OPvPCapturePointHP; +public: + OutdoorPvPHP(); + bool SetupOutdoorPvP(); + void HandlePlayerEnterZone(Player *plr, uint32 zone); + void HandlePlayerLeaveZone(Player *plr, uint32 zone); + bool Update(uint32 diff); + void FillInitialWorldStates(WorldPacket &data); + void SendRemoveWorldStates(Player * plr); + void HandleKillImpl(Player * plr, Unit * killed); +private: + // how many towers are controlled + uint32 m_AllianceTowersControlled; + uint32 m_HordeTowersControlled; +}; + +#endif + diff --git a/src/server/game/OutdoorPvP/Zones/OutdoorPvPNA.cpp b/src/server/game/OutdoorPvP/Zones/OutdoorPvPNA.cpp new file mode 100644 index 00000000000..2360c1e0fb0 --- /dev/null +++ b/src/server/game/OutdoorPvP/Zones/OutdoorPvPNA.cpp @@ -0,0 +1,664 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OutdoorPvPNA.h" +#include "Player.h" +#include "ObjectMgr.h" +#include "OutdoorPvPMgr.h" +#include "WorldPacket.h" +#include "Language.h" +#include "World.h" + +OutdoorPvPNA::OutdoorPvPNA() +{ + m_TypeId = OUTDOOR_PVP_NA; +} + +void OutdoorPvPNA::HandleKillImpl(Player *plr, Unit * killed) +{ + if (killed->GetTypeId() == TYPEID_PLAYER && plr->GetTeam() != killed->ToPlayer()->GetTeam()) + { + plr->KilledMonsterCredit(NA_CREDIT_MARKER,0); // 0 guid, btw it isn't even used in killedmonster function :S + if (plr->GetTeam() == ALLIANCE) + plr->CastSpell(plr,NA_KILL_TOKEN_ALLIANCE,true); + else + plr->CastSpell(plr,NA_KILL_TOKEN_HORDE,true); + } +} + +uint32 OPvPCapturePointNA::GetAliveGuardsCount() +{ + uint32 cnt = 0; + for (std::map::iterator itr = m_Creatures.begin(); itr != m_Creatures.end(); ++itr) + { + switch(itr->first) + { + case NA_NPC_GUARD_01: + case NA_NPC_GUARD_02: + case NA_NPC_GUARD_03: + case NA_NPC_GUARD_04: + case NA_NPC_GUARD_05: + case NA_NPC_GUARD_06: + case NA_NPC_GUARD_07: + case NA_NPC_GUARD_08: + case NA_NPC_GUARD_09: + case NA_NPC_GUARD_10: + case NA_NPC_GUARD_11: + case NA_NPC_GUARD_12: + case NA_NPC_GUARD_13: + case NA_NPC_GUARD_14: + case NA_NPC_GUARD_15: + { + if (Creature * cr = HashMapHolder::Find(itr->second)) + { + if (cr->isAlive()) + ++cnt; + } + else if (CreatureData const * cd = objmgr.GetCreatureData(GUID_LOPART(itr->second))) + { + if (!cd->is_dead) + ++cnt; + } + } + break; + default: + break; + } + } + return cnt; +} + +void OPvPCapturePointNA::SpawnNPCsForTeam(uint32 team) +{ + const creature_type * creatures = NULL; + if (team == ALLIANCE) + creatures=AllianceControlNPCs; + else if (team == HORDE) + creatures=HordeControlNPCs; + else + return; + for (int i = 0; i < NA_CONTROL_NPC_NUM; ++i) + AddCreature(i,creatures[i].entry,creatures[i].teamval,creatures[i].map,creatures[i].x,creatures[i].y,creatures[i].z,creatures[i].o,1000000); +} + +void OPvPCapturePointNA::DeSpawnNPCs() +{ + for (int i = 0; i < NA_CONTROL_NPC_NUM; ++i) + DelCreature(i); +} + +void OPvPCapturePointNA::SpawnGOsForTeam(uint32 team) +{ + const go_type * gos = NULL; + if (team == ALLIANCE) + gos=AllianceControlGOs; + else if (team == HORDE) + gos=HordeControlGOs; + else + return; + for (int i = 0; i < NA_CONTROL_GO_NUM; ++i) + { + if (i == NA_ROOST_S || + i == NA_ROOST_W || + i == NA_ROOST_N || + i == NA_ROOST_E || + i == NA_BOMB_WAGON_S || + i == NA_BOMB_WAGON_W || + i == NA_BOMB_WAGON_N || + i == NA_BOMB_WAGON_E) + continue; // roosts and bomb wagons are spawned when someone uses the matching destroyed roost + AddObject(i,gos[i].entry,gos[i].map,gos[i].x,gos[i].y,gos[i].z,gos[i].o,gos[i].rot0,gos[i].rot1,gos[i].rot2,gos[i].rot3); + } +} + +void OPvPCapturePointNA::DeSpawnGOs() +{ + for (int i = 0; i < NA_CONTROL_GO_NUM; ++i) + { + DelObject(i); + } +} + +void OPvPCapturePointNA::FactionTakeOver(uint32 team) +{ + if (m_ControllingFaction) + objmgr.RemoveGraveYardLink(NA_HALAA_GRAVEYARD,NA_HALAA_GRAVEYARD_ZONE,m_ControllingFaction,false); + if (m_ControllingFaction == ALLIANCE) + sWorld.SendZoneText(NA_HALAA_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_NA_LOOSE_A)); + else if (m_ControllingFaction == HORDE) + sWorld.SendZoneText(NA_HALAA_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_NA_LOOSE_H)); + + m_ControllingFaction = team; + if (m_ControllingFaction) + objmgr.AddGraveYardLink(NA_HALAA_GRAVEYARD,NA_HALAA_GRAVEYARD_ZONE,m_ControllingFaction,false); + DeSpawnGOs(); + DeSpawnNPCs(); + SpawnGOsForTeam(team); + SpawnNPCsForTeam(team); + m_GuardsAlive = NA_GUARDS_MAX; + m_capturable = false; + this->UpdateHalaaWorldState(); + if (team == ALLIANCE) + { + m_WyvernStateSouth = WYVERN_NEU_HORDE; + m_WyvernStateNorth = WYVERN_NEU_HORDE; + m_WyvernStateEast = WYVERN_NEU_HORDE; + m_WyvernStateWest = WYVERN_NEU_HORDE; + m_PvP->TeamApplyBuff(TEAM_ALLIANCE, NA_CAPTURE_BUFF); + m_PvP->SendUpdateWorldState(NA_UI_HORDE_GUARDS_SHOW, 0); + m_PvP->SendUpdateWorldState(NA_UI_ALLIANCE_GUARDS_SHOW, 1); + m_PvP->SendUpdateWorldState(NA_UI_GUARDS_LEFT, m_GuardsAlive); + sWorld.SendZoneText(NA_HALAA_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_NA_CAPTURE_A)); + } + else + { + m_WyvernStateSouth = WYVERN_NEU_ALLIANCE; + m_WyvernStateNorth = WYVERN_NEU_ALLIANCE; + m_WyvernStateEast = WYVERN_NEU_ALLIANCE; + m_WyvernStateWest = WYVERN_NEU_ALLIANCE; + m_PvP->TeamApplyBuff(TEAM_HORDE, NA_CAPTURE_BUFF); + m_PvP->SendUpdateWorldState(NA_UI_HORDE_GUARDS_SHOW, 1); + m_PvP->SendUpdateWorldState(NA_UI_ALLIANCE_GUARDS_SHOW, 0); + m_PvP->SendUpdateWorldState(NA_UI_GUARDS_LEFT, m_GuardsAlive); + sWorld.SendZoneText(NA_HALAA_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_NA_CAPTURE_H)); + } + UpdateWyvernRoostWorldState(NA_ROOST_S); + UpdateWyvernRoostWorldState(NA_ROOST_N); + UpdateWyvernRoostWorldState(NA_ROOST_W); + UpdateWyvernRoostWorldState(NA_ROOST_E); +} + +bool OPvPCapturePointNA::HandlePlayerEnter(Player *plr) +{ + if (OPvPCapturePoint::HandlePlayerEnter(plr)) + { + plr->SendUpdateWorldState(NA_UI_TOWER_SLIDER_DISPLAY, 1); + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + plr->SendUpdateWorldState(NA_UI_TOWER_SLIDER_POS, phase); + plr->SendUpdateWorldState(NA_UI_TOWER_SLIDER_N, m_neutralValuePct); + return true; + } + return false; +} + +void OPvPCapturePointNA::HandlePlayerLeave(Player *plr) +{ + plr->SendUpdateWorldState(NA_UI_TOWER_SLIDER_DISPLAY, 0); + OPvPCapturePoint::HandlePlayerLeave(plr); +} + +OPvPCapturePointNA::OPvPCapturePointNA(OutdoorPvP *pvp) : +OPvPCapturePoint(pvp), m_capturable(true), m_GuardsAlive(0), m_ControllingFaction(0), +m_HalaaState(HALAA_N), m_WyvernStateSouth(0), m_WyvernStateNorth(0), m_WyvernStateWest(0), +m_WyvernStateEast(0), m_RespawnTimer(NA_RESPAWN_TIME), m_GuardCheckTimer(NA_GUARD_CHECK_TIME) +{ + SetCapturePointData(182210,530,-1572.57,7945.3,-22.475,2.05949,0,0,0.857167,0.515038); +} + +bool OutdoorPvPNA::SetupOutdoorPvP() +{ +// m_TypeId = OUTDOOR_PVP_NA; _MUST_ be set in ctor, because of spawns cleanup + // add the zones affected by the pvp buff + RegisterZone(NA_BUFF_ZONE); + + // halaa + m_obj = new OPvPCapturePointNA(this); + if (!m_obj) + return false; + AddCapturePoint(m_obj); + + return true; +} + +void OutdoorPvPNA::HandlePlayerEnterZone(Player * plr, uint32 zone) +{ + // add buffs + if (plr->GetTeam() == m_obj->m_ControllingFaction) + plr->CastSpell(plr,NA_CAPTURE_BUFF,true); + OutdoorPvP::HandlePlayerEnterZone(plr,zone); +} + +void OutdoorPvPNA::HandlePlayerLeaveZone(Player * plr, uint32 zone) +{ + // remove buffs + plr->RemoveAurasDueToSpell(NA_CAPTURE_BUFF); + OutdoorPvP::HandlePlayerLeaveZone(plr, zone); +} + +void OutdoorPvPNA::FillInitialWorldStates(WorldPacket &data) +{ + m_obj->FillInitialWorldStates(data); +} + +void OPvPCapturePointNA::FillInitialWorldStates(WorldPacket &data) +{ + if (m_ControllingFaction == ALLIANCE) + { + data << NA_UI_HORDE_GUARDS_SHOW << uint32(0); + data << NA_UI_ALLIANCE_GUARDS_SHOW << uint32(1); + } + else if (m_ControllingFaction == HORDE) + { + data << NA_UI_HORDE_GUARDS_SHOW << uint32(1); + data << NA_UI_ALLIANCE_GUARDS_SHOW << uint32(0); + } + else + { + data << NA_UI_HORDE_GUARDS_SHOW << uint32(0); + data << NA_UI_ALLIANCE_GUARDS_SHOW << uint32(0); + } + + data << NA_UI_GUARDS_MAX << NA_GUARDS_MAX; + data << NA_UI_GUARDS_LEFT << uint32(m_GuardsAlive); + + data << NA_UI_TOWER_SLIDER_DISPLAY << uint32(0); + data << NA_UI_TOWER_SLIDER_POS << uint32(50); + data << NA_UI_TOWER_SLIDER_N << uint32(100); + + data << NA_MAP_WYVERN_NORTH_NEU_H << uint32(bool(m_WyvernStateNorth & WYVERN_NEU_HORDE)); + data << NA_MAP_WYVERN_NORTH_NEU_A << uint32(bool(m_WyvernStateNorth & WYVERN_NEU_ALLIANCE)); + data << NA_MAP_WYVERN_NORTH_H << uint32(bool(m_WyvernStateNorth & WYVERN_HORDE)); + data << NA_MAP_WYVERN_NORTH_A << uint32(bool(m_WyvernStateNorth & WYVERN_ALLIANCE)); + + data << NA_MAP_WYVERN_SOUTH_NEU_H << uint32(bool(m_WyvernStateSouth & WYVERN_NEU_HORDE)); + data << NA_MAP_WYVERN_SOUTH_NEU_A << uint32(bool(m_WyvernStateSouth & WYVERN_NEU_ALLIANCE)); + data << NA_MAP_WYVERN_SOUTH_H << uint32(bool(m_WyvernStateSouth & WYVERN_HORDE)); + data << NA_MAP_WYVERN_SOUTH_A << uint32(bool(m_WyvernStateSouth & WYVERN_ALLIANCE)); + + data << NA_MAP_WYVERN_WEST_NEU_H << uint32(bool(m_WyvernStateWest & WYVERN_NEU_HORDE)); + data << NA_MAP_WYVERN_WEST_NEU_A << uint32(bool(m_WyvernStateWest & WYVERN_NEU_ALLIANCE)); + data << NA_MAP_WYVERN_WEST_H << uint32(bool(m_WyvernStateWest & WYVERN_HORDE)); + data << NA_MAP_WYVERN_WEST_A << uint32(bool(m_WyvernStateWest & WYVERN_ALLIANCE)); + + data << NA_MAP_WYVERN_EAST_NEU_H << uint32(bool(m_WyvernStateEast & WYVERN_NEU_HORDE)); + data << NA_MAP_WYVERN_EAST_NEU_A << uint32(bool(m_WyvernStateEast & WYVERN_NEU_ALLIANCE)); + data << NA_MAP_WYVERN_EAST_H << uint32(bool(m_WyvernStateEast & WYVERN_HORDE)); + data << NA_MAP_WYVERN_EAST_A << uint32(bool(m_WyvernStateEast & WYVERN_ALLIANCE)); + + data << NA_MAP_HALAA_NEUTRAL << uint32(bool(m_HalaaState & HALAA_N)); + data << NA_MAP_HALAA_NEU_A << uint32(bool(m_HalaaState & HALAA_N_A)); + data << NA_MAP_HALAA_NEU_H << uint32(bool(m_HalaaState & HALAA_N_H)); + data << NA_MAP_HALAA_HORDE << uint32(bool(m_HalaaState & HALAA_H)); + data << NA_MAP_HALAA_ALLIANCE << uint32(bool(m_HalaaState & HALAA_A)); +} + +void OutdoorPvPNA::SendRemoveWorldStates(Player *plr) +{ + plr->SendUpdateWorldState(NA_UI_HORDE_GUARDS_SHOW,0); + plr->SendUpdateWorldState(NA_UI_ALLIANCE_GUARDS_SHOW,0); + plr->SendUpdateWorldState(NA_UI_GUARDS_MAX,0); + plr->SendUpdateWorldState(NA_UI_GUARDS_LEFT,0); + plr->SendUpdateWorldState(NA_UI_TOWER_SLIDER_DISPLAY,0); + plr->SendUpdateWorldState(NA_UI_TOWER_SLIDER_POS,0); + plr->SendUpdateWorldState(NA_UI_TOWER_SLIDER_N,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_NEU_H,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_NEU_A,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_H,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_A,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_NEU_H,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_NEU_A,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_H,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_A,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_WEST_NEU_H,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_WEST_NEU_A,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_WEST_H,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_WEST_A,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_EAST_NEU_H,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_EAST_NEU_A,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_EAST_H,0); + plr->SendUpdateWorldState(NA_MAP_WYVERN_EAST_A,0); + plr->SendUpdateWorldState(NA_MAP_HALAA_NEUTRAL,0); + plr->SendUpdateWorldState(NA_MAP_HALAA_NEU_A,0); + plr->SendUpdateWorldState(NA_MAP_HALAA_NEU_H,0); + plr->SendUpdateWorldState(NA_MAP_HALAA_HORDE,0); + plr->SendUpdateWorldState(NA_MAP_HALAA_ALLIANCE,0); +} + +bool OutdoorPvPNA::Update(uint32 diff) +{ + return m_obj->Update(diff); +} + +bool OPvPCapturePointNA::HandleCustomSpell(Player * plr, uint32 spellId, GameObject * /*go*/) +{ + std::vector nodes; + nodes.resize(2); + bool retval = false; + switch(spellId) + { + case NA_SPELL_FLY_NORTH: + nodes[0] = FlightPathStartNodes[NA_ROOST_N]; + nodes[1] = FlightPathEndNodes[NA_ROOST_N]; + plr->ActivateTaxiPathTo(nodes); + plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); + plr->UpdatePvP(true,true); + retval = true; + break; + case NA_SPELL_FLY_SOUTH: + nodes[0] = FlightPathStartNodes[NA_ROOST_S]; + nodes[1] = FlightPathEndNodes[NA_ROOST_S]; + plr->ActivateTaxiPathTo(nodes); + plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); + plr->UpdatePvP(true,true); + retval = true; + break; + case NA_SPELL_FLY_WEST: + nodes[0] = FlightPathStartNodes[NA_ROOST_W]; + nodes[1] = FlightPathEndNodes[NA_ROOST_W]; + plr->ActivateTaxiPathTo(nodes); + plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); + plr->UpdatePvP(true,true); + retval = true; + break; + case NA_SPELL_FLY_EAST: + nodes[0] = FlightPathStartNodes[NA_ROOST_E]; + nodes[1] = FlightPathEndNodes[NA_ROOST_E]; + plr->ActivateTaxiPathTo(nodes); + plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); + plr->UpdatePvP(true,true); + retval = true; + break; + default: + break; + } + + if (retval) + { + //Adding items + uint32 noSpaceForCount = 0; + + // check space and find places + ItemPosCountVec dest; + + int32 count = 10; + uint32 itemid = 24538; + // bomb id count + uint8 msg = plr->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemid, count, &noSpaceForCount); + if (msg != EQUIP_ERR_OK) // convert to possible store amount + count -= noSpaceForCount; + + if (count == 0 || dest.empty()) // can't add any + { + return true; + } + + Item* item = plr->StoreNewItem(dest, itemid, true); + + if (count > 0 && item) + { + plr->SendNewItem(item,count,true,false); + } + + return true; + } + return false; +} + +int32 OPvPCapturePointNA::HandleOpenGo(Player *plr, uint64 guid) +{ + uint32 retval = OPvPCapturePoint::HandleOpenGo(plr, guid); + if (retval >= 0) + { + const go_type * gos = NULL; + if (m_ControllingFaction == ALLIANCE) + gos=AllianceControlGOs; + else if (m_ControllingFaction == HORDE) + gos=HordeControlGOs; + else + return -1; + + int32 del = -1; + int32 del2 = -1; + int32 add = -1; + int32 add2 = -1; + + switch(retval) + { + case NA_DESTROYED_ROOST_S: + del = NA_DESTROYED_ROOST_S; + add = NA_ROOST_S; + add2 = NA_BOMB_WAGON_S; + if (m_ControllingFaction == HORDE) + m_WyvernStateSouth = WYVERN_ALLIANCE; + else + m_WyvernStateSouth = WYVERN_HORDE; + UpdateWyvernRoostWorldState(NA_ROOST_S); + break; + case NA_DESTROYED_ROOST_N: + del = NA_DESTROYED_ROOST_N; + add = NA_ROOST_N; + add2 = NA_BOMB_WAGON_N; + if (m_ControllingFaction == HORDE) + m_WyvernStateNorth = WYVERN_ALLIANCE; + else + m_WyvernStateNorth = WYVERN_HORDE; + UpdateWyvernRoostWorldState(NA_ROOST_N); + break; + case NA_DESTROYED_ROOST_W: + del = NA_DESTROYED_ROOST_W; + add = NA_ROOST_W; + add2 = NA_BOMB_WAGON_W; + if (m_ControllingFaction == HORDE) + m_WyvernStateWest = WYVERN_ALLIANCE; + else + m_WyvernStateWest = WYVERN_HORDE; + UpdateWyvernRoostWorldState(NA_ROOST_W); + break; + case NA_DESTROYED_ROOST_E: + del = NA_DESTROYED_ROOST_E; + add = NA_ROOST_E; + add2 = NA_BOMB_WAGON_E; + if (m_ControllingFaction == HORDE) + m_WyvernStateEast = WYVERN_ALLIANCE; + else + m_WyvernStateEast = WYVERN_HORDE; + UpdateWyvernRoostWorldState(NA_ROOST_E); + break; + case NA_BOMB_WAGON_S: + del = NA_BOMB_WAGON_S; + del2 = NA_ROOST_S; + add = NA_DESTROYED_ROOST_S; + if (m_ControllingFaction == HORDE) + m_WyvernStateSouth = WYVERN_NEU_ALLIANCE; + else + m_WyvernStateSouth = WYVERN_NEU_HORDE; + UpdateWyvernRoostWorldState(NA_ROOST_S); + break; + case NA_BOMB_WAGON_N: + del = NA_BOMB_WAGON_N; + del2 = NA_ROOST_N; + add = NA_DESTROYED_ROOST_N; + if (m_ControllingFaction == HORDE) + m_WyvernStateNorth = WYVERN_NEU_ALLIANCE; + else + m_WyvernStateNorth = WYVERN_NEU_HORDE; + UpdateWyvernRoostWorldState(NA_ROOST_N); + break; + case NA_BOMB_WAGON_W: + del = NA_BOMB_WAGON_W; + del2 = NA_ROOST_W; + add = NA_DESTROYED_ROOST_W; + if (m_ControllingFaction == HORDE) + m_WyvernStateWest = WYVERN_NEU_ALLIANCE; + else + m_WyvernStateWest = WYVERN_NEU_HORDE; + UpdateWyvernRoostWorldState(NA_ROOST_W); + break; + case NA_BOMB_WAGON_E: + del = NA_BOMB_WAGON_E; + del2 = NA_ROOST_E; + add = NA_DESTROYED_ROOST_E; + if (m_ControllingFaction == HORDE) + m_WyvernStateEast = WYVERN_NEU_ALLIANCE; + else + m_WyvernStateEast = WYVERN_NEU_HORDE; + UpdateWyvernRoostWorldState(NA_ROOST_E); + break; + default: + return -1; + break; + } + + if (del>-1) + DelObject(del); + + if (del2>-1) + DelObject(del2); + + if (add>-1) + AddObject(add,gos[add].entry,gos[add].map,gos[add].x,gos[add].y,gos[add].z,gos[add].o,gos[add].rot0,gos[add].rot1,gos[add].rot2,gos[add].rot3); + + if (add2>-1) + AddObject(add2,gos[add2].entry,gos[add2].map,gos[add2].x,gos[add2].y,gos[add2].z,gos[add2].o,gos[add2].rot0,gos[add2].rot1,gos[add2].rot2,gos[add2].rot3); + + return retval; + } + return -1; +} + +bool OPvPCapturePointNA::Update(uint32 diff) +{ + // let the controlling faction advance in phase + bool capturable = false; + if (m_ControllingFaction == ALLIANCE && m_activePlayers[0].size() > m_activePlayers[1].size()) + capturable = true; + else if (m_ControllingFaction == HORDE && m_activePlayers[0].size() < m_activePlayers[1].size()) + capturable = true; + + if (m_GuardCheckTimer < diff) + { + m_GuardCheckTimer = NA_GUARD_CHECK_TIME; + uint32 cnt = GetAliveGuardsCount(); + if (cnt != m_GuardsAlive) + { + m_GuardsAlive = cnt; + if (m_GuardsAlive == 0) + m_capturable = true; + // update the guard count for the players in zone + m_PvP->SendUpdateWorldState(NA_UI_GUARDS_LEFT,m_GuardsAlive); + } + } else m_GuardCheckTimer -= diff; + + if (m_capturable || capturable) + { + if (m_RespawnTimer < diff) + { + // if the guards have been killed, then the challenger has one hour to take over halaa. + // in case they fail to do it, the guards are respawned, and they have to start again. + if (m_ControllingFaction) + FactionTakeOver(m_ControllingFaction); + m_RespawnTimer = NA_RESPAWN_TIME; + } else m_RespawnTimer -= diff; + + return OPvPCapturePoint::Update(diff); + } + return false; +} + +void OPvPCapturePointNA::ChangeState() +{ + uint32 artkit = 21; + switch(m_State) + { + case OBJECTIVESTATE_NEUTRAL: + m_HalaaState = HALAA_N; + break; + case OBJECTIVESTATE_ALLIANCE: + m_HalaaState = HALAA_A; + FactionTakeOver(ALLIANCE); + artkit = 2; + break; + case OBJECTIVESTATE_HORDE: + m_HalaaState = HALAA_H; + FactionTakeOver(HORDE); + artkit = 1; + break; + case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: + m_HalaaState = HALAA_N_A; + break; + case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: + m_HalaaState = HALAA_N_H; + break; + case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: + m_HalaaState = HALAA_N_A; + artkit = 2; + break; + case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: + m_HalaaState = HALAA_N_H; + artkit = 1; + break; + } + + GameObject* flag = HashMapHolder::Find(m_capturePointGUID); + if (flag) + { + flag->SetGoArtKit(artkit); + } + + UpdateHalaaWorldState(); +} + +void OPvPCapturePointNA::SendChangePhase() +{ + // send this too, sometimes the slider disappears, dunno why :( + SendUpdateWorldState(NA_UI_TOWER_SLIDER_DISPLAY, 1); + // send these updates to only the ones in this objective + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + SendUpdateWorldState(NA_UI_TOWER_SLIDER_POS, phase); + SendUpdateWorldState(NA_UI_TOWER_SLIDER_N, m_neutralValuePct); +} + +void OPvPCapturePointNA::UpdateHalaaWorldState() +{ + m_PvP->SendUpdateWorldState(NA_MAP_HALAA_NEUTRAL ,uint32(bool(m_HalaaState & HALAA_N))); + m_PvP->SendUpdateWorldState(NA_MAP_HALAA_NEU_A ,uint32(bool(m_HalaaState & HALAA_N_A))); + m_PvP->SendUpdateWorldState(NA_MAP_HALAA_NEU_H ,uint32(bool(m_HalaaState & HALAA_N_H))); + m_PvP->SendUpdateWorldState(NA_MAP_HALAA_HORDE ,uint32(bool(m_HalaaState & HALAA_H))); + m_PvP->SendUpdateWorldState(NA_MAP_HALAA_ALLIANCE ,uint32(bool(m_HalaaState & HALAA_A))); +} + +void OPvPCapturePointNA::UpdateWyvernRoostWorldState(uint32 roost) +{ + switch(roost) + { + case NA_ROOST_S: + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_NEU_H,uint32(bool(m_WyvernStateSouth & WYVERN_NEU_HORDE))); + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_NEU_A,uint32(bool(m_WyvernStateSouth & WYVERN_NEU_ALLIANCE))); + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_H,uint32(bool(m_WyvernStateSouth & WYVERN_HORDE))); + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_SOUTH_A,uint32(bool(m_WyvernStateSouth & WYVERN_ALLIANCE))); + break; + case NA_ROOST_N: + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_NEU_H,uint32(bool(m_WyvernStateNorth & WYVERN_NEU_HORDE))); + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_NEU_A,uint32(bool(m_WyvernStateNorth & WYVERN_NEU_ALLIANCE))); + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_H,uint32(bool(m_WyvernStateNorth & WYVERN_HORDE))); + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_NORTH_A,uint32(bool(m_WyvernStateNorth & WYVERN_ALLIANCE))); + break; + case NA_ROOST_W: + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_WEST_NEU_H,uint32(bool(m_WyvernStateWest & WYVERN_NEU_HORDE))); + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_WEST_NEU_A,uint32(bool(m_WyvernStateWest & WYVERN_NEU_ALLIANCE))); + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_WEST_H,uint32(bool(m_WyvernStateWest & WYVERN_HORDE))); + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_WEST_A,uint32(bool(m_WyvernStateWest & WYVERN_ALLIANCE))); + break; + case NA_ROOST_E: + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_EAST_NEU_H,uint32(bool(m_WyvernStateEast & WYVERN_NEU_HORDE))); + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_EAST_NEU_A,uint32(bool(m_WyvernStateEast & WYVERN_NEU_ALLIANCE))); + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_EAST_H,uint32(bool(m_WyvernStateEast & WYVERN_HORDE))); + m_PvP->SendUpdateWorldState(NA_MAP_WYVERN_EAST_A,uint32(bool(m_WyvernStateEast & WYVERN_ALLIANCE))); + break; + } +} diff --git a/src/server/game/OutdoorPvP/Zones/OutdoorPvPNA.h b/src/server/game/OutdoorPvP/Zones/OutdoorPvPNA.h new file mode 100644 index 00000000000..124f51e8040 --- /dev/null +++ b/src/server/game/OutdoorPvP/Zones/OutdoorPvPNA.h @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OUTDOOR_PVP_NA_ +#define OUTDOOR_PVP_NA_ + +// TODO: "sometimes" set to neutral + +#include "OutdoorPvPImpl.h" +enum OutdoorPvPNASpells +{ + NA_KILL_TOKEN_ALLIANCE = 33005, + NA_KILL_TOKEN_HORDE = 33004, + NA_CAPTURE_BUFF = 33795 // strength of the halaani +}; +// kill credit for pks +const uint32 NA_CREDIT_MARKER = 24867; +const uint32 NA_GUARDS_MAX = 15; + +const uint32 NA_BUFF_ZONE = 3518; + +const uint32 NA_HALAA_GRAVEYARD = 993; + +const uint32 NA_HALAA_GRAVEYARD_ZONE = 3518; // need to add zone id, not area id + +const uint32 NA_RESPAWN_TIME = 3600000; // one hour to capture after defeating all guards + +const uint32 NA_GUARD_CHECK_TIME = 500; // every half second + +enum OutdoorPvPNAWorldStates{ + NA_UI_HORDE_GUARDS_SHOW = 2503, + NA_UI_ALLIANCE_GUARDS_SHOW = 2502, + NA_UI_GUARDS_MAX = 2493, + NA_UI_GUARDS_LEFT = 2491, + + NA_UI_TOWER_SLIDER_DISPLAY = 2495, + NA_UI_TOWER_SLIDER_POS = 2494, + NA_UI_TOWER_SLIDER_N = 2497, + + NA_MAP_WYVERN_NORTH_NEU_H = 2762, + NA_MAP_WYVERN_NORTH_NEU_A = 2662, + NA_MAP_WYVERN_NORTH_H = 2663, + NA_MAP_WYVERN_NORTH_A = 2664, + + NA_MAP_WYVERN_SOUTH_NEU_H = 2760, + NA_MAP_WYVERN_SOUTH_NEU_A = 2670, + NA_MAP_WYVERN_SOUTH_H = 2668, + NA_MAP_WYVERN_SOUTH_A = 2669, + + NA_MAP_WYVERN_WEST_NEU_H = 2761, + NA_MAP_WYVERN_WEST_NEU_A = 2667, + NA_MAP_WYVERN_WEST_H = 2665, + NA_MAP_WYVERN_WEST_A = 2666, + + NA_MAP_WYVERN_EAST_NEU_H = 2763, + NA_MAP_WYVERN_EAST_NEU_A = 2659, + NA_MAP_WYVERN_EAST_H = 2660, + NA_MAP_WYVERN_EAST_A = 2661, + + NA_MAP_HALAA_NEUTRAL = 2671, + NA_MAP_HALAA_NEU_A = 2676, + NA_MAP_HALAA_NEU_H = 2677, + NA_MAP_HALAA_HORDE = 2672, + NA_MAP_HALAA_ALLIANCE = 2673 +}; + +const uint32 FLIGHT_NODES_NUM = 4; + +// used to access the elements of Horde/AllyControlGOs +enum ControlGOTypes{ + NA_ROOST_S = 0, + NA_ROOST_W = 1, + NA_ROOST_N = 2, + NA_ROOST_E = 3, + + NA_BOMB_WAGON_S = 4, + NA_BOMB_WAGON_W = 5, + NA_BOMB_WAGON_N = 6, + NA_BOMB_WAGON_E = 7, + + NA_DESTROYED_ROOST_S = 8, + NA_DESTROYED_ROOST_W = 9, + NA_DESTROYED_ROOST_N = 10, + NA_DESTROYED_ROOST_E = 11, + + NA_CONTROL_GO_NUM = 12 +}; + +const uint32 FlightPathStartNodes[FLIGHT_NODES_NUM] = {103,105,107,109}; +const uint32 FlightPathEndNodes[FLIGHT_NODES_NUM] = {104,106,108,110}; + +enum FlightSpellsNA{ + NA_SPELL_FLY_SOUTH = 32059, + NA_SPELL_FLY_WEST = 32068, + NA_SPELL_FLY_NORTH = 32075, + NA_SPELL_FLY_EAST = 32081 +}; + +// spawned when the alliance is attacking, horde is in control +const go_type HordeControlGOs[NA_CONTROL_GO_NUM] = { + {182267,530,-1815.8,8036.51,-26.2354,-2.89725,0,0,0.992546,-0.121869}, //ALLY_ROOST_SOUTH + {182280,530,-1507.95,8132.1,-19.5585,-1.3439,0,0,0.622515,-0.782608}, //ALLY_ROOST_WEST + {182281,530,-1384.52,7779.33,-11.1663,-0.575959,0,0,0.284015,-0.95882}, //ALLY_ROOST_NORTH + {182282,530,-1650.11,7732.56,-15.4505,-2.80998,0,0,0.986286,-0.165048}, //ALLY_ROOST_EAST + + {182222,530,-1825.4022,8039.2602,-26.08,-2.89725,0,0,0.992546,-0.121869}, //HORDE_BOMB_WAGON_SOUTH + {182272,530,-1515.37,8136.91,-20.42,-1.3439,0,0,0.622515,-0.782608}, //HORDE_BOMB_WAGON_WEST + {182273,530,-1377.95,7773.44,-10.31,-0.575959,0,0,0.284015,-0.95882}, //HORDE_BOMB_WAGON_NORTH + {182274,530,-1659.87,7733.15,-15.75,-2.80998,0,0,0.986286,-0.165048}, //HORDE_BOMB_WAGON_EAST + + {182266,530,-1815.8,8036.51,-26.2354,-2.89725,0,0,0.992546,-0.121869}, //DESTROYED_ALLY_ROOST_SOUTH + {182275,530,-1507.95,8132.1,-19.5585,-1.3439,0,0,0.622515,-0.782608}, //DESTROYED_ALLY_ROOST_WEST + {182276,530,-1384.52,7779.33,-11.1663,-0.575959,0,0,0.284015,-0.95882}, //DESTROYED_ALLY_ROOST_NORTH + {182277,530,-1650.11,7732.56,-15.4505,-2.80998,0,0,0.986286,-0.165048} //DESTROYED_ALLY_ROOST_EAST +}; + +// spawned when the horde is attacking, alliance is in control +const go_type AllianceControlGOs[NA_CONTROL_GO_NUM] = { + {182301,530,-1815.8,8036.51,-26.2354,-2.89725,0,0,0.992546,-0.121869}, //HORDE_ROOST_SOUTH + {182302,530,-1507.95,8132.1,-19.5585,-1.3439,0,0,0.622515,-0.782608}, //HORDE_ROOST_WEST + {182303,530,-1384.52,7779.33,-11.1663,-0.575959,0,0,0.284015,-0.95882}, //HORDE_ROOST_NORTH + {182304,530,-1650.11,7732.56,-15.4505,-2.80998,0,0,0.986286,-0.165048}, //HORDE_ROOST_EAST + + {182305,530,-1825.4022,8039.2602,-26.08,-2.89725,0,0,0.992546,-0.121869}, //ALLY_BOMB_WAGON_SOUTH + {182306,530,-1515.37,8136.91,-20.42,-1.3439,0,0,0.622515,-0.782608}, //ALLY_BOMB_WAGON_WEST + {182307,530,-1377.95,7773.44,-10.31,-0.575959,0,0,0.284015,-0.95882}, //ALLY_BOMB_WAGON_NORTH + {182308,530,-1659.87,7733.15,-15.75,-2.80998,0,0,0.986286,-0.165048}, //ALLY_BOMB_WAGON_EAST + + {182297,530,-1815.8,8036.51,-26.2354,-2.89725,0,0,0.992546,-0.121869}, //DESTROYED_HORDE_ROOST_SOUTH + {182298,530,-1507.95,8132.1,-19.5585,-1.3439,0,0,0.622515,-0.782608}, //DESTROYED_HORDE_ROOST_WEST + {182299,530,-1384.52,7779.33,-11.1663,-0.575959,0,0,0.284015,-0.95882}, //DESTROYED_HORDE_ROOST_NORTH + {182300,530,-1650.11,7732.56,-15.4505,-2.80998,0,0,0.986286,-0.165048} //DESTROYED_HORDE_ROOST_EAST +}; + +enum ControlNPCTypes{ + NA_NPC_RESEARCHER = 0, + NA_NPC_QUARTERMASTER, + NA_NPC_BLADE_MERCHANT, + NA_NPC_FOOD_MERCHANT, + NA_NPC_AMMO, + + NA_NPC_GUARD_01, + NA_NPC_GUARD_02, + NA_NPC_GUARD_03, + NA_NPC_GUARD_04, + NA_NPC_GUARD_05, + NA_NPC_GUARD_06, + NA_NPC_GUARD_07, + NA_NPC_GUARD_08, + NA_NPC_GUARD_09, + NA_NPC_GUARD_10, + NA_NPC_GUARD_11, + NA_NPC_GUARD_12, + NA_NPC_GUARD_13, + NA_NPC_GUARD_14, + NA_NPC_GUARD_15, + + NA_CONTROL_NPC_NUM +}; + +const creature_type HordeControlNPCs[NA_CONTROL_NPC_NUM] = { + {18816,67,530,-1523.92,7951.76,-17.6942,3.51172}, + {18821,67,530,-1527.75,7952.46,-17.6948,3.99317}, + {21474,67,530,-1520.14,7927.11,-20.2527,3.39389}, + {21484,67,530,-1524.84,7930.34,-20.182,3.6405}, + {21483,67,530,-1570.01,7993.8,-22.4505,5.02655}, + {18192,67,530,-1654.06,8000.46,-26.59,3.37}, + {18192,67,530,-1487.18,7899.1,-19.53,0.954}, + {18192,67,530,-1480.88,7908.79,-19.19,4.485}, + {18192,67,530,-1540.56,7995.44,-20.45,0.947}, + {18192,67,530,-1546.95,8000.85,-20.72,6.035}, + {18192,67,530,-1595.31,7860.53,-21.51,3.747}, + {18192,67,530,-1642.31,7995.59,-25.8,3.317}, + {18192,67,530,-1545.46,7995.35,-20.63,1.094}, + {18192,67,530,-1487.58,7907.99,-19.27,5.567}, + {18192,67,530,-1651.54,7988.56,-26.5289,2.98451}, + {18192,67,530,-1602.46,7866.43,-22.1177,4.74729}, + {18192,67,530,-1591.22,7875.29,-22.3536,4.34587}, + {18192,67,530,-1550.6,7944.45,-21.63,3.559}, + {18192,67,530,-1545.57,7935.83,-21.13,3.448}, + {18192,67,530,-1550.86,7937.56,-21.7,3.801} +}; + +const creature_type AllianceControlNPCs[NA_CONTROL_NPC_NUM] = { + {18817,469,530,-1591.18,8020.39,-22.2042,4.59022}, + {18822,469,530,-1588.0,8019.0,-22.2042,4.06662}, + {21485,469,530,-1521.93,7927.37,-20.2299,3.24631}, + {21487,469,530,-1540.33,7971.95,-20.7186,3.07178}, + {21488,469,530,-1570.01,7993.8,-22.4505,5.02655}, + {18256,469,530,-1654.06,8000.46,-26.59,3.37}, + {18256,469,530,-1487.18,7899.1,-19.53,0.954}, + {18256,469,530,-1480.88,7908.79,-19.19,4.485}, + {18256,469,530,-1540.56,7995.44,-20.45,0.947}, + {18256,469,530,-1546.95,8000.85,-20.72,6.035}, + {18256,469,530,-1595.31,7860.53,-21.51,3.747}, + {18256,469,530,-1642.31,7995.59,-25.8,3.317}, + {18256,469,530,-1545.46,7995.35,-20.63,1.094}, + {18256,469,530,-1487.58,7907.99,-19.27,5.567}, + {18256,469,530,-1651.54,7988.56,-26.5289,2.98451}, + {18256,469,530,-1602.46,7866.43,-22.1177,4.74729}, + {18256,469,530,-1591.22,7875.29,-22.3536,4.34587}, + {18256,469,530,-1603.75,8000.36,-24.18,4.516}, + {18256,469,530,-1585.73,7994.68,-23.29,4.439}, + {18256,469,530,-1595.5,7991.27,-23.53,4.738} +}; + +enum WyvernStates{ + WYVERN_NEU_HORDE = 1, + WYVERN_NEU_ALLIANCE = 2, + WYVERN_HORDE = 4, + WYVERN_ALLIANCE = 8 +}; + +enum HalaaStates{ + HALAA_N = 1, + HALAA_N_A = 2, + HALAA_A = 4, + HALAA_N_H = 8, + HALAA_H = 16 +}; + +class Unit; +class Creature; +class OutdoorPvPNA; +class OPvPCapturePointNA : public OPvPCapturePoint +{ +friend class OutdoorPvPNA; +public: + OPvPCapturePointNA(OutdoorPvP * pvp); + bool Update(uint32 diff); + void ChangeState(); + void SendChangePhase(); + void FillInitialWorldStates(WorldPacket & data); + // used when player is activated/inactivated in the area + bool HandlePlayerEnter(Player * plr); + void HandlePlayerLeave(Player * plr); + bool HandleCustomSpell(Player *plr, uint32 spellId, GameObject * go); + int32 HandleOpenGo(Player *plr, uint64 guid); + uint32 GetAliveGuardsCount(); +protected: + // called when a faction takes control + void FactionTakeOver(uint32 team); + + void DeSpawnNPCs(); + void DeSpawnGOs(); + void SpawnNPCsForTeam(uint32 team); + void SpawnGOsForTeam(uint32 team); + + void UpdateWyvernRoostWorldState(uint32 roost); + void UpdateHalaaWorldState(); + +private: + bool m_capturable; + uint32 m_GuardsAlive; + uint32 m_ControllingFaction; + uint32 m_WyvernStateNorth; + uint32 m_WyvernStateSouth; + uint32 m_WyvernStateEast; + uint32 m_WyvernStateWest; + uint32 m_HalaaState; + uint32 m_RespawnTimer; + uint32 m_GuardCheckTimer; +}; + +class OutdoorPvPNA : public OutdoorPvP +{ +friend class OPvPCapturePointNA; +public: + OutdoorPvPNA(); + bool SetupOutdoorPvP(); + void HandlePlayerEnterZone(Player *plr, uint32 zone); + void HandlePlayerLeaveZone(Player *plr, uint32 zone); + bool Update(uint32 diff); + void FillInitialWorldStates(WorldPacket &data); + void SendRemoveWorldStates(Player * plr); + void HandleKillImpl(Player * plr, Unit * killed); +private: + OPvPCapturePointNA * m_obj; +}; + +#endif + diff --git a/src/server/game/OutdoorPvP/Zones/OutdoorPvPSI.cpp b/src/server/game/OutdoorPvP/Zones/OutdoorPvPSI.cpp new file mode 100644 index 00000000000..408901f9d06 --- /dev/null +++ b/src/server/game/OutdoorPvP/Zones/OutdoorPvPSI.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OutdoorPvPSI.h" +#include "WorldPacket.h" +#include "Player.h" +#include "GameObject.h" +#include "MapManager.h" +#include "ObjectMgr.h" +#include "OutdoorPvPMgr.h" +#include "Language.h" +#include "World.h" + +OutdoorPvPSI::OutdoorPvPSI() +{ + m_TypeId = OUTDOOR_PVP_SI; + m_Gathered_A = 0; + m_Gathered_H = 0; + m_LastController = 0; +} + +void OutdoorPvPSI::FillInitialWorldStates(WorldPacket &data) +{ + data << SI_GATHERED_A << m_Gathered_A; + data << SI_GATHERED_H << m_Gathered_H; + data << SI_SILITHYST_MAX << SI_MAX_RESOURCES; +} + +void OutdoorPvPSI::SendRemoveWorldStates(Player *plr) +{ + plr->SendUpdateWorldState(SI_GATHERED_A,0); + plr->SendUpdateWorldState(SI_GATHERED_H,0); + plr->SendUpdateWorldState(SI_SILITHYST_MAX,0); +} + +void OutdoorPvPSI::UpdateWorldState() +{ + SendUpdateWorldState(SI_GATHERED_A,m_Gathered_A); + SendUpdateWorldState(SI_GATHERED_H,m_Gathered_H); + SendUpdateWorldState(SI_SILITHYST_MAX,SI_MAX_RESOURCES); +} + +bool OutdoorPvPSI::SetupOutdoorPvP() +{ + for (int i = 0; i < OutdoorPvPSIBuffZonesNum; ++i) + RegisterZone(OutdoorPvPSIBuffZones[i]); + return true; +} + +bool OutdoorPvPSI::Update(uint32 /*diff*/) +{ + return false; +} + +void OutdoorPvPSI::HandlePlayerEnterZone(Player * plr, uint32 zone) +{ + if (plr->GetTeam() == m_LastController) + plr->CastSpell(plr,SI_CENARION_FAVOR,true); + OutdoorPvP::HandlePlayerEnterZone(plr,zone); +} + +void OutdoorPvPSI::HandlePlayerLeaveZone(Player * plr, uint32 zone) +{ + // remove buffs + plr->RemoveAurasDueToSpell(SI_CENARION_FAVOR); + OutdoorPvP::HandlePlayerLeaveZone(plr, zone); +} + +bool OutdoorPvPSI::HandleAreaTrigger(Player *plr, uint32 trigger) +{ + switch(trigger) + { + case SI_AREATRIGGER_A: + if (plr->GetTeam() == ALLIANCE && plr->HasAura(SI_SILITHYST_FLAG)) + { + // remove aura + plr->RemoveAurasDueToSpell(SI_SILITHYST_FLAG); + ++ m_Gathered_A; + if (m_Gathered_A >= SI_MAX_RESOURCES) + { + TeamApplyBuff(TEAM_ALLIANCE, SI_CENARION_FAVOR); + sWorld.SendZoneText(OutdoorPvPSIBuffZones[0],objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_SI_CAPTURE_A)); + m_LastController = ALLIANCE; + m_Gathered_A = 0; + m_Gathered_H = 0; + } + UpdateWorldState(); + // reward player + plr->CastSpell(plr,SI_TRACES_OF_SILITHYST,true); + // add 19 honor + plr->RewardHonor(NULL,1,19); + // add 20 cenarion circle repu + plr->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(609),20); + // complete quest + plr->KilledMonsterCredit(SI_TURNIN_QUEST_CM_A,0); + } + return true; + case SI_AREATRIGGER_H: + if (plr->GetTeam() == HORDE && plr->HasAura(SI_SILITHYST_FLAG)) + { + // remove aura + plr->RemoveAurasDueToSpell(SI_SILITHYST_FLAG); + ++ m_Gathered_H; + if (m_Gathered_H >= SI_MAX_RESOURCES) + { + TeamApplyBuff(TEAM_HORDE, SI_CENARION_FAVOR); + sWorld.SendZoneText(OutdoorPvPSIBuffZones[0],objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_SI_CAPTURE_H)); + m_LastController = HORDE; + m_Gathered_A = 0; + m_Gathered_H = 0; + } + UpdateWorldState(); + // reward player + plr->CastSpell(plr,SI_TRACES_OF_SILITHYST,true); + // add 19 honor + plr->RewardHonor(NULL,1,19); + // add 20 cenarion circle repu + plr->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(609),20); + // complete quest + plr->KilledMonsterCredit(SI_TURNIN_QUEST_CM_H,0); + } + return true; + } + return false; +} + +bool OutdoorPvPSI::HandleDropFlag(Player *plr, uint32 spellId) +{ + if (spellId == SI_SILITHYST_FLAG) + { + // if it was dropped away from the player's turn-in point, then create a silithyst mound, if it was dropped near the areatrigger, then it was dispelled by the outdoorpvp, so do nothing + switch(plr->GetTeam()) + { + case ALLIANCE: + { + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(SI_AREATRIGGER_A); + if (atEntry) + { + // 5.0f is safe-distance + if (plr->GetDistance(atEntry->x,atEntry->y,atEntry->z) > 5.0f + atEntry->radius) + { + // he dropped it further, summon mound + GameObject * go = new GameObject; + Map * map = plr->GetMap(); + if (!map) + { + delete go; + return true; + } + + if (!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),SI_SILITHYST_MOUND, map, plr->GetPhaseMask(), plr->GetPositionX(),plr->GetPositionY(),plr->GetPositionZ(),plr->GetOrientation(),0,0,0,0,100,GO_STATE_READY)) + { + delete go; + } + else + { + go->SetRespawnTime(0); + map->Add(go); + } + } + } + } + break; + case HORDE: + { + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(SI_AREATRIGGER_H); + if (atEntry) + { + // 5.0f is safe-distance + if (plr->GetDistance(atEntry->x,atEntry->y,atEntry->z) > 5.0f + atEntry->radius) + { + // he dropped it further, summon mound + GameObject * go = new GameObject; + Map * map = plr->GetMap(); + if (!map) + { + delete go; + return true; + } + if (!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),SI_SILITHYST_MOUND, map, plr->GetPhaseMask() ,plr->GetPositionX(),plr->GetPositionY(),plr->GetPositionZ(),plr->GetOrientation(),0,0,0,0,100,GO_STATE_READY)) + { + delete go; + } + else + { + go->SetRespawnTime(0); + map->Add(go); + } + } + } + } + break; + } + return true; + } + return false; +} + +bool OutdoorPvPSI::HandleCustomSpell(Player *plr, uint32 spellId, GameObject *go) +{ + if (!go || spellId != SI_SILITHYST_FLAG_GO_SPELL) + return false; + plr->CastSpell(plr,SI_SILITHYST_FLAG,true); + if (go->GetGOInfo()->id == SI_SILITHYST_MOUND) + { + // despawn go + go->SetRespawnTime(0); + go->Delete(); + } + return true; +} + diff --git a/src/server/game/OutdoorPvP/Zones/OutdoorPvPSI.h b/src/server/game/OutdoorPvP/Zones/OutdoorPvPSI.h new file mode 100644 index 00000000000..3176669c42c --- /dev/null +++ b/src/server/game/OutdoorPvP/Zones/OutdoorPvPSI.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OUTDOOR_PVP_SI_ +#define OUTDOOR_PVP_SI_ + +#include "OutdoorPvPImpl.h" + +enum OutdoorPvPSISpells +{ + SI_SILITHYST_FLAG_GO_SPELL = 29518, + SI_SILITHYST_FLAG = 29519, + SI_TRACES_OF_SILITHYST = 29534, + SI_CENARION_FAVOR = 30754 +}; + +const uint32 SI_MAX_RESOURCES = 200; + +const uint32 OutdoorPvPSIBuffZonesNum = 3; + +const uint32 OutdoorPvPSIBuffZones[OutdoorPvPSIBuffZonesNum] = { 1377, 3428, 3429 }; + +const uint32 SI_AREATRIGGER_H = 4168; + +const uint32 SI_AREATRIGGER_A = 4162; + +const uint32 SI_TURNIN_QUEST_CM_A = 17090; + +const uint32 SI_TURNIN_QUEST_CM_H = 18199; + +const uint32 SI_SILITHYST_MOUND = 181597; + +enum SI_WorldStates{ + SI_GATHERED_A = 2313, + SI_GATHERED_H = 2314, + SI_SILITHYST_MAX = 2317 +}; + +class OutdoorPvPSI : public OutdoorPvP +{ +public: + OutdoorPvPSI(); + bool SetupOutdoorPvP(); + void HandlePlayerEnterZone(Player *plr, uint32 zone); + void HandlePlayerLeaveZone(Player *plr, uint32 zone); + bool Update(uint32 diff); + void FillInitialWorldStates(WorldPacket &data); + void SendRemoveWorldStates(Player * plr); + bool HandleAreaTrigger(Player * plr, uint32 trigger); + bool HandleDropFlag(Player * plr, uint32 spellId); + bool HandleCustomSpell(Player * plr, uint32 spellId, GameObject *go); + void UpdateWorldState(); +private: + uint32 m_Gathered_A; + uint32 m_Gathered_H; + uint32 m_LastController; +}; + +#endif + diff --git a/src/server/game/OutdoorPvP/Zones/OutdoorPvPTF.cpp b/src/server/game/OutdoorPvP/Zones/OutdoorPvPTF.cpp new file mode 100644 index 00000000000..4d5682bf1d6 --- /dev/null +++ b/src/server/game/OutdoorPvP/Zones/OutdoorPvPTF.cpp @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OutdoorPvPTF.h" +#include "OutdoorPvPMgr.h" +#include "WorldPacket.h" +#include "Player.h" +#include "ObjectMgr.h" +#include "Language.h" +#include "World.h" + +OutdoorPvPTF::OutdoorPvPTF() +{ + m_TypeId = OUTDOOR_PVP_TF; +} + +OPvPCapturePointTF::OPvPCapturePointTF(OutdoorPvP *pvp, OutdoorPvPTF_TowerType type) +: OPvPCapturePoint(pvp), m_TowerType(type), m_TowerState(TF_TOWERSTATE_N) +{ + SetCapturePointData(TFCapturePoints[type].entry,TFCapturePoints[type].map,TFCapturePoints[type].x,TFCapturePoints[type].y,TFCapturePoints[type].z,TFCapturePoints[type].o,TFCapturePoints[type].rot0,TFCapturePoints[type].rot1,TFCapturePoints[type].rot2,TFCapturePoints[type].rot3); +} + +void OPvPCapturePointTF::FillInitialWorldStates(WorldPacket &data) +{ + data << uint32(TFTowerWorldStates[m_TowerType].n) << uint32(bool(m_TowerState & TF_TOWERSTATE_N)); + data << uint32(TFTowerWorldStates[m_TowerType].h) << uint32(bool(m_TowerState & TF_TOWERSTATE_H)); + data << uint32(TFTowerWorldStates[m_TowerType].a) << uint32(bool(m_TowerState & TF_TOWERSTATE_A)); +} + +void OutdoorPvPTF::FillInitialWorldStates(WorldPacket &data) +{ + data << TF_UI_TOWER_SLIDER_POS << uint32(50); + data << TF_UI_TOWER_SLIDER_N << uint32(100); + data << TF_UI_TOWER_SLIDER_DISPLAY << uint32(0); + + data << TF_UI_TOWER_COUNT_H << m_HordeTowersControlled; + data << TF_UI_TOWER_COUNT_A << m_AllianceTowersControlled; + data << TF_UI_TOWERS_CONTROLLED_DISPLAY << uint32(!m_IsLocked); + + data << TF_UI_LOCKED_TIME_MINUTES_FIRST_DIGIT << first_digit; + data << TF_UI_LOCKED_TIME_MINUTES_SECOND_DIGIT << second_digit; + data << TF_UI_LOCKED_TIME_HOURS << hours_left; + + data << TF_UI_LOCKED_DISPLAY_NEUTRAL << uint32(m_IsLocked && !m_HordeTowersControlled && !m_AllianceTowersControlled); + data << TF_UI_LOCKED_DISPLAY_HORDE << uint32(m_IsLocked && (m_HordeTowersControlled > m_AllianceTowersControlled)); + data << TF_UI_LOCKED_DISPLAY_ALLIANCE << uint32(m_IsLocked && (m_HordeTowersControlled < m_AllianceTowersControlled)); + + for (OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) + { + itr->second->FillInitialWorldStates(data); + } +} + +void OutdoorPvPTF::SendRemoveWorldStates(Player * plr) +{ + plr->SendUpdateWorldState(TF_UI_TOWER_SLIDER_POS,uint32(0)); + plr->SendUpdateWorldState(TF_UI_TOWER_SLIDER_N,uint32(0)); + plr->SendUpdateWorldState(TF_UI_TOWER_SLIDER_DISPLAY,uint32(0)); + + plr->SendUpdateWorldState(TF_UI_TOWER_COUNT_H,uint32(0)); + plr->SendUpdateWorldState(TF_UI_TOWER_COUNT_A,uint32(0)); + plr->SendUpdateWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY,uint32(0)); + + plr->SendUpdateWorldState(TF_UI_LOCKED_TIME_MINUTES_FIRST_DIGIT,uint32(0)); + plr->SendUpdateWorldState(TF_UI_LOCKED_TIME_MINUTES_SECOND_DIGIT,uint32(0)); + plr->SendUpdateWorldState(TF_UI_LOCKED_TIME_HOURS,uint32(0)); + + plr->SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL,uint32(0)); + plr->SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE,uint32(0)); + plr->SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE,uint32(0)); + + for (int i = 0; i < TF_TOWER_NUM; ++i) + { + plr->SendUpdateWorldState(uint32(TFTowerWorldStates[i].n),uint32(0)); + plr->SendUpdateWorldState(uint32(TFTowerWorldStates[i].h),uint32(0)); + plr->SendUpdateWorldState(uint32(TFTowerWorldStates[i].a),uint32(0)); + } +} + +void OPvPCapturePointTF::UpdateTowerState() +{ + m_PvP->SendUpdateWorldState(uint32(TFTowerWorldStates[m_TowerType].n),uint32(bool(m_TowerState & TF_TOWERSTATE_N))); + m_PvP->SendUpdateWorldState(uint32(TFTowerWorldStates[m_TowerType].h),uint32(bool(m_TowerState & TF_TOWERSTATE_H))); + m_PvP->SendUpdateWorldState(uint32(TFTowerWorldStates[m_TowerType].a),uint32(bool(m_TowerState & TF_TOWERSTATE_A))); +} + +bool OPvPCapturePointTF::HandlePlayerEnter(Player *plr) +{ + if (OPvPCapturePoint::HandlePlayerEnter(plr)) + { + plr->SendUpdateWorldState(TF_UI_TOWER_SLIDER_DISPLAY, 1); + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + plr->SendUpdateWorldState(TF_UI_TOWER_SLIDER_POS, phase); + plr->SendUpdateWorldState(TF_UI_TOWER_SLIDER_N, m_neutralValuePct); + return true; + } + return false; +} + +void OPvPCapturePointTF::HandlePlayerLeave(Player *plr) +{ + plr->SendUpdateWorldState(TF_UI_TOWER_SLIDER_DISPLAY, 0); + OPvPCapturePoint::HandlePlayerLeave(plr); +} + +bool OutdoorPvPTF::Update(uint32 diff) +{ + bool changed = OutdoorPvP::Update(diff); + + if (changed) + { + if (m_AllianceTowersControlled == TF_TOWER_NUM) + { + TeamApplyBuff(TEAM_ALLIANCE, TF_CAPTURE_BUFF); + m_IsLocked = true; + SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL,uint32(0)); + SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE,uint32(0)); + SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE,uint32(1)); + SendUpdateWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, uint32(0)); + } + else if (m_HordeTowersControlled == TF_TOWER_NUM) + { + TeamApplyBuff(TEAM_HORDE, TF_CAPTURE_BUFF); + m_IsLocked = true; + SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL,uint32(0)); + SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE,uint32(1)); + SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE,uint32(0)); + SendUpdateWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, uint32(0)); + } + else + { + TeamCastSpell(TEAM_ALLIANCE, -TF_CAPTURE_BUFF); + TeamCastSpell(TEAM_HORDE, -TF_CAPTURE_BUFF); + } + SendUpdateWorldState(TF_UI_TOWER_COUNT_A, m_AllianceTowersControlled); + SendUpdateWorldState(TF_UI_TOWER_COUNT_H, m_HordeTowersControlled); + } + if (m_IsLocked) + { + // lock timer is down, release lock + if (m_LockTimer < diff) + { + m_LockTimer = TF_LOCK_TIME; + m_LockTimerUpdate = 0; + m_IsLocked = false; + SendUpdateWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, uint32(1)); + SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL,uint32(0)); + SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE,uint32(0)); + SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE,uint32(0)); + } + else + { + // worldstateui update timer is down, update ui with new time data + if (m_LockTimerUpdate < diff) + { + m_LockTimerUpdate = TF_LOCK_TIME_UPDATE; + uint32 minutes_left = m_LockTimer / 60000; + hours_left = minutes_left / 60; + minutes_left -= hours_left * 60; + second_digit = minutes_left % 10; + first_digit = minutes_left / 10; + + SendUpdateWorldState(TF_UI_LOCKED_TIME_MINUTES_FIRST_DIGIT,first_digit); + SendUpdateWorldState(TF_UI_LOCKED_TIME_MINUTES_SECOND_DIGIT,second_digit); + SendUpdateWorldState(TF_UI_LOCKED_TIME_HOURS,hours_left); + } else m_LockTimerUpdate -= diff; + m_LockTimer -= diff; + } + } + return changed; +} + +void OutdoorPvPTF::HandlePlayerEnterZone(Player * plr, uint32 zone) +{ + if (plr->GetTeam() == ALLIANCE) + { + if (m_AllianceTowersControlled >= TF_TOWER_NUM) + plr->CastSpell(plr,TF_CAPTURE_BUFF,true); + } + else + { + if (m_HordeTowersControlled >= TF_TOWER_NUM) + plr->CastSpell(plr,TF_CAPTURE_BUFF,true); + } + OutdoorPvP::HandlePlayerEnterZone(plr,zone); +} + +void OutdoorPvPTF::HandlePlayerLeaveZone(Player * plr, uint32 zone) +{ + // remove buffs + plr->RemoveAurasDueToSpell(TF_CAPTURE_BUFF); + OutdoorPvP::HandlePlayerLeaveZone(plr, zone); +} + +bool OutdoorPvPTF::SetupOutdoorPvP() +{ + m_AllianceTowersControlled = 0; + m_HordeTowersControlled = 0; + + m_IsLocked = false; + m_LockTimer = TF_LOCK_TIME; + m_LockTimerUpdate = 0; + hours_left = 6; + second_digit = 0; + first_digit = 0; + + // add the zones affected by the pvp buff + for (int i = 0; i < OutdoorPvPTFBuffZonesNum; ++i) + RegisterZone(OutdoorPvPTFBuffZones[i]); + + AddCapturePoint(new OPvPCapturePointTF(this,TF_TOWER_NW)); + AddCapturePoint(new OPvPCapturePointTF(this,TF_TOWER_N)); + AddCapturePoint(new OPvPCapturePointTF(this,TF_TOWER_NE)); + AddCapturePoint(new OPvPCapturePointTF(this,TF_TOWER_SE)); + AddCapturePoint(new OPvPCapturePointTF(this,TF_TOWER_S)); + + return true; +} + +bool OPvPCapturePointTF::Update(uint32 diff) +{ + // can update even in locked state if gathers the controlling faction + bool canupdate = ((((OutdoorPvPTF*)m_PvP)->m_AllianceTowersControlled > 0) && m_activePlayers[0].size() > m_activePlayers[1].size()) || + ((((OutdoorPvPTF*)m_PvP)->m_HordeTowersControlled > 0) && m_activePlayers[0].size() < m_activePlayers[1].size()); + // if gathers the other faction, then only update if the pvp is unlocked + canupdate = canupdate || !((OutdoorPvPTF*)m_PvP)->m_IsLocked; + return canupdate && OPvPCapturePoint::Update(diff); +} + +void OPvPCapturePointTF::ChangeState() +{ + // if changing from controlling alliance to horde + if (m_OldState == OBJECTIVESTATE_ALLIANCE) + { + if (((OutdoorPvPTF*)m_PvP)->m_AllianceTowersControlled) + ((OutdoorPvPTF*)m_PvP)->m_AllianceTowersControlled--; + sWorld.SendZoneText(OutdoorPvPTFBuffZones[0],objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_TF_LOOSE_A)); + } + // if changing from controlling horde to alliance + else if (m_OldState == OBJECTIVESTATE_HORDE) + { + if (((OutdoorPvPTF*)m_PvP)->m_HordeTowersControlled) + ((OutdoorPvPTF*)m_PvP)->m_HordeTowersControlled--; + sWorld.SendZoneText(OutdoorPvPTFBuffZones[0],objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_TF_LOOSE_H)); + } + + uint32 artkit = 21; + + switch(m_State) + { + case OBJECTIVESTATE_ALLIANCE: + m_TowerState = TF_TOWERSTATE_A; + artkit = 2; + if (((OutdoorPvPTF*)m_PvP)->m_AllianceTowersControlledm_AllianceTowersControlled++; + sWorld.SendZoneText(OutdoorPvPTFBuffZones[0],objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_TF_CAPTURE_A)); + for (PlayerSet::iterator itr = m_activePlayers[0].begin(); itr != m_activePlayers[0].end(); ++itr) + (*itr)->AreaExploredOrEventHappens(TF_ALLY_QUEST); + break; + case OBJECTIVESTATE_HORDE: + m_TowerState = TF_TOWERSTATE_H; + artkit = 1; + if (((OutdoorPvPTF*)m_PvP)->m_HordeTowersControlledm_HordeTowersControlled++; + sWorld.SendZoneText(OutdoorPvPTFBuffZones[0],objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_TF_CAPTURE_H)); + for (PlayerSet::iterator itr = m_activePlayers[1].begin(); itr != m_activePlayers[1].end(); ++itr) + (*itr)->AreaExploredOrEventHappens(TF_HORDE_QUEST); + break; + case OBJECTIVESTATE_NEUTRAL: + case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: + case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: + case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: + case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: + m_TowerState = TF_TOWERSTATE_N; + break; + } + + GameObject* flag = HashMapHolder::Find(m_capturePointGUID); + if (flag) + flag->SetGoArtKit(artkit); + + UpdateTowerState(); +} + +void OPvPCapturePointTF::SendChangePhase() +{ + // send this too, sometimes the slider disappears, dunno why :( + SendUpdateWorldState(TF_UI_TOWER_SLIDER_DISPLAY, 1); + // send these updates to only the ones in this objective + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + SendUpdateWorldState(TF_UI_TOWER_SLIDER_POS, phase); + // send this too, sometimes it resets :S + SendUpdateWorldState(TF_UI_TOWER_SLIDER_N, m_neutralValuePct); +} + diff --git a/src/server/game/OutdoorPvP/Zones/OutdoorPvPTF.h b/src/server/game/OutdoorPvP/Zones/OutdoorPvPTF.h new file mode 100644 index 00000000000..3a88b7fd309 --- /dev/null +++ b/src/server/game/OutdoorPvP/Zones/OutdoorPvPTF.h @@ -0,0 +1,117 @@ +#ifndef OUTDOOR_PVP_TF_ +#define OUTDOOR_PVP_TF_ + +#include "OutdoorPvPImpl.h" + +const uint32 OutdoorPvPTFBuffZonesNum = 5; + +const uint32 OutdoorPvPTFBuffZones[OutdoorPvPTFBuffZonesNum] = { 3519 /*Terokkar Forest*/, 3791 /*Sethekk Halls*/, 3789 /*Shadow Labyrinth*/, 3792 /*Mana-Tombs*/, 3790 /*Auchenai Crypts*/ }; + +// locked for 6 hours after capture +const uint32 TF_LOCK_TIME = 3600 * 6 * 1000; +// update lock timer every 1/4 minute (overkill, but this way it's sure the timer won't "jump" 2 minutes at once.) +const uint32 TF_LOCK_TIME_UPDATE = 15000; + +// blessing of auchindoun +#define TF_CAPTURE_BUFF 33377 + +const uint32 TF_ALLY_QUEST = 11505; +const uint32 TF_HORDE_QUEST = 11506; + +enum OutdoorPvPTF_TowerType{ + TF_TOWER_NW = 0, + TF_TOWER_N, + TF_TOWER_NE, + TF_TOWER_SE, + TF_TOWER_S, + TF_TOWER_NUM +}; + +const go_type TFCapturePoints[TF_TOWER_NUM] = { + {183104,530,-3081.65,5335.03,17.1853,-2.14675,0,0,0.878817,-0.477159}, + {183411,530,-2939.9,4788.73,18.987,2.77507,0,0,0.983255,0.182236}, + {183412,530,-3174.94,4440.97,16.2281,1.86750,0,0.803857,0.594823}, + {183413,530,-3603.31,4529.15,20.9077,0.994838,0,0,0.477159,0.878817}, + {183414,530,-3812.37,4899.3,17.7249,0.087266,0,0,0.043619,0.999048} +}; + +struct tf_tower_world_state{ + uint32 n; + uint32 h; + uint32 a; +}; + +const tf_tower_world_state TFTowerWorldStates[TF_TOWER_NUM] = { + {0xa79,0xa7a,0xa7b}, + {0xa7e,0xa7d,0xa7c}, + {0xa82,0xa81,0xa80}, + {0xa88,0xa87,0xa86}, + {0xa85,0xa84,0xa83} +}; + +const uint32 TFTowerPlayerEnterEvents[TF_TOWER_NUM] = {12226, 12497, 12486, 12499, 12501}; + +const uint32 TFTowerPlayerLeaveEvents[TF_TOWER_NUM] = {12225, 12496, 12487, 12498, 12500}; + +enum TFWorldStates{ + TF_UI_TOWER_SLIDER_POS = 0xa41, + TF_UI_TOWER_SLIDER_N = 0xa40, + TF_UI_TOWER_SLIDER_DISPLAY = 0xa3f, + + TF_UI_TOWER_COUNT_H = 0xa3e, + TF_UI_TOWER_COUNT_A = 0xa3d, + TF_UI_TOWERS_CONTROLLED_DISPLAY = 0xa3c, + + TF_UI_LOCKED_TIME_MINUTES_FIRST_DIGIT = 0x9d0, + TF_UI_LOCKED_TIME_MINUTES_SECOND_DIGIT = 0x9ce, + TF_UI_LOCKED_TIME_HOURS = 0x9cd, + TF_UI_LOCKED_DISPLAY_NEUTRAL = 0x9cc, + TF_UI_LOCKED_DISPLAY_HORDE = 0xad0, + TF_UI_LOCKED_DISPLAY_ALLIANCE = 0xacf +}; + +enum TFTowerStates { + TF_TOWERSTATE_N = 1, + TF_TOWERSTATE_H = 2, + TF_TOWERSTATE_A = 4 +}; + +class OPvPCapturePointTF : public OPvPCapturePoint +{ +public: + OPvPCapturePointTF(OutdoorPvP * pvp, OutdoorPvPTF_TowerType type); + bool Update(uint32 diff); + void ChangeState(); + void SendChangePhase(); + void FillInitialWorldStates(WorldPacket & data); + // used when player is activated/inactivated in the area + bool HandlePlayerEnter(Player * plr); + void HandlePlayerLeave(Player * plr); + void UpdateTowerState(); +protected: + OutdoorPvPTF_TowerType m_TowerType; + uint32 m_TowerState; +}; + +class OutdoorPvPTF : public OutdoorPvP +{ +friend class OPvPCapturePointTF; +public: + OutdoorPvPTF(); + bool SetupOutdoorPvP(); + void HandlePlayerEnterZone(Player *plr, uint32 zone); + void HandlePlayerLeaveZone(Player *plr, uint32 zone); + bool Update(uint32 diff); + void FillInitialWorldStates(WorldPacket &data); + void SendRemoveWorldStates(Player * plr); +private: + bool m_IsLocked; + uint32 m_LockTimer; + uint32 m_LockTimerUpdate; + uint32 m_AllianceTowersControlled; + uint32 m_HordeTowersControlled; + uint32 hours_left, second_digit, first_digit; +}; + +#endif + diff --git a/src/server/game/OutdoorPvP/Zones/OutdoorPvPZM.cpp b/src/server/game/OutdoorPvP/Zones/OutdoorPvPZM.cpp new file mode 100644 index 00000000000..fb548816c3a --- /dev/null +++ b/src/server/game/OutdoorPvP/Zones/OutdoorPvPZM.cpp @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OutdoorPvPZM.h" +#include "ObjectMgr.h" +#include "OutdoorPvPMgr.h" +#include "Player.h" +#include "Creature.h" +#include "ObjectAccessor.h" +#include "WorldPacket.h" +#include "GossipDef.h" +#include "World.h" + +OPvPCapturePointZM_Beacon::OPvPCapturePointZM_Beacon(OutdoorPvP *pvp, ZM_BeaconType type) +: OPvPCapturePoint(pvp), m_TowerType(type), m_TowerState(ZM_TOWERSTATE_N) +{ + SetCapturePointData(ZMCapturePoints[type].entry,ZMCapturePoints[type].map,ZMCapturePoints[type].x,ZMCapturePoints[type].y,ZMCapturePoints[type].z,ZMCapturePoints[type].o,ZMCapturePoints[type].rot0,ZMCapturePoints[type].rot1,ZMCapturePoints[type].rot2,ZMCapturePoints[type].rot3); +} + +void OPvPCapturePointZM_Beacon::FillInitialWorldStates(WorldPacket &data) +{ + data << uint32(ZMBeaconInfo[m_TowerType].ui_tower_n) << uint32(bool(m_TowerState & ZM_TOWERSTATE_N)); + data << uint32(ZMBeaconInfo[m_TowerType].map_tower_n) << uint32(bool(m_TowerState & ZM_TOWERSTATE_N)); + data << uint32(ZMBeaconInfo[m_TowerType].ui_tower_a) << uint32(bool(m_TowerState & ZM_TOWERSTATE_A)); + data << uint32(ZMBeaconInfo[m_TowerType].map_tower_a) << uint32(bool(m_TowerState & ZM_TOWERSTATE_A)); + data << uint32(ZMBeaconInfo[m_TowerType].ui_tower_h) << uint32(bool(m_TowerState & ZM_TOWERSTATE_H)); + data << uint32(ZMBeaconInfo[m_TowerType].map_tower_h) << uint32(bool(m_TowerState & ZM_TOWERSTATE_H)); +} + +void OPvPCapturePointZM_Beacon::UpdateTowerState() +{ + m_PvP->SendUpdateWorldState(uint32(ZMBeaconInfo[m_TowerType].ui_tower_n),uint32(bool(m_TowerState & ZM_TOWERSTATE_N))); + m_PvP->SendUpdateWorldState(uint32(ZMBeaconInfo[m_TowerType].map_tower_n),uint32(bool(m_TowerState & ZM_TOWERSTATE_N))); + m_PvP->SendUpdateWorldState(uint32(ZMBeaconInfo[m_TowerType].ui_tower_a),uint32(bool(m_TowerState & ZM_TOWERSTATE_A))); + m_PvP->SendUpdateWorldState(uint32(ZMBeaconInfo[m_TowerType].map_tower_a),uint32(bool(m_TowerState & ZM_TOWERSTATE_A))); + m_PvP->SendUpdateWorldState(uint32(ZMBeaconInfo[m_TowerType].ui_tower_h),uint32(bool(m_TowerState & ZM_TOWERSTATE_H))); + m_PvP->SendUpdateWorldState(uint32(ZMBeaconInfo[m_TowerType].map_tower_h),uint32(bool(m_TowerState & ZM_TOWERSTATE_H))); +} + +bool OPvPCapturePointZM_Beacon::HandlePlayerEnter(Player *plr) +{ + if (OPvPCapturePoint::HandlePlayerEnter(plr)) + { + plr->SendUpdateWorldState(ZMBeaconInfo[m_TowerType].slider_disp, 1); + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + plr->SendUpdateWorldState(ZMBeaconInfo[m_TowerType].slider_pos, phase); + plr->SendUpdateWorldState(ZMBeaconInfo[m_TowerType].slider_n, m_neutralValuePct); + return true; + } + return false; +} + +void OPvPCapturePointZM_Beacon::HandlePlayerLeave(Player *plr) +{ + plr->SendUpdateWorldState(ZMBeaconInfo[m_TowerType].slider_disp, 0); + OPvPCapturePoint::HandlePlayerLeave(plr); +} + +void OPvPCapturePointZM_Beacon::ChangeState() +{ + // if changing from controlling alliance to horde + if (m_OldState == OBJECTIVESTATE_ALLIANCE) + { + if (((OutdoorPvPZM*)m_PvP)->m_AllianceTowersControlled) + ((OutdoorPvPZM*)m_PvP)->m_AllianceTowersControlled--; + sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(ZMBeaconLooseA[m_TowerType])); + } + // if changing from controlling horde to alliance + else if (m_OldState == OBJECTIVESTATE_HORDE) + { + if (((OutdoorPvPZM*)m_PvP)->m_HordeTowersControlled) + ((OutdoorPvPZM*)m_PvP)->m_HordeTowersControlled--; + sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(ZMBeaconLooseH[m_TowerType])); + } + + switch(m_State) + { + case OBJECTIVESTATE_ALLIANCE: + m_TowerState = ZM_TOWERSTATE_A; + if (((OutdoorPvPZM*)m_PvP)->m_AllianceTowersControlledm_AllianceTowersControlled++; + sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(ZMBeaconCaptureA[m_TowerType])); + break; + case OBJECTIVESTATE_HORDE: + m_TowerState = ZM_TOWERSTATE_H; + if (((OutdoorPvPZM*)m_PvP)->m_HordeTowersControlledm_HordeTowersControlled++; + sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(ZMBeaconCaptureH[m_TowerType])); + break; + case OBJECTIVESTATE_NEUTRAL: + case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: + case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: + case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: + case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: + m_TowerState = ZM_TOWERSTATE_N; + break; + } + + UpdateTowerState(); +} + +void OPvPCapturePointZM_Beacon::SendChangePhase() +{ + // send this too, sometimes the slider disappears, dunno why :( + SendUpdateWorldState(ZMBeaconInfo[m_TowerType].slider_disp, 1); + // send these updates to only the ones in this objective + uint32 phase = (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f); + SendUpdateWorldState(ZMBeaconInfo[m_TowerType].slider_pos, phase); + SendUpdateWorldState(ZMBeaconInfo[m_TowerType].slider_n, m_neutralValuePct); +} + +bool OutdoorPvPZM::Update(uint32 diff) +{ + bool changed = OutdoorPvP::Update(diff); + if (changed) + { + if (m_AllianceTowersControlled == ZM_NUM_BEACONS) + m_GraveYard->SetBeaconState(ALLIANCE); + else if (m_HordeTowersControlled == ZM_NUM_BEACONS) + m_GraveYard->SetBeaconState(HORDE); + else + m_GraveYard->SetBeaconState(0); + } + return changed; +} + +void OutdoorPvPZM::HandlePlayerEnterZone(Player * plr, uint32 zone) +{ + if (plr->GetTeam() == ALLIANCE) + { + if (m_GraveYard->m_GraveYardState & ZM_GRAVEYARD_A) + plr->CastSpell(plr,ZM_CAPTURE_BUFF,true); + } + else + { + if (m_GraveYard->m_GraveYardState & ZM_GRAVEYARD_H) + plr->CastSpell(plr,ZM_CAPTURE_BUFF,true); + } + OutdoorPvP::HandlePlayerEnterZone(plr,zone); +} + +void OutdoorPvPZM::HandlePlayerLeaveZone(Player * plr, uint32 zone) +{ + // remove buffs + plr->RemoveAurasDueToSpell(ZM_CAPTURE_BUFF); + // remove flag + plr->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_A); + plr->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_H); + OutdoorPvP::HandlePlayerLeaveZone(plr, zone); +} + +OutdoorPvPZM::OutdoorPvPZM() +{ + m_TypeId = OUTDOOR_PVP_ZM; + m_GraveYard = NULL; + m_AllianceTowersControlled = 0; + m_HordeTowersControlled = 0; + +} + +bool OutdoorPvPZM::SetupOutdoorPvP() +{ + m_AllianceTowersControlled = 0; + m_HordeTowersControlled = 0; + + // add the zones affected by the pvp buff + for (int i = 0; i < OutdoorPvPZMBuffZonesNum; ++i) + RegisterZone(OutdoorPvPZMBuffZones[i]); + + AddCapturePoint(new OPvPCapturePointZM_Beacon(this,ZM_BEACON_WEST)); + AddCapturePoint(new OPvPCapturePointZM_Beacon(this,ZM_BEACON_EAST)); + m_GraveYard = new OPvPCapturePointZM_GraveYard(this); + AddCapturePoint(m_GraveYard); // though the update function isn't used, the handleusego is! + + return true; +} + +void OutdoorPvPZM::HandleKillImpl(Player *plr, Unit * killed) +{ + if (killed->GetTypeId() != TYPEID_PLAYER) + return; + + if (plr->GetTeam() == ALLIANCE && killed->ToPlayer()->GetTeam() != ALLIANCE) + plr->CastSpell(plr,ZM_AlliancePlayerKillReward,true); + else if (plr->GetTeam() == HORDE && killed->ToPlayer()->GetTeam() != HORDE) + plr->CastSpell(plr,ZM_HordePlayerKillReward,true); +} + +bool OPvPCapturePointZM_GraveYard::Update(uint32 /*diff*/) +{ + bool retval = m_State != m_OldState; + m_State = m_OldState; + return retval; +} + +int32 OPvPCapturePointZM_GraveYard::HandleOpenGo(Player *plr, uint64 guid) +{ + uint32 retval = OPvPCapturePoint::HandleOpenGo(plr, guid); + if (retval >= 0) + { + if (plr->HasAura(ZM_BATTLE_STANDARD_A) && m_GraveYardState != ZM_GRAVEYARD_A) + { + if (m_GraveYardState == ZM_GRAVEYARD_H) + sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_ZM_LOOSE_GY_H)); + m_GraveYardState = ZM_GRAVEYARD_A; + DelObject(0); // only one gotype is used in the whole outdoor pvp, no need to call it a constant + AddObject(0,ZM_Banner_A.entry,ZM_Banner_A.map,ZM_Banner_A.x,ZM_Banner_A.y,ZM_Banner_A.z,ZM_Banner_A.o,ZM_Banner_A.rot0,ZM_Banner_A.rot1,ZM_Banner_A.rot2,ZM_Banner_A.rot3); + objmgr.RemoveGraveYardLink(ZM_GRAVEYARD_ID, ZM_GRAVEYARD_ZONE, HORDE); // rem gy + objmgr.AddGraveYardLink(ZM_GRAVEYARD_ID, ZM_GRAVEYARD_ZONE, ALLIANCE, false); // add gy + m_PvP->TeamApplyBuff(TEAM_ALLIANCE, ZM_CAPTURE_BUFF); + plr->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_A); + sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_ZM_CAPTURE_GY_A)); + } + else if (plr->HasAura(ZM_BATTLE_STANDARD_H) && m_GraveYardState != ZM_GRAVEYARD_H) + { + if (m_GraveYardState == ZM_GRAVEYARD_A) + sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_ZM_LOOSE_GY_A)); + m_GraveYardState = ZM_GRAVEYARD_H; + DelObject(0); // only one gotype is used in the whole outdoor pvp, no need to call it a constant + AddObject(0,ZM_Banner_H.entry,ZM_Banner_H.map,ZM_Banner_H.x,ZM_Banner_H.y,ZM_Banner_H.z,ZM_Banner_H.o,ZM_Banner_H.rot0,ZM_Banner_H.rot1,ZM_Banner_H.rot2,ZM_Banner_H.rot3); + objmgr.RemoveGraveYardLink(ZM_GRAVEYARD_ID, ZM_GRAVEYARD_ZONE, ALLIANCE); // rem gy + objmgr.AddGraveYardLink(ZM_GRAVEYARD_ID, ZM_GRAVEYARD_ZONE, HORDE, false); // add gy + m_PvP->TeamApplyBuff(TEAM_HORDE, ZM_CAPTURE_BUFF); + plr->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_H); + sWorld.SendZoneText(ZM_GRAVEYARD_ZONE,objmgr.GetTrinityStringForDBCLocale(LANG_OPVP_ZM_CAPTURE_GY_H)); + } + UpdateTowerState(); + } + return retval; +} + +OPvPCapturePointZM_GraveYard::OPvPCapturePointZM_GraveYard(OutdoorPvP *pvp) +: OPvPCapturePoint(pvp) +{ + m_BothControllingFaction = 0; + m_GraveYardState = ZM_GRAVEYARD_N; + m_FlagCarrierGUID = 0; + // add field scouts here + AddCreature(ZM_ALLIANCE_FIELD_SCOUT,ZM_AllianceFieldScout.entry,ZM_AllianceFieldScout.teamval,ZM_AllianceFieldScout.map,ZM_AllianceFieldScout.x,ZM_AllianceFieldScout.y,ZM_AllianceFieldScout.z,ZM_AllianceFieldScout.o); + AddCreature(ZM_HORDE_FIELD_SCOUT,ZM_HordeFieldScout.entry,ZM_HordeFieldScout.teamval,ZM_HordeFieldScout.map,ZM_HordeFieldScout.x,ZM_HordeFieldScout.y,ZM_HordeFieldScout.z,ZM_HordeFieldScout.o); + // add neutral banner + AddObject(0,ZM_Banner_N.entry,ZM_Banner_N.map,ZM_Banner_N.x,ZM_Banner_N.y,ZM_Banner_N.z,ZM_Banner_N.o,ZM_Banner_N.rot0,ZM_Banner_N.rot1,ZM_Banner_N.rot2,ZM_Banner_N.rot3); +} + +void OPvPCapturePointZM_GraveYard::UpdateTowerState() +{ + m_PvP->SendUpdateWorldState(ZM_MAP_GRAVEYARD_N,uint32(bool(m_GraveYardState & ZM_GRAVEYARD_N))); + m_PvP->SendUpdateWorldState(ZM_MAP_GRAVEYARD_H,uint32(bool(m_GraveYardState & ZM_GRAVEYARD_H))); + m_PvP->SendUpdateWorldState(ZM_MAP_GRAVEYARD_A,uint32(bool(m_GraveYardState & ZM_GRAVEYARD_A))); + + m_PvP->SendUpdateWorldState(ZM_MAP_ALLIANCE_FLAG_READY,uint32(m_BothControllingFaction == ALLIANCE)); + m_PvP->SendUpdateWorldState(ZM_MAP_ALLIANCE_FLAG_NOT_READY,uint32(m_BothControllingFaction != ALLIANCE)); + m_PvP->SendUpdateWorldState(ZM_MAP_HORDE_FLAG_READY,uint32(m_BothControllingFaction == HORDE)); + m_PvP->SendUpdateWorldState(ZM_MAP_HORDE_FLAG_NOT_READY,uint32(m_BothControllingFaction != HORDE)); +} + +void OPvPCapturePointZM_GraveYard::FillInitialWorldStates(WorldPacket &data) +{ + data << ZM_MAP_GRAVEYARD_N << uint32(bool(m_GraveYardState & ZM_GRAVEYARD_N)); + data << ZM_MAP_GRAVEYARD_H << uint32(bool(m_GraveYardState & ZM_GRAVEYARD_H)); + data << ZM_MAP_GRAVEYARD_A << uint32(bool(m_GraveYardState & ZM_GRAVEYARD_A)); + + data << ZM_MAP_ALLIANCE_FLAG_READY << uint32(m_BothControllingFaction == ALLIANCE); + data << ZM_MAP_ALLIANCE_FLAG_NOT_READY << uint32(m_BothControllingFaction != ALLIANCE); + data << ZM_MAP_HORDE_FLAG_READY << uint32(m_BothControllingFaction == HORDE); + data << ZM_MAP_HORDE_FLAG_NOT_READY << uint32(m_BothControllingFaction != HORDE); +} + +void OPvPCapturePointZM_GraveYard::SetBeaconState(uint32 controlling_faction) +{ + // nothing to do here + if (m_BothControllingFaction == controlling_faction) + return; + m_BothControllingFaction = controlling_faction; + + switch(controlling_faction) + { + case ALLIANCE: + // if ally already controls the gy and taken back both beacons, return, nothing to do for us + if (m_GraveYardState & ZM_GRAVEYARD_A) + return; + // ally doesn't control the gy, but controls the side beacons -> add gossip option, add neutral banner + break; + case HORDE: + // if horde already controls the gy and taken back both beacons, return, nothing to do for us + if (m_GraveYardState & ZM_GRAVEYARD_H) + return; + // horde doesn't control the gy, but controls the side beacons -> add gossip option, add neutral banner + break; + default: + // if the graveyard is not neutral, then leave it that way + // if the graveyard is neutral, then we have to dispel the buff from the flag carrier + if (m_GraveYardState & ZM_GRAVEYARD_N) + { + // gy was neutral, thus neutral banner was spawned, it is possible that someone was taking the flag to the gy + if (m_FlagCarrierGUID) + { + // remove flag from carrier, reset flag carrier guid + Player * p = objmgr.GetPlayer(m_FlagCarrierGUID); + if (p) + { + p->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_A); + p->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_H); + } + m_FlagCarrierGUID = 0; + } + } + break; + } + // send worldstateupdate + UpdateTowerState(); +} + +bool OPvPCapturePointZM_GraveYard::CanTalkTo(Player * plr, Creature * c, GossipMenuItems gso) +{ + uint64 guid = c->GetGUID(); + std::map::iterator itr = m_CreatureTypes.find(guid); + if (itr != m_CreatureTypes.end()) + { + if (itr->second == ZM_ALLIANCE_FIELD_SCOUT && plr->GetTeam() == ALLIANCE && m_BothControllingFaction == ALLIANCE && !m_FlagCarrierGUID && m_GraveYardState != ZM_GRAVEYARD_A) + return true; + else if (itr->second == ZM_HORDE_FIELD_SCOUT && plr->GetTeam() == HORDE && m_BothControllingFaction == HORDE && !m_FlagCarrierGUID && m_GraveYardState != ZM_GRAVEYARD_H) + return true; + } + return false; +} + +bool OPvPCapturePointZM_GraveYard::HandleGossipOption(Player *plr, uint64 guid, uint32 /*gossipid*/) +{ + std::map::iterator itr = m_CreatureTypes.find(guid); + if (itr != m_CreatureTypes.end()) + { + Creature * cr = HashMapHolder::Find(guid); + if (!cr) + return true; + // if the flag is already taken, then return + if (m_FlagCarrierGUID) + return true; + if (itr->second == ZM_ALLIANCE_FIELD_SCOUT) + { + cr->CastSpell(plr,ZM_BATTLE_STANDARD_A,true); + m_FlagCarrierGUID = plr->GetGUID(); + } + else if (itr->second == ZM_HORDE_FIELD_SCOUT) + { + cr->CastSpell(plr,ZM_BATTLE_STANDARD_H,true); + m_FlagCarrierGUID = plr->GetGUID(); + } + UpdateTowerState(); + plr->PlayerTalkClass->CloseGossip(); + return true; + } + return false; +} + +bool OPvPCapturePointZM_GraveYard::HandleDropFlag(Player * /*plr*/, uint32 spellId) +{ + switch(spellId) + { + case ZM_BATTLE_STANDARD_A: + m_FlagCarrierGUID = 0; + return true; + case ZM_BATTLE_STANDARD_H: + m_FlagCarrierGUID = 0; + return true; + } + return false; +} + +void OutdoorPvPZM::FillInitialWorldStates(WorldPacket &data) +{ + data << ZM_WORLDSTATE_UNK_1 << uint32(1); + for (OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) + { + itr->second->FillInitialWorldStates(data); + } +} + +void OutdoorPvPZM::SendRemoveWorldStates(Player *plr) +{ + plr->SendUpdateWorldState(ZM_UI_TOWER_SLIDER_N_W,0); + plr->SendUpdateWorldState(ZM_UI_TOWER_SLIDER_POS_W,0); + plr->SendUpdateWorldState(ZM_UI_TOWER_SLIDER_DISPLAY_W,0); + plr->SendUpdateWorldState(ZM_UI_TOWER_SLIDER_N_E,0); + plr->SendUpdateWorldState(ZM_UI_TOWER_SLIDER_POS_E,0); + plr->SendUpdateWorldState(ZM_UI_TOWER_SLIDER_DISPLAY_E,0); + plr->SendUpdateWorldState(ZM_WORLDSTATE_UNK_1,1); + plr->SendUpdateWorldState(ZM_UI_TOWER_EAST_N,0); + plr->SendUpdateWorldState(ZM_UI_TOWER_EAST_H,0); + plr->SendUpdateWorldState(ZM_UI_TOWER_EAST_A,0); + plr->SendUpdateWorldState(ZM_UI_TOWER_WEST_N,0); + plr->SendUpdateWorldState(ZM_UI_TOWER_WEST_H,0); + plr->SendUpdateWorldState(ZM_UI_TOWER_WEST_A,0); + plr->SendUpdateWorldState(ZM_MAP_TOWER_EAST_N,0); + plr->SendUpdateWorldState(ZM_MAP_TOWER_EAST_H,0); + plr->SendUpdateWorldState(ZM_MAP_TOWER_EAST_A,0); + plr->SendUpdateWorldState(ZM_MAP_GRAVEYARD_H,0); + plr->SendUpdateWorldState(ZM_MAP_GRAVEYARD_A,0); + plr->SendUpdateWorldState(ZM_MAP_GRAVEYARD_N,0); + plr->SendUpdateWorldState(ZM_MAP_TOWER_WEST_N,0); + plr->SendUpdateWorldState(ZM_MAP_TOWER_WEST_H,0); + plr->SendUpdateWorldState(ZM_MAP_TOWER_WEST_A,0); + plr->SendUpdateWorldState(ZM_MAP_HORDE_FLAG_READY,0); + plr->SendUpdateWorldState(ZM_MAP_HORDE_FLAG_NOT_READY,0); + plr->SendUpdateWorldState(ZM_MAP_ALLIANCE_FLAG_NOT_READY,0); + plr->SendUpdateWorldState(ZM_MAP_ALLIANCE_FLAG_READY,0); +} + diff --git a/src/server/game/OutdoorPvP/Zones/OutdoorPvPZM.h b/src/server/game/OutdoorPvP/Zones/OutdoorPvPZM.h new file mode 100644 index 00000000000..cd26e6bb527 --- /dev/null +++ b/src/server/game/OutdoorPvP/Zones/OutdoorPvPZM.h @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OUTDOOR_PVP_ZM_ +#define OUTDOOR_PVP_ZM_ + +#include "OutdoorPvPImpl.h" +#include "Language.h" + +const uint32 OutdoorPvPZMBuffZonesNum = 5; +// the buff is cast in these zones +const uint32 OutdoorPvPZMBuffZones[OutdoorPvPZMBuffZonesNum] = {3521,3607,3717,3715,3716}; +// linked when the central tower is controlled +const uint32 ZM_GRAVEYARD_ZONE = 3521; +// linked when the central tower is controlled +const uint32 ZM_GRAVEYARD_ID = 969; + +enum OutdoorPvPZMSpells +{ + // cast on the players of the controlling faction + ZM_CAPTURE_BUFF = 33779, // twin spire blessing + // spell that the field scout casts on the player to carry the flag + ZM_BATTLE_STANDARD_A = 32430, + // spell that the field scout casts on the player to carry the flag + ZM_BATTLE_STANDARD_H = 32431, + // token create spell + ZM_AlliancePlayerKillReward = 32155, + // token create spell + ZM_HordePlayerKillReward = 32158 +}; + +// banners 182527, 182528, 182529, gotta check them ingame +const go_type ZM_Banner_A = { 182527,530,253.54,7083.81,36.7728,-0.017453,0,0,0.008727,-0.999962 }; +const go_type ZM_Banner_H = { 182528,530,253.54,7083.81,36.7728,-0.017453,0,0,0.008727,-0.999962 }; +const go_type ZM_Banner_N = { 182529,530,253.54,7083.81,36.7728,-0.017453,0,0,0.008727,-0.999962 }; + +// horde field scout spawn data +const creature_type ZM_HordeFieldScout = {18564,67,530,296.625,7818.4,42.6294,5.18363}; +// alliance field scout spawn data +const creature_type ZM_AllianceFieldScout = {18581,469,530,374.395,6230.08,22.8351,0.593412}; + +enum ZMCreatureTypes{ + ZM_ALLIANCE_FIELD_SCOUT = 0, + ZM_HORDE_FIELD_SCOUT, + ZM_CREATURE_NUM +}; + +struct zm_beacon { + uint32 slider_disp; + uint32 slider_n; + uint32 slider_pos; + uint32 ui_tower_n; + uint32 ui_tower_h; + uint32 ui_tower_a; + uint32 map_tower_n; + uint32 map_tower_h; + uint32 map_tower_a; + uint32 event_enter; + uint32 event_leave; +}; + +enum ZM_BeaconType{ + ZM_BEACON_EAST = 0, + ZM_BEACON_WEST, + ZM_NUM_BEACONS +}; + +const zm_beacon ZMBeaconInfo[ZM_NUM_BEACONS] = { + {2533,2535,2534,2560,2559,2558,2652,2651,2650,11807,11806}, + {2527,2529,2528,2557,2556,2555,2646,2645,2644,11805,11804} +}; + +const uint32 ZMBeaconCaptureA[ZM_NUM_BEACONS] = { + LANG_OPVP_ZM_CAPTURE_EAST_A, + LANG_OPVP_ZM_CAPTURE_WEST_A +}; + +const uint32 ZMBeaconCaptureH[ZM_NUM_BEACONS] = { + LANG_OPVP_ZM_CAPTURE_EAST_H, + LANG_OPVP_ZM_CAPTURE_WEST_H +}; + +const uint32 ZMBeaconLooseA[ZM_NUM_BEACONS] = { + LANG_OPVP_ZM_LOOSE_EAST_A, + LANG_OPVP_ZM_LOOSE_WEST_A +}; + +const uint32 ZMBeaconLooseH[ZM_NUM_BEACONS] = { + LANG_OPVP_ZM_LOOSE_EAST_H, + LANG_OPVP_ZM_LOOSE_WEST_H +}; + +const go_type ZMCapturePoints[ZM_NUM_BEACONS] = { + {182523,530,303.243,6841.36,40.1245,-1.58825,0,0,0.71325,-0.700909}, + {182522,530,336.466,7340.26,41.4984,-1.58825,0,0,0.71325,-0.700909} +}; + +enum OutdoorPvPZMWorldStates +{ + ZM_UI_TOWER_SLIDER_N_W = 2529, + ZM_UI_TOWER_SLIDER_POS_W = 2528, + ZM_UI_TOWER_SLIDER_DISPLAY_W = 2527, + + ZM_UI_TOWER_SLIDER_N_E = 2535, + ZM_UI_TOWER_SLIDER_POS_E = 2534, + ZM_UI_TOWER_SLIDER_DISPLAY_E = 2533, + + ZM_WORLDSTATE_UNK_1 = 2653, + + ZM_UI_TOWER_EAST_N = 2560, + ZM_UI_TOWER_EAST_H = 2559, + ZM_UI_TOWER_EAST_A = 2558, + ZM_UI_TOWER_WEST_N = 2557, + ZM_UI_TOWER_WEST_H = 2556, + ZM_UI_TOWER_WEST_A = 2555, + + ZM_MAP_TOWER_EAST_N = 2652, + ZM_MAP_TOWER_EAST_H = 2651, + ZM_MAP_TOWER_EAST_A = 2650, + ZM_MAP_GRAVEYARD_H = 2649, + ZM_MAP_GRAVEYARD_A = 2648, + ZM_MAP_GRAVEYARD_N = 2647, + ZM_MAP_TOWER_WEST_N = 2646, + ZM_MAP_TOWER_WEST_H = 2645, + ZM_MAP_TOWER_WEST_A = 2644, + + ZM_MAP_HORDE_FLAG_READY = 2658, + ZM_MAP_HORDE_FLAG_NOT_READY = 2657, + ZM_MAP_ALLIANCE_FLAG_NOT_READY = 2656, + ZM_MAP_ALLIANCE_FLAG_READY = 2655 +}; + +enum ZM_TowerStateMask{ + ZM_TOWERSTATE_N = 1, + ZM_TOWERSTATE_A = 2, + ZM_TOWERSTATE_H = 4 +}; + +class OutdoorPvPZM; +class OPvPCapturePointZM_Beacon : public OPvPCapturePoint +{ +friend class OutdoorPvPZM; +public: + OPvPCapturePointZM_Beacon(OutdoorPvP * pvp, ZM_BeaconType type); + void ChangeState(); + void SendChangePhase(); + void FillInitialWorldStates(WorldPacket & data); + // used when player is activated/inactivated in the area + bool HandlePlayerEnter(Player * plr); + void HandlePlayerLeave(Player * plr); + void UpdateTowerState(); +protected: + ZM_BeaconType m_TowerType; + uint32 m_TowerState; +}; + +enum ZM_GraveYardState{ + ZM_GRAVEYARD_N = 1, + ZM_GRAVEYARD_A = 2, + ZM_GRAVEYARD_H = 4 +}; + +class OPvPCapturePointZM_GraveYard : public OPvPCapturePoint +{ +friend class OutdoorPvPZM; +public: + OPvPCapturePointZM_GraveYard(OutdoorPvP * pvp); + bool Update(uint32 diff); + void ChangeState() {} + void FillInitialWorldStates(WorldPacket & data); + void UpdateTowerState(); + int32 HandleOpenGo(Player *plr, uint64 guid); + void SetBeaconState(uint32 controlling_team); // not good atm + bool HandleGossipOption(Player * plr, uint64 guid, uint32 gossipid); + bool HandleDropFlag(Player * plr, uint32 spellId); + bool CanTalkTo(Player * plr, Creature * c, GossipMenuItems gso); +private: + uint32 m_GraveYardState; +protected: + uint32 m_BothControllingFaction; + uint64 m_FlagCarrierGUID; +}; + +class OutdoorPvPZM : public OutdoorPvP +{ +friend class OPvPCapturePointZM_Beacon; +public: + OutdoorPvPZM(); + bool SetupOutdoorPvP(); + void HandlePlayerEnterZone(Player *plr, uint32 zone); + void HandlePlayerLeaveZone(Player *plr, uint32 zone); + bool Update(uint32 diff); + void FillInitialWorldStates(WorldPacket &data); + void SendRemoveWorldStates(Player * plr); + void HandleKillImpl(Player * plr, Unit * killed); +private: + OPvPCapturePointZM_GraveYard * m_GraveYard; + uint32 m_AllianceTowersControlled; + uint32 m_HordeTowersControlled; +}; + +// todo: flag carrier death/leave/mount/activitychange should give back the gossip options +#endif + diff --git a/src/server/game/PrecompiledHeaders/ScriptedPch.cpp b/src/server/game/PrecompiledHeaders/ScriptedPch.cpp new file mode 100644 index 00000000000..a80690d05da --- /dev/null +++ b/src/server/game/PrecompiledHeaders/ScriptedPch.cpp @@ -0,0 +1,6 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 +* This program is free software licensed under GPL version 2 +* Please see the included DOCS/LICENSE.TXT for more information */ + +#include "ScriptedPch.h" + diff --git a/src/server/game/PrecompiledHeaders/ScriptedPch.h b/src/server/game/PrecompiledHeaders/ScriptedPch.h new file mode 100644 index 00000000000..1e83a88b87a --- /dev/null +++ b/src/server/game/PrecompiledHeaders/ScriptedPch.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 +* This program is free software licensed under GPL version 2 +* Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef SC_PRECOMPILED_H +#define SC_PRECOMPILED_H + +#include "ScriptMgr.h" +#include "Cell.h" +#include "CellImpl.h" +#include "GameEventMgr.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "Unit.h" +#include "GameObject.h" +#include "ScriptedCreature.h" +#include "ScriptedGossip.h" +#include "ScriptedInstance.h" +#include "CombatAI.h" +#include "PassiveAI.h" +#include "Chat.h" +#include "DBCStructure.h" +#include "DBCStores.h" +#include "ObjectMgr.h" + +#ifdef WIN32 +#include + +#endif + +#endif + diff --git a/src/server/game/Quests/QueryHandler.cpp b/src/server/game/Quests/QueryHandler.cpp deleted file mode 100644 index 1067ad49bc4..00000000000 --- a/src/server/game/Quests/QueryHandler.cpp +++ /dev/null @@ -1,539 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Language.h" -#include "Database/DatabaseEnv.h" -#include "Database/DatabaseImpl.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" -#include "World.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "UpdateMask.h" -#include "NPCHandler.h" -#include "Pet.h" -#include "MapManager.h" - -void WorldSession::SendNameQueryOpcode(Player *p) -{ - if (!p) - return; - // guess size - WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8+1+1+1+1+1+10)); - data.append(p->GetPackGUID()); // player guid - data << uint8(0); // added in 3.1 - data << p->GetName(); // played name - data << uint8(0); // realm name for cross realm BG usage - data << uint8(p->getRace()); - data << uint8(p->getGender()); - data << uint8(p->getClass()); - if (DeclinedName const* names = p->GetDeclinedNames()) - { - data << uint8(1); // is declined - for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - data << names->name[i]; - } - else - data << uint8(0); // is not declined - - SendPacket(&data); -} - -void WorldSession::SendNameQueryOpcodeFromDB(uint64 guid) -{ - CharacterDatabase.AsyncPQuery(&WorldSession::SendNameQueryOpcodeFromDBCallBack, GetAccountId(), - !sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) ? - // ------- Query Without Declined Names -------- - // 0 1 2 3 4 - "SELECT guid, name, race, gender, class " - "FROM characters WHERE guid = '%u'" - : - // --------- Query With Declined Names --------- - // 0 1 2 3 4 - "SELECT characters.guid, name, race, gender, class, " - // 5 6 7 8 9 - "genitive, dative, accusative, instrumental, prepositional " - "FROM characters LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid WHERE characters.guid = '%u'", - GUID_LOPART(guid)); -} - -void WorldSession::SendNameQueryOpcodeFromDBCallBack(QueryResult_AutoPtr result, uint32 accountId) -{ - if (!result) - return; - - WorldSession * session = sWorld.FindSession(accountId); - if (!session) - return; - - Field *fields = result->Fetch(); - uint32 guid = fields[0].GetUInt32(); - std::string name = fields[1].GetCppString(); - uint8 pRace = 0, pGender = 0, pClass = 0; - if (name == "") - name = session->GetTrinityString(LANG_NON_EXIST_CHARACTER); - else - { - pRace = fields[2].GetUInt8(); - pGender = fields[3].GetUInt8(); - pClass = fields[4].GetUInt8(); - } - // guess size - WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8+1+1+1+1+1+1+10)); - data.appendPackGUID(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); - data << uint8(0); // added in 3.1 - data << name; - data << uint8(0); // realm name for cross realm BG usage - data << uint8(pRace); // race - data << uint8(pGender); // gender - data << uint8(pClass); // class - - // if the first declined name field (5) is empty, the rest must be too - if (sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) && fields[5].GetCppString() != "") - { - data << uint8(1); // is declined - for (int i = 5; i < MAX_DECLINED_NAME_CASES+5; ++i) - data << fields[i].GetCppString(); - } - else - data << uint8(0); // is not declined - - session->SendPacket(&data); -} - -void WorldSession::HandleNameQueryOpcode(WorldPacket & recv_data) -{ - uint64 guid; - - recv_data >> guid; - - Player *pChar = objmgr.GetPlayer(guid); - - if (pChar) - SendNameQueryOpcode(pChar); - else - SendNameQueryOpcodeFromDB(guid); -} - -void WorldSession::HandleQueryTimeOpcode(WorldPacket & /*recv_data*/) -{ - SendQueryTimeResponse(); -} - -void WorldSession::SendQueryTimeResponse() -{ - WorldPacket data(SMSG_QUERY_TIME_RESPONSE, 4+4); - data << uint32(time(NULL)); - data << uint32(sWorld.GetNextDailyQuestsResetTime() - time(NULL)); - SendPacket(&data); -} - -/// Only _static_ data send in this packet !!! -void WorldSession::HandleCreatureQueryOpcode(WorldPacket & recv_data) -{ - uint32 entry; - recv_data >> entry; - uint64 guid; - recv_data >> guid; - - CreatureInfo const *ci = objmgr.GetCreatureTemplate(entry); - if (ci) - { - - std::string Name, SubName; - Name = ci->Name; - SubName = ci->SubName; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - CreatureLocale const *cl = objmgr.GetCreatureLocale(entry); - if (cl) - { - if (cl->Name.size() > size_t(loc_idx) && !cl->Name[loc_idx].empty()) - Name = cl->Name[loc_idx]; - if (cl->SubName.size() > size_t(loc_idx) && !cl->SubName[loc_idx].empty()) - SubName = cl->SubName[loc_idx]; - } - } - sLog.outDetail("WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u.", ci->Name, entry); - // guess size - WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 100); - data << uint32(entry); // creature entry - data << Name; - data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4, always empty - data << SubName; - data << ci->IconName; // "Directions" for guard, string for Icons 2.3.0 - data << uint32(ci->type_flags); // flags - data << uint32(ci->type); // CreatureType.dbc - data << uint32(ci->family); // CreatureFamily.dbc - data << uint32(ci->rank); // Creature Rank (elite, boss, etc) - data << uint32(ci->KillCredit[0]); // new in 3.1, kill credit - data << uint32(ci->KillCredit[1]); // new in 3.1, kill credit - data << uint32(ci->Modelid1); // Modelid1 - data << uint32(ci->Modelid2); // Modelid2 - data << uint32(ci->Modelid3); // Modelid3 - data << uint32(ci->Modelid4); // Modelid4 - data << float(ci->ModHealth); // dmg/hp modifier - data << float(ci->ModMana); // dmg/mana modifier - data << uint8(ci->RacialLeader); - for (uint32 i = 0; i < 6; ++i) - data << uint32(ci->questItems[i]); // itemId[6], quest drop - data << uint32(ci->movementId); // CreatureMovementInfo.dbc - SendPacket(&data); - sLog.outDebug("WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE"); - } - else - { - sLog.outDebug("WORLD: CMSG_CREATURE_QUERY - NO CREATURE INFO! (GUID: %u, ENTRY: %u)", - GUID_LOPART(guid), entry); - WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 4); - data << uint32(entry | 0x80000000); - SendPacket(&data); - sLog.outDebug("WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE"); - } -} - -/// Only _static_ data send in this packet !!! -void WorldSession::HandleGameObjectQueryOpcode(WorldPacket & recv_data) -{ - uint32 entryID; - recv_data >> entryID; - uint64 guid; - recv_data >> guid; - - const GameObjectInfo *info = objmgr.GetGameObjectInfo(entryID); - if (info) - { - std::string Name; - std::string IconName; - std::string CastBarCaption; - - Name = info->name; - IconName = info->IconName; - CastBarCaption = info->castBarCaption; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - GameObjectLocale const *gl = objmgr.GetGameObjectLocale(entryID); - if (gl) - { - if (gl->Name.size() > size_t(loc_idx) && !gl->Name[loc_idx].empty()) - Name = gl->Name[loc_idx]; - if (gl->CastBarCaption.size() > size_t(loc_idx) && !gl->CastBarCaption[loc_idx].empty()) - CastBarCaption = gl->CastBarCaption[loc_idx]; - } - } - sLog.outDetail("WORLD: CMSG_GAMEOBJECT_QUERY '%s' - Entry: %u. ", info->name, entryID); - WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 150); - data << uint32(entryID); - data << uint32(info->type); - data << uint32(info->displayId); - data << Name; - data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4 - data << IconName; // 2.0.3, string. Icon name to use instead of default icon for go's (ex: "Attack" makes sword) - data << CastBarCaption; // 2.0.3, string. Text will appear in Cast Bar when using GO (ex: "Collecting") - data << info->unk1; // 2.0.3, string - data.append(info->raw.data, 24); - data << float(info->size); // go size - for (uint32 i = 0; i < 6; ++i) - data << uint32(info->questItems[i]); // itemId[6], quest drop - SendPacket(&data); - sLog.outDebug("WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE"); - } - else - { - sLog.outDebug("WORLD: CMSG_GAMEOBJECT_QUERY - Missing gameobject info for (GUID: %u, ENTRY: %u)", - GUID_LOPART(guid), entryID); - WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 4); - data << uint32(entryID | 0x80000000); - SendPacket(&data); - sLog.outDebug("WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE"); - } -} - -void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDetail("WORLD: Received MSG_CORPSE_QUERY"); - - Corpse *corpse = GetPlayer()->GetCorpse(); - - if (!corpse) - { - WorldPacket data(MSG_CORPSE_QUERY, 1); - data << uint8(0); // corpse not found - SendPacket(&data); - return; - } - - uint32 mapid = corpse->GetMapId(); - float x = corpse->GetPositionX(); - float y = corpse->GetPositionY(); - float z = corpse->GetPositionZ(); - uint32 corpsemapid = mapid; - - // if corpse at different map - if (mapid != _player->GetMapId()) - { - // search entrance map for proper show entrance - if (MapEntry const* corpseMapEntry = sMapStore.LookupEntry(mapid)) - { - if (corpseMapEntry->IsDungeon() && corpseMapEntry->entrance_map >= 0) - { - // if corpse map have entrance - if (Map const* entranceMap = MapManager::Instance().CreateBaseMap(corpseMapEntry->entrance_map)) - { - mapid = corpseMapEntry->entrance_map; - x = corpseMapEntry->entrance_x; - y = corpseMapEntry->entrance_y; - z = entranceMap->GetHeight(x, y, MAX_HEIGHT); - } - } - } - } - - WorldPacket data(MSG_CORPSE_QUERY, 1+(6*4)); - data << uint8(1); // corpse found - data << int32(mapid); - data << float(x); - data << float(y); - data << float(z); - data << int32(corpsemapid); - data << uint32(0); // unknown - SendPacket(&data); -} - -void WorldSession::HandleNpcTextQueryOpcode(WorldPacket & recv_data) -{ - uint32 textID; - uint64 guid; - - recv_data >> textID; - sLog.outDetail("WORLD: CMSG_NPC_TEXT_QUERY ID '%u'", textID); - - recv_data >> guid; - GetPlayer()->SetUInt64Value(UNIT_FIELD_TARGET, guid); - - GossipText const* pGossip = objmgr.GetGossipText(textID); - - WorldPacket data(SMSG_NPC_TEXT_UPDATE, 100); // guess size - data << textID; - - if (!pGossip) - { - for (uint32 i = 0; i < 8; ++i) - { - data << float(0); - data << "Greetings $N"; - data << "Greetings $N"; - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - } - } - else - { - std::string Text_0[8], Text_1[8]; - for (int i = 0; i < 8; ++i) - { - Text_0[i]=pGossip->Options[i].Text_0; - Text_1[i]=pGossip->Options[i].Text_1; - } - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textID); - if (nl) - { - for (int i = 0; i < 8; ++i) - { - if (nl->Text_0[i].size() > size_t(loc_idx) && !nl->Text_0[i][loc_idx].empty()) - Text_0[i]=nl->Text_0[i][loc_idx]; - if (nl->Text_1[i].size() > size_t(loc_idx) && !nl->Text_1[i][loc_idx].empty()) - Text_1[i]=nl->Text_1[i][loc_idx]; - } - } - } - - for (int i = 0; i < 8; ++i) - { - data << pGossip->Options[i].Probability; - - if (Text_0[i].empty()) - data << Text_1[i]; - else - data << Text_0[i]; - - if (Text_1[i].empty()) - data << Text_0[i]; - else - data << Text_1[i]; - - data << pGossip->Options[i].Language; - - for (int j = 0; j < 3; ++j) - { - data << pGossip->Options[i].Emotes[j]._Delay; - data << pGossip->Options[i].Emotes[j]._Emote; - } - } - } - - SendPacket(&data); - - sLog.outDebug("WORLD: Sent SMSG_NPC_TEXT_UPDATE"); -} - -void WorldSession::HandlePageTextQueryOpcode(WorldPacket & recv_data) -{ - sLog.outDetail("WORLD: Received CMSG_PAGE_TEXT_QUERY"); - recv_data.hexlike(); - - uint32 pageID; - recv_data >> pageID; - recv_data.read_skip(); // guid - - while (pageID) - { - PageText const *pPage = sPageTextStore.LookupEntry(pageID); - // guess size - WorldPacket data(SMSG_PAGE_TEXT_QUERY_RESPONSE, 50); - data << pageID; - - if (!pPage) - { - data << "Item page missing."; - data << uint32(0); - pageID = 0; - } - else - { - std::string Text = pPage->Text; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - PageTextLocale const *pl = objmgr.GetPageTextLocale(pageID); - if (pl) - { - if (pl->Text.size() > size_t(loc_idx) && !pl->Text[loc_idx].empty()) - Text = pl->Text[loc_idx]; - } - } - - data << Text; - data << uint32(pPage->Next_Page); - pageID = pPage->Next_Page; - } - SendPacket(&data); - - sLog.outDebug("WORLD: Sent SMSG_PAGE_TEXT_QUERY_RESPONSE"); - } -} - -void WorldSession::HandleCorpseMapPositionQuery(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: Recv CMSG_CORPSE_MAP_POSITION_QUERY"); - - uint32 unk; - recv_data >> unk; - - WorldPacket data(SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE, 4+4+4+4); - data << float(0); - data << float(0); - data << float(0); - data << float(0); - SendPacket(&data); -} - -void WorldSession::HandleQuestPOIQuery(WorldPacket& recv_data) -{ - uint32 count; - recv_data >> count; // quest count, max=25 - - if (count >= MAX_QUEST_LOG_SIZE) - return; - - WorldPacket data(SMSG_QUEST_POI_QUERY_RESPONSE, 4+(4+4)*count); - data << uint32(count); // count - - for (int i = 0; i < count; ++i) - { - uint32 questId; - recv_data >> questId; // quest id - - bool questOk = false; - - uint16 questSlot = _player->FindQuestSlot(questId); - - if (questSlot != MAX_QUEST_LOG_SIZE) - questOk =_player->GetQuestSlotQuestId(questSlot) == questId; - - if (questOk) - { - QuestPOIVector const *POI = objmgr.GetQuestPOIVector(questId); - - if (POI) - { - data << uint32(questId); // quest ID - data << uint32(POI->size()); // POI count - - for (QuestPOIVector::const_iterator itr = POI->begin(); itr != POI->end(); ++itr) - { - data << uint32(itr->Id); // POI index - data << int32(itr->ObjectiveIndex); // objective index - data << uint32(itr->MapId); // mapid - data << uint32(itr->AreaId); // areaid - data << uint32(itr->Unk2); // unknown - data << uint32(itr->Unk3); // unknown - data << uint32(itr->Unk4); // unknown - data << uint32(itr->points.size()); // POI points count - - for (std::vector::const_iterator itr2 = itr->points.begin(); itr2 != itr->points.end(); ++itr2) - { - data << int32(itr2->x); // POI point x - data << int32(itr2->y); // POI point y - } - } - } - else - { - data << uint32(questId); // quest ID - data << uint32(0); // POI count - } - } - else - { - data << uint32(questId); // quest ID - data << uint32(0); // POI count - } - } - - SendPacket(&data); -} \ No newline at end of file diff --git a/src/server/game/Quests/QuestHandler.cpp b/src/server/game/Quests/QuestHandler.cpp deleted file mode 100644 index 8043f5ed149..00000000000 --- a/src/server/game/Quests/QuestHandler.cpp +++ /dev/null @@ -1,721 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Log.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "World.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "GossipDef.h" -#include "QuestDef.h" -#include "ObjectAccessor.h" -#include "Group.h" -#include "BattleGround.h" -#include "BattleGroundAV.h" -#include "ScriptMgr.h" - -void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - uint8 questStatus = DIALOG_STATUS_NONE; - uint8 defstatus = DIALOG_STATUS_NONE; - - Object* questgiver = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); - if (!questgiver) - { - sLog.outDetail("Error in CMSG_QUESTGIVER_STATUS_QUERY, called for not found questgiver (Typeid: %u GUID: %u)",GuidHigh2TypeId(GUID_HIPART(guid)),GUID_LOPART(guid)); - return; - } - - switch(questgiver->GetTypeId()) - { - case TYPEID_UNIT: - { - sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for npc, guid = %u",uint32(GUID_LOPART(guid))); - Creature* cr_questgiver=questgiver->ToCreature(); - if (!cr_questgiver->IsHostileTo(_player)) // not show quest status to enemies - { - questStatus = sScriptMgr.NPCDialogStatus(_player, cr_questgiver); - if (questStatus > 6) - questStatus = getDialogStatus(_player, cr_questgiver, defstatus); - } - break; - } - case TYPEID_GAMEOBJECT: - { - sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for GameObject guid = %u",uint32(GUID_LOPART(guid))); - GameObject* go_questgiver=(GameObject*)questgiver; - questStatus = sScriptMgr.GODialogStatus(_player, go_questgiver); - if (questStatus > 6) - questStatus = getDialogStatus(_player, go_questgiver, defstatus); - break; - } - default: - sLog.outError("QuestGiver called for unexpected type %u", questgiver->GetTypeId()); - break; - } - - //inform client about status of quest - _player->PlayerTalkClass->SendQuestGiverStatus(questStatus, guid); -} - -void WorldSession::HandleQuestgiverHelloOpcode(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - - sLog.outDebug ("WORLD: Received CMSG_QUESTGIVER_HELLO npc = %u", GUID_LOPART(guid)); - - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_NONE); - if (!pCreature) - { - sLog.outDebug ("WORLD: HandleQuestgiverHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", - GUID_LOPART(guid)); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - // Stop the npc if moving - pCreature->StopMoving(); - - if (sScriptMgr.GossipHello(_player, pCreature)) - return; - - _player->PrepareGossipMenu(pCreature, pCreature->GetCreatureInfo()->GossipMenuId, true); - _player->SendPreparedGossip(pCreature); -} - -void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPacket & recv_data) -{ - uint64 guid; - uint32 quest; - uint32 unk1; - recv_data >> guid >> quest >> unk1; - - if (!GetPlayer()->isAlive()) - return; - - sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_ACCEPT_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), quest, unk1); - - Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT|TYPEMASK_ITEM|TYPEMASK_PLAYER); - - // no or incorrect quest giver - if (!pObject - || (pObject->GetTypeId() != TYPEID_PLAYER && !pObject->hasQuest(quest)) - || (pObject->GetTypeId() == TYPEID_PLAYER && !pObject->ToPlayer()->CanShareQuest(quest)) -) - { - _player->PlayerTalkClass->CloseGossip(); - _player->SetDivider(0); - return; - } - - Quest const* qInfo = objmgr.GetQuestTemplate(quest); - if (qInfo) - { - // prevent cheating - if (!GetPlayer()->CanTakeQuest(qInfo,true)) - { - _player->PlayerTalkClass->CloseGossip(); - _player->SetDivider(0); - return; - } - - if (_player->GetDivider() != 0) - { - Player *pPlayer = ObjectAccessor::FindPlayer(_player->GetDivider()); - if (pPlayer) - { - pPlayer->SendPushToPartyResponse(_player, QUEST_PARTY_MSG_ACCEPT_QUEST); - _player->SetDivider(0); - } - } - - if (_player->CanAddQuest(qInfo, true)) - { - _player->AddQuest(qInfo, pObject); - - if (qInfo->HasFlag(QUEST_FLAGS_PARTY_ACCEPT)) - { - if (Group* pGroup = _player->GetGroup()) - { - for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* pPlayer = itr->getSource(); - - if (!pPlayer || pPlayer == _player) // not self - continue; - - if (pPlayer->CanTakeQuest(qInfo, true)) - { - pPlayer->SetDivider(_player->GetGUID()); - - //need confirmation that any gossip window will close - pPlayer->PlayerTalkClass->CloseGossip(); - - _player->SendQuestConfirmAccept(qInfo, pPlayer); - } - } - } - } - - if (_player->CanCompleteQuest(quest)) - _player->CompleteQuest(quest); - - switch(pObject->GetTypeId()) - { - case TYPEID_UNIT: - sScriptMgr.QuestAccept(_player, (pObject->ToCreature()), qInfo); - break; - case TYPEID_ITEM: - case TYPEID_CONTAINER: - { - sScriptMgr.ItemQuestAccept(_player, ((Item*)pObject), qInfo); - - // destroy not required for quest finish quest starting item - bool destroyItem = true; - for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) - { - if ((qInfo->ReqItemId[i] == ((Item*)pObject)->GetEntry()) && (((Item*)pObject)->GetProto()->MaxCount > 0)) - { - destroyItem = false; - break; - } - } - - if (destroyItem) - _player->DestroyItem(((Item*)pObject)->GetBagSlot(),((Item*)pObject)->GetSlot(),true); - - break; - } - case TYPEID_GAMEOBJECT: - sScriptMgr.GOQuestAccept(_player, ((GameObject*)pObject), qInfo); - break; - } - _player->PlayerTalkClass->CloseGossip(); - - if (qInfo->GetSrcSpell() > 0) - _player->CastSpell(_player, qInfo->GetSrcSpell(), true); - - return; - } - } - - _player->PlayerTalkClass->CloseGossip(); -} - -void WorldSession::HandleQuestgiverQueryQuestOpcode(WorldPacket & recv_data) -{ - uint64 guid; - uint32 quest; - uint8 unk1; - recv_data >> guid >> quest >> unk1; - sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_QUERY_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), quest, unk1); - - // Verify that the guid is valid and is a questgiver or involved in the requested quest - Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT|TYPEMASK_ITEM); - if (!pObject||!pObject->hasQuest(quest) && !pObject->hasInvolvedQuest(quest)) - { - _player->PlayerTalkClass->CloseGossip(); - return; - } - - Quest const* pQuest = objmgr.GetQuestTemplate(quest); - if (pQuest) - { - if (pQuest->HasFlag(QUEST_FLAGS_AUTO_ACCEPT) && _player->CanAddQuest(pQuest, true)) - { - _player->AddQuest(pQuest, pObject); - if (_player->CanCompleteQuest(quest)) - _player->CompleteQuest(quest); - } - - if (pQuest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)) - _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, pObject->GetGUID(), _player->CanCompleteQuest(pQuest->GetQuestId()), true); - else - _player->PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, pObject->GetGUID(), true); - } -} - -void WorldSession::HandleQuestQueryOpcode(WorldPacket & recv_data) -{ - uint32 quest; - recv_data >> quest; - sLog.outDebug("WORLD: Received CMSG_QUEST_QUERY quest = %u",quest); - - Quest const *pQuest = objmgr.GetQuestTemplate(quest); - if (pQuest) - { - _player->PlayerTalkClass->SendQuestQueryResponse(pQuest); - } -} - -void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket & recv_data) -{ - uint32 quest, reward; - uint64 guid; - recv_data >> guid >> quest >> reward; - - if (reward >= QUEST_REWARD_CHOICES_COUNT) - { - sLog.outError("Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player %s (guid %d) tried to get invalid reward (%u) (probably packet hacking)", _player->GetName(), _player->GetGUIDLow(), reward); - return; - } - - if (!GetPlayer()->isAlive()) - return; - - sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_CHOOSE_REWARD npc = %u, quest = %u, reward = %u",uint32(GUID_LOPART(guid)),quest,reward); - - Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); - if (!pObject) - return; - - if (!pObject->hasInvolvedQuest(quest)) - return; - - Quest const *pQuest = objmgr.GetQuestTemplate(quest); - if (pQuest) - { - if (_player->CanRewardQuest(pQuest, reward, true)) - { - _player->RewardQuest(pQuest, reward, pObject); - - switch(pObject->GetTypeId()) - { - case TYPEID_UNIT: - if (!(sScriptMgr.ChooseReward(_player, (pObject->ToCreature()), pQuest, reward))) - { - // Send next quest - if (Quest const* nextquest = _player->GetNextQuest(guid ,pQuest)) - _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextquest,guid,true); - } - break; - case TYPEID_GAMEOBJECT: - if (!sScriptMgr.GOChooseReward(_player, ((GameObject*)pObject), pQuest, reward)) - { - // Send next quest - if (Quest const* nextquest = _player->GetNextQuest(guid ,pQuest)) - _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextquest,guid,true); - } - break; - } - } - else - _player->PlayerTalkClass->SendQuestGiverOfferReward(pQuest, guid, true); - } -} - -void WorldSession::HandleQuestgiverRequestRewardOpcode(WorldPacket & recv_data) -{ - uint32 quest; - uint64 guid; - recv_data >> guid >> quest; - - if (!GetPlayer()->isAlive()) - return; - - sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_REQUEST_REWARD npc = %u, quest = %u",uint32(GUID_LOPART(guid)),quest); - - Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); - if (!pObject||!pObject->hasInvolvedQuest(quest)) - return; - - if (_player->CanCompleteQuest(quest)) - _player->CompleteQuest(quest); - - if (_player->GetQuestStatus(quest) != QUEST_STATUS_COMPLETE) - return; - - if (Quest const *pQuest = objmgr.GetQuestTemplate(quest)) - _player->PlayerTalkClass->SendQuestGiverOfferReward(pQuest, guid, true); -} - -void WorldSession::HandleQuestgiverCancel(WorldPacket& /*recv_data*/) -{ - sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_CANCEL"); - - _player->PlayerTalkClass->CloseGossip(); -} - -void WorldSession::HandleQuestLogSwapQuest(WorldPacket& recv_data) -{ - uint8 slot1, slot2; - recv_data >> slot1 >> slot2; - - if (slot1 == slot2 || slot1 >= MAX_QUEST_LOG_SIZE || slot2 >= MAX_QUEST_LOG_SIZE) - return; - - sLog.outDebug("WORLD: Received CMSG_QUESTLOG_SWAP_QUEST slot 1 = %u, slot 2 = %u", slot1, slot2); - - GetPlayer()->SwapQuestSlot(slot1,slot2); -} - -void WorldSession::HandleQuestLogRemoveQuest(WorldPacket& recv_data) -{ - uint8 slot; - recv_data >> slot; - - sLog.outDebug("WORLD: Received CMSG_QUESTLOG_REMOVE_QUEST slot = %u",slot); - - if (slot < MAX_QUEST_LOG_SIZE) - { - if (uint32 quest = _player->GetQuestSlotQuestId(slot)) - { - if (!_player->TakeQuestSourceItem(quest, true)) - return; // can't un-equip some items, reject quest cancel - - if (const Quest *pQuest = objmgr.GetQuestTemplate(quest)) - { - if (pQuest->HasFlag(QUEST_TRINITY_FLAGS_TIMED)) - _player->RemoveTimedQuest(quest); - } - - _player->TakeQuestSourceItem(quest, true); // remove quest src item from player - _player->SetQuestStatus(quest, QUEST_STATUS_NONE); - _player->GetAchievementMgr().RemoveTimedAchievement(ACHIEVEMENT_TIMED_TYPE_QUEST, quest); - } - - _player->SetQuestSlot(slot, 0); - - _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED, 1); - } -} - -void WorldSession::HandleQuestConfirmAccept(WorldPacket& recv_data) -{ - uint32 quest; - recv_data >> quest; - - sLog.outDebug("WORLD: Received CMSG_QUEST_CONFIRM_ACCEPT quest = %u", quest); - - if (const Quest* pQuest = objmgr.GetQuestTemplate(quest)) - { - if (!pQuest->HasFlag(QUEST_FLAGS_PARTY_ACCEPT)) - return; - - Player* pOriginalPlayer = ObjectAccessor::FindPlayer(_player->GetDivider()); - - if (!pOriginalPlayer) - return; - - if (pQuest->GetType() == QUEST_TYPE_RAID) - { - if (!_player->IsInSameRaidWith(pOriginalPlayer)) - return; - } - else - { - if (!_player->IsInSameGroupWith(pOriginalPlayer)) - return; - } - - if (_player->CanAddQuest(pQuest, true)) - _player->AddQuest(pQuest, NULL); // NULL, this prevent DB script from duplicate running - - _player->SetDivider(0); - } -} - -void WorldSession::HandleQuestgiverCompleteQuest(WorldPacket& recv_data) -{ - uint32 quest; - uint64 guid; - recv_data >> guid >> quest; - - if (!GetPlayer()->isAlive()) - return; - - sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %u, quest = %u",uint32(GUID_LOPART(guid)),quest); - - Quest const *pQuest = objmgr.GetQuestTemplate(quest); - if (pQuest) - { - // TODO: need a virtual function - if (GetPlayer()->InBattleGround()) - if (BattleGround* bg = GetPlayer()->GetBattleGround()) - if (bg->GetTypeID() == BATTLEGROUND_AV) - ((BattleGroundAV*)bg)->HandleQuestComplete(quest, GetPlayer()); - - if (_player->GetQuestStatus(quest) != QUEST_STATUS_COMPLETE) - { - if (pQuest->IsRepeatable()) - _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanCompleteRepeatableQuest(pQuest), false); - else - _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanRewardQuest(pQuest,false), false); - } - else - { - if (pQuest->GetReqItemsCount()) // some items required - _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanRewardQuest(pQuest,false), false); - else // no items required - _player->PlayerTalkClass->SendQuestGiverOfferReward(pQuest, guid, true); - } - } -} - -void WorldSession::HandleQuestgiverQuestAutoLaunch(WorldPacket& /*recvPacket*/) -{ - sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_QUEST_AUTOLAUNCH"); -} - -void WorldSession::HandlePushQuestToParty(WorldPacket& recvPacket) -{ - uint32 questId; - recvPacket >> questId; - - sLog.outDebug("WORLD: Received CMSG_PUSHQUESTTOPARTY quest = %u", questId); - - if (Quest const *pQuest = objmgr.GetQuestTemplate(questId)) - { - if (Group* pGroup = _player->GetGroup()) - { - for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player *pPlayer = itr->getSource(); - - if (!pPlayer || pPlayer == _player) // skip self - continue; - - _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_SHARING_QUEST); - - if (!pPlayer->SatisfyQuestStatus(pQuest, false)) - { - _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_HAVE_QUEST); - continue; - } - - if (pPlayer->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE) - { - _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_FINISH_QUEST); - continue; - } - - if (!pPlayer->CanTakeQuest(pQuest, false)) - { - _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_CANT_TAKE_QUEST); - continue; - } - - if (!pPlayer->SatisfyQuestLog(false)) - { - _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_LOG_FULL); - continue; - } - - if (pPlayer->GetDivider() != 0) - { - _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_BUSY); - continue; - } - - pPlayer->PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, _player->GetGUID(), true); - pPlayer->SetDivider(_player->GetGUID()); - } - } - } -} - -void WorldSession::HandleQuestPushResult(WorldPacket& recvPacket) -{ - uint64 guid; - uint8 msg; - recvPacket >> guid >> msg; - - sLog.outDebug("WORLD: Received MSG_QUEST_PUSH_RESULT"); - - if (_player->GetDivider() != 0) - { - Player *pPlayer = ObjectAccessor::FindPlayer(_player->GetDivider()); - if (pPlayer) - { - WorldPacket data(MSG_QUEST_PUSH_RESULT, (8+1)); - data << uint64(guid); - data << uint8(msg); // valid values: 0-8 - pPlayer->GetSession()->SendPacket(&data); - _player->SetDivider(0); - } - } -} - -uint32 WorldSession::getDialogStatus(Player *pPlayer, Object* questgiver, uint32 defstatus) -{ - uint32 result = defstatus; - - QuestRelations const* qir; - QuestRelations const* qr; - - switch(questgiver->GetTypeId()) - { - case TYPEID_GAMEOBJECT: - { - qir = &objmgr.mGOQuestInvolvedRelations; - qr = &objmgr.mGOQuestRelations; - break; - } - case TYPEID_UNIT: - { - qir = &objmgr.mCreatureQuestInvolvedRelations; - qr = &objmgr.mCreatureQuestRelations; - break; - } - default: - //its imposible, but check ^) - sLog.outError("Warning: GetDialogStatus called for unexpected type %u", questgiver->GetTypeId()); - return DIALOG_STATUS_NONE; - } - - for (QuestRelations::const_iterator i = qir->lower_bound(questgiver->GetEntry()); i != qir->upper_bound(questgiver->GetEntry()); ++i) - { - uint32 result2 = 0; - uint32 quest_id = i->second; - Quest const *pQuest = objmgr.GetQuestTemplate(quest_id); - if (!pQuest) continue; - - QuestStatus status = pPlayer->GetQuestStatus(quest_id); - if ((status == QUEST_STATUS_COMPLETE && !pPlayer->GetQuestRewardStatus(quest_id)) || - (pQuest->IsAutoComplete() && pPlayer->CanTakeQuest(pQuest, false))) - { - if (pQuest->IsAutoComplete() && pQuest->IsRepeatable()) - result2 = DIALOG_STATUS_REWARD_REP; - else - result2 = DIALOG_STATUS_REWARD; - } - else if (status == QUEST_STATUS_INCOMPLETE) - result2 = DIALOG_STATUS_INCOMPLETE; - - if (result2 > result) - result = result2; - } - - for (QuestRelations::const_iterator i = qr->lower_bound(questgiver->GetEntry()); i != qr->upper_bound(questgiver->GetEntry()); ++i) - { - uint32 result2 = 0; - uint32 quest_id = i->second; - Quest const *pQuest = objmgr.GetQuestTemplate(quest_id); - if (!pQuest) - continue; - - QuestStatus status = pPlayer->GetQuestStatus(quest_id); - if (status == QUEST_STATUS_NONE) - { - if (pPlayer->CanSeeStartQuest(pQuest)) - { - if (pPlayer->SatisfyQuestLevel(pQuest, false)) - { - if (pQuest->IsAutoComplete() || (pQuest->IsRepeatable() && pPlayer->getQuestStatusMap()[quest_id].m_rewarded)) - result2 = DIALOG_STATUS_REWARD_REP; - else if (pPlayer->getLevel() <= ((pPlayer->GetQuestLevel(pQuest) == -1) ? pPlayer->getLevel() : pPlayer->GetQuestLevel(pQuest) + sWorld.getConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF))) - { - if (pQuest->HasFlag(QUEST_FLAGS_DAILY) || pQuest->HasFlag(QUEST_FLAGS_WEEKLY)) - result2 = DIALOG_STATUS_AVAILABLE_REP; - else - result2 = DIALOG_STATUS_AVAILABLE; - } - else - result2 = DIALOG_STATUS_LOW_LEVEL_AVAILABLE; - } - else - result2 = DIALOG_STATUS_UNAVAILABLE; - } - } - - if (result2 > result) - result = result2; - } - - return result; -} - -void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket*/) -{ - sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY"); - - uint32 count = 0; - - WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4); - data << uint32(count); // placeholder - - for (Player::ClientGUIDs::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr) - { - uint8 questStatus = DIALOG_STATUS_NONE; - uint8 defstatus = DIALOG_STATUS_NONE; - - if (IS_CRE_OR_VEH_OR_PET_GUID(*itr)) - { - // need also pet quests case support - Creature *questgiver = ObjectAccessor::GetCreatureOrPetOrVehicle(*GetPlayer(),*itr); - if (!questgiver || questgiver->IsHostileTo(_player)) - continue; - if (!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) - continue; - questStatus = sScriptMgr.NPCDialogStatus(_player, questgiver); - if (questStatus > 6) - questStatus = getDialogStatus(_player, questgiver, defstatus); - - data << uint64(questgiver->GetGUID()); - data << uint8(questStatus); - ++count; - } - else if (IS_GAMEOBJECT_GUID(*itr)) - { - GameObject *questgiver = GetPlayer()->GetMap()->GetGameObject(*itr); - if (!questgiver) - continue; - if (questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER) - continue; - questStatus = sScriptMgr.GODialogStatus(_player, questgiver); - if (questStatus > 6) - questStatus = getDialogStatus(_player, questgiver, defstatus); - - data << uint64(questgiver->GetGUID()); - data << uint8(questStatus); - ++count; - } - } - - data.put(0, count); // write real count - SendPacket(&data); -} - -void WorldSession::HandleQueryQuestsCompleted(WorldPacket & /*recv_data*/) -{ - uint32 count = 0; - - WorldPacket data(SMSG_QUERY_QUESTS_COMPLETED_RESPONSE, 4+4*count); - data << uint32(count); - - for (QuestStatusMap::const_iterator itr = _player->getQuestStatusMap().begin(); itr != _player->getQuestStatusMap().end(); ++itr) - { - if (itr->second.m_rewarded) - { - data << uint32(itr->first); - count++; - } - } - data.put(0, count); - SendPacket(&data); -} diff --git a/src/server/game/ScriptMgr/ScriptLoader.cpp b/src/server/game/ScriptMgr/ScriptLoader.cpp deleted file mode 100644 index 2006c091287..00000000000 --- a/src/server/game/ScriptMgr/ScriptLoader.cpp +++ /dev/null @@ -1,1023 +0,0 @@ -/* Copyright (C) 2008 - 2010 TrinityCore - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ScriptedPch.h" - -#ifdef WIN32 - #define DO_SCRIPTS -#endif - -#ifdef DO_SCRIPTS -//custom - -//examples -void AddSC_example_creature(); -void AddSC_example_escort(); -void AddSC_example_gossip_codebox(); -void AddSC_example_misc(); - -//world -void AddSC_areatrigger_scripts(); -void AddSC_boss_emeriss(); -void AddSC_boss_taerar(); -void AddSC_boss_ysondre(); -void AddSC_generic_creature(); -void AddSC_go_scripts(); -void AddSC_guards(); -void AddSC_item_scripts(); -void AddSC_npc_professions(); -void AddSC_npc_innkeeper(); -void AddSC_npcs_special(); -void AddSC_npc_taxi(); - -//eastern kingdoms -void AddSC_alterac_valley(); //Alterac Valley -void AddSC_boss_balinda(); -void AddSC_boss_drekthar(); -void AddSC_boss_galvangar(); -void AddSC_boss_vanndar(); -void AddSC_blackrock_depths(); //Blackrock Depths -void AddSC_boss_ambassador_flamelash(); -void AddSC_boss_anubshiah(); -void AddSC_boss_draganthaurissan(); -void AddSC_boss_general_angerforge(); -void AddSC_boss_gorosh_the_dervish(); -void AddSC_boss_grizzle(); -void AddSC_boss_high_interrogator_gerstahn(); -void AddSC_boss_magmus(); -void AddSC_boss_moira_bronzebeard(); -void AddSC_boss_tomb_of_seven(); -void AddSC_instance_blackrock_depths(); -void AddSC_blackrock_spire(); //Blackrock Spire -void AddSC_boss_drakkisath(); -void AddSC_boss_halycon(); -void AddSC_boss_highlordomokk(); -void AddSC_boss_mothersmolderweb(); -void AddSC_boss_overlordwyrmthalak(); -void AddSC_boss_shadowvosh(); -void AddSC_boss_thebeast(); -void AddSC_boss_warmastervoone(); -void AddSC_boss_quatermasterzigris(); -void AddSC_boss_pyroguard_emberseer(); -void AddSC_boss_gyth(); -void AddSC_boss_rend_blackhand(); -void AddSC_instance_blackrock_spire(); -void AddSC_boss_razorgore(); //Blackwing lair -void AddSC_boss_vael(); -void AddSC_boss_broodlord(); -void AddSC_boss_firemaw(); -void AddSC_boss_ebonroc(); -void AddSC_boss_flamegor(); -void AddSC_boss_chromaggus(); -void AddSC_boss_nefarian(); -void AddSC_boss_victor_nefarius(); -void AddSC_boss_mr_smite(); -void AddSC_deadmines(); //Deadmines -void AddSC_instance_deadmines(); -void AddSC_gnomeregan(); //Gnomeregan -void AddSC_instance_gnomeregan(); -void AddSC_boss_attumen(); //Karazhan -void AddSC_boss_curator(); -void AddSC_boss_maiden_of_virtue(); -void AddSC_boss_shade_of_aran(); -void AddSC_boss_malchezaar(); -void AddSC_boss_terestian_illhoof(); -void AddSC_boss_moroes(); -void AddSC_bosses_opera(); -void AddSC_boss_netherspite(); -void AddSC_instance_karazhan(); -void AddSC_karazhan(); -void AddSC_boss_nightbane(); -void AddSC_boss_felblood_kaelthas(); // Magister's Terrace -void AddSC_boss_selin_fireheart(); -void AddSC_boss_vexallus(); -void AddSC_boss_priestess_delrissa(); -void AddSC_instance_magisters_terrace(); -void AddSC_magisters_terrace(); -void AddSC_boss_lucifron(); //Molten core -void AddSC_boss_magmadar(); -void AddSC_boss_gehennas(); -void AddSC_boss_garr(); -void AddSC_boss_baron_geddon(); -void AddSC_boss_shazzrah(); -void AddSC_boss_golemagg(); -void AddSC_boss_sulfuron(); -void AddSC_boss_majordomo(); -void AddSC_boss_ragnaros(); -void AddSC_instance_molten_core(); -void AddSC_molten_core(); -void AddSC_the_scarlet_enclave(); //Scarlet Enclave -void AddSC_the_scarlet_enclave_c1(); -void AddSC_the_scarlet_enclave_c2(); -void AddSC_the_scarlet_enclave_c5(); -void AddSC_boss_arcanist_doan(); //Scarlet Monastery -void AddSC_boss_azshir_the_sleepless(); -void AddSC_boss_bloodmage_thalnos(); -void AddSC_boss_headless_horseman(); -void AddSC_boss_herod(); -void AddSC_boss_high_inquisitor_fairbanks(); -void AddSC_boss_houndmaster_loksey(); -void AddSC_boss_interrogator_vishas(); -void AddSC_boss_scorn(); -void AddSC_instance_scarlet_monastery(); -void AddSC_boss_mograine_and_whitemane(); -void AddSC_boss_darkmaster_gandling(); //Scholomance -void AddSC_boss_death_knight_darkreaver(); -void AddSC_boss_theolenkrastinov(); -void AddSC_boss_illuciabarov(); -void AddSC_boss_instructormalicia(); -void AddSC_boss_jandicebarov(); -void AddSC_boss_kormok(); -void AddSC_boss_lordalexeibarov(); -void AddSC_boss_lorekeeperpolkelt(); -void AddSC_boss_rasfrost(); -void AddSC_boss_theravenian(); -void AddSC_boss_vectus(); -void AddSC_instance_scholomance(); -void AddSC_shadowfang_keep(); //Shadowfang keep -void AddSC_instance_shadowfang_keep(); -void AddSC_boss_magistrate_barthilas(); //Stratholme -void AddSC_boss_maleki_the_pallid(); -void AddSC_boss_nerubenkan(); -void AddSC_boss_cannon_master_willey(); -void AddSC_boss_baroness_anastari(); -void AddSC_boss_ramstein_the_gorger(); -void AddSC_boss_timmy_the_cruel(); -void AddSC_boss_postmaster_malown(); -void AddSC_boss_baron_rivendare(); -void AddSC_boss_dathrohan_balnazzar(); -void AddSC_boss_order_of_silver_hand(); -void AddSC_instance_stratholme(); -void AddSC_stratholme(); -void AddSC_sunken_temple(); // Sunken Temple -void AddSC_instance_sunken_temple(); -void AddSC_instance_sunwell_plateau(); //Sunwell Plateau -void AddSC_boss_kalecgos(); -void AddSC_boss_brutallus(); -void AddSC_boss_felmyst(); -void AddSC_boss_eredar_twins(); -void AddSC_boss_muru(); -void AddSC_boss_kiljaeden(); -void AddSC_sunwell_plateau(); -void AddSC_boss_archaedas(); //Uldaman -void AddSC_boss_ironaya(); -void AddSC_uldaman(); -void AddSC_instance_uldaman(); -void AddSC_boss_akilzon(); //Zul'Aman -void AddSC_boss_halazzi(); -void AddSC_boss_hex_lord_malacrass(); -void AddSC_boss_janalai(); -void AddSC_boss_nalorakk(); -void AddSC_boss_zuljin(); -void AddSC_instance_zulaman(); -void AddSC_zulaman(); -void AddSC_boss_jeklik(); //Zul'Gurub -void AddSC_boss_venoxis(); -void AddSC_boss_marli(); -void AddSC_boss_mandokir(); -void AddSC_boss_gahzranka(); -void AddSC_boss_thekal(); -void AddSC_boss_arlokk(); -void AddSC_boss_jindo(); -void AddSC_boss_hakkar(); -void AddSC_boss_grilek(); -void AddSC_boss_hazzarah(); -void AddSC_boss_renataki(); -void AddSC_boss_wushoolay(); -void AddSC_instance_zulgurub(); - -//void AddSC_alterac_mountains(); -void AddSC_arathi_highlands(); -void AddSC_blasted_lands(); -void AddSC_boss_kruul(); -void AddSC_burning_steppes(); -void AddSC_dun_morogh(); -void AddSC_duskwood(); -void AddSC_eastern_plaguelands(); -void AddSC_elwynn_forest(); -void AddSC_eversong_woods(); -void AddSC_ghostlands(); -void AddSC_hinterlands(); -void AddSC_ironforge(); -void AddSC_isle_of_queldanas(); -void AddSC_loch_modan(); -void AddSC_redridge_mountains(); -void AddSC_searing_gorge(); -void AddSC_silvermoon_city(); -void AddSC_silverpine_forest(); -void AddSC_stormwind_city(); -void AddSC_stranglethorn_vale(); -void AddSC_tirisfal_glades(); -void AddSC_undercity(); -void AddSC_western_plaguelands(); -void AddSC_westfall(); -void AddSC_wetlands(); - -//kalimdor -void AddSC_blackfathom_deeps(); //Blackfathom Depths -void AddSC_boss_gelihast(); -void AddSC_boss_kelris(); -void AddSC_boss_aku_mai(); -void AddSC_instance_blackfathom_deeps(); -void AddSC_hyjal(); //CoT Battle for Mt. Hyjal -void AddSC_boss_archimonde(); -void AddSC_instance_mount_hyjal(); -void AddSC_hyjal_trash(); -void AddSC_boss_rage_winterchill(); -void AddSC_boss_anetheron(); -void AddSC_boss_kazrogal(); -void AddSC_boss_azgalor(); -void AddSC_boss_captain_skarloc(); //CoT Old Hillsbrad -void AddSC_boss_epoch_hunter(); -void AddSC_boss_lieutenant_drake(); -void AddSC_instance_old_hillsbrad(); -void AddSC_old_hillsbrad(); -void AddSC_boss_aeonus(); //CoT The Dark Portal -void AddSC_boss_chrono_lord_deja(); -void AddSC_boss_temporus(); -void AddSC_dark_portal(); -void AddSC_instance_dark_portal(); -void AddSC_boss_epoch(); //CoT Culling Of Stratholme -void AddSC_boss_infinite_corruptor(); -void AddSC_boss_salramm(); -void AddSC_boss_mal_ganis(); -void AddSC_boss_meathook(); -void AddSC_culling_of_stratholme(); -void AddSC_instance_culling_of_stratholme(); -void AddSC_boss_celebras_the_cursed(); //Maraudon -void AddSC_boss_landslide(); -void AddSC_boss_noxxion(); -void AddSC_boss_ptheradras(); -void AddSC_boss_onyxia(); //Onyxia's Lair -void AddSC_instance_onyxias_lair(); -void AddSC_boss_amnennar_the_coldbringer(); //Razorfen Downs -void AddSC_razorfen_downs(); -void AddSC_instance_razorfen_downs(); -void AddSC_razorfen_kraul(); //Razorfen Kraul -void AddSC_boss_kurinnaxx(); //Ruins of ahn'qiraj -void AddSC_boss_rajaxx(); -void AddSC_boss_moam(); -void AddSC_boss_buru(); -void AddSC_boss_ayamiss(); -void AddSC_boss_ossirian(); -void AddSC_instance_ruins_of_ahnqiraj(); -void AddSC_boss_cthun(); //Temple of ahn'qiraj -void AddSC_boss_fankriss(); -void AddSC_boss_huhuran(); -void AddSC_bug_trio(); -void AddSC_boss_sartura(); -void AddSC_boss_skeram(); -void AddSC_boss_twinemperors(); -void AddSC_mob_anubisath_sentinel(); -void AddSC_instance_temple_of_ahnqiraj(); -void AddSC_wailing_caverns(); //Wailing caverns -void AddSC_instance_wailing_caverns(); -void AddSC_zulfarrak(); //Zul'Farrak generic -void AddSC_instance_zulfarrak(); //Zul'Farrak instance script - -void AddSC_ashenvale(); -void AddSC_azshara(); -void AddSC_azuremyst_isle(); -void AddSC_bloodmyst_isle(); -void AddSC_boss_azuregos(); -void AddSC_darkshore(); -void AddSC_desolace(); -void AddSC_durotar(); -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(); -void AddSC_tanaris(); -void AddSC_teldrassil(); -void AddSC_the_barrens(); -void AddSC_thousand_needles(); -void AddSC_thunder_bluff(); -void AddSC_ungoro_crater(); -void AddSC_winterspring(); - -//northrend -void AddSC_boss_slad_ran(); -void AddSC_boss_moorabi(); -void AddSC_boss_drakkari_colossus(); -void AddSC_boss_gal_darah(); -void AddSC_boss_eck(); -void AddSC_instance_gundrak(); -void AddSC_boss_krik_thir(); //Azjol-Nerub -void AddSC_boss_hadronox(); -void AddSC_boss_anub_arak(); -void AddSC_instance_azjol_nerub(); -void AddSC_instance_ahnkahet(); //Azjol-Nerub Ahn'kahet -void AddSC_boss_amanitar(); -void AddSC_boss_taldaram(); -void AddSC_boss_jedoga_shadowseeker(); -void AddSC_boss_elder_nadox(); -void AddSC_boss_volazj(); -void AddSC_boss_argent_challenge(); //Trial of the Champion -void AddSC_boss_black_knight(); -void AddSC_boss_grand_champions(); -void AddSC_instance_trial_of_the_champion(); -void AddSC_trial_of_the_champion(); -void AddSC_boss_anubrekhan(); //Naxxramas -void AddSC_boss_maexxna(); -void AddSC_boss_patchwerk(); -void AddSC_boss_grobbulus(); -void AddSC_boss_razuvious(); -void AddSC_boss_kelthuzad(); -void AddSC_boss_loatheb(); -void AddSC_boss_noth(); -void AddSC_boss_gluth(); -void AddSC_boss_sapphiron(); -void AddSC_boss_four_horsemen(); -void AddSC_boss_faerlina(); -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_anomalus(); -void AddSC_boss_ormorok(); -void AddSC_boss_keristrasza(); -void AddSC_instance_nexus(); -void AddSC_boss_drakos(); //The Nexus The Oculus -void AddSC_boss_urom(); -void AddSC_instance_oculus(); -void AddSC_oculus(); -void AddSC_boss_sartharion(); //Obsidian Sanctum -void AddSC_instance_obsidian_sanctum(); -void AddSC_boss_bjarngrim(); //Ulduar Halls of Lightning -void AddSC_boss_loken(); -void AddSC_boss_ionar(); -void AddSC_boss_volkhan(); -void AddSC_instance_halls_of_lightning(); -void AddSC_boss_maiden_of_grief(); //Ulduar Halls of Stone -void AddSC_boss_krystallus(); -void AddSC_boss_sjonnir(); -void AddSC_instance_halls_of_stone(); -void AddSC_halls_of_stone(); -void AddSC_boss_auriaya(); //Ulduar Ulduar -void AddSC_boss_flame_leviathan(); -void AddSC_boss_ignis(); -void AddSC_boss_razorscale(); -void AddSC_boss_xt002(); -void AddSC_boss_kologarn(); -void AddSC_boss_assembly_of_iron(); -void AddSC_ulduar_teleporter(); -void AddSC_instance_ulduar(); -void AddSC_boss_keleseth(); //Utgarde Keep -void AddSC_boss_skarvald_dalronn(); -void AddSC_boss_ingvar_the_plunderer(); -void AddSC_instance_utgarde_keep(); -void AddSC_boss_svala(); //Utgarde pinnacle -void AddSC_boss_palehoof(); -void AddSC_boss_skadi(); -void AddSC_boss_ymiron(); -void AddSC_instance_utgarde_pinnacle(); -void AddSC_utgarde_keep(); -void AddSC_boss_archavon(); //Vault of Archavon -void AddSC_boss_emalon(); -void AddSC_boss_koralon(); -void AddSC_boss_toravon(); -void AddSC_instance_archavon(); -void AddSC_boss_trollgore(); //Drak'Tharon Keep -void AddSC_boss_novos(); -void AddSC_boss_dred(); -void AddSC_boss_tharon_ja(); -void AddSC_instance_drak_tharon(); -void AddSC_boss_cyanigosa(); //Violet Hold -void AddSC_boss_erekem(); -void AddSC_boss_ichoron(); -void AddSC_boss_lavanthor(); -void AddSC_boss_moragg(); -void AddSC_boss_xevozz(); -void AddSC_boss_zuramat(); -void AddSC_instance_violet_hold(); -void AddSC_violet_hold(); -void AddSC_instance_forge_of_souls(); //Forge of Souls -void AddSC_forge_of_souls(); -void AddSC_boss_bronjahm(); -void AddSC_boss_devourer_of_souls(); -void AddSC_instance_pit_of_saron(); //Pit of Saron -void AddSC_pit_of_saron(); -void AddSC_boss_garfrost(); -void AddSC_boss_ick(); -void AddSC_boss_tyrannus(); -void AddSC_instance_halls_of_reflection(); // Halls of Reflection -void AddSC_halls_of_reflection(); -void AddSC_boss_falric(); -void AddSC_boss_marwyn(); - -void AddSC_dalaran(); -void AddSC_borean_tundra(); -void AddSC_dragonblight(); -void AddSC_grizzly_hills(); -void AddSC_howling_fjord(); -void AddSC_icecrown(); -void AddSC_sholazar_basin(); -void AddSC_storm_peaks(); -void AddSC_zuldrak(); -void AddSC_crystalsong_forest(); - -//outland -void AddSC_boss_exarch_maladaar(); //Auchindoun Auchenai Crypts -void AddSC_boss_shirrak_the_dead_watcher(); -void AddSC_boss_nexusprince_shaffar(); //Auchindoun Mana Tombs -void AddSC_boss_pandemonius(); -void AddSC_boss_darkweaver_syth(); //Auchindoun Sekketh Halls -void AddSC_boss_talon_king_ikiss(); -void AddSC_instance_sethekk_halls(); -void AddSC_instance_shadow_labyrinth(); //Auchindoun Shadow Labyrinth -void AddSC_boss_ambassador_hellmaw(); -void AddSC_boss_blackheart_the_inciter(); -void AddSC_boss_grandmaster_vorpil(); -void AddSC_boss_murmur(); -void AddSC_black_temple(); //Black Temple -void AddSC_boss_illidan(); -void AddSC_boss_shade_of_akama(); -void AddSC_boss_supremus(); -void AddSC_boss_gurtogg_bloodboil(); -void AddSC_boss_mother_shahraz(); -void AddSC_boss_reliquary_of_souls(); -void AddSC_boss_teron_gorefiend(); -void AddSC_boss_najentus(); -void AddSC_boss_illidari_council(); -void AddSC_instance_black_temple(); -void AddSC_boss_fathomlord_karathress(); //CR Serpent Shrine Cavern -void AddSC_boss_hydross_the_unstable(); -void AddSC_boss_lady_vashj(); -void AddSC_boss_leotheras_the_blind(); -void AddSC_boss_morogrim_tidewalker(); -void AddSC_instance_serpentshrine_cavern(); -void AddSC_boss_the_lurker_below(); -void AddSC_boss_hydromancer_thespia(); //CR Steam Vault -void AddSC_boss_mekgineer_steamrigger(); -void AddSC_boss_warlord_kalithresh(); -void AddSC_instance_steam_vault(); -void AddSC_boss_hungarfen(); //CR Underbog -void AddSC_boss_the_black_stalker(); -void AddSC_boss_gruul(); //Gruul's Lair -void AddSC_boss_high_king_maulgar(); -void AddSC_instance_gruuls_lair(); -void AddSC_boss_broggok(); //HC Blood Furnace -void AddSC_boss_kelidan_the_breaker(); -void AddSC_boss_the_maker(); -void AddSC_instance_blood_furnace(); -void AddSC_boss_magtheridon(); //HC Magtheridon's Lair -void AddSC_instance_magtheridons_lair(); -void AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls -void AddSC_boss_warbringer_omrogg(); -void AddSC_boss_warchief_kargath_bladefist(); -void AddSC_instance_shattered_halls(); -void AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts -void AddSC_boss_omor_the_unscarred(); -void AddSC_boss_vazruden_the_herald(); -void AddSC_instance_ramparts(); -void AddSC_arcatraz(); //TK Arcatraz -void AddSC_boss_harbinger_skyriss(); -void AddSC_instance_arcatraz(); -void AddSC_boss_high_botanist_freywinn(); //TK Botanica -void AddSC_boss_laj(); -void AddSC_boss_warp_splinter(); -void AddSC_boss_alar(); //TK The Eye -void AddSC_boss_kaelthas(); -void AddSC_boss_void_reaver(); -void AddSC_boss_high_astromancer_solarian(); -void AddSC_instance_the_eye(); -void AddSC_the_eye(); -void AddSC_boss_gatewatcher_iron_hand(); //TK The Mechanar -void AddSC_boss_nethermancer_sepethrea(); -void AddSC_boss_pathaleon_the_calculator(); -void AddSC_instance_mechanar(); - -void AddSC_blades_edge_mountains(); -void AddSC_boss_doomlordkazzak(); -void AddSC_boss_doomwalker(); -void AddSC_hellfire_peninsula(); -void AddSC_nagrand(); -void AddSC_netherstorm(); -void AddSC_shadowmoon_valley(); -void AddSC_shattrath_city(); -void AddSC_terokkar_forest(); -void AddSC_zangarmarsh(); -void AddSC_onevents(); - -#endif - -void AddScripts() -{ -#ifdef DO_SCRIPTS - - //custom - - //examples - AddSC_example_creature(); - AddSC_example_escort(); - AddSC_example_gossip_codebox(); - AddSC_example_misc(); - - //world - AddSC_areatrigger_scripts(); - AddSC_boss_emeriss(); - AddSC_boss_taerar(); - AddSC_boss_ysondre(); - AddSC_generic_creature(); - AddSC_go_scripts(); - AddSC_guards(); - AddSC_item_scripts(); - AddSC_npc_professions(); - AddSC_npc_innkeeper(); - AddSC_npcs_special(); - AddSC_npc_taxi(); - - //eastern kingdoms - AddSC_alterac_valley(); //Alterac Valley - AddSC_boss_balinda(); - AddSC_boss_drekthar(); - AddSC_boss_galvangar(); - AddSC_boss_vanndar(); - AddSC_blackrock_depths(); //Blackrock Depths - AddSC_boss_ambassador_flamelash(); - AddSC_boss_anubshiah(); - AddSC_boss_draganthaurissan(); - AddSC_boss_general_angerforge(); - AddSC_boss_gorosh_the_dervish(); - AddSC_boss_grizzle(); - AddSC_boss_high_interrogator_gerstahn(); - AddSC_boss_magmus(); - AddSC_boss_moira_bronzebeard(); - AddSC_boss_tomb_of_seven(); - AddSC_instance_blackrock_depths(); - AddSC_blackrock_spire(); //Blackrock Spire - AddSC_boss_drakkisath(); - AddSC_boss_halycon(); - AddSC_boss_highlordomokk(); - AddSC_boss_mothersmolderweb(); - AddSC_boss_overlordwyrmthalak(); - AddSC_boss_shadowvosh(); - AddSC_boss_thebeast(); - AddSC_boss_warmastervoone(); - AddSC_boss_quatermasterzigris(); - AddSC_boss_pyroguard_emberseer(); - AddSC_boss_gyth(); - AddSC_boss_rend_blackhand(); - AddSC_instance_blackrock_spire(); - AddSC_boss_razorgore(); //Blackwing lair - AddSC_boss_vael(); - AddSC_boss_broodlord(); - AddSC_boss_firemaw(); - AddSC_boss_ebonroc(); - AddSC_boss_flamegor(); - AddSC_boss_chromaggus(); - AddSC_boss_nefarian(); - AddSC_boss_victor_nefarius(); - AddSC_boss_mr_smite(); - AddSC_deadmines(); //Deadmines - AddSC_instance_deadmines(); - AddSC_gnomeregan(); //Gnomeregan - AddSC_instance_gnomeregan(); - AddSC_boss_attumen(); //Karazhan - AddSC_boss_curator(); - AddSC_boss_maiden_of_virtue(); - AddSC_boss_shade_of_aran(); - AddSC_boss_malchezaar(); - AddSC_boss_terestian_illhoof(); - AddSC_boss_moroes(); - AddSC_bosses_opera(); - AddSC_boss_netherspite(); - AddSC_instance_karazhan(); - AddSC_karazhan(); - AddSC_boss_nightbane(); - AddSC_boss_felblood_kaelthas(); // Magister's Terrace - AddSC_boss_selin_fireheart(); - AddSC_boss_vexallus(); - AddSC_boss_priestess_delrissa(); - AddSC_instance_magisters_terrace(); - AddSC_magisters_terrace(); - AddSC_boss_lucifron(); //Molten core - AddSC_boss_magmadar(); - AddSC_boss_gehennas(); - AddSC_boss_garr(); - AddSC_boss_baron_geddon(); - AddSC_boss_shazzrah(); - AddSC_boss_golemagg(); - AddSC_boss_sulfuron(); - AddSC_boss_majordomo(); - AddSC_boss_ragnaros(); - AddSC_instance_molten_core(); - AddSC_molten_core(); - AddSC_the_scarlet_enclave(); //Scarlet Enclave - AddSC_the_scarlet_enclave_c1(); - AddSC_the_scarlet_enclave_c2(); - AddSC_the_scarlet_enclave_c5(); - AddSC_boss_arcanist_doan(); //Scarlet Monastery - AddSC_boss_azshir_the_sleepless(); - AddSC_boss_bloodmage_thalnos(); - AddSC_boss_headless_horseman(); - AddSC_boss_herod(); - AddSC_boss_high_inquisitor_fairbanks(); - AddSC_boss_houndmaster_loksey(); - AddSC_boss_interrogator_vishas(); - AddSC_boss_scorn(); - AddSC_instance_scarlet_monastery(); - AddSC_boss_mograine_and_whitemane(); - AddSC_boss_darkmaster_gandling(); //Scholomance - AddSC_boss_death_knight_darkreaver(); - AddSC_boss_theolenkrastinov(); - AddSC_boss_illuciabarov(); - AddSC_boss_instructormalicia(); - AddSC_boss_jandicebarov(); - AddSC_boss_kormok(); - AddSC_boss_lordalexeibarov(); - AddSC_boss_lorekeeperpolkelt(); - AddSC_boss_rasfrost(); - AddSC_boss_theravenian(); - AddSC_boss_vectus(); - AddSC_instance_scholomance(); - AddSC_shadowfang_keep(); //Shadowfang keep - AddSC_instance_shadowfang_keep(); - AddSC_boss_magistrate_barthilas(); //Stratholme - AddSC_boss_maleki_the_pallid(); - AddSC_boss_nerubenkan(); - AddSC_boss_cannon_master_willey(); - AddSC_boss_baroness_anastari(); - AddSC_boss_ramstein_the_gorger(); - AddSC_boss_timmy_the_cruel(); - AddSC_boss_postmaster_malown(); - AddSC_boss_baron_rivendare(); - AddSC_boss_dathrohan_balnazzar(); - AddSC_boss_order_of_silver_hand(); - AddSC_instance_stratholme(); - AddSC_stratholme(); - AddSC_sunken_temple(); // Sunken Temple - AddSC_instance_sunken_temple(); - AddSC_instance_sunwell_plateau(); //Sunwell Plateau - AddSC_boss_kalecgos(); - AddSC_boss_brutallus(); - AddSC_boss_felmyst(); - AddSC_boss_eredar_twins(); - AddSC_boss_muru(); - AddSC_boss_kiljaeden(); - AddSC_sunwell_plateau(); - AddSC_boss_archaedas(); //Uldaman - AddSC_boss_ironaya(); - AddSC_uldaman(); - AddSC_instance_uldaman(); - AddSC_boss_akilzon(); //Zul'Aman - AddSC_boss_halazzi(); - AddSC_boss_hex_lord_malacrass(); - AddSC_boss_janalai(); - AddSC_boss_nalorakk(); - AddSC_boss_zuljin(); - AddSC_instance_zulaman(); - AddSC_zulaman(); - AddSC_boss_jeklik(); //Zul'Gurub - AddSC_boss_venoxis(); - AddSC_boss_marli(); - AddSC_boss_mandokir(); - AddSC_boss_gahzranka(); - AddSC_boss_thekal(); - AddSC_boss_arlokk(); - AddSC_boss_jindo(); - AddSC_boss_hakkar(); - AddSC_boss_grilek(); - AddSC_boss_hazzarah(); - AddSC_boss_renataki(); - AddSC_boss_wushoolay(); - AddSC_instance_zulgurub(); - - //AddSC_alterac_mountains(); - AddSC_arathi_highlands(); - AddSC_blasted_lands(); - AddSC_boss_kruul(); - AddSC_burning_steppes(); - AddSC_dun_morogh(); - AddSC_duskwood(); - AddSC_eastern_plaguelands(); - AddSC_elwynn_forest(); - AddSC_eversong_woods(); - AddSC_ghostlands(); - AddSC_hinterlands(); - AddSC_ironforge(); - AddSC_isle_of_queldanas(); - AddSC_loch_modan(); - AddSC_redridge_mountains(); - AddSC_searing_gorge(); - AddSC_silvermoon_city(); - AddSC_silverpine_forest(); - AddSC_stormwind_city(); - AddSC_stranglethorn_vale(); - AddSC_tirisfal_glades(); - AddSC_undercity(); - AddSC_western_plaguelands(); - AddSC_westfall(); - AddSC_wetlands(); - - //kalimdor - AddSC_blackfathom_deeps(); //Blackfathom Depths - AddSC_boss_gelihast(); - AddSC_boss_kelris(); - AddSC_boss_aku_mai(); - AddSC_instance_blackfathom_deeps(); - AddSC_hyjal(); //CoT Battle for Mt. Hyjal - AddSC_boss_archimonde(); - AddSC_instance_mount_hyjal(); - AddSC_hyjal_trash(); - AddSC_boss_rage_winterchill(); - AddSC_boss_anetheron(); - AddSC_boss_kazrogal(); - AddSC_boss_azgalor(); - AddSC_boss_captain_skarloc(); //CoT Old Hillsbrad - AddSC_boss_epoch_hunter(); - AddSC_boss_lieutenant_drake(); - AddSC_instance_old_hillsbrad(); - AddSC_old_hillsbrad(); - AddSC_boss_aeonus(); //CoT The Dark Portal - AddSC_boss_chrono_lord_deja(); - AddSC_boss_temporus(); - AddSC_dark_portal(); - AddSC_instance_dark_portal(); - AddSC_boss_epoch(); //CoT Culling Of Stratholme - AddSC_boss_infinite_corruptor(); - AddSC_boss_salramm(); - AddSC_boss_mal_ganis(); - AddSC_boss_meathook(); - AddSC_culling_of_stratholme(); - AddSC_instance_culling_of_stratholme(); - AddSC_boss_celebras_the_cursed(); //Maraudon - AddSC_boss_landslide(); - AddSC_boss_noxxion(); - AddSC_boss_ptheradras(); - AddSC_boss_onyxia(); //Onyxia's Lair - AddSC_instance_onyxias_lair(); - AddSC_boss_amnennar_the_coldbringer(); //Razorfen Downs - AddSC_razorfen_downs(); - AddSC_instance_razorfen_downs(); - AddSC_razorfen_kraul(); //Razorfen Kraul - AddSC_boss_kurinnaxx(); //Ruins of ahn'qiraj - AddSC_boss_rajaxx(); - AddSC_boss_moam(); - AddSC_boss_buru(); - AddSC_boss_ayamiss(); - AddSC_boss_ossirian(); - AddSC_instance_ruins_of_ahnqiraj(); - AddSC_boss_cthun(); //Temple of ahn'qiraj - AddSC_boss_fankriss(); - AddSC_boss_huhuran(); - AddSC_bug_trio(); - AddSC_boss_sartura(); - AddSC_boss_skeram(); - AddSC_boss_twinemperors(); - AddSC_mob_anubisath_sentinel(); - AddSC_instance_temple_of_ahnqiraj(); - AddSC_wailing_caverns(); //Wailing caverns - AddSC_instance_wailing_caverns(); - AddSC_zulfarrak(); //Zul'Farrak generic - AddSC_instance_zulfarrak(); //Zul'Farrak instance script - - AddSC_ashenvale(); - AddSC_azshara(); - AddSC_azuremyst_isle(); - AddSC_bloodmyst_isle(); - AddSC_boss_azuregos(); - AddSC_darkshore(); - AddSC_desolace(); - AddSC_durotar(); - AddSC_dustwallow_marsh(); - AddSC_felwood(); - AddSC_feralas(); - AddSC_moonglade(); - AddSC_mulgore(); - AddSC_orgrimmar(); - AddSC_silithus(); - AddSC_stonetalon_mountains(); - AddSC_tanaris(); - AddSC_teldrassil(); - AddSC_the_barrens(); - AddSC_thousand_needles(); - AddSC_thunder_bluff(); - AddSC_ungoro_crater(); - AddSC_winterspring(); - - //northrend - AddSC_boss_slad_ran(); //Gundrak - AddSC_boss_moorabi(); - AddSC_boss_drakkari_colossus(); - AddSC_boss_gal_darah(); - AddSC_boss_eck(); - AddSC_instance_gundrak(); - AddSC_boss_amanitar(); - AddSC_boss_taldaram(); //Azjol-Nerub Ahn'kahet - AddSC_boss_elder_nadox(); - AddSC_boss_jedoga_shadowseeker(); - AddSC_boss_volazj(); - AddSC_instance_ahnkahet(); - AddSC_boss_argent_challenge(); //Trial of the Champion - AddSC_boss_black_knight(); - AddSC_boss_grand_champions(); - AddSC_instance_trial_of_the_champion(); - AddSC_trial_of_the_champion(); - AddSC_boss_krik_thir(); //Azjol-Nerub Azjol-Nerub - AddSC_boss_hadronox(); - AddSC_boss_anub_arak(); - AddSC_instance_azjol_nerub(); - AddSC_boss_anubrekhan(); //Naxxramas - AddSC_boss_maexxna(); - AddSC_boss_patchwerk(); - AddSC_boss_grobbulus(); - AddSC_boss_razuvious(); - AddSC_boss_kelthuzad(); - AddSC_boss_loatheb(); - AddSC_boss_noth(); - AddSC_boss_gluth(); - AddSC_boss_sapphiron(); - AddSC_boss_four_horsemen(); - AddSC_boss_faerlina(); - AddSC_boss_heigan(); - AddSC_boss_gothik(); - AddSC_boss_thaddius(); - AddSC_instance_naxxramas(); - AddSC_boss_magus_telestra(); //The Nexus Nexus - AddSC_boss_anomalus(); - AddSC_boss_ormorok(); - AddSC_boss_keristrasza(); - AddSC_instance_nexus(); - AddSC_boss_drakos(); //The Nexus The Oculus - AddSC_boss_urom(); - AddSC_instance_oculus(); - AddSC_oculus(); - AddSC_boss_sartharion(); //Obsidian Sanctum - AddSC_instance_obsidian_sanctum(); - AddSC_boss_bjarngrim(); //Ulduar Halls of Lightning - AddSC_boss_loken(); - AddSC_boss_ionar(); - AddSC_boss_volkhan(); - AddSC_instance_halls_of_lightning(); - AddSC_boss_maiden_of_grief(); //Ulduar Halls of Stone - AddSC_boss_krystallus(); - AddSC_boss_sjonnir(); - AddSC_instance_halls_of_stone(); - AddSC_halls_of_stone(); - AddSC_boss_auriaya(); //Ulduar Ulduar - AddSC_boss_flame_leviathan(); - AddSC_boss_ignis(); - AddSC_boss_razorscale(); - AddSC_boss_xt002(); - AddSC_boss_assembly_of_iron(); - AddSC_boss_kologarn(); - AddSC_ulduar_teleporter(); - AddSC_instance_ulduar(); - AddSC_boss_keleseth(); //Utgarde Keep - AddSC_boss_skarvald_dalronn(); - AddSC_boss_ingvar_the_plunderer(); - AddSC_instance_utgarde_keep(); - AddSC_boss_svala(); //Utgarde pinnacle - AddSC_boss_palehoof(); - AddSC_boss_skadi(); - AddSC_boss_ymiron(); - AddSC_instance_utgarde_pinnacle(); - AddSC_utgarde_keep(); - AddSC_boss_archavon(); //Vault of Archavon - AddSC_boss_emalon(); - AddSC_boss_koralon(); - AddSC_boss_toravon(); - AddSC_instance_archavon(); - AddSC_boss_trollgore(); //Drak'Tharon Keep - AddSC_boss_novos(); - AddSC_boss_dred(); - AddSC_boss_tharon_ja(); - AddSC_instance_drak_tharon(); - AddSC_boss_cyanigosa(); //Violet Hold - AddSC_boss_erekem(); - AddSC_boss_ichoron(); - AddSC_boss_lavanthor(); - AddSC_boss_moragg(); - AddSC_boss_xevozz(); - AddSC_boss_zuramat(); - AddSC_instance_violet_hold(); - AddSC_violet_hold(); - AddSC_instance_forge_of_souls(); //Forge of Souls - AddSC_forge_of_souls(); - AddSC_boss_bronjahm(); - AddSC_boss_devourer_of_souls(); - AddSC_instance_pit_of_saron(); //Pit of Saron - AddSC_pit_of_saron(); - AddSC_boss_garfrost(); - AddSC_boss_ick(); - AddSC_boss_tyrannus(); - AddSC_instance_halls_of_reflection(); // Halls of Reflection - AddSC_halls_of_reflection(); - AddSC_boss_falric(); - AddSC_boss_marwyn(); - - AddSC_dalaran(); - AddSC_borean_tundra(); - AddSC_dragonblight(); - AddSC_grizzly_hills(); - AddSC_howling_fjord(); - AddSC_icecrown(); - AddSC_sholazar_basin(); - AddSC_storm_peaks(); - AddSC_zuldrak(); - AddSC_crystalsong_forest(); - - //outland - AddSC_boss_exarch_maladaar(); //Auchindoun Auchenai Crypts - AddSC_boss_shirrak_the_dead_watcher(); - AddSC_boss_nexusprince_shaffar(); //Auchindoun Mana Tombs - AddSC_boss_pandemonius(); - AddSC_boss_darkweaver_syth(); //Auchindoun Sekketh Halls - AddSC_boss_talon_king_ikiss(); - AddSC_instance_sethekk_halls(); - AddSC_instance_shadow_labyrinth(); //Auchindoun Shadow Labyrinth - AddSC_boss_ambassador_hellmaw(); - AddSC_boss_blackheart_the_inciter(); - AddSC_boss_grandmaster_vorpil(); - AddSC_boss_murmur(); - AddSC_black_temple(); //Black Temple - AddSC_boss_illidan(); - AddSC_boss_shade_of_akama(); - AddSC_boss_supremus(); - AddSC_boss_gurtogg_bloodboil(); - AddSC_boss_mother_shahraz(); - AddSC_boss_reliquary_of_souls(); - AddSC_boss_teron_gorefiend(); - AddSC_boss_najentus(); - AddSC_boss_illidari_council(); - AddSC_instance_black_temple(); - AddSC_boss_fathomlord_karathress(); //CR Serpent Shrine Cavern - AddSC_boss_hydross_the_unstable(); - AddSC_boss_lady_vashj(); - AddSC_boss_leotheras_the_blind(); - AddSC_boss_morogrim_tidewalker(); - AddSC_instance_serpentshrine_cavern(); - AddSC_boss_the_lurker_below(); - AddSC_boss_hydromancer_thespia(); //CR Steam Vault - AddSC_boss_mekgineer_steamrigger(); - AddSC_boss_warlord_kalithresh(); - AddSC_instance_steam_vault(); - AddSC_boss_hungarfen(); //CR Underbog - AddSC_boss_the_black_stalker(); - AddSC_boss_gruul(); //Gruul's Lair - AddSC_boss_high_king_maulgar(); - AddSC_instance_gruuls_lair(); - AddSC_boss_broggok(); //HC Blood Furnace - AddSC_boss_kelidan_the_breaker(); - AddSC_boss_the_maker(); - AddSC_instance_blood_furnace(); - AddSC_boss_magtheridon(); //HC Magtheridon's Lair - AddSC_instance_magtheridons_lair(); - AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls - AddSC_boss_warbringer_omrogg(); - AddSC_boss_warchief_kargath_bladefist(); - AddSC_instance_shattered_halls(); - AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts - AddSC_boss_omor_the_unscarred(); - AddSC_boss_vazruden_the_herald(); - AddSC_instance_ramparts(); - AddSC_arcatraz(); //TK Arcatraz - AddSC_boss_harbinger_skyriss(); - AddSC_instance_arcatraz(); - AddSC_boss_high_botanist_freywinn(); //TK Botanica - AddSC_boss_laj(); - AddSC_boss_warp_splinter(); - AddSC_boss_alar(); //TK The Eye - AddSC_boss_kaelthas(); - AddSC_boss_void_reaver(); - AddSC_boss_high_astromancer_solarian(); - AddSC_instance_the_eye(); - AddSC_the_eye(); - AddSC_boss_gatewatcher_iron_hand(); //TK The Mechanar - AddSC_boss_nethermancer_sepethrea(); - AddSC_boss_pathaleon_the_calculator(); - AddSC_instance_mechanar(); - - AddSC_blades_edge_mountains(); - AddSC_boss_doomlordkazzak(); - AddSC_boss_doomwalker(); - AddSC_hellfire_peninsula(); - AddSC_nagrand(); - AddSC_netherstorm(); - AddSC_shadowmoon_valley(); - AddSC_shattrath_city(); - AddSC_terokkar_forest(); - AddSC_zangarmarsh(); - AddSC_onevents(); - -#endif -} diff --git a/src/server/game/ScriptMgr/ScriptLoader.h b/src/server/game/ScriptMgr/ScriptLoader.h deleted file mode 100644 index 57fb7d821f1..00000000000 --- a/src/server/game/ScriptMgr/ScriptLoader.h +++ /dev/null @@ -1,10 +0,0 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 -* This program is free software licensed under GPL version 2 -* Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef SC_SCRIPTLOADER_H -#define SC_SCRIPTLOADER_H - -void AddScripts(); - -#endif diff --git a/src/server/game/ScriptMgr/ScriptMgr.cpp b/src/server/game/ScriptMgr/ScriptMgr.cpp deleted file mode 100644 index 2dcfd258942..00000000000 --- a/src/server/game/ScriptMgr/ScriptMgr.cpp +++ /dev/null @@ -1,549 +0,0 @@ -/* Copyright (C) 2006 - 2008 TrinityScript - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#include "ScriptedPch.h" -#include "Config/Config.h" -#include "Database/DatabaseEnv.h" -#include "DBCStores.h" -#include "ObjectMgr.h" -#include "ProgressBar.h" -#include "ScriptLoader.h" -#include "ScriptSystem.h" -#include "Policies/SingletonImp.h" - -INSTANTIATE_SINGLETON_1(ScriptMgr); - -int num_sc_scripts; -Script *m_scripts[MAX_SCRIPTS]; - -void FillSpellSummary(); -void LoadOverridenSQLData(); - -void ScriptMgr::LoadDatabase() -{ - pSystemMgr.LoadVersion(); - pSystemMgr.LoadScriptTexts(); - pSystemMgr.LoadScriptTextsCustom(); - pSystemMgr.LoadScriptWaypoints(); -} - -struct TSpellSummary { - uint8 Targets; // set of enum SelectTarget - uint8 Effects; // set of enum SelectEffect -}extern *SpellSummary; - -ScriptMgr::ScriptMgr() -{ - -} -ScriptMgr::~ScriptMgr() -{ - -} - -void ScriptMgr::ScriptsInit() -{ - //Trinity Script startup - outstring_log(" _____ _ _ _ ____ _ _"); - outstring_log("|_ _| __(_)_ __ (_) |_ _ _/ ___| ___ _ __(_)_ __ | |_ "); - outstring_log(" | || '__| | '_ \\| | __| | | \\___ \\ / __| \'__| | \'_ \\| __|"); - outstring_log(" | || | | | | | | | |_| |_| |___) | (__| | | | |_) | |_ "); - outstring_log(" |_||_| |_|_| |_|_|\\__|\\__, |____/ \\___|_| |_| .__/ \\__|"); - outstring_log(" |___/ |_| "); - outstring_log(""); - outstring_log(""); - - //Load database (must be called after SD2Config.SetSource). - LoadDatabase(); - - outstring_log("TSCR: Loading C++ scripts"); - barGoLink bar(1); - bar.step(); - outstring_log(""); - - for (uint16 i =0; i> Loaded %i C++ Scripts.", num_sc_scripts); - - outstring_log(">> Load Overriden SQL Data."); - LoadOverridenSQLData(); -} - -//********************************* -//*** Functions used globally *** - -void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) -{ - if (!pSource) - { - error_log("TSCR: DoScriptText entry %i, invalid Source pointer.", iTextEntry); - return; - } - - if (iTextEntry >= 0) - { - error_log("TSCR: DoScriptText with source entry %u (TypeId=%u, guid=%u) attempts to process text entry %i, but text entry must be negative.", pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), iTextEntry); - return; - } - - const StringTextData* pData = pSystemMgr.GetTextData(iTextEntry); - - if (!pData) - { - error_log("TSCR: DoScriptText with source entry %u (TypeId=%u, guid=%u) could not find text entry %i.", pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), iTextEntry); - return; - } - - debug_log("TSCR: DoScriptText: text entry=%i, Sound=%u, Type=%u, Language=%u, Emote=%u", iTextEntry, pData->uiSoundId, pData->uiType, pData->uiLanguage, pData->uiEmote); - - if (pData->uiSoundId) - { - if (GetSoundEntriesStore()->LookupEntry(pData->uiSoundId)) - { - pSource->SendPlaySound(pData->uiSoundId, false); - } - else - error_log("TSCR: DoScriptText entry %i tried to process invalid sound id %u.", iTextEntry, pData->uiSoundId); - } - - if (pData->uiEmote) - { - if (pSource->GetTypeId() == TYPEID_UNIT || pSource->GetTypeId() == TYPEID_PLAYER) - ((Unit*)pSource)->HandleEmoteCommand(pData->uiEmote); - else - error_log("TSCR: DoScriptText entry %i tried to process emote for invalid TypeId (%u).", iTextEntry, pSource->GetTypeId()); - } - - switch(pData->uiType) - { - case CHAT_TYPE_SAY: - pSource->MonsterSay(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0); - break; - case CHAT_TYPE_YELL: - pSource->MonsterYell(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0); - break; - case CHAT_TYPE_TEXT_EMOTE: - pSource->MonsterTextEmote(iTextEntry, pTarget ? pTarget->GetGUID() : 0); - break; - case CHAT_TYPE_BOSS_EMOTE: - pSource->MonsterTextEmote(iTextEntry, pTarget ? pTarget->GetGUID() : 0, true); - break; - case CHAT_TYPE_WHISPER: - { - if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) - pSource->MonsterWhisper(iTextEntry, pTarget->GetGUID()); - else - error_log("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry); - } - break; - case CHAT_TYPE_BOSS_WHISPER: - { - if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) - pSource->MonsterWhisper(iTextEntry, pTarget->GetGUID(), true); - else - error_log("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry); - } - break; - case CHAT_TYPE_ZONE_YELL: - pSource->MonsterYellToZone(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0); - break; - } -} - -void Script::RegisterSelf() -{ - // try to find scripts which try to use another script's allocated memory - // that means didn't allocate memory for script - for (uint16 i = 0; i < MAX_SCRIPTS; ++i) - { - // somebody forgot to allocate memory for a script by a method like this: newscript = new Script - if (m_scripts[i] == this) - { - error_log("ScriptName: '%s' - Forgot to allocate memory, so this script and/or the script before that can't work.", Name.c_str()); - // don't register it - // and don't delete it because its memory is used for another script - return; - } - } - - int id = GetScriptId(Name.c_str()); - if (id) - { - // try to find the script in assigned scripts - bool IsExist = false; - for (uint16 i = 0; i < MAX_SCRIPTS; ++i) - { - if (m_scripts[i]) - { - // if the assigned script's name and the new script's name is the same - if (m_scripts[i]->Name == Name) - { - IsExist = true; - break; - } - } - } - - // if the script doesn't assigned -> assign it! - if (!IsExist) - { - m_scripts[id] = this; - ++num_sc_scripts; - } - // if the script is already assigned -> delete it! - else - { - // TODO: write a better error message than this one :) - error_log("ScriptName: '%s' already assigned with the same ScriptName, so the script can't work.", Name.c_str()); - delete this; - } - } - else - { - if (Name.find("example") == std::string::npos) - error_db_log("TrinityScript: RegisterSelf, but script named %s does not have ScriptName assigned in database.",(this)->Name.c_str()); - delete this; - } -} - -void ScriptMgr::OnLogin(Player *pPlayer) -{ - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnLogin) return; - tmpscript->pOnLogin(pPlayer); -} - -void ScriptMgr::OnLogout(Player *pPlayer) -{ - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnLogout) return; - tmpscript->pOnLogout(pPlayer); -} - -void ScriptMgr::OnPVPKill(Player *killer, Player *killed) -{ - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnPVPKill) return; - tmpscript->pOnPVPKill(killer, killed); -} - -bool ScriptMgr::OnSpellCast (Unit *pUnitTarget, Item *pItemTarget, GameObject *pGoTarget, uint32 i, SpellEntry const *spell) -{ - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnSpellCast) return true; - return tmpscript->pOnSpellCast(pUnitTarget,pItemTarget,pGoTarget,i,spell); -} - -uint32 ScriptMgr::OnGetXP(Player *pPlayer, uint32 amount) -{ - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnGetXP) return amount; - return tmpscript->pOnGetXP(pPlayer,amount); -} - -uint32 ScriptMgr::OnGetMoney(Player *pPlayer, int32 amount) -{ - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnGetMoney) return amount; - return tmpscript->pOnGetMoney(pPlayer,amount); -} - -bool ScriptMgr::OnPlayerChat(Player *pPlayer, const char *text) -{ - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnPlayerChat) return true; - return tmpscript->pOnPlayerChat(pPlayer,text); -} - -void ScriptMgr::OnServerStartup() -{ - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnServerStartup) return; - tmpscript->pOnServerStartup(); -} - -void ScriptMgr::OnServerShutdown() -{ - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnServerShutdown) return; - tmpscript->pOnServerShutdown(); -} - -void ScriptMgr::OnAreaChange(Player *pPlayer, AreaTableEntry const *pArea) -{ - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnAreaChange) return; - tmpscript->pOnAreaChange(pPlayer, pArea); -} - -bool ScriptMgr::OnItemClick (Player *pPlayer, Item *pItem) -{ - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnItemClick) return true; - return tmpscript->pOnItemClick(pPlayer,pItem); -} - -bool ScriptMgr::OnItemOpen (Player *pPlayer, Item *pItem) -{ - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnItemOpen) return true; - return tmpscript->pOnItemOpen(pPlayer,pItem); -} - -bool ScriptMgr::OnGoClick (Player *pPlayer, GameObject *pGameObject) -{ - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnGoClick) return true; - return tmpscript->pOnGoClick(pPlayer,pGameObject); -} - -void ScriptMgr::OnCreatureKill (Player *pPlayer, Creature *pCreature) -{ - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnCreatureKill) return; - tmpscript->pOnCreatureKill(pPlayer,pCreature); -} - -char const* ScriptMgr::ScriptsVersion() -{ - return "Integrated Trinity Scripts"; -} - -bool ScriptMgr::GossipHello (Player * pPlayer, Creature* pCreature) -{ - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pGossipHello) return false; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGossipHello(pPlayer, pCreature); -} - -bool ScriptMgr::GossipSelect(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - debug_log("TSCR: Gossip selection, sender: %d, action: %d", uiSender, uiAction); - - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pGossipSelect) return false; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGossipSelect(pPlayer, pCreature, uiSender, uiAction); -} - -bool ScriptMgr::GossipSelectWithCode(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction, const char* sCode) -{ - debug_log("TSCR: Gossip selection with code, sender: %d, action: %d", uiSender, uiAction); - - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pGossipSelectWithCode) return false; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGossipSelectWithCode(pPlayer, pCreature, uiSender, uiAction, sCode); -} - -bool ScriptMgr::GOSelect(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction) -{ - if (!pGO) - return false; - debug_log("TSCR: Gossip selection, sender: %d, action: %d", uiSender, uiAction); - - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOSelect) return false; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOSelect(pPlayer, pGO, uiSender, uiAction); -} - -bool ScriptMgr::GOSelectWithCode(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction, const char* sCode) -{ - if (!pGO) - return false; - debug_log("TSCR: Gossip selection, sender: %d, action: %d",uiSender, uiAction); - - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOSelectWithCode) return false; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOSelectWithCode(pPlayer, pGO, uiSender ,uiAction, sCode); -} - -bool ScriptMgr::QuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest) -{ - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pQuestAccept) return false; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pQuestAccept(pPlayer, pCreature, pQuest); -} - -bool ScriptMgr::QuestSelect(Player* pPlayer, Creature* pCreature, Quest const* pQuest) -{ - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pQuestSelect) return false; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pQuestSelect(pPlayer, pCreature, pQuest); -} - -bool ScriptMgr::QuestComplete(Player* pPlayer, Creature* pCreature, Quest const* pQuest) -{ - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pQuestComplete) return false; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pQuestComplete(pPlayer, pCreature, pQuest); -} - -bool ScriptMgr::ChooseReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt) -{ - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pChooseReward) return false; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pChooseReward(pPlayer, pCreature, pQuest, opt); -} - -uint32 ScriptMgr::NPCDialogStatus(Player* pPlayer, Creature* pCreature) -{ - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pNPCDialogStatus) return 100; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pNPCDialogStatus(pPlayer, pCreature); -} - -uint32 ScriptMgr::GODialogStatus(Player* pPlayer, GameObject* pGO) -{ - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGODialogStatus) return 100; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGODialogStatus(pPlayer, pGO); -} - -bool ScriptMgr::ItemHello(Player* pPlayer, Item* pItem, Quest const* pQuest) -{ - Script *tmpscript = m_scripts[pItem->GetProto()->ScriptId]; - if (!tmpscript || !tmpscript->pItemHello) return false; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pItemHello(pPlayer, pItem, pQuest); -} - -bool ScriptMgr::ItemQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest) -{ - Script *tmpscript = m_scripts[pItem->GetProto()->ScriptId]; - if (!tmpscript || !tmpscript->pItemQuestAccept) return false; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pItemQuestAccept(pPlayer, pItem, pQuest); -} - -bool ScriptMgr::GOHello(Player* pPlayer, GameObject* pGO) -{ - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOHello) return false; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOHello(pPlayer, pGO); -} - -bool ScriptMgr::GOQuestAccept(Player* pPlayer, GameObject* pGO, Quest const* pQuest) -{ - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOQuestAccept) return false; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOQuestAccept(pPlayer, pGO, pQuest); -} - -bool ScriptMgr::GOChooseReward(Player* pPlayer, GameObject* pGO, Quest const* pQuest, uint32 opt) -{ - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOChooseReward) return false; - - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOChooseReward(pPlayer, pGO, pQuest, opt); -} - -void ScriptMgr::GODestroyed(Player* pPlayer, GameObject* pGO, uint32 destroyedEvent) -{ - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript) return; - tmpscript->pGODestroyed(pPlayer, pGO, destroyedEvent); -} - -bool ScriptMgr::AreaTrigger(Player* pPlayer, AreaTriggerEntry const* atEntry) -{ - Script *tmpscript = m_scripts[GetAreaTriggerScriptId(atEntry->id)]; - if (!tmpscript || !tmpscript->pAreaTrigger) return false; - - return tmpscript->pAreaTrigger(pPlayer, atEntry); -} - -CreatureAI* ScriptMgr::GetAI(Creature* pCreature) -{ - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->GetAI) return NULL; - - return tmpscript->GetAI(pCreature); -} - -bool ScriptMgr::ItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) -{ - Script *tmpscript = m_scripts[pItem->GetProto()->ScriptId]; - if (!tmpscript || !tmpscript->pItemUse) return false; - - return tmpscript->pItemUse(pPlayer, pItem, targets); -} - -bool ScriptMgr::ItemExpire(Player* pPlayer, ItemPrototype const * pItemProto) -{ - Script *tmpscript = m_scripts[pItemProto->ScriptId]; - if (!tmpscript || !tmpscript->pItemExpire) return true; - - return tmpscript->pItemExpire(pPlayer, pItemProto); -} - -bool ScriptMgr::EffectDummyCreature(Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget) -{ - Script *tmpscript = m_scripts[crTarget->GetScriptId()]; - - if (!tmpscript || !tmpscript->pEffectDummyCreature) return false; - - return tmpscript->pEffectDummyCreature(caster, spellId, effIndex, crTarget); -} - -bool ScriptMgr::EffectDummyGameObj(Unit *caster, uint32 spellId, uint32 effIndex, GameObject *gameObjTarget) -{ - Script *tmpscript = m_scripts[gameObjTarget->GetGOInfo()->ScriptId]; - - if (!tmpscript || !tmpscript->pEffectDummyGameObj) return false; - - return tmpscript->pEffectDummyGameObj(caster, spellId, effIndex, gameObjTarget); -} - -bool ScriptMgr::EffectDummyItem(Unit *caster, uint32 spellId, uint32 effIndex, Item *itemTarget) -{ - Script *tmpscript = m_scripts[itemTarget->GetProto()->ScriptId]; - - if (!tmpscript || !tmpscript->pEffectDummyItem) return false; - - return tmpscript->pEffectDummyItem(caster, spellId, effIndex, itemTarget); -} - -InstanceData* ScriptMgr::CreateInstanceData(Map *map) -{ - if (!map->IsDungeon()) return NULL; - - Script *tmpscript = m_scripts[((InstanceMap*)map)->GetScriptId()]; - if (!tmpscript || !tmpscript->GetInstanceData) return NULL; - - return tmpscript->GetInstanceData(map); -} - diff --git a/src/server/game/ScriptMgr/ScriptMgr.h b/src/server/game/ScriptMgr/ScriptMgr.h deleted file mode 100644 index ed7200d5786..00000000000 --- a/src/server/game/ScriptMgr/ScriptMgr.h +++ /dev/null @@ -1,163 +0,0 @@ -/* Copyright (C) 2008-2010 Trinity - * - * Thanks to the original authors: ScriptDev2 - * - * This program is free software licensed under GPL version 2 - * Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef SC_SCRIPTMGR_H -#define SC_SCRIPTMGR_H - -#include "Common.h" -#include "Platform/CompilerDefs.h" -#include "DBCStructure.h" -#include "Config/ConfigEnv.h" - -class Player; -class Creature; -class CreatureAI; -class InstanceData; -class Quest; -class Item; -class GameObject; -class SpellCastTargets; -class Map; -class Unit; -class WorldObject; -struct ItemPrototype; - -#define MAX_SCRIPTS 5000 //72 bytes each (approx 351kb) -#define VISIBLE_RANGE (166.0f) //MAX visible range (size of grid) -#define DEFAULT_TEXT "" - -struct Script -{ - Script() : - pOnLogin(NULL), pOnLogout(NULL), pOnPVPKill(NULL), pOnSpellCast(NULL), pOnGetXP(NULL), - pOnGetMoney(NULL), pOnPlayerChat(NULL), pOnServerStartup(NULL), pOnServerShutdown(NULL), - pOnAreaChange(NULL), pOnItemClick(NULL), pOnItemOpen(NULL), pOnGoClick(NULL), pOnCreatureKill(NULL), - pGossipHello(NULL), pQuestAccept(NULL), pGossipSelect(NULL), pGossipSelectWithCode(NULL), - pGOSelect(NULL), pGOSelectWithCode(NULL), - pQuestSelect(NULL), pQuestComplete(NULL), pNPCDialogStatus(NULL), pGODialogStatus(NULL), - pChooseReward(NULL), pGODestroyed(NULL), pItemHello(NULL), pGOHello(NULL), pAreaTrigger(NULL), pItemQuestAccept(NULL), - pGOQuestAccept(NULL), pGOChooseReward(NULL),pItemUse(NULL), pItemExpire(NULL), - pEffectDummyCreature(NULL), pEffectDummyGameObj(NULL), pEffectDummyItem(NULL), - GetAI(NULL), GetInstanceData(NULL) - {} - - std::string Name; - - //Methods to be scripted - void (*pOnLogin)(Player*); - void (*pOnLogout)(Player*); - void (*pOnPVPKill)(Player*, Player*); - bool (*pOnSpellCast)(Unit*, Item*, GameObject*, uint32, SpellEntry const*); - uint32 (*pOnGetXP)(Player*, uint32); - int32 (*pOnGetMoney)(Player*, int32); - bool (*pOnPlayerChat)(Player*, const char*); - void (*pOnServerStartup)(); - void (*pOnServerShutdown)(); - void (*pOnAreaChange)(Player*, AreaTableEntry const*); - bool (*pOnItemClick)(Player*, Item*); - bool (*pOnItemOpen)(Player*, Item*); - bool (*pOnGoClick)(Player*, GameObject*); - void (*pOnCreatureKill)(Player*, Creature*); - bool (*pGossipHello)(Player*, Creature*); - bool (*pQuestAccept)(Player*, Creature*, Quest const*); - bool (*pGossipSelect)(Player*, Creature*, uint32 , uint32); - bool (*pGossipSelectWithCode)(Player*, Creature*, uint32 , uint32 , const char*); - bool (*pGOSelect)(Player*, GameObject*, uint32 , uint32); - bool (*pGOSelectWithCode)(Player*, GameObject*, uint32 , uint32 , const char*); - bool (*pQuestSelect)(Player*, Creature*, Quest const*); - bool (*pQuestComplete)(Player*, Creature*, Quest const*); - uint32 (*pNPCDialogStatus)(Player*, Creature*); - uint32 (*pGODialogStatus)(Player*, GameObject * _GO); - bool (*pChooseReward)(Player*, Creature*, Quest const*, uint32); - bool (*pItemHello)(Player*, Item*, Quest const*); - bool (*pGOHello)(Player*, GameObject*); - bool (*pAreaTrigger)(Player*, AreaTriggerEntry const*); - bool (*pItemQuestAccept)(Player*, Item *, Quest const*); - bool (*pGOQuestAccept)(Player*, GameObject*, Quest const*); - bool (*pGOChooseReward)(Player*, GameObject*, Quest const*, uint32); - void (*pGODestroyed)(Player*, GameObject*, uint32); - bool (*pItemUse)(Player*, Item*, SpellCastTargets const&); - bool (*pItemExpire)(Player*, ItemPrototype const *); - bool (*pEffectDummyCreature)(Unit*, uint32, uint32, Creature*); - bool (*pEffectDummyGameObj)(Unit*, uint32, uint32, GameObject*); - bool (*pEffectDummyItem)(Unit*, uint32, uint32, Item*); - - CreatureAI* (*GetAI)(Creature*); - InstanceData* (*GetInstanceData)(Map*); - - void RegisterSelf(); -}; - -class ScriptMgr -{ - public: - ScriptMgr(); - ~ScriptMgr(); - - void ScriptsInit(); - void LoadDatabase(); - char const* ScriptsVersion(); - - //event handlers - void OnLogin(Player *pPlayer); - void OnLogout(Player *pPlayer); - void OnPVPKill(Player *killer, Player *killed); - bool OnSpellCast (Unit *pUnitTarget, Item *pItemTarget, GameObject *pGoTarget, uint32 i, SpellEntry const *spell); - uint32 OnGetXP(Player *pPlayer, uint32 amount); - uint32 OnGetMoney(Player *pPlayer, int32 amount); - bool OnPlayerChat(Player *pPlayer, const char *text); - void OnServerStartup(); - void OnServerShutdown(); - void OnAreaChange(Player *pPlayer, AreaTableEntry const *pArea); - bool OnItemClick (Player *pPlayer, Item *pItem); - bool OnItemOpen (Player *pPlayer, Item *pItem); - bool OnGoClick (Player *pPlayer, GameObject *pGameObject); - void OnCreatureKill (Player *pPlayer, Creature *pCreature); - bool GossipHello (Player * pPlayer, Creature* pCreature); - bool GossipSelect(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction); - bool GossipSelectWithCode(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction, const char* sCode); - bool GOSelect(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction); - bool GOSelectWithCode(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction, const char* sCode); - bool QuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest); - bool QuestSelect(Player* pPlayer, Creature* pCreature, Quest const* pQuest); - bool QuestComplete(Player* pPlayer, Creature* pCreature, Quest const* pQuest); - bool ChooseReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt); - uint32 NPCDialogStatus(Player* pPlayer, Creature* pCreature); - uint32 GODialogStatus(Player* pPlayer, GameObject* pGO); - bool ItemHello(Player* pPlayer, Item* pItem, Quest const* pQuest); - bool ItemQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest); - bool GOHello(Player* pPlayer, GameObject* pGO); - bool GOQuestAccept(Player* pPlayer, GameObject* pGO, Quest const* pQuest); - bool GOChooseReward(Player* pPlayer, GameObject* pGO, Quest const* pQuest, uint32 opt); - void GODestroyed(Player* pPlayer, GameObject* pGO, uint32 destroyedEvent); - bool AreaTrigger(Player* pPlayer,AreaTriggerEntry const* atEntry); - CreatureAI* GetAI(Creature* pCreature); - bool ItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets); - bool ItemExpire(Player* pPlayer, ItemPrototype const * pItemProto); - bool EffectDummyCreature(Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget); - bool EffectDummyGameObj(Unit *caster, uint32 spellId, uint32 effIndex, GameObject *gameObjTarget); - bool EffectDummyItem(Unit *caster, uint32 spellId, uint32 effIndex, Item *itemTarget); - InstanceData* CreateInstanceData(Map *map); -}; - -//Config file accessors -//std::string GetConfigValueStr(char const* option); -//int32 GetConfigValueInt32(char const* option); -//float GetConfigValueFloat(char const* option); - -//Generic scripting text function -void DoScriptText(int32 textEntry, WorldObject* pSource, Unit *pTarget = NULL); - -#if COMPILER == COMPILER_GNU -#define FUNC_PTR(name,callconvention,returntype,parameters) typedef returntype(*name)parameters __attribute__ ((callconvention)); -#else -#define FUNC_PTR(name, callconvention, returntype, parameters) typedef returntype(callconvention *name)parameters; -#endif - -#define sScriptMgr Trinity::Singleton::Instance() -#endif - diff --git a/src/server/game/ScriptMgr/ScriptSystem.cpp b/src/server/game/ScriptMgr/ScriptSystem.cpp deleted file mode 100644 index 0037b100412..00000000000 --- a/src/server/game/ScriptMgr/ScriptSystem.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (C) 2008-2010 Trinity - * - * Thanks to the original authors: MaNGOS - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ScriptedPch.h" -#include "ScriptSystem.h" -#include "ProgressBar.h" -#include "ObjectMgr.h" -#include "Database/DatabaseEnv.h" - -SystemMgr::SystemMgr() -{ -} - -SystemMgr& SystemMgr::Instance() -{ - static SystemMgr pSysMgr; - return pSysMgr; -} - -void SystemMgr::LoadVersion() -{ - //Get Version information - QueryResult_AutoPtr Result = WorldDatabase.Query("SELECT script_version FROM version LIMIT 1"); - - if (Result) - { - Field* pFields = Result->Fetch(); - - outstring_log("TSCR: Database version is: %s", pFields[0].GetString()); - outstring_log(""); - } - else - { - error_log("TSCR: Missing `version`.`script_version` information."); - outstring_log(""); - } -} - -void SystemMgr::LoadScriptTexts() -{ - outstring_log("TSCR: Loading Script Texts..."); - LoadTrinityStrings(WorldDatabase,"script_texts",TEXT_SOURCE_RANGE,1+(TEXT_SOURCE_RANGE*2)); - - QueryResult_AutoPtr Result = WorldDatabase.Query("SELECT entry, sound, type, language, emote FROM script_texts"); - - outstring_log("TSCR: Loading Script Texts additional data..."); - - if (Result) - { - barGoLink bar(Result->GetRowCount()); - uint32 uiCount = 0; - - do - { - bar.step(); - Field* pFields = Result->Fetch(); - StringTextData pTemp; - - int32 iId = pFields[0].GetInt32(); - pTemp.uiSoundId = pFields[1].GetUInt32(); - pTemp.uiType = pFields[2].GetUInt32(); - pTemp.uiLanguage = pFields[3].GetUInt32(); - pTemp.uiEmote = pFields[4].GetUInt32(); - - if (iId >= 0) - { - error_db_log("TSCR: Entry %i in table `script_texts` is not a negative value.", iId); - continue; - } - - if (iId > TEXT_SOURCE_RANGE || iId <= TEXT_SOURCE_RANGE*2) - { - error_db_log("TSCR: Entry %i in table `script_texts` is out of accepted entry range for table.", iId); - continue; - } - - if (pTemp.uiSoundId) - { - if (!GetSoundEntriesStore()->LookupEntry(pTemp.uiSoundId)) - error_db_log("TSCR: Entry %i in table `script_texts` has soundId %u but sound does not exist.", iId, pTemp.uiSoundId); - } - - if (!GetLanguageDescByID(pTemp.uiLanguage)) - error_db_log("TSCR: Entry %i in table `script_texts` using Language %u but Language does not exist.", iId, pTemp.uiLanguage); - - if (pTemp.uiType > CHAT_TYPE_ZONE_YELL) - error_db_log("TSCR: Entry %i in table `script_texts` has Type %u but this Chat Type does not exist.", iId, pTemp.uiType); - - m_mTextDataMap[iId] = pTemp; - ++uiCount; - } while (Result->NextRow()); - - outstring_log(""); - outstring_log(">> Loaded %u additional Script Texts data.", uiCount); - } - else - { - barGoLink bar(1); - bar.step(); - outstring_log(""); - outstring_log(">> Loaded 0 additional Script Texts data. DB table `script_texts` is empty."); - } -} - -void SystemMgr::LoadScriptTextsCustom() -{ - outstring_log("TSCR: Loading Custom Texts..."); - LoadTrinityStrings(WorldDatabase,"custom_texts",TEXT_SOURCE_RANGE*2,1+(TEXT_SOURCE_RANGE*3)); - - QueryResult_AutoPtr Result = WorldDatabase.Query("SELECT entry, sound, type, language, emote FROM custom_texts"); - - outstring_log("TSCR: Loading Custom Texts additional data..."); - - if (Result) - { - barGoLink bar(Result->GetRowCount()); - uint32 uiCount = 0; - - do - { - bar.step(); - Field* pFields = Result->Fetch(); - StringTextData pTemp; - - int32 iId = pFields[0].GetInt32(); - pTemp.uiSoundId = pFields[1].GetUInt32(); - pTemp.uiType = pFields[2].GetUInt32(); - pTemp.uiLanguage = pFields[3].GetUInt32(); - pTemp.uiEmote = pFields[4].GetUInt32(); - - if (iId >= 0) - { - error_db_log("TSCR: Entry %i in table `custom_texts` is not a negative value.", iId); - continue; - } - - if (iId > TEXT_SOURCE_RANGE*2 || iId <= TEXT_SOURCE_RANGE*3) - { - error_db_log("TSCR: Entry %i in table `custom_texts` is out of accepted entry range for table.", iId); - continue; - } - - if (pTemp.uiSoundId) - { - if (!GetSoundEntriesStore()->LookupEntry(pTemp.uiSoundId)) - error_db_log("TSCR: Entry %i in table `custom_texts` has soundId %u but sound does not exist.", iId, pTemp.uiSoundId); - } - - if (!GetLanguageDescByID(pTemp.uiLanguage)) - error_db_log("TSCR: Entry %i in table `custom_texts` using Language %u but Language does not exist.", iId, pTemp.uiLanguage); - - if (pTemp.uiType > CHAT_TYPE_ZONE_YELL) - error_db_log("TSCR: Entry %i in table `custom_texts` has Type %u but this Chat Type does not exist.", iId, pTemp.uiType); - - m_mTextDataMap[iId] = pTemp; - ++uiCount; - } while (Result->NextRow()); - - outstring_log(""); - outstring_log(">> Loaded %u additional Custom Texts data.", uiCount); - } - else - { - barGoLink bar(1); - bar.step(); - outstring_log(""); - outstring_log(">> Loaded 0 additional Custom Texts data. DB table `custom_texts` is empty."); - } -} - -void SystemMgr::LoadScriptWaypoints() -{ - // Drop Existing Waypoint list - m_mPointMoveMap.clear(); - - uint64 uiCreatureCount = 0; - - // Load Waypoints - QueryResult_AutoPtr Result = WorldDatabase.Query("SELECT COUNT(entry) FROM script_waypoint GROUP BY entry"); - if (Result) - uiCreatureCount = Result->GetRowCount(); - - outstring_log("TSCR: Loading Script Waypoints for %u creature(s)...", uiCreatureCount); - - Result = WorldDatabase.Query("SELECT entry, pointid, location_x, location_y, location_z, waittime FROM script_waypoint ORDER BY pointid"); - - if (Result) - { - barGoLink bar(Result->GetRowCount()); - uint32 uiNodeCount = 0; - - do - { - bar.step(); - Field* pFields = Result->Fetch(); - ScriptPointMove pTemp; - - pTemp.uiCreatureEntry = pFields[0].GetUInt32(); - uint32 uiEntry = pTemp.uiCreatureEntry; - pTemp.uiPointId = pFields[1].GetUInt32(); - pTemp.fX = pFields[2].GetFloat(); - pTemp.fY = pFields[3].GetFloat(); - pTemp.fZ = pFields[4].GetFloat(); - pTemp.uiWaitTime = pFields[5].GetUInt32(); - - CreatureInfo const* pCInfo = GetCreatureTemplateStore(pTemp.uiCreatureEntry); - - if (!pCInfo) - { - error_db_log("TSCR: DB table script_waypoint has waypoint for non-existant creature entry %u", pTemp.uiCreatureEntry); - continue; - } - - if (!pCInfo->ScriptID) - error_db_log("TSCR: DB table script_waypoint has waypoint for creature entry %u, but creature does not have ScriptName defined and then useless.", pTemp.uiCreatureEntry); - - m_mPointMoveMap[uiEntry].push_back(pTemp); - ++uiNodeCount; - } while (Result->NextRow()); - - outstring_log(""); - outstring_log(">> Loaded %u Script Waypoint nodes.", uiNodeCount); - } - else - { - barGoLink bar(1); - bar.step(); - outstring_log(""); - outstring_log(">> Loaded 0 Script Waypoints. DB table `script_waypoint` is empty."); - } -} diff --git a/src/server/game/ScriptMgr/ScriptSystem.h b/src/server/game/ScriptMgr/ScriptSystem.h deleted file mode 100644 index f78cd2e64fa..00000000000 --- a/src/server/game/ScriptMgr/ScriptSystem.h +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 -* This program is free software licensed under GPL version 2 -* Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef SC_SYSTEM_H -#define SC_SYSTEM_H - -#define TEXT_SOURCE_RANGE -1000000 //the amount of entries each text source has available - -//TODO: find better namings and definitions. -//N=Neutral, A=Alliance, H=Horde. -//NEUTRAL or FRIEND = Hostility to player surroundings (not a good definition) -//ACTIVE or PASSIVE = Hostility to environment surroundings. -enum eEscortFaction -{ - FACTION_ESCORT_A_NEUTRAL_PASSIVE = 10, - FACTION_ESCORT_H_NEUTRAL_PASSIVE = 33, - FACTION_ESCORT_N_NEUTRAL_PASSIVE = 113, - - FACTION_ESCORT_A_NEUTRAL_ACTIVE = 231, - FACTION_ESCORT_H_NEUTRAL_ACTIVE = 232, - FACTION_ESCORT_N_NEUTRAL_ACTIVE = 250, - - FACTION_ESCORT_N_FRIEND_PASSIVE = 290, - FACTION_ESCORT_N_FRIEND_ACTIVE = 495, - - FACTION_ESCORT_A_PASSIVE = 774, - FACTION_ESCORT_H_PASSIVE = 775, - - FACTION_ESCORT_N_ACTIVE = 1986, - FACTION_ESCORT_H_ACTIVE = 2046 -}; - -struct ScriptPointMove -{ - uint32 uiCreatureEntry; - uint32 uiPointId; - float fX; - float fY; - float fZ; - uint32 uiWaitTime; -}; - -struct StringTextData -{ - uint32 uiSoundId; - uint8 uiType; - uint32 uiLanguage; - uint32 uiEmote; -}; - -#define pSystemMgr SystemMgr::Instance() - -class SystemMgr -{ - public: - SystemMgr(); - ~SystemMgr() {} - - static SystemMgr& Instance(); - - //Maps and lists - typedef UNORDERED_MAP TextDataMap; - typedef UNORDERED_MAP > PointMoveMap; - - //Database - void LoadVersion(); - void LoadScriptTexts(); - void LoadScriptTextsCustom(); - void LoadScriptWaypoints(); - - //Retrive from storage - StringTextData const* GetTextData(int32 uiTextId) const - { - TextDataMap::const_iterator itr = m_mTextDataMap.find(uiTextId); - - if (itr == m_mTextDataMap.end()) - return NULL; - - return &itr->second; - } - - std::vector const &GetPointMoveList(uint32 uiCreatureEntry) const - { - static std::vector vEmpty; - - PointMoveMap::const_iterator itr = m_mPointMoveMap.find(uiCreatureEntry); - - if (itr == m_mPointMoveMap.end()) - return vEmpty; - - return itr->second; - } - - protected: - TextDataMap m_mTextDataMap; //additional data for text strings - PointMoveMap m_mPointMoveMap; //coordinates for waypoints -}; - -#endif diff --git a/src/server/game/ScriptMgr/ScriptedPch.cpp b/src/server/game/ScriptMgr/ScriptedPch.cpp deleted file mode 100644 index a80690d05da..00000000000 --- a/src/server/game/ScriptMgr/ScriptedPch.cpp +++ /dev/null @@ -1,6 +0,0 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 -* This program is free software licensed under GPL version 2 -* Please see the included DOCS/LICENSE.TXT for more information */ - -#include "ScriptedPch.h" - diff --git a/src/server/game/ScriptMgr/ScriptedPch.h b/src/server/game/ScriptMgr/ScriptedPch.h deleted file mode 100644 index 1e83a88b87a..00000000000 --- a/src/server/game/ScriptMgr/ScriptedPch.h +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 -* This program is free software licensed under GPL version 2 -* Please see the included DOCS/LICENSE.TXT for more information */ - -#ifndef SC_PRECOMPILED_H -#define SC_PRECOMPILED_H - -#include "ScriptMgr.h" -#include "Cell.h" -#include "CellImpl.h" -#include "GameEventMgr.h" -#include "GridNotifiers.h" -#include "GridNotifiersImpl.h" -#include "Unit.h" -#include "GameObject.h" -#include "ScriptedCreature.h" -#include "ScriptedGossip.h" -#include "ScriptedInstance.h" -#include "CombatAI.h" -#include "PassiveAI.h" -#include "Chat.h" -#include "DBCStructure.h" -#include "DBCStores.h" -#include "ObjectMgr.h" - -#ifdef WIN32 -#include - -#endif - -#endif - diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp new file mode 100644 index 00000000000..2006c091287 --- /dev/null +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -0,0 +1,1023 @@ +/* Copyright (C) 2008 - 2010 TrinityCore + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" + +#ifdef WIN32 + #define DO_SCRIPTS +#endif + +#ifdef DO_SCRIPTS +//custom + +//examples +void AddSC_example_creature(); +void AddSC_example_escort(); +void AddSC_example_gossip_codebox(); +void AddSC_example_misc(); + +//world +void AddSC_areatrigger_scripts(); +void AddSC_boss_emeriss(); +void AddSC_boss_taerar(); +void AddSC_boss_ysondre(); +void AddSC_generic_creature(); +void AddSC_go_scripts(); +void AddSC_guards(); +void AddSC_item_scripts(); +void AddSC_npc_professions(); +void AddSC_npc_innkeeper(); +void AddSC_npcs_special(); +void AddSC_npc_taxi(); + +//eastern kingdoms +void AddSC_alterac_valley(); //Alterac Valley +void AddSC_boss_balinda(); +void AddSC_boss_drekthar(); +void AddSC_boss_galvangar(); +void AddSC_boss_vanndar(); +void AddSC_blackrock_depths(); //Blackrock Depths +void AddSC_boss_ambassador_flamelash(); +void AddSC_boss_anubshiah(); +void AddSC_boss_draganthaurissan(); +void AddSC_boss_general_angerforge(); +void AddSC_boss_gorosh_the_dervish(); +void AddSC_boss_grizzle(); +void AddSC_boss_high_interrogator_gerstahn(); +void AddSC_boss_magmus(); +void AddSC_boss_moira_bronzebeard(); +void AddSC_boss_tomb_of_seven(); +void AddSC_instance_blackrock_depths(); +void AddSC_blackrock_spire(); //Blackrock Spire +void AddSC_boss_drakkisath(); +void AddSC_boss_halycon(); +void AddSC_boss_highlordomokk(); +void AddSC_boss_mothersmolderweb(); +void AddSC_boss_overlordwyrmthalak(); +void AddSC_boss_shadowvosh(); +void AddSC_boss_thebeast(); +void AddSC_boss_warmastervoone(); +void AddSC_boss_quatermasterzigris(); +void AddSC_boss_pyroguard_emberseer(); +void AddSC_boss_gyth(); +void AddSC_boss_rend_blackhand(); +void AddSC_instance_blackrock_spire(); +void AddSC_boss_razorgore(); //Blackwing lair +void AddSC_boss_vael(); +void AddSC_boss_broodlord(); +void AddSC_boss_firemaw(); +void AddSC_boss_ebonroc(); +void AddSC_boss_flamegor(); +void AddSC_boss_chromaggus(); +void AddSC_boss_nefarian(); +void AddSC_boss_victor_nefarius(); +void AddSC_boss_mr_smite(); +void AddSC_deadmines(); //Deadmines +void AddSC_instance_deadmines(); +void AddSC_gnomeregan(); //Gnomeregan +void AddSC_instance_gnomeregan(); +void AddSC_boss_attumen(); //Karazhan +void AddSC_boss_curator(); +void AddSC_boss_maiden_of_virtue(); +void AddSC_boss_shade_of_aran(); +void AddSC_boss_malchezaar(); +void AddSC_boss_terestian_illhoof(); +void AddSC_boss_moroes(); +void AddSC_bosses_opera(); +void AddSC_boss_netherspite(); +void AddSC_instance_karazhan(); +void AddSC_karazhan(); +void AddSC_boss_nightbane(); +void AddSC_boss_felblood_kaelthas(); // Magister's Terrace +void AddSC_boss_selin_fireheart(); +void AddSC_boss_vexallus(); +void AddSC_boss_priestess_delrissa(); +void AddSC_instance_magisters_terrace(); +void AddSC_magisters_terrace(); +void AddSC_boss_lucifron(); //Molten core +void AddSC_boss_magmadar(); +void AddSC_boss_gehennas(); +void AddSC_boss_garr(); +void AddSC_boss_baron_geddon(); +void AddSC_boss_shazzrah(); +void AddSC_boss_golemagg(); +void AddSC_boss_sulfuron(); +void AddSC_boss_majordomo(); +void AddSC_boss_ragnaros(); +void AddSC_instance_molten_core(); +void AddSC_molten_core(); +void AddSC_the_scarlet_enclave(); //Scarlet Enclave +void AddSC_the_scarlet_enclave_c1(); +void AddSC_the_scarlet_enclave_c2(); +void AddSC_the_scarlet_enclave_c5(); +void AddSC_boss_arcanist_doan(); //Scarlet Monastery +void AddSC_boss_azshir_the_sleepless(); +void AddSC_boss_bloodmage_thalnos(); +void AddSC_boss_headless_horseman(); +void AddSC_boss_herod(); +void AddSC_boss_high_inquisitor_fairbanks(); +void AddSC_boss_houndmaster_loksey(); +void AddSC_boss_interrogator_vishas(); +void AddSC_boss_scorn(); +void AddSC_instance_scarlet_monastery(); +void AddSC_boss_mograine_and_whitemane(); +void AddSC_boss_darkmaster_gandling(); //Scholomance +void AddSC_boss_death_knight_darkreaver(); +void AddSC_boss_theolenkrastinov(); +void AddSC_boss_illuciabarov(); +void AddSC_boss_instructormalicia(); +void AddSC_boss_jandicebarov(); +void AddSC_boss_kormok(); +void AddSC_boss_lordalexeibarov(); +void AddSC_boss_lorekeeperpolkelt(); +void AddSC_boss_rasfrost(); +void AddSC_boss_theravenian(); +void AddSC_boss_vectus(); +void AddSC_instance_scholomance(); +void AddSC_shadowfang_keep(); //Shadowfang keep +void AddSC_instance_shadowfang_keep(); +void AddSC_boss_magistrate_barthilas(); //Stratholme +void AddSC_boss_maleki_the_pallid(); +void AddSC_boss_nerubenkan(); +void AddSC_boss_cannon_master_willey(); +void AddSC_boss_baroness_anastari(); +void AddSC_boss_ramstein_the_gorger(); +void AddSC_boss_timmy_the_cruel(); +void AddSC_boss_postmaster_malown(); +void AddSC_boss_baron_rivendare(); +void AddSC_boss_dathrohan_balnazzar(); +void AddSC_boss_order_of_silver_hand(); +void AddSC_instance_stratholme(); +void AddSC_stratholme(); +void AddSC_sunken_temple(); // Sunken Temple +void AddSC_instance_sunken_temple(); +void AddSC_instance_sunwell_plateau(); //Sunwell Plateau +void AddSC_boss_kalecgos(); +void AddSC_boss_brutallus(); +void AddSC_boss_felmyst(); +void AddSC_boss_eredar_twins(); +void AddSC_boss_muru(); +void AddSC_boss_kiljaeden(); +void AddSC_sunwell_plateau(); +void AddSC_boss_archaedas(); //Uldaman +void AddSC_boss_ironaya(); +void AddSC_uldaman(); +void AddSC_instance_uldaman(); +void AddSC_boss_akilzon(); //Zul'Aman +void AddSC_boss_halazzi(); +void AddSC_boss_hex_lord_malacrass(); +void AddSC_boss_janalai(); +void AddSC_boss_nalorakk(); +void AddSC_boss_zuljin(); +void AddSC_instance_zulaman(); +void AddSC_zulaman(); +void AddSC_boss_jeklik(); //Zul'Gurub +void AddSC_boss_venoxis(); +void AddSC_boss_marli(); +void AddSC_boss_mandokir(); +void AddSC_boss_gahzranka(); +void AddSC_boss_thekal(); +void AddSC_boss_arlokk(); +void AddSC_boss_jindo(); +void AddSC_boss_hakkar(); +void AddSC_boss_grilek(); +void AddSC_boss_hazzarah(); +void AddSC_boss_renataki(); +void AddSC_boss_wushoolay(); +void AddSC_instance_zulgurub(); + +//void AddSC_alterac_mountains(); +void AddSC_arathi_highlands(); +void AddSC_blasted_lands(); +void AddSC_boss_kruul(); +void AddSC_burning_steppes(); +void AddSC_dun_morogh(); +void AddSC_duskwood(); +void AddSC_eastern_plaguelands(); +void AddSC_elwynn_forest(); +void AddSC_eversong_woods(); +void AddSC_ghostlands(); +void AddSC_hinterlands(); +void AddSC_ironforge(); +void AddSC_isle_of_queldanas(); +void AddSC_loch_modan(); +void AddSC_redridge_mountains(); +void AddSC_searing_gorge(); +void AddSC_silvermoon_city(); +void AddSC_silverpine_forest(); +void AddSC_stormwind_city(); +void AddSC_stranglethorn_vale(); +void AddSC_tirisfal_glades(); +void AddSC_undercity(); +void AddSC_western_plaguelands(); +void AddSC_westfall(); +void AddSC_wetlands(); + +//kalimdor +void AddSC_blackfathom_deeps(); //Blackfathom Depths +void AddSC_boss_gelihast(); +void AddSC_boss_kelris(); +void AddSC_boss_aku_mai(); +void AddSC_instance_blackfathom_deeps(); +void AddSC_hyjal(); //CoT Battle for Mt. Hyjal +void AddSC_boss_archimonde(); +void AddSC_instance_mount_hyjal(); +void AddSC_hyjal_trash(); +void AddSC_boss_rage_winterchill(); +void AddSC_boss_anetheron(); +void AddSC_boss_kazrogal(); +void AddSC_boss_azgalor(); +void AddSC_boss_captain_skarloc(); //CoT Old Hillsbrad +void AddSC_boss_epoch_hunter(); +void AddSC_boss_lieutenant_drake(); +void AddSC_instance_old_hillsbrad(); +void AddSC_old_hillsbrad(); +void AddSC_boss_aeonus(); //CoT The Dark Portal +void AddSC_boss_chrono_lord_deja(); +void AddSC_boss_temporus(); +void AddSC_dark_portal(); +void AddSC_instance_dark_portal(); +void AddSC_boss_epoch(); //CoT Culling Of Stratholme +void AddSC_boss_infinite_corruptor(); +void AddSC_boss_salramm(); +void AddSC_boss_mal_ganis(); +void AddSC_boss_meathook(); +void AddSC_culling_of_stratholme(); +void AddSC_instance_culling_of_stratholme(); +void AddSC_boss_celebras_the_cursed(); //Maraudon +void AddSC_boss_landslide(); +void AddSC_boss_noxxion(); +void AddSC_boss_ptheradras(); +void AddSC_boss_onyxia(); //Onyxia's Lair +void AddSC_instance_onyxias_lair(); +void AddSC_boss_amnennar_the_coldbringer(); //Razorfen Downs +void AddSC_razorfen_downs(); +void AddSC_instance_razorfen_downs(); +void AddSC_razorfen_kraul(); //Razorfen Kraul +void AddSC_boss_kurinnaxx(); //Ruins of ahn'qiraj +void AddSC_boss_rajaxx(); +void AddSC_boss_moam(); +void AddSC_boss_buru(); +void AddSC_boss_ayamiss(); +void AddSC_boss_ossirian(); +void AddSC_instance_ruins_of_ahnqiraj(); +void AddSC_boss_cthun(); //Temple of ahn'qiraj +void AddSC_boss_fankriss(); +void AddSC_boss_huhuran(); +void AddSC_bug_trio(); +void AddSC_boss_sartura(); +void AddSC_boss_skeram(); +void AddSC_boss_twinemperors(); +void AddSC_mob_anubisath_sentinel(); +void AddSC_instance_temple_of_ahnqiraj(); +void AddSC_wailing_caverns(); //Wailing caverns +void AddSC_instance_wailing_caverns(); +void AddSC_zulfarrak(); //Zul'Farrak generic +void AddSC_instance_zulfarrak(); //Zul'Farrak instance script + +void AddSC_ashenvale(); +void AddSC_azshara(); +void AddSC_azuremyst_isle(); +void AddSC_bloodmyst_isle(); +void AddSC_boss_azuregos(); +void AddSC_darkshore(); +void AddSC_desolace(); +void AddSC_durotar(); +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(); +void AddSC_tanaris(); +void AddSC_teldrassil(); +void AddSC_the_barrens(); +void AddSC_thousand_needles(); +void AddSC_thunder_bluff(); +void AddSC_ungoro_crater(); +void AddSC_winterspring(); + +//northrend +void AddSC_boss_slad_ran(); +void AddSC_boss_moorabi(); +void AddSC_boss_drakkari_colossus(); +void AddSC_boss_gal_darah(); +void AddSC_boss_eck(); +void AddSC_instance_gundrak(); +void AddSC_boss_krik_thir(); //Azjol-Nerub +void AddSC_boss_hadronox(); +void AddSC_boss_anub_arak(); +void AddSC_instance_azjol_nerub(); +void AddSC_instance_ahnkahet(); //Azjol-Nerub Ahn'kahet +void AddSC_boss_amanitar(); +void AddSC_boss_taldaram(); +void AddSC_boss_jedoga_shadowseeker(); +void AddSC_boss_elder_nadox(); +void AddSC_boss_volazj(); +void AddSC_boss_argent_challenge(); //Trial of the Champion +void AddSC_boss_black_knight(); +void AddSC_boss_grand_champions(); +void AddSC_instance_trial_of_the_champion(); +void AddSC_trial_of_the_champion(); +void AddSC_boss_anubrekhan(); //Naxxramas +void AddSC_boss_maexxna(); +void AddSC_boss_patchwerk(); +void AddSC_boss_grobbulus(); +void AddSC_boss_razuvious(); +void AddSC_boss_kelthuzad(); +void AddSC_boss_loatheb(); +void AddSC_boss_noth(); +void AddSC_boss_gluth(); +void AddSC_boss_sapphiron(); +void AddSC_boss_four_horsemen(); +void AddSC_boss_faerlina(); +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_anomalus(); +void AddSC_boss_ormorok(); +void AddSC_boss_keristrasza(); +void AddSC_instance_nexus(); +void AddSC_boss_drakos(); //The Nexus The Oculus +void AddSC_boss_urom(); +void AddSC_instance_oculus(); +void AddSC_oculus(); +void AddSC_boss_sartharion(); //Obsidian Sanctum +void AddSC_instance_obsidian_sanctum(); +void AddSC_boss_bjarngrim(); //Ulduar Halls of Lightning +void AddSC_boss_loken(); +void AddSC_boss_ionar(); +void AddSC_boss_volkhan(); +void AddSC_instance_halls_of_lightning(); +void AddSC_boss_maiden_of_grief(); //Ulduar Halls of Stone +void AddSC_boss_krystallus(); +void AddSC_boss_sjonnir(); +void AddSC_instance_halls_of_stone(); +void AddSC_halls_of_stone(); +void AddSC_boss_auriaya(); //Ulduar Ulduar +void AddSC_boss_flame_leviathan(); +void AddSC_boss_ignis(); +void AddSC_boss_razorscale(); +void AddSC_boss_xt002(); +void AddSC_boss_kologarn(); +void AddSC_boss_assembly_of_iron(); +void AddSC_ulduar_teleporter(); +void AddSC_instance_ulduar(); +void AddSC_boss_keleseth(); //Utgarde Keep +void AddSC_boss_skarvald_dalronn(); +void AddSC_boss_ingvar_the_plunderer(); +void AddSC_instance_utgarde_keep(); +void AddSC_boss_svala(); //Utgarde pinnacle +void AddSC_boss_palehoof(); +void AddSC_boss_skadi(); +void AddSC_boss_ymiron(); +void AddSC_instance_utgarde_pinnacle(); +void AddSC_utgarde_keep(); +void AddSC_boss_archavon(); //Vault of Archavon +void AddSC_boss_emalon(); +void AddSC_boss_koralon(); +void AddSC_boss_toravon(); +void AddSC_instance_archavon(); +void AddSC_boss_trollgore(); //Drak'Tharon Keep +void AddSC_boss_novos(); +void AddSC_boss_dred(); +void AddSC_boss_tharon_ja(); +void AddSC_instance_drak_tharon(); +void AddSC_boss_cyanigosa(); //Violet Hold +void AddSC_boss_erekem(); +void AddSC_boss_ichoron(); +void AddSC_boss_lavanthor(); +void AddSC_boss_moragg(); +void AddSC_boss_xevozz(); +void AddSC_boss_zuramat(); +void AddSC_instance_violet_hold(); +void AddSC_violet_hold(); +void AddSC_instance_forge_of_souls(); //Forge of Souls +void AddSC_forge_of_souls(); +void AddSC_boss_bronjahm(); +void AddSC_boss_devourer_of_souls(); +void AddSC_instance_pit_of_saron(); //Pit of Saron +void AddSC_pit_of_saron(); +void AddSC_boss_garfrost(); +void AddSC_boss_ick(); +void AddSC_boss_tyrannus(); +void AddSC_instance_halls_of_reflection(); // Halls of Reflection +void AddSC_halls_of_reflection(); +void AddSC_boss_falric(); +void AddSC_boss_marwyn(); + +void AddSC_dalaran(); +void AddSC_borean_tundra(); +void AddSC_dragonblight(); +void AddSC_grizzly_hills(); +void AddSC_howling_fjord(); +void AddSC_icecrown(); +void AddSC_sholazar_basin(); +void AddSC_storm_peaks(); +void AddSC_zuldrak(); +void AddSC_crystalsong_forest(); + +//outland +void AddSC_boss_exarch_maladaar(); //Auchindoun Auchenai Crypts +void AddSC_boss_shirrak_the_dead_watcher(); +void AddSC_boss_nexusprince_shaffar(); //Auchindoun Mana Tombs +void AddSC_boss_pandemonius(); +void AddSC_boss_darkweaver_syth(); //Auchindoun Sekketh Halls +void AddSC_boss_talon_king_ikiss(); +void AddSC_instance_sethekk_halls(); +void AddSC_instance_shadow_labyrinth(); //Auchindoun Shadow Labyrinth +void AddSC_boss_ambassador_hellmaw(); +void AddSC_boss_blackheart_the_inciter(); +void AddSC_boss_grandmaster_vorpil(); +void AddSC_boss_murmur(); +void AddSC_black_temple(); //Black Temple +void AddSC_boss_illidan(); +void AddSC_boss_shade_of_akama(); +void AddSC_boss_supremus(); +void AddSC_boss_gurtogg_bloodboil(); +void AddSC_boss_mother_shahraz(); +void AddSC_boss_reliquary_of_souls(); +void AddSC_boss_teron_gorefiend(); +void AddSC_boss_najentus(); +void AddSC_boss_illidari_council(); +void AddSC_instance_black_temple(); +void AddSC_boss_fathomlord_karathress(); //CR Serpent Shrine Cavern +void AddSC_boss_hydross_the_unstable(); +void AddSC_boss_lady_vashj(); +void AddSC_boss_leotheras_the_blind(); +void AddSC_boss_morogrim_tidewalker(); +void AddSC_instance_serpentshrine_cavern(); +void AddSC_boss_the_lurker_below(); +void AddSC_boss_hydromancer_thespia(); //CR Steam Vault +void AddSC_boss_mekgineer_steamrigger(); +void AddSC_boss_warlord_kalithresh(); +void AddSC_instance_steam_vault(); +void AddSC_boss_hungarfen(); //CR Underbog +void AddSC_boss_the_black_stalker(); +void AddSC_boss_gruul(); //Gruul's Lair +void AddSC_boss_high_king_maulgar(); +void AddSC_instance_gruuls_lair(); +void AddSC_boss_broggok(); //HC Blood Furnace +void AddSC_boss_kelidan_the_breaker(); +void AddSC_boss_the_maker(); +void AddSC_instance_blood_furnace(); +void AddSC_boss_magtheridon(); //HC Magtheridon's Lair +void AddSC_instance_magtheridons_lair(); +void AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls +void AddSC_boss_warbringer_omrogg(); +void AddSC_boss_warchief_kargath_bladefist(); +void AddSC_instance_shattered_halls(); +void AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts +void AddSC_boss_omor_the_unscarred(); +void AddSC_boss_vazruden_the_herald(); +void AddSC_instance_ramparts(); +void AddSC_arcatraz(); //TK Arcatraz +void AddSC_boss_harbinger_skyriss(); +void AddSC_instance_arcatraz(); +void AddSC_boss_high_botanist_freywinn(); //TK Botanica +void AddSC_boss_laj(); +void AddSC_boss_warp_splinter(); +void AddSC_boss_alar(); //TK The Eye +void AddSC_boss_kaelthas(); +void AddSC_boss_void_reaver(); +void AddSC_boss_high_astromancer_solarian(); +void AddSC_instance_the_eye(); +void AddSC_the_eye(); +void AddSC_boss_gatewatcher_iron_hand(); //TK The Mechanar +void AddSC_boss_nethermancer_sepethrea(); +void AddSC_boss_pathaleon_the_calculator(); +void AddSC_instance_mechanar(); + +void AddSC_blades_edge_mountains(); +void AddSC_boss_doomlordkazzak(); +void AddSC_boss_doomwalker(); +void AddSC_hellfire_peninsula(); +void AddSC_nagrand(); +void AddSC_netherstorm(); +void AddSC_shadowmoon_valley(); +void AddSC_shattrath_city(); +void AddSC_terokkar_forest(); +void AddSC_zangarmarsh(); +void AddSC_onevents(); + +#endif + +void AddScripts() +{ +#ifdef DO_SCRIPTS + + //custom + + //examples + AddSC_example_creature(); + AddSC_example_escort(); + AddSC_example_gossip_codebox(); + AddSC_example_misc(); + + //world + AddSC_areatrigger_scripts(); + AddSC_boss_emeriss(); + AddSC_boss_taerar(); + AddSC_boss_ysondre(); + AddSC_generic_creature(); + AddSC_go_scripts(); + AddSC_guards(); + AddSC_item_scripts(); + AddSC_npc_professions(); + AddSC_npc_innkeeper(); + AddSC_npcs_special(); + AddSC_npc_taxi(); + + //eastern kingdoms + AddSC_alterac_valley(); //Alterac Valley + AddSC_boss_balinda(); + AddSC_boss_drekthar(); + AddSC_boss_galvangar(); + AddSC_boss_vanndar(); + AddSC_blackrock_depths(); //Blackrock Depths + AddSC_boss_ambassador_flamelash(); + AddSC_boss_anubshiah(); + AddSC_boss_draganthaurissan(); + AddSC_boss_general_angerforge(); + AddSC_boss_gorosh_the_dervish(); + AddSC_boss_grizzle(); + AddSC_boss_high_interrogator_gerstahn(); + AddSC_boss_magmus(); + AddSC_boss_moira_bronzebeard(); + AddSC_boss_tomb_of_seven(); + AddSC_instance_blackrock_depths(); + AddSC_blackrock_spire(); //Blackrock Spire + AddSC_boss_drakkisath(); + AddSC_boss_halycon(); + AddSC_boss_highlordomokk(); + AddSC_boss_mothersmolderweb(); + AddSC_boss_overlordwyrmthalak(); + AddSC_boss_shadowvosh(); + AddSC_boss_thebeast(); + AddSC_boss_warmastervoone(); + AddSC_boss_quatermasterzigris(); + AddSC_boss_pyroguard_emberseer(); + AddSC_boss_gyth(); + AddSC_boss_rend_blackhand(); + AddSC_instance_blackrock_spire(); + AddSC_boss_razorgore(); //Blackwing lair + AddSC_boss_vael(); + AddSC_boss_broodlord(); + AddSC_boss_firemaw(); + AddSC_boss_ebonroc(); + AddSC_boss_flamegor(); + AddSC_boss_chromaggus(); + AddSC_boss_nefarian(); + AddSC_boss_victor_nefarius(); + AddSC_boss_mr_smite(); + AddSC_deadmines(); //Deadmines + AddSC_instance_deadmines(); + AddSC_gnomeregan(); //Gnomeregan + AddSC_instance_gnomeregan(); + AddSC_boss_attumen(); //Karazhan + AddSC_boss_curator(); + AddSC_boss_maiden_of_virtue(); + AddSC_boss_shade_of_aran(); + AddSC_boss_malchezaar(); + AddSC_boss_terestian_illhoof(); + AddSC_boss_moroes(); + AddSC_bosses_opera(); + AddSC_boss_netherspite(); + AddSC_instance_karazhan(); + AddSC_karazhan(); + AddSC_boss_nightbane(); + AddSC_boss_felblood_kaelthas(); // Magister's Terrace + AddSC_boss_selin_fireheart(); + AddSC_boss_vexallus(); + AddSC_boss_priestess_delrissa(); + AddSC_instance_magisters_terrace(); + AddSC_magisters_terrace(); + AddSC_boss_lucifron(); //Molten core + AddSC_boss_magmadar(); + AddSC_boss_gehennas(); + AddSC_boss_garr(); + AddSC_boss_baron_geddon(); + AddSC_boss_shazzrah(); + AddSC_boss_golemagg(); + AddSC_boss_sulfuron(); + AddSC_boss_majordomo(); + AddSC_boss_ragnaros(); + AddSC_instance_molten_core(); + AddSC_molten_core(); + AddSC_the_scarlet_enclave(); //Scarlet Enclave + AddSC_the_scarlet_enclave_c1(); + AddSC_the_scarlet_enclave_c2(); + AddSC_the_scarlet_enclave_c5(); + AddSC_boss_arcanist_doan(); //Scarlet Monastery + AddSC_boss_azshir_the_sleepless(); + AddSC_boss_bloodmage_thalnos(); + AddSC_boss_headless_horseman(); + AddSC_boss_herod(); + AddSC_boss_high_inquisitor_fairbanks(); + AddSC_boss_houndmaster_loksey(); + AddSC_boss_interrogator_vishas(); + AddSC_boss_scorn(); + AddSC_instance_scarlet_monastery(); + AddSC_boss_mograine_and_whitemane(); + AddSC_boss_darkmaster_gandling(); //Scholomance + AddSC_boss_death_knight_darkreaver(); + AddSC_boss_theolenkrastinov(); + AddSC_boss_illuciabarov(); + AddSC_boss_instructormalicia(); + AddSC_boss_jandicebarov(); + AddSC_boss_kormok(); + AddSC_boss_lordalexeibarov(); + AddSC_boss_lorekeeperpolkelt(); + AddSC_boss_rasfrost(); + AddSC_boss_theravenian(); + AddSC_boss_vectus(); + AddSC_instance_scholomance(); + AddSC_shadowfang_keep(); //Shadowfang keep + AddSC_instance_shadowfang_keep(); + AddSC_boss_magistrate_barthilas(); //Stratholme + AddSC_boss_maleki_the_pallid(); + AddSC_boss_nerubenkan(); + AddSC_boss_cannon_master_willey(); + AddSC_boss_baroness_anastari(); + AddSC_boss_ramstein_the_gorger(); + AddSC_boss_timmy_the_cruel(); + AddSC_boss_postmaster_malown(); + AddSC_boss_baron_rivendare(); + AddSC_boss_dathrohan_balnazzar(); + AddSC_boss_order_of_silver_hand(); + AddSC_instance_stratholme(); + AddSC_stratholme(); + AddSC_sunken_temple(); // Sunken Temple + AddSC_instance_sunken_temple(); + AddSC_instance_sunwell_plateau(); //Sunwell Plateau + AddSC_boss_kalecgos(); + AddSC_boss_brutallus(); + AddSC_boss_felmyst(); + AddSC_boss_eredar_twins(); + AddSC_boss_muru(); + AddSC_boss_kiljaeden(); + AddSC_sunwell_plateau(); + AddSC_boss_archaedas(); //Uldaman + AddSC_boss_ironaya(); + AddSC_uldaman(); + AddSC_instance_uldaman(); + AddSC_boss_akilzon(); //Zul'Aman + AddSC_boss_halazzi(); + AddSC_boss_hex_lord_malacrass(); + AddSC_boss_janalai(); + AddSC_boss_nalorakk(); + AddSC_boss_zuljin(); + AddSC_instance_zulaman(); + AddSC_zulaman(); + AddSC_boss_jeklik(); //Zul'Gurub + AddSC_boss_venoxis(); + AddSC_boss_marli(); + AddSC_boss_mandokir(); + AddSC_boss_gahzranka(); + AddSC_boss_thekal(); + AddSC_boss_arlokk(); + AddSC_boss_jindo(); + AddSC_boss_hakkar(); + AddSC_boss_grilek(); + AddSC_boss_hazzarah(); + AddSC_boss_renataki(); + AddSC_boss_wushoolay(); + AddSC_instance_zulgurub(); + + //AddSC_alterac_mountains(); + AddSC_arathi_highlands(); + AddSC_blasted_lands(); + AddSC_boss_kruul(); + AddSC_burning_steppes(); + AddSC_dun_morogh(); + AddSC_duskwood(); + AddSC_eastern_plaguelands(); + AddSC_elwynn_forest(); + AddSC_eversong_woods(); + AddSC_ghostlands(); + AddSC_hinterlands(); + AddSC_ironforge(); + AddSC_isle_of_queldanas(); + AddSC_loch_modan(); + AddSC_redridge_mountains(); + AddSC_searing_gorge(); + AddSC_silvermoon_city(); + AddSC_silverpine_forest(); + AddSC_stormwind_city(); + AddSC_stranglethorn_vale(); + AddSC_tirisfal_glades(); + AddSC_undercity(); + AddSC_western_plaguelands(); + AddSC_westfall(); + AddSC_wetlands(); + + //kalimdor + AddSC_blackfathom_deeps(); //Blackfathom Depths + AddSC_boss_gelihast(); + AddSC_boss_kelris(); + AddSC_boss_aku_mai(); + AddSC_instance_blackfathom_deeps(); + AddSC_hyjal(); //CoT Battle for Mt. Hyjal + AddSC_boss_archimonde(); + AddSC_instance_mount_hyjal(); + AddSC_hyjal_trash(); + AddSC_boss_rage_winterchill(); + AddSC_boss_anetheron(); + AddSC_boss_kazrogal(); + AddSC_boss_azgalor(); + AddSC_boss_captain_skarloc(); //CoT Old Hillsbrad + AddSC_boss_epoch_hunter(); + AddSC_boss_lieutenant_drake(); + AddSC_instance_old_hillsbrad(); + AddSC_old_hillsbrad(); + AddSC_boss_aeonus(); //CoT The Dark Portal + AddSC_boss_chrono_lord_deja(); + AddSC_boss_temporus(); + AddSC_dark_portal(); + AddSC_instance_dark_portal(); + AddSC_boss_epoch(); //CoT Culling Of Stratholme + AddSC_boss_infinite_corruptor(); + AddSC_boss_salramm(); + AddSC_boss_mal_ganis(); + AddSC_boss_meathook(); + AddSC_culling_of_stratholme(); + AddSC_instance_culling_of_stratholme(); + AddSC_boss_celebras_the_cursed(); //Maraudon + AddSC_boss_landslide(); + AddSC_boss_noxxion(); + AddSC_boss_ptheradras(); + AddSC_boss_onyxia(); //Onyxia's Lair + AddSC_instance_onyxias_lair(); + AddSC_boss_amnennar_the_coldbringer(); //Razorfen Downs + AddSC_razorfen_downs(); + AddSC_instance_razorfen_downs(); + AddSC_razorfen_kraul(); //Razorfen Kraul + AddSC_boss_kurinnaxx(); //Ruins of ahn'qiraj + AddSC_boss_rajaxx(); + AddSC_boss_moam(); + AddSC_boss_buru(); + AddSC_boss_ayamiss(); + AddSC_boss_ossirian(); + AddSC_instance_ruins_of_ahnqiraj(); + AddSC_boss_cthun(); //Temple of ahn'qiraj + AddSC_boss_fankriss(); + AddSC_boss_huhuran(); + AddSC_bug_trio(); + AddSC_boss_sartura(); + AddSC_boss_skeram(); + AddSC_boss_twinemperors(); + AddSC_mob_anubisath_sentinel(); + AddSC_instance_temple_of_ahnqiraj(); + AddSC_wailing_caverns(); //Wailing caverns + AddSC_instance_wailing_caverns(); + AddSC_zulfarrak(); //Zul'Farrak generic + AddSC_instance_zulfarrak(); //Zul'Farrak instance script + + AddSC_ashenvale(); + AddSC_azshara(); + AddSC_azuremyst_isle(); + AddSC_bloodmyst_isle(); + AddSC_boss_azuregos(); + AddSC_darkshore(); + AddSC_desolace(); + AddSC_durotar(); + AddSC_dustwallow_marsh(); + AddSC_felwood(); + AddSC_feralas(); + AddSC_moonglade(); + AddSC_mulgore(); + AddSC_orgrimmar(); + AddSC_silithus(); + AddSC_stonetalon_mountains(); + AddSC_tanaris(); + AddSC_teldrassil(); + AddSC_the_barrens(); + AddSC_thousand_needles(); + AddSC_thunder_bluff(); + AddSC_ungoro_crater(); + AddSC_winterspring(); + + //northrend + AddSC_boss_slad_ran(); //Gundrak + AddSC_boss_moorabi(); + AddSC_boss_drakkari_colossus(); + AddSC_boss_gal_darah(); + AddSC_boss_eck(); + AddSC_instance_gundrak(); + AddSC_boss_amanitar(); + AddSC_boss_taldaram(); //Azjol-Nerub Ahn'kahet + AddSC_boss_elder_nadox(); + AddSC_boss_jedoga_shadowseeker(); + AddSC_boss_volazj(); + AddSC_instance_ahnkahet(); + AddSC_boss_argent_challenge(); //Trial of the Champion + AddSC_boss_black_knight(); + AddSC_boss_grand_champions(); + AddSC_instance_trial_of_the_champion(); + AddSC_trial_of_the_champion(); + AddSC_boss_krik_thir(); //Azjol-Nerub Azjol-Nerub + AddSC_boss_hadronox(); + AddSC_boss_anub_arak(); + AddSC_instance_azjol_nerub(); + AddSC_boss_anubrekhan(); //Naxxramas + AddSC_boss_maexxna(); + AddSC_boss_patchwerk(); + AddSC_boss_grobbulus(); + AddSC_boss_razuvious(); + AddSC_boss_kelthuzad(); + AddSC_boss_loatheb(); + AddSC_boss_noth(); + AddSC_boss_gluth(); + AddSC_boss_sapphiron(); + AddSC_boss_four_horsemen(); + AddSC_boss_faerlina(); + AddSC_boss_heigan(); + AddSC_boss_gothik(); + AddSC_boss_thaddius(); + AddSC_instance_naxxramas(); + AddSC_boss_magus_telestra(); //The Nexus Nexus + AddSC_boss_anomalus(); + AddSC_boss_ormorok(); + AddSC_boss_keristrasza(); + AddSC_instance_nexus(); + AddSC_boss_drakos(); //The Nexus The Oculus + AddSC_boss_urom(); + AddSC_instance_oculus(); + AddSC_oculus(); + AddSC_boss_sartharion(); //Obsidian Sanctum + AddSC_instance_obsidian_sanctum(); + AddSC_boss_bjarngrim(); //Ulduar Halls of Lightning + AddSC_boss_loken(); + AddSC_boss_ionar(); + AddSC_boss_volkhan(); + AddSC_instance_halls_of_lightning(); + AddSC_boss_maiden_of_grief(); //Ulduar Halls of Stone + AddSC_boss_krystallus(); + AddSC_boss_sjonnir(); + AddSC_instance_halls_of_stone(); + AddSC_halls_of_stone(); + AddSC_boss_auriaya(); //Ulduar Ulduar + AddSC_boss_flame_leviathan(); + AddSC_boss_ignis(); + AddSC_boss_razorscale(); + AddSC_boss_xt002(); + AddSC_boss_assembly_of_iron(); + AddSC_boss_kologarn(); + AddSC_ulduar_teleporter(); + AddSC_instance_ulduar(); + AddSC_boss_keleseth(); //Utgarde Keep + AddSC_boss_skarvald_dalronn(); + AddSC_boss_ingvar_the_plunderer(); + AddSC_instance_utgarde_keep(); + AddSC_boss_svala(); //Utgarde pinnacle + AddSC_boss_palehoof(); + AddSC_boss_skadi(); + AddSC_boss_ymiron(); + AddSC_instance_utgarde_pinnacle(); + AddSC_utgarde_keep(); + AddSC_boss_archavon(); //Vault of Archavon + AddSC_boss_emalon(); + AddSC_boss_koralon(); + AddSC_boss_toravon(); + AddSC_instance_archavon(); + AddSC_boss_trollgore(); //Drak'Tharon Keep + AddSC_boss_novos(); + AddSC_boss_dred(); + AddSC_boss_tharon_ja(); + AddSC_instance_drak_tharon(); + AddSC_boss_cyanigosa(); //Violet Hold + AddSC_boss_erekem(); + AddSC_boss_ichoron(); + AddSC_boss_lavanthor(); + AddSC_boss_moragg(); + AddSC_boss_xevozz(); + AddSC_boss_zuramat(); + AddSC_instance_violet_hold(); + AddSC_violet_hold(); + AddSC_instance_forge_of_souls(); //Forge of Souls + AddSC_forge_of_souls(); + AddSC_boss_bronjahm(); + AddSC_boss_devourer_of_souls(); + AddSC_instance_pit_of_saron(); //Pit of Saron + AddSC_pit_of_saron(); + AddSC_boss_garfrost(); + AddSC_boss_ick(); + AddSC_boss_tyrannus(); + AddSC_instance_halls_of_reflection(); // Halls of Reflection + AddSC_halls_of_reflection(); + AddSC_boss_falric(); + AddSC_boss_marwyn(); + + AddSC_dalaran(); + AddSC_borean_tundra(); + AddSC_dragonblight(); + AddSC_grizzly_hills(); + AddSC_howling_fjord(); + AddSC_icecrown(); + AddSC_sholazar_basin(); + AddSC_storm_peaks(); + AddSC_zuldrak(); + AddSC_crystalsong_forest(); + + //outland + AddSC_boss_exarch_maladaar(); //Auchindoun Auchenai Crypts + AddSC_boss_shirrak_the_dead_watcher(); + AddSC_boss_nexusprince_shaffar(); //Auchindoun Mana Tombs + AddSC_boss_pandemonius(); + AddSC_boss_darkweaver_syth(); //Auchindoun Sekketh Halls + AddSC_boss_talon_king_ikiss(); + AddSC_instance_sethekk_halls(); + AddSC_instance_shadow_labyrinth(); //Auchindoun Shadow Labyrinth + AddSC_boss_ambassador_hellmaw(); + AddSC_boss_blackheart_the_inciter(); + AddSC_boss_grandmaster_vorpil(); + AddSC_boss_murmur(); + AddSC_black_temple(); //Black Temple + AddSC_boss_illidan(); + AddSC_boss_shade_of_akama(); + AddSC_boss_supremus(); + AddSC_boss_gurtogg_bloodboil(); + AddSC_boss_mother_shahraz(); + AddSC_boss_reliquary_of_souls(); + AddSC_boss_teron_gorefiend(); + AddSC_boss_najentus(); + AddSC_boss_illidari_council(); + AddSC_instance_black_temple(); + AddSC_boss_fathomlord_karathress(); //CR Serpent Shrine Cavern + AddSC_boss_hydross_the_unstable(); + AddSC_boss_lady_vashj(); + AddSC_boss_leotheras_the_blind(); + AddSC_boss_morogrim_tidewalker(); + AddSC_instance_serpentshrine_cavern(); + AddSC_boss_the_lurker_below(); + AddSC_boss_hydromancer_thespia(); //CR Steam Vault + AddSC_boss_mekgineer_steamrigger(); + AddSC_boss_warlord_kalithresh(); + AddSC_instance_steam_vault(); + AddSC_boss_hungarfen(); //CR Underbog + AddSC_boss_the_black_stalker(); + AddSC_boss_gruul(); //Gruul's Lair + AddSC_boss_high_king_maulgar(); + AddSC_instance_gruuls_lair(); + AddSC_boss_broggok(); //HC Blood Furnace + AddSC_boss_kelidan_the_breaker(); + AddSC_boss_the_maker(); + AddSC_instance_blood_furnace(); + AddSC_boss_magtheridon(); //HC Magtheridon's Lair + AddSC_instance_magtheridons_lair(); + AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls + AddSC_boss_warbringer_omrogg(); + AddSC_boss_warchief_kargath_bladefist(); + AddSC_instance_shattered_halls(); + AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts + AddSC_boss_omor_the_unscarred(); + AddSC_boss_vazruden_the_herald(); + AddSC_instance_ramparts(); + AddSC_arcatraz(); //TK Arcatraz + AddSC_boss_harbinger_skyriss(); + AddSC_instance_arcatraz(); + AddSC_boss_high_botanist_freywinn(); //TK Botanica + AddSC_boss_laj(); + AddSC_boss_warp_splinter(); + AddSC_boss_alar(); //TK The Eye + AddSC_boss_kaelthas(); + AddSC_boss_void_reaver(); + AddSC_boss_high_astromancer_solarian(); + AddSC_instance_the_eye(); + AddSC_the_eye(); + AddSC_boss_gatewatcher_iron_hand(); //TK The Mechanar + AddSC_boss_nethermancer_sepethrea(); + AddSC_boss_pathaleon_the_calculator(); + AddSC_instance_mechanar(); + + AddSC_blades_edge_mountains(); + AddSC_boss_doomlordkazzak(); + AddSC_boss_doomwalker(); + AddSC_hellfire_peninsula(); + AddSC_nagrand(); + AddSC_netherstorm(); + AddSC_shadowmoon_valley(); + AddSC_shattrath_city(); + AddSC_terokkar_forest(); + AddSC_zangarmarsh(); + AddSC_onevents(); + +#endif +} diff --git a/src/server/game/Scripting/ScriptLoader.h b/src/server/game/Scripting/ScriptLoader.h new file mode 100644 index 00000000000..57fb7d821f1 --- /dev/null +++ b/src/server/game/Scripting/ScriptLoader.h @@ -0,0 +1,10 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 +* This program is free software licensed under GPL version 2 +* Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef SC_SCRIPTLOADER_H +#define SC_SCRIPTLOADER_H + +void AddScripts(); + +#endif diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp new file mode 100644 index 00000000000..2dcfd258942 --- /dev/null +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -0,0 +1,549 @@ +/* Copyright (C) 2006 - 2008 TrinityScript + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#include "ScriptedPch.h" +#include "Config/Config.h" +#include "Database/DatabaseEnv.h" +#include "DBCStores.h" +#include "ObjectMgr.h" +#include "ProgressBar.h" +#include "ScriptLoader.h" +#include "ScriptSystem.h" +#include "Policies/SingletonImp.h" + +INSTANTIATE_SINGLETON_1(ScriptMgr); + +int num_sc_scripts; +Script *m_scripts[MAX_SCRIPTS]; + +void FillSpellSummary(); +void LoadOverridenSQLData(); + +void ScriptMgr::LoadDatabase() +{ + pSystemMgr.LoadVersion(); + pSystemMgr.LoadScriptTexts(); + pSystemMgr.LoadScriptTextsCustom(); + pSystemMgr.LoadScriptWaypoints(); +} + +struct TSpellSummary { + uint8 Targets; // set of enum SelectTarget + uint8 Effects; // set of enum SelectEffect +}extern *SpellSummary; + +ScriptMgr::ScriptMgr() +{ + +} +ScriptMgr::~ScriptMgr() +{ + +} + +void ScriptMgr::ScriptsInit() +{ + //Trinity Script startup + outstring_log(" _____ _ _ _ ____ _ _"); + outstring_log("|_ _| __(_)_ __ (_) |_ _ _/ ___| ___ _ __(_)_ __ | |_ "); + outstring_log(" | || '__| | '_ \\| | __| | | \\___ \\ / __| \'__| | \'_ \\| __|"); + outstring_log(" | || | | | | | | | |_| |_| |___) | (__| | | | |_) | |_ "); + outstring_log(" |_||_| |_|_| |_|_|\\__|\\__, |____/ \\___|_| |_| .__/ \\__|"); + outstring_log(" |___/ |_| "); + outstring_log(""); + outstring_log(""); + + //Load database (must be called after SD2Config.SetSource). + LoadDatabase(); + + outstring_log("TSCR: Loading C++ scripts"); + barGoLink bar(1); + bar.step(); + outstring_log(""); + + for (uint16 i =0; i> Loaded %i C++ Scripts.", num_sc_scripts); + + outstring_log(">> Load Overriden SQL Data."); + LoadOverridenSQLData(); +} + +//********************************* +//*** Functions used globally *** + +void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) +{ + if (!pSource) + { + error_log("TSCR: DoScriptText entry %i, invalid Source pointer.", iTextEntry); + return; + } + + if (iTextEntry >= 0) + { + error_log("TSCR: DoScriptText with source entry %u (TypeId=%u, guid=%u) attempts to process text entry %i, but text entry must be negative.", pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), iTextEntry); + return; + } + + const StringTextData* pData = pSystemMgr.GetTextData(iTextEntry); + + if (!pData) + { + error_log("TSCR: DoScriptText with source entry %u (TypeId=%u, guid=%u) could not find text entry %i.", pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), iTextEntry); + return; + } + + debug_log("TSCR: DoScriptText: text entry=%i, Sound=%u, Type=%u, Language=%u, Emote=%u", iTextEntry, pData->uiSoundId, pData->uiType, pData->uiLanguage, pData->uiEmote); + + if (pData->uiSoundId) + { + if (GetSoundEntriesStore()->LookupEntry(pData->uiSoundId)) + { + pSource->SendPlaySound(pData->uiSoundId, false); + } + else + error_log("TSCR: DoScriptText entry %i tried to process invalid sound id %u.", iTextEntry, pData->uiSoundId); + } + + if (pData->uiEmote) + { + if (pSource->GetTypeId() == TYPEID_UNIT || pSource->GetTypeId() == TYPEID_PLAYER) + ((Unit*)pSource)->HandleEmoteCommand(pData->uiEmote); + else + error_log("TSCR: DoScriptText entry %i tried to process emote for invalid TypeId (%u).", iTextEntry, pSource->GetTypeId()); + } + + switch(pData->uiType) + { + case CHAT_TYPE_SAY: + pSource->MonsterSay(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0); + break; + case CHAT_TYPE_YELL: + pSource->MonsterYell(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0); + break; + case CHAT_TYPE_TEXT_EMOTE: + pSource->MonsterTextEmote(iTextEntry, pTarget ? pTarget->GetGUID() : 0); + break; + case CHAT_TYPE_BOSS_EMOTE: + pSource->MonsterTextEmote(iTextEntry, pTarget ? pTarget->GetGUID() : 0, true); + break; + case CHAT_TYPE_WHISPER: + { + if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) + pSource->MonsterWhisper(iTextEntry, pTarget->GetGUID()); + else + error_log("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry); + } + break; + case CHAT_TYPE_BOSS_WHISPER: + { + if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) + pSource->MonsterWhisper(iTextEntry, pTarget->GetGUID(), true); + else + error_log("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry); + } + break; + case CHAT_TYPE_ZONE_YELL: + pSource->MonsterYellToZone(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0); + break; + } +} + +void Script::RegisterSelf() +{ + // try to find scripts which try to use another script's allocated memory + // that means didn't allocate memory for script + for (uint16 i = 0; i < MAX_SCRIPTS; ++i) + { + // somebody forgot to allocate memory for a script by a method like this: newscript = new Script + if (m_scripts[i] == this) + { + error_log("ScriptName: '%s' - Forgot to allocate memory, so this script and/or the script before that can't work.", Name.c_str()); + // don't register it + // and don't delete it because its memory is used for another script + return; + } + } + + int id = GetScriptId(Name.c_str()); + if (id) + { + // try to find the script in assigned scripts + bool IsExist = false; + for (uint16 i = 0; i < MAX_SCRIPTS; ++i) + { + if (m_scripts[i]) + { + // if the assigned script's name and the new script's name is the same + if (m_scripts[i]->Name == Name) + { + IsExist = true; + break; + } + } + } + + // if the script doesn't assigned -> assign it! + if (!IsExist) + { + m_scripts[id] = this; + ++num_sc_scripts; + } + // if the script is already assigned -> delete it! + else + { + // TODO: write a better error message than this one :) + error_log("ScriptName: '%s' already assigned with the same ScriptName, so the script can't work.", Name.c_str()); + delete this; + } + } + else + { + if (Name.find("example") == std::string::npos) + error_db_log("TrinityScript: RegisterSelf, but script named %s does not have ScriptName assigned in database.",(this)->Name.c_str()); + delete this; + } +} + +void ScriptMgr::OnLogin(Player *pPlayer) +{ + Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; + if (!tmpscript || !tmpscript->pOnLogin) return; + tmpscript->pOnLogin(pPlayer); +} + +void ScriptMgr::OnLogout(Player *pPlayer) +{ + Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; + if (!tmpscript || !tmpscript->pOnLogout) return; + tmpscript->pOnLogout(pPlayer); +} + +void ScriptMgr::OnPVPKill(Player *killer, Player *killed) +{ + Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; + if (!tmpscript || !tmpscript->pOnPVPKill) return; + tmpscript->pOnPVPKill(killer, killed); +} + +bool ScriptMgr::OnSpellCast (Unit *pUnitTarget, Item *pItemTarget, GameObject *pGoTarget, uint32 i, SpellEntry const *spell) +{ + Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; + if (!tmpscript || !tmpscript->pOnSpellCast) return true; + return tmpscript->pOnSpellCast(pUnitTarget,pItemTarget,pGoTarget,i,spell); +} + +uint32 ScriptMgr::OnGetXP(Player *pPlayer, uint32 amount) +{ + Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; + if (!tmpscript || !tmpscript->pOnGetXP) return amount; + return tmpscript->pOnGetXP(pPlayer,amount); +} + +uint32 ScriptMgr::OnGetMoney(Player *pPlayer, int32 amount) +{ + Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; + if (!tmpscript || !tmpscript->pOnGetMoney) return amount; + return tmpscript->pOnGetMoney(pPlayer,amount); +} + +bool ScriptMgr::OnPlayerChat(Player *pPlayer, const char *text) +{ + Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; + if (!tmpscript || !tmpscript->pOnPlayerChat) return true; + return tmpscript->pOnPlayerChat(pPlayer,text); +} + +void ScriptMgr::OnServerStartup() +{ + Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; + if (!tmpscript || !tmpscript->pOnServerStartup) return; + tmpscript->pOnServerStartup(); +} + +void ScriptMgr::OnServerShutdown() +{ + Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; + if (!tmpscript || !tmpscript->pOnServerShutdown) return; + tmpscript->pOnServerShutdown(); +} + +void ScriptMgr::OnAreaChange(Player *pPlayer, AreaTableEntry const *pArea) +{ + Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; + if (!tmpscript || !tmpscript->pOnAreaChange) return; + tmpscript->pOnAreaChange(pPlayer, pArea); +} + +bool ScriptMgr::OnItemClick (Player *pPlayer, Item *pItem) +{ + Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; + if (!tmpscript || !tmpscript->pOnItemClick) return true; + return tmpscript->pOnItemClick(pPlayer,pItem); +} + +bool ScriptMgr::OnItemOpen (Player *pPlayer, Item *pItem) +{ + Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; + if (!tmpscript || !tmpscript->pOnItemOpen) return true; + return tmpscript->pOnItemOpen(pPlayer,pItem); +} + +bool ScriptMgr::OnGoClick (Player *pPlayer, GameObject *pGameObject) +{ + Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; + if (!tmpscript || !tmpscript->pOnGoClick) return true; + return tmpscript->pOnGoClick(pPlayer,pGameObject); +} + +void ScriptMgr::OnCreatureKill (Player *pPlayer, Creature *pCreature) +{ + Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; + if (!tmpscript || !tmpscript->pOnCreatureKill) return; + tmpscript->pOnCreatureKill(pPlayer,pCreature); +} + +char const* ScriptMgr::ScriptsVersion() +{ + return "Integrated Trinity Scripts"; +} + +bool ScriptMgr::GossipHello (Player * pPlayer, Creature* pCreature) +{ + Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!tmpscript || !tmpscript->pGossipHello) return false; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pGossipHello(pPlayer, pCreature); +} + +bool ScriptMgr::GossipSelect(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + debug_log("TSCR: Gossip selection, sender: %d, action: %d", uiSender, uiAction); + + Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!tmpscript || !tmpscript->pGossipSelect) return false; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pGossipSelect(pPlayer, pCreature, uiSender, uiAction); +} + +bool ScriptMgr::GossipSelectWithCode(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction, const char* sCode) +{ + debug_log("TSCR: Gossip selection with code, sender: %d, action: %d", uiSender, uiAction); + + Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!tmpscript || !tmpscript->pGossipSelectWithCode) return false; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pGossipSelectWithCode(pPlayer, pCreature, uiSender, uiAction, sCode); +} + +bool ScriptMgr::GOSelect(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction) +{ + if (!pGO) + return false; + debug_log("TSCR: Gossip selection, sender: %d, action: %d", uiSender, uiAction); + + Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; + if (!tmpscript || !tmpscript->pGOSelect) return false; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pGOSelect(pPlayer, pGO, uiSender, uiAction); +} + +bool ScriptMgr::GOSelectWithCode(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction, const char* sCode) +{ + if (!pGO) + return false; + debug_log("TSCR: Gossip selection, sender: %d, action: %d",uiSender, uiAction); + + Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; + if (!tmpscript || !tmpscript->pGOSelectWithCode) return false; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pGOSelectWithCode(pPlayer, pGO, uiSender ,uiAction, sCode); +} + +bool ScriptMgr::QuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +{ + Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!tmpscript || !tmpscript->pQuestAccept) return false; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pQuestAccept(pPlayer, pCreature, pQuest); +} + +bool ScriptMgr::QuestSelect(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +{ + Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!tmpscript || !tmpscript->pQuestSelect) return false; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pQuestSelect(pPlayer, pCreature, pQuest); +} + +bool ScriptMgr::QuestComplete(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +{ + Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!tmpscript || !tmpscript->pQuestComplete) return false; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pQuestComplete(pPlayer, pCreature, pQuest); +} + +bool ScriptMgr::ChooseReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt) +{ + Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!tmpscript || !tmpscript->pChooseReward) return false; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pChooseReward(pPlayer, pCreature, pQuest, opt); +} + +uint32 ScriptMgr::NPCDialogStatus(Player* pPlayer, Creature* pCreature) +{ + Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!tmpscript || !tmpscript->pNPCDialogStatus) return 100; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pNPCDialogStatus(pPlayer, pCreature); +} + +uint32 ScriptMgr::GODialogStatus(Player* pPlayer, GameObject* pGO) +{ + Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; + if (!tmpscript || !tmpscript->pGODialogStatus) return 100; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pGODialogStatus(pPlayer, pGO); +} + +bool ScriptMgr::ItemHello(Player* pPlayer, Item* pItem, Quest const* pQuest) +{ + Script *tmpscript = m_scripts[pItem->GetProto()->ScriptId]; + if (!tmpscript || !tmpscript->pItemHello) return false; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pItemHello(pPlayer, pItem, pQuest); +} + +bool ScriptMgr::ItemQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest) +{ + Script *tmpscript = m_scripts[pItem->GetProto()->ScriptId]; + if (!tmpscript || !tmpscript->pItemQuestAccept) return false; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pItemQuestAccept(pPlayer, pItem, pQuest); +} + +bool ScriptMgr::GOHello(Player* pPlayer, GameObject* pGO) +{ + Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; + if (!tmpscript || !tmpscript->pGOHello) return false; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pGOHello(pPlayer, pGO); +} + +bool ScriptMgr::GOQuestAccept(Player* pPlayer, GameObject* pGO, Quest const* pQuest) +{ + Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; + if (!tmpscript || !tmpscript->pGOQuestAccept) return false; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pGOQuestAccept(pPlayer, pGO, pQuest); +} + +bool ScriptMgr::GOChooseReward(Player* pPlayer, GameObject* pGO, Quest const* pQuest, uint32 opt) +{ + Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; + if (!tmpscript || !tmpscript->pGOChooseReward) return false; + + pPlayer->PlayerTalkClass->ClearMenus(); + return tmpscript->pGOChooseReward(pPlayer, pGO, pQuest, opt); +} + +void ScriptMgr::GODestroyed(Player* pPlayer, GameObject* pGO, uint32 destroyedEvent) +{ + Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; + if (!tmpscript) return; + tmpscript->pGODestroyed(pPlayer, pGO, destroyedEvent); +} + +bool ScriptMgr::AreaTrigger(Player* pPlayer, AreaTriggerEntry const* atEntry) +{ + Script *tmpscript = m_scripts[GetAreaTriggerScriptId(atEntry->id)]; + if (!tmpscript || !tmpscript->pAreaTrigger) return false; + + return tmpscript->pAreaTrigger(pPlayer, atEntry); +} + +CreatureAI* ScriptMgr::GetAI(Creature* pCreature) +{ + Script *tmpscript = m_scripts[pCreature->GetScriptId()]; + if (!tmpscript || !tmpscript->GetAI) return NULL; + + return tmpscript->GetAI(pCreature); +} + +bool ScriptMgr::ItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) +{ + Script *tmpscript = m_scripts[pItem->GetProto()->ScriptId]; + if (!tmpscript || !tmpscript->pItemUse) return false; + + return tmpscript->pItemUse(pPlayer, pItem, targets); +} + +bool ScriptMgr::ItemExpire(Player* pPlayer, ItemPrototype const * pItemProto) +{ + Script *tmpscript = m_scripts[pItemProto->ScriptId]; + if (!tmpscript || !tmpscript->pItemExpire) return true; + + return tmpscript->pItemExpire(pPlayer, pItemProto); +} + +bool ScriptMgr::EffectDummyCreature(Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget) +{ + Script *tmpscript = m_scripts[crTarget->GetScriptId()]; + + if (!tmpscript || !tmpscript->pEffectDummyCreature) return false; + + return tmpscript->pEffectDummyCreature(caster, spellId, effIndex, crTarget); +} + +bool ScriptMgr::EffectDummyGameObj(Unit *caster, uint32 spellId, uint32 effIndex, GameObject *gameObjTarget) +{ + Script *tmpscript = m_scripts[gameObjTarget->GetGOInfo()->ScriptId]; + + if (!tmpscript || !tmpscript->pEffectDummyGameObj) return false; + + return tmpscript->pEffectDummyGameObj(caster, spellId, effIndex, gameObjTarget); +} + +bool ScriptMgr::EffectDummyItem(Unit *caster, uint32 spellId, uint32 effIndex, Item *itemTarget) +{ + Script *tmpscript = m_scripts[itemTarget->GetProto()->ScriptId]; + + if (!tmpscript || !tmpscript->pEffectDummyItem) return false; + + return tmpscript->pEffectDummyItem(caster, spellId, effIndex, itemTarget); +} + +InstanceData* ScriptMgr::CreateInstanceData(Map *map) +{ + if (!map->IsDungeon()) return NULL; + + Script *tmpscript = m_scripts[((InstanceMap*)map)->GetScriptId()]; + if (!tmpscript || !tmpscript->GetInstanceData) return NULL; + + return tmpscript->GetInstanceData(map); +} + diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h new file mode 100644 index 00000000000..ed7200d5786 --- /dev/null +++ b/src/server/game/Scripting/ScriptMgr.h @@ -0,0 +1,163 @@ +/* Copyright (C) 2008-2010 Trinity + * + * Thanks to the original authors: ScriptDev2 + * + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef SC_SCRIPTMGR_H +#define SC_SCRIPTMGR_H + +#include "Common.h" +#include "Platform/CompilerDefs.h" +#include "DBCStructure.h" +#include "Config/ConfigEnv.h" + +class Player; +class Creature; +class CreatureAI; +class InstanceData; +class Quest; +class Item; +class GameObject; +class SpellCastTargets; +class Map; +class Unit; +class WorldObject; +struct ItemPrototype; + +#define MAX_SCRIPTS 5000 //72 bytes each (approx 351kb) +#define VISIBLE_RANGE (166.0f) //MAX visible range (size of grid) +#define DEFAULT_TEXT "" + +struct Script +{ + Script() : + pOnLogin(NULL), pOnLogout(NULL), pOnPVPKill(NULL), pOnSpellCast(NULL), pOnGetXP(NULL), + pOnGetMoney(NULL), pOnPlayerChat(NULL), pOnServerStartup(NULL), pOnServerShutdown(NULL), + pOnAreaChange(NULL), pOnItemClick(NULL), pOnItemOpen(NULL), pOnGoClick(NULL), pOnCreatureKill(NULL), + pGossipHello(NULL), pQuestAccept(NULL), pGossipSelect(NULL), pGossipSelectWithCode(NULL), + pGOSelect(NULL), pGOSelectWithCode(NULL), + pQuestSelect(NULL), pQuestComplete(NULL), pNPCDialogStatus(NULL), pGODialogStatus(NULL), + pChooseReward(NULL), pGODestroyed(NULL), pItemHello(NULL), pGOHello(NULL), pAreaTrigger(NULL), pItemQuestAccept(NULL), + pGOQuestAccept(NULL), pGOChooseReward(NULL),pItemUse(NULL), pItemExpire(NULL), + pEffectDummyCreature(NULL), pEffectDummyGameObj(NULL), pEffectDummyItem(NULL), + GetAI(NULL), GetInstanceData(NULL) + {} + + std::string Name; + + //Methods to be scripted + void (*pOnLogin)(Player*); + void (*pOnLogout)(Player*); + void (*pOnPVPKill)(Player*, Player*); + bool (*pOnSpellCast)(Unit*, Item*, GameObject*, uint32, SpellEntry const*); + uint32 (*pOnGetXP)(Player*, uint32); + int32 (*pOnGetMoney)(Player*, int32); + bool (*pOnPlayerChat)(Player*, const char*); + void (*pOnServerStartup)(); + void (*pOnServerShutdown)(); + void (*pOnAreaChange)(Player*, AreaTableEntry const*); + bool (*pOnItemClick)(Player*, Item*); + bool (*pOnItemOpen)(Player*, Item*); + bool (*pOnGoClick)(Player*, GameObject*); + void (*pOnCreatureKill)(Player*, Creature*); + bool (*pGossipHello)(Player*, Creature*); + bool (*pQuestAccept)(Player*, Creature*, Quest const*); + bool (*pGossipSelect)(Player*, Creature*, uint32 , uint32); + bool (*pGossipSelectWithCode)(Player*, Creature*, uint32 , uint32 , const char*); + bool (*pGOSelect)(Player*, GameObject*, uint32 , uint32); + bool (*pGOSelectWithCode)(Player*, GameObject*, uint32 , uint32 , const char*); + bool (*pQuestSelect)(Player*, Creature*, Quest const*); + bool (*pQuestComplete)(Player*, Creature*, Quest const*); + uint32 (*pNPCDialogStatus)(Player*, Creature*); + uint32 (*pGODialogStatus)(Player*, GameObject * _GO); + bool (*pChooseReward)(Player*, Creature*, Quest const*, uint32); + bool (*pItemHello)(Player*, Item*, Quest const*); + bool (*pGOHello)(Player*, GameObject*); + bool (*pAreaTrigger)(Player*, AreaTriggerEntry const*); + bool (*pItemQuestAccept)(Player*, Item *, Quest const*); + bool (*pGOQuestAccept)(Player*, GameObject*, Quest const*); + bool (*pGOChooseReward)(Player*, GameObject*, Quest const*, uint32); + void (*pGODestroyed)(Player*, GameObject*, uint32); + bool (*pItemUse)(Player*, Item*, SpellCastTargets const&); + bool (*pItemExpire)(Player*, ItemPrototype const *); + bool (*pEffectDummyCreature)(Unit*, uint32, uint32, Creature*); + bool (*pEffectDummyGameObj)(Unit*, uint32, uint32, GameObject*); + bool (*pEffectDummyItem)(Unit*, uint32, uint32, Item*); + + CreatureAI* (*GetAI)(Creature*); + InstanceData* (*GetInstanceData)(Map*); + + void RegisterSelf(); +}; + +class ScriptMgr +{ + public: + ScriptMgr(); + ~ScriptMgr(); + + void ScriptsInit(); + void LoadDatabase(); + char const* ScriptsVersion(); + + //event handlers + void OnLogin(Player *pPlayer); + void OnLogout(Player *pPlayer); + void OnPVPKill(Player *killer, Player *killed); + bool OnSpellCast (Unit *pUnitTarget, Item *pItemTarget, GameObject *pGoTarget, uint32 i, SpellEntry const *spell); + uint32 OnGetXP(Player *pPlayer, uint32 amount); + uint32 OnGetMoney(Player *pPlayer, int32 amount); + bool OnPlayerChat(Player *pPlayer, const char *text); + void OnServerStartup(); + void OnServerShutdown(); + void OnAreaChange(Player *pPlayer, AreaTableEntry const *pArea); + bool OnItemClick (Player *pPlayer, Item *pItem); + bool OnItemOpen (Player *pPlayer, Item *pItem); + bool OnGoClick (Player *pPlayer, GameObject *pGameObject); + void OnCreatureKill (Player *pPlayer, Creature *pCreature); + bool GossipHello (Player * pPlayer, Creature* pCreature); + bool GossipSelect(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction); + bool GossipSelectWithCode(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction, const char* sCode); + bool GOSelect(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction); + bool GOSelectWithCode(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction, const char* sCode); + bool QuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest); + bool QuestSelect(Player* pPlayer, Creature* pCreature, Quest const* pQuest); + bool QuestComplete(Player* pPlayer, Creature* pCreature, Quest const* pQuest); + bool ChooseReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt); + uint32 NPCDialogStatus(Player* pPlayer, Creature* pCreature); + uint32 GODialogStatus(Player* pPlayer, GameObject* pGO); + bool ItemHello(Player* pPlayer, Item* pItem, Quest const* pQuest); + bool ItemQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest); + bool GOHello(Player* pPlayer, GameObject* pGO); + bool GOQuestAccept(Player* pPlayer, GameObject* pGO, Quest const* pQuest); + bool GOChooseReward(Player* pPlayer, GameObject* pGO, Quest const* pQuest, uint32 opt); + void GODestroyed(Player* pPlayer, GameObject* pGO, uint32 destroyedEvent); + bool AreaTrigger(Player* pPlayer,AreaTriggerEntry const* atEntry); + CreatureAI* GetAI(Creature* pCreature); + bool ItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets); + bool ItemExpire(Player* pPlayer, ItemPrototype const * pItemProto); + bool EffectDummyCreature(Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget); + bool EffectDummyGameObj(Unit *caster, uint32 spellId, uint32 effIndex, GameObject *gameObjTarget); + bool EffectDummyItem(Unit *caster, uint32 spellId, uint32 effIndex, Item *itemTarget); + InstanceData* CreateInstanceData(Map *map); +}; + +//Config file accessors +//std::string GetConfigValueStr(char const* option); +//int32 GetConfigValueInt32(char const* option); +//float GetConfigValueFloat(char const* option); + +//Generic scripting text function +void DoScriptText(int32 textEntry, WorldObject* pSource, Unit *pTarget = NULL); + +#if COMPILER == COMPILER_GNU +#define FUNC_PTR(name,callconvention,returntype,parameters) typedef returntype(*name)parameters __attribute__ ((callconvention)); +#else +#define FUNC_PTR(name, callconvention, returntype, parameters) typedef returntype(callconvention *name)parameters; +#endif + +#define sScriptMgr Trinity::Singleton::Instance() +#endif + diff --git a/src/server/game/Scripting/ScriptSystem.cpp b/src/server/game/Scripting/ScriptSystem.cpp new file mode 100644 index 00000000000..0037b100412 --- /dev/null +++ b/src/server/game/Scripting/ScriptSystem.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2008-2010 Trinity + * + * Thanks to the original authors: MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptedPch.h" +#include "ScriptSystem.h" +#include "ProgressBar.h" +#include "ObjectMgr.h" +#include "Database/DatabaseEnv.h" + +SystemMgr::SystemMgr() +{ +} + +SystemMgr& SystemMgr::Instance() +{ + static SystemMgr pSysMgr; + return pSysMgr; +} + +void SystemMgr::LoadVersion() +{ + //Get Version information + QueryResult_AutoPtr Result = WorldDatabase.Query("SELECT script_version FROM version LIMIT 1"); + + if (Result) + { + Field* pFields = Result->Fetch(); + + outstring_log("TSCR: Database version is: %s", pFields[0].GetString()); + outstring_log(""); + } + else + { + error_log("TSCR: Missing `version`.`script_version` information."); + outstring_log(""); + } +} + +void SystemMgr::LoadScriptTexts() +{ + outstring_log("TSCR: Loading Script Texts..."); + LoadTrinityStrings(WorldDatabase,"script_texts",TEXT_SOURCE_RANGE,1+(TEXT_SOURCE_RANGE*2)); + + QueryResult_AutoPtr Result = WorldDatabase.Query("SELECT entry, sound, type, language, emote FROM script_texts"); + + outstring_log("TSCR: Loading Script Texts additional data..."); + + if (Result) + { + barGoLink bar(Result->GetRowCount()); + uint32 uiCount = 0; + + do + { + bar.step(); + Field* pFields = Result->Fetch(); + StringTextData pTemp; + + int32 iId = pFields[0].GetInt32(); + pTemp.uiSoundId = pFields[1].GetUInt32(); + pTemp.uiType = pFields[2].GetUInt32(); + pTemp.uiLanguage = pFields[3].GetUInt32(); + pTemp.uiEmote = pFields[4].GetUInt32(); + + if (iId >= 0) + { + error_db_log("TSCR: Entry %i in table `script_texts` is not a negative value.", iId); + continue; + } + + if (iId > TEXT_SOURCE_RANGE || iId <= TEXT_SOURCE_RANGE*2) + { + error_db_log("TSCR: Entry %i in table `script_texts` is out of accepted entry range for table.", iId); + continue; + } + + if (pTemp.uiSoundId) + { + if (!GetSoundEntriesStore()->LookupEntry(pTemp.uiSoundId)) + error_db_log("TSCR: Entry %i in table `script_texts` has soundId %u but sound does not exist.", iId, pTemp.uiSoundId); + } + + if (!GetLanguageDescByID(pTemp.uiLanguage)) + error_db_log("TSCR: Entry %i in table `script_texts` using Language %u but Language does not exist.", iId, pTemp.uiLanguage); + + if (pTemp.uiType > CHAT_TYPE_ZONE_YELL) + error_db_log("TSCR: Entry %i in table `script_texts` has Type %u but this Chat Type does not exist.", iId, pTemp.uiType); + + m_mTextDataMap[iId] = pTemp; + ++uiCount; + } while (Result->NextRow()); + + outstring_log(""); + outstring_log(">> Loaded %u additional Script Texts data.", uiCount); + } + else + { + barGoLink bar(1); + bar.step(); + outstring_log(""); + outstring_log(">> Loaded 0 additional Script Texts data. DB table `script_texts` is empty."); + } +} + +void SystemMgr::LoadScriptTextsCustom() +{ + outstring_log("TSCR: Loading Custom Texts..."); + LoadTrinityStrings(WorldDatabase,"custom_texts",TEXT_SOURCE_RANGE*2,1+(TEXT_SOURCE_RANGE*3)); + + QueryResult_AutoPtr Result = WorldDatabase.Query("SELECT entry, sound, type, language, emote FROM custom_texts"); + + outstring_log("TSCR: Loading Custom Texts additional data..."); + + if (Result) + { + barGoLink bar(Result->GetRowCount()); + uint32 uiCount = 0; + + do + { + bar.step(); + Field* pFields = Result->Fetch(); + StringTextData pTemp; + + int32 iId = pFields[0].GetInt32(); + pTemp.uiSoundId = pFields[1].GetUInt32(); + pTemp.uiType = pFields[2].GetUInt32(); + pTemp.uiLanguage = pFields[3].GetUInt32(); + pTemp.uiEmote = pFields[4].GetUInt32(); + + if (iId >= 0) + { + error_db_log("TSCR: Entry %i in table `custom_texts` is not a negative value.", iId); + continue; + } + + if (iId > TEXT_SOURCE_RANGE*2 || iId <= TEXT_SOURCE_RANGE*3) + { + error_db_log("TSCR: Entry %i in table `custom_texts` is out of accepted entry range for table.", iId); + continue; + } + + if (pTemp.uiSoundId) + { + if (!GetSoundEntriesStore()->LookupEntry(pTemp.uiSoundId)) + error_db_log("TSCR: Entry %i in table `custom_texts` has soundId %u but sound does not exist.", iId, pTemp.uiSoundId); + } + + if (!GetLanguageDescByID(pTemp.uiLanguage)) + error_db_log("TSCR: Entry %i in table `custom_texts` using Language %u but Language does not exist.", iId, pTemp.uiLanguage); + + if (pTemp.uiType > CHAT_TYPE_ZONE_YELL) + error_db_log("TSCR: Entry %i in table `custom_texts` has Type %u but this Chat Type does not exist.", iId, pTemp.uiType); + + m_mTextDataMap[iId] = pTemp; + ++uiCount; + } while (Result->NextRow()); + + outstring_log(""); + outstring_log(">> Loaded %u additional Custom Texts data.", uiCount); + } + else + { + barGoLink bar(1); + bar.step(); + outstring_log(""); + outstring_log(">> Loaded 0 additional Custom Texts data. DB table `custom_texts` is empty."); + } +} + +void SystemMgr::LoadScriptWaypoints() +{ + // Drop Existing Waypoint list + m_mPointMoveMap.clear(); + + uint64 uiCreatureCount = 0; + + // Load Waypoints + QueryResult_AutoPtr Result = WorldDatabase.Query("SELECT COUNT(entry) FROM script_waypoint GROUP BY entry"); + if (Result) + uiCreatureCount = Result->GetRowCount(); + + outstring_log("TSCR: Loading Script Waypoints for %u creature(s)...", uiCreatureCount); + + Result = WorldDatabase.Query("SELECT entry, pointid, location_x, location_y, location_z, waittime FROM script_waypoint ORDER BY pointid"); + + if (Result) + { + barGoLink bar(Result->GetRowCount()); + uint32 uiNodeCount = 0; + + do + { + bar.step(); + Field* pFields = Result->Fetch(); + ScriptPointMove pTemp; + + pTemp.uiCreatureEntry = pFields[0].GetUInt32(); + uint32 uiEntry = pTemp.uiCreatureEntry; + pTemp.uiPointId = pFields[1].GetUInt32(); + pTemp.fX = pFields[2].GetFloat(); + pTemp.fY = pFields[3].GetFloat(); + pTemp.fZ = pFields[4].GetFloat(); + pTemp.uiWaitTime = pFields[5].GetUInt32(); + + CreatureInfo const* pCInfo = GetCreatureTemplateStore(pTemp.uiCreatureEntry); + + if (!pCInfo) + { + error_db_log("TSCR: DB table script_waypoint has waypoint for non-existant creature entry %u", pTemp.uiCreatureEntry); + continue; + } + + if (!pCInfo->ScriptID) + error_db_log("TSCR: DB table script_waypoint has waypoint for creature entry %u, but creature does not have ScriptName defined and then useless.", pTemp.uiCreatureEntry); + + m_mPointMoveMap[uiEntry].push_back(pTemp); + ++uiNodeCount; + } while (Result->NextRow()); + + outstring_log(""); + outstring_log(">> Loaded %u Script Waypoint nodes.", uiNodeCount); + } + else + { + barGoLink bar(1); + bar.step(); + outstring_log(""); + outstring_log(">> Loaded 0 Script Waypoints. DB table `script_waypoint` is empty."); + } +} diff --git a/src/server/game/Scripting/ScriptSystem.h b/src/server/game/Scripting/ScriptSystem.h new file mode 100644 index 00000000000..f78cd2e64fa --- /dev/null +++ b/src/server/game/Scripting/ScriptSystem.h @@ -0,0 +1,100 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 +* This program is free software licensed under GPL version 2 +* Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef SC_SYSTEM_H +#define SC_SYSTEM_H + +#define TEXT_SOURCE_RANGE -1000000 //the amount of entries each text source has available + +//TODO: find better namings and definitions. +//N=Neutral, A=Alliance, H=Horde. +//NEUTRAL or FRIEND = Hostility to player surroundings (not a good definition) +//ACTIVE or PASSIVE = Hostility to environment surroundings. +enum eEscortFaction +{ + FACTION_ESCORT_A_NEUTRAL_PASSIVE = 10, + FACTION_ESCORT_H_NEUTRAL_PASSIVE = 33, + FACTION_ESCORT_N_NEUTRAL_PASSIVE = 113, + + FACTION_ESCORT_A_NEUTRAL_ACTIVE = 231, + FACTION_ESCORT_H_NEUTRAL_ACTIVE = 232, + FACTION_ESCORT_N_NEUTRAL_ACTIVE = 250, + + FACTION_ESCORT_N_FRIEND_PASSIVE = 290, + FACTION_ESCORT_N_FRIEND_ACTIVE = 495, + + FACTION_ESCORT_A_PASSIVE = 774, + FACTION_ESCORT_H_PASSIVE = 775, + + FACTION_ESCORT_N_ACTIVE = 1986, + FACTION_ESCORT_H_ACTIVE = 2046 +}; + +struct ScriptPointMove +{ + uint32 uiCreatureEntry; + uint32 uiPointId; + float fX; + float fY; + float fZ; + uint32 uiWaitTime; +}; + +struct StringTextData +{ + uint32 uiSoundId; + uint8 uiType; + uint32 uiLanguage; + uint32 uiEmote; +}; + +#define pSystemMgr SystemMgr::Instance() + +class SystemMgr +{ + public: + SystemMgr(); + ~SystemMgr() {} + + static SystemMgr& Instance(); + + //Maps and lists + typedef UNORDERED_MAP TextDataMap; + typedef UNORDERED_MAP > PointMoveMap; + + //Database + void LoadVersion(); + void LoadScriptTexts(); + void LoadScriptTextsCustom(); + void LoadScriptWaypoints(); + + //Retrive from storage + StringTextData const* GetTextData(int32 uiTextId) const + { + TextDataMap::const_iterator itr = m_mTextDataMap.find(uiTextId); + + if (itr == m_mTextDataMap.end()) + return NULL; + + return &itr->second; + } + + std::vector const &GetPointMoveList(uint32 uiCreatureEntry) const + { + static std::vector vEmpty; + + PointMoveMap::const_iterator itr = m_mPointMoveMap.find(uiCreatureEntry); + + if (itr == m_mPointMoveMap.end()) + return vEmpty; + + return itr->second; + } + + protected: + TextDataMap m_mTextDataMap; //additional data for text strings + PointMoveMap m_mPointMoveMap; //coordinates for waypoints +}; + +#endif diff --git a/src/server/game/Server/Protocol/Handlers/AddonHandler.cpp b/src/server/game/Server/Protocol/Handlers/AddonHandler.cpp new file mode 100644 index 00000000000..a9c8101d7b1 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/AddonHandler.cpp @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "zlib/zlib.h" + +#include "AddonHandler.h" +#include "Database/DatabaseEnv.h" +#include "Policies/SingletonImp.h" +#include "Opcodes.h" + +#include "Log.h" + +INSTANTIATE_SINGLETON_1( AddonHandler ); + +AddonHandler::AddonHandler() +{ +} + +AddonHandler::~AddonHandler() +{ +} + +bool AddonHandler::BuildAddonPacket(WorldPacket *Source, WorldPacket *Target) +{ + ByteBuffer AddOnPacked; + uLongf AddonRealSize; + uint32 CurrentPosition; + uint32 TempValue; + + unsigned char tdata[256] = + { + 0xC3, 0x5B, 0x50, 0x84, 0xB9, 0x3E, 0x32, 0x42, 0x8C, 0xD0, 0xC7, 0x48, 0xFA, 0x0E, 0x5D, 0x54, + 0x5A, 0xA3, 0x0E, 0x14, 0xBA, 0x9E, 0x0D, 0xB9, 0x5D, 0x8B, 0xEE, 0xB6, 0x84, 0x93, 0x45, 0x75, + 0xFF, 0x31, 0xFE, 0x2F, 0x64, 0x3F, 0x3D, 0x6D, 0x07, 0xD9, 0x44, 0x9B, 0x40, 0x85, 0x59, 0x34, + 0x4E, 0x10, 0xE1, 0xE7, 0x43, 0x69, 0xEF, 0x7C, 0x16, 0xFC, 0xB4, 0xED, 0x1B, 0x95, 0x28, 0xA8, + 0x23, 0x76, 0x51, 0x31, 0x57, 0x30, 0x2B, 0x79, 0x08, 0x50, 0x10, 0x1C, 0x4A, 0x1A, 0x2C, 0xC8, + 0x8B, 0x8F, 0x05, 0x2D, 0x22, 0x3D, 0xDB, 0x5A, 0x24, 0x7A, 0x0F, 0x13, 0x50, 0x37, 0x8F, 0x5A, + 0xCC, 0x9E, 0x04, 0x44, 0x0E, 0x87, 0x01, 0xD4, 0xA3, 0x15, 0x94, 0x16, 0x34, 0xC6, 0xC2, 0xC3, + 0xFB, 0x49, 0xFE, 0xE1, 0xF9, 0xDA, 0x8C, 0x50, 0x3C, 0xBE, 0x2C, 0xBB, 0x57, 0xED, 0x46, 0xB9, + 0xAD, 0x8B, 0xC6, 0xDF, 0x0E, 0xD6, 0x0F, 0xBE, 0x80, 0xB3, 0x8B, 0x1E, 0x77, 0xCF, 0xAD, 0x22, + 0xCF, 0xB7, 0x4B, 0xCF, 0xFB, 0xF0, 0x6B, 0x11, 0x45, 0x2D, 0x7A, 0x81, 0x18, 0xF2, 0x92, 0x7E, + 0x98, 0x56, 0x5D, 0x5E, 0x69, 0x72, 0x0A, 0x0D, 0x03, 0x0A, 0x85, 0xA2, 0x85, 0x9C, 0xCB, 0xFB, + 0x56, 0x6E, 0x8F, 0x44, 0xBB, 0x8F, 0x02, 0x22, 0x68, 0x63, 0x97, 0xBC, 0x85, 0xBA, 0xA8, 0xF7, + 0xB5, 0x40, 0x68, 0x3C, 0x77, 0x86, 0x6F, 0x4B, 0xD7, 0x88, 0xCA, 0x8A, 0xD7, 0xCE, 0x36, 0xF0, + 0x45, 0x6E, 0xD5, 0x64, 0x79, 0x0F, 0x17, 0xFC, 0x64, 0xDD, 0x10, 0x6F, 0xF3, 0xF5, 0xE0, 0xA6, + 0xC3, 0xFB, 0x1B, 0x8C, 0x29, 0xEF, 0x8E, 0xE5, 0x34, 0xCB, 0xD1, 0x2A, 0xCE, 0x79, 0xC3, 0x9A, + 0x0D, 0x36, 0xEA, 0x01, 0xE0, 0xAA, 0x91, 0x20, 0x54, 0xF0, 0x72, 0xD8, 0x1E, 0xC7, 0x89, 0xD2 + }; + + // broken addon packet, can't be received from real client + if (Source->rpos() + 4 > Source->size()) + return false; + + *Source >> TempValue; // get real size of the packed structure + + // empty addon packet, nothing process, can't be received from real client + if(!TempValue) + return false; + + AddonRealSize = TempValue; // temp value because ZLIB only excepts uLongf + + CurrentPosition = Source->rpos(); // get the position of the pointer in the structure + + AddOnPacked.resize(AddonRealSize); // resize target for zlib action + + if (!uncompress(const_cast(AddOnPacked.contents()), &AddonRealSize, const_cast((*Source).contents() + CurrentPosition), (*Source).size() - CurrentPosition)!= Z_OK) + { + Target->Initialize(SMSG_ADDON_INFO); + + uint32 addonsCount; + AddOnPacked >> addonsCount; // addons count? + + for(uint32 i = 0; i < addonsCount; ++i) + { + std::string addonName; + uint8 enabled; + uint32 crc, unk2; + + // check next addon data format correctness + if(AddOnPacked.rpos()+1 > AddOnPacked.size()) + return false; + + AddOnPacked >> addonName; + + // recheck next addon data format correctness + if(AddOnPacked.rpos()+1+4+4 > AddOnPacked.size()) + return false; + + AddOnPacked >> enabled >> crc >> unk2; + + sLog.outDebug("ADDON: Name: %s, Enabled: 0x%x, CRC: 0x%x, Unknown2: 0x%x", addonName.c_str(), enabled, crc, unk2); + + uint8 state = (enabled ? 2 : 1); + *Target << uint8(state); + + uint8 unk1 = (enabled ? 1 : 0); + *Target << uint8(unk1); + if (unk1) + { + uint8 unk2 = (crc != 0x4c1c776d); // If addon is Standard addon CRC + *Target << uint8(unk2); + if (unk2) + Target->append(tdata, sizeof(tdata)); + + *Target << uint32(0); + } + + uint8 unk3 = (enabled ? 0 : 1); + *Target << uint8(unk3); + if (unk3) + { + // String, 256 (null terminated?) + *Target << uint8(0); + } + } + + uint32 unk4; + AddOnPacked >> unk4; + + uint32 count = 0; + *Target << uint32(count); + /*for(uint32 i = 0; i < count; ++i) + { + uint32 + string (16 bytes) + string (16 bytes) + uint32 + }*/ + + if(AddOnPacked.rpos() != AddOnPacked.size()) + sLog.outDebug("packet under read!"); + } + else + { + sLog.outError("Addon packet uncompress error :("); + return false; + } + return true; +} + +/* Code use in 1.10.2 when client not ignore ban state sended for addons. Saved for reference if client switch to use server ban state information +void AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target, uint32 Packetoffset) +{ + ByteBuffer AddOnPacked; + uLongf AddonRealSize; + uint32 CurrentPosition; + uint32 TempValue; + + *Source >> TempValue; //get real size of the packed structure + + AddonRealSize = TempValue; //temp value becouse ZLIB only excepts uLongf + + CurrentPosition = Source->rpos(); //get the position of the pointer in the structure + + AddOnPacked.resize(AddonRealSize); //resize target for zlib action + + if (!uncompress((uint8*)AddOnPacked.contents(), &AddonRealSize, (uint8*)(*Source).contents() + CurrentPosition, (*Source).size() - CurrentPosition)!= Z_OK) + { + bool* AddonAllowed = new bool; //handle addon check and enable-ing + + uint32 Unknown1; + uint8 Unknown0; + + AddOnPacked >> Unknown0; + AddOnPacked >> Unknown1; + + Target->Initialize(SMSG_ADDON_INFO); + + uint32 i = 5; //offset for addon extraction + while(i != AddOnPacked.size()) + { + std::string AddonNames; + AddOns* Addonstr = new AddOns; + uint8 unk6; + uint64 CRCCHECK; + AddOnPacked >> AddonNames >> CRCCHECK >> unk6; + + //sLog.outDebug("ADDON: Name:%s CRC:%x Unknown:%x",AddonNames.c_str(), CRCCHECK,unk6); + + Addonstr->Name = AddonNames; + Addonstr->CRC = CRCCHECK; + + //if not allowed but unknown added to list + if (GetAddonStatus(Addonstr, AddonAllowed)) // If addon is new + { + Addonstr->Enabled = m_Addon_Default; // by default new addons are set from Config file + *AddonAllowed = m_Addon_Default; // Set addon allowed on default value + _AddAddon(Addonstr); + sLog.outDetail("Found new Addon, Name:%s CRC:%x Unknown:%x",AddonNames.c_str(), CRCCHECK, unk6); + } + + if (CRCCHECK == 0x4C1C776D01LL) //If addon is Standard addon CRC + { + //value's standard Addons + *Target << uint8(0) << uint8(2) << uint8(1) << uint8(0) << uint32(0); + } + else if (*AddonAllowed) //if addon is Custom addons + //value's enable addon + *Target << uint8(0x00) << uint8(0x01) << uint8(0x00) << uint8(0x01); + else + //value's disable addom + *Target << uint8(0x00) << uint8(0x0) << uint8(0x00) << uint8(0x0); + + i += AddonNames.size() + 10; + } + *Target << uint8(0x0); + + //delete mem allocation + delete AddonAllowed; + } + else + { + //handle uncompress error + } +} +*/ + diff --git a/src/server/game/Server/Protocol/Handlers/AddonHandler.h b/src/server/game/Server/Protocol/Handlers/AddonHandler.h new file mode 100644 index 00000000000..999785339bc --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/AddonHandler.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ADDONHANDLER_H +#define __ADDONHANDLER_H + +#include "Common.h" +#include "Config/ConfigEnv.h" +#include "Policies/Singleton.h" + +#include "WorldPacket.h" + +class AddonHandler +{ + public: + /* Construction */ + AddonHandler(); + ~AddonHandler(); + //built addon packet + bool BuildAddonPacket(WorldPacket* Source, WorldPacket* Target); +}; +#define sAddOnHandler Trinity::Singleton::Instance() +#endif + diff --git a/src/server/game/Server/Protocol/Handlers/ArenaTeamHandler.cpp b/src/server/game/Server/Protocol/Handlers/ArenaTeamHandler.cpp new file mode 100644 index 00000000000..3a9a14524f9 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/ArenaTeamHandler.cpp @@ -0,0 +1,391 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Player.h" +#include "World.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Database/DatabaseEnv.h" + +#include "ArenaTeam.h" +#include "Log.h" +#include "ObjectMgr.h" +#include "SocialMgr.h" + +void WorldSession::HandleInspectArenaTeamsOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("MSG_INSPECT_ARENA_TEAMS"); + + uint64 guid; + recv_data >> guid; + sLog.outDebug("Inspect Arena stats (GUID: %u TypeId: %u)", GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(guid))); + + if (Player *plr = objmgr.GetPlayer(guid)) + { + for (uint8 i = 0; i < MAX_ARENA_SLOT; ++i) + { + if (uint32 a_id = plr->GetArenaTeamId(i)) + { + if (ArenaTeam *at = objmgr.GetArenaTeamById(a_id)) + at->InspectStats(this, plr->GetGUID()); + } + } + } +} + +void WorldSession::HandleArenaTeamQueryOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_ARENA_TEAM_QUERY"); + + uint32 ArenaTeamId; + recv_data >> ArenaTeamId; + + if (ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId)) + { + arenateam->Query(this); + arenateam->Stats(this); + } +} + +void WorldSession::HandleArenaTeamRosterOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_ARENA_TEAM_ROSTER"); + + uint32 ArenaTeamId; // arena team id + recv_data >> ArenaTeamId; + + if (ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId)) + arenateam->Roster(this); +} + +void WorldSession::HandleArenaTeamInviteOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("CMSG_ARENA_TEAM_INVITE"); + + uint32 ArenaTeamId; // arena team id + std::string Invitedname; + + Player * player = NULL; + + recv_data >> ArenaTeamId >> Invitedname; + + if (!Invitedname.empty()) + { + if (!normalizePlayerName(Invitedname)) + return; + + player = ObjectAccessor::Instance().FindPlayerByName(Invitedname.c_str()); + } + + if (!player) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", Invitedname, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S); + return; + } + + if (player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", player->GetName(), ERR_ARENA_TEAM_TARGET_TOO_LOW_S); + return; + } + + ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId); + if (!arenateam) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM); + return; + } + + // OK result but not send invite + if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) + return; + + if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeam() != GetPlayer()->GetTeam()) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); + return; + } + + if (player->GetArenaTeamId(arenateam->GetSlot())) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", player->GetName(), ERR_ALREADY_IN_ARENA_TEAM_S); + return; + } + + if (player->GetArenaTeamIdInvited()) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S); + return; + } + + if (arenateam->GetMembersSize() >= arenateam->GetType() * 2) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, arenateam->GetName(), "", ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S); + return; + } + + sLog.outDebug("Player %s Invited %s to Join his ArenaTeam", GetPlayer()->GetName(), Invitedname.c_str()); + + player->SetArenaTeamIdInvited(arenateam->GetId()); + + WorldPacket data(SMSG_ARENA_TEAM_INVITE, (8+10)); + data << GetPlayer()->GetName(); + data << arenateam->GetName(); + player->GetSession()->SendPacket(&data); + + sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_INVITE"); +} + +void WorldSession::HandleArenaTeamAcceptOpcode(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("CMSG_ARENA_TEAM_ACCEPT"); // empty opcode + + ArenaTeam *at = objmgr.GetArenaTeamById(_player->GetArenaTeamIdInvited()); + if (!at) + return; + + if (_player->GetArenaTeamId(at->GetSlot())) + { + // already in arena team that size + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ALREADY_IN_ARENA_TEAM); + return; + } + + if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && _player->GetTeam() != objmgr.GetPlayerTeamByGUID(at->GetCaptain())) + { + // not let enemies sign petition + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_NOT_ALLIED); + return; + } + + if (!at->AddMember(_player->GetGUID())) + { + // arena team not found + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S,"","",ERR_ARENA_TEAM_INTERNAL); + return; + } + + // event + at->BroadcastEvent(ERR_ARENA_TEAM_JOIN_SS, _player->GetGUID(), 2, _player->GetName(), at->GetName(), ""); +} + +void WorldSession::HandleArenaTeamDeclineOpcode(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("CMSG_ARENA_TEAM_DECLINE"); // empty opcode + + _player->SetArenaTeamIdInvited(0); // no more invited +} + +void WorldSession::HandleArenaTeamLeaveOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("CMSG_ARENA_TEAM_LEAVE"); + + uint32 ArenaTeamId; // arena team id + recv_data >> ArenaTeamId; + + ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId); + if (!at) + return; + + if (_player->GetGUID() == at->GetCaptain() && at->GetMembersSize() > 1) + { + // check for correctness + SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S); + return; + } + + // arena team has only one member (=captain) + if (_player->GetGUID() == at->GetCaptain()) + { + at->Disband(this); + delete at; + return; + } + + at->DelMember(_player->GetGUID()); + + // event + at->BroadcastEvent(ERR_ARENA_TEAM_LEAVE_SS, _player->GetGUID(), 2, _player->GetName(), at->GetName(), ""); + + // send you are no longer member of team + SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, at->GetName(), "", 0); +} + +void WorldSession::HandleArenaTeamDisbandOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("CMSG_ARENA_TEAM_DISBAND"); + + uint32 ArenaTeamId; // arena team id + recv_data >> ArenaTeamId; + + if (ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId)) + { + if (at->GetCaptain() != _player->GetGUID()) + return; + + if (at->IsFighting()) + return; + + at->Disband(this); + delete at; + } +} + +void WorldSession::HandleArenaTeamRemoveOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("CMSG_ARENA_TEAM_REMOVE"); + + uint32 ArenaTeamId; + std::string name; + + recv_data >> ArenaTeamId; + recv_data >> name; + + ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId); + if (!at) // arena team not found + return; + + if (at->GetCaptain() != _player->GetGUID()) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS); + return; + } + + if (!normalizePlayerName(name)) + return; + + ArenaTeamMember* member = at->GetMember(name); + if (!member) // member not found + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", name, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S); + return; + } + + if (at->GetCaptain() == member->guid) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S); + return; + } + + at->DelMember(member->guid); + + // event + at->BroadcastEvent(ERR_ARENA_TEAM_REMOVE_SSS, 0, 3, name, at->GetName(), _player->GetName()); +} + +void WorldSession::HandleArenaTeamLeaderOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("CMSG_ARENA_TEAM_LEADER"); + + uint32 ArenaTeamId; + std::string name; + + recv_data >> ArenaTeamId; + recv_data >> name; + + ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId); + if (!at) // arena team not found + return; + + if (at->GetCaptain() != _player->GetGUID()) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS); + return; + } + + if (!normalizePlayerName(name)) + return; + + ArenaTeamMember* member = at->GetMember(name); + if (!member) // member not found + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", name, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S); + return; + } + + if (at->GetCaptain() == member->guid) // target player already captain + return; + + at->SetCaptain(member->guid); + + // event + at->BroadcastEvent(ERR_ARENA_TEAM_LEADER_CHANGED_SSS, 0, 3, _player->GetName(), name, at->GetName()); +} + +void WorldSession::SendArenaTeamCommandResult(uint32 team_action, const std::string& team, const std::string& player, uint32 error_id) +{ + WorldPacket data(SMSG_ARENA_TEAM_COMMAND_RESULT, 4+team.length()+1+player.length()+1+4); + data << uint32(team_action); + data << team; + data << player; + data << uint32(error_id); + SendPacket(&data); +} + +void WorldSession::SendNotInArenaTeamPacket(uint8 type) +{ + WorldPacket data(SMSG_ARENA_ERROR, 4+1); // 886 - You are not in a %uv%u arena team + uint32 unk = 0; + data << uint32(unk); // unk(0) + if (!unk) + data << uint8(type); // team type (2=2v2,3=3v3,5=5v5), can be used for custom types... + SendPacket(&data); +} + +/* ++ERR_ARENA_NO_TEAM_II "You are not in a %dv%d arena team" + ++ERR_ARENA_TEAM_CREATE_S "%s created. To disband, use /teamdisband [2v2, 3v3, 5v5]." ++ERR_ARENA_TEAM_INVITE_SS "You have invited %s to join %s" ++ERR_ARENA_TEAM_QUIT_S "You are no longer a member of %s" +ERR_ARENA_TEAM_FOUNDER_S "Congratulations, you are a founding member of %s! To leave, use /teamquit [2v2, 3v3, 5v5]." + ++ERR_ARENA_TEAM_INTERNAL "Internal arena team error" ++ERR_ALREADY_IN_ARENA_TEAM "You are already in an arena team of that size" ++ERR_ALREADY_IN_ARENA_TEAM_S "%s is already in an arena team of that size" ++ERR_INVITED_TO_ARENA_TEAM "You have already been invited into an arena team" ++ERR_ALREADY_INVITED_TO_ARENA_TEAM_S "%s has already been invited to an arena team" ++ERR_ARENA_TEAM_NAME_INVALID "That name contains invalid characters, please enter a new name" ++ERR_ARENA_TEAM_NAME_EXISTS_S "There is already an arena team named \"%s\"" ++ERR_ARENA_TEAM_LEADER_LEAVE_S "You must promote a new team captain using /teamcaptain before leaving the team" ++ERR_ARENA_TEAM_PERMISSIONS "You don't have permission to do that" ++ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM "You are not in an arena team of that size" ++ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM_SS "%s is not in %s" ++ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S "\"%s\" not found" ++ERR_ARENA_TEAM_NOT_ALLIED "You cannot invite players from the opposing alliance" + ++ERR_ARENA_TEAM_JOIN_SS "%s has joined %s" ++ERR_ARENA_TEAM_YOU_JOIN_S "You have joined %s. To leave, use /teamquit [2v2, 3v3, 5v5]." + ++ERR_ARENA_TEAM_LEAVE_SS "%s has left %s" + ++ERR_ARENA_TEAM_LEADER_IS_SS "%s is the captain of %s" ++ERR_ARENA_TEAM_LEADER_CHANGED_SSS "%s has made %s the new captain of %s" + ++ERR_ARENA_TEAM_REMOVE_SSS "%s has been kicked out of %s by %s" + ++ERR_ARENA_TEAM_DISBANDED_S "%s has disbanded %s" + +ERR_ARENA_TEAM_TARGET_TOO_LOW_S "%s is not high enough level to join your team" + +ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S "%s is full" + +ERR_ARENA_TEAM_LEVEL_TOO_LOW_I "You must be level %d to form an arena team" +*/ diff --git a/src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp b/src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp new file mode 100644 index 00000000000..8fec3b7df1d --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp @@ -0,0 +1,664 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ObjectMgr.h" +#include "Player.h" +#include "World.h" +#include "WorldPacket.h" +#include "WorldSession.h" + +#include "AuctionHouseBot.h" +#include "AuctionHouseMgr.h" +#include "Log.h" +#include "Opcodes.h" +#include "UpdateMask.h" +#include "Util.h" + +//please DO NOT use iterator++, because it is slower than ++iterator!!! +//post-incrementation is always slower than pre-incrementation ! + +//void called when player click on auctioneer npc +void WorldSession::HandleAuctionHelloOpcode(WorldPacket & recv_data) +{ + uint64 guid; //NPC guid + recv_data >> guid; + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_AUCTIONEER); + if (!unit) + { + sLog.outDebug("WORLD: HandleAuctionHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + SendAuctionHello(guid, unit); +} + +//this void causes that auction window is opened +void WorldSession::SendAuctionHello(uint64 guid, Creature* unit) +{ + if (GetPlayer()->getLevel() < sWorld.getConfig(CONFIG_AUCTION_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_AUCTION_REQ), sWorld.getConfig(CONFIG_AUCTION_LEVEL_REQ)); + return; + } + + AuctionHouseEntry const* ahEntry = AuctionHouseMgr::GetAuctionHouseEntry(unit->getFaction()); + if (!ahEntry) + return; + + WorldPacket data(MSG_AUCTION_HELLO, 12); + data << uint64(guid); + data << uint32(ahEntry->houseId); + data << uint8(1); // 3.3.3: 1 - AH enabled, 0 - AH disabled + SendPacket(&data); +} + +//call this method when player bids, creates, or deletes auction +void WorldSession::SendAuctionCommandResult(uint32 auctionId, uint32 Action, uint32 ErrorCode, uint32 bidError) +{ + WorldPacket data(SMSG_AUCTION_COMMAND_RESULT, 16); + data << auctionId; + data << Action; + data << ErrorCode; + if (!ErrorCode && Action) + data << bidError; //when bid, then send 0, once... + SendPacket(&data); +} + +//this function sends notification, if bidder is online +void WorldSession::SendAuctionBidderNotification(uint32 location, uint32 auctionId, uint64 bidder, uint32 bidSum, uint32 diff, uint32 item_template) +{ + WorldPacket data(SMSG_AUCTION_BIDDER_NOTIFICATION, (8*4)); + data << uint32(location); + data << uint32(auctionId); + data << uint64(bidder); + data << uint32(bidSum); + data << uint32(diff); + data << uint32(item_template); + data << uint32(0); + SendPacket(&data); +} + +//this void causes on client to display: "Your auction sold" +void WorldSession::SendAuctionOwnerNotification(AuctionEntry* auction) +{ + WorldPacket data(SMSG_AUCTION_OWNER_NOTIFICATION, (7*4)); + data << auction->Id; + data << auction->bid; + data << (uint32) 0; //unk + data << (uint32) 0; //unk + data << (uint32) 0; //unk + data << auction->item_template; + data << (uint32) 0; //unk + SendPacket(&data); +} + +//this function sends mail to old bidder +void WorldSession::SendAuctionOutbiddedMail(AuctionEntry *auction, uint32 newPrice) +{ + uint64 oldBidder_guid = MAKE_NEW_GUID(auction->bidder,0, HIGHGUID_PLAYER); + Player *oldBidder = objmgr.GetPlayer(oldBidder_guid); + + uint32 oldBidder_accId = 0; + if (!oldBidder) + oldBidder_accId = objmgr.GetPlayerAccountIdByGUID(oldBidder_guid); + + // old bidder exist + if (oldBidder || oldBidder_accId) + { + std::ostringstream msgAuctionOutbiddedSubject; + msgAuctionOutbiddedSubject << auction->item_template << ":0:" << AUCTION_OUTBIDDED << ":0:0"; + + if (oldBidder && !_player) + oldBidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, auctionbot.GetAHBplayerGUID(), newPrice, auction->GetAuctionOutBid(), auction->item_template); + + if (oldBidder && _player) + oldBidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, _player->GetGUID(), newPrice, auction->GetAuctionOutBid(), auction->item_template); + + MailDraft(msgAuctionOutbiddedSubject.str(), "") // TODO: fix body + .AddMoney(auction->bid) + .SendMailTo(MailReceiver(oldBidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED); + } +} + +//this function sends mail, when auction is cancelled to old bidder +void WorldSession::SendAuctionCancelledToBidderMail(AuctionEntry* auction) +{ + uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER); + Player *bidder = objmgr.GetPlayer(bidder_guid); + + uint32 bidder_accId = 0; + if (!bidder) + bidder_accId = objmgr.GetPlayerAccountIdByGUID(bidder_guid); + + // bidder exist + if (bidder || bidder_accId) + { + std::ostringstream msgAuctionCancelledSubject; + msgAuctionCancelledSubject << auction->item_template << ":0:" << AUCTION_CANCELLED_TO_BIDDER << ":0:0"; + + MailDraft(msgAuctionCancelledSubject.str(), "") // TODO: fix body + .AddMoney(auction->bid) + .SendMailTo(MailReceiver(bidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED); + } +} + +//this void creates new auction and adds auction to some auctionhouse +void WorldSession::HandleAuctionSellItem(WorldPacket & recv_data) +{ + uint64 auctioneer, item; + uint32 etime, bid, buyout; + recv_data >> auctioneer; + recv_data.read_skip(); // const 1? + recv_data >> item; + recv_data.read_skip(); // unk 3.2.2, const 1? + recv_data >> bid; + recv_data >> buyout; + recv_data >> etime; + + Player *pl = GetPlayer(); + + if (!item || !bid || !etime) + return; //check for cheaters + + Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer,UNIT_NPC_FLAG_AUCTIONEER); + if (!pCreature) + { + sLog.outDebug("WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); + return; + } + + AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(pCreature->getFaction()); + if (!auctionHouseEntry) + { + sLog.outDebug("WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction.", uint32(GUID_LOPART(auctioneer))); + return; + } + + sLog.outDebug("WORLD: HandleAuctionSellItem - ETIME: %u", etime); + + // client send time in minutes, convert to common used sec time + etime *= MINUTE; + + sLog.outDebug("WORLD: HandleAuctionSellItem - ETIME: %u", etime); + + // client understand only 3 auction time + switch(etime) + { + case 1*MIN_AUCTION_TIME: + case 2*MIN_AUCTION_TIME: + case 4*MIN_AUCTION_TIME: + break; + default: + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + Item *it = pl->GetItemByGuid(item); + //do not allow to sell already auctioned items + if (auctionmgr.GetAItem(GUID_LOPART(item))) + { + sLog.outError("AuctionError, player %s is sending item id: %u, but item is already in another auction", pl->GetName(), GUID_LOPART(item)); + SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); + return; + } + // prevent sending bag with items (cheat: can be placed in bag after adding equiped empty bag to auction) + if (!it) + { + SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_ITEM_NOT_FOUND); + return; + } + + if (!it->CanBeTraded()) + { + SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); + return; + } + + if (it->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || it->GetUInt32Value(ITEM_FIELD_DURATION)) + { + SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); + return; + } + + AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(pCreature->getFaction()); + + //we have to take deposit : + uint32 deposit = auctionmgr.GetAuctionDeposit(auctionHouseEntry, etime, it); + if (pl->GetMoney() < deposit) + { + SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_NOT_ENOUGHT_MONEY); + return; + } + + if (GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) + { + sLog.outCommand(GetAccountId(),"GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", + GetPlayerName(),GetAccountId(),it->GetProto()->Name1,it->GetEntry(),it->GetCount()); + } + + pl->ModifyMoney(-int32(deposit)); + + uint32 auction_time = uint32(etime * sWorld.getRate(RATE_AUCTION_TIME)); + + AuctionEntry *AH = new AuctionEntry; + AH->Id = objmgr.GenerateAuctionID(); + if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) + AH->auctioneer = 23442; + else + AH->auctioneer = GUID_LOPART(auctioneer); + AH->item_guidlow = GUID_LOPART(item); + AH->item_template = it->GetEntry(); + AH->owner = pl->GetGUIDLow(); + AH->startbid = bid; + AH->bidder = 0; + AH->bid = 0; + AH->buyout = buyout; + AH->expire_time = time(NULL) + auction_time; + AH->deposit = deposit; + AH->auctionHouseEntry = auctionHouseEntry; + + sLog.outDetail("selling item %u to auctioneer %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", GUID_LOPART(item), AH->auctioneer, bid, buyout, auction_time, AH->GetHouseId()); + auctionmgr.AddAItem(it); + auctionHouse->AddAuction(AH); + + pl->MoveItemFromInventory(it->GetBagSlot(), it->GetSlot(), true); + + CharacterDatabase.BeginTransaction(); + it->DeleteFromInventoryDB(); + it->SaveToDB(); // recursive and not have transaction guard into self, not in inventiory and can be save standalone + AH->SaveToDB(); + pl->SaveInventoryAndGoldToDB(); + CharacterDatabase.CommitTransaction(); + + SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); + + GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); +} + +//this function is called when client bids or buys out auction +void WorldSession::HandleAuctionPlaceBid(WorldPacket & recv_data) +{ + uint64 auctioneer; + uint32 auctionId; + uint32 price; + recv_data >> auctioneer; + recv_data >> auctionId >> price; + + if (!auctionId || !price) + return; //check for cheaters + + Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); + if (!pCreature) + { + sLog.outDebug("WORLD: HandleAuctionPlaceBid - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject *auctionHouse = auctionmgr.GetAuctionsMap(pCreature->getFaction()); + + AuctionEntry *auction = auctionHouse->GetAuction(auctionId); + Player *pl = GetPlayer(); + + if (!auction || auction->owner == pl->GetGUIDLow()) + { + //you cannot bid your own auction: + SendAuctionCommandResult(0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR); + return; + } + + // impossible have online own another character (use this for speedup check in case online owner) + Player* auction_owner = objmgr.GetPlayer(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)); + if (!auction_owner && objmgr.GetPlayerAccountIdByGUID(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)) == pl->GetSession()->GetAccountId()) + { + //you cannot bid your another character auction: + SendAuctionCommandResult(0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR); + return; + } + + // cheating + if (price <= auction->bid || price < auction->startbid) + return; + + // price too low for next bid if not buyout + if ((price < auction->buyout || auction->buyout == 0) && + price < auction->bid + auction->GetAuctionOutBid()) + { + //auction has already higher bid, client tests it! + return; + } + + if (price > pl->GetMoney()) + { + //you don't have enought money!, client tests! + //SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???); + return; + } + + if (price < auction->buyout || auction->buyout == 0) + { + if (auction->bidder > 0) + { + if (auction->bidder == pl->GetGUIDLow()) + pl->ModifyMoney(-int32(price - auction->bid)); + else + { + // mail to last bidder and return money + SendAuctionOutbiddedMail(auction, price); + pl->ModifyMoney(-int32(price)); + } + } + else + pl->ModifyMoney(-int32(price)); + + auction->bidder = pl->GetGUIDLow(); + auction->bid = price; + GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, price); + + // after this update we should save player's money ... + CharacterDatabase.BeginTransaction(); + CharacterDatabase.PExecute("UPDATE auctionhouse SET buyguid = '%u',lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id); + + SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK, 0); + } + else + { + //buyout: + if (pl->GetGUIDLow() == auction->bidder) + pl->ModifyMoney(-int32(auction->buyout - auction->bid)); + else + { + pl->ModifyMoney(-int32(auction->buyout)); + if (auction->bidder) //buyout for bidded auction .. + SendAuctionOutbiddedMail(auction, auction->buyout); + } + auction->bidder = pl->GetGUIDLow(); + auction->bid = auction->buyout; + GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout); + + auctionmgr.SendAuctionSalePendingMail(auction); + auctionmgr.SendAuctionSuccessfulMail(auction); + auctionmgr.SendAuctionWonMail(auction); + + SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK); + + CharacterDatabase.BeginTransaction(); + auction->DeleteFromDB(); + uint32 item_template = auction->item_template; + auctionmgr.RemoveAItem(auction->item_guidlow); + auctionHouse->RemoveAuction(auction, item_template); + } + pl->SaveInventoryAndGoldToDB(); + CharacterDatabase.CommitTransaction(); +} + +//this void is called when auction_owner cancels his auction +void WorldSession::HandleAuctionRemoveItem(WorldPacket & recv_data) +{ + uint64 auctioneer; + uint32 auctionId; + recv_data >> auctioneer; + recv_data >> auctionId; + //sLog.outDebug("Cancel AUCTION AuctionID: %u", auctionId); + + Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer,UNIT_NPC_FLAG_AUCTIONEER); + if (!pCreature) + { + sLog.outDebug("WORLD: HandleAuctionRemoveItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(pCreature->getFaction()); + + AuctionEntry *auction = auctionHouse->GetAuction(auctionId); + Player *pl = GetPlayer(); + + if (auction && auction->owner == pl->GetGUIDLow()) + { + Item *pItem = auctionmgr.GetAItem(auction->item_guidlow); + if (pItem) + { + if (auction->bidder > 0) // If we have a bidder, we have to send him the money he paid + { + uint32 auctionCut = auction->GetAuctionCut(); + if (pl->GetMoney() < auctionCut) //player doesn't have enough money, maybe message needed + return; + //some auctionBidderNotification would be needed, but don't know that parts.. + SendAuctionCancelledToBidderMail(auction); + pl->ModifyMoney(-int32(auctionCut)); + } + // Return the item by mail + std::ostringstream msgAuctionCanceledOwner; + msgAuctionCanceledOwner << auction->item_template << ":0:" << AUCTION_CANCELED << ":0:0"; + + // item will deleted or added to received mail list + MailDraft(msgAuctionCanceledOwner.str(), "") // TODO: fix body + .AddItem(pItem) + .SendMailTo(pl, auction, MAIL_CHECK_MASK_COPIED); + } + else + { + sLog.outError("Auction id: %u has non-existed item (item guid : %u)!!!", auction->Id, auction->item_guidlow); + SendAuctionCommandResult(0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR); + return; + } + } + else + { + SendAuctionCommandResult(0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR); + //this code isn't possible ... maybe there should be assert + sLog.outError("CHEATER : %u, he tried to cancel auction (id: %u) of another player, or auction is NULL", pl->GetGUIDLow(), auctionId); + return; + } + + //inform player, that auction is removed + SendAuctionCommandResult(auction->Id, AUCTION_CANCEL, AUCTION_OK); + + // Now remove the auction + CharacterDatabase.BeginTransaction(); + pl->SaveInventoryAndGoldToDB(); + auction->DeleteFromDB(); + uint32 item_template = auction->item_template; + auctionmgr.RemoveAItem(auction->item_guidlow); + auctionHouse->RemoveAuction(auction, item_template); + CharacterDatabase.CommitTransaction(); +} + +//called when player lists his bids +void WorldSession::HandleAuctionListBidderItems(WorldPacket & recv_data) +{ + uint64 guid; //NPC guid + uint32 listfrom; //page of auctions + uint32 outbiddedCount; //count of outbidded auctions + + recv_data >> guid; + recv_data >> listfrom; // not used in fact (this list not have page control in client) + recv_data >> outbiddedCount; + if (recv_data.size() != (16 + outbiddedCount * 4)) + { + sLog.outError("Client sent bad opcode!!! with count: %u and size : %lu (must be: %u)", outbiddedCount, (unsigned long)recv_data.size(),(16 + outbiddedCount * 4)); + outbiddedCount = 0; + } + + Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_AUCTIONEER); + if (!pCreature) + { + sLog.outDebug("WORLD: HandleAuctionListBidderItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(pCreature->getFaction()); + + WorldPacket data(SMSG_AUCTION_BIDDER_LIST_RESULT, (4+4+4)); + Player *pl = GetPlayer(); + data << (uint32) 0; //add 0 as count + uint32 count = 0; + uint32 totalcount = 0; + while (outbiddedCount > 0) //add all data, which client requires + { + --outbiddedCount; + uint32 outbiddedAuctionId; + recv_data >> outbiddedAuctionId; + AuctionEntry * auction = auctionHouse->GetAuction(outbiddedAuctionId); + if (auction && auction->BuildAuctionInfo(data)) + { + ++totalcount; + ++count; + } + } + + auctionHouse->BuildListBidderItems(data,pl,count,totalcount); + data.put(0, count); // add count to placeholder + data << totalcount; + data << (uint32)300; //unk 2.3.0 + SendPacket(&data); +} + +//this void sends player info about his auctions +void WorldSession::HandleAuctionListOwnerItems(WorldPacket & recv_data) +{ + uint32 listfrom; + uint64 guid; + + recv_data >> guid; + recv_data >> listfrom; // not used in fact (this list not have page control in client) + + Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_AUCTIONEER); + if (!pCreature) + { + sLog.outDebug("WORLD: HandleAuctionListOwnerItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(pCreature->getFaction()); + + WorldPacket data(SMSG_AUCTION_OWNER_LIST_RESULT, (4+4+4)); + data << (uint32) 0; // amount place holder + + uint32 count = 0; + uint32 totalcount = 0; + + auctionHouse->BuildListOwnerItems(data,_player,count,totalcount); + data.put(0, count); + data << (uint32) totalcount; + data << (uint32) 0; + SendPacket(&data); +} + +//this void is called when player clicks on search button +void WorldSession::HandleAuctionListItems(WorldPacket & recv_data) +{ + std::string searchedname; + uint8 levelmin, levelmax, usable; + uint32 listfrom, auctionSlotID, auctionMainCategory, auctionSubCategory, quality; + uint64 guid; + + recv_data >> guid; + recv_data >> listfrom; // start, used for page control listing by 50 elements + recv_data >> searchedname; + + recv_data >> levelmin >> levelmax; + recv_data >> auctionSlotID >> auctionMainCategory >> auctionSubCategory; + recv_data >> quality >> usable; + + recv_data.read_skip(16); // unknown 16 bytes: 00 07 01 00 00 01 05 00 06 00 09 01 08 00 03 00 + + Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_AUCTIONEER); + if (!pCreature) + { + sLog.outDebug("WORLD: HandleAuctionListItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(pCreature->getFaction()); + + //sLog.outDebug("Auctionhouse search (GUID: %u TypeId: %u)", , list from: %u, searchedname: %s, levelmin: %u, levelmax: %u, auctionSlotID: %u, auctionMainCategory: %u, auctionSubCategory: %u, quality: %u, usable: %u", + // GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(guid)), listfrom, searchedname.c_str(), levelmin, levelmax, auctionSlotID, auctionMainCategory, auctionSubCategory, quality, usable); + + WorldPacket data(SMSG_AUCTION_LIST_RESULT, (4+4+4)); + uint32 count = 0; + uint32 totalcount = 0; + data << (uint32) 0; + + // converting string that we try to find to lower case + std::wstring wsearchedname; + if (!Utf8toWStr(searchedname,wsearchedname)) + return; + + wstrToLower(wsearchedname); + + auctionHouse->BuildListAuctionItems(data,_player, + wsearchedname, listfrom, levelmin, levelmax, usable, + auctionSlotID, auctionMainCategory, auctionSubCategory, quality, + count,totalcount); + + data.put(0, count); + data << (uint32) totalcount; + data << (uint32) 300; // unk 2.3.0 const? + SendPacket(&data); +} + +void WorldSession::HandleAuctionListPendingSales(WorldPacket & recv_data) +{ + sLog.outDebug("CMSG_AUCTION_LIST_PENDING_SALES"); + + recv_data.read_skip(); + + uint32 count = 0; + + WorldPacket data(SMSG_AUCTION_LIST_PENDING_SALES, 4); + data << uint32(count); // count + /*for (uint32 i = 0; i < count; ++i) + { + data << ""; // string + data << ""; // string + data << uint32(0); + data << uint32(0); + data << float(0); + }*/ + SendPacket(&data); +} diff --git a/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp b/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp new file mode 100644 index 00000000000..e779f2a8ab1 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp @@ -0,0 +1,803 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "WorldPacket.h" +#include "WorldSession.h" + +#include "ArenaTeam.h" +#include "BattleGroundMgr.h" +#include "BattleGroundWS.h" +#include "BattleGround.h" +#include "Chat.h" +#include "Language.h" +#include "Log.h" +#include "Player.h" +#include "Object.h" +#include "Opcodes.h" + +void WorldSession::HandleBattlemasterHelloOpcode(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + sLog.outDebug("WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(guid))); + + Creature *unit = GetPlayer()->GetMap()->GetCreature(guid); + if (!unit) + return; + + if (!unit->isBattleMaster()) // it's not battlemaster + return; + + // Stop the npc if moving + unit->StopMoving(); + + BattleGroundTypeId bgTypeId = sBattleGroundMgr.GetBattleMasterBG(unit->GetEntry()); + + if (!_player->GetBGAccessByLevel(bgTypeId)) + { + // temp, must be gossip message... + SendNotification(LANG_YOUR_BG_LEVEL_REQ_ERROR); + return; + } + + SendBattlegGroundList(guid, bgTypeId); +} + +void WorldSession::SendBattlegGroundList(uint64 guid, BattleGroundTypeId bgTypeId) +{ + WorldPacket data; + sBattleGroundMgr.BuildBattleGroundListPacket(&data, guid, _player, bgTypeId, 0); + SendPacket(&data); +} + +void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket & recv_data) +{ + uint64 guid; + uint32 bgTypeId_; + uint32 instanceId; + uint8 joinAsGroup; + bool isPremade = false; + Group * grp = NULL; + + recv_data >> guid; // battlemaster guid + recv_data >> bgTypeId_; // battleground type id (DBC id) + recv_data >> instanceId; // instance id, 0 if First Available selected + recv_data >> joinAsGroup; // join as group + + if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) + { + sLog.outError("Battleground: invalid bgtype (%u) received. possible cheater? player guid %u",bgTypeId_,_player->GetGUIDLow()); + return; + } + + BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_); + + sLog.outDebug("WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid))); + + // can do this, since it's battleground, not arena + BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, 0); + BattleGroundQueueTypeId bgQueueTypeIdRandom = BattleGroundMgr::BGQueueTypeId(BATTLEGROUND_RB, 0); + + // ignore if player is already in BG + if (_player->InBattleGround()) + return; + + // get bg instance or bg template if instance not found + BattleGround *bg = NULL; + if (instanceId) + bg = sBattleGroundMgr.GetBattleGroundThroughClientInstance(instanceId, bgTypeId); + + if (!bg) + bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); + if (!bg) + return; + + // expected bracket entry + PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),_player->getLevel()); + if (!bracketEntry) + return; + + GroupJoinBattlegroundResult err; + + // check queue conditions + if (!joinAsGroup) + { + // check Deserter debuff + if (!_player->CanJoinToBattleground()) + { + WorldPacket data; + sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); + _player->GetSession()->SendPacket(&data); + return; + } + + if (_player->GetBattleGroundQueueIndex(bgQueueTypeIdRandom) < PLAYER_MAX_BATTLEGROUND_QUEUES) + { + //player is already in random queue + WorldPacket data; + sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, ERR_IN_RANDOM_BG); + _player->GetSession()->SendPacket(&data); + return; + } + + if (_player->InBattleGroundQueue() && bgTypeId == BATTLEGROUND_RB) + { + //player is already in queue, can't start random queue + WorldPacket data; + sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, ERR_IN_NON_RANDOM_BG); + _player->GetSession()->SendPacket(&data); + return; + } + + // check if already in queue + if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) + //player is already in this queue + return; + + // check if has free queue slots + if (!_player->HasFreeBattleGroundQueueId()) + { + WorldPacket data; + sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_TOO_MANY_QUEUES); + _player->GetSession()->SendPacket(&data); + return; + } + + BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; + + GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, 0, false, isPremade, 0); + uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); + // already checked if queueSlot is valid, now just get it + uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId); + + WorldPacket data; + // send status packet (in queue) + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); + SendPacket(&data); + sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); + } + else + { + grp = _player->GetGroup(); + // no group found, error + if (!grp) + return; + if (grp->GetLeaderGUID() != _player->GetGUID()) + return; + err = grp->CanJoinBattleGroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0); + isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam()); + + BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; + GroupQueueInfo * ginfo = NULL; + uint32 avgTime = 0; + + if (err > 0) + { + sLog.outDebug("Battleground: the following players are joining as group:"); + ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, 0, false, isPremade, 0); + avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); + } + + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player *member = itr->getSource(); + if (!member) continue; // this should never happen + + WorldPacket data; + + if (err <= 0) + { + sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, err); + member->GetSession()->SendPacket(&data); + continue; + } + + // add to queue + uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); + + // send status packet (in queue) + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); + member->GetSession()->SendPacket(&data); + sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, err); + member->GetSession()->SendPacket(&data); + sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName()); + } + sLog.outDebug("Battleground: group end"); + + } + sBattleGroundMgr.ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); +} + +void WorldSession::HandleBattleGroundPlayerPositionsOpcode(WorldPacket & /*recv_data*/) +{ + // empty opcode + sLog.outDebug("WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message"); + + BattleGround *bg = _player->GetBattleGround(); + if (!bg) // can't be received if player not in battleground + return; + + switch(bg->GetTypeID(true)) + { + case BATTLEGROUND_WS: + { + uint32 count1 = 0; //always constant zero? + uint32 count2 = 0; //count of next fields + + Player *ali_plr = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID()); + if (ali_plr) + ++count2; + + Player *horde_plr = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetHordeFlagPickerGUID()); + if (horde_plr) + ++count2; + + WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4+16*count1+16*count2)); + data << count1; // alliance flag holders count - obsolete, now always 0 + /*for (uint8 i = 0; i < count1; ++i) + { + data << uint64(0); // guid + data << (float)0; // x + data << (float)0; // y + }*/ + data << count2; // horde flag holders count - obsolete, now count of next fields + if (ali_plr) + { + data << (uint64)ali_plr->GetGUID(); + data << (float)ali_plr->GetPositionX(); + data << (float)ali_plr->GetPositionY(); + } + if (horde_plr) + { + data << (uint64)horde_plr->GetGUID(); + data << (float)horde_plr->GetPositionX(); + data << (float)horde_plr->GetPositionY(); + } + + SendPacket(&data); + } + break; + case BATTLEGROUND_EY: + //TODO : fix me! + break; + case BATTLEGROUND_AB: + case BATTLEGROUND_AV: + { + //for other BG types - send default + WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4)); + data << uint32(0); + data << uint32(0); + SendPacket(&data); + } + break; + default: + //maybe it is sent also in arena - do nothing + break; + } +} + +void WorldSession::HandlePVPLogDataOpcode(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("WORLD: Recvd MSG_PVP_LOG_DATA Message"); + + BattleGround *bg = _player->GetBattleGround(); + if (!bg) + return; + + WorldPacket data; + sBattleGroundMgr.BuildPvpLogDataPacket(&data, bg); + SendPacket(&data); + + sLog.outDebug("WORLD: Sent MSG_PVP_LOG_DATA Message"); +} + +void WorldSession::HandleBattlefieldListOpcode(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: Recvd CMSG_BATTLEFIELD_LIST Message"); + + uint32 bgTypeId; + recv_data >> bgTypeId; // id from DBC + + uint8 fromWhere; + recv_data >> fromWhere; // 0 - battlemaster (lua: ShowBattlefieldList), 1 - UI (lua: RequestBattlegroundInstanceInfo) + + uint8 unk1; + recv_data >> unk1; // Unknown 3.2.2 + + BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); + if (!bl) + { + sLog.outError("Battleground: invalid bgtype received."); + return; + } + + WorldPacket data; + sBattleGroundMgr.BuildBattleGroundListPacket(&data, 0, _player, BattleGroundTypeId(bgTypeId), fromWhere); + SendPacket(&data); +} + +void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: Recvd CMSG_BATTLEFIELD_PORT Message"); + + uint8 type; // arenatype if arena + uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1 + uint32 bgTypeId_; // type id from dbc + uint16 unk; // 0x1F90 constant? + uint8 action; // enter battle 0x1, leave queue 0x0 + + recv_data >> type >> unk2 >> bgTypeId_ >> unk >> action; + + if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) + { + sLog.outError("BattlegroundHandler: invalid bgtype (%u) received.", bgTypeId_); + return; + } + if (!_player->InBattleGroundQueue()) + { + sLog.outError("BattlegroundHandler: Invalid CMSG_BATTLEFIELD_PORT received from player (%u), he is not in bg_queue.", _player->GetGUIDLow()); + return; + } + + //get GroupQueueInfo from BattleGroundQueue + BattleGroundTypeId bgTypeId = BattleGroundTypeId(bgTypeId_); + BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type); + BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; + //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattleGroundQueue::RemovePlayer() function + GroupQueueInfo ginfo; + if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) + { + sLog.outError("BattlegroundHandler: itrplayerstatus not found."); + return; + } + // if action == 1, then instanceId is required + if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) + { + sLog.outError("BattlegroundHandler: instance not found."); + return; + } + + BattleGround *bg = sBattleGroundMgr.GetBattleGround(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); + + // bg template might and must be used in case of leaving queue, when instance is not created yet + if (!bg && action == 0) + bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); + if (!bg) + { + sLog.outError("BattlegroundHandler: bg_template not found for type id %u.", bgTypeId); + return; + } + + // expected bracket entry + PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),_player->getLevel()); + if (!bracketEntry) + return; + + //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it + if (action == 1 && ginfo.ArenaType == 0) + { + //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue + if (!_player->CanJoinToBattleground()) + { + //send bg command result to show nice message + WorldPacket data2; + sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data2, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); + _player->GetSession()->SendPacket(&data2); + action = 0; + sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); + } + //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue + if (_player->getLevel() > bg->GetMaxLevel()) + { + sLog.outError("Battleground: Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!", + _player->GetName(), _player->GetGUIDLow(), _player->getLevel(), bg->GetMaxLevel(), bg->GetTypeID()); + action = 0; + } + } + uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId); + WorldPacket data; + switch(action) + { + case 1: // port to battleground + if (!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId)) + return; // cheating? + + if (!_player->InBattleGround()) + _player->SetBattleGroundEntryPoint(); + + // resurrect the player + if (!_player->isAlive()) + { + _player->ResurrectPlayer(1.0f); + _player->SpawnCorpseBones(); + } + // stop taxi flight at port + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType()); + _player->GetSession()->SendPacket(&data); + // remove battleground queue status from BGmgr + bgQueue.RemovePlayer(_player->GetGUID(), false); + // this is still needed here if battleground "jumping" shouldn't add deserter debuff + // also this is required to prevent stuck at old battleground after SetBattleGroundId set to new + if (BattleGround *currentBg = _player->GetBattleGround()) + currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); + + // set the destination instance id + _player->SetBattleGroundId(bg->GetInstanceID(), bgTypeId); + // set the destination team + _player->SetBGTeam(ginfo.Team); + // bg->HandleBeforeTeleportToBattleGround(_player); + sBattleGroundMgr.SendToBattleGround(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); + // add only in HandleMoveWorldPortAck() + // bg->AddPlayer(_player,team); + sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId); + break; + case 0: // leave queue + // if player leaves rated arena match before match start, it is counted as he played but he lost + if (ginfo.IsRated) + { + ArenaTeam * at = objmgr.GetArenaTeamById(ginfo.Team); + if (at) + { + sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), ginfo.OpponentsTeamRating); + at->MemberLost(_player, ginfo.OpponentsTeamRating); + at->SaveToDB(); + } + } + _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); + bgQueue.RemovePlayer(_player->GetGUID(), true); + // player left queue, we should update it - do not update Arena Queue + if (!ginfo.ArenaType) + sBattleGroundMgr.ScheduleQueueUpdate(ginfo.ArenaTeamRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); + SendPacket(&data); + sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); + break; + default: + sLog.outError("Battleground port: unknown action %u", action); + break; + } +} + +void WorldSession::HandleLeaveBattlefieldOpcode(WorldPacket& recv_data) +{ + sLog.outDebug("WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message"); + + recv_data.read_skip(); // unk1 + recv_data.read_skip(); // unk2 + recv_data.read_skip(); // BattleGroundTypeId + recv_data.read_skip(); // unk3 + + // not allow leave battleground in combat + if (_player->isInCombat()) + if (BattleGround* bg = _player->GetBattleGround()) + if (bg->GetStatus() != STATUS_WAIT_LEAVE) + return; + + _player->LeaveBattleground(); +} + +void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recv_data*/) +{ + // empty opcode + sLog.outDebug("WORLD: Battleground status"); + + WorldPacket data; + // we must update all queues here + BattleGround *bg = NULL; + for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) + { + BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i); + if (!bgQueueTypeId) + continue; + BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); + uint8 arenaType = BattleGroundMgr::BGArenaType(bgQueueTypeId); + if (bgTypeId == _player->GetBattleGroundTypeId()) + { + bg = _player->GetBattleGround(); + //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena + //so i must use bg pointer to get that information + if (bg && bg->GetArenaType() == arenaType) + { + // this line is checked, i only don't know if GetStartTime is changing itself after bg end! + // send status in BattleGround + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType); + SendPacket(&data); + continue; + } + } + //we are sending update to player about queue - he can be invited there! + //get GroupQueueInfo for queue status + BattleGroundQueue& bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; + GroupQueueInfo ginfo; + if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) + continue; + if (ginfo.IsInvitedToBGInstanceGUID) + { + bg = sBattleGroundMgr.GetBattleGround(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); + if (!bg) + continue; + uint32 remainingTime = getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime); + // send status invited to BattleGround + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType); + SendPacket(&data); + } + else + { + bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); + if (!bg) + continue; + + // expected bracket entry + PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),_player->getLevel()); + if (!bracketEntry) + continue; + + uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, bracketEntry->GetBracketId()); + // send status in BattleGround Queue + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, getMSTime()), arenaType); + SendPacket(&data); + } + } +} + +void WorldSession::HandleAreaSpiritHealerQueryOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY"); + + BattleGround *bg = _player->GetBattleGround(); + + uint64 guid; + recv_data >> guid; + + Creature *unit = GetPlayer()->GetMap()->GetCreature(guid); + if (!unit) + return; + + if (!unit->isSpiritService()) // it's not spirit service + return; + + if (bg) + sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, guid); +} + + +void WorldSession::HandleAreaSpiritHealerQueueOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE"); + + BattleGround *bg = _player->GetBattleGround(); + + uint64 guid; + recv_data >> guid; + + Creature *unit = GetPlayer()->GetMap()->GetCreature(guid); + if (!unit) + return; + + if (!unit->isSpiritService()) // it's not spirit service + return; + + if (bg) + bg->AddPlayerToResurrectQueue(guid, _player->GetGUID()); +} + + +void WorldSession::HandleBattlemasterJoinArena(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_BATTLEMASTER_JOIN_ARENA"); + //recv_data.hexlike(); + + uint64 guid; // arena Battlemaster guid + uint8 arenaslot; // 2v2, 3v3 or 5v5 + uint8 asGroup; // asGroup + uint8 isRated; // isRated + Group * grp = NULL; + + recv_data >> guid >> arenaslot >> asGroup >> isRated; + + // ignore if we already in BG or BG queue + if (_player->InBattleGround()) + return; + + Creature *unit = GetPlayer()->GetMap()->GetCreature(guid); + if (!unit) + return; + + if (!unit->isBattleMaster()) // it's not battle master + return; + + uint8 arenatype = 0; + uint32 arenaRating = 0; + + switch(arenaslot) + { + case 0: + arenatype = ARENA_TYPE_2v2; + break; + case 1: + arenatype = ARENA_TYPE_3v3; + break; + case 2: + arenatype = ARENA_TYPE_5v5; + break; + default: + sLog.outError("Unknown arena slot %u at HandleBattlemasterJoinArena()", arenaslot); + return; + } + + //check existance + BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA); + if (!bg) + { + sLog.outError("Battleground: template bg (all arenas) not found"); + return; + } + + BattleGroundTypeId bgTypeId = bg->GetTypeID(); + BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenatype); + PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),_player->getLevel()); + if (!bracketEntry) + return; + + GroupJoinBattlegroundResult err = ERR_GROUP_JOIN_BATTLEGROUND_FAIL; + + if (!asGroup) + { + // check if already in queue + if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) + //player is already in this queue + return; + // check if has free queue slots + if (!_player->HasFreeBattleGroundQueueId()) + return; + } + else + { + grp = _player->GetGroup(); + // no group found, error + if (!grp) + return; + if (grp->GetLeaderGUID() != _player->GetGUID()) + return; + err = grp->CanJoinBattleGroundQueue(bg, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot); + } + + uint32 ateamId = 0; + + if (isRated) + { + ateamId = _player->GetArenaTeamId(arenaslot); + // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice) + ArenaTeam * at = objmgr.GetArenaTeamById(ateamId); + if (!at) + { + _player->GetSession()->SendNotInArenaTeamPacket(arenatype); + return; + } + // get the team rating for queueing + arenaRating = at->GetRating(); + // the arenateam id must match for everyone in the group + // get the personal ratings for queueing + uint32 avg_pers_rating = 0; + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player *member = itr->getSource(); + + // calc avg personal rating + avg_pers_rating += member->GetArenaPersonalRating(arenaslot); + } + + if (arenatype) + avg_pers_rating /= arenatype; + + // if avg personal rating is more than 150 points below the teams rating, the team will be queued against an opponent matching or similar to the average personal rating + if (avg_pers_rating + 150 < arenaRating) + arenaRating = avg_pers_rating; + + if (arenaRating <= 0) + arenaRating = 1; + } + + BattleGroundQueue &bgQueue = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId]; + if (asGroup) + { + uint32 avgTime = 0; + + if (err > 0) + { + sLog.outDebug("Battleground: arena join as group start"); + if (isRated) + { + sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype); + bg->SetRated(true); + } + else + bg->SetRated(false); + + GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, arenatype, isRated, false, arenaRating, ateamId); + avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); + } + + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player *member = itr->getSource(); + if (!member) + continue; + + WorldPacket data; + + if (err <= 0) + { + sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, err); + member->GetSession()->SendPacket(&data); + continue; + } + + // add to queue + uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); + + // send status packet (in queue) + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); + member->GetSession()->SendPacket(&data); + sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, err); + member->GetSession()->SendPacket(&data); + sLog.outDebug("Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName()); + } + } + else + { + GroupQueueInfo * ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, arenatype, isRated, false, arenaRating, ateamId); + uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); + uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId); + + WorldPacket data; + // send status packet (in queue) + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); + SendPacket(&data); + sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); + } + sBattleGroundMgr.ScheduleQueueUpdate(arenaRating, arenatype, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); +} + +void WorldSession::HandleReportPvPAFK(WorldPacket & recv_data) +{ + uint64 playerGuid; + recv_data >> playerGuid; + Player *reportedPlayer = objmgr.GetPlayer(playerGuid); + + if (!reportedPlayer) + { + sLog.outDebug("WorldSession::HandleReportPvPAFK: player not found"); + return; + } + + sLog.outDebug("WorldSession::HandleReportPvPAFK: %s reported %s", _player->GetName(), reportedPlayer->GetName()); + + reportedPlayer->ReportedAfkBy(_player); +} diff --git a/src/server/game/Server/Protocol/Handlers/CalendarHandler.cpp b/src/server/game/Server/Protocol/Handlers/CalendarHandler.cpp new file mode 100644 index 00000000000..f6679c5d5ac --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/CalendarHandler.cpp @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" + +#include "InstanceSaveMgr.h" +#include "Log.h" +#include "Opcodes.h" +#include "Player.h" + +void WorldSession::HandleCalendarGetCalendar(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_GET_CALENDAR"); // empty + + time_t cur_time = time(NULL); + + WorldPacket data(SMSG_CALENDAR_SEND_CALENDAR,4+4*0+4+4*0+4+4); + + data << uint32(0); // invite count + /* + for (;;) + { + uint64 inviteId; + uint64 unkGuid0; + uint8 unk1, unk2, unk3; + uint64 creatorGuid; + } + */ + + data << uint32(0); // event count + /* + for (;;) + { + uint64 eventId; + std::string title; // 128 chars + uint32 type; + uint32 occurrenceTime; + uint32 flags; + uint32 unk4; -- possibly mapid for dungeon/raid + uint64 creatorGuid; + } + */ + + data << uint32(0); // unk + data << uint32(secsToTimeBitFields(cur_time)); // current time + + uint32 counter = 0; + size_t p_counter = data.wpos(); + data << uint32(counter); // instance save count + + for (int i = 0; i < MAX_DIFFICULTY; ++i) + { + for (Player::BoundInstancesMap::const_iterator itr = _player->m_boundInstances[i].begin(); itr != _player->m_boundInstances[i].end(); ++itr) + { + if (itr->second.perm) + { + InstanceSave *save = itr->second.save; + data << uint32(save->GetMapId()); + data << uint32(save->GetDifficulty()); + data << uint32(save->GetResetTime() - cur_time); + data << uint64(save->GetInstanceId()); // instance save id as unique instance copy id + ++counter; + } + } + } + + data.put(p_counter, counter); + + data << uint32(1135753200); // unk (28.12.2005 12:00) + + counter = 0; + p_counter = data.wpos(); + data << uint32(counter); // raid reset count + + ResetTimeByMapDifficultyMap const& resets = sInstanceSaveManager.GetResetTimeMap(); + for (ResetTimeByMapDifficultyMap::const_iterator itr = resets.begin(); itr != resets.end(); ++itr) + { + uint32 mapid = PAIR32_LOPART(itr->first); + MapEntry const* mapEnt = sMapStore.LookupEntry(mapid); + if (!mapEnt || !mapEnt->IsRaid()) + continue; + + data << uint32(mapid); + data << uint32(itr->second - cur_time); + data << uint32(mapEnt->unk_time); + ++counter; + } + + data.put(p_counter, counter); + + data << uint32(0); // holiday count? + /* + for (;;) + { + uint32 unk5, unk6, unk7, unk8, unk9; + for (uint32 j = 0; j < 26; ++j) + { + uint32 unk10; + } + for (uint32 j = 0; j < 10; ++j) + { + uint32 unk11; + } + for (uint32 j = 0; j < 10; ++j) + { + uint32 unk12; + } + std::string holidayName; // 64 chars + } + */ + + sLog.outDebug("Sending calendar"); + data.hexlike(); + SendPacket(&data); +} + +void WorldSession::HandleCalendarGetEvent(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_GET_EVENT"); + recv_data.hexlike(); + recv_data.read_skip(); // unk +} + +void WorldSession::HandleCalendarGuildFilter(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_GUILD_FILTER"); + recv_data.hexlike(); + recv_data.read_skip(); // unk1 + recv_data.read_skip(); // unk2 + recv_data.read_skip(); // unk3 +} + +void WorldSession::HandleCalendarArenaTeam(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_ARENA_TEAM"); + recv_data.hexlike(); + recv_data.read_skip(); // unk +} + +void WorldSession::HandleCalendarAddEvent(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_ADD_EVENT"); + recv_data.hexlike(); + recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam + + //std::string unk1, unk2; + //recv_data >> (std::string)unk1; + //recv_data >> (std::string)unk2; + + //uint8 unk3, unk4; + //uint32 unk5, unk6, unk7, unk8, unk9, count = 0; + //recv_data >> (uint8)unk3; + //recv_data >> (uint8)unk4; + //recv_data >> (uint32)unk5; + //recv_data >> (uint32)unk6; + //recv_data >> (uint32)unk7; + //recv_data >> (uint32)unk8; + //recv_data >> (uint32)unk9; + //if (!((unk9 >> 6) & 1)) + //{ + // recv_data >> (uint32)count; + // if (count) + // { + // uint8 unk12,unk13; + // uint64 guid; + // for (int i=0; i> (uint8)unk12; + // recv_data >> (uint8)unk13; + // } + // } + //} +} + +void WorldSession::HandleCalendarUpdateEvent(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_UPDATE_EVENT"); + recv_data.hexlike(); + recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam + + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> std::string + //recv_data >> std::string + //recv_data >> uint8 + //recv_data >> uint8 + //recv_data >> uint32 + //recv_data >> uint32 + //recv_data >> uint32 + //recv_data >> uint32 + //recv_data >> uint32 +} + +void WorldSession::HandleCalendarRemoveEvent(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_REMOVE_EVENT"); + recv_data.hexlike(); + recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam + + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint32 + +} + +void WorldSession::HandleCalendarCopyEvent(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_COPY_EVENT"); + recv_data.hexlike(); + recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam + + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint32 + +} + +void WorldSession::HandleCalendarEventInvite(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_INVITE"); + recv_data.hexlike(); + recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam + + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> std::string + //recv_data >> uint8 + //recv_data >> uint8 + +} + +void WorldSession::HandleCalendarEventRsvp(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_RSVP"); + recv_data.hexlike(); + recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam + + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint32 + +} + +void WorldSession::HandleCalendarEventRemoveInvite(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_REMOVE_INVITE"); + recv_data.hexlike(); + recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam + + //recv_data.readPackGUID(guid) + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint64 +} + +void WorldSession::HandleCalendarEventStatus(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_STATUS"); + recv_data.hexlike(); + recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam + + //recv_data.readPackGUID(guid) + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint32 +} + +void WorldSession::HandleCalendarEventModeratorStatus(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_MODERATOR_STATUS"); + recv_data.hexlike(); + recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam + + //recv_data.readPackGUID(guid) + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint32 +} + +void WorldSession::HandleCalendarComplain(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_COMPLAIN"); + recv_data.hexlike(); + recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam + + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint64 +} + +void WorldSession::HandleCalendarGetNumPending(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("WORLD: CMSG_CALENDAR_GET_NUM_PENDING"); // empty + + WorldPacket data(SMSG_CALENDAR_SEND_NUM_PENDING, 4); + data << uint32(0); // 0 - no pending invites, 1 - some pending invites + SendPacket(&data); +} diff --git a/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp b/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp new file mode 100644 index 00000000000..0f615579cb6 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Policies/SingletonImp.h" + +#include "ObjectMgr.h" // for normalizePlayerName +#include "ChannelMgr.h" + +void WorldSession::HandleJoinChannel(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + + uint32 channel_id; + uint8 unknown1, unknown2; + std::string channelname, pass; + + recvPacket >> channel_id >> unknown1 >> unknown2; + recvPacket >> channelname; + + if (channelname.empty()) + return; + + recvPacket >> pass; + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + { + cMgr->team = _player->GetTeam(); + if (Channel *chn = cMgr->GetJoinChannel(channelname, channel_id)) + chn->Join(_player->GetGUID(), pass.c_str()); + } +} + +void WorldSession::HandleLeaveChannel(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + + uint32 unk; + std::string channelname; + recvPacket >> unk; // channel id? + recvPacket >> channelname; + + if (channelname.empty()) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + { + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->Leave(_player->GetGUID(), true); + cMgr->LeftChannel(channelname); + } +} + +void WorldSession::HandleChannelList(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname; + recvPacket >> channelname; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->List(_player); +} + +void WorldSession::HandleChannelPassword(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname, pass; + recvPacket >> channelname; + + recvPacket >> pass; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->Password(_player->GetGUID(), pass.c_str()); +} + +void WorldSession::HandleChannelSetOwner(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname, newp; + recvPacket >> channelname; + + recvPacket >> newp; + + if (!normalizePlayerName(newp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->SetOwner(_player->GetGUID(), newp.c_str()); +} + +void WorldSession::HandleChannelOwner(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname; + recvPacket >> channelname; + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->SendWhoOwner(_player->GetGUID()); +} + +void WorldSession::HandleChannelModerator(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->SetModerator(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelUnmoderator(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->UnsetModerator(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelMute(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->SetMute(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelUnmute(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->UnsetMute(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelInvite(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->Invite(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelKick(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->Kick(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelBan(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->Ban(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelUnban(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->UnBan(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelAnnouncements(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname; + recvPacket >> channelname; + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->Announce(_player->GetGUID()); +} + +void WorldSession::HandleChannelModerate(WorldPacket& recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname; + recvPacket >> channelname; + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->Moderate(_player->GetGUID()); +} + +void WorldSession::HandleChannelDisplayListQuery(WorldPacket &recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname; + recvPacket >> channelname; + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->List(_player); +} + +void WorldSession::HandleGetChannelMemberCount(WorldPacket &recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname; + recvPacket >> channelname; + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + { + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + { + WorldPacket data(SMSG_CHANNEL_MEMBER_COUNT, chn->GetName().size()+1+1+4); + data << chn->GetName(); + data << uint8(chn->GetFlags()); + data << uint32(chn->GetNumPlayers()); + SendPacket(&data); + } + } +} + +void WorldSession::HandleSetChannelWatch(WorldPacket &recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); + //recvPacket.hexlike(); + std::string channelname; + recvPacket >> channelname; + /*if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel *chn = cMgr->GetChannel(channelname, _player)) + chn->JoinNotify(_player->GetGUID());*/ +} + diff --git a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp new file mode 100644 index 00000000000..416827d73ea --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp @@ -0,0 +1,1406 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "SystemConfig.h" +#include "World.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Auth/md5.h" +#include "Database/DatabaseEnv.h" +#include "Database/DatabaseImpl.h" + +#include "ArenaTeam.h" +#include "Chat.h" +#include "Group.h" +#include "Guild.h" +#include "Language.h" +#include "Log.h" +#include "Opcodes.h" +#include "Player.h" +#include "PlayerDump.h" +#include "SharedDefines.h" +#include "SocialMgr.h" +#include "UpdateMask.h" +#include "Util.h" +#include "ScriptMgr.h" + +class LoginQueryHolder : public SqlQueryHolder +{ + private: + uint32 m_accountId; + uint64 m_guid; + public: + LoginQueryHolder(uint32 accountId, uint64 guid) + : m_accountId(accountId), m_guid(guid) { } + uint64 GetGuid() const { return m_guid; } + uint32 GetAccountId() const { return m_accountId; } + bool Initialize(); +}; + +bool LoginQueryHolder::Initialize() +{ + SetSize(MAX_PLAYER_LOGIN_QUERY); + + bool res = true; + + // NOTE: all fields in `characters` must be read to prevent lost character data at next save in case wrong DB structure. + // !!! NOTE: including unused `zone`,`online` + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags," + "position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost," + "resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty," + "arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, todayKills, yesterdayKills, chosenTitle, knownCurrencies, watchedFaction, drunk," + "health, power1, power2, power3, power4, power5, power6, power7, instance_id, speccount, activespec, exploredZones, equipmentCache, ammoId, knownTitles, actionBars FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT guid FROM group_member WHERE memberGuid =%u", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_mask,recalculate_mask,stackcount,amount0,amount1,amount2,base_amount0,base_amount1,base_amount2,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLS, "SELECT spell,active,disabled FROM character_spell WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS, "SELECT quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4 FROM character_queststatus WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS,"SELECT quest,time FROM character_queststatus_daily WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADWEKLYQUESTSTATUS,"SELECT quest FROM character_queststatus_weekly WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADREPUTATION, "SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, "SELECT data,text,bag,slot,item,item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag,slot", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, "SELECT a.button,a.action,a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activespec AND a.guid = '%u' ORDER BY button", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = '%u' AND (checked & 1)=0 AND deliver_time <= '" UI64FMTD "'", GUID_LOPART(m_guid),(uint64)time(NULL)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = '%u' AND (checked & 1)=0", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSOCIALLIST, "SELECT friend,flags,note FROM character_social WHERE guid = '%u' LIMIT 255", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADHOMEBIND, "SELECT map,zone,position_x,position_y,position_z FROM character_homebind WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS, "SELECT spell,item,time FROM character_spell_cooldown WHERE guid = '%u'", GUID_LOPART(m_guid)); + if (sWorld.getConfig(CONFIG_DECLINED_NAMES_USED)) + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = '%u'",GUID_LOPART(m_guid)); + // in other case still be dummy query + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGUILD, "SELECT guildid,rank FROM guild_member WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADARENAINFO, "SELECT arenateamid, played_week, played_season, wons_season, personal_rating FROM arena_team_member WHERE guid='%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS, "SELECT achievement, date FROM character_achievement WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS,"SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, item0, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE guid = '%u' ORDER BY setindex", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBGDATA, "SELECT instance_id, team, join_x, join_y, join_z, join_o, join_map, taxi_start, taxi_end, mount_spell FROM character_battleground_data WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGLYPHS, "SELECT spec, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6 FROM character_glyphs WHERE guid='%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADTALENTS, "SELECT spell, spec FROM character_talent WHERE guid='%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA, "SELECT type, time, data FROM character_account_data WHERE guid='%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADRANDOMBG, "SELECT guid FROM character_battleground_random WHERE guid = '%u'", GUID_LOPART(m_guid)); + + return res; +} + +// don't call WorldSession directly +// it may get deleted before the query callbacks get executed +// instead pass an account id to this handler +class CharacterHandler +{ + + public: + void HandleCharEnumCallback(QueryResult_AutoPtr result, uint32 account) + { + WorldSession * session = sWorld.FindSession(account); + if (!session) + return; + session->HandleCharEnum(result); + } + void HandlePlayerLoginCallback(QueryResult_AutoPtr /*dummy*/, SqlQueryHolder * holder) + { + if (!holder) return; + WorldSession *session = sWorld.FindSession(((LoginQueryHolder*)holder)->GetAccountId()); + if (!session) + { + delete holder; + return; + } + session->HandlePlayerLogin((LoginQueryHolder*)holder); + } +} chrHandler; + +void WorldSession::HandleCharEnum(QueryResult_AutoPtr result) +{ + WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size + + uint8 num = 0; + + data << num; + + if (result) + { + do + { + uint32 guidlow = (*result)[0].GetUInt32(); + sLog.outDetail("Loading char guid %u from account %u.",guidlow,GetAccountId()); + if (Player::BuildEnumData(result, &data)) + ++num; + } + while (result->NextRow()); + } + + data.put(0, num); + + SendPacket(&data); +} + +void WorldSession::HandleCharEnumOpcode(WorldPacket & /*recv_data*/) +{ + /// get all the data necessary for loading all characters (along with their pets) on the account + CharacterDatabase.AsyncPQuery(&chrHandler, &CharacterHandler::HandleCharEnumCallback, GetAccountId(), + !sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) ? + // ------- Query Without Declined Names -------- + // 0 1 2 3 4 5 6 7 + "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, " + // 8 9 10 11 12 13 14 + "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, " + // 15 16 17 18 19 + "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.equipmentCache " + "FROM characters LEFT JOIN character_pet ON characters.guid=character_pet.owner AND character_pet.slot='%u' " + "LEFT JOIN guild_member ON characters.guid = guild_member.guid " + "WHERE characters.account = '%u' ORDER BY characters.guid" + : + // --------- Query With Declined Names --------- + // 0 1 2 3 4 5 6 7 + "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, " + // 8 9 10 11 12 13 14 + "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, " + // 15 16 17 18 19 20 + "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.equipmentCache, character_declinedname.genitive " + "FROM characters LEFT JOIN character_pet ON characters.guid = character_pet.owner AND character_pet.slot='%u' " + "LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid " + "LEFT JOIN guild_member ON characters.guid = guild_member.guid " + "WHERE characters.account = '%u' ORDER BY characters.guid", + PET_SAVE_AS_CURRENT,GetAccountId()); +} + +void WorldSession::HandleCharCreateOpcode(WorldPacket & recv_data) +{ + std::string name; + uint8 race_,class_; + + recv_data >> name; + + recv_data >> race_; + recv_data >> class_; + + WorldPacket data(SMSG_CHAR_CREATE, 1); // returned with diff.values in all cases + + if (GetSecurity() == SEC_PLAYER) + { + if (uint32 mask = sWorld.getConfig(CONFIG_CHARACTERS_CREATING_DISABLED)) + { + bool disabled = false; + + uint32 team = Player::TeamForRace(race_); + switch(team) + { + case ALLIANCE: disabled = mask & (1<<0); break; + case HORDE: disabled = mask & (1<<1); break; + } + + if (disabled) + { + data << (uint8)CHAR_CREATE_DISABLED; + SendPacket(&data); + return; + } + } + } + + ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(class_); + ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race_); + + if (!classEntry || !raceEntry) + { + data << (uint8)CHAR_CREATE_FAILED; + SendPacket(&data); + sLog.outError("Class: %u or Race %u not found in DBC (Wrong DBC files?) or Cheater?", class_, race_); + return; + } + + // prevent character creating Expansion race without Expansion account + if (raceEntry->expansion > Expansion()) + { + data << (uint8)CHAR_CREATE_EXPANSION; + sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u race (%u)",Expansion(),GetAccountId(),raceEntry->expansion,race_); + SendPacket(&data); + return; + } + + // prevent character creating Expansion class without Expansion account + if (classEntry->expansion > Expansion()) + { + data << (uint8)CHAR_CREATE_EXPANSION_CLASS; + sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u class (%u)",Expansion(),GetAccountId(),classEntry->expansion,class_); + SendPacket(&data); + return; + } + + // prevent character creating with invalid name + if (!normalizePlayerName(name)) + { + data << (uint8)CHAR_NAME_NO_NAME; + SendPacket(&data); + sLog.outError("Account:[%d] but tried to Create character with empty [name] ",GetAccountId()); + return; + } + + // check name limitations + uint8 res = ObjectMgr::CheckPlayerName(name,true); + if (res != CHAR_NAME_SUCCESS) + { + data << uint8(res); + SendPacket(&data); + return; + } + + if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(name)) + { + data << (uint8)CHAR_NAME_RESERVED; + SendPacket(&data); + return; + } + + if (objmgr.GetPlayerGUIDByName(name)) + { + data << (uint8)CHAR_CREATE_NAME_IN_USE; + SendPacket(&data); + return; + } + + QueryResult_AutoPtr resultacct = LoginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'", GetAccountId()); + if (resultacct) + { + Field *fields=resultacct->Fetch(); + uint32 acctcharcount = fields[0].GetUInt32(); + + if (acctcharcount >= sWorld.getConfig(CONFIG_CHARACTERS_PER_ACCOUNT)) + { + data << (uint8)CHAR_CREATE_ACCOUNT_LIMIT; + SendPacket(&data); + return; + } + } + + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE account = '%d'", GetAccountId()); + uint8 charcount = 0; + if (result) + { + Field *fields=result->Fetch(); + charcount = fields[0].GetUInt8(); + + if (charcount >= sWorld.getConfig(CONFIG_CHARACTERS_PER_REALM)) + { + data << (uint8)CHAR_CREATE_SERVER_LIMIT; + SendPacket(&data); + return; + } + } + + // speedup check for heroic class disabled case + uint32 heroic_free_slots = sWorld.getConfig(CONFIG_HEROIC_CHARACTERS_PER_REALM); + if (heroic_free_slots == 0 && GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT) + { + data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT; + SendPacket(&data); + return; + } + + // speedup check for heroic class disabled case + uint32 req_level_for_heroic = sWorld.getConfig(CONFIG_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING); + if (GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && req_level_for_heroic > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT; + SendPacket(&data); + return; + } + + bool AllowTwoSideAccounts = !sWorld.IsPvPRealm() || sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || GetSecurity() > SEC_PLAYER; + uint32 skipCinematics = sWorld.getConfig(CONFIG_SKIP_CINEMATICS); + + bool have_same_race = false; + + // if 0 then allowed creating without any characters + bool have_req_level_for_heroic = (req_level_for_heroic == 0); + + if (!AllowTwoSideAccounts || skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT) + { + QueryResult_AutoPtr result2 = CharacterDatabase.PQuery("SELECT level,race,class FROM characters WHERE account = '%u' %s", + GetAccountId(), (skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT) ? "" : "LIMIT 1"); + if (result2) + { + uint32 team_= Player::TeamForRace(race_); + + Field* field = result2->Fetch(); + uint8 acc_race = field[1].GetUInt32(); + + if (GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT) + { + uint8 acc_class = field[2].GetUInt32(); + if (acc_class == CLASS_DEATH_KNIGHT) + { + if (heroic_free_slots > 0) + --heroic_free_slots; + + if (heroic_free_slots == 0) + { + data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT; + SendPacket(&data); + return; + } + } + + if (!have_req_level_for_heroic) + { + uint32 acc_level = field[0].GetUInt32(); + if (acc_level >= req_level_for_heroic) + have_req_level_for_heroic = true; + } + } + + // need to check team only for first character + // TODO: what to if account already has characters of both races? + if (!AllowTwoSideAccounts) + { + uint32 acc_team=0; + if (acc_race > 0) + acc_team = Player::TeamForRace(acc_race); + + if (acc_team != team_) + { + data << (uint8)CHAR_CREATE_PVP_TEAMS_VIOLATION; + SendPacket(&data); + return; + } + } + + // search same race for cinematic or same class if need + // TODO: check if cinematic already shown? (already logged in?; cinematic field) + while ((skipCinematics == 1 && !have_same_race) || class_ == CLASS_DEATH_KNIGHT) + { + if (!result2->NextRow()) + break; + + field = result2->Fetch(); + acc_race = field[1].GetUInt32(); + + if (!have_same_race) + have_same_race = race_ == acc_race; + + if (GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT) + { + uint8 acc_class = field[2].GetUInt32(); + if (acc_class == CLASS_DEATH_KNIGHT) + { + if (heroic_free_slots > 0) + --heroic_free_slots; + + if (heroic_free_slots == 0) + { + data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT; + SendPacket(&data); + return; + } + } + + if (!have_req_level_for_heroic) + { + uint32 acc_level = field[0].GetUInt32(); + if (acc_level >= req_level_for_heroic) + have_req_level_for_heroic = true; + } + } + } + } + } + + if (GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && !have_req_level_for_heroic) + { + data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT; + SendPacket(&data); + return; + } + + // extract other data required for player creating + uint8 gender, skin, face, hairStyle, hairColor, facialHair, outfitId; + recv_data >> gender >> skin >> face; + recv_data >> hairStyle >> hairColor >> facialHair >> outfitId; + + if (recv_data.rpos() < recv_data.wpos()) + { + uint8 unk; + recv_data >> unk; + sLog.outDebug("Character creation %s (account %u) has unhandled tail data: [%u]", name.c_str(), GetAccountId(), unk); + } + + Player * pNewChar = new Player(this); + if (!pNewChar->Create(objmgr.GenerateLowGuid(HIGHGUID_PLAYER), name, race_, class_, gender, skin, face, hairStyle, hairColor, facialHair, outfitId)) + { + // Player not create (race/class problem?) + pNewChar->CleanupsBeforeDelete(); + delete pNewChar; + + data << (uint8)CHAR_CREATE_ERROR; + SendPacket(&data); + + return; + } + + if ((have_same_race && skipCinematics == 1) || skipCinematics == 2) + pNewChar->setCinematic(1); // not show intro + + pNewChar->SetAtLoginFlag(AT_LOGIN_FIRST); // First login + + // Player created, save it now + pNewChar->SaveToDB(); + charcount+=1; + + LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", GetAccountId(), realmID); + LoginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charcount, GetAccountId(), realmID); + + pNewChar->CleanupsBeforeDelete(); + + data << (uint8)CHAR_CREATE_SUCCESS; + SendPacket(&data); + + std::string IP_str = GetRemoteAddress(); + sLog.outBasic("Account: %d (IP: %s) Create Character:[%s] (GUID: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), pNewChar->GetGUIDLow()); + sLog.outChar("Account: %d (IP: %s) Create Character:[%s] (GUID: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), pNewChar->GetGUIDLow()); + delete pNewChar; // created only to call SaveToDB() + +} + +void WorldSession::HandleCharDeleteOpcode(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + + // can't delete loaded character + if (objmgr.GetPlayer(guid)) + return; + + uint32 accountId = 0; + std::string name; + + // is guild leader + if (objmgr.GetGuildByLeader(guid)) + { + WorldPacket data(SMSG_CHAR_DELETE, 1); + data << (uint8)CHAR_DELETE_FAILED_GUILD_LEADER; + SendPacket(&data); + return; + } + + // is arena team captain + if (objmgr.GetArenaTeamByCaptain(guid)) + { + WorldPacket data(SMSG_CHAR_DELETE, 1); + data << (uint8)CHAR_DELETE_FAILED_ARENA_CAPTAIN; + SendPacket(&data); + return; + } + + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT account,name FROM characters WHERE guid='%u'", GUID_LOPART(guid)); + if (result) + { + Field *fields = result->Fetch(); + accountId = fields[0].GetUInt32(); + name = fields[1].GetCppString(); + } + + // prevent deleting other players' characters using cheating tools + if (accountId != GetAccountId()) + return; + + std::string IP_str = GetRemoteAddress(); + sLog.outDetail("Account: %d (IP: %s) Delete Character:[%s] (GUID: %u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid)); + sLog.outChar("Account: %d (IP: %s) Delete Character:[%s] (GUID: %u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid)); + + if (sLog.IsOutCharDump()) // optimize GetPlayerDump call + { + std::string dump = PlayerDumpWriter().GetDump(GUID_LOPART(guid)); + sLog.outCharDump(dump.c_str(),GetAccountId(),GUID_LOPART(guid),name.c_str()); + } + + Player::DeleteFromDB(guid, GetAccountId()); + + WorldPacket data(SMSG_CHAR_DELETE, 1); + data << (uint8)CHAR_DELETE_SUCCESS; + SendPacket(&data); +} + +void WorldSession::HandlePlayerLoginOpcode(WorldPacket & recv_data) +{ + if (PlayerLoading() || GetPlayer() != NULL) + { + sLog.outError("Player tryes to login again, AccountId = %d",GetAccountId()); + return; + } + + m_playerLoading = true; + uint64 playerGuid = 0; + + DEBUG_LOG("WORLD: Recvd Player Logon Message"); + + recv_data >> playerGuid; + + LoginQueryHolder *holder = new LoginQueryHolder(GetAccountId(), playerGuid); + if (!holder->Initialize()) + { + delete holder; // delete all unprocessed queries + m_playerLoading = false; + return; + } + + CharacterDatabase.DelayQueryHolder(&chrHandler, &CharacterHandler::HandlePlayerLoginCallback, holder); +} + +void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) +{ + uint64 playerGuid = holder->GetGuid(); + + Player* pCurrChar = new Player(this); + // for send server info and strings (config) + ChatHandler chH = ChatHandler(pCurrChar); + + // "GetAccountId() == db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools) + if (!pCurrChar->LoadFromDB(GUID_LOPART(playerGuid), holder)) + { + KickPlayer(); // disconnect client, player no set to session and it will not deleted or saved at kick + delete pCurrChar; // delete it manually + delete holder; // delete all unprocessed queries + m_playerLoading = false; + return; + } + + pCurrChar->GetMotionMaster()->Initialize(); + + SetPlayer(pCurrChar); + + pCurrChar->SendDungeonDifficulty(false); + + WorldPacket data(SMSG_LOGIN_VERIFY_WORLD, 20); + data << pCurrChar->GetMapId(); + data << pCurrChar->GetPositionX(); + data << pCurrChar->GetPositionY(); + data << pCurrChar->GetPositionZ(); + data << pCurrChar->GetOrientation(); + SendPacket(&data); + + // load player specific part before send times + LoadAccountData(holder->GetResult(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA),PER_CHARACTER_CACHE_MASK); + SendAccountDataTimes(PER_CHARACTER_CACHE_MASK); + + data.Initialize(SMSG_FEATURE_SYSTEM_STATUS, 2); // added in 2.2.0 + data << uint8(2); // unknown value + data << uint8(0); // enable(1)/disable(0) voice chat interface in client + SendPacket(&data); + + // Send MOTD + { + data.Initialize(SMSG_MOTD, 50); // new in 2.0.1 + data << (uint32)0; + + uint32 linecount=0; + std::string str_motd = sWorld.GetMotd(); + std::string::size_type pos, nextpos; + + pos = 0; + while ((nextpos= str_motd.find('@',pos)) != std::string::npos) + { + if (nextpos != pos) + { + data << str_motd.substr(pos,nextpos-pos); + ++linecount; + } + pos = nextpos+1; + } + + if (posGetGUIDLow()); + QueryResult_AutoPtr resultGuild = holder->GetResult(PLAYER_LOGIN_QUERY_LOADGUILD); + + if (resultGuild) + { + Field *fields = resultGuild->Fetch(); + pCurrChar->SetInGuild(fields[0].GetUInt32()); + pCurrChar->SetRank(fields[1].GetUInt32()); + } + else if (pCurrChar->GetGuildId()) // clear guild related fields in case wrong data about non existed membership + { + pCurrChar->SetInGuild(0); + pCurrChar->SetRank(0); + } + + if (pCurrChar->GetGuildId() != 0) + { + Guild* guild = objmgr.GetGuildById(pCurrChar->GetGuildId()); + if (guild) + { + data.Initialize(SMSG_GUILD_EVENT, (1+1+guild->GetMOTD().size()+1)); + data << uint8(GE_MOTD); + data << uint8(1); + data << guild->GetMOTD(); + SendPacket(&data); + DEBUG_LOG("WORLD: Sent guild-motd (SMSG_GUILD_EVENT)"); + + guild->DisplayGuildBankTabsInfo(this); + + guild->BroadcastEvent(GE_SIGNED_ON, pCurrChar->GetGUID(), 1, pCurrChar->GetName(), "", ""); + } + else + { + // remove wrong guild data + sLog.outError("Player %s (GUID: %u) marked as member not existed guild (id: %u), removing guild membership for player.",pCurrChar->GetName(),pCurrChar->GetGUIDLow(),pCurrChar->GetGuildId()); + pCurrChar->SetInGuild(0); + } + } + + data.Initialize(SMSG_LEARNED_DANCE_MOVES, 4+4); + data << uint32(0); + data << uint32(0); + SendPacket(&data); + + pCurrChar->SendInitialPacketsBeforeAddToMap(); + + //Show cinematic at the first time that player login + if (!pCurrChar->getCinematic()) + { + pCurrChar->setCinematic(1); + + if (ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(pCurrChar->getClass())) + { + if (cEntry->CinematicSequence) + pCurrChar->SendCinematicStart(cEntry->CinematicSequence); + else if (ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(pCurrChar->getRace())) + pCurrChar->SendCinematicStart(rEntry->CinematicSequence); + + // send new char string if not empty + if (!sWorld.GetNewCharString().empty()) + chH.PSendSysMessage(sWorld.GetNewCharString().c_str()); + } + } + + if (!pCurrChar->GetMap()->Add(pCurrChar) || !pCurrChar->CheckInstanceLoginValid()) + { + AreaTrigger const* at = objmgr.GetGoBackTrigger(pCurrChar->GetMapId()); + if (at) + pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation()); + else + pCurrChar->TeleportTo(pCurrChar->m_homebindMapId, pCurrChar->m_homebindX, pCurrChar->m_homebindY, pCurrChar->m_homebindZ, pCurrChar->GetOrientation()); + } + + ObjectAccessor::Instance().AddObject(pCurrChar); + //sLog.outDebug("Player %s added to Map.",pCurrChar->GetName()); + + pCurrChar->SendInitialPacketsAfterAddToMap(); + + CharacterDatabase.PExecute("UPDATE characters SET online = 1 WHERE guid = '%u'", pCurrChar->GetGUIDLow()); + LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = '%u'", GetAccountId()); + pCurrChar->SetInGameTime(getMSTime()); + + // announce group about member online (must be after add to player list to receive announce to self) + if (Group *group = pCurrChar->GetGroup()) + { + //pCurrChar->groupInfo.group->SendInit(this); // useless + group->SendUpdate(); + group->ResetMaxEnchantingLevel(); + } + + // friend status + sSocialMgr.SendFriendStatus(pCurrChar, FRIEND_ONLINE, pCurrChar->GetGUIDLow(), true); + + // Place character in world (and load zone) before some object loading + pCurrChar->LoadCorpse(); + + // setting Ghost+speed if dead + if (pCurrChar->m_deathState != ALIVE) + { + // not blizz like, we must correctly save and load player instead... + if (pCurrChar->getRace() == RACE_NIGHTELF) + pCurrChar->CastSpell(pCurrChar, 20584, true, 0);// auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form) + pCurrChar->CastSpell(pCurrChar, 8326, true, 0); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?) + + pCurrChar->SetMovement(MOVE_WATER_WALK); + } + + pCurrChar->ContinueTaxiFlight(); + + // reset for all pets before pet loading + if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) + Pet::resetTalentsForAllPetsOf(pCurrChar); + + // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned) + pCurrChar->LoadPet(); + + // Set FFA PvP for non GM in non-rest mode + if (sWorld.IsFFAPvPRealm() && !pCurrChar->isGameMaster() && !pCurrChar->HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_RESTING)) + pCurrChar->SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); + + if (pCurrChar->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP)) + pCurrChar->SetContestedPvP(); + + // Apply at_login requests + if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_SPELLS)) + { + pCurrChar->resetSpells(); + SendNotification(LANG_RESET_SPELLS); + } + + if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS)) + { + pCurrChar->resetTalents(true); + pCurrChar->SendTalentsInfoData(false); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state + SendNotification(LANG_RESET_TALENTS); + } + + if (pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST)) + pCurrChar->RemoveAtLoginFlag(AT_LOGIN_FIRST); + + // show time before shutdown if shutdown planned. + if (sWorld.IsShutdowning()) + sWorld.ShutdownMsg(true,pCurrChar); + + if (sWorld.getConfig(CONFIG_ALL_TAXI_PATHS)) + pCurrChar->SetTaxiCheater(true); + + if (pCurrChar->isGameMaster()) + SendNotification(LANG_GM_ON); + + std::string IP_str = GetRemoteAddress(); + sLog.outChar("Account: %d (IP: %s) Login Character:[%s] (GUID: %u)", + GetAccountId(),IP_str.c_str(),pCurrChar->GetName() ,pCurrChar->GetGUIDLow()); + + if (!pCurrChar->IsStandState() && !pCurrChar->hasUnitState(UNIT_STAT_STUNNED)) + pCurrChar->SetStandState(UNIT_STAND_STATE_STAND); + + m_playerLoading = false; + + //Hook for OnLogin Event + sScriptMgr.OnLogin(pCurrChar); + delete holder; +} + +void WorldSession::HandleSetFactionAtWar(WorldPacket & recv_data) +{ + DEBUG_LOG("WORLD: Received CMSG_SET_FACTION_ATWAR"); + + uint32 repListID; + uint8 flag; + + recv_data >> repListID; + recv_data >> flag; + + GetPlayer()->GetReputationMgr().SetAtWar(repListID,flag); +} + +//I think this function is never used :/ I dunno, but i guess this opcode not exists +void WorldSession::HandleSetFactionCheat(WorldPacket & /*recv_data*/) +{ + sLog.outError("WORLD SESSION: HandleSetFactionCheat, not expected call, please report."); + /* + uint32 FactionID; + uint32 Standing; + + recv_data >> FactionID; + recv_data >> Standing; + + std::list::iterator itr; + + for (itr = GetPlayer()->factions.begin(); itr != GetPlayer()->factions.end(); ++itr) + { + if (itr->ReputationListID == FactionID) + { + itr->Standing += Standing; + itr->Flags = (itr->Flags | 1); + break; + } + } + */ + GetPlayer()->GetReputationMgr().SendStates(); +} + +void WorldSession::HandleMeetingStoneInfo(WorldPacket & /*recv_data*/) +{ + DEBUG_LOG("WORLD: Received CMSG_MEETING_STONE_INFO"); + + //SendLfgUpdate(0, 0, 0); +} + +void WorldSession::HandleTutorialFlag(WorldPacket & recv_data) +{ + uint32 iFlag; + recv_data >> iFlag; + + uint32 wInt = (iFlag / 32); + if (wInt >= 8) + { + //sLog.outError("CHEATER? Account:[%d] Guid[%u] tried to send wrong CMSG_TUTORIAL_FLAG", GetAccountId(),GetGUID()); + return; + } + uint32 rInt = (iFlag % 32); + + uint32 tutflag = GetTutorialInt(wInt); + tutflag |= (1 << rInt); + SetTutorialInt(wInt, tutflag); + + //sLog.outDebug("Received Tutorial Flag Set {%u}.", iFlag); +} + +void WorldSession::HandleTutorialClear(WorldPacket & /*recv_data*/) +{ + for (int i = 0; i < 8; ++i) + SetTutorialInt(i, 0xFFFFFFFF); +} + +void WorldSession::HandleTutorialReset(WorldPacket & /*recv_data*/) +{ + for (int i = 0; i < 8; ++i) + SetTutorialInt(i, 0x00000000); +} + +void WorldSession::HandleSetWatchedFactionOpcode(WorldPacket & recv_data) +{ + DEBUG_LOG("WORLD: Received CMSG_SET_WATCHED_FACTION"); + uint32 fact; + recv_data >> fact; + GetPlayer()->SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fact); +} + +void WorldSession::HandleSetFactionInactiveOpcode(WorldPacket & recv_data) +{ + DEBUG_LOG("WORLD: Received CMSG_SET_FACTION_INACTIVE"); + uint32 replistid; + uint8 inactive; + recv_data >> replistid >> inactive; + + _player->GetReputationMgr().SetInactive(replistid, inactive); +} + +void WorldSession::HandleShowingHelmOpcode(WorldPacket & /*recv_data*/) +{ + DEBUG_LOG("CMSG_SHOWING_HELM for %s", _player->GetName()); + _player->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM); +} + +void WorldSession::HandleShowingCloakOpcode(WorldPacket & /*recv_data*/) +{ + DEBUG_LOG("CMSG_SHOWING_CLOAK for %s", _player->GetName()); + _player->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK); +} + +void WorldSession::HandleCharRenameOpcode(WorldPacket& recv_data) +{ + uint64 guid; + std::string newname; + + recv_data >> guid; + recv_data >> newname; + + // prevent character rename to invalid name + if (!normalizePlayerName(newname)) + { + WorldPacket data(SMSG_CHAR_RENAME, 1); + data << uint8(CHAR_NAME_NO_NAME); + SendPacket(&data); + return; + } + + uint8 res = ObjectMgr::CheckPlayerName(newname,true); + if (res != CHAR_NAME_SUCCESS) + { + WorldPacket data(SMSG_CHAR_RENAME, 1); + data << uint8(res); + SendPacket(&data); + return; + } + + // check name limitations + if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname)) + { + WorldPacket data(SMSG_CHAR_RENAME, 1); + data << uint8(CHAR_NAME_RESERVED); + SendPacket(&data); + return; + } + + std::string escaped_newname = newname; + CharacterDatabase.escape_string(escaped_newname); + + // make sure that the character belongs to the current account, that rename at login is enabled + // and that there is no character with the desired new name + CharacterDatabase.AsyncPQuery(&WorldSession::HandleChangePlayerNameOpcodeCallBack, + GetAccountId(), newname, + "SELECT guid, name FROM characters WHERE guid = %d AND account = %d AND (at_login & %d) = %d AND NOT EXISTS (SELECT NULL FROM characters WHERE name = '%s')", + GUID_LOPART(guid), GetAccountId(), AT_LOGIN_RENAME, AT_LOGIN_RENAME, escaped_newname.c_str() +); +} + +void WorldSession::HandleChangePlayerNameOpcodeCallBack(QueryResult_AutoPtr result, uint32 accountId, std::string newname) +{ + WorldSession * session = sWorld.FindSession(accountId); + if (!session) + return; + + if (!result) + { + WorldPacket data(SMSG_CHAR_RENAME, 1); + data << uint8(CHAR_CREATE_ERROR); + session->SendPacket(&data); + return; + } + + uint32 guidLow = result->Fetch()[0].GetUInt32(); + uint64 guid = MAKE_NEW_GUID(guidLow, 0, HIGHGUID_PLAYER); + std::string oldname = result->Fetch()[1].GetCppString(); + + CharacterDatabase.PExecute("UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'", newname.c_str(), uint32(AT_LOGIN_RENAME), guidLow); + CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid ='%u'", guidLow); + + sLog.outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s", session->GetAccountId(), session->GetRemoteAddress().c_str(), oldname.c_str(), guidLow, newname.c_str()); + + WorldPacket data(SMSG_CHAR_RENAME, 1+8+(newname.size()+1)); + data << uint8(RESPONSE_SUCCESS); + data << uint64(guid); + data << newname; + session->SendPacket(&data); +} + +void WorldSession::HandleSetPlayerDeclinedNames(WorldPacket& recv_data) +{ + uint64 guid; + + recv_data >> guid; + + // not accept declined names for unsupported languages + std::string name; + if (!objmgr.GetPlayerNameByGUID(guid, name)) + { + WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); + data << uint32(1); + data << uint64(guid); + SendPacket(&data); + return; + } + + std::wstring wname; + if (!Utf8toWStr(name, wname)) + { + WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); + data << uint32(1); + data << uint64(guid); + SendPacket(&data); + return; + } + + if (!isCyrillicCharacter(wname[0])) // name already stored as only single alphabet using + { + WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); + data << uint32(1); + data << uint64(guid); + SendPacket(&data); + return; + } + + std::string name2; + DeclinedName declinedname; + + recv_data >> name2; + + if (name2 != name) // character have different name + { + WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); + data << uint32(1); + data << uint64(guid); + SendPacket(&data); + return; + } + + for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + { + recv_data >> declinedname.name[i]; + if (!normalizePlayerName(declinedname.name[i])) + { + WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); + data << uint32(1); + data << uint64(guid); + SendPacket(&data); + return; + } + } + + if (!ObjectMgr::CheckDeclinedNames(GetMainPartOfName(wname, 0), declinedname)) + { + WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); + data << uint32(1); + data << uint64(guid); + SendPacket(&data); + return; + } + + for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + CharacterDatabase.escape_string(declinedname.name[i]); + + CharacterDatabase.BeginTransaction(); + CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid = '%u'", GUID_LOPART(guid)); + CharacterDatabase.PExecute("INSERT INTO character_declinedname (guid, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u','%s','%s','%s','%s','%s')", + GUID_LOPART(guid), declinedname.name[0].c_str(), declinedname.name[1].c_str(), declinedname.name[2].c_str(), declinedname.name[3].c_str(), declinedname.name[4].c_str()); + CharacterDatabase.CommitTransaction(); + + WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); + data << uint32(0); // OK + data << uint64(guid); + SendPacket(&data); +} + +void WorldSession::HandleAlterAppearance(WorldPacket & recv_data) +{ + sLog.outDebug("CMSG_ALTER_APPEARANCE"); + + uint32 Hair, Color, FacialHair, SkinColor; + recv_data >> Hair >> Color >> FacialHair >> SkinColor; + + BarberShopStyleEntry const* bs_hair = sBarberShopStyleStore.LookupEntry(Hair); + + if (!bs_hair || bs_hair->type != 0 || bs_hair->race != _player->getRace() || bs_hair->gender != _player->getGender()) + return; + + BarberShopStyleEntry const* bs_facialHair = sBarberShopStyleStore.LookupEntry(FacialHair); + + if (!bs_facialHair || bs_facialHair->type != 2 || bs_facialHair->race != _player->getRace() || bs_facialHair->gender != _player->getGender()) + return; + + BarberShopStyleEntry const* bs_skinColor = sBarberShopStyleStore.LookupEntry(SkinColor); + + if (bs_skinColor && (bs_skinColor->type != 3 || bs_skinColor->race != _player->getRace() || bs_skinColor->gender != _player->getGender())) + return; + + uint32 Cost = _player->GetBarberShopCost(bs_hair->hair_id, Color, bs_facialHair->hair_id, bs_skinColor); + + // 0 - ok + // 1,3 - not enough money + // 2 - you have to seat on barber chair + if (_player->GetMoney() < Cost) + { + WorldPacket data(SMSG_BARBER_SHOP_RESULT, 4); + data << uint32(1); // no money + SendPacket(&data); + return; + } + else + { + WorldPacket data(SMSG_BARBER_SHOP_RESULT, 4); + data << uint32(0); // ok + SendPacket(&data); + } + + _player->ModifyMoney(-int32(Cost)); // it isn't free + _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER, Cost); + + _player->SetByteValue(PLAYER_BYTES, 2, uint8(bs_hair->hair_id)); + _player->SetByteValue(PLAYER_BYTES, 3, uint8(Color)); + _player->SetByteValue(PLAYER_BYTES_2, 0, uint8(bs_facialHair->hair_id)); + if (bs_skinColor) + _player->SetByteValue(PLAYER_BYTES, 0, uint8(bs_skinColor->hair_id)); + + _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP, 1); + + _player->SetStandState(0); // stand up +} + +void WorldSession::HandleRemoveGlyph(WorldPacket & recv_data) +{ + uint32 slot; + recv_data >> slot; + + if (slot >= MAX_GLYPH_SLOT_INDEX) + { + sLog.outDebug("Client sent wrong glyph slot number in opcode CMSG_REMOVE_GLYPH %u", slot); + return; + } + + if (uint32 glyph = _player->GetGlyph(slot)) + { + if (GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph)) + { + _player->RemoveAurasDueToSpell(gp->SpellId); + _player->SetGlyph(slot, 0); + _player->SendTalentsInfoData(false); + } + } +} + +void WorldSession::HandleCharCustomize(WorldPacket& recv_data) +{ + uint64 guid; + std::string newname; + + recv_data >> guid; + recv_data >> newname; + + uint8 gender, skin, face, hairStyle, hairColor, facialHair; + recv_data >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face; + + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT at_login FROM characters WHERE guid ='%u'", GUID_LOPART(guid)); + if (!result) + { + WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); + data << uint8(CHAR_CREATE_ERROR); + SendPacket(&data); + return; + } + + Field *fields = result->Fetch(); + uint32 at_loginFlags = fields[0].GetUInt32(); + + if (!(at_loginFlags & AT_LOGIN_CUSTOMIZE)) + { + WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); + data << uint8(CHAR_CREATE_ERROR); + SendPacket(&data); + return; + } + + // prevent character rename to invalid name + if (!normalizePlayerName(newname)) + { + WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); + data << uint8(CHAR_NAME_NO_NAME); + SendPacket(&data); + return; + } + + uint8 res = ObjectMgr::CheckPlayerName(newname,true); + if (res != CHAR_NAME_SUCCESS) + { + WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); + data << uint8(res); + SendPacket(&data); + return; + } + + // check name limitations + if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname)) + { + WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); + data << uint8(CHAR_NAME_RESERVED); + SendPacket(&data); + return; + } + + // character with this name already exist + if (uint64 newguid = objmgr.GetPlayerGUIDByName(newname)) + { + if (newguid != guid) + { + WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); + data << uint8(CHAR_CREATE_NAME_IN_USE); + SendPacket(&data); + return; + } + } + + CharacterDatabase.escape_string(newname); + if (QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT name FROM characters WHERE guid ='%u'", GUID_LOPART(guid))) + { + std::string oldname = result->Fetch()[0].GetCppString(); + std::string IP_str = GetRemoteAddress(); + sLog.outChar("Account: %d (IP: %s), Character[%s] (guid:%u) Customized to: %s", GetAccountId(), IP_str.c_str(), oldname.c_str(), GUID_LOPART(guid), newname.c_str()); + } + Player::Customize(guid, gender, skin, face, hairStyle, hairColor, facialHair); + CharacterDatabase.PExecute("UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'", newname.c_str(), uint32(AT_LOGIN_CUSTOMIZE), GUID_LOPART(guid)); + CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid ='%u'", GUID_LOPART(guid)); + + WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1+8+(newname.size()+1)+6); + data << uint8(RESPONSE_SUCCESS); + data << uint64(guid); + data << newname; + data << uint8(gender); + data << uint8(skin); + data << uint8(face); + data << uint8(hairStyle); + data << uint8(hairColor); + data << uint8(facialHair); + SendPacket(&data); +} + +void WorldSession::HandleEquipmentSetSave(WorldPacket &recv_data) +{ + sLog.outDebug("CMSG_EQUIPMENT_SET_SAVE"); + + uint64 setGuid; + if (!recv_data.readPackGUID(setGuid)) + return; + + uint32 index; + recv_data >> index; + if (index >= MAX_EQUIPMENT_SET_INDEX) // client set slots amount + return; + + std::string name; + recv_data >> name; + + std::string iconName; + recv_data >> iconName; + + EquipmentSet eqSet; + + eqSet.Guid = setGuid; + eqSet.Name = name; + eqSet.IconName = iconName; + eqSet.state = EQUIPMENT_SET_NEW; + + for (uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) + { + uint64 itemGuid; + if (!recv_data.readPackGUID(itemGuid)) + return; + + Item *item = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + + if (!item && itemGuid) // cheating check 1 + return; + + if (item && item->GetGUID() != itemGuid) // cheating check 2 + return; + + eqSet.Items[i] = GUID_LOPART(itemGuid); + } + + _player->SetEquipmentSet(index, eqSet); +} + +void WorldSession::HandleEquipmentSetDelete(WorldPacket &recv_data) +{ + sLog.outDebug("CMSG_EQUIPMENT_SET_DELETE"); + + uint64 setGuid; + if (!recv_data.readPackGUID(setGuid)) + return; + + _player->DeleteEquipmentSet(setGuid); +} + +void WorldSession::HandleEquipmentSetUse(WorldPacket &recv_data) +{ + sLog.outDebug("CMSG_EQUIPMENT_SET_USE"); + recv_data.hexlike(); + + for (uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) + { + uint64 itemGuid; + if (!recv_data.readPackGUID(itemGuid)) + return; + + uint8 srcbag, srcslot; + recv_data >> srcbag >> srcslot; + + sLog.outDebug("Item " UI64FMTD ": srcbag %u, srcslot %u", itemGuid, srcbag, srcslot); + + Item *item = _player->GetItemByGuid(itemGuid); + + uint16 dstpos = i | (INVENTORY_SLOT_BAG_0 << 8); + + if (!item) + { + Item *uItem = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + if (!uItem) + continue; + + ItemPosCountVec sDest; + uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sDest, uItem, false); + if (msg == EQUIP_ERR_OK) + { + _player->RemoveItem(INVENTORY_SLOT_BAG_0, i, true); + _player->StoreItem(sDest, uItem, true); + } + else + _player->SendEquipError(msg, uItem, NULL); + + continue; + } + + if (item->GetPos() == dstpos) + continue; + + _player->SwapItem(item->GetPos(), dstpos); + } + + WorldPacket data(SMSG_EQUIPMENT_SET_USE_RESULT, 1); + data << uint8(0); // 4 - equipment swap failed - inventory is full + SendPacket(&data); +} + +void WorldSession::HandleOnPVPKill(Player *killed) +{ + sScriptMgr.OnPVPKill(GetPlayer(), killed); +} + +bool WorldSession::HandleOnPlayerChat(const char *text) +{ + return sScriptMgr.OnPlayerChat(GetPlayer(), text); +} + +uint32 WorldSession::HandleOnGetXP(uint32 amount) +{ + return sScriptMgr.OnGetXP(GetPlayer(), amount); +} + +int32 WorldSession::HandleOnGetMoney(int32 amount) +{ + return sScriptMgr.OnGetMoney(GetPlayer(), amount); +} + +void WorldSession::HandleOnAreaChange(AreaTableEntry const *pArea) +{ + sScriptMgr.OnAreaChange(GetPlayer(), pArea); +} + +bool WorldSession::HandleOnItemClick(Item *pItem) +{ + return sScriptMgr.OnItemClick(GetPlayer(), pItem); +} + +bool WorldSession::HandleOnItemOpen(Item *pItem) +{ + return sScriptMgr.OnItemOpen(GetPlayer(), pItem); +} + +bool WorldSession::HandleOnGoClick(GameObject *pGameObject) +{ + return sScriptMgr.OnGoClick(GetPlayer(), pGameObject); +} + +void WorldSession::HandleOnCreatureKill(Creature *pCreature) +{ + sScriptMgr.OnCreatureKill(GetPlayer(), pCreature); +} diff --git a/src/server/game/Server/Protocol/Handlers/ChatHandler.cpp b/src/server/game/Server/Protocol/Handlers/ChatHandler.cpp new file mode 100644 index 00000000000..88e2b5473a5 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/ChatHandler.cpp @@ -0,0 +1,756 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "World.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Database/DatabaseEnv.h" + +#include "CellImpl.h" +#include "Chat.h" +#include "ChannelMgr.h" +#include "GridNotifiersImpl.h" +#include "Group.h" +#include "Guild.h" +#include "Language.h" +#include "Log.h" +#include "Opcodes.h" +#include "Player.h" +#include "SpellAuras.h" +#include "SpellAuraEffects.h" +#include "Util.h" + +bool WorldSession::processChatmessageFurtherAfterSecurityChecks(std::string& msg, uint32 lang) +{ + if (lang != LANG_ADDON) + { + // strip invisible characters for non-addon messages + if (sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) + stripLineInvisibleChars(msg); + + if (sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) && GetSecurity() < SEC_MODERATOR + && !ChatHandler(this).isValidChatMessage(msg.c_str())) + { + sLog.outError("Player %s (GUID: %u) sent a chatmessage with an invalid link: %s", GetPlayer()->GetName(), + GetPlayer()->GetGUIDLow(), msg.c_str()); + if (sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK)) + KickPlayer(); + return false; + } + } + + return true; +} + +void WorldSession::HandleMessagechatOpcode(WorldPacket & recv_data) +{ + uint32 type; + uint32 lang; + + recv_data >> type; + recv_data >> lang; + + if (type >= MAX_CHAT_MSG_TYPE) + { + sLog.outError("CHAT: Wrong message type received: %u", type); + return; + } + + //sLog.outDebug("CHAT: packet received. type %u, lang %u", type, lang); + + // prevent talking at unknown language (cheating) + LanguageDesc const* langDesc = GetLanguageDescByID(lang); + if (!langDesc) + { + SendNotification(LANG_UNKNOWN_LANGUAGE); + return; + } + if (langDesc->skill_id != 0 && !_player->HasSkill(langDesc->skill_id)) + { + // also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language) + Unit::AuraEffectList const& langAuras = _player->GetAuraEffectsByType(SPELL_AURA_COMPREHEND_LANGUAGE); + bool foundAura = false; + for (Unit::AuraEffectList::const_iterator i = langAuras.begin(); i != langAuras.end(); ++i) + { + if ((*i)->GetMiscValue() == int32(lang)) + { + foundAura = true; + break; + } + } + if (!foundAura) + { + SendNotification(LANG_NOT_LEARNED_LANGUAGE); + return; + } + } + + if (lang == LANG_ADDON) + { + if (sWorld.getConfig(CONFIG_CHATLOG_ADDON)) + { + std::string msg = ""; + recv_data >> msg; + + if (msg.empty()) + { + sLog.outDebug("Player %s send empty addon msg", GetPlayer()->GetName()); + return; + } + + sLog.outChat("[ADDON] Player %s sends: %s", + GetPlayer()->GetName(), msg.c_str()); + } + + // Disabled addon channel? + if (!sWorld.getConfig(CONFIG_ADDON_CHANNEL)) + return; + } + // LANG_ADDON should not be changed nor be affected by flood control + else + { + // send in universal language if player in .gmon mode (ignore spell effects) + if (_player->isGameMaster()) + lang = LANG_UNIVERSAL; + else + { + // send in universal language in two side iteration allowed mode + if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT)) + lang = LANG_UNIVERSAL; + else + { + switch(type) + { + case CHAT_MSG_PARTY: + case CHAT_MSG_RAID: + case CHAT_MSG_RAID_LEADER: + case CHAT_MSG_RAID_WARNING: + // allow two side chat at group channel if two side group allowed + if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP)) + lang = LANG_UNIVERSAL; + break; + case CHAT_MSG_GUILD: + case CHAT_MSG_OFFICER: + // allow two side chat at guild channel if two side guild allowed + if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) + lang = LANG_UNIVERSAL; + break; + } + } + + // but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used) + Unit::AuraEffectList const& ModLangAuras = _player->GetAuraEffectsByType(SPELL_AURA_MOD_LANGUAGE); + if (!ModLangAuras.empty()) + lang = ModLangAuras.front()->GetMiscValue(); + } + + if (!_player->CanSpeak()) + { + std::string timeStr = secsToTimeString(m_muteTime - time(NULL)); + SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING),timeStr.c_str()); + return; + } + + if (type != CHAT_MSG_AFK && type != CHAT_MSG_DND) + GetPlayer()->UpdateSpeakTime(); + } + + if (GetPlayer()->HasAura(1852) && type != CHAT_MSG_WHISPER) + { + std::string msg=""; + recv_data >> msg; + + SendNotification(GetTrinityString(LANG_GM_SILENCE), GetPlayer()->GetName()); + return; + } + + switch(type) + { + case CHAT_MSG_SAY: + case CHAT_MSG_EMOTE: + case CHAT_MSG_YELL: + { + std::string msg; + recv_data >> msg; + + if (msg.empty()) + break; + + if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) + break; + + if (_player->getLevel() < sWorld.getConfig(CONFIG_CHAT_SAY_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_SAY_REQ), sWorld.getConfig(CONFIG_CHAT_SAY_LEVEL_REQ)); + return; + } + + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; + + if (msg.empty()) + break; + + if (type == CHAT_MSG_SAY) + GetPlayer()->Say(msg, lang); + else if (type == CHAT_MSG_EMOTE) + GetPlayer()->TextEmote(msg); + else if (type == CHAT_MSG_YELL) + GetPlayer()->Yell(msg, lang); + } break; + + case CHAT_MSG_WHISPER: + { + std::string to, msg; + recv_data >> to; + recv_data >> msg; + + if (_player->getLevel() < sWorld.getConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_WHISPER_REQ), sWorld.getConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ)); + return; + } + + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; + + if (msg.empty()) + break; + + if (!normalizePlayerName(to)) + { + SendPlayerNotFoundNotice(to); + break; + } + + Player *player = objmgr.GetPlayer(to.c_str()); + uint32 tSecurity = GetSecurity(); + uint32 pSecurity = player ? player->GetSession()->GetSecurity() : SEC_PLAYER; + if (!player || (tSecurity == SEC_PLAYER && pSecurity > SEC_PLAYER && !player->isAcceptWhispers())) + { + SendPlayerNotFoundNotice(to); + return; + } + + if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT) && tSecurity == SEC_PLAYER && pSecurity == SEC_PLAYER) + { + uint32 sidea = GetPlayer()->GetTeam(); + uint32 sideb = player->GetTeam(); + if (sidea != sideb) + { + SendWrongFactionNotice(); + return; + } + } + + if (GetPlayer()->HasAura(1852) && !player->isGameMaster()) + { + SendNotification(GetTrinityString(LANG_GM_SILENCE), GetPlayer()->GetName()); + return; + } + + GetPlayer()->Whisper(msg, lang, player->GetGUID()); + } break; + + case CHAT_MSG_PARTY: + case CHAT_MSG_PARTY_LEADER: + { + std::string msg; + recv_data >> msg; + + if (msg.empty()) + break; + + if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) + break; + + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; + + if (msg.empty()) + break; + + // if player is in battleground, he cannot say to battleground members by /p + Group *group = GetPlayer()->GetOriginalGroup(); + if (!group) + { + group = _player->GetGroup(); + if (!group || group->isBGGroup()) + return; + } + + if ((type == CHAT_MSG_PARTY_LEADER) && !group->IsLeader(_player->GetGUID())) + return; + + WorldPacket data; + ChatHandler::FillMessageData(&data, this, type, lang, NULL, 0, msg.c_str(), NULL); + group->BroadcastPacket(&data, false, group->GetMemberGroup(GetPlayer()->GetGUID())); + + if (sWorld.getConfig(CONFIG_CHATLOG_PARTY)) + sLog.outChat("[PARTY] Player %s tells group with leader %s: %s", + GetPlayer()->GetName(), group->GetLeaderName(), msg.c_str()); + } break; + + case CHAT_MSG_GUILD: + { + std::string msg; + recv_data >> msg; + + if (msg.empty()) + break; + + if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) + break; + + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; + + if (msg.empty()) + break; + + if (GetPlayer()->GetGuildId()) + { + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + + if (guild) + guild->BroadcastToGuild(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); + + if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHATLOG_GUILD)) + { + sLog.outChat("[GUILD] Player %s tells guild %s: %s", + GetPlayer()->GetName(), guild->GetName().c_str(), msg.c_str()); + } + else if (lang == LANG_ADDON && sWorld.getConfig(CONFIG_CHATLOG_ADDON)) + { + sLog.outChat("[ADDON] Player %s sends to guild %s: %s", + GetPlayer()->GetName(), guild->GetName().c_str(), msg.c_str()); + } + } + + break; + } + case CHAT_MSG_OFFICER: + { + std::string msg; + recv_data >> msg; + + if (msg.empty()) + break; + + if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) + break; + + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; + + if (msg.empty()) + break; + + if (GetPlayer()->GetGuildId()) + { + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + + if (guild) + guild->BroadcastToOfficers(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); + + if (sWorld.getConfig(CONFIG_CHATLOG_GUILD)) + sLog.outChat("[OFFICER] Player %s tells guild %s officers: %s", + GetPlayer()->GetName(), guild->GetName().c_str(), msg.c_str()); + } + break; + } + case CHAT_MSG_RAID: + { + std::string msg; + recv_data >> msg; + + if (msg.empty()) + break; + + if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) + break; + + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; + + if (msg.empty()) + break; + + // if player is in battleground, he cannot say to battleground members by /ra + Group *group = GetPlayer()->GetOriginalGroup(); + if (!group) + { + group = GetPlayer()->GetGroup(); + if (!group || group->isBGGroup() || !group->isRaidGroup()) + return; + } + + WorldPacket data; + ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, "", 0, msg.c_str(), NULL); + group->BroadcastPacket(&data, false); + + if (sWorld.getConfig(CONFIG_CHATLOG_RAID)) + sLog.outChat("[RAID] Player %s tells raid with leader %s: %s", + GetPlayer()->GetName(), group->GetLeaderName(), msg.c_str()); + } break; + case CHAT_MSG_RAID_LEADER: + { + std::string msg; + recv_data >> msg; + + if (msg.empty()) + break; + + if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) + break; + + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; + + if (msg.empty()) + break; + + // if player is in battleground, he cannot say to battleground members by /ra + Group *group = GetPlayer()->GetOriginalGroup(); + if (!group) + { + group = GetPlayer()->GetGroup(); + if (!group || group->isBGGroup() || !group->isRaidGroup() || !group->IsLeader(_player->GetGUID())) + return; + } + + WorldPacket data; + ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, "", 0, msg.c_str(), NULL); + group->BroadcastPacket(&data, false); + + if (sWorld.getConfig(CONFIG_CHATLOG_RAID)) + sLog.outChat("[RAID] Leader player %s tells raid: %s", + GetPlayer()->GetName(), msg.c_str()); + } break; + case CHAT_MSG_RAID_WARNING: + { + std::string msg; + recv_data >> msg; + + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; + + if (msg.empty()) + break; + + Group *group = GetPlayer()->GetGroup(); + if (!group || !group->isRaidGroup() || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())) || group->isBGGroup()) + return; + + WorldPacket data; + //in battleground, raid warning is sent only to players in battleground - code is ok + ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, "", 0, msg.c_str(), NULL); + group->BroadcastPacket(&data, false); + + if (sWorld.getConfig(CONFIG_CHATLOG_RAID)) + sLog.outChat("[RAID] Leader player %s warns raid with: %s", + GetPlayer()->GetName(), msg.c_str()); + } break; + + case CHAT_MSG_BATTLEGROUND: + { + std::string msg; + recv_data >> msg; + + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; + + if (msg.empty()) + break; + + //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() + Group *group = GetPlayer()->GetGroup(); + if (!group || !group->isBGGroup()) + return; + + WorldPacket data; + ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, "", 0, msg.c_str(), NULL); + group->BroadcastPacket(&data, false); + + if (sWorld.getConfig(CONFIG_CHATLOG_BGROUND)) + sLog.outChat("[BATTLEGROUND] Player %s tells battleground with leader %s: %s", + GetPlayer()->GetName(), group->GetLeaderName(), msg.c_str()); + } break; + + case CHAT_MSG_BATTLEGROUND_LEADER: + { + std::string msg; + recv_data >> msg; + + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; + + if (msg.empty()) + break; + + // battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() + Group *group = GetPlayer()->GetGroup(); + if (!group || !group->isBGGroup() || !group->IsLeader(GetPlayer()->GetGUID())) + return; + + WorldPacket data; + ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, "", 0, msg.c_str(), NULL); + group->BroadcastPacket(&data, false); + + if (sWorld.getConfig(CONFIG_CHATLOG_BGROUND)) + sLog.outChat("[RAID] Leader player %s tells battleground: %s", + GetPlayer()->GetName(), msg.c_str()); + } break; + + case CHAT_MSG_CHANNEL: + { + std::string channel, msg; + recv_data >> channel; + recv_data >> msg; + + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; + + if (_player->getLevel() < sWorld.getConfig(CONFIG_CHAT_CHANNEL_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_CHANNEL_REQ), sWorld.getConfig(CONFIG_CHAT_CHANNEL_LEVEL_REQ)); + return; + } + + if (msg.empty()) + break; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + { + + if (Channel *chn = cMgr->GetChannel(channel, _player)) + { + chn->Say(_player->GetGUID(), msg.c_str(), lang); + + if ((chn->HasFlag(CHANNEL_FLAG_TRADE) || + chn->HasFlag(CHANNEL_FLAG_GENERAL) || + chn->HasFlag(CHANNEL_FLAG_CITY) || + chn->HasFlag(CHANNEL_FLAG_LFG)) && + sWorld.getConfig(CONFIG_CHATLOG_SYSCHAN)) + sLog.outChat("[SYSCHAN] Player %s tells channel %s: %s", + GetPlayer()->GetName(), chn->GetName().c_str(), msg.c_str()); + else if (sWorld.getConfig(CONFIG_CHATLOG_CHANNEL)) + sLog.outChat("[CHANNEL] Player %s tells channel %s: %s", + GetPlayer()->GetName(), chn->GetName().c_str(), msg.c_str()); + } + } + } break; + + case CHAT_MSG_AFK: + { + std::string msg; + recv_data >> msg; + + if ((msg.empty() || !_player->isAFK()) && !_player->isInCombat()) + { + if (!_player->isAFK()) + { + if (msg.empty()) + msg = GetTrinityString(LANG_PLAYER_AFK_DEFAULT); + _player->afkMsg = msg; + } + _player->ToggleAFK(); + if (_player->isAFK() && _player->isDND()) + _player->ToggleDND(); + } + } break; + + case CHAT_MSG_DND: + { + std::string msg; + recv_data >> msg; + + if (msg.empty() || !_player->isDND()) + { + if (!_player->isDND()) + { + if (msg.empty()) + msg = GetTrinityString(LANG_PLAYER_DND_DEFAULT); + _player->dndMsg = msg; + } + _player->ToggleDND(); + if (_player->isDND() && _player->isAFK()) + _player->ToggleAFK(); + } + } break; + + default: + sLog.outError("CHAT: unknown message type %u, lang: %u", type, lang); + break; + } +} + +void WorldSession::HandleEmoteOpcode(WorldPacket & recv_data) +{ + if (!GetPlayer()->isAlive()) + return; + + uint32 emote; + recv_data >> emote; + GetPlayer()->HandleEmoteCommand(emote); +} + +namespace Trinity +{ + class EmoteChatBuilder + { + public: + EmoteChatBuilder(Player const& pl, uint32 text_emote, uint32 emote_num, Unit const* target) + : i_player(pl), i_text_emote(text_emote), i_emote_num(emote_num), i_target(target) {} + + void operator()(WorldPacket& data, int32 loc_idx) + { + char const* nam = i_target ? i_target->GetNameForLocaleIdx(loc_idx) : NULL; + uint32 namlen = (nam ? strlen(nam) : 0) + 1; + + data.Initialize(SMSG_TEXT_EMOTE, (20+namlen)); + data << i_player.GetGUID(); + data << (uint32)i_text_emote; + data << i_emote_num; + data << (uint32)namlen; + if (namlen > 1) + data.append(nam, namlen); + else + data << (uint8)0x00; + } + + private: + Player const& i_player; + uint32 i_text_emote; + uint32 i_emote_num; + Unit const* i_target; + }; +} // namespace Trinity + +void WorldSession::HandleTextEmoteOpcode(WorldPacket & recv_data) +{ + if (!GetPlayer()->isAlive()) + return; + + if (!GetPlayer()->CanSpeak()) + { + std::string timeStr = secsToTimeString(m_muteTime - time(NULL)); + SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING),timeStr.c_str()); + return; + } + + uint32 text_emote, emoteNum; + uint64 guid; + + recv_data >> text_emote; + recv_data >> emoteNum; + recv_data >> guid; + + EmotesTextEntry const *em = sEmotesTextStore.LookupEntry(text_emote); + if (!em) + return; + + uint32 emote_anim = em->textid; + + switch(emote_anim) + { + case EMOTE_STATE_SLEEP: + case EMOTE_STATE_SIT: + case EMOTE_STATE_KNEEL: + case EMOTE_ONESHOT_NONE: + break; + default: + GetPlayer()->HandleEmoteCommand(emote_anim); + break; + } + + Unit* unit = ObjectAccessor::GetUnit(*_player, guid); + + CellPair p = Trinity::ComputeCellPair(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY()); + + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + Trinity::EmoteChatBuilder emote_builder(*GetPlayer(), text_emote, emoteNum, unit); + Trinity::LocalizedPacketDo emote_do(emote_builder); + Trinity::PlayerDistWorker > emote_worker(GetPlayer(), sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), emote_do); + TypeContainerVisitor >, WorldTypeMapContainer> message(emote_worker); + cell.Visit(p, message, *GetPlayer()->GetMap(), *GetPlayer(), sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE)); + + GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit); + + //Send scripted event call + if (unit && unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->AI()) + ((Creature*)unit)->AI()->ReceiveEmote(GetPlayer(), text_emote); +} + +void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data) +{ + uint64 iguid; + uint8 unk; + //sLog.outDebug("WORLD: Received CMSG_CHAT_IGNORED"); + + recv_data >> iguid; + recv_data >> unk; // probably related to spam reporting + + Player *player = objmgr.GetPlayer(iguid); + if (!player || !player->GetSession()) + return; + + WorldPacket data; + ChatHandler::FillMessageData(&data, this, CHAT_MSG_IGNORED, LANG_UNIVERSAL, NULL, GetPlayer()->GetGUID(), GetPlayer()->GetName(), NULL); + player->GetSession()->SendPacket(&data); +} + +void WorldSession::HandleChannelDeclineInvite(WorldPacket &recvPacket) +{ + sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); +} + +void WorldSession::SendPlayerNotFoundNotice(std::string name) +{ + WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, name.size()+1); + data << name; + SendPacket(&data); +} + +void WorldSession::SendPlayerAmbiguousNotice(std::string name) +{ + WorldPacket data(SMSG_CHAT_PLAYER_AMBIGUOUS, name.size()+1); + data << name; + SendPacket(&data); +} + +void WorldSession::SendWrongFactionNotice() +{ + WorldPacket data(SMSG_CHAT_WRONG_FACTION, 0); + SendPacket(&data); +} + +void WorldSession::SendChatRestrictedNotice(ChatRestrictionType restriction) +{ + WorldPacket data(SMSG_CHAT_RESTRICTED, 1); + data << uint8(restriction); + SendPacket(&data); +} diff --git a/src/server/game/Server/Protocol/Handlers/CombatHandler.cpp b/src/server/game/Server/Protocol/Handlers/CombatHandler.cpp new file mode 100644 index 00000000000..404b70c1c84 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/CombatHandler.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Log.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "ObjectAccessor.h" +#include "CreatureAI.h" +#include "ObjectDefines.h" + +void WorldSession::HandleAttackSwingOpcode(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + + DEBUG_LOG("WORLD: Recvd CMSG_ATTACKSWING Message guidlow:%u guidhigh:%u", GUID_LOPART(guid), GUID_HIPART(guid)); + + Unit *pEnemy = ObjectAccessor::GetUnit(*_player, guid); + + if (!pEnemy) + { + if (!IS_UNIT_GUID(guid)) + sLog.outError("WORLD: Object %u (TypeID: %u) isn't player, pet or creature",GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(guid))); + else + sLog.outError("WORLD: Enemy %s %u not found",GetLogNameForGuid(guid),GUID_LOPART(guid)); + + // stop attack state at client + SendAttackStop(NULL); + return; + } + + if (!_player->canAttack(pEnemy)) + { + sLog.outError("WORLD: Enemy %s %u is friendly",(IS_PLAYER_GUID(guid) ? "player" : "creature"),GUID_LOPART(guid)); + + // stop attack state at client + SendAttackStop(pEnemy); + return; + } + + _player->Attack(pEnemy,true); +} + +void WorldSession::HandleAttackStopOpcode(WorldPacket & /*recv_data*/) +{ + GetPlayer()->AttackStop(); +} + +void WorldSession::HandleSetSheathedOpcode(WorldPacket & recv_data) +{ + uint32 sheathed; + recv_data >> sheathed; + + //sLog.outDebug("WORLD: Recvd CMSG_SETSHEATHED Message guidlow:%u value1:%u", GetPlayer()->GetGUIDLow(), sheathed); + + if (sheathed >= MAX_SHEATH_STATE) + { + sLog.outError("Unknown sheath state %u ??",sheathed); + return; + } + + GetPlayer()->SetSheath(SheathState(sheathed)); +} + +void WorldSession::SendAttackStop(Unit const* enemy) +{ + WorldPacket data(SMSG_ATTACKSTOP, (4+20)); // we guess size + data.append(GetPlayer()->GetPackGUID()); + data.append(enemy ? enemy->GetPackGUID() : 0); // must be packed guid + data << uint32(0); // unk, can be 1 also + SendPacket(&data); +} + diff --git a/src/server/game/Server/Protocol/Handlers/DuelHandler.cpp b/src/server/game/Server/Protocol/Handlers/DuelHandler.cpp new file mode 100644 index 00000000000..99c8a774b03 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/DuelHandler.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Log.h" +#include "Opcodes.h" +#include "UpdateData.h" +#include "Player.h" + +void WorldSession::HandleDuelAcceptedOpcode(WorldPacket& recvPacket) +{ + uint64 guid; + Player *pl; + Player *plTarget; + + if (!GetPlayer()->duel) // ignore accept from duel-sender + return; + + recvPacket >> guid; + + pl = GetPlayer(); + plTarget = pl->duel->opponent; + + if (pl == pl->duel->initiator || !plTarget || pl == plTarget || pl->duel->startTime != 0 || plTarget->duel->startTime != 0) + return; + + //sLog.outDebug("WORLD: received CMSG_DUEL_ACCEPTED"); + DEBUG_LOG("Player 1 is: %u (%s)", pl->GetGUIDLow(),pl->GetName()); + DEBUG_LOG("Player 2 is: %u (%s)", plTarget->GetGUIDLow(),plTarget->GetName()); + + time_t now = time(NULL); + pl->duel->startTimer = now; + plTarget->duel->startTimer = now; + + pl->SendDuelCountdown(3000); + plTarget->SendDuelCountdown(3000); +} + +void WorldSession::HandleDuelCancelledOpcode(WorldPacket& recvPacket) +{ + //sLog.outDebug("WORLD: received CMSG_DUEL_CANCELLED"); + + // no duel requested + if (!GetPlayer()->duel) + return; + + // player surrendered in a duel using /forfeit + if (GetPlayer()->duel->startTime != 0) + { + GetPlayer()->CombatStopWithPets(true); + if (GetPlayer()->duel->opponent) + GetPlayer()->duel->opponent->CombatStopWithPets(true); + + GetPlayer()->CastSpell(GetPlayer(), 7267, true); // beg + GetPlayer()->DuelComplete(DUEL_WON); + return; + } + + // player either discarded the duel using the "discard button" + // or used "/forfeit" before countdown reached 0 + uint64 guid; + recvPacket >> guid; + + GetPlayer()->DuelComplete(DUEL_INTERUPTED); +} diff --git a/src/server/game/Server/Protocol/Handlers/GroupHandler.cpp b/src/server/game/Server/Protocol/Handlers/GroupHandler.cpp new file mode 100644 index 00000000000..f973bc24722 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/GroupHandler.cpp @@ -0,0 +1,940 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "Opcodes.h" +#include "Log.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "Group.h" +#include "SocialMgr.h" +#include "Util.h" +#include "SpellAuras.h" +#include "Vehicle.h" +#include "LFG.h" + +class Aura; + +/* differeces from off: + -you can uninvite yourself - is is useful + -you can accept invitation even if leader went offline +*/ +/* todo: + -group_destroyed msg is sent but not shown + -reduce xp gaining when in raid group + -quest sharing has to be corrected + -FIX sending PartyMemberStats +*/ + +void WorldSession::SendPartyResult(PartyOperation operation, const std::string& member, PartyResult res) +{ + WorldPacket data(SMSG_PARTY_COMMAND_RESULT, (4+member.size()+1+4+4)); + data << (uint32)operation; + data << member; + data << (uint32)res; + data << uint32(0); // LFD cooldown related (used with ERR_PARTY_LFG_BOOT_COOLDOWN_S and ERR_PARTY_LFG_BOOT_NOT_ELIGIBLE_S) + + SendPacket(&data); +} + +void WorldSession::HandleGroupInviteOpcode(WorldPacket & recv_data) +{ + std::string membername; + recv_data >> membername; + + // attempt add selected player + + // cheating + if (!normalizePlayerName(membername)) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_BAD_PLAYER_NAME_S); + return; + } + + Player *player = objmgr.GetPlayer(membername.c_str()); + + // no player + if (!player) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_BAD_PLAYER_NAME_S); + return; + } + + // restrict invite to GMs + if (!sWorld.getConfig(CONFIG_ALLOW_GM_GROUP) && !GetPlayer()->isGameMaster() && player->isGameMaster()) + return; + + // can't group with + if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && GetPlayer()->GetTeam() != player->GetTeam()) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_PLAYER_WRONG_FACTION); + return; + } + if (GetPlayer()->GetInstanceId() != 0 && player->GetInstanceId() != 0 && GetPlayer()->GetInstanceId() != player->GetInstanceId() && GetPlayer()->GetMapId() == player->GetMapId()) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_TARGET_NOT_IN_INSTANCE_S); + return; + } + // just ignore us + if (player->GetInstanceId() != 0 && player->GetDungeonDifficulty() != GetPlayer()->GetDungeonDifficulty()) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_IGNORING_YOU_S); + return; + } + + if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_IGNORING_YOU_S); + return; + } + + Group *group = GetPlayer()->GetGroup(); + if (group && group->isBGGroup()) + group = GetPlayer()->GetOriginalGroup(); + + Group *group2 = player->GetGroup(); + if (group2 && group2->isBGGroup()) + group2 = player->GetOriginalGroup(); + // player already in another group or invited + if (group2 || player->GetGroupInvite()) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_ALREADY_IN_GROUP_S); + return; + } + + if (group) + { + // not have permissions for invite + if (group->isRaidGroup() && !group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) + { + SendPartyResult(PARTY_OP_INVITE, "", ERR_NOT_LEADER); + return; + } + // not have place + if (group->IsFull()) + { + SendPartyResult(PARTY_OP_INVITE, "", ERR_GROUP_FULL); + return; + } + } + + // ok, but group not exist, start a new group + // but don't create and save the group to the DB until + // at least one person joins + if (!group) + { + group = new Group; + // new group: if can't add then delete + if (!group->AddLeaderInvite(GetPlayer())) + { + delete group; + return; + } + if (!group->AddInvite(player)) + { + delete group; + return; + } + } + else + { + // already existed group: if can't add then just leave + if (!group->AddInvite(player)) + { + return; + } + } + + // ok, we do it + WorldPacket data(SMSG_GROUP_INVITE, 10); // guess size + data << uint8(1); // invited/already in group flag + data << GetPlayer()->GetName(); // max len 48 + data << uint32(0); // unk + data << uint8(0); // count + //for (int i = 0; i < count; ++i) + // data << uint32(0); + data << uint32(0); // unk + player->GetSession()->SendPacket(&data); + + SendLfgUpdatePlayer(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); + SendLfgUpdateParty(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); + SendPartyResult(PARTY_OP_INVITE, membername, ERR_PARTY_RESULT_OK); +} + +void WorldSession::HandleGroupAcceptOpcode(WorldPacket & /*recv_data*/) +{ + Group *group = GetPlayer()->GetGroupInvite(); + if (!group) return; + + if (group->GetLeaderGUID() == GetPlayer()->GetGUID()) + { + sLog.outError("HandleGroupAcceptOpcode: player %s(%d) tried to accept an invite to his own group", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); + return; + } + + // remove in from ivites in any case + group->RemoveInvite(GetPlayer()); + + /** error handling **/ + /********************/ + + // not have place + if (group->IsFull()) + { + SendPartyResult(PARTY_OP_INVITE, "", ERR_GROUP_FULL); + return; + } + + Player* leader = objmgr.GetPlayer(group->GetLeaderGUID()); + + // forming a new group, create it + if (!group->IsCreated()) + { + if (leader) + group->RemoveInvite(leader); + group->Create(group->GetLeaderGUID(), group->GetLeaderName()); + objmgr.AddGroup(group); + } + + // everything's fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!! + if (!group->AddMember(GetPlayer()->GetGUID(), GetPlayer()->GetName())) + return; + + SendLfgUpdatePlayer(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); + for (GroupReference *itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + if (Player *plrg = itr->getSource()) + { + plrg->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_CLEAR_LOCK_LIST); + plrg->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_CLEAR_LOCK_LIST); + } + + group->BroadcastGroupUpdate(); +} + +void WorldSession::HandleGroupDeclineOpcode(WorldPacket & /*recv_data*/) +{ + Group *group = GetPlayer()->GetGroupInvite(); + if (!group) return; + + // remember leader if online + Player *leader = objmgr.GetPlayer(group->GetLeaderGUID()); + + // uninvite, group can be deleted + GetPlayer()->UninviteFromGroup(); + + if (!leader || !leader->GetSession()) + return; + + // report + WorldPacket data(SMSG_GROUP_DECLINE, 10); // guess size + data << GetPlayer()->GetName(); + leader->GetSession()->SendPacket(&data); +} + +void WorldSession::HandleGroupUninviteGuidOpcode(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + recv_data.read_skip(); // reason + + //can't uninvite yourself + if (guid == GetPlayer()->GetGUID()) + { + sLog.outError("WorldSession::HandleGroupUninviteGuidOpcode: leader %s(%d) tried to uninvite himself from the group.", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); + return; + } + + PartyResult res = GetPlayer()->CanUninviteFromGroup(); + if (res != ERR_PARTY_RESULT_OK) + { + SendPartyResult(PARTY_OP_UNINVITE, "", res); + return; + } + + Group* grp = GetPlayer()->GetGroup(); + if (!grp) + return; + + if (grp->IsMember(guid)) + { + Player::RemoveFromGroup(grp,guid); + return; + } + + if (Player* plr = grp->GetInvited(guid)) + { + plr->UninviteFromGroup(); + return; + } + + SendPartyResult(PARTY_OP_UNINVITE, "", ERR_TARGET_NOT_IN_GROUP_S); +} + +void WorldSession::HandleGroupUninviteOpcode(WorldPacket & recv_data) +{ + std::string membername; + recv_data >> membername; + + // player not found + if (!normalizePlayerName(membername)) + return; + + // can't uninvite yourself + if (GetPlayer()->GetName() == membername) + { + sLog.outError("WorldSession::HandleGroupUninviteOpcode: leader %s(%d) tried to uninvite himself from the group.", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); + return; + } + + PartyResult res = GetPlayer()->CanUninviteFromGroup(); + if (res != ERR_PARTY_RESULT_OK) + { + SendPartyResult(PARTY_OP_UNINVITE, "", res); + return; + } + + Group* grp = GetPlayer()->GetGroup(); + if (!grp) + return; + + if (uint64 guid = grp->GetMemberGUID(membername)) + { + Player::RemoveFromGroup(grp,guid); + return; + } + + if (Player* plr = grp->GetInvited(membername)) + { + plr->UninviteFromGroup(); + return; + } + + SendPartyResult(PARTY_OP_UNINVITE, membername, ERR_TARGET_NOT_IN_GROUP_S); +} + +void WorldSession::HandleGroupSetLeaderOpcode(WorldPacket & recv_data) +{ + Group *group = GetPlayer()->GetGroup(); + if (!group) + return; + + uint64 guid; + recv_data >> guid; + + Player *player = objmgr.GetPlayer(guid); + + /** error handling **/ + if (!player || !group->IsLeader(GetPlayer()->GetGUID()) || player->GetGroup() != group) + return; + /********************/ + + // everything's fine, do it + group->ChangeLeader(guid); +} + +void WorldSession::HandleGroupDisbandOpcode(WorldPacket & /*recv_data*/) +{ + if (!GetPlayer()->GetGroup()) + return; + + if (_player->InBattleGround()) + { + SendPartyResult(PARTY_OP_INVITE, "", ERR_INVITE_RESTRICTED); + return; + } + + /** error handling **/ + /********************/ + + // everything's fine, do it + SendPartyResult(PARTY_OP_LEAVE, GetPlayer()->GetName(), ERR_PARTY_RESULT_OK); + + GetPlayer()->RemoveFromGroup(); +} + +void WorldSession::HandleLootMethodOpcode(WorldPacket & recv_data) +{ + Group *group = GetPlayer()->GetGroup(); + if (!group) + return; + + uint32 lootMethod; + uint64 lootMaster; + uint32 lootThreshold; + recv_data >> lootMethod >> lootMaster >> lootThreshold; + + /** error handling **/ + if (!group->IsLeader(GetPlayer()->GetGUID())) + return; + /********************/ + + // everything's fine, do it + group->SetLootMethod((LootMethod)lootMethod); + group->SetLooterGuid(lootMaster); + group->SetLootThreshold((ItemQualities)lootThreshold); + group->SendUpdate(); +} + +void WorldSession::HandleLootRoll(WorldPacket &recv_data) +{ + if (!GetPlayer()->GetGroup()) + return; + + uint64 Guid; + uint32 NumberOfPlayers; + uint8 rollType; + recv_data >> Guid; //guid of the item rolled + recv_data >> NumberOfPlayers; + recv_data >> rollType; //0: pass, 1: need, 2: greed + + //sLog.outDebug("WORLD RECIEVE CMSG_LOOT_ROLL, From:%u, Numberofplayers:%u, Choise:%u", (uint32)Guid, NumberOfPlayers, Choise); + + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; + + // everything's fine, do it + group->CountRollVote(GetPlayer()->GetGUID(), Guid, NumberOfPlayers, rollType); + + switch (rollType) + { + case ROLL_NEED: + GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED, 1); + break; + case ROLL_GREED: + GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED, 1); + break; + } +} + +void WorldSession::HandleMinimapPingOpcode(WorldPacket& recv_data) +{ + if (!GetPlayer()->GetGroup()) + return; + + float x, y; + recv_data >> x; + recv_data >> y; + + //sLog.outDebug("Received opcode MSG_MINIMAP_PING X: %f, Y: %f", x, y); + + /** error handling **/ + /********************/ + + // everything's fine, do it + WorldPacket data(MSG_MINIMAP_PING, (8+4+4)); + data << uint64(GetPlayer()->GetGUID()); + data << float(x); + data << float(y); + GetPlayer()->GetGroup()->BroadcastPacket(&data, true, -1, GetPlayer()->GetGUID()); +} + +void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data) +{ + uint32 minimum, maximum, roll; + recv_data >> minimum; + recv_data >> maximum; + + /** error handling **/ + if (minimum > maximum || maximum > 10000) // < 32768 for urand call + return; + /********************/ + + // everything's fine, do it + roll = urand(minimum, maximum); + + //sLog.outDebug("ROLL: MIN: %u, MAX: %u, ROLL: %u", minimum, maximum, roll); + + WorldPacket data(MSG_RANDOM_ROLL, 4+4+4+8); + data << uint32(minimum); + data << uint32(maximum); + data << uint32(roll); + data << uint64(GetPlayer()->GetGUID()); + if (GetPlayer()->GetGroup()) + GetPlayer()->GetGroup()->BroadcastPacket(&data, false); + else + SendPacket(&data); +} + +void WorldSession::HandleRaidTargetUpdateOpcode(WorldPacket & recv_data) +{ + Group *group = GetPlayer()->GetGroup(); + if (!group) + return; + + uint8 x; + recv_data >> x; + + /** error handling **/ + /********************/ + + // everything's fine, do it + if (x == 0xFF) // target icon request + { + group->SendTargetIconList(this); + } + else // target icon update + { + if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) + return; + + uint64 guid; + recv_data >> guid; + group->SetTargetIcon(x, _player->GetGUID(), guid); + } +} + +void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket & /*recv_data*/) +{ + Group *group = GetPlayer()->GetGroup(); + if (!group) + return; + + if (_player->InBattleGround()) + return; + + /** error handling **/ + if (!group->IsLeader(GetPlayer()->GetGUID()) || group->GetMembersCount() < 2) + return; + /********************/ + + // everything's fine, do it (is it 0 (PARTY_OP_INVITE) correct code) + SendPartyResult(PARTY_OP_INVITE, "", ERR_PARTY_RESULT_OK); + group->ConvertToRaid(); +} + +void WorldSession::HandleGroupChangeSubGroupOpcode(WorldPacket & recv_data) +{ + // we will get correct pointer for group here, so we don't have to check if group is BG raid + Group *group = GetPlayer()->GetGroup(); + if (!group) + return; + + std::string name; + uint8 groupNr; + recv_data >> name; + + recv_data >> groupNr; + + /** error handling **/ + uint64 senderGuid = GetPlayer()->GetGUID(); + if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid)) + return; + + if (!group->HasFreeSlotSubGroup(groupNr)) + return; + /********************/ + + Player *movedPlayer=objmgr.GetPlayer(name.c_str()); + if (!movedPlayer) + return; + + //Do not allow leader to change group of player in combat + if (movedPlayer->isInCombat()) + return; + + // everything's fine, do it + group->ChangeMembersGroup(movedPlayer, groupNr); +} + +void WorldSession::HandleGroupAssistantLeaderOpcode(WorldPacket & recv_data) +{ + Group *group = GetPlayer()->GetGroup(); + if (!group) + return; + + uint64 guid; + uint8 flag; + recv_data >> guid; + recv_data >> flag; + + /** error handling **/ + if (!group->IsLeader(GetPlayer()->GetGUID())) + return; + /********************/ + + // everything's fine, do it + group->SetAssistant(guid, (flag != 0)); +} + +void WorldSession::HandlePartyAssignmentOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("MSG_PARTY_ASSIGNMENT"); + + Group *group = GetPlayer()->GetGroup(); + if (!group) + return; + + uint8 flag, apply; + uint64 guid; + recv_data >> flag >> apply; + recv_data >> guid; + + /** error handling **/ + uint64 senderGuid = GetPlayer()->GetGUID(); + if (!group->IsLeader(senderGuid) && group->IsAssistant(senderGuid)) + return; + /********************/ + + // everything's fine, do it + if (flag == 0) + group->SetMainTank(guid, apply); + + else if (flag == 1) + group->SetMainAssistant(guid, apply); +} + +void WorldSession::HandleRaidReadyCheckOpcode(WorldPacket & recv_data) +{ + Group *group = GetPlayer()->GetGroup(); + if (!group) + return; + + if (recv_data.empty()) // request + { + /** error handling **/ + if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) + return; + /********************/ + + // everything's fine, do it + WorldPacket data(MSG_RAID_READY_CHECK, 8); + data << GetPlayer()->GetGUID(); + group->BroadcastPacket(&data, false, -1); + + group->OfflineReadyCheck(); + } + else // answer + { + uint8 state; + recv_data >> state; + + // everything's fine, do it + WorldPacket data(MSG_RAID_READY_CHECK_CONFIRM, 9); + data << uint64(GetPlayer()->GetGUID()); + data << uint8(state); + group->BroadcastReadyCheck(&data); + } +} + +void WorldSession::HandleRaidReadyCheckFinishedOpcode(WorldPacket & /*recv_data*/) +{ + //Group* group = GetPlayer()->GetGroup(); + //if (!group) + // return; + + //if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) + // return; + + // Is any reaction need? +} + +void WorldSession::BuildPartyMemberStatsChangedPacket(Player *player, WorldPacket *data) +{ + uint32 mask = player->GetGroupUpdateFlag(); + + if (mask == GROUP_UPDATE_FLAG_NONE) + return; + + if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) // if update power type, update current/max power also + mask |= (GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER); + + if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) // same for pets + mask |= (GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER); + + uint32 byteCount = 0; + for (int i = 1; i < GROUP_UPDATE_FLAGS_COUNT; ++i) + if (mask & (1 << i)) + byteCount += GroupUpdateLength[i]; + + data->Initialize(SMSG_PARTY_MEMBER_STATS, 8 + 4 + byteCount); + data->append(player->GetPackGUID()); + *data << (uint32) mask; + + if (mask & GROUP_UPDATE_FLAG_STATUS) + { + if (player) + { + if (player->IsPvP()) + *data << (uint16) (MEMBER_STATUS_ONLINE | MEMBER_STATUS_PVP); + else + *data << (uint16) MEMBER_STATUS_ONLINE; + } + else + *data << (uint16) MEMBER_STATUS_OFFLINE; + } + + if (mask & GROUP_UPDATE_FLAG_CUR_HP) + *data << (uint32) player->GetHealth(); + + if (mask & GROUP_UPDATE_FLAG_MAX_HP) + *data << (uint32) player->GetMaxHealth(); + + Powers powerType = player->getPowerType(); + if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) + *data << (uint8) powerType; + + if (mask & GROUP_UPDATE_FLAG_CUR_POWER) + *data << (uint16) player->GetPower(powerType); + + if (mask & GROUP_UPDATE_FLAG_MAX_POWER) + *data << (uint16) player->GetMaxPower(powerType); + + if (mask & GROUP_UPDATE_FLAG_LEVEL) + *data << (uint16) player->getLevel(); + + if (mask & GROUP_UPDATE_FLAG_ZONE) + *data << (uint16) player->GetZoneId(); + + if (mask & GROUP_UPDATE_FLAG_POSITION) + *data << (uint16) player->GetPositionX() << (uint16) player->GetPositionY(); + + if (mask & GROUP_UPDATE_FLAG_AURAS) + { + const uint64& auramask = player->GetAuraUpdateMaskForRaid(); + *data << uint64(auramask); + for (uint32 i = 0; i < MAX_AURAS; ++i) + { + if (auramask & (uint64(1) << i)) + { + AuraApplication const * aurApp = player->GetVisibleAura(i); + *data << uint32(aurApp ? aurApp->GetBase()->GetId() : 0); + *data << uint8(1); + } + } + } + + Pet *pet = player->GetPet(); + if (mask & GROUP_UPDATE_FLAG_PET_GUID) + { + if (pet) + *data << (uint64) pet->GetGUID(); + else + *data << (uint64) 0; + } + + if (mask & GROUP_UPDATE_FLAG_PET_NAME) + { + if (pet) + *data << pet->GetName(); + else + *data << (uint8) 0; + } + + if (mask & GROUP_UPDATE_FLAG_PET_MODEL_ID) + { + if (pet) + *data << (uint16) pet->GetDisplayId(); + else + *data << (uint16) 0; + } + + if (mask & GROUP_UPDATE_FLAG_PET_CUR_HP) + { + if (pet) + *data << (uint32) pet->GetHealth(); + else + *data << (uint32) 0; + } + + if (mask & GROUP_UPDATE_FLAG_PET_MAX_HP) + { + if (pet) + *data << (uint32) pet->GetMaxHealth(); + else + *data << (uint32) 0; + } + + if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) + { + if (pet) + *data << (uint8) pet->getPowerType(); + else + *data << (uint8) 0; + } + + if (mask & GROUP_UPDATE_FLAG_PET_CUR_POWER) + { + if (pet) + *data << (uint16) pet->GetPower(pet->getPowerType()); + else + *data << (uint16) 0; + } + + if (mask & GROUP_UPDATE_FLAG_PET_MAX_POWER) + { + if (pet) + *data << (uint16) pet->GetMaxPower(pet->getPowerType()); + else + *data << (uint16) 0; + } + + if (mask & GROUP_UPDATE_FLAG_VEHICLE_SEAT) + { + if (player->GetVehicle()){ + Vehicle* vv=player->GetVehicle(); + *data << (uint32) vv->GetVehicleInfo()->m_seatID[player->m_movementInfo.t_seat]; + } + } + + if (mask & GROUP_UPDATE_FLAG_PET_AURAS) + { + if (pet) + { + const uint64& auramask = pet->GetAuraUpdateMaskForRaid(); + *data << uint64(auramask); + for (uint32 i = 0; i < MAX_AURAS; ++i) + { + if (auramask & (uint64(1) << i)) + { + AuraApplication const * aurApp = player->GetVisibleAura(i); + *data << uint32(aurApp ? aurApp->GetBase()->GetId() : 0); + *data << uint8(1); + } + } + } + else + *data << (uint64) 0; + } +} + +/*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/ +void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_REQUEST_PARTY_MEMBER_STATS"); + uint64 Guid; + recv_data >> Guid; + + Player *player = objmgr.GetPlayer(Guid); + if (!player) + { + WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 3+4+2); + data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related + data.appendPackGUID(Guid); + data << (uint32) GROUP_UPDATE_FLAG_STATUS; + data << (uint16) MEMBER_STATUS_OFFLINE; + SendPacket(&data); + return; + } + + Pet *pet = player->GetPet(); + + WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 4+2+2+2+1+2*6+8+1+8); + data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related + data.append(player->GetPackGUID()); + + uint32 mask1 = 0x00040BFF; // common mask, real flags used 0x000040BFF + if (pet) + mask1 = 0x7FFFFFFF; // for hunters and other classes with pets + + Powers powerType = player->getPowerType(); + data << (uint32) mask1; // group update mask + data << (uint16) MEMBER_STATUS_ONLINE; // member's online status + data << (uint32) player->GetHealth(); // GROUP_UPDATE_FLAG_CUR_HP + data << (uint32) player->GetMaxHealth(); // GROUP_UPDATE_FLAG_MAX_HP + data << (uint8) powerType; // GROUP_UPDATE_FLAG_POWER_TYPE + data << (uint16) player->GetPower(powerType); // GROUP_UPDATE_FLAG_CUR_POWER + data << (uint16) player->GetMaxPower(powerType); // GROUP_UPDATE_FLAG_MAX_POWER + data << (uint16) player->getLevel(); // GROUP_UPDATE_FLAG_LEVEL + data << (uint16) player->GetZoneId(); // GROUP_UPDATE_FLAG_ZONE + data << (uint16) player->GetPositionX(); // GROUP_UPDATE_FLAG_POSITION + data << (uint16) player->GetPositionY(); // GROUP_UPDATE_FLAG_POSITION + + uint64 auramask = 0; + size_t maskPos = data.wpos(); + data << (uint64) auramask; // placeholder + for (uint8 i = 0; i < MAX_AURAS; ++i) + { + if (AuraApplication * aurApp = player->GetVisibleAura(i)) + { + auramask |= (uint64(1) << i); + data << (uint32) aurApp->GetBase()->GetId(); + data << (uint8) 1; + } + } + data.put(maskPos,auramask); // GROUP_UPDATE_FLAG_AURAS + + if (pet) + { + Powers petpowertype = pet->getPowerType(); + data << (uint64) pet->GetGUID(); // GROUP_UPDATE_FLAG_PET_GUID + data << pet->GetName(); // GROUP_UPDATE_FLAG_PET_NAME + data << (uint16) pet->GetDisplayId(); // GROUP_UPDATE_FLAG_PET_MODEL_ID + data << (uint32) pet->GetHealth(); // GROUP_UPDATE_FLAG_PET_CUR_HP + data << (uint32) pet->GetMaxHealth(); // GROUP_UPDATE_FLAG_PET_MAX_HP + data << (uint8) petpowertype; // GROUP_UPDATE_FLAG_PET_POWER_TYPE + data << (uint16) pet->GetPower(petpowertype); // GROUP_UPDATE_FLAG_PET_CUR_POWER + data << (uint16) pet->GetMaxPower(petpowertype); // GROUP_UPDATE_FLAG_PET_MAX_POWER + + uint64 petauramask = 0; + size_t petMaskPos = data.wpos(); + data << (uint64) petauramask; // placeholder + for (uint8 i = 0; i < MAX_AURAS; ++i) + { + if (AuraApplication * auraApp = pet->GetVisibleAura(i)) + { + petauramask |= (uint64(1) << i); + data << (uint32) auraApp->GetBase()->GetId(); + data << (uint8) 1; + } + } + data.put(petMaskPos,petauramask); // GROUP_UPDATE_FLAG_PET_AURAS + } + else + { + data << (uint8) 0; // GROUP_UPDATE_FLAG_PET_NAME + data << (uint64) 0; // GROUP_UPDATE_FLAG_PET_AURAS + } + + SendPacket(&data); +} + +/*!*/void WorldSession::HandleRequestRaidInfoOpcode(WorldPacket & /*recv_data*/) +{ + // every time the player checks the character screen + _player->SendRaidInfo(); +} + +/*void WorldSession::HandleGroupCancelOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: got CMSG_GROUP_CANCEL."); +}*/ + +void WorldSession::HandleOptOutOfLootOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_OPT_OUT_OF_LOOT"); + + uint32 passOnLoot; + recv_data >> passOnLoot; // 1 always pass, 0 do not pass + + // ignore if player not loaded + if (!GetPlayer()) // needed because STATUS_AUTHED + { + if (passOnLoot != 0) + sLog.outError("CMSG_OPT_OUT_OF_LOOT value<>0 for not-loaded character!"); + return; + } + + GetPlayer()->SetPassOnGroupLoot(passOnLoot); +} diff --git a/src/server/game/Server/Protocol/Handlers/GuildHandler.cpp b/src/server/game/Server/Protocol/Handlers/GuildHandler.cpp new file mode 100644 index 00000000000..6803fe63a86 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/GuildHandler.cpp @@ -0,0 +1,1225 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectMgr.h" +#include "Log.h" +#include "Opcodes.h" +#include "Guild.h" +#include "GossipDef.h" +#include "SocialMgr.h" + +void WorldSession::HandleGuildQueryOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_QUERY"); + + uint32 guildId; + recvPacket >> guildId; + + if (Guild *guild = objmgr.GetGuildById(guildId)) + { + guild->Query(this); + return; + } + + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); +} + +void WorldSession::HandleGuildCreateOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_CREATE"); + + std::string gname; + recvPacket >> gname; + + if (GetPlayer()->GetGuildId()) // already in guild + return; + + Guild *guild = new Guild; + if (!guild->Create(GetPlayer(), gname)) + { + delete guild; + return; + } + + objmgr.AddGuild(guild); +} + +void WorldSession::HandleGuildInviteOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_INVITE"); + + std::string Invitedname, plname; + + Player * player = NULL; + recvPacket >> Invitedname; + + if (normalizePlayerName(Invitedname)) + player = ObjectAccessor::Instance().FindPlayerByName(Invitedname.c_str()); + + if (!player) + { + SendGuildCommandResult(GUILD_INVITE_S, Invitedname, ERR_GUILD_PLAYER_NOT_FOUND_S); + return; + } + + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + if (!guild) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + + // OK result but not send invite + if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) + return; + + // not let enemies sign guild charter + if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeam() != GetPlayer()->GetTeam()) + { + SendGuildCommandResult(GUILD_INVITE_S, Invitedname, ERR_GUILD_NOT_ALLIED); + return; + } + + if (player->GetGuildId()) + { + plname = player->GetName(); + SendGuildCommandResult(GUILD_INVITE_S, plname, ERR_ALREADY_IN_GUILD_S); + return; + } + + if (player->GetGuildIdInvited()) + { + plname = player->GetName(); + SendGuildCommandResult(GUILD_INVITE_S, plname, ERR_ALREADY_INVITED_TO_GUILD_S); + return; + } + + if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_INVITE)) + { + SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); + return; + } + + sLog.outDebug("Player %s Invited %s to Join his Guild", GetPlayer()->GetName(), Invitedname.c_str()); + + player->SetGuildIdInvited(GetPlayer()->GetGuildId()); + // Put record into guildlog + guild->LogGuildEvent(GUILD_EVENT_LOG_INVITE_PLAYER, GetPlayer()->GetGUIDLow(), player->GetGUIDLow(), 0); + + WorldPacket data(SMSG_GUILD_INVITE, (8+10)); // guess size + data << GetPlayer()->GetName(); + data << guild->GetName(); + player->GetSession()->SendPacket(&data); + + sLog.outDebug("WORLD: Sent (SMSG_GUILD_INVITE)"); +} + +void WorldSession::HandleGuildRemoveOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_REMOVE"); + + std::string plName; + recvPacket >> plName; + + if (!normalizePlayerName(plName)) + return; + + Guild* guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + if (!guild) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + + if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_REMOVE)) + { + SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); + return; + } + + uint64 plGuid; + MemberSlot* slot = guild->GetMemberSlot(plName, plGuid); + if (!slot) + { + SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); + return; + } + + if (slot->RankId == GR_GUILDMASTER) + { + SendGuildCommandResult(GUILD_QUIT_S, "", ERR_GUILD_LEADER_LEAVE); + return; + } + + //do not allow to kick player with same or higher rights + if (GetPlayer()->GetRank() >= slot->RankId) + { + SendGuildCommandResult(GUILD_QUIT_S, plName, ERR_GUILD_RANK_TOO_HIGH_S); + return; + } + + guild->DelMember(plGuid); + // Put record into guildlog + guild->LogGuildEvent(GUILD_EVENT_LOG_UNINVITE_PLAYER, GetPlayer()->GetGUIDLow(), GUID_LOPART(plGuid), 0); + + guild->BroadcastEvent(GE_REMOVED, 0, 2, plName, _player->GetName(), ""); +} + +void WorldSession::HandleGuildAcceptOpcode(WorldPacket& /*recvPacket*/) +{ + Guild *guild; + Player *player = GetPlayer(); + + sLog.outDebug("WORLD: Received CMSG_GUILD_ACCEPT"); + + guild = objmgr.GetGuildById(player->GetGuildIdInvited()); + if (!guild || player->GetGuildId()) + return; + + // not let enemies sign guild charter + if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeam() != objmgr.GetPlayerTeamByGUID(guild->GetLeader())) + return; + + if (!guild->AddMember(GetPlayer()->GetGUID(),guild->GetLowestRank())) + return; + // Put record into guildlog + guild->LogGuildEvent(GUILD_EVENT_LOG_JOIN_GUILD, GetPlayer()->GetGUIDLow(), 0, 0); + + guild->BroadcastEvent(GE_JOINED, player->GetGUID(), 1, player->GetName(), "", ""); + + sLog.outDebug("WORLD: Sent (SMSG_GUILD_EVENT)"); +} + +void WorldSession::HandleGuildDeclineOpcode(WorldPacket& /*recvPacket*/) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_DECLINE"); + + GetPlayer()->SetGuildIdInvited(0); + GetPlayer()->SetInGuild(0); +} + +void WorldSession::HandleGuildInfoOpcode(WorldPacket& /*recvPacket*/) +{ + Guild *guild; + sLog.outDebug("WORLD: Received CMSG_GUILD_INFO"); + + guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + if (!guild) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + + WorldPacket data(SMSG_GUILD_INFO, (guild->GetName().size() + 4 + 4 + 4)); + data << guild->GetName(); + data << secsToTimeBitFields(guild->GetCreatedDate()); // 3.x (prev. year + month + day) + data << guild->GetMemberSize(); // char amount + data << guild->GetMemberSize(); // acc amount + + SendPacket(&data); +} + +void WorldSession::HandleGuildRosterOpcode(WorldPacket& /*recvPacket*/) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_ROSTER"); + + if (Guild* guild = objmgr.GetGuildById(_player->GetGuildId())) + guild->Roster(this); +} + +void WorldSession::HandleGuildPromoteOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_PROMOTE"); + + std::string plName; + recvPacket >> plName; + + if (!normalizePlayerName(plName)) + return; + + Guild* guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + if (!guild) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + + if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_PROMOTE)) + { + SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); + return; + } + + uint64 plGuid; + MemberSlot* slot = guild->GetMemberSlot(plName, plGuid); + + if (!slot) + { + SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); + return; + } + + if (plGuid == GetPlayer()->GetGUID()) + { + SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_NAME_INVALID); + return; + } + + //allow to promote only to lower rank than member's rank + //guildmaster's rank = 0 + //GetPlayer()->GetRank() + 1 is highest rank that current player can promote to + if (GetPlayer()->GetRank() + 1 >= slot->RankId) + { + SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_RANK_TOO_HIGH_S); + return; + } + + uint32 newRankId = slot->RankId - 1; //when promoting player, rank is decreased + + guild->BroadcastEvent(GE_PROMOTION, 0, 3, _player->GetName(), plName, guild->GetRankName(newRankId)); + + guild->ChangeRank(plGuid, newRankId); + // Put record into guildlog + guild->LogGuildEvent(GUILD_EVENT_LOG_PROMOTE_PLAYER, GetPlayer()->GetGUIDLow(), GUID_LOPART(plGuid), newRankId); +} + +void WorldSession::HandleGuildDemoteOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_DEMOTE"); + + std::string plName; + recvPacket >> plName; + + if (!normalizePlayerName(plName)) + return; + + Guild* guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + + if (!guild) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + + if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_DEMOTE)) + { + SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); + return; + } + + uint64 plGuid; + MemberSlot* slot = guild->GetMemberSlot(plName, plGuid); + + if (!slot) + { + SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); + return; + } + + if (plGuid == GetPlayer()->GetGUID()) + { + SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_NAME_INVALID); + return; + } + + //do not allow to demote same or higher rank + if (GetPlayer()->GetRank() >= slot->RankId) + { + SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_RANK_TOO_HIGH_S); + return; + } + + //do not allow to demote lowest rank + if (slot->RankId >= guild->GetLowestRank()) + { + SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_RANK_TOO_LOW_S); + return; + } + + uint32 newRankId = slot->RankId + 1; //when demoting player, rank is increased + + guild->ChangeRank(plGuid, newRankId); + // Put record into guildlog + guild->LogGuildEvent(GUILD_EVENT_LOG_DEMOTE_PLAYER, GetPlayer()->GetGUIDLow(), GUID_LOPART(plGuid), newRankId); + + guild->BroadcastEvent(GE_DEMOTION, 0, 3, _player->GetName(), plName, guild->GetRankName(slot->RankId)); +} + +void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_LEAVE"); + + Guild *guild = objmgr.GetGuildById(_player->GetGuildId()); + if (!guild) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + + if (_player->GetGUID() == guild->GetLeader() && guild->GetMemberSize() > 1) + { + SendGuildCommandResult(GUILD_QUIT_S, "", ERR_GUILD_LEADER_LEAVE); + return; + } + + if (_player->GetGUID() == guild->GetLeader()) + { + guild->Disband(); + return; + } + + guild->DelMember(_player->GetGUID()); + // Put record into guildlog + guild->LogGuildEvent(GUILD_EVENT_LOG_LEAVE_GUILD, _player->GetGUIDLow(), 0, 0); + + guild->BroadcastEvent(GE_LEFT, _player->GetGUID(), 1, _player->GetName(), "", ""); + + SendGuildCommandResult(GUILD_QUIT_S, guild->GetName(), ERR_PLAYER_NO_MORE_IN_GUILD); +} + +void WorldSession::HandleGuildDisbandOpcode(WorldPacket& /*recvPacket*/) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_DISBAND"); + + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + if (!guild) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + + if (GetPlayer()->GetGUID() != guild->GetLeader()) + { + SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); + return; + } + + guild->Disband(); + + sLog.outDebug("WORLD: Guild Successfully Disbanded"); +} + +void WorldSession::HandleGuildLeaderOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_LEADER"); + + std::string name; + recvPacket >> name; + + Player *oldLeader = GetPlayer(); + + if (!normalizePlayerName(name)) + return; + + Guild *guild = objmgr.GetGuildById(oldLeader->GetGuildId()); + + if (!guild) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + + if (oldLeader->GetGUID() != guild->GetLeader()) + { + SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); + return; + } + + uint64 newLeaderGUID; + MemberSlot* slot = guild->GetMemberSlot(name, newLeaderGUID); + + if (!slot) + { + SendGuildCommandResult(GUILD_INVITE_S, name, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); + return; + } + + guild->SetLeader(newLeaderGUID); + guild->ChangeRank(oldLeader->GetGUID(), GR_OFFICER); + + guild->BroadcastEvent(GE_LEADER_CHANGED, 0, 2, oldLeader->GetName(), name, ""); +} + +void WorldSession::HandleGuildMOTDOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_MOTD"); + + std::string MOTD; + + if (!recvPacket.empty()) + recvPacket >> MOTD; + else + MOTD = ""; + + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + if (!guild) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + + if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_SETMOTD)) + { + SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); + return; + } + + guild->SetMOTD(MOTD); + + guild->BroadcastEvent(GE_MOTD, 0, 1, MOTD, "", ""); +} + +void WorldSession::HandleGuildSetPublicNoteOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_SET_PUBLIC_NOTE"); + + std::string name,PNOTE; + recvPacket >> name; + + if (!normalizePlayerName(name)) + return; + + Guild* guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + if (!guild) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + + if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_EPNOTE)) + { + SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); + return; + } + + uint64 plGuid; + MemberSlot* slot = guild->GetMemberSlot(name, plGuid); + + if (!slot) + { + SendGuildCommandResult(GUILD_INVITE_S, name, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); + return; + } + + recvPacket >> PNOTE; + guild->SetPNOTE(plGuid, PNOTE); + + guild->Roster(this); +} + +void WorldSession::HandleGuildSetOfficerNoteOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_SET_OFFICER_NOTE"); + + std::string plName, OFFNOTE; + recvPacket >> plName; + + if (!normalizePlayerName(plName)) + return; + + Guild* guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + if (!guild) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + + if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_EOFFNOTE)) + { + SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); + return; + } + + uint64 plGuid; + MemberSlot* slot = guild->GetMemberSlot(plName, plGuid); + + if (!slot) + { + SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); + return; + } + + recvPacket >> OFFNOTE; + guild->SetOFFNOTE(plGuid, OFFNOTE); + + guild->Roster(this); +} + +void WorldSession::HandleGuildRankOpcode(WorldPacket& recvPacket) +{ + std::string rankname; + uint32 rankId; + uint32 rights, MoneyPerDay; + + sLog.outDebug("WORLD: Received CMSG_GUILD_RANK"); + + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + if (!guild) + { + recvPacket.rpos(recvPacket.wpos()); // set to end to avoid warnings spam + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + else if (GetPlayer()->GetGUID() != guild->GetLeader()) + { + recvPacket.rpos(recvPacket.wpos()); // set to end to avoid warnings spam + SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); + return; + } + + recvPacket >> rankId; + recvPacket >> rights; + recvPacket >> rankname; + recvPacket >> MoneyPerDay; + + for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) + { + uint32 BankRights; + uint32 BankSlotPerDay; + + recvPacket >> BankRights; + recvPacket >> BankSlotPerDay; + guild->SetBankRightsAndSlots(rankId, uint8(i), uint16(BankRights & 0xFF), uint16(BankSlotPerDay), true); + } + + sLog.outDebug("WORLD: Changed RankName to %s , Rights to 0x%.4X", rankname.c_str(), rights); + + guild->SetBankMoneyPerDay(rankId, MoneyPerDay); + guild->SetRankName(rankId, rankname); + + if (rankId == GR_GUILDMASTER) // prevent loss leader rights + rights = GR_RIGHT_ALL; + + guild->SetRankRights(rankId, rights); + + guild->Query(this); + guild->Roster(); // broadcast for tab rights update +} + +void WorldSession::HandleGuildAddRankOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_ADD_RANK"); + + std::string rankname; + recvPacket >> rankname; + + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + if (!guild) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + + if (GetPlayer()->GetGUID() != guild->GetLeader()) + { + SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); + return; + } + + if (guild->GetRanksSize() >= GUILD_RANKS_MAX_COUNT) // client not let create more 10 than ranks + return; + + guild->CreateRank(rankname, GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + + guild->Query(this); + guild->Roster(); // broadcast for tab rights update +} + +void WorldSession::HandleGuildDelRankOpcode(WorldPacket& /*recvPacket*/) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_DEL_RANK"); + + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + if (!guild) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + else if (GetPlayer()->GetGUID() != guild->GetLeader()) + { + SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); + return; + } + + guild->DelRank(); + + guild->Query(this); + guild->Roster(); // broadcast for tab rights update +} + +void WorldSession::SendGuildCommandResult(uint32 typecmd, const std::string& str,uint32 cmdresult) +{ + WorldPacket data(SMSG_GUILD_COMMAND_RESULT, (8+str.size()+1)); + data << typecmd; + data << str; + data << cmdresult; + SendPacket(&data); + + sLog.outDebug("WORLD: Sent (SMSG_GUILD_COMMAND_RESULT)"); +} + +void WorldSession::HandleGuildChangeInfoTextOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: Received CMSG_GUILD_INFO_TEXT"); + + std::string GINFO; + + recvPacket >> GINFO; + + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + if (!guild) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + return; + } + + if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_MODIFY_GUILD_INFO)) + { + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PERMISSIONS); + return; + } + + guild->SetGINFO(GINFO); +} + +void WorldSession::HandleSaveGuildEmblemOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: Received MSG_SAVE_GUILD_EMBLEM"); + + uint64 vendorGuid; + + uint32 EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor; + + recvPacket >> vendorGuid; + recvPacket >> EmblemStyle >> EmblemColor >> BorderStyle >> BorderColor >> BackgroundColor; + + Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorGuid,UNIT_NPC_FLAG_TABARDDESIGNER); + if (!pCreature) + { + //"That's not an emblem vendor!" + SendSaveGuildEmblem(ERR_GUILDEMBLEM_INVALIDVENDOR); + sLog.outDebug("WORLD: HandleSaveGuildEmblemOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(vendorGuid)); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + if (!guild) + { + //"You are not part of a guild!"; + SendSaveGuildEmblem(ERR_GUILDEMBLEM_NOGUILD); + return; + } + + if (guild->GetLeader() != GetPlayer()->GetGUID()) + { + //"Only guild leaders can create emblems." + SendSaveGuildEmblem(ERR_GUILDEMBLEM_NOTGUILDMASTER); + return; + } + + if (GetPlayer()->GetMoney() < 10*GOLD) + { + //"You can't afford to do that." + SendSaveGuildEmblem(ERR_GUILDEMBLEM_NOTENOUGHMONEY); + return; + } + + GetPlayer()->ModifyMoney(-10*GOLD); + guild->SetEmblem(EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor); + + //"Guild Emblem saved." + SendSaveGuildEmblem(ERR_GUILDEMBLEM_SUCCESS); + + guild->Query(this); +} + +void WorldSession::HandleGuildEventLogQueryOpcode(WorldPacket& /* recvPacket */) +{ + // empty + sLog.outDebug("WORLD: Received (MSG_GUILD_EVENT_LOG_QUERY)"); + if (uint32 GuildId = GetPlayer()->GetGuildId()) + if (Guild *pGuild = objmgr.GetGuildById(GuildId)) + pGuild->DisplayGuildEventLog(this); +} + +/****** GUILD BANK *******/ + +void WorldSession::HandleGuildBankMoneyWithdrawn(WorldPacket & /* recv_data */) +{ + sLog.outDebug("WORLD: Received (MSG_GUILD_BANK_MONEY_WITHDRAWN)"); + if (uint32 GuildId = GetPlayer()->GetGuildId()) + if (Guild *pGuild = objmgr.GetGuildById(GuildId)) + pGuild->SendMoneyInfo(this, GetPlayer()->GetGUIDLow()); +} + +void WorldSession::HandleGuildPermissions(WorldPacket& /* recv_data */) +{ + sLog.outDebug("WORLD: Received (MSG_GUILD_PERMISSIONS)"); + + if (uint32 GuildId = GetPlayer()->GetGuildId()) + { + if (Guild *pGuild = objmgr.GetGuildById(GuildId)) + { + uint32 rankId = GetPlayer()->GetRank(); + + WorldPacket data(MSG_GUILD_PERMISSIONS, 4*15+1); + data << uint32(rankId); // guild rank id + data << uint32(pGuild->GetRankRights(rankId)); // rank rights + // money per day left + data << uint32(pGuild->GetMemberMoneyWithdrawRem(GetPlayer()->GetGUIDLow())); + data << uint8(pGuild->GetPurchasedTabs()); // tabs count + // why sending all info when not all tabs are purchased??? + for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) + { + data << uint32(pGuild->GetBankRights(rankId, uint8(i))); + data << uint32(pGuild->GetMemberSlotWithdrawRem(GetPlayer()->GetGUIDLow(), uint8(i))); + } + SendPacket(&data); + sLog.outDebug("WORLD: Sent (MSG_GUILD_PERMISSIONS)"); + } + } +} + +/* Called when clicking on Guild bank gameobject */ +void WorldSession::HandleGuildBankerActivate(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received (CMSG_GUILD_BANKER_ACTIVATE)"); + + uint64 GoGuid; + uint8 unk; + recv_data >> GoGuid >> unk; + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + return; + + if (uint32 GuildId = GetPlayer()->GetGuildId()) + { + if (Guild *pGuild = objmgr.GetGuildById(GuildId)) + { + pGuild->DisplayGuildBankTabsInfo(this); // this also will load guild bank if not yet + return; + } + } + + SendGuildCommandResult(GUILD_UNK1, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); +} + +/* Called when opening guild bank tab only (first one) */ +void WorldSession::HandleGuildBankQueryTab(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_QUERY_TAB)"); + + uint64 GoGuid; + uint8 TabId, unk1; + recv_data >> GoGuid >> TabId >> unk1; + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + return; + + uint32 GuildId = GetPlayer()->GetGuildId(); + if (!GuildId) + return; + + Guild *pGuild = objmgr.GetGuildById(GuildId); + if (!pGuild) + return; + + if (TabId >= pGuild->GetPurchasedTabs()) + return; + + // Let's update the amount of gold the player can withdraw before displaying the content + // This is useful if money withdraw right has changed + pGuild->SendMoneyInfo(this, GetPlayer()->GetGUIDLow()); + pGuild->DisplayGuildBankContent(this, TabId); +} + +void WorldSession::HandleGuildBankDepositMoney(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_DEPOSIT_MONEY)"); + + uint64 GoGuid; + uint32 money; + recv_data >> GoGuid >> money; + + if (!money) + return; + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + return; + + if (GetPlayer()->GetMoney() < money) + return; + + uint32 GuildId = GetPlayer()->GetGuildId(); + if (!GuildId) + return; + + Guild *pGuild = objmgr.GetGuildById(GuildId); + if (!pGuild) + return; + + if (!pGuild->GetPurchasedTabs()) + return; + + CharacterDatabase.BeginTransaction(); + + pGuild->SetBankMoney(pGuild->GetGuildBankMoney()+money); + GetPlayer()->ModifyMoney(-int(money)); + GetPlayer()->SaveGoldToDB(); + + CharacterDatabase.CommitTransaction(); + + // logging money + if (_player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) + { + sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit money (Amount: %u) to guild bank (Guild ID %u)", + _player->GetName(),_player->GetSession()->GetAccountId(),money,GuildId); + } + + // log + pGuild->LogBankEvent(GUILD_BANK_LOG_DEPOSIT_MONEY, uint8(0), GetPlayer()->GetGUIDLow(), money); + + pGuild->DisplayGuildBankTabsInfo(this); + pGuild->DisplayGuildBankContent(this, 0); + pGuild->DisplayGuildBankMoneyUpdate(this); +} + +void WorldSession::HandleGuildBankWithdrawMoney(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_WITHDRAW_MONEY)"); + + uint64 GoGuid; + uint32 money; + recv_data >> GoGuid >> money; + + if (!money) + return; + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + return; + + uint32 GuildId = GetPlayer()->GetGuildId(); + if (GuildId == 0) + return; + + Guild *pGuild = objmgr.GetGuildById(GuildId); + if (!pGuild) + return; + + if (!pGuild->GetPurchasedTabs()) + return; + + if (pGuild->GetGuildBankMoney()HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_WITHDRAW_GOLD)) + return; + + CharacterDatabase.BeginTransaction(); + + if (!pGuild->MemberMoneyWithdraw(money, GetPlayer()->GetGUIDLow())) + { + CharacterDatabase.RollbackTransaction(); + return; + } + + GetPlayer()->ModifyMoney(money); + GetPlayer()->SaveGoldToDB(); + + CharacterDatabase.CommitTransaction(); + + // Log + pGuild->LogBankEvent(GUILD_BANK_LOG_WITHDRAW_MONEY, uint8(0), GetPlayer()->GetGUIDLow(), money); + + pGuild->SendMoneyInfo(this, GetPlayer()->GetGUIDLow()); + pGuild->DisplayGuildBankTabsInfo(this); + pGuild->DisplayGuildBankContent(this,0); + pGuild->DisplayGuildBankMoneyUpdate(this); +} + +void WorldSession::HandleGuildBankSwapItems(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_SWAP_ITEMS)"); + + uint64 GoGuid; + uint8 BankToBank; + + uint8 BankTab, BankTabSlot, AutoStore; + uint8 PlayerSlot = NULL_SLOT; + uint8 PlayerBag = NULL_BAG; + uint8 BankTabDst = 0, BankTabSlotDst = 0, unk2; + uint8 ToChar = 1; + uint32 ItemEntry, unk1; + uint32 AutoStoreCount = 0; + uint32 SplitedAmount = 0; + + recv_data >> GoGuid >> BankToBank; + + uint32 GuildId = GetPlayer()->GetGuildId(); + if (!GuildId) + { + recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet + return; + } + + Guild *pGuild = objmgr.GetGuildById(GuildId); + if (!pGuild) + { + recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet + return; + } + + if (BankToBank) + { + recv_data >> BankTabDst; + recv_data >> BankTabSlotDst; + recv_data >> unk1; // always 0 + recv_data >> BankTab; + recv_data >> BankTabSlot; + recv_data >> ItemEntry; + recv_data >> unk2; // always 0 + recv_data >> SplitedAmount; + + if (BankTabSlotDst >= GUILD_BANK_MAX_SLOTS || + (BankTabDst == BankTab && BankTabSlotDst == BankTabSlot) || + BankTab >= pGuild->GetPurchasedTabs() || + BankTabDst >= pGuild->GetPurchasedTabs()) + { + recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet + return; + } + } + else + { + recv_data >> BankTab; + recv_data >> BankTabSlot; + recv_data >> ItemEntry; + recv_data >> AutoStore; + if (AutoStore) + { + recv_data >> AutoStoreCount; + recv_data.read_skip(); // ToChar (?), always and expected to be 1 (autostore only triggered in guild->ToChar) + recv_data.read_skip(); // unknown, always 0 + } + else + { + recv_data >> PlayerBag; + recv_data >> PlayerSlot; + recv_data >> ToChar; + recv_data >> SplitedAmount; + } + + if (BankTabSlot >= GUILD_BANK_MAX_SLOTS && BankTabSlot != 0xFF || + BankTab >= pGuild->GetPurchasedTabs()) + { + recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet + return; + } + } + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + return; + + if (BankTab >= pGuild->GetPurchasedTabs()) + return; + + // Bank <-> Bank + if (BankToBank) + { + pGuild->SwapItems(_player, BankTab, BankTabSlot, BankTabDst, BankTabSlotDst, SplitedAmount); + return; + } + + // Player <-> Bank + + // allow work with inventory only + if (!Player::IsInventoryPos(PlayerBag, PlayerSlot) && !(PlayerBag == NULL_BAG && PlayerSlot == NULL_SLOT)) + { + _player->SendEquipError(EQUIP_ERR_NONE, NULL, NULL); + return; + } + + // BankToChar swap or char to bank remaining + if (ToChar) // Bank -> Char cases + pGuild->MoveFromBankToChar(_player, BankTab, BankTabSlot, PlayerBag, PlayerSlot, SplitedAmount); + else // Char -> Bank cases + pGuild->MoveFromCharToBank(_player, PlayerBag, PlayerSlot, BankTab, BankTabSlot, SplitedAmount); +} + +void WorldSession::HandleGuildBankBuyTab(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_BUY_TAB)"); + + uint64 GoGuid; + uint8 TabId; + + recv_data >> GoGuid; + recv_data >> TabId; + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + return; + + uint32 GuildId = GetPlayer()->GetGuildId(); + if (!GuildId) + return; + + Guild *pGuild = objmgr.GetGuildById(GuildId); + if (!pGuild) + return; + + // m_PurchasedTabs = 0 when buying Tab 0, that is why this check can be made + if (TabId != pGuild->GetPurchasedTabs()) + return; + + uint32 TabCost = GetGuildBankTabPrice(TabId) * GOLD; + if (!TabCost) + return; + + if (GetPlayer()->GetMoney() < TabCost) // Should not happen, this is checked by client + return; + + // Go on with creating tab + pGuild->CreateNewBankTab(); + GetPlayer()->ModifyMoney(-int(TabCost)); + pGuild->SetBankMoneyPerDay(GetPlayer()->GetRank(), WITHDRAW_MONEY_UNLIMITED); + pGuild->SetBankRightsAndSlots(GetPlayer()->GetRank(), TabId, GUILD_BANK_RIGHT_FULL, WITHDRAW_SLOT_UNLIMITED, true); + pGuild->Roster(); // broadcast for tab rights update + pGuild->DisplayGuildBankTabsInfo(this); +} + +void WorldSession::HandleGuildBankUpdateTab(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_UPDATE_TAB)"); + + uint64 GoGuid; + uint8 TabId; + std::string Name; + std::string IconIndex; + + recv_data >> GoGuid; + recv_data >> TabId; + recv_data >> Name; + recv_data >> IconIndex; + + if (Name.empty()) + return; + + if (IconIndex.empty()) + return; + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + return; + + uint32 GuildId = GetPlayer()->GetGuildId(); + if (!GuildId) + return; + + Guild *pGuild = objmgr.GetGuildById(GuildId); + if (!pGuild) + return; + + if (TabId >= pGuild->GetPurchasedTabs()) + return; + + pGuild->SetGuildBankTabInfo(TabId, Name, IconIndex); + pGuild->DisplayGuildBankTabsInfo(this); + pGuild->DisplayGuildBankContent(this, TabId); +} + +void WorldSession::HandleGuildBankLogQuery(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received (MSG_GUILD_BANK_LOG_QUERY)"); + + uint8 TabId; + recv_data >> TabId; + + uint32 GuildId = GetPlayer()->GetGuildId(); + if (!GuildId) + return; + + Guild *pGuild = objmgr.GetGuildById(GuildId); + if (!pGuild) + return; + + // GUILD_BANK_MAX_TABS send by client for money log + if (TabId >= pGuild->GetPurchasedTabs() && TabId != GUILD_BANK_MAX_TABS) + return; + + pGuild->DisplayGuildBankLogs(this, TabId); +} + +void WorldSession::HandleQueryGuildBankTabText(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: Received MSG_QUERY_GUILD_BANK_TEXT"); + + uint8 TabId; + recv_data >> TabId; + + uint32 GuildId = GetPlayer()->GetGuildId(); + if (!GuildId) + return; + + Guild *pGuild = objmgr.GetGuildById(GuildId); + if (!pGuild) + return; + + if (TabId >= pGuild->GetPurchasedTabs()) + return; + + pGuild->SendGuildBankTabText(this, TabId); +} + +void WorldSession::HandleSetGuildBankTabText(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_SET_GUILD_BANK_TEXT"); + + uint8 TabId; + std::string Text; + recv_data >> TabId; + recv_data >> Text; + + uint32 GuildId = GetPlayer()->GetGuildId(); + if (!GuildId) + return; + + Guild *pGuild = objmgr.GetGuildById(GuildId); + if (!pGuild) + return; + + if (TabId >= pGuild->GetPurchasedTabs()) + return; + + pGuild->SetGuildBankTabText(TabId, Text); +} + +void WorldSession::SendSaveGuildEmblem(uint32 msg) +{ + WorldPacket data(MSG_SAVE_GUILD_EMBLEM, 4); + data << uint32(msg); // not part of guild + SendPacket(&data); +} diff --git a/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp b/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp new file mode 100644 index 00000000000..53aede43492 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp @@ -0,0 +1,1430 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "Item.h" +#include "UpdateData.h" +#include "ObjectAccessor.h" + +void WorldSession::HandleSplitItemOpcode(WorldPacket & recv_data) +{ + //sLog.outDebug("WORLD: CMSG_SPLIT_ITEM"); + uint8 srcbag, srcslot, dstbag, dstslot; + uint32 count; + + recv_data >> srcbag >> srcslot >> dstbag >> dstslot >> count; + //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u, count = %u", srcbag, srcslot, dstbag, dstslot, count); + + uint16 src = ((srcbag << 8) | srcslot); + uint16 dst = ((dstbag << 8) | dstslot); + + if (src == dst) + return; + + if (count == 0) + return; //check count - if zero it's fake packet + + if (!_player->IsValidPos(srcbag,srcslot)) + { + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + if (!_player->IsValidPos(dstbag,dstslot)) + { + _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); + return; + } + + _player->SplitItem(src, dst, count); +} + +void WorldSession::HandleSwapInvItemOpcode(WorldPacket & recv_data) +{ + //sLog.outDebug("WORLD: CMSG_SWAP_INV_ITEM"); + uint8 srcslot, dstslot; + + recv_data >> dstslot >> srcslot; + //sLog.outDebug("STORAGE: receive srcslot = %u, dstslot = %u", srcslot, dstslot); + + // prevent attempt swap same item to current position generated by client at special checting sequence + if (srcslot == dstslot) + return; + + if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0,srcslot)) + { + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0,dstslot)) + { + _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); + return; + } + + uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot); + uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot); + + _player->SwapItem(src, dst); +} + +void WorldSession::HandleAutoEquipItemSlotOpcode(WorldPacket & recv_data) +{ + uint64 itemguid; + uint8 dstslot; + recv_data >> itemguid >> dstslot; + + // cheating attempt, client should never send opcode in that case + if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, dstslot)) + return; + + Item* item = _player->GetItemByGuid(itemguid); + uint16 dstpos = dstslot | (INVENTORY_SLOT_BAG_0 << 8); + + if (!item || item->GetPos() == dstpos) + return; + + _player->SwapItem(item->GetPos(), dstpos); +} + +void WorldSession::HandleSwapItem(WorldPacket & recv_data) +{ + //sLog.outDebug("WORLD: CMSG_SWAP_ITEM"); + uint8 dstbag, dstslot, srcbag, srcslot; + + recv_data >> dstbag >> dstslot >> srcbag >> srcslot ; + //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u", srcbag, srcslot, dstbag, dstslot); + + uint16 src = ((srcbag << 8) | srcslot); + uint16 dst = ((dstbag << 8) | dstslot); + + // prevent attempt swap same item to current position generated by client at special checting sequence + if (src == dst) + return; + + if (!_player->IsValidPos(srcbag,srcslot)) + { + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + if (!_player->IsValidPos(dstbag,dstslot)) + { + _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); + return; + } + + _player->SwapItem(src, dst); +} + +void WorldSession::HandleAutoEquipItemOpcode(WorldPacket & recv_data) +{ + //sLog.outDebug("WORLD: CMSG_AUTOEQUIP_ITEM"); + uint8 srcbag, srcslot; + + recv_data >> srcbag >> srcslot; + //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); + + Item *pSrcItem = _player->GetItemByPos(srcbag, srcslot); + if (!pSrcItem) + return; // only at cheat + + uint16 dest; + uint8 msg = _player->CanEquipItem(NULL_SLOT, dest, pSrcItem, !pSrcItem->IsBag()); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pSrcItem, NULL); + return; + } + + uint16 src = pSrcItem->GetPos(); + if (dest == src) // prevent equip in same slot, only at cheat + return; + + Item *pDstItem = _player->GetItemByPos(dest); + if (!pDstItem) // empty slot, simple case + { + _player->RemoveItem(srcbag, srcslot, true); + _player->EquipItem(dest, pSrcItem, true); + _player->AutoUnequipOffhandIfNeed(); + } + else // have currently equipped item, not simple case + { + uint8 dstbag = pDstItem->GetBagSlot(); + uint8 dstslot = pDstItem->GetSlot(); + + msg = _player->CanUnequipItem(dest, !pSrcItem->IsBag()); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pDstItem, NULL); + return; + } + + // check dest->src move possibility + ItemPosCountVec sSrc; + uint16 eSrc = 0; + if (_player->IsInventoryPos(src)) + { + msg = _player->CanStoreItem(srcbag, srcslot, sSrc, pDstItem, true); + if (msg != EQUIP_ERR_OK) + msg = _player->CanStoreItem(srcbag, NULL_SLOT, sSrc, pDstItem, true); + if (msg != EQUIP_ERR_OK) + msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sSrc, pDstItem, true); + } + else if (_player->IsBankPos(src)) + { + msg = _player->CanBankItem(srcbag, srcslot, sSrc, pDstItem, true); + if (msg != EQUIP_ERR_OK) + msg = _player->CanBankItem(srcbag, NULL_SLOT, sSrc, pDstItem, true); + if (msg != EQUIP_ERR_OK) + msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, sSrc, pDstItem, true); + } + else if (_player->IsEquipmentPos(src)) + { + msg = _player->CanEquipItem(srcslot, eSrc, pDstItem, true); + if (msg == EQUIP_ERR_OK) + msg = _player->CanUnequipItem(eSrc, true); + } + + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pDstItem, pSrcItem); + return; + } + + // now do moves, remove... + _player->RemoveItem(dstbag, dstslot, false); + _player->RemoveItem(srcbag, srcslot, false); + + // add to dest + _player->EquipItem(dest, pSrcItem, true); + + // add to src + if (_player->IsInventoryPos(src)) + _player->StoreItem(sSrc, pDstItem, true); + else if (_player->IsBankPos(src)) + _player->BankItem(sSrc, pDstItem, true); + else if (_player->IsEquipmentPos(src)) + _player->EquipItem(eSrc, pDstItem, true); + + _player->AutoUnequipOffhandIfNeed(); + } +} + +void WorldSession::HandleDestroyItemOpcode(WorldPacket & recv_data) +{ + //sLog.outDebug("WORLD: CMSG_DESTROYITEM"); + uint8 bag, slot, count, data1, data2, data3; + + recv_data >> bag >> slot >> count >> data1 >> data2 >> data3; + //sLog.outDebug("STORAGE: receive bag = %u, slot = %u, count = %u", bag, slot, count); + + uint16 pos = (bag << 8) | slot; + + // prevent drop unequipable items (in combat, for example) and non-empty bags + if (_player->IsEquipmentPos(pos) || _player->IsBagPos(pos)) + { + uint8 msg = _player->CanUnequipItem(pos, false); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, _player->GetItemByPos(pos), NULL); + return; + } + } + + Item *pItem = _player->GetItemByPos(bag, slot); + if (!pItem) + { + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + if (count) + { + uint32 i_count = count; + _player->DestroyItemCount(pItem, i_count, true); + } + else + _player->DestroyItem(bag, slot, true); +} + +// Only _static_ data send in this packet !!! +void WorldSession::HandleItemQuerySingleOpcode(WorldPacket & recv_data) +{ + //sLog.outDebug("WORLD: CMSG_ITEM_QUERY_SINGLE"); + uint32 item; + recv_data >> item; + + sLog.outDetail("STORAGE: Item Query = %u", item); + + ItemPrototype const *pProto = objmgr.GetItemPrototype(item); + if (pProto) + { + std::string Name = pProto->Name1; + std::string Description = pProto->Description; + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId); + if (il) + { + if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty()) + Name = il->Name[loc_idx]; + if (il->Description.size() > size_t(loc_idx) && !il->Description[loc_idx].empty()) + Description = il->Description[loc_idx]; + } + } + // guess size + WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 600); + data << pProto->ItemId; + data << pProto->Class; + data << pProto->SubClass; + data << int32(pProto->Unk0); // new 2.0.3, not exist in wdb cache? + data << Name; + data << uint8(0x00); //pProto->Name2; // blizz not send name there, just uint8(0x00); <-- \0 = empty string = empty name... + data << uint8(0x00); //pProto->Name3; // blizz not send name there, just uint8(0x00); + data << uint8(0x00); //pProto->Name4; // blizz not send name there, just uint8(0x00); + data << pProto->DisplayInfoID; + data << pProto->Quality; + data << pProto->Flags; + data << pProto->Flags2; + data << pProto->BuyPrice; + data << pProto->SellPrice; + data << pProto->InventoryType; + data << pProto->AllowableClass; + data << pProto->AllowableRace; + data << pProto->ItemLevel; + data << pProto->RequiredLevel; + data << pProto->RequiredSkill; + data << pProto->RequiredSkillRank; + data << pProto->RequiredSpell; + data << pProto->RequiredHonorRank; + data << pProto->RequiredCityRank; + data << pProto->RequiredReputationFaction; + data << pProto->RequiredReputationRank; + data << int32(pProto->MaxCount); + data << int32(pProto->Stackable); + data << pProto->ContainerSlots; + data << pProto->StatsCount; // item stats count + for (uint32 i = 0; i < pProto->StatsCount; ++i) + { + data << pProto->ItemStat[i].ItemStatType; + data << pProto->ItemStat[i].ItemStatValue; + } + data << pProto->ScalingStatDistribution; // scaling stats distribution + data << pProto->ScalingStatValue; // some kind of flags used to determine stat values column + for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) + { + data << pProto->Damage[i].DamageMin; + data << pProto->Damage[i].DamageMax; + data << pProto->Damage[i].DamageType; + } + + // resistances (7) + data << pProto->Armor; + data << pProto->HolyRes; + data << pProto->FireRes; + data << pProto->NatureRes; + data << pProto->FrostRes; + data << pProto->ShadowRes; + data << pProto->ArcaneRes; + + data << pProto->Delay; + data << pProto->AmmoType; + data << pProto->RangedModRange; + + for (int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s) + { + // send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown + // use `item_template` or if not set then only use spell cooldowns + SpellEntry const* spell = sSpellStore.LookupEntry(pProto->Spells[s].SpellId); + if (spell) + { + bool db_data = pProto->Spells[s].SpellCooldown >= 0 || pProto->Spells[s].SpellCategoryCooldown >= 0; + + data << pProto->Spells[s].SpellId; + data << pProto->Spells[s].SpellTrigger; + data << uint32(-abs(pProto->Spells[s].SpellCharges)); + + if (db_data) + { + data << uint32(pProto->Spells[s].SpellCooldown); + data << uint32(pProto->Spells[s].SpellCategory); + data << uint32(pProto->Spells[s].SpellCategoryCooldown); + } + else + { + data << uint32(spell->RecoveryTime); + data << uint32(spell->Category); + data << uint32(spell->CategoryRecoveryTime); + } + } + else + { + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(-1); + data << uint32(0); + data << uint32(-1); + } + } + data << pProto->Bonding; + data << Description; + data << pProto->PageText; + data << pProto->LanguageID; + data << pProto->PageMaterial; + data << pProto->StartQuest; + data << pProto->LockID; + data << int32(pProto->Material); + data << pProto->Sheath; + data << pProto->RandomProperty; + data << pProto->RandomSuffix; + data << pProto->Block; + data << pProto->ItemSet; + data << pProto->MaxDurability; + data << pProto->Area; + data << pProto->Map; // Added in 1.12.x & 2.0.1 client branch + data << pProto->BagFamily; + data << pProto->TotemCategory; + for (int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s) + { + data << pProto->Socket[s].Color; + data << pProto->Socket[s].Content; + } + data << pProto->socketBonus; + data << pProto->GemProperties; + data << pProto->RequiredDisenchantSkill; + data << pProto->ArmorDamageModifier; + data << abs(pProto->Duration); // added in 2.4.2.8209, duration (seconds) + data << pProto->ItemLimitCategory; // WotLK, ItemLimitCategory + data << pProto->HolidayId; // Holiday.dbc? + SendPacket(&data); + } + else + { + sLog.outDebug("WORLD: CMSG_ITEM_QUERY_SINGLE - NO item INFO! (ENTRY: %u)", item); + WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 4); + data << uint32(item | 0x80000000); + SendPacket(&data); + } +} + +void WorldSession::HandleReadItem(WorldPacket & recv_data) +{ + //sLog.outDebug("WORLD: CMSG_READ_ITEM"); + + uint8 bag, slot; + recv_data >> bag >> slot; + + //sLog.outDetail("STORAGE: Read bag = %u, slot = %u", bag, slot); + Item *pItem = _player->GetItemByPos(bag, slot); + + if (pItem && pItem->GetProto()->PageText) + { + WorldPacket data; + + uint8 msg = _player->CanUseItem(pItem); + if (msg == EQUIP_ERR_OK) + { + data.Initialize (SMSG_READ_ITEM_OK, 8); + sLog.outDetail("STORAGE: Item page sent"); + } + else + { + data.Initialize(SMSG_READ_ITEM_FAILED, 8); + sLog.outDetail("STORAGE: Unable to read item"); + _player->SendEquipError(msg, pItem, NULL); + } + data << pItem->GetGUID(); + SendPacket(&data); + } + else + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); +} + +void WorldSession::HandlePageQuerySkippedOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_PAGE_TEXT_QUERY"); + + uint32 itemid; + uint64 guid; + + recv_data >> itemid >> guid; + + sLog.outDetail("Packet Info: itemid: %u guidlow: %u guidentry: %u guidhigh: %u", + itemid, GUID_LOPART(guid), GUID_ENPART(guid), GUID_HIPART(guid)); +} + +void WorldSession::HandleSellItemOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_SELL_ITEM"); + uint64 vendorguid, itemguid; + uint32 count; + + recv_data >> vendorguid >> itemguid >> count; + + if (!itemguid) + return; + + Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR); + if (!pCreature) + { + sLog.outDebug("WORLD: HandleSellItemOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid))); + _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, itemguid, 0); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + Item *pItem = _player->GetItemByGuid(itemguid); + if (pItem) + { + // prevent sell not owner item + if (_player->GetGUID() != pItem->GetOwnerGUID()) + { + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); + return; + } + + // prevent sell non empty bag by drag-and-drop at vendor's item list + if (pItem->IsBag() && !((Bag*)pItem)->IsEmpty()) + { + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); + return; + } + + // prevent sell currently looted item + if (_player->GetLootGUID() == pItem->GetGUID()) + { + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); + return; + } + + // special case at auto sell (sell all) + if (count == 0) + { + count = pItem->GetCount(); + } + else + { + // prevent sell more items that exist in stack (possible only not from client) + if (count > pItem->GetCount()) + { + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); + return; + } + } + + ItemPrototype const *pProto = pItem->GetProto(); + if (pProto) + { + if (pProto->SellPrice > 0) + { + if (count < pItem->GetCount()) // need split items + { + Item *pNewItem = pItem->CloneItem(count, _player); + if (!pNewItem) + { + sLog.outError("WORLD: HandleSellItemOpcode - could not create clone of item %u; count = %u", pItem->GetEntry(), count); + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); + return; + } + + pItem->SetCount(pItem->GetCount() - count); + _player->ItemRemovedQuestCheck(pItem->GetEntry(), count); + if (_player->IsInWorld()) + pItem->SendUpdateToPlayer(_player); + pItem->SetState(ITEM_CHANGED, _player); + + _player->AddItemToBuyBackSlot(pNewItem); + if (_player->IsInWorld()) + pNewItem->SendUpdateToPlayer(_player); + } + else + { + _player->ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount()); + _player->RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true); + pItem->RemoveFromUpdateQueueOf(_player); + _player->AddItemToBuyBackSlot(pItem); + } + + uint32 money = pProto->SellPrice * count; + _player->ModifyMoney(money); + _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS, money); + } + else + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); + return; + } + } + _player->SendSellError(SELL_ERR_CANT_FIND_ITEM, pCreature, itemguid, 0); + return; +} + +void WorldSession::HandleBuybackItem(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_BUYBACK_ITEM"); + uint64 vendorguid; + uint32 slot; + + recv_data >> vendorguid >> slot; + + Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR); + if (!pCreature) + { + sLog.outDebug("WORLD: HandleBuybackItem - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid))); + _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + Item *pItem = _player->GetItemFromBuyBackSlot(slot); + if (pItem) + { + uint32 price = _player->GetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + slot - BUYBACK_SLOT_START); + if (_player->GetMoney() < price) + { + _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, pItem->GetEntry(), 0); + return; + } + + ItemPosCountVec dest; + uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false); + if (msg == EQUIP_ERR_OK) + { + _player->ModifyMoney(-(int32)price); + _player->RemoveItemFromBuyBackSlot(slot, false); + _player->ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount()); + _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, pItem->GetEntry(), pItem->GetCount()); + _player->StoreItem(dest, pItem, true); + } + else + _player->SendEquipError(msg, pItem, NULL); + return; + } + else + _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, pCreature, 0, 0); +} + +void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_BUY_ITEM_IN_SLOT"); + uint64 vendorguid, bagguid; + uint32 item, slot, count; + uint8 bagslot; + + recv_data >> vendorguid >> item >> slot >> bagguid >> bagslot >> count; + + // client expects count starting at 1, and we send vendorslot+1 to client already + if (slot > 0) + --slot; + else + return; // cheating + + uint8 bag = NULL_BAG; // init for case invalid bagGUID + + // find bag slot by bag guid + if (bagguid == _player->GetGUID()) + bag = INVENTORY_SLOT_BAG_0; + else + { + for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + { + if (Bag *pBag = (Bag*)_player->GetItemByPos(INVENTORY_SLOT_BAG_0,i)) + { + if (bagguid == pBag->GetGUID()) + { + bag = i; + break; + } + } + } + } + + // bag not found, cheating? + if (bag == NULL_BAG) + return; + + GetPlayer()->BuyItemFromVendorSlot(vendorguid,slot,item,count,bag,bagslot); +} + +void WorldSession::HandleBuyItemOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_BUY_ITEM"); + uint64 vendorguid; + uint32 item, slot, count; + uint8 unk1; + + recv_data >> vendorguid >> item >> slot >> count >> unk1; + + // client expects count starting at 1, and we send vendorslot+1 to client already + if (slot > 0) + --slot; + else + return; // cheating + + GetPlayer()->BuyItemFromVendorSlot(vendorguid,slot,item,count,NULL_BAG,NULL_SLOT); +} + +void WorldSession::HandleListInventoryOpcode(WorldPacket & recv_data) +{ + uint64 guid; + + recv_data >> guid; + + if (!GetPlayer()->isAlive()) + return; + + sLog.outDebug("WORLD: Recvd CMSG_LIST_INVENTORY"); + + SendListInventory(guid); +} + +void WorldSession::SendListInventory(uint64 vendorguid) +{ + sLog.outDebug("WORLD: Sent SMSG_LIST_INVENTORY"); + + Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR); + if (!pCreature) + { + sLog.outDebug("WORLD: SendListInventory - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid))); + _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + // Stop the npc if moving + pCreature->StopMoving(); + + VendorItemData const* vItems = pCreature->GetVendorItems(); + if (!vItems) + { + _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); + return; + } + + uint8 numitems = vItems->GetItemCount(); + uint8 count = 0; + + WorldPacket data(SMSG_LIST_INVENTORY, (8+1+numitems*8*4)); + data << uint64(vendorguid); + + size_t count_pos = data.wpos(); + data << uint8(count); + + float discountMod = _player->GetReputationPriceDiscount(pCreature); + + for (uint8 vendorslot = 0; vendorslot < numitems; ++vendorslot ) + { + if (VendorItem const* crItem = vItems->GetItem(vendorslot)) + { + if (ItemPrototype const *pProto = objmgr.GetItemPrototype(crItem->item)) + { + if ((pProto->AllowableClass & _player->getClassMask()) == 0 && pProto->Bonding == BIND_WHEN_PICKED_UP && !_player->isGameMaster()) + continue; + // Only display items in vendor lists for the team the + // player is on. If GM on, display all items. + // `item_template`.`Faction` is actually `Team`. + // 1 == Horde / 2 == Alliance. Field will be renamed in later + // patch. + if (pProto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY && _player->GetTeam() == ALLIANCE || pProto->Flags2 == ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && _player->GetTeam() == HORDE && !_player->isGameMaster()) + continue; + ++count; + + // reputation discount + int32 price = uint32(floor(pProto->BuyPrice * discountMod)); + + data << uint32(vendorslot+1); // client expects counting to start at 1 + data << uint32(crItem->item); + data << uint32(pProto->DisplayInfoID); + data << int32(crItem->maxcount <= 0 ? 0xFFFFFFFF : pCreature->GetVendorItemCurrentCount(crItem)); + data << uint32(price); + data << uint32(pProto->MaxDurability); + data << uint32(pProto->BuyCount); + data << uint32(crItem->ExtendedCost); + } + } + } + + if (count == 0 || data.size() != 8 + 1 + size_t(count) * 8 * 4) + return; + + data.put(count_pos, count); + SendPacket(&data); +} + +void WorldSession::HandleAutoStoreBagItemOpcode(WorldPacket & recv_data) +{ + //sLog.outDebug("WORLD: CMSG_AUTOSTORE_BAG_ITEM"); + uint8 srcbag, srcslot, dstbag; + + recv_data >> srcbag >> srcslot >> dstbag; + //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u", srcbag, srcslot, dstbag); + + Item *pItem = _player->GetItemByPos(srcbag, srcslot); + if (!pItem) + return; + + if (!_player->IsValidPos(dstbag,NULL_SLOT)) + { + _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); + return; + } + + uint16 src = pItem->GetPos(); + + // check unequip potability for equipped items and bank bags + if (_player->IsEquipmentPos (src) || _player->IsBagPos (src)) + { + uint8 msg = _player->CanUnequipItem(src, !_player->IsBagPos (src)); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pItem, NULL); + return; + } + } + + ItemPosCountVec dest; + uint8 msg = _player->CanStoreItem(dstbag, NULL_SLOT, dest, pItem, false); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pItem, NULL); + return; + } + + // no-op: placed in same slot + if (dest.size() == 1 && dest[0].pos == src) + { + // just remove grey item state + _player->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); + return; + } + + _player->RemoveItem(srcbag, srcslot, true); + _player->StoreItem(dest, pItem, true); +} + +void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: CMSG_BUY_BANK_SLOT"); + + uint64 guid; + recvPacket >> guid; + + // cheating protection + /* not critical if "cheated", and check skip allow by slots in bank windows open by .bank command. + Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER); + if (!pCreature) + { + sLog.outDebug("WORLD: HandleBuyBankSlotOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + */ + + uint32 slot = _player->GetBankBagSlotCount(); + + // next slot + ++slot; + + sLog.outDetail("PLAYER: Buy bank bag slot, slot number = %u", slot); + + BankBagSlotPricesEntry const* slotEntry = sBankBagSlotPricesStore.LookupEntry(slot); + + WorldPacket data(SMSG_BUY_BANK_SLOT_RESULT, 4); + + if (!slotEntry) + { + data << uint32(ERR_BANKSLOT_FAILED_TOO_MANY); + SendPacket(&data); + return; + } + + uint32 price = slotEntry->price; + + if (_player->GetMoney() < price) + { + data << uint32(ERR_BANKSLOT_INSUFFICIENT_FUNDS); + SendPacket(&data); + return; + } + + _player->SetBankBagSlotCount(slot); + _player->ModifyMoney(-int32(price)); + + data << uint32(ERR_BANKSLOT_OK); + SendPacket(&data); + + _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT); +} + +void WorldSession::HandleAutoBankItemOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: CMSG_AUTOBANK_ITEM"); + uint8 srcbag, srcslot; + + recvPacket >> srcbag >> srcslot; + sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); + + Item *pItem = _player->GetItemByPos(srcbag, srcslot); + if (!pItem) + return; + + ItemPosCountVec dest; + uint8 msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, dest, pItem, false); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pItem, NULL); + return; + } + + _player->RemoveItem(srcbag, srcslot, true); + _player->BankItem(dest, pItem, true); +} + +void WorldSession::HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket) +{ + sLog.outDebug("WORLD: CMSG_AUTOSTORE_BANK_ITEM"); + uint8 srcbag, srcslot; + + recvPacket >> srcbag >> srcslot; + sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); + + Item *pItem = _player->GetItemByPos(srcbag, srcslot); + if (!pItem) + return; + + if (_player->IsBankPos(srcbag, srcslot)) // moving from bank to inventory + { + ItemPosCountVec dest; + uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pItem, NULL); + return; + } + + _player->RemoveItem(srcbag, srcslot, true); + _player->StoreItem(dest, pItem, true); + } + else // moving from inventory to bank + { + ItemPosCountVec dest; + uint8 msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, dest, pItem, false); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pItem, NULL); + return; + } + + _player->RemoveItem(srcbag, srcslot, true); + _player->BankItem(dest, pItem, true); + } +} + +void WorldSession::HandleSetAmmoOpcode(WorldPacket & recv_data) +{ + if (!GetPlayer()->isAlive()) + { + GetPlayer()->SendEquipError(EQUIP_ERR_YOU_ARE_DEAD, NULL, NULL); + return; + } + + sLog.outDebug("WORLD: CMSG_SET_AMMO"); + uint32 item; + + recv_data >> item; + + if (!item) + GetPlayer()->RemoveAmmo(); + else + GetPlayer()->SetAmmo(item); +} + +void WorldSession::SendEnchantmentLog(uint64 Target, uint64 Caster,uint32 ItemID,uint32 SpellID) +{ + WorldPacket data(SMSG_ENCHANTMENTLOG, (8+8+4+4+1)); // last check 2.0.10 + data << uint64(Target); + data << uint64(Caster); + data << uint32(ItemID); + data << uint32(SpellID); + data << uint8(0); + SendPacket(&data); +} + +void WorldSession::SendItemEnchantTimeUpdate(uint64 Playerguid, uint64 Itemguid,uint32 slot,uint32 Duration) +{ + // last check 2.0.10 + WorldPacket data(SMSG_ITEM_ENCHANT_TIME_UPDATE, (8+4+4+8)); + data << uint64(Itemguid); + data << uint32(slot); + data << uint32(Duration); + data << uint64(Playerguid); + SendPacket(&data); +} + +void WorldSession::HandleItemNameQueryOpcode(WorldPacket & recv_data) +{ + uint32 itemid; + recv_data >> itemid; + recv_data.read_skip(); // guid + + sLog.outDebug("WORLD: CMSG_ITEM_NAME_QUERY %u", itemid); + ItemPrototype const *pProto = objmgr.GetItemPrototype(itemid); + if (pProto) + { + std::string Name; + Name = pProto->Name1; + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId); + if (il) + { + if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty()) + Name = il->Name[loc_idx]; + } + } + // guess size + WorldPacket data(SMSG_ITEM_NAME_QUERY_RESPONSE, (4+10)); + data << uint32(pProto->ItemId); + data << Name; + data << uint32(pProto->InventoryType); + SendPacket(&data); + return; + } +// This is a BS check, there are lots of items listed in Item.dbc that do not even exist on official -- so we can NEVER get the data for them. +// If you *really* want to spam your error log -- uncomment this. +/* else + { + // listed in dbc or not expected to exist unknown item + if (sItemStore.LookupEntry(itemid)) + sLog.outErrorDb("WORLD: CMSG_ITEM_NAME_QUERY for item %u failed (item listed in Item.dbc but not exist in DB)", itemid); + else + sLog.outError("WORLD: CMSG_ITEM_NAME_QUERY for item %u failed (unknown item, not listed in Item.dbc)", itemid); + } */ +} + +void WorldSession::HandleWrapItemOpcode(WorldPacket& recv_data) +{ + sLog.outDebug("Received opcode CMSG_WRAP_ITEM"); + + uint8 gift_bag, gift_slot, item_bag, item_slot; + //recv_data.hexlike(); + + recv_data >> gift_bag >> gift_slot; // paper + recv_data >> item_bag >> item_slot; // item + + sLog.outDebug("WRAP: receive gift_bag = %u, gift_slot = %u, item_bag = %u, item_slot = %u", gift_bag, gift_slot, item_bag, item_slot); + + Item *gift = _player->GetItemByPos(gift_bag, gift_slot); + if (!gift) + { + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL); + return; + } + + if (!gift->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPER))// cheating: non-wrapper wrapper + { + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL); + return; + } + + Item *item = _player->GetItemByPos(item_bag, item_slot); + + if (!item) + { + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, item, NULL); + return; + } + + if (item == gift) // not possable with pacjket from real client + { + _player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL); + return; + } + + if (item->IsEquipped()) + { + _player->SendEquipError(EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED, item, NULL); + return; + } + + if (item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)) // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED); + { + _player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL); + return; + } + + if (item->IsBag()) + { + _player->SendEquipError(EQUIP_ERR_BAGS_CANT_BE_WRAPPED, item, NULL); + return; + } + + if (item->IsSoulBound()) + { + _player->SendEquipError(EQUIP_ERR_BOUND_CANT_BE_WRAPPED, item, NULL); + return; + } + + if (item->GetMaxStackCount() != 1) + { + _player->SendEquipError(EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED, item, NULL); + return; + } + + // maybe not correct check (it is better than nothing) + if (item->GetProto()->MaxCount>0) + { + _player->SendEquipError(EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED, item, NULL); + return; + } + + CharacterDatabase.BeginTransaction(); + CharacterDatabase.PExecute("INSERT INTO character_gifts VALUES ('%u', '%u', '%u', '%u')", GUID_LOPART(item->GetOwnerGUID()), item->GetGUIDLow(), item->GetEntry(), item->GetUInt32Value(ITEM_FIELD_FLAGS)); + item->SetEntry(gift->GetEntry()); + + switch (item->GetEntry()) + { + case 5042: item->SetEntry(5043); break; + case 5048: item->SetEntry(5044); break; + case 17303: item->SetEntry(17302); break; + case 17304: item->SetEntry(17305); break; + case 17307: item->SetEntry(17308); break; + case 21830: item->SetEntry(21831); break; + } + item->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); + item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED); + item->SetState(ITEM_CHANGED, _player); + + if (item->GetState() == ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance` + { + // after save it will be impossible to remove the item from the queue + item->RemoveFromUpdateQueueOf(_player); + item->SaveToDB(); // item gave inventory record unchanged and can be save standalone + } + CharacterDatabase.CommitTransaction(); + + uint32 count = 1; + _player->DestroyItemCount(gift, count, true); +} + +void WorldSession::HandleSocketOpcode(WorldPacket& recv_data) +{ + sLog.outDebug("WORLD: CMSG_SOCKET_GEMS"); + + uint64 item_guid; + uint64 gem_guids[MAX_GEM_SOCKETS]; + + recv_data >> item_guid; + if (!item_guid) + return; + + for (int i = 0; i < MAX_GEM_SOCKETS; ++i) + recv_data >> gem_guids[i]; + + //cheat -> tried to socket same gem multiple times + if ((gem_guids[0] && (gem_guids[0] == gem_guids[1] || gem_guids[0] == gem_guids[2])) || + (gem_guids[1] && (gem_guids[1] == gem_guids[2]))) + return; + + Item *itemTarget = _player->GetItemByGuid(item_guid); + if (!itemTarget) //missing item to socket + return; + + ItemPrototype const* itemProto = itemTarget->GetProto(); + if (!itemProto) + return; + + //this slot is excepted when applying / removing meta gem bonus + uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT); + + Item *Gems[MAX_GEM_SOCKETS]; + for (int i = 0; i < MAX_GEM_SOCKETS; ++i) + Gems[i] = gem_guids[i] ? _player->GetItemByGuid(gem_guids[i]) : NULL; + + GemPropertiesEntry const *GemProps[MAX_GEM_SOCKETS]; + for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get geminfo from dbc storage + GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetProto()->GemProperties) : NULL; + + for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe + { + if (!GemProps[i]) + continue; + + // tried to put gem in socket where no socket exists (take care about prismatic sockets) + if (!itemProto->Socket[i].Color) + { + // no prismatic socket + if (!itemTarget->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT)) + return; + + // not first not-colored (not normaly used) socket + if (i != 0 && !itemProto->Socket[i-1].Color && (i+1 >= MAX_GEM_SOCKETS || itemProto->Socket[i+1].Color)) + return; + + // ok, this is first not colored socket for item with prismatic socket + } + + // tried to put normal gem in meta socket + if (itemProto->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META) + return; + + // tried to put meta gem in normal socket + if (itemProto->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META) + return; + } + + uint32 GemEnchants[MAX_GEM_SOCKETS]; + uint32 OldEnchants[MAX_GEM_SOCKETS]; + for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get new and old enchantments + { + GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0; + OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i)); + } + + // check unique-equipped conditions + for (int i = 0; i < MAX_GEM_SOCKETS; ++i) + { + if (!Gems[i]) + continue; + + // continue check for case when attempt add 2 similar unique equipped gems in one item. + ItemPrototype const* iGemProto = Gems[i]->GetProto(); + + // unique item (for new and already placed bit removed enchantments + if (iGemProto->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED) + { + for (int j = 0; j < MAX_GEM_SOCKETS; ++j) + { + if (i == j) // skip self + continue; + + if (Gems[j]) + { + if (iGemProto->ItemId == Gems[j]->GetEntry()) + { + _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); + return; + } + } + else if (OldEnchants[j]) + { + if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j])) + { + if (iGemProto->ItemId == enchantEntry->GemID) + { + _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); + return; + } + } + } + + } + } + + // unique limit type item + int32 limit_newcount = 0; + if (iGemProto->ItemLimitCategory) + { + if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->ItemLimitCategory)) + { + for (int j = 0; j < MAX_GEM_SOCKETS; ++j) + { + if (Gems[j]) + { + // destroyed gem + if (OldEnchants[j]) + { + if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j])) + if (ItemPrototype const* jProto = ObjectMgr::GetItemPrototype(enchantEntry->GemID)) + if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory) + --limit_newcount; + } + + // new gem + if (iGemProto->ItemLimitCategory == Gems[j]->GetProto()->ItemLimitCategory) + ++limit_newcount; + } + // existed gem + else if (OldEnchants[j]) + { + if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j])) + if (ItemPrototype const* jProto = ObjectMgr::GetItemPrototype(enchantEntry->GemID)) + if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory) + ++limit_newcount; + } + } + + if (limit_newcount > 0 && uint32(limit_newcount) > limitEntry->maxCount) + { + _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); + return; + } + } + } + + // for equipped item check all equipment for duplicate equipped gems + if (itemTarget->IsEquipped()) + { + if (uint8 res = _player->CanEquipUniqueItem(Gems[i],slot,limit_newcount >= 0 ? limit_newcount : 0)) + { + _player->SendEquipError(res, itemTarget, NULL); + return; + } + } + } + + bool SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus + _player->ToggleMetaGemsActive(slot, false); //turn off all metagems (except for the target item) + + //if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met + + //remove ALL enchants + for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) + _player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),false); + + for (int i = 0; i < MAX_GEM_SOCKETS; ++i) + { + if (GemEnchants[i]) + { + itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i],0,0); + if (Item* guidItem = _player->GetItemByGuid(gem_guids[i])) + _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true); + } + } + + for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) + _player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),true); + + bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state + if (SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change... + { + _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,false); + itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetProto()->socketBonus : 0), 0, 0); + _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,true); + //it is not displayed, client has an inbuilt system to determine if the bonus is activated + } + + _player->ToggleMetaGemsActive(slot, true); //turn on all metagems (except for target item) +} + +void WorldSession::HandleCancelTempEnchantmentOpcode(WorldPacket& recv_data) +{ + sLog.outDebug("WORLD: CMSG_CANCEL_TEMP_ENCHANTMENT"); + + uint32 eslot; + + recv_data >> eslot; + + // apply only to equipped item + if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0,eslot)) + return; + + Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, eslot); + + if (!item) + return; + + if (!item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) + return; + + GetPlayer()->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,false); + item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT); +} + +void WorldSession::HandleItemRefundInfoRequest(WorldPacket& recv_data) +{ + sLog.outDebug("WORLD: CMSG_ITEM_REFUND_INFO"); + + uint64 guid; + recv_data >> guid; // item guid + + Item *item = _player->GetItemByGuid(guid); + if (!item) + { + sLog.outDebug("Item refund: item not found!"); + return; + } + + GetPlayer()->SendRefundInfo(item); +} + +void WorldSession::HandleItemRefund(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_ITEM_REFUND"); + uint64 guid; + recv_data >> guid; // item guid + + Item *item = _player->GetItemByGuid(guid); + if (!item) + { + sLog.outDebug("Item refund: item not found!"); + return; + } + + GetPlayer()->RefundItem(item); +} + +/** + * Handles the packet sent by the client when requesting information about item text. + * + * This function is called when player clicks on item which has some flag set + */ +void WorldSession::HandleItemTextQuery(WorldPacket & recv_data ) +{ + uint64 itemGuid; + recv_data >> itemGuid; + + sLog.outDebug("CMSG_ITEM_TEXT_QUERY item guid: %u", GUID_LOPART(itemGuid)); + + WorldPacket data(SMSG_ITEM_TEXT_QUERY_RESPONSE, (4+10)); // guess size + + if (Item *item = _player->GetItemByGuid(itemGuid)) + { + data << uint8(0); // has text + data << uint64(itemGuid); // item guid + data << item->GetText(); + } + else + { + data << uint8(1); // no text + } + + SendPacket(&data); +} diff --git a/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp b/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp new file mode 100644 index 00000000000..0746973ff4c --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp @@ -0,0 +1,251 @@ +/* + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "LFGMgr.h" +#include "WorldSession.h" +#include "WorldPacket.h" +#include "Player.h" + +void WorldSession::HandleLfgJoinOpcode(WorldPacket &recv_data) +{ + sLog.outDebug("CMSG_LFG_JOIN"); + + uint8 numDungeons; + uint32 dungeon; + uint32 roles; + std::string comment; + + recv_data >> roles; + recv_data.read_skip(); // unk - always 0 + recv_data.read_skip(); // unk - always 0 + recv_data >> numDungeons; + if (!numDungeons) + { + sLog.outError("Invalid CMSG_LFG_JOIN packet sent by %s", GetPlayer()->GetName()); + recv_data.rpos(recv_data.wpos()); + return; + } + + GetPlayer()->m_lookingForGroup.roles = uint8(roles); + for (int8 i = 0 ; i < numDungeons; ++i) + { + recv_data >> dungeon; + // remove the type from the dungeon entry + GetPlayer()->m_lookingForGroup.applyDungeons.insert((dungeon & 0x00FFFFFF)); + } + + recv_data >> numDungeons; // unk - always 3 + for (int8 i = 0 ; i < numDungeons; ++i) + recv_data.read_skip(); // unk - always 0 + + recv_data >> comment; + + GetPlayer()->m_lookingForGroup.comment = comment; + sLFGMgr.Join(GetPlayer()); +} + +void WorldSession::HandleLfgLeaveOpcode(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("CMSG_LFG_LEAVE"); + + // Check cheating - only leader can leave the queue + if (Group *grp = GetPlayer()->GetGroup()) + { + if (grp->GetLeaderGUID() != GetPlayer()->GetGUID()) + return; + else + sLFGMgr.Leave(GetPlayer(), grp); + } + else + sLFGMgr.Leave(GetPlayer()); +} + +void WorldSession::HandleLfgSetRolesOpcode(WorldPacket &recv_data) +{ + sLog.outDebug("CMSG_LFG_SET_ROLES"); + + uint8 roles; + recv_data >> roles; // Player Group Roles + + Group *grp = GetPlayer()->GetGroup(); + if (!grp) + return; + GetPlayer()->m_lookingForGroup.roles = roles; + sLFGMgr.UpdateRoleCheck(grp, GetPlayer()); +} + +void WorldSession::HandleSetLfgCommentOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("CMSG_SET_LFG_COMMENT"); + + std::string comment; + recv_data >> comment; + + GetPlayer()->m_lookingForGroup.comment = comment; +} + +void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket &/*recv_data*/) +{ + sLog.outDebug("CMSG_LFD_PLAYER_LOCK_INFO_REQUEST"); + sLFGMgr.SendLfgPlayerInfo(GetPlayer()); +} + +void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket &/*recv_data*/) +{ + sLog.outDebug("CMSG_LFD_PARTY_LOCK_INFO_REQUEST"); + sLFGMgr.SendLfgPartyInfo(GetPlayer()); +} + +void WorldSession::SendLfgUpdatePlayer(uint8 updateType) +{ + bool queued = false; + bool extrainfo = false; + + switch(updateType) + { + case LFG_UPDATETYPE_JOIN_PROPOSAL: + case LFG_UPDATETYPE_ADDED_TO_QUEUE: + queued = true; + extrainfo = true; + break; + //case LFG_UPDATETYPE_CLEAR_LOCK_LIST: // TODO: Sometimes has extrainfo - Check ocurrences... + case LFG_UPDATETYPE_PROPOSAL_FOUND: + extrainfo = true; + break; + } + sLog.outDebug("SMSG_LFG_UPDATE_PLAYER"); + WorldPacket data(SMSG_LFG_UPDATE_PLAYER, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + GetPlayer()->m_lookingForGroup.applyDungeons.size() * 4 + GetPlayer()->m_lookingForGroup.comment.length())); + data << uint8(updateType); // Lfg Update type + data << uint8(extrainfo); // Extra info + if (extrainfo) + { + data << uint8(queued); // Join the queue + data << uint8(0); // unk - Always 0 + data << uint8(0); // unk - Always 0 + + uint8 size = GetPlayer()->m_lookingForGroup.applyDungeons.size(); + data << uint8(size); + + for (LfgDungeonSet::const_iterator it = GetPlayer()->m_lookingForGroup.applyDungeons.begin(); it != GetPlayer()->m_lookingForGroup.applyDungeons.end(); ++it) + data << uint32(*it); + data << GetPlayer()->m_lookingForGroup.comment; + } + SendPacket(&data); +} + +void WorldSession::SendLfgUpdateParty(uint8 updateType) +{ + bool join = false; + bool extrainfo = false; + bool queued = false; + + switch(updateType) + { + case LFG_UPDATETYPE_JOIN_PROPOSAL: + extrainfo = true; + break; + case LFG_UPDATETYPE_ADDED_TO_QUEUE: + extrainfo = true; + join = true; + queued = true; + break; + case LFG_UPDATETYPE_CLEAR_LOCK_LIST: + // join = true; // TODO: Sometimes queued and extrainfo - Check ocurrences... + queued = true; + break; + case LFG_UPDATETYPE_PROPOSAL_FOUND: + extrainfo = true; + join = true; + break; + } + + sLog.outDebug("SMSG_LFG_UPDATE_PARTY"); + WorldPacket data(SMSG_LFG_UPDATE_PARTY, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + 1 + GetPlayer()->m_lookingForGroup.applyDungeons.size() * 4 + GetPlayer()->m_lookingForGroup.comment.length())); + data << uint8(updateType); // Lfg Update type + data << uint8(extrainfo); // Extra info + if (extrainfo) + { + data << uint8(join); // LFG Join + data << uint8(queued); // Join the queue + data << uint8(0); // unk - Always 0 + data << uint8(0); // unk - Always 0 + for (uint8 i = 0; i < 3; ++i) + data << uint8(0); // unk - Always 0 + + uint8 size = GetPlayer()->m_lookingForGroup.applyDungeons.size(); + data << uint8(size); + + for (LfgDungeonSet::const_iterator it = GetPlayer()->m_lookingForGroup.applyDungeons.begin(); it != GetPlayer()->m_lookingForGroup.applyDungeons.end(); ++it) + data << uint32(*it); + + data << GetPlayer()->m_lookingForGroup.comment; + } + SendPacket(&data); +} + +void WorldSession::SendLfgRoleChosen(uint64 guid, uint8 roles) +{ + sLog.outDebug("SMSG_LFG_ROLE_CHOSEN"); + + WorldPacket data(SMSG_LFG_ROLE_CHOSEN); + data << uint64(guid); // Guid + data << uint8(roles > 0); // Ready + data << uint32(roles); // Roles + SendPacket(&data); +} + +void WorldSession::SendLfgJoinResult(uint8 checkResult, uint8 checkValue) +{ + if (checkResult == LFG_JOIN_PARTY_NOT_MEET_REQS) // Should never happen - its handled in Mgr + return; + + sLog.outDebug("SMSG_LFG_JOIN_RESULT"); + + WorldPacket data(SMSG_LFG_JOIN_RESULT); + data << uint32(checkResult); // Check Result + data << uint32(checkValue); // Check Value + SendPacket(&data); +} + +void WorldSession::SendLfgQueueStatus(uint32 dungeon, int32 waitTime, int32 avgWaitTime, int32 waitTimeTanks, int32 waitTimeHealer, int32 waitTimeDps, uint32 queuedTime, uint8 tanks, uint8 healers, uint8 dps) +{ + sLog.outDebug("SMSG_LFG_QUEUE_STATUS"); + WorldPacket data(SMSG_LFG_QUEUE_STATUS); + + data << uint32(dungeon); // Dungeon + data << uint32(avgWaitTime); // Average Wait time + data << uint32(waitTime); // Wait Time + data << uint32(waitTimeTanks); // Wait Tanks + data << uint32(waitTimeHealer); // Wait Healers + data << uint32(waitTimeDps); // Wait Dps + data << uint8(tanks); // Tanks needed + data << uint8(healers); // Healers needed + data << uint8(dps); // Dps needed + data << uint32(queuedTime); // Player wait time in queue + SendPacket(&data); +} + +void WorldSession::SendLfgUpdateSearch(bool update) +{ + sLog.outDebug("SMSG_LFG_UPDATE_SEARCH"); + + WorldPacket data(SMSG_LFG_UPDATE_SEARCH); + data << uint8(update); // In Lfg Queue? + SendPacket(&data); +} diff --git a/src/server/game/Server/Protocol/Handlers/LootHandler.cpp b/src/server/game/Server/Protocol/Handlers/LootHandler.cpp new file mode 100644 index 00000000000..55aefb3c1f5 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/LootHandler.cpp @@ -0,0 +1,549 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "Log.h" +#include "Corpse.h" +#include "GameObject.h" +#include "Player.h" +#include "ObjectAccessor.h" +#include "WorldSession.h" +#include "LootMgr.h" +#include "Object.h" +#include "Group.h" +#include "World.h" +#include "Util.h" + +void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); + Player *player = GetPlayer(); + uint64 lguid = player->GetLootGUID(); + Loot *loot; + uint8 lootSlot; + + recv_data >> lootSlot; + + if (IS_GAMEOBJECT_GUID(lguid)) + { + GameObject *go = player->GetMap()->GetGameObject(lguid); + + // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO + if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player,INTERACTION_DISTANCE))) + { + player->SendLootRelease(lguid); + return; + } + + loot = &go->loot; + } + else if (IS_ITEM_GUID(lguid)) + { + Item *pItem = player->GetItemByGuid(lguid); + + if (!pItem) + { + player->SendLootRelease(lguid); + return; + } + + loot = &pItem->loot; + } + else if (IS_CORPSE_GUID(lguid)) + { + Corpse *bones = ObjectAccessor::GetCorpse(*player, lguid); + if (!bones) + { + player->SendLootRelease(lguid); + return; + } + loot = &bones->loot; + } + else + { + Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); + + bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass() == CLASS_ROGUE && pCreature->lootForPickPocketed); + + if (!ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) + { + player->SendLootRelease(lguid); + return; + } + + loot = &pCreature->loot; + } + + QuestItem *qitem = NULL; + QuestItem *ffaitem = NULL; + QuestItem *conditem = NULL; + + LootItem *item = loot->LootItemInSlot(lootSlot,player,&qitem,&ffaitem,&conditem); + + if (!item) + { + player->SendEquipError(EQUIP_ERR_ALREADY_LOOTED, NULL, NULL); + return; + } + + // questitems use the blocked field for other purposes + if (!qitem && item->is_blocked) + { + player->SendLootRelease(lguid); + return; + } + + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item->itemid, item->count); + if (msg == EQUIP_ERR_OK) + { + Item * newitem = player->StoreNewItem(dest, item->itemid, true, item->randomPropertyId); + + if (qitem) + { + qitem->is_looted = true; + //freeforall is 1 if everyone's supposed to get the quest item. + if (item->freeforall || loot->GetPlayerQuestItems().size() == 1) + player->SendNotifyLootItemRemoved(lootSlot); + else + loot->NotifyQuestItemRemoved(qitem->index); + } + else + { + if (ffaitem) + { + //freeforall case, notify only one player of the removal + ffaitem->is_looted=true; + player->SendNotifyLootItemRemoved(lootSlot); + } + else + { + //not freeforall, notify everyone + if (conditem) + conditem->is_looted=true; + loot->NotifyItemRemoved(lootSlot); + } + } + + //if only one person is supposed to loot the item, then set it to looted + if (!item->freeforall) + item->is_looted = true; + + --loot->unlootedCount; + + player->SendNewItem(newitem, uint32(item->count), false, false, true); + player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count); + player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item->count); + player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item->itemid, item->count); + } + else + player->SendEquipError(msg, NULL, NULL); +} + +void WorldSession::HandleLootMoneyOpcode(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("WORLD: CMSG_LOOT_MONEY"); + + Player *player = GetPlayer(); + uint64 guid = player->GetLootGUID(); + if (!guid) + return; + + Loot *pLoot = NULL; + + switch(GUID_HIPART(guid)) + { + case HIGHGUID_GAMEOBJECT: + { + GameObject *pGameObject = GetPlayer()->GetMap()->GetGameObject(guid); + + // not check distance for GO in case owned GO (fishing bobber case, for example) + if (pGameObject && ((pGameObject->GetOwnerGUID() == _player->GetGUID() || pGameObject->IsWithinDistInMap(_player,INTERACTION_DISTANCE)))) + pLoot = &pGameObject->loot; + + break; + } + case HIGHGUID_CORPSE: // remove insignia ONLY in BG + { + Corpse *bones = ObjectAccessor::GetCorpse(*GetPlayer(), guid); + + if (bones && bones->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) + pLoot = &bones->loot; + + break; + } + case HIGHGUID_ITEM: + { + if (Item *item = GetPlayer()->GetItemByGuid(guid)) + pLoot = &item->loot; + break; + } + case HIGHGUID_UNIT: + { + Creature* pCreature = GetPlayer()->GetMap()->GetCreature(guid); + + bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass() == CLASS_ROGUE && pCreature->lootForPickPocketed); + + if (ok_loot && pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) + pLoot = &pCreature->loot ; + + break; + } + default: + return; // unlootable type + } + + if (pLoot) + { + if (!IS_ITEM_GUID(guid) && player->GetGroup()) //item can be looted only single player + { + Group *group = player->GetGroup(); + + std::vector playersNear; + for (GroupReference *itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* playerGroup = itr->getSource(); + if (!playerGroup) + continue; + if (player->IsWithinDistInMap(playerGroup,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) + playersNear.push_back(playerGroup); + } + + uint32 money_per_player = uint32((pLoot->gold)/(playersNear.size())); + + for (std::vector::const_iterator i = playersNear.begin(); i != playersNear.end(); ++i) + { + (*i)->ModifyMoney(money_per_player); + (*i)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, money_per_player); + //Offset surely incorrect, but works + WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4); + data << uint32(money_per_player); + (*i)->GetSession()->SendPacket(&data); + } + } + else + { + player->ModifyMoney(pLoot->gold); + player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, pLoot->gold); + } + pLoot->gold = 0; + pLoot->NotifyMoneyRemoved(); + } +} + +void WorldSession::HandleLootOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_LOOT"); + + uint64 guid; + recv_data >> guid; + + // Check possible cheat + if (!_player->isAlive()) + return; + + GetPlayer()->SendLoot(guid, LOOT_CORPSE); +} + +void WorldSession::HandleLootReleaseOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_LOOT_RELEASE"); + + // cheaters can modify lguid to prevent correct apply loot release code and re-loot + // use internal stored guid + recv_data.read_skip(); // guid; + + if (uint64 lguid = GetPlayer()->GetLootGUID()) + DoLootRelease(lguid); +} + +void WorldSession::DoLootRelease(uint64 lguid) +{ + Player *player = GetPlayer(); + Loot *loot; + + player->SetLootGUID(0); + player->SendLootRelease(lguid); + + player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); + + if (!player->IsInWorld()) + return; + + if (IS_GAMEOBJECT_GUID(lguid)) + { + GameObject *go = GetPlayer()->GetMap()->GetGameObject(lguid); + + // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO + if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player,INTERACTION_DISTANCE))) + return; + + loot = &go->loot; + + if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR) + { + // locked doors are opened with spelleffect openlock, prevent remove its as looted + go->UseDoorOrButton(); + } + else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) + { + // GO is mineral vein? so it is not removed after its looted + if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST) + { + uint32 go_min = go->GetGOInfo()->chest.minSuccessOpens; + uint32 go_max = go->GetGOInfo()->chest.maxSuccessOpens; + + // only vein pass this check + if (go_min != 0 && go_max > go_min) + { + float amount_rate = sWorld.getRate(RATE_MINING_AMOUNT); + float min_amount = go_min*amount_rate; + float max_amount = go_max*amount_rate; + + go->AddUse(); + float uses = float(go->GetUseCount()); + + if (uses < max_amount) + { + if (uses >= min_amount) + { + float chance_rate = sWorld.getRate(RATE_MINING_NEXT); + + int32 ReqValue = 175; + LockEntry const *lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId); + if (lockInfo) + ReqValue = lockInfo->Skill[0]; + float skill = float(player->GetSkillValue(SKILL_MINING))/(ReqValue+25); + double chance = pow(0.8*chance_rate,4*(1/double(max_amount))*double(uses)); + if (roll_chance_f(100*chance+skill)) + { + go->SetLootState(GO_READY); + } + else // not have more uses + go->SetLootState(GO_JUST_DEACTIVATED); + } + else // 100% chance until min uses + go->SetLootState(GO_READY); + } + else // max uses already + go->SetLootState(GO_JUST_DEACTIVATED); + } + else // not vein + go->SetLootState(GO_JUST_DEACTIVATED); + } + else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) + { // The fishing hole used once more + go->AddUse(); // if the max usage is reached, will be despawned in next tick + if (go->GetUseCount() >= irand(go->GetGOInfo()->fishinghole.minSuccessOpens,go->GetGOInfo()->fishinghole.maxSuccessOpens)) + { + go->SetLootState(GO_JUST_DEACTIVATED); + } + else + go->SetLootState(GO_READY); + } + else // not chest (or vein/herb/etc) + go->SetLootState(GO_JUST_DEACTIVATED); + + loot->clear(); + } + else + { + // not fully looted object + go->SetLootState(GO_ACTIVATED); + + // if the round robin player release, reset it. + if (player->GetGUID() == loot->roundRobinPlayer) + { + if (Group* pGroup = player->GetGroup()) + { + if (pGroup->GetLootMethod() != MASTER_LOOT) + { + loot->roundRobinPlayer = 0; + } + } + else + loot->roundRobinPlayer = 0; + } + } + } + else if (IS_CORPSE_GUID(lguid)) // ONLY remove insignia at BG + { + Corpse *corpse = ObjectAccessor::GetCorpse(*player, lguid); + if (!corpse || !corpse->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) + return; + + loot = &corpse->loot; + + if (loot->isLooted()) + { + loot->clear(); + corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); + } + } + else if (IS_ITEM_GUID(lguid)) + { + Item *pItem = player->GetItemByGuid(lguid); + if (!pItem) + return; + + ItemPrototype const* proto = pItem->GetProto(); + + // destroy only 5 items from stack in case prospecting and milling + if ((proto->BagFamily & (BAG_FAMILY_MASK_MINING_SUPP|BAG_FAMILY_MASK_HERBS)) && + proto->Class == ITEM_CLASS_TRADE_GOODS) + { + pItem->m_lootGenerated = false; + pItem->loot.clear(); + + uint32 count = pItem->GetCount(); + + // >=5 checked in spell code, but will work for cheating cases also with removing from another stacks. + if (count > 5) + count = 5; + + player->DestroyItemCount(pItem, count, true); + } + else + // FIXME: item must not be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or cheating possible. + player->DestroyItem(pItem->GetBagSlot(),pItem->GetSlot(), true); + return; // item can be looted only single player + } + else + { + Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); + + bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass() == CLASS_ROGUE && pCreature->lootForPickPocketed); + if (!ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) + return; + + loot = &pCreature->loot; + if (loot->isLooted()) + { + // skip pickpocketing loot for speed, skinning timer redunction is no-op in fact + if (!pCreature->isAlive()) + pCreature->AllLootRemovedFromCorpse(); + + pCreature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + pCreature->SetLootRecipient(NULL); + loot->clear(); + } + else + { + // if the round robin player release, reset it. + if (player->GetGUID() == loot->roundRobinPlayer) + { + if (Group* pGroup = player->GetGroup()) + { + if (pGroup->GetLootMethod() != MASTER_LOOT) + { + loot->roundRobinPlayer = 0; + pGroup->SendLooter(pCreature, NULL); + + // force update of dynamic flags, otherwise other group's players still not able to loot. + pCreature->ForceValuesUpdateAtIndex(UNIT_DYNAMIC_FLAGS); + } + } + else + loot->roundRobinPlayer = 0; + } + } + } + + //Player is not looking at loot list, he doesn't need to see updates on the loot list + loot->RemoveLooter(player->GetGUID()); +} + +void WorldSession::HandleLootMasterGiveOpcode(WorldPacket & recv_data) +{ + uint8 slotid; + uint64 lootguid, target_playerguid; + + recv_data >> lootguid >> slotid >> target_playerguid; + + if (!_player->GetGroup() || _player->GetGroup()->GetLooterGuid() != _player->GetGUID()) + { + _player->SendLootRelease(GetPlayer()->GetLootGUID()); + return; + } + + Player *target = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(target_playerguid, 0, HIGHGUID_PLAYER)); + if (!target) + return; + + sLog.outDebug("WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName()); + + if (_player->GetLootGUID() != lootguid) + return; + + Loot *pLoot = NULL; + + if (IS_CRE_OR_VEH_GUID(GetPlayer()->GetLootGUID())) + { + Creature *pCreature = GetPlayer()->GetMap()->GetCreature(lootguid); + if (!pCreature) + return; + + pLoot = &pCreature->loot; + } + else if (IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) + { + GameObject *pGO = GetPlayer()->GetMap()->GetGameObject(lootguid); + if (!pGO) + return; + + pLoot = &pGO->loot; + } + + if (!pLoot) + return; + + if (slotid > pLoot->items.size()) + { + sLog.outDebug("AutoLootItem: Player %s might be using a hack! (slot %d, size %lu)",GetPlayer()->GetName(), slotid, (unsigned long)pLoot->items.size()); + return; + } + + LootItem& item = pLoot->items[slotid]; + + ItemPosCountVec dest; + uint8 msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); + if (msg != EQUIP_ERR_OK) + { + target->SendEquipError(msg, NULL, NULL); + _player->SendEquipError(msg, NULL, NULL); // send duplicate of error massage to master looter + return; + } + + // not move item from loot to target inventory + Item * newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId); + target->SendNewItem(newitem, uint32(item.count), false, false, true); + target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); + target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, pLoot->loot_type, item.count); + target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); + + // mark as looted + item.count=0; + item.is_looted=true; + + pLoot->NotifyItemRemoved(slotid); + --pLoot->unlootedCount; +} + diff --git a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp new file mode 100644 index 00000000000..ea6f892c126 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp @@ -0,0 +1,1721 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Language.h" +#include "Database/DatabaseEnv.h" +#include "Database/DatabaseImpl.h" +#include "WorldPacket.h" +#include "Opcodes.h" +#include "Log.h" +#include "Player.h" +#include "GossipDef.h" +#include "World.h" +#include "ObjectMgr.h" +#include "WorldSession.h" +#include "Auth/BigNumber.h" +#include "Auth/Sha1.h" +#include "UpdateData.h" +#include "LootMgr.h" +#include "Chat.h" +#include +#include "ObjectAccessor.h" +#include "Object.h" +#include "BattleGround.h" +#include "OutdoorPvP.h" +#include "Pet.h" +#include "SocialMgr.h" +#include "CellImpl.h" +#include "AccountMgr.h" +#include "Vehicle.h" +#include "CreatureAI.h" +#include "DBCEnums.h" +#include "ScriptMgr.h" +#include "MapManager.h" +#include "InstanceData.h" + +void WorldSession::HandleRepopRequestOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Recvd CMSG_REPOP_REQUEST Message"); + + recv_data.read_skip(); + + if (GetPlayer()->isAlive()||GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) + return; + + // the world update order is sessions, players, creatures + // the netcode runs in parallel with all of these + // creatures can kill players + // so if the server is lagging enough the player can + // release spirit after he's killed but before he is updated + if (GetPlayer()->getDeathState() == JUST_DIED) + { + sLog.outDebug("HandleRepopRequestOpcode: got request after player %s(%d) was killed and before he was updated", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); + GetPlayer()->KillPlayer(); + } + + //this is spirit release confirm? + GetPlayer()->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT, true); + GetPlayer()->BuildPlayerRepop(); + GetPlayer()->RepopAtGraveyard(); +} + +void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION"); + + uint32 gossipListId; + uint32 menuId; + uint64 guid; + std::string code = ""; + + recv_data >> guid >> menuId >> gossipListId; + + if (_player->PlayerTalkClass->GossipOptionCoded(gossipListId)) + { + // recheck + sLog.outBasic("reading string"); + recv_data >> code; + sLog.outBasic("string read: %s", code.c_str()); + } + + Creature *unit = NULL; + GameObject *go = NULL; + if (IS_CRE_OR_VEH_GUID(guid)) + { + unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); + if (!unit) + { + sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + } + else if (IS_GAMEOBJECT_GUID(guid)) + { + go = _player->GetMap()->GetGameObject(guid); + if (!go) + { + sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - GameObject (GUID: %u) not found.", uint32(GUID_LOPART(guid))); + return; + } + } + else + { + sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - unsupported GUID type for highguid %u. lowpart %u.", uint32(GUID_HIPART(guid)), uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + if ((unit && unit->GetCreatureInfo()->ScriptID != unit->LastUsedScriptID) || (go && go->GetGOInfo()->ScriptId != go->LastUsedScriptID)) + { + sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - Script reloaded while in use, ignoring and set new scipt id"); + if (unit) + unit->LastUsedScriptID = unit->GetCreatureInfo()->ScriptID; + if (go) + go->LastUsedScriptID = go->GetGOInfo()->ScriptId; + _player->PlayerTalkClass->CloseGossip(); + return; + } + if (!code.empty()) + { + if (unit) + { + if (!sScriptMgr.GossipSelectWithCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str())) + _player->OnGossipSelect(unit, gossipListId, menuId); + } + else + sScriptMgr.GOSelectWithCode(_player, go, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str()); + } + else + { + if (unit) + { + if (!sScriptMgr.GossipSelect(_player, unit, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId))) + _player->OnGossipSelect(unit, gossipListId, menuId); + } + else + sScriptMgr.GOSelect(_player, go, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId)); + } +} + +void WorldSession::HandleWhoOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Recvd CMSG_WHO Message"); + //recv_data.hexlike(); + + uint32 clientcount = 0; + + uint32 level_min, level_max, racemask, classmask, zones_count, str_count; + uint32 zoneids[10]; // 10 is client limit + std::string player_name, guild_name; + + recv_data >> level_min; // maximal player level, default 0 + recv_data >> level_max; // minimal player level, default 100 (MAX_LEVEL) + recv_data >> player_name; // player name, case sensitive... + + recv_data >> guild_name; // guild name, case sensitive... + + recv_data >> racemask; // race mask + recv_data >> classmask; // class mask + recv_data >> zones_count; // zones count, client limit = 10 (2.0.10) + + if (zones_count > 10) + return; // can't be received from real client or broken packet + + for (uint32 i = 0; i < zones_count; ++i) + { + uint32 temp; + recv_data >> temp; // zone id, 0 if zone is unknown... + zoneids[i] = temp; + sLog.outDebug("Zone %u: %u", i, zoneids[i]); + } + + recv_data >> str_count; // user entered strings count, client limit=4 (checked on 2.0.10) + + if (str_count > 4) + return; // can't be received from real client or broken packet + + sLog.outDebug("Minlvl %u, maxlvl %u, name %s, guild %s, racemask %u, classmask %u, zones %u, strings %u", level_min, level_max, player_name.c_str(), guild_name.c_str(), racemask, classmask, zones_count, str_count); + + std::wstring str[4]; // 4 is client limit + for (uint32 i = 0; i < str_count; ++i) + { + std::string temp; + recv_data >> temp; // user entered string, it used as universal search pattern(guild+player name)? + + if (!Utf8toWStr(temp,str[i])) + continue; + + wstrToLower(str[i]); + + sLog.outDebug("String %u: %s", i, temp.c_str()); + } + + std::wstring wplayer_name; + std::wstring wguild_name; + if (!(Utf8toWStr(player_name, wplayer_name) && Utf8toWStr(guild_name, wguild_name))) + return; + wstrToLower(wplayer_name); + wstrToLower(wguild_name); + + // client send in case not set max level value 100 but Trinity supports 255 max level, + // update it to show GMs with characters after 100 level + if (level_max >= MAX_LEVEL) + level_max = STRONG_MAX_LEVEL; + + uint32 team = _player->GetTeam(); + uint32 security = GetSecurity(); + bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); + uint32 gmLevelInWhoList = sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST); + + WorldPacket data(SMSG_WHO, 50); // guess size + data << uint32(clientcount); // clientcount place holder, listed count + data << uint32(clientcount); // clientcount place holder, online count + + ObjectAccessor::Guard guard(*HashMapHolder::GetLock()); + HashMapHolder::MapType& m = ObjectAccessor::Instance().GetPlayers(); + for (HashMapHolder::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) + { + if (security == SEC_PLAYER) + { + // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST + if (itr->second->GetTeam() != team && !allowTwoSideWhoList) + continue; + + // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST + if ((itr->second->GetSession()->GetSecurity() > gmLevelInWhoList)) + continue; + } + + //do not process players which are not in world + if (!(itr->second->IsInWorld())) + continue; + + // check if target is globally visible for player + if (!(itr->second->IsVisibleGloballyFor(_player))) + continue; + + // check if target's level is in level range + uint8 lvl = itr->second->getLevel(); + if (lvl < level_min || lvl > level_max) + continue; + + // check if class matches classmask + uint32 class_ = itr->second->getClass(); + if (!(classmask & (1 << class_))) + continue; + + // check if race matches racemask + uint32 race = itr->second->getRace(); + if (!(racemask & (1 << race))) + continue; + + uint32 pzoneid = itr->second->GetZoneId(); + + bool z_show = true; + for (uint32 i = 0; i < zones_count; ++i) + { + if (zoneids[i] == pzoneid) + { + z_show = true; + break; + } + + z_show = false; + } + if (!z_show) + continue; + + std::string pname = itr->second->GetName(); + std::wstring wpname; + if (!Utf8toWStr(pname,wpname)) + continue; + wstrToLower(wpname); + + if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos)) + continue; + + std::string gname = objmgr.GetGuildNameById(itr->second->GetGuildId()); + std::wstring wgname; + if (!Utf8toWStr(gname,wgname)) + continue; + wstrToLower(wgname); + + if (!(wguild_name.empty() || wgname.find(wguild_name) != std::wstring::npos)) + continue; + + std::string aname; + if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId())) + aname = areaEntry->area_name[GetSessionDbcLocale()]; + + bool s_show = true; + for (uint32 i = 0; i < str_count; ++i) + { + if (!str[i].empty()) + { + if (wgname.find(str[i]) != std::wstring::npos || + wpname.find(str[i]) != std::wstring::npos || + Utf8FitTo(aname, str[i])) + { + s_show = true; + break; + } + s_show = false; + } + } + if (!s_show) + continue; + + data << pname; // player name + data << gname; // guild name + data << uint32(lvl); // player level + data << uint32(class_); // player class + data << uint32(race); // player race + data << uint8(0); // new 2.4.0 + data << uint32(pzoneid); // player zone id + + // 49 is maximum player count sent to client - can be overridden + // through config, but is unstable + if ((++clientcount) == sWorld.getConfig(CONFIG_MAX_WHO)) + break; + } + + uint32 count = m.size(); + data.put( 0, clientcount ); // insert right count, listed count + data.put( 4, count > 50 ? count : clientcount ); // insert right count, online count + + SendPacket(&data); + sLog.outDebug("WORLD: Send SMSG_WHO Message"); +} + +void WorldSession::HandleLogoutRequestOpcode(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("WORLD: Recvd CMSG_LOGOUT_REQUEST Message, security - %u", GetSecurity()); + + if (uint64 lguid = GetPlayer()->GetLootGUID()) + DoLootRelease(lguid); + + uint8 reason = 0; + + if (GetPlayer()->isInCombat()) + reason = 1; + else if (GetPlayer()->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_JUMPING | MOVEMENTFLAG_FALLING)) + reason = 3; // is jumping or falling + else if (GetPlayer()->duel || GetPlayer()->HasAura(9454)) // is dueling or frozen by GM via freeze command + reason = 2; // FIXME - Need the correct value + + if (reason) + { + WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); + data << uint8(reason); + data << uint32(0); + SendPacket(&data); + LogoutRequest(0); + return; + } + + //instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in TrinityCore.conf + if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->isInFlight() || + GetSecurity() >= sWorld.getConfig(CONFIG_INSTANT_LOGOUT)) + { + WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); + data << uint8(0); + data << uint32(16777216); + SendPacket(&data); + LogoutPlayer(true); + return; + } + + // not set flags if player can't free move to prevent lost state at logout cancel + if (GetPlayer()->CanFreeMove()) + { + GetPlayer()->SetStandState(UNIT_STAND_STATE_SIT); + + WorldPacket data(SMSG_FORCE_MOVE_ROOT, (8+4)); // guess size + data.append(GetPlayer()->GetPackGUID()); + data << (uint32)2; + SendPacket(&data); + GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); + } + + WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); + data << uint8(0); + data << uint32(0); + SendPacket(&data); + LogoutRequest(time(NULL)); +} + +void WorldSession::HandlePlayerLogoutOpcode(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("WORLD: Recvd CMSG_PLAYER_LOGOUT Message"); +} + +void WorldSession::HandleLogoutCancelOpcode(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("WORLD: Recvd CMSG_LOGOUT_CANCEL Message"); + + LogoutRequest(0); + + WorldPacket data(SMSG_LOGOUT_CANCEL_ACK, 0); + SendPacket(&data); + + // not remove flags if can't free move - its not set in Logout request code. + if (GetPlayer()->CanFreeMove()) + { + //!we can move again + data.Initialize(SMSG_FORCE_MOVE_UNROOT, 8); // guess size + data.append(GetPlayer()->GetPackGUID()); + data << uint32(0); + SendPacket(&data); + + //! Stand Up + GetPlayer()->SetStandState(UNIT_STAND_STATE_STAND); + + //! DISABLE_ROTATE + GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); + } + + sLog.outDebug("WORLD: sent SMSG_LOGOUT_CANCEL_ACK Message"); +} + +void WorldSession::HandleTogglePvP(WorldPacket & recv_data) +{ + // this opcode can be used in two ways: Either set explicit new status or toggle old status + if (recv_data.size() == 1) + { + bool newPvPStatus; + recv_data >> newPvPStatus; + GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP, newPvPStatus); + GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER, !newPvPStatus); + } + else + { + GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); + GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER); + } + + if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP)) + { + if (!GetPlayer()->IsPvP() || GetPlayer()->pvpInfo.endTimer != 0) + GetPlayer()->UpdatePvP(true, true); + } + else + { + if (!GetPlayer()->pvpInfo.inHostileArea && GetPlayer()->IsPvP()) + GetPlayer()->pvpInfo.endTimer = time(NULL); // start toggle-off + } + + //if (OutdoorPvP * pvp = _player->GetOutdoorPvP()) + // pvp->HandlePlayerActivityChanged(_player); +} + +void WorldSession::HandleZoneUpdateOpcode(WorldPacket & recv_data) +{ + uint32 newZone; + recv_data >> newZone; + + sLog.outDetail("WORLD: Recvd ZONE_UPDATE: %u", newZone); + + // use server size data + uint32 newzone, newarea; + GetPlayer()->GetZoneAndAreaId(newzone,newarea); + GetPlayer()->UpdateZone(newzone,newarea); + //GetPlayer()->SendInitWorldStates(true,newZone); +} + +void WorldSession::HandleSetTargetOpcode(WorldPacket & recv_data) +{ + // When this packet send? + uint64 guid ; + recv_data >> guid; + + _player->SetUInt32Value(UNIT_FIELD_TARGET, guid); + + // update reputation list if need + Unit* unit = ObjectAccessor::GetUnit(*_player, guid); + if (!unit) + return; + + if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction())) + _player->GetReputationMgr().SetVisible(factionTemplateEntry); +} + +void WorldSession::HandleSetSelectionOpcode(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + + _player->SetSelection(guid); + + // update reputation list if need + Unit* unit = ObjectAccessor::GetUnit(*_player, guid); + if (!unit) + return; + + if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction())) + _player->GetReputationMgr().SetVisible(factionTemplateEntry); +} + +void WorldSession::HandleStandStateChangeOpcode(WorldPacket & recv_data) +{ + // sLog.outDebug("WORLD: Received CMSG_STANDSTATECHANGE"); -- too many spam in log at lags/debug stop + uint32 animstate; + recv_data >> animstate; + + _player->SetStandState(animstate); +} + +void WorldSession::HandleContactListOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_CONTACT_LIST"); + uint32 unk; + recv_data >> unk; + sLog.outDebug("unk value is %u", unk); + _player->GetSocial()->SendSocialList(); +} + +void WorldSession::HandleAddFriendOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_ADD_FRIEND"); + + std::string friendName = GetTrinityString(LANG_FRIEND_IGNORE_UNKNOWN); + std::string friendNote; + + recv_data >> friendName; + + recv_data >> friendNote; + + if (!normalizePlayerName(friendName)) + return; + + CharacterDatabase.escape_string(friendName); // prevent SQL injection - normal name don't must changed by this call + + sLog.outDebug("WORLD: %s asked to add friend : '%s'", + GetPlayer()->GetName(), friendName.c_str()); + + CharacterDatabase.AsyncPQuery(&WorldSession::HandleAddFriendOpcodeCallBack, GetAccountId(), friendNote, "SELECT guid, race, account FROM characters WHERE name = '%s'", friendName.c_str()); +} + +void WorldSession::HandleAddFriendOpcodeCallBack(QueryResult_AutoPtr result, uint32 accountId, std::string friendNote) +{ + uint64 friendGuid; + uint64 friendAcctid; + uint32 team; + FriendsResult friendResult; + + WorldSession * session = sWorld.FindSession(accountId); + + if (!session || !session->GetPlayer()) + return; + + friendResult = FRIEND_NOT_FOUND; + friendGuid = 0; + + if (result) + { + friendGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); + team = Player::TeamForRace((*result)[1].GetUInt8()); + friendAcctid = (*result)[2].GetUInt32(); + + if (session->GetSecurity() >= SEC_MODERATOR || sWorld.getConfig(CONFIG_ALLOW_GM_FRIEND) || accmgr.GetSecurity(friendAcctid) < SEC_MODERATOR) + { + if (friendGuid) + { + if (friendGuid == session->GetPlayer()->GetGUID()) + friendResult = FRIEND_SELF; + else if (session->GetPlayer()->GetTeam() != team && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && session->GetSecurity() < SEC_MODERATOR) + friendResult = FRIEND_ENEMY; + else if (session->GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid))) + friendResult = FRIEND_ALREADY; + else + { + Player* pFriend = ObjectAccessor::FindPlayer(friendGuid); + if (pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(session->GetPlayer())) + friendResult = FRIEND_ADDED_ONLINE; + else + friendResult = FRIEND_ADDED_OFFLINE; + if (!session->GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false)) + { + friendResult = FRIEND_LIST_FULL; + sLog.outDebug("WORLD: %s's friend list is full.", session->GetPlayer()->GetName()); + } + } + session->GetPlayer()->GetSocial()->SetFriendNote(GUID_LOPART(friendGuid), friendNote); + } + } + } + + sSocialMgr.SendFriendStatus(session->GetPlayer(), friendResult, GUID_LOPART(friendGuid), false); + + sLog.outDebug("WORLD: Sent (SMSG_FRIEND_STATUS)"); +} + +void WorldSession::HandleDelFriendOpcode(WorldPacket & recv_data) +{ + uint64 FriendGUID; + + sLog.outDebug("WORLD: Received CMSG_DEL_FRIEND"); + + recv_data >> FriendGUID; + + _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(FriendGUID), false); + + sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_REMOVED, GUID_LOPART(FriendGUID), false); + + sLog.outDebug("WORLD: Sent motd (SMSG_FRIEND_STATUS)"); +} + +void WorldSession::HandleAddIgnoreOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_ADD_IGNORE"); + + std::string IgnoreName = GetTrinityString(LANG_FRIEND_IGNORE_UNKNOWN); + + recv_data >> IgnoreName; + + if (!normalizePlayerName(IgnoreName)) + return; + + CharacterDatabase.escape_string(IgnoreName); // prevent SQL injection - normal name don't must changed by this call + + sLog.outDebug("WORLD: %s asked to Ignore: '%s'", + GetPlayer()->GetName(), IgnoreName.c_str()); + + CharacterDatabase.AsyncPQuery(&WorldSession::HandleAddIgnoreOpcodeCallBack, GetAccountId(), "SELECT guid FROM characters WHERE name = '%s'", IgnoreName.c_str()); +} + +void WorldSession::HandleAddIgnoreOpcodeCallBack(QueryResult_AutoPtr result, uint32 accountId) +{ + uint64 IgnoreGuid; + FriendsResult ignoreResult; + + WorldSession * session = sWorld.FindSession(accountId); + + if (!session || !session->GetPlayer()) + return; + + ignoreResult = FRIEND_IGNORE_NOT_FOUND; + IgnoreGuid = 0; + + if (result) + { + IgnoreGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); + + if (IgnoreGuid) + { + if (IgnoreGuid == session->GetPlayer()->GetGUID()) //not add yourself + ignoreResult = FRIEND_IGNORE_SELF; + else if (session->GetPlayer()->GetSocial()->HasIgnore(GUID_LOPART(IgnoreGuid))) + ignoreResult = FRIEND_IGNORE_ALREADY; + else + { + ignoreResult = FRIEND_IGNORE_ADDED; + + // ignore list full + if (!session->GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(IgnoreGuid), true)) + ignoreResult = FRIEND_IGNORE_FULL; + } + } + } + + sSocialMgr.SendFriendStatus(session->GetPlayer(), ignoreResult, GUID_LOPART(IgnoreGuid), false); + + sLog.outDebug("WORLD: Sent (SMSG_FRIEND_STATUS)"); +} + +void WorldSession::HandleDelIgnoreOpcode(WorldPacket & recv_data) +{ + uint64 IgnoreGUID; + + sLog.outDebug("WORLD: Received CMSG_DEL_IGNORE"); + + recv_data >> IgnoreGUID; + + _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(IgnoreGUID), true); + + sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_IGNORE_REMOVED, GUID_LOPART(IgnoreGUID), false); + + sLog.outDebug("WORLD: Sent motd (SMSG_FRIEND_STATUS)"); +} + +void WorldSession::HandleSetContactNotesOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("CMSG_SET_CONTACT_NOTES"); + uint64 guid; + std::string note; + recv_data >> guid >> note; + _player->GetSocial()->SetFriendNote(guid, note); +} + +void WorldSession::HandleBugOpcode(WorldPacket & recv_data) +{ + uint32 suggestion, contentlen, typelen; + std::string content, type; + + recv_data >> suggestion >> contentlen >> content; + + recv_data >> typelen >> type; + + if (suggestion == 0) + sLog.outDebug("WORLD: Received CMSG_BUG [Bug Report]"); + else + sLog.outDebug("WORLD: Received CMSG_BUG [Suggestion]"); + + sLog.outDebug("%s", type.c_str()); + sLog.outDebug("%s", content.c_str()); + + CharacterDatabase.escape_string(type); + CharacterDatabase.escape_string(content); + CharacterDatabase.PExecute ("INSERT INTO bugreport (type,content) VALUES('%s', '%s')", type.c_str(), content.c_str()); +} + +void WorldSession::HandleReclaimCorpseOpcode(WorldPacket &recv_data) +{ + sLog.outDetail("WORLD: Received CMSG_RECLAIM_CORPSE"); + + uint64 guid; + recv_data >> guid; + + if (GetPlayer()->isAlive()) + return; + + // do not allow corpse reclaim in arena + if (GetPlayer()->InArena()) + return; + + // body not released yet + if (!GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) + return; + + Corpse *corpse = GetPlayer()->GetCorpse(); + + if (!corpse) + return; + + // prevent resurrect before 30-sec delay after body release not finished + if (corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType() == CORPSE_RESURRECTABLE_PVP) > time(NULL)) + return; + + if (!corpse->IsWithinDistInMap(GetPlayer(), CORPSE_RECLAIM_RADIUS, true)) + return; + + // resurrect + GetPlayer()->ResurrectPlayer(GetPlayer()->InBattleGround() ? 1.0f : 0.5f); + + // spawn bones + GetPlayer()->SpawnCorpseBones(); +} + +void WorldSession::HandleResurrectResponseOpcode(WorldPacket & recv_data) +{ + sLog.outDetail("WORLD: Received CMSG_RESURRECT_RESPONSE"); + + uint64 guid; + uint8 status; + recv_data >> guid; + recv_data >> status; + + if (GetPlayer()->isAlive()) + return; + + if (status == 0) + { + GetPlayer()->clearResurrectRequestData(); // reject + return; + } + + if (!GetPlayer()->isRessurectRequestedBy(guid)) + return; + + GetPlayer()->ResurectUsingRequestData(); +} + +void WorldSession::SendAreaTriggerMessage(const char* Text, ...) +{ + va_list ap; + char szStr [1024]; + szStr[0] = '\0'; + + va_start(ap, Text); + vsnprintf(szStr, 1024, Text, ap); + va_end(ap); + + uint32 length = strlen(szStr)+1; + WorldPacket data(SMSG_AREA_TRIGGER_MESSAGE, 4+length); + data << length; + data << szStr; + SendPacket(&data); +} + +void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_AREATRIGGER"); + + uint32 Trigger_ID; + + recv_data >> Trigger_ID; + sLog.outDebug("Trigger ID:%u",Trigger_ID); + + if (GetPlayer()->isInFlight()) + { + sLog.outDebug("Player '%s' (GUID: %u) in flight, ignore Area Trigger ID:%u",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow(), Trigger_ID); + return; + } + + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); + if (!atEntry) + { + sLog.outDebug("Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID:%u",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow(), Trigger_ID); + return; + } + + if (GetPlayer()->GetMapId() != atEntry->mapid) + { + sLog.outDebug("Player '%s' (GUID: %u) too far (trigger map: %u player map: %u), ignore Area Trigger ID: %u", GetPlayer()->GetName(), atEntry->mapid, GetPlayer()->GetMapId(), GetPlayer()->GetGUIDLow(), Trigger_ID); + return; + } + + // delta is safe radius + const float delta = 5.0f; + // check if player in the range of areatrigger + Player* pl = GetPlayer(); + + if (atEntry->radius > 0) + { + // if we have radius check it + float dist = pl->GetDistance(atEntry->x,atEntry->y,atEntry->z); + if (dist > atEntry->radius + delta) + { + sLog.outDebug("Player '%s' (GUID: %u) too far (radius: %f distance: %f), ignore Area Trigger ID: %u", + pl->GetName(), pl->GetGUIDLow(), atEntry->radius, dist, Trigger_ID); + return; + } + } + else + { + // we have only extent + + // rotate the players position instead of rotating the whole cube, that way we can make a simplified + // is-in-cube check and we have to calculate only one point instead of 4 + + // 2PI = 360°, keep in mind that ingame orientation is counter-clockwise + double rotation = 2*M_PI-atEntry->box_orientation; + double sinVal = sin(rotation); + double cosVal = cos(rotation); + + float playerBoxDistX = pl->GetPositionX() - atEntry->x; + float playerBoxDistY = pl->GetPositionY() - atEntry->y; + + float rotPlayerX = atEntry->x + playerBoxDistX * cosVal - playerBoxDistY*sinVal; + float rotPlayerY = atEntry->y + playerBoxDistY * cosVal + playerBoxDistX*sinVal; + + // box edges are parallel to coordiante axis, so we can treat every dimension independently :D + float dz = pl->GetPositionZ() - atEntry->z; + float dx = rotPlayerX - atEntry->x; + float dy = rotPlayerY - atEntry->y; + if ((fabs(dx) > atEntry->box_x/2 + delta) || + (fabs(dy) > atEntry->box_y/2 + delta) || + (fabs(dz) > atEntry->box_z/2 + delta)) + { + sLog.outDebug("Player '%s' (GUID: %u) too far (1/2 box X: %f 1/2 box Y: %f 1/2 box Z: %f rotatedPlayerX: %f rotatedPlayerY: %f dZ:%f), ignore Area Trigger ID: %u", + pl->GetName(), pl->GetGUIDLow(), atEntry->box_x/2, atEntry->box_y/2, atEntry->box_z/2, rotPlayerX, rotPlayerY, dz, Trigger_ID); + return; + } + } + + if (sScriptMgr.AreaTrigger(GetPlayer(), atEntry)) + return; + + uint32 quest_id = objmgr.GetQuestForAreaTrigger(Trigger_ID); + if (quest_id && GetPlayer()->isAlive() && GetPlayer()->IsActiveQuest(quest_id)) + { + Quest const* pQuest = objmgr.GetQuestTemplate(quest_id); + if (pQuest) + { + if (GetPlayer()->GetQuestStatus(quest_id) == QUEST_STATUS_INCOMPLETE) + GetPlayer()->AreaExploredOrEventHappens(quest_id); + } + } + + if (objmgr.IsTavernAreaTrigger(Trigger_ID)) + { + // set resting flag we are in the inn + GetPlayer()->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); + GetPlayer()->InnEnter(time(NULL), atEntry->mapid, atEntry->x, atEntry->y, atEntry->z); + GetPlayer()->SetRestType(REST_TYPE_IN_TAVERN); + + if (sWorld.IsFFAPvPRealm()) + GetPlayer()->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); + + return; + } + + if (GetPlayer()->InBattleGround()) + { + BattleGround* bg = GetPlayer()->GetBattleGround(); + if (bg) + if (bg->GetStatus() == STATUS_IN_PROGRESS) + bg->HandleAreaTrigger(GetPlayer(), Trigger_ID); + + return; + } + + if (OutdoorPvP * pvp = GetPlayer()->GetOutdoorPvP()) + { + if (pvp->HandleAreaTrigger(_player, Trigger_ID)) + return; + } + + // NULL if all values default (non teleport trigger) + AreaTrigger const* at = objmgr.GetAreaTrigger(Trigger_ID); + if (!at) + return; + + if (!GetPlayer()->Satisfy(objmgr.GetAccessRequirement(at->access_id), at->target_mapId, true)) + return; + + // check if player can enter instance : instance not full, and raid instance not in encounter fight + if (!MapManager::Instance().CanPlayerEnter(at->target_mapId, GetPlayer(), false)) + return; + + GetPlayer()->TeleportTo(at->target_mapId,at->target_X,at->target_Y,at->target_Z,at->target_Orientation,TELE_TO_NOT_LEAVE_TRANSPORT); +} + +void WorldSession::HandleUpdateAccountData(WorldPacket &recv_data) +{ + sLog.outDetail("WORLD: Received CMSG_UPDATE_ACCOUNT_DATA"); + + uint32 type, timestamp, decompressedSize; + recv_data >> type >> timestamp >> decompressedSize; + + sLog.outDebug("UAD: type %u, time %u, decompressedSize %u", type, timestamp, decompressedSize); + + if (type > NUM_ACCOUNT_DATA_TYPES) + return; + + if (decompressedSize == 0) // erase + { + SetAccountData(AccountDataType(type), 0, ""); + + WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4+4); + data << uint32(type); + data << uint32(0); + SendPacket(&data); + + return; + } + + if (decompressedSize > 0xFFFF) + { + recv_data.rpos(recv_data.wpos()); // unnneded warning spam in this case + sLog.outError("UAD: Account data packet too big, size %u", decompressedSize); + return; + } + + ByteBuffer dest; + dest.resize(decompressedSize); + + uLongf realSize = decompressedSize; + if (uncompress(const_cast(dest.contents()), &realSize, const_cast(recv_data.contents() + recv_data.rpos()), recv_data.size() - recv_data.rpos()) != Z_OK) + { + recv_data.rpos(recv_data.wpos()); // unnneded warning spam in this case + sLog.outError("UAD: Failed to decompress account data"); + return; + } + + recv_data.rpos(recv_data.wpos()); // uncompress read (recv_data.size() - recv_data.rpos()) + + std::string adata; + dest >> adata; + + SetAccountData(AccountDataType(type), timestamp, adata); + + WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4+4); + data << uint32(type); + data << uint32(0); + SendPacket(&data); +} + +void WorldSession::HandleRequestAccountData(WorldPacket& recv_data) +{ + sLog.outDetail("WORLD: Received CMSG_REQUEST_ACCOUNT_DATA"); + + uint32 type; + recv_data >> type; + + sLog.outDebug("RAD: type %u", type); + + if (type > NUM_ACCOUNT_DATA_TYPES) + return; + + AccountData *adata = GetAccountData(AccountDataType(type)); + + uint32 size = adata->Data.size(); + + uLongf destSize = compressBound(size); + + ByteBuffer dest; + dest.resize(destSize); + + if (size && compress(const_cast(dest.contents()), &destSize, (uint8*)adata->Data.c_str(), size) != Z_OK) + { + sLog.outDebug("RAD: Failed to compress account data"); + return; + } + + dest.resize(destSize); + + WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA, 8+4+4+4+destSize); + data << uint64(_player ? _player->GetGUID() : 0); // player guid + data << uint32(type); // type (0-7) + data << uint32(adata->Time); // unix time + data << uint32(size); // decompressed length + data.append(dest); // compressed data + SendPacket(&data); +} + +void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_SET_ACTION_BUTTON"); + uint8 button; + uint32 packetData; + recv_data >> button >> packetData; + + uint32 action = ACTION_BUTTON_ACTION(packetData); + uint8 type = ACTION_BUTTON_TYPE(packetData); + + sLog.outDetail("BUTTON: %u ACTION: %u TYPE: %u", button, action, type); + if (!packetData) + { + sLog.outDetail("MISC: Remove action from button %u", button); + GetPlayer()->removeActionButton(button); + } + else + { + switch(type) + { + case ACTION_BUTTON_MACRO: + case ACTION_BUTTON_CMACRO: + sLog.outDetail("MISC: Added Macro %u into button %u", action, button); + break; + case ACTION_BUTTON_EQSET: + sLog.outDetail("MISC: Added EquipmentSet %u into button %u", action, button); + break; + case ACTION_BUTTON_SPELL: + sLog.outDetail("MISC: Added Spell %u into button %u", action, button); + break; + case ACTION_BUTTON_ITEM: + sLog.outDetail("MISC: Added Item %u into button %u", action, button); + break; + default: + sLog.outError("MISC: Unknown action button type %u for action %u into button %u", type, action, button); + return; + } + GetPlayer()->addActionButton(button, action, type); + } +} + +void WorldSession::HandleCompleteCinematic(WorldPacket & /*recv_data*/) +{ + DEBUG_LOG("WORLD: Player is watching cinema"); +} + +void WorldSession::HandleNextCinematicCamera(WorldPacket & /*recv_data*/) +{ + DEBUG_LOG("WORLD: Which movie to play"); +} + +void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket & recv_data) +{ + /* WorldSession::Update(getMSTime());*/ + DEBUG_LOG("WORLD: Time Lag/Synchronization Resent/Update"); + + uint64 guid; + if (!recv_data.readPackGUID(guid)) + { + recv_data.rpos(recv_data.wpos()); + return; + } + recv_data.read_skip(); + /* + uint64 guid; + uint32 time_skipped; + recv_data >> guid; + recv_data >> time_skipped; + sLog.outDebug("WORLD: CMSG_MOVE_TIME_SKIPPED"); + + /// TODO + must be need use in Trinity + We substract server Lags to move time (AntiLags) + for exmaple + GetPlayer()->ModifyLastMoveTime(-int32(time_skipped)); + */ +} + +void WorldSession::HandleFeatherFallAck(WorldPacket &recv_data) +{ + DEBUG_LOG("WORLD: CMSG_MOVE_FEATHER_FALL_ACK"); + + // no used + recv_data.rpos(recv_data.wpos()); // prevent warnings spam +} + +void WorldSession::HandleMoveUnRootAck(WorldPacket& recv_data) +{ + // no used + recv_data.rpos(recv_data.wpos()); // prevent warnings spam +/* + uint64 guid; + recv_data >> guid; + + // now can skip not our packet + if (_player->GetGUID() != guid) + { + recv_data.rpos(recv_data.wpos()); // prevent warnings spam + return; + } + + sLog.outDebug("WORLD: CMSG_FORCE_MOVE_UNROOT_ACK"); + + recv_data.read_skip(); // unk + + MovementInfo movementInfo; + movementInfo.guid = guid; + ReadMovementInfo(recv_data, &movementInfo); + recv_data.read_skip(); // unk2 +*/ +} + +void WorldSession::HandleMoveRootAck(WorldPacket& recv_data) +{ + // no used + recv_data.rpos(recv_data.wpos()); // prevent warnings spam +/* + uint64 guid; + recv_data >> guid; + + // now can skip not our packet + if (_player->GetGUID() != guid) + { + recv_data.rpos(recv_data.wpos()); // prevent warnings spam + return; + } + + sLog.outDebug("WORLD: CMSG_FORCE_MOVE_ROOT_ACK"); + + recv_data.read_skip(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recv_data, &movementInfo); +*/ +} + +void WorldSession::HandleSetActionBarToggles(WorldPacket& recv_data) +{ + uint8 ActionBar; + + recv_data >> ActionBar; + + if (!GetPlayer()) // ignore until not logged (check needed because STATUS_AUTHED) + { + if (ActionBar != 0) + sLog.outError("WorldSession::HandleSetActionBarToggles in not logged state with value: %u, ignored",uint32(ActionBar)); + return; + } + + GetPlayer()->SetByteValue(PLAYER_FIELD_BYTES, 2, ActionBar); +} + +void WorldSession::HandleWardenDataOpcode(WorldPacket& recv_data) +{ + recv_data.read_skip(); + /* + uint8 tmp; + recv_data >> tmp; + sLog.outDebug("Received opcode CMSG_WARDEN_DATA, not resolve.uint8 = %u",tmp); + */ +} + +void WorldSession::HandlePlayedTime(WorldPacket& recv_data) +{ + uint8 unk1; + recv_data >> unk1; // 0 or 1 expected + + WorldPacket data(SMSG_PLAYED_TIME, 4 + 4 + 1); + data << uint32(_player->GetTotalPlayedTime()); + data << uint32(_player->GetLevelPlayedTime()); + data << uint8(unk1); // 0 - will not show in chat frame + SendPacket(&data); +} + +void WorldSession::HandleInspectOpcode(WorldPacket& recv_data) +{ + uint64 guid; + recv_data >> guid; + DEBUG_LOG("Inspected guid is " UI64FMTD, guid); + + _player->SetSelection(guid); + + Player *plr = objmgr.GetPlayer(guid); + if (!plr) // wrong player + return; + + uint32 talent_points = 0x47; + uint32 guid_size = plr->GetPackGUID().wpos(); + WorldPacket data(SMSG_INSPECT_TALENT, guid_size+4+talent_points); + data.append(plr->GetPackGUID()); + + if (sWorld.getConfig(CONFIG_TALENTS_INSPECTING) || _player->isGameMaster()) + { + plr->BuildPlayerTalentsInfoData(&data); + } + else + { + data << uint32(0); // unspentTalentPoints + data << uint8(0); // talentGroupCount + data << uint8(0); // talentGroupIndex + } + + plr->BuildEnchantmentsInfoData(&data); + SendPacket(&data); +} + +void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket& recv_data) +{ + uint64 guid; + recv_data >> guid; + + Player *player = objmgr.GetPlayer(guid); + + if (!player) + { + sLog.outError("InspectHonorStats: WTF, player not found..."); + return; + } + + WorldPacket data(MSG_INSPECT_HONOR_STATS, 8+1+4*4); + data << uint64(player->GetGUID()); + data << uint8(player->GetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY)); + data << uint32(player->GetUInt32Value(PLAYER_FIELD_KILLS)); + data << uint32(player->GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION)); + data << uint32(player->GetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION)); + data << uint32(player->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS)); + SendPacket(&data); +} + +void WorldSession::HandleWorldTeleportOpcode(WorldPacket& recv_data) +{ + // write in client console: worldport 469 452 6454 2536 180 or /console worldport 469 452 6454 2536 180 + // Received opcode CMSG_WORLD_TELEPORT + // Time is ***, map=469, x=452.000000, y=6454.000000, z=2536.000000, orient=3.141593 + + uint32 time; + uint32 mapid; + float PositionX; + float PositionY; + float PositionZ; + float Orientation; + + recv_data >> time; // time in m.sec. + recv_data >> mapid; + recv_data >> PositionX; + recv_data >> PositionY; + recv_data >> PositionZ; + recv_data >> Orientation; // o (3.141593 = 180 degrees) + + //sLog.outDebug("Received opcode CMSG_WORLD_TELEPORT"); + if (GetPlayer()->isInFlight()) + { + sLog.outDebug("Player '%s' (GUID: %u) in flight, ignore worldport command.",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow()); + return; + } + + DEBUG_LOG("Time %u sec, map=%u, x=%f, y=%f, z=%f, orient=%f", time/1000, mapid, PositionX, PositionY, PositionZ, Orientation); + + if (GetSecurity() >= SEC_ADMINISTRATOR) + GetPlayer()->TeleportTo(mapid,PositionX,PositionY,PositionZ,Orientation); + else + SendNotification(LANG_YOU_NOT_HAVE_PERMISSION); + sLog.outDebug("Received worldport command from player %s", GetPlayer()->GetName()); +} + +void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data) +{ + sLog.outDebug("Received opcode CMSG_WHOIS"); + std::string charname; + recv_data >> charname; + + if (GetSecurity() < SEC_ADMINISTRATOR) + { + SendNotification(LANG_YOU_NOT_HAVE_PERMISSION); + return; + } + + if (charname.empty() || !normalizePlayerName (charname)) + { + SendNotification(LANG_NEED_CHARACTER_NAME); + return; + } + + Player *plr = objmgr.GetPlayer(charname.c_str()); + + if (!plr) + { + SendNotification(LANG_PLAYER_NOT_EXIST_OR_OFFLINE, charname.c_str()); + return; + } + + uint32 accid = plr->GetSession()->GetAccountId(); + + QueryResult_AutoPtr result = LoginDatabase.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid); + if (!result) + { + SendNotification(LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND, charname.c_str()); + return; + } + + Field *fields = result->Fetch(); + std::string acc = fields[0].GetCppString(); + if (acc.empty()) + acc = "Unknown"; + std::string email = fields[1].GetCppString(); + if (email.empty()) + email = "Unknown"; + std::string lastip = fields[2].GetCppString(); + if (lastip.empty()) + lastip = "Unknown"; + + std::string msg = charname + "'s " + "account is " + acc + ", e-mail: " + email + ", last ip: " + lastip; + + WorldPacket data(SMSG_WHOIS, msg.size()+1); + data << msg; + _player->GetSession()->SendPacket(&data); + + sLog.outDebug("Received whois command from player %s for character %s", GetPlayer()->GetName(), charname.c_str()); +} + +void WorldSession::HandleComplainOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_COMPLAIN"); + recv_data.hexlike(); + + uint8 spam_type; // 0 - mail, 1 - chat + uint64 spammer_guid; + uint32 unk1 = 0; + uint32 unk2 = 0; + uint32 unk3 = 0; + uint32 unk4 = 0; + std::string description = ""; + recv_data >> spam_type; // unk 0x01 const, may be spam type (mail/chat) + recv_data >> spammer_guid; // player guid + switch(spam_type) + { + case 0: + recv_data >> unk1; // const 0 + recv_data >> unk2; // probably mail id + recv_data >> unk3; // const 0 + break; + case 1: + recv_data >> unk1; // probably language + recv_data >> unk2; // message type? + recv_data >> unk3; // probably channel id + recv_data >> unk4; // unk random value + recv_data >> description; // spam description string (messagetype, channel name, player name, message) + break; + } + + // NOTE: all chat messages from this spammer automatically ignored by spam reporter until logout in case chat spam. + // if it's mail spam - ALL mails from this spammer automatically removed by client + + // Complaint Received message + WorldPacket data(SMSG_COMPLAIN_RESULT, 1); + data << uint8(0); + SendPacket(&data); + + sLog.outDebug("REPORT SPAM: type %u, guid %u, unk1 %u, unk2 %u, unk3 %u, unk4 %u, message %s", spam_type, GUID_LOPART(spammer_guid), unk1, unk2, unk3, unk4, description.c_str()); +} + +void WorldSession::HandleRealmSplitOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("CMSG_REALM_SPLIT"); + + uint32 unk; + std::string split_date = "01/01/01"; + recv_data >> unk; + + WorldPacket data(SMSG_REALM_SPLIT, 4+4+split_date.size()+1); + data << unk; + data << uint32(0x00000000); // realm split state + // split states: + // 0x0 realm normal + // 0x1 realm split + // 0x2 realm split pending + data << split_date; + SendPacket(&data); + //sLog.outDebug("response sent %u", unk); +} + +void WorldSession::HandleFarSightOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_FAR_SIGHT"); + //recv_data.hexlike(); + + uint8 apply; + recv_data >> apply; + + switch(apply) + { + case 0: + sLog.outDebug("Player %u set vision to self", _player->GetGUIDLow()); + _player->SetSeer(_player); + break; + case 1: + sLog.outDebug("Added FarSight " I64FMT " to player %u", _player->GetUInt64Value(PLAYER_FARSIGHT), _player->GetGUIDLow()); + if (WorldObject *target = _player->GetViewpoint()) + _player->SetSeer(target); + else + sLog.outError("Player %s requests non-existing seer", _player->GetName()); + break; + default: + sLog.outDebug("Unhandled mode in CMSG_FAR_SIGHT: %u", apply); + return; + } + + GetPlayer()->UpdateVisibilityForPlayer(); +} + +void WorldSession::HandleSetTitleOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("CMSG_SET_TITLE"); + + int32 title; + recv_data >> title; + + // -1 at none + if (title > 0 && title < MAX_TITLE_INDEX) + { + if (!GetPlayer()->HasTitle(title)) + return; + } + else + title = 0; + + GetPlayer()->SetUInt32Value(PLAYER_CHOSEN_TITLE, title); +} + +void WorldSession::HandleTimeSyncResp(WorldPacket & recv_data) +{ + sLog.outDebug("CMSG_TIME_SYNC_RESP"); + + uint32 counter, clientTicks; + recv_data >> counter >> clientTicks; + + if (counter != _player->m_timeSyncCounter - 1) + sLog.outDebug("Wrong time sync counter from player %s (cheater?)", _player->GetName()); + + sLog.outDebug("Time sync received: counter %u, client ticks %u, time since last sync %u", counter, clientTicks, clientTicks - _player->m_timeSyncClient); + + uint32 ourTicks = clientTicks + (getMSTime() - _player->m_timeSyncServer); + + // diff should be small + sLog.outDebug("Our ticks: %u, diff %u, latency %u", ourTicks, ourTicks - clientTicks, GetLatency()); + + _player->m_timeSyncClient = clientTicks; +} + +void WorldSession::HandleResetInstancesOpcode(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("WORLD: CMSG_RESET_INSTANCES"); + Group *pGroup = _player->GetGroup(); + if (pGroup) + { + if (pGroup->IsLeader(_player->GetGUID())) + { + pGroup->ResetInstances(INSTANCE_RESET_ALL, false, _player); + pGroup->ResetInstances(INSTANCE_RESET_ALL, true,_player); + } + } + else + { + _player->ResetInstances(INSTANCE_RESET_ALL, false); + _player->ResetInstances(INSTANCE_RESET_ALL, true); + } +} + +void WorldSession::HandleSetDungeonDifficultyOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("MSG_SET_DUNGEON_DIFFICULTY"); + + uint32 mode; + recv_data >> mode; + + if (mode >= MAX_DUNGEON_DIFFICULTY) + { + sLog.outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode); + return; + } + + if (Difficulty(mode) == _player->GetDungeonDifficulty()) + return; + + // cannot reset while in an instance + Map *map = _player->GetMap(); + if (map && map->IsDungeon()) + { + sLog.outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); + return; + } + + if (_player->getLevel() < LEVELREQUIREMENT_HEROIC) + return; + + Group *pGroup = _player->GetGroup(); + if (pGroup) + { + if (pGroup->IsLeader(_player->GetGUID())) + { + for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* pGroupGuy = itr->getSource(); + if (!pGroupGuy) + continue; + + if (!pGroupGuy->IsInMap(pGroupGuy)) + return; + + map = pGroupGuy->GetMap(); + if (map && map->IsNonRaidDungeon()) + { + sLog.outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); + return; + } + } + // the difficulty is set even if the instances can't be reset + //_player->SendDungeonDifficulty(true); + pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false, _player); + pGroup->SetDungeonDifficulty(Difficulty(mode)); + } + } + else + { + _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false); + _player->SetDungeonDifficulty(Difficulty(mode)); + } +} + +void WorldSession::HandleSetRaidDifficultyOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("MSG_SET_RAID_DIFFICULTY"); + + uint32 mode; + recv_data >> mode; + + if (mode >= MAX_RAID_DIFFICULTY) + { + sLog.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode); + return; + } + + // cannot reset while in an instance + Map *map = _player->GetMap(); + if (map && map->IsDungeon()) + { + sLog.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); + return; + } + + if (Difficulty(mode) == _player->GetRaidDifficulty()) + return; + + if (_player->getLevel() < LEVELREQUIREMENT_HEROIC) + return; + + Group *pGroup = _player->GetGroup(); + if (pGroup) + { + if (pGroup->IsLeader(_player->GetGUID())) + { + for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* pGroupGuy = itr->getSource(); + if (!pGroupGuy) + continue; + + if (!pGroupGuy->IsInMap(pGroupGuy)) + return; + + map = pGroupGuy->GetMap(); + if (map && map->IsRaid()) + { + sLog.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); + return; + } + } + // the difficulty is set even if the instances can't be reset + //_player->SendDungeonDifficulty(true); + pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true, _player); + pGroup->SetRaidDifficulty(Difficulty(mode)); + } + } + else + { + _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true); + _player->SetRaidDifficulty(Difficulty(mode)); + } +} + +void WorldSession::HandleCancelMountAuraOpcode(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("WORLD: CMSG_CANCEL_MOUNT_AURA"); + + //If player is not mounted, so go out :) + if (!_player->IsMounted()) // not blizz like; no any messages on blizz + { + ChatHandler(this).SendSysMessage(LANG_CHAR_NON_MOUNTED); + return; + } + + if (_player->isInFlight()) // not blizz like; no any messages on blizz + { + ChatHandler(this).SendSysMessage(LANG_YOU_IN_FLIGHT); + return; + } + + _player->Unmount(); + _player->RemoveAurasByType(SPELL_AURA_MOUNTED); +} + +void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket & recv_data) +{ + // fly mode on/off + sLog.outDebug("WORLD: CMSG_MOVE_SET_CAN_FLY_ACK"); + //recv_data.hexlike(); + + uint64 guid; // guid - unused + if (!recv_data.readPackGUID(guid)) + return; + + recv_data.read_skip(); // unk + + MovementInfo movementInfo; + movementInfo.guid = guid; + ReadMovementInfo(recv_data, &movementInfo); + + recv_data.read_skip(); // unk2 + + _player->m_mover->m_movementInfo.flags = movementInfo.GetMovementFlags(); +} + +void WorldSession::HandleRequestPetInfoOpcode(WorldPacket & /*recv_data */) +{ + /* + sLog.outDebug("WORLD: CMSG_REQUEST_PET_INFO"); + recv_data.hexlike(); + */ +} + +void WorldSession::HandleSetTaxiBenchmarkOpcode(WorldPacket & recv_data) +{ + uint8 mode; + recv_data >> mode; + + sLog.outDebug("Client used \"/timetest %d\" command", mode); +} + +void WorldSession::HandleQueryInspectAchievements(WorldPacket & recv_data) +{ + uint64 guid; + if (!recv_data.readPackGUID(guid)) + return; + + Player *player = objmgr.GetPlayer(guid); + if (!player) + return; + + player->GetAchievementMgr().SendRespondInspectAchievements(_player); +} + +void WorldSession::HandleWorldStateUITimerUpdate(WorldPacket& /*recv_data*/) +{ + // empty opcode + sLog.outDebug("WORLD: CMSG_WORLD_STATE_UI_TIMER_UPDATE"); + + WorldPacket data(SMSG_WORLD_STATE_UI_TIMER_UPDATE, 4); + data << uint32(time(NULL)); + SendPacket(&data); +} + +void WorldSession::HandleReadyForAccountDataTimes(WorldPacket& /*recv_data*/) +{ + // empty opcode + sLog.outDebug("WORLD: CMSG_READY_FOR_ACCOUNT_DATA_TIMES"); + + SendAccountDataTimes(GLOBAL_CACHE_MASK); +} + +void WorldSession::SendSetPhaseShift(uint32 PhaseShift) +{ + WorldPacket data(SMSG_SET_PHASE_SHIFT, 4); + data << uint32(PhaseShift); + SendPacket(&data); +} diff --git a/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp b/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp new file mode 100644 index 00000000000..1148fe174fc --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp @@ -0,0 +1,746 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" +#include "Corpse.h" +#include "Player.h" +#include "Vehicle.h" +#include "SpellAuras.h" +#include "MapManager.h" +#include "Transports.h" +#include "BattleGround.h" +#include "WaypointMovementGenerator.h" +#include "InstanceSaveMgr.h" +#include "ObjectMgr.h" + +void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("WORLD: got MSG_MOVE_WORLDPORT_ACK."); + HandleMoveWorldportAckOpcode(); +} + +void WorldSession::HandleMoveWorldportAckOpcode() +{ + // ignore unexpected far teleports + if (!GetPlayer()->IsBeingTeleportedFar()) + return; + + // get the teleport destination + WorldLocation &loc = GetPlayer()->GetTeleportDest(); + + // possible errors in the coordinate validity check + if (!MapManager::IsValidMapCoord(loc)) + { + LogoutPlayer(false); + return; + } + + // get the destination map entry, not the current one, this will fix homebind and reset greeting + MapEntry const* mEntry = sMapStore.LookupEntry(loc.GetMapId()); + InstanceTemplate const* mInstance = objmgr.GetInstanceTemplate(loc.GetMapId()); + + // reset instance validity, except if going to an instance inside an instance + if (GetPlayer()->m_InstanceValid == false && !mInstance) + GetPlayer()->m_InstanceValid = true; + + GetPlayer()->SetSemaphoreTeleportFar(false); + + Map * oldMap = GetPlayer()->GetMap(); + assert(oldMap); + if (GetPlayer()->IsInWorld()) + { + sLog.outCrash("Player is still in world when teleported from map %u! to new map %u", oldMap->GetId(), loc.GetMapId()); + oldMap->Remove(GetPlayer(), false); + } + + // relocate the player to the teleport destination + Map * newMap = MapManager::Instance().CreateMap(loc.GetMapId(), GetPlayer(), 0); + // the CanEnter checks are done in TeleporTo but conditions may change + // while the player is in transit, for example the map may get full + if (!newMap || !newMap->CanEnter(GetPlayer())) + { + sLog.outError("Map %d could not be created for player %d, porting player to homebind", loc.GetMapId(), GetPlayer()->GetGUIDLow()); + GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation()); + return; + } + else + GetPlayer()->Relocate(&loc); + + GetPlayer()->ResetMap(); + GetPlayer()->SetMap(newMap); + + GetPlayer()->SendInitialPacketsBeforeAddToMap(); + if (!GetPlayer()->GetMap()->Add(GetPlayer())) + { + sLog.outError("WORLD: failed to teleport player %s (%d) to map %d because of unknown reason!", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.GetMapId()); + GetPlayer()->ResetMap(); + GetPlayer()->SetMap(oldMap); + GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation()); + return; + } + + // battleground state prepare (in case join to BG), at relogin/tele player not invited + // only add to bg group and object, if the player was invited (else he entered through command) + if (_player->InBattleGround()) + { + // cleanup setting if outdated + if (!mEntry->IsBattleGroundOrArena()) + { + // We're not in BG + _player->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); + // reset destination bg team + _player->SetBGTeam(0); + } + // join to bg case + else if (BattleGround *bg = _player->GetBattleGround()) + { + if (_player->IsInvitedForBattleGroundInstance(_player->GetBattleGroundId())) + bg->AddPlayer(_player); + } + } + + GetPlayer()->SendInitialPacketsAfterAddToMap(); + + // flight fast teleport case + if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) + { + if (!_player->InBattleGround()) + { + // short preparations to continue flight + FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); + flight->Initialize(*GetPlayer()); + return; + } + + // battleground state prepare, stop flight + GetPlayer()->GetMotionMaster()->MovementExpired(); + GetPlayer()->CleanupAfterTaxiFlight(); + } + + // resurrect character at enter into instance where his corpse exist after add to map + Corpse *corpse = GetPlayer()->GetCorpse(); + if (corpse && corpse->GetType() != CORPSE_BONES && corpse->GetMapId() == GetPlayer()->GetMapId()) + { + if (mEntry->IsDungeon()) + { + GetPlayer()->ResurrectPlayer(0.5f,false); + GetPlayer()->SpawnCorpseBones(); + } + } + + bool allowMount = !mEntry->IsDungeon() || mEntry->IsBattleGroundOrArena(); + if (mInstance) + { + Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid()); + if (MapDifficulty const* mapDiff = GetMapDifficultyData(mEntry->MapID,diff)) + { + if (mapDiff->resetTime) + { + if (uint32 timeReset = sInstanceSaveManager.GetResetTimeFor(mEntry->MapID,diff)) + { + uint32 timeleft = timeReset - time(NULL); + GetPlayer()->SendInstanceResetWarning(mEntry->MapID, diff, timeleft); + } + } + } + allowMount = mInstance->allowMount; + } + + // mount allow check + if (!allowMount) + _player->RemoveAurasByType(SPELL_AURA_MOUNTED); + + // update zone immediately, otherwise leave channel will cause crash in mtmap + uint32 newzone, newarea; + GetPlayer()->GetZoneAndAreaId(newzone, newarea); + GetPlayer()->UpdateZone(newzone, newarea); + + // honorless target + if (GetPlayer()->pvpInfo.inHostileArea) + GetPlayer()->CastSpell(GetPlayer(), 2479, true); + + // resummon pet + GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); + + //lets process all delayed operations on successful teleport + GetPlayer()->ProcessDelayedOperations(); +} + +void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data) +{ + sLog.outDebug("MSG_MOVE_TELEPORT_ACK"); + uint64 guid; + + if (!recv_data.readPackGUID(guid)) + return; + + uint32 flags, time; + recv_data >> flags >> time; + DEBUG_LOG("Guid " UI64FMTD, guid); + DEBUG_LOG("Flags %u, time %u", flags, time/IN_MILISECONDS); + + Unit *mover = _player->m_mover; + Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; + + if (!plMover || !plMover->IsBeingTeleportedNear()) + return; + + if (guid != plMover->GetGUID()) + return; + + plMover->SetSemaphoreTeleportNear(false); + + uint32 old_zone = plMover->GetZoneId(); + + WorldLocation const& dest = plMover->GetTeleportDest(); + + plMover->SetPosition(dest,true); + + uint32 newzone, newarea; + plMover->GetZoneAndAreaId(newzone, newarea); + plMover->UpdateZone(newzone, newarea); + + // new zone + if (old_zone != newzone) + { + // honorless target + if (plMover->pvpInfo.inHostileArea) + plMover->CastSpell(plMover, 2479, true); + } + + // resummon pet + GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); + + //lets process all delayed operations on successful teleport + GetPlayer()->ProcessDelayedOperations(); +} + +void WorldSession::HandleMovementOpcodes(WorldPacket & recv_data) +{ + uint16 opcode = recv_data.GetOpcode(); + //sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); + recv_data.hexlike(); + + Unit *mover = _player->m_mover; + + assert(mover != NULL); // there must always be a mover + + Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; + + // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck + if (plMover && plMover->IsBeingTeleported()) + { + recv_data.rpos(recv_data.wpos()); // prevent warnings spam + return; + } + + /* extract packet */ + uint64 guid; + + if (!recv_data.readPackGUID(guid)) + return; + + MovementInfo movementInfo; + movementInfo.guid = guid; + ReadMovementInfo(recv_data, &movementInfo); + /*----------------*/ + + /* if (recv_data.size() != recv_data.rpos()) + { + sLog.outError("MovementHandler: player %s (guid %d, account %u) sent a packet (opcode %u) that is " SIZEFMTD " bytes larger than it should be. Kicked as cheater.", _player->GetName(), _player->GetGUIDLow(), _player->GetSession()->GetAccountId(), recv_data.GetOpcode(), recv_data.size() - recv_data.rpos()); + KickPlayer();*/ + recv_data.rpos(recv_data.wpos()); // prevent warnings spam + /* return; + }*/ + + if (!Trinity::IsValidMapCoord(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o)) + { + recv_data.rpos(recv_data.wpos()); // prevent warnings spam + return; + } + + /* handle special cases */ + if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) + { + // transports size limited + // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) + if (movementInfo.t_x > 50 || movementInfo.t_y > 50 || movementInfo.t_z > 50) + { + recv_data.rpos(recv_data.wpos()); // prevent warnings spam + return; + } + + if (!Trinity::IsValidMapCoord(movementInfo.x+movementInfo.t_x, movementInfo.y + movementInfo.t_y, + movementInfo.z + movementInfo.t_z, movementInfo.o + movementInfo.t_o)) + { + recv_data.rpos(recv_data.wpos()); // prevent warnings spam + return; + } + + // if we boarded a transport, add us to it + if (plMover && !plMover->GetTransport()) + { + // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list + for (MapManager::TransportSet::const_iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter) + { + if ((*iter)->GetGUID() == movementInfo.t_guid) + { + plMover->m_transport = (*iter); + (*iter)->AddPassenger(plMover); + break; + } + } + } + + if (!mover->GetTransport() && !mover->GetVehicle()) + { + GameObject *go = mover->GetMap()->GetGameObject(movementInfo.t_guid); + if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) + movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; + } + } + else if (plMover && plMover->GetTransport()) // if we were on a transport, leave + { + plMover->m_transport->RemovePassenger(plMover); + plMover->m_transport = NULL; + movementInfo.t_x = 0.0f; + movementInfo.t_y = 0.0f; + movementInfo.t_z = 0.0f; + movementInfo.t_o = 0.0f; + movementInfo.t_time = 0; + movementInfo.t_seat = -1; + } + + // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). + if (opcode == MSG_MOVE_FALL_LAND && plMover && !plMover->isInFlight()) + plMover->HandleFall(movementInfo); + + if (plMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plMover->IsInWater()) + { + // now client not include swimming flag in case jumping under water + plMover->SetInWater(!plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.x, movementInfo.y, movementInfo.z)); + } + + /*----------------------*/ + + /* process position-change */ + WorldPacket data(opcode, recv_data.size()); + movementInfo.time = getMSTime(); + movementInfo.guid = mover->GetGUID(); + WriteMovementInfo(&data, &movementInfo); + mover->SendMessageToSet(&data, _player); + + mover->m_movementInfo = movementInfo; + + // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() + if (mover->GetVehicle()) + { + mover->SetOrientation(movementInfo.o); + return; + } + + mover->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); + + if (plMover) // nothing is charmed, or player charmed + { + plMover->UpdateFallInformationIfNeed(movementInfo, opcode); + + if (movementInfo.z < -500.0f) + { + if (plMover->InBattleGround() + && plMover->GetBattleGround() + && plMover->GetBattleGround()->HandlePlayerUnderMap(_player)) + { + // do nothing, the handle already did if returned true + } + else + { + // NOTE: this is actually called many times while falling + // even after the player has been teleported away + // TODO: discard movement packets after the player is rooted + if (plMover->isAlive()) + { + plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); + // pl can be alive if GM/etc + if (!plMover->isAlive()) + { + // change the death state to CORPSE to prevent the death timer from + // starting in the next player update + plMover->KillPlayer(); + plMover->BuildPlayerRepop(); + } + } + + // cancel the death timer here if started + plMover->RepopAtGraveyard(); + } + } + } + /*else // creature charmed + { + if (mover->canFly()) + { + bool flying = mover->IsFlying(); + if (flying != ((mover->GetByteValue(UNIT_FIELD_BYTES_1, 3) & 0x02) ? true : false)) + mover->SetFlying(flying); + } + }*/ + + //sLog.outString("Receive Movement Packet %s:", opcodeTable[recv_data.GetOpcode()]); + //mover->OutMovementInfo(); +} + +void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recv_data) +{ + uint32 opcode = recv_data.GetOpcode(); + sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); + + /* extract packet */ + uint64 guid; + uint32 unk1; + float newspeed; + + if (!recv_data.readPackGUID(guid)) + return; + + // now can skip not our packet + if (_player->GetGUID() != guid) + { + recv_data.rpos(recv_data.wpos()); // prevent warnings spam + return; + } + + // continue parse packet + + recv_data >> unk1; // counter or moveEvent + + MovementInfo movementInfo; + movementInfo.guid = guid; + ReadMovementInfo(recv_data, &movementInfo); + + recv_data >> newspeed; + /*----------------*/ + + // client ACK send one packet for mounted/run case and need skip all except last from its + // in other cases anti-cheat check can be fail in false case + UnitMoveType move_type; + UnitMoveType force_move_type; + + static char const* move_type_name[MAX_MOVE_TYPE] = { "Walk", "Run", "RunBack", "Swim", "SwimBack", "TurnRate", "Flight", "FlightBack", "PitchRate" }; + + switch(opcode) + { + case CMSG_FORCE_WALK_SPEED_CHANGE_ACK: move_type = MOVE_WALK; force_move_type = MOVE_WALK; break; + case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: move_type = MOVE_RUN; force_move_type = MOVE_RUN; break; + case CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK: move_type = MOVE_RUN_BACK; force_move_type = MOVE_RUN_BACK; break; + case CMSG_FORCE_SWIM_SPEED_CHANGE_ACK: move_type = MOVE_SWIM; force_move_type = MOVE_SWIM; break; + case CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK: move_type = MOVE_SWIM_BACK; force_move_type = MOVE_SWIM_BACK; break; + case CMSG_FORCE_TURN_RATE_CHANGE_ACK: move_type = MOVE_TURN_RATE; force_move_type = MOVE_TURN_RATE; break; + case CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT; force_move_type = MOVE_FLIGHT; break; + case CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT_BACK; force_move_type = MOVE_FLIGHT_BACK; break; + case CMSG_FORCE_PITCH_RATE_CHANGE_ACK: move_type = MOVE_PITCH_RATE; force_move_type = MOVE_PITCH_RATE; break; + default: + sLog.outError("WorldSession::HandleForceSpeedChangeAck: Unknown move type opcode: %u", opcode); + return; + } + + // skip all forced speed changes except last and unexpected + // in run/mounted case used one ACK and it must be skipped.m_forced_speed_changes[MOVE_RUN} store both. + if (_player->m_forced_speed_changes[force_move_type] > 0) + { + --_player->m_forced_speed_changes[force_move_type]; + if (_player->m_forced_speed_changes[force_move_type] > 0) + return; + } + + if (!_player->GetTransport() && fabs(_player->GetSpeed(move_type) - newspeed) > 0.01f) + { + if (_player->GetSpeed(move_type) > newspeed) // must be greater - just correct + { + sLog.outError("%sSpeedChange player %s is NOT correct (must be %f instead %f), force set to correct value", + move_type_name[move_type], _player->GetName(), _player->GetSpeed(move_type), newspeed); + _player->SetSpeed(move_type,_player->GetSpeedRate(move_type),true); + } + else // must be lesser - cheating + { + sLog.outBasic("Player %s from account id %u kicked for incorrect speed (must be %f instead %f)", + _player->GetName(),_player->GetSession()->GetAccountId(),_player->GetSpeed(move_type), newspeed); + _player->GetSession()->KickPlayer(); + } + } +} + +void WorldSession::HandleSetActiveMoverOpcode(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: Recvd CMSG_SET_ACTIVE_MOVER"); + + uint64 guid; + recv_data >> guid; + + if (GetPlayer()->IsInWorld()) + if (Unit *mover = ObjectAccessor::GetUnit(*GetPlayer(), guid)) + { + GetPlayer()->SetMover(mover); + if (mover != GetPlayer() && mover->canFly()) + { + WorldPacket data(SMSG_MOVE_SET_CAN_FLY, 12); + data.append(mover->GetPackGUID()); + data << uint32(0); + SendPacket(&data); + } + } + else + { + sLog.outError("HandleSetActiveMoverOpcode: incorrect mover guid: mover is " UI64FMTD " and should be " UI64FMTD, guid, _player->m_mover->GetGUID()); + GetPlayer()->SetMover(GetPlayer()); + } +} + +void WorldSession::HandleMoveNotActiveMover(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: Recvd CMSG_MOVE_NOT_ACTIVE_MOVER"); + + uint64 old_mover_guid; + if (!recv_data.readPackGUID(old_mover_guid)) + return; + + /*if (_player->m_mover->GetGUID() == old_mover_guid) + { + sLog.outError("HandleMoveNotActiveMover: incorrect mover guid: mover is " I64FMT " and should be " I64FMT " instead of " I64FMT, _player->m_mover->GetGUID(), _player->GetGUID(), old_mover_guid); + recv_data.rpos(recv_data.wpos()); // prevent warnings spam + return; + }*/ + + MovementInfo mi; + mi.guid = old_mover_guid; + ReadMovementInfo(recv_data, &mi); + + //ReadMovementInfo(recv_data, &_player->m_mover->m_movementInfo); + _player->m_movementInfo = mi; +} + +void WorldSession::HandleDismissControlledVehicle(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: Recvd CMSG_DISMISS_CONTROLLED_VEHICLE"); + recv_data.hexlike(); + + uint64 vehicleGUID = _player->GetCharmGUID(); + + if (!vehicleGUID) // something wrong here... + { + recv_data.rpos(recv_data.wpos()); // prevent warnings spam + return; + } + + uint64 guid; + + if (!recv_data.readPackGUID(guid)) + return; + + MovementInfo mi; + mi.guid = guid; + ReadMovementInfo(recv_data, &mi); + + _player->m_movementInfo = mi; + + /* + ReadMovementInfo(recv_data, &_player->m_mover->m_movementInfo);*/ + _player->ExitVehicle(); +} + +void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: Recvd CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE"); + recv_data.hexlike(); + + Unit* vehicle_base = GetPlayer()->GetVehicleBase(); + if (!vehicle_base) + return; + + switch (recv_data.GetOpcode()) + { + case CMSG_REQUEST_VEHICLE_PREV_SEAT: + GetPlayer()->ChangeSeat(-1, false); + break; + case CMSG_REQUEST_VEHICLE_NEXT_SEAT: + GetPlayer()->ChangeSeat(-1, true); + break; + case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: + { + uint64 guid; // current vehicle guid + if (!recv_data.readPackGUID(guid)) + return; + + ReadMovementInfo(recv_data, &vehicle_base->m_movementInfo); + + uint64 accessory; // accessory guid + if (!recv_data.readPackGUID(accessory)) + return; + + int8 seatId; + recv_data >> seatId; + + if (vehicle_base->GetGUID() != guid) + return; + + if (!accessory) + GetPlayer()->ChangeSeat(-1, seatId > 0); // prev/next + else if (Unit *vehUnit = Unit::GetUnit(*GetPlayer(), accessory)) + { + if (Vehicle *vehicle = vehUnit->GetVehicleKit()) + if (vehicle->HasEmptySeat(seatId)) + GetPlayer()->EnterVehicle(vehicle, seatId); + } + } + break; + case CMSG_REQUEST_VEHICLE_SWITCH_SEAT: + { + uint64 guid; // current vehicle guid + if (!recv_data.readPackGUID(guid)) + return; + + int8 seatId; + recv_data >> seatId; + + if (vehicle_base->GetGUID() == guid) + GetPlayer()->ChangeSeat(seatId); + else if (Unit *vehUnit = Unit::GetUnit(*GetPlayer(), guid)) + if (Vehicle *vehicle = vehUnit->GetVehicleKit()) + if (vehicle->HasEmptySeat(seatId)) + GetPlayer()->EnterVehicle(vehicle, seatId); + } + break; + default: + break; + } +} + +void WorldSession::HandleEnterPlayerVehicle(WorldPacket &data) +{ + // Read guid + uint64 guid; + data >> guid; + + if (Player* pl=ObjectAccessor::FindPlayer(guid)) + { + if (!pl->GetVehicleKit()) + return; + if (!pl->IsInRaidWith(_player)) + return; + if (!pl->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) + return; + _player->EnterVehicle(pl); + } +} + +void WorldSession::HandleEjectPasenger(WorldPacket &data) +{ + if (data.GetOpcode() == CMSG_EJECT_PASSENGER) + { + if (Vehicle* Vv= _player->GetVehicleKit()) + { + uint64 guid; + data >> guid; + if (Player* Pl=ObjectAccessor::FindPlayer(guid)) + Pl->ExitVehicle(); + } + } +} + +void WorldSession::HandleRequestVehicleExit(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: Recvd CMSG_REQUEST_VEHICLE_EXIT"); + recv_data.hexlike(); + GetPlayer()->ExitVehicle(); +} + +void WorldSession::HandleMountSpecialAnimOpcode(WorldPacket& /*recvdata*/) +{ + //sLog.outDebug("WORLD: Recvd CMSG_MOUNTSPECIAL_ANIM"); + + WorldPacket data(SMSG_MOUNTSPECIAL_ANIM, 8); + data << uint64(GetPlayer()->GetGUID()); + + GetPlayer()->SendMessageToSet(&data, false); +} + +void WorldSession::HandleMoveKnockBackAck(WorldPacket & recv_data) +{ + sLog.outDebug("CMSG_MOVE_KNOCK_BACK_ACK"); + + uint64 guid; // guid - unused + if (!recv_data.readPackGUID(guid)) + return; + + recv_data.read_skip(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recv_data, &movementInfo); +} + +void WorldSession::HandleMoveHoverAck(WorldPacket& recv_data) +{ + sLog.outDebug("CMSG_MOVE_HOVER_ACK"); + + uint64 guid; // guid - unused + if (!recv_data.readPackGUID(guid)) + return; + + recv_data.read_skip(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recv_data, &movementInfo); + + recv_data.read_skip(); // unk2 +} + +void WorldSession::HandleMoveWaterWalkAck(WorldPacket& recv_data) +{ + sLog.outDebug("CMSG_MOVE_WATER_WALK_ACK"); + + uint64 guid; // guid - unused + if (!recv_data.readPackGUID(guid)) + return; + + recv_data.read_skip(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recv_data, &movementInfo); + + recv_data.read_skip(); // unk2 +} + +void WorldSession::HandleSummonResponseOpcode(WorldPacket& recv_data) +{ + if (!_player->isAlive() || _player->isInCombat()) + return; + + uint64 summoner_guid; + bool agree; + recv_data >> summoner_guid; + recv_data >> agree; + + _player->SummonIfPossible(agree); +} + diff --git a/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp b/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp new file mode 100644 index 00000000000..4e73fb381af --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp @@ -0,0 +1,869 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Language.h" +#include "Database/DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "Player.h" +#include "GossipDef.h" +#include "UpdateMask.h" +#include "ObjectAccessor.h" +#include "Creature.h" +#include "Pet.h" +#include "BattleGroundMgr.h" +#include "BattleGround.h" +#include "Guild.h" +#include "ScriptMgr.h" + +void WorldSession::HandleTabardVendorActivateOpcode(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TABARDDESIGNER); + if (!unit) + { + sLog.outDebug("WORLD: HandleTabardVendorActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + SendTabardVendorActivate(guid); +} + +void WorldSession::SendTabardVendorActivate(uint64 guid) +{ + WorldPacket data(MSG_TABARDVENDOR_ACTIVATE, 8); + data << guid; + SendPacket(&data); +} + +void WorldSession::HandleBankerActivateOpcode(WorldPacket & recv_data) +{ + uint64 guid; + + sLog.outDebug("WORLD: Received CMSG_BANKER_ACTIVATE"); + + recv_data >> guid; + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_BANKER); + if (!unit) + { + sLog.outDebug("WORLD: HandleBankerActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + SendShowBank(guid); +} + +void WorldSession::SendShowBank(uint64 guid) +{ + WorldPacket data(SMSG_SHOW_BANK, 8); + data << guid; + SendPacket(&data); +} + +void WorldSession::HandleTrainerListOpcode(WorldPacket & recv_data) +{ + uint64 guid; + + recv_data >> guid; + SendTrainerList(guid); +} + +void WorldSession::SendTrainerList(uint64 guid) +{ + std::string str = GetTrinityString(LANG_NPC_TAINER_HELLO); + SendTrainerList(guid, str); +} + +void WorldSession::SendTrainerList(uint64 guid, const std::string& strTitle) +{ + sLog.outDebug("WORLD: SendTrainerList"); + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TRAINER); + if (!unit) + { + sLog.outDebug("WORLD: SendTrainerList - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + // trainer list loaded at check; + if (!unit->isCanTrainingOf(_player,true)) + return; + + CreatureInfo const *ci = unit->GetCreatureInfo(); + + if (!ci) + { + sLog.outDebug("WORLD: SendTrainerList - (GUID: %u) NO CREATUREINFO!",GUID_LOPART(guid)); + return; + } + + TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); + if (!trainer_spells) + { + sLog.outDebug("WORLD: SendTrainerList - Training spells not found for creature (GUID: %u Entry: %u)", + GUID_LOPART(guid), unit->GetEntry()); + return; + } + + WorldPacket data(SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1); + data << guid; + data << uint32(trainer_spells->trainerType); + + size_t count_pos = data.wpos(); + data << uint32(trainer_spells->spellList.size()); + + // reputation discount + float fDiscountMod = _player->GetReputationPriceDiscount(unit); + bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProfessionPoints() > 0; + + uint32 count = 0; + for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr) + { + TrainerSpell const* tSpell = &itr->second; + + bool valid = true; + bool primary_prof_first_rank = false; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i) + { + if (!tSpell->learnedSpell[i]) + continue; + if (!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell[i])) + { + valid = false; + break; + } + if (spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->learnedSpell[i])) + primary_prof_first_rank = true; + } + if (!valid) + continue; + + TrainerSpellState state = _player->GetTrainerSpellState(tSpell); + + data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case) + data << uint8(state == TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state); + data << uint32(floor(tSpell->spellCost * fDiscountMod)); + + data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0); + // primary prof. learn confirmation dialog + data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state + data << uint8(tSpell->reqLevel); + data << uint32(tSpell->reqSkill); + data << uint32(tSpell->reqSkillValue); + //prev + req or req + 0 + uint8 maxReq = 0; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i) + { + if (!tSpell->learnedSpell[i]) + continue; + if (SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->learnedSpell[i])) + { + if (chain_node->prev) + { + data << uint32(chain_node->prev); + ++maxReq; + } + } + if (maxReq == 3) + break; + SpellsRequiringSpellMapBounds spellsRequired = spellmgr.GetSpellsRequiredForSpellBounds(tSpell->learnedSpell[i]); + for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second && maxReq < 3; ++itr2) + { + data << uint32(itr2->second); + ++maxReq; + } + if (maxReq == 3) + break; + } + while (maxReq < 3) + { + data << uint32(0); + ++maxReq; + } + + ++count; + } + + data << strTitle; + + data.put(count_pos,count); + SendPacket(&data); +} + +void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket & recv_data) +{ + uint64 guid; + uint32 spellId = 0; + + recv_data >> guid >> spellId; + sLog.outDebug("WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u",uint32(GUID_LOPART(guid)), spellId); + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); + if (!unit) + { + sLog.outDebug("WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + if (!unit->isCanTrainingOf(_player,true)) + return; + + // check present spell in trainer spell list + TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); + if (!trainer_spells) + return; + + // not found, cheat? + TrainerSpell const* trainer_spell = trainer_spells->Find(spellId); + if (!trainer_spell) + return; + + // can't be learn, cheat? Or double learn with lags... + if (_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN) + return; + + // apply reputation discount + uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit))); + + // check money requirement + if (_player->GetMoney() < nSpellCost) + return; + + _player->ModifyMoney(-int32(nSpellCost)); + + WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 12); // visual effect on trainer + data << uint64(guid); + data << uint32(0xB3); // index from SpellVisualKit.dbc + SendPacket(&data); + + data.Initialize(SMSG_PLAY_SPELL_IMPACT, 12); // visual effect on player + data << uint64(_player->GetGUID()); + data << uint32(0x016A); // index from SpellVisualKit.dbc + SendPacket(&data); + + // learn explicitly or cast explicitly + if (trainer_spell->IsCastable()) + _player->CastSpell(_player,trainer_spell->spell,true); + else + _player->learnSpell(spellId, false); + + data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12); + data << uint64(guid); + data << uint32(spellId); // should be same as in packet from client + SendPacket(&data); +} + +void WorldSession::HandleGossipHelloOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_GOSSIP_HELLO"); + + uint64 guid; + recv_data >> guid; + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); + if (!unit) + { + sLog.outDebug("WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + GetPlayer()->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK); + // remove fake death + //if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + // GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + if (unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider()) + { + unit->StopMoving(); + } + + // If spiritguide, no need for gossip menu, just put player into resurrect queue + if (unit->isSpiritGuide()) + { + BattleGround *bg = _player->GetBattleGround(); + if (bg) + { + bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID()); + sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID()); + return; + } + } + + if (!sScriptMgr.GossipHello(_player, unit)) + { +// _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID()); + _player->PrepareGossipMenu(unit, unit->GetCreatureInfo()->GossipMenuId, true); + _player->SendPreparedGossip(unit); + } +} + +/*void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_GOSSIP_SELECT_OPTION"); + + uint32 option; + uint32 unk; + uint64 guid; + std::string code = ""; + + recv_data >> guid >> unk >> option; + + if (_player->PlayerTalkClass->GossipOptionCoded(option)) + { + sLog.outDebug("reading string"); + recv_data >> code; + sLog.outDebug("string read: %s", code.c_str()); + } + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); + if (!unit) + { + sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + if (!code.empty()) + { + if (!Script->GossipSelectWithCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction(option), code.c_str())) + unit->OnGossipSelect (_player, option); + } + else + { + if (!Script->GossipSelect (_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction (option))) + unit->OnGossipSelect (_player, option); + } +}*/ + +void WorldSession::HandleSpiritHealerActivateOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_SPIRIT_HEALER_ACTIVATE"); + + uint64 guid; + + recv_data >> guid; + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_SPIRITHEALER); + if (!unit) + { + sLog.outDebug("WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + SendSpiritResurrect(); +} + +void WorldSession::SendSpiritResurrect() +{ + _player->ResurrectPlayer(0.5f, true); + + _player->DurabilityLossAll(0.25f,true); + + // get corpse nearest graveyard + WorldSafeLocsEntry const *corpseGrave = NULL; + Corpse *corpse = _player->GetCorpse(); + if (corpse) + corpseGrave = objmgr.GetClosestGraveYard( + corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam()); + + // now can spawn bones + _player->SpawnCorpseBones(); + + // teleport to nearest from corpse graveyard, if different from nearest to player ghost + if (corpseGrave) + { + WorldSafeLocsEntry const *ghostGrave = objmgr.GetClosestGraveYard( + _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam()); + + if (corpseGrave != ghostGrave) + _player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation()); + // or update at original position + else + _player->UpdateObjectVisibility(); + } + // or update at original position + else + _player->UpdateObjectVisibility(); +} + +void WorldSession::HandleBinderActivateOpcode(WorldPacket & recv_data) +{ + uint64 npcGUID; + recv_data >> npcGUID; + + if (!GetPlayer()->IsInWorld() || !GetPlayer()->isAlive()) + return; + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID,UNIT_NPC_FLAG_INNKEEPER); + if (!unit) + { + sLog.outDebug("WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + SendBindPoint(unit); +} + +void WorldSession::SendBindPoint(Creature *npc) +{ + // prevent set homebind to instances in any case + if (GetPlayer()->GetMap()->Instanceable()) + return; + + uint32 bindspell = 3286; + + // update sql homebind + CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'", + _player->GetMapId(), _player->GetAreaId(), _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetGUIDLow()); + _player->m_homebindMapId = _player->GetMapId(); + _player->m_homebindAreaId = _player->GetAreaId(); + _player->m_homebindX = _player->GetPositionX(); + _player->m_homebindY = _player->GetPositionY(); + _player->m_homebindZ = _player->GetPositionZ(); + + // send spell for homebinding (3286) + npc->CastSpell(_player, bindspell, true); + + WorldPacket data(SMSG_TRAINER_BUY_SUCCEEDED, (8+4)); + data << uint64(npc->GetGUID()); + data << uint32(bindspell); + SendPacket(&data); + + _player->PlayerTalkClass->CloseGossip(); +} + +void WorldSession::HandleListStabledPetsOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS"); + uint64 npcGUID; + + recv_data >> npcGUID; + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER); + if (!unit) + { + sLog.outDebug("WORLD: HandleListStabledPetsOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + // remove mounts this fix bug where getting pet from stable while mounted deletes pet. + if (GetPlayer()->IsMounted()) + GetPlayer()->RemoveAurasByType(SPELL_AURA_MOUNTED); + + SendStablePet(npcGUID); +} + +void WorldSession::SendStablePet(uint64 guid) +{ + sLog.outDebug("WORLD: Recv MSG_LIST_STABLED_PETS Send."); + + WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size + data << uint64 (guid); + + Pet *pet = _player->GetPet(); + + size_t wpos = data.wpos(); + data << uint8(0); // place holder for slot show number + + data << uint8(GetPlayer()->m_stableSlots); + + uint8 num = 0; // counter for place holder + + // not let move dead pet in slot + if (pet && pet->isAlive() && pet->getPetType() == HUNTER_PET) + { + data << uint32(pet->GetCharmInfo()->GetPetNumber()); + data << uint32(pet->GetEntry()); + data << uint32(pet->getLevel()); + data << pet->GetName(); // petname + data << uint8(1); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show) + ++num; + } + + // 0 1 2 3 4 + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT owner, id, entry, level, name FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot", + _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT); + + if (result) + { + do + { + Field *fields = result->Fetch(); + + data << uint32(fields[1].GetUInt32()); // petnumber + data << uint32(fields[2].GetUInt32()); // creature entry + data << uint32(fields[3].GetUInt32()); // level + data << fields[4].GetString(); // name + data << uint8(2); // 1 = current, 2/3 = in stable (any from 4,5,... create problems with proper show) + + ++num; + }while (result->NextRow()); + } + + data.put(wpos, num); // set real data to placeholder + SendPacket(&data); +} + +void WorldSession::HandleStablePet(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Recv CMSG_STABLE_PET"); + uint64 npcGUID; + + recv_data >> npcGUID; + + if (!GetPlayer()->isAlive()) + return; + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER); + if (!unit) + { + sLog.outDebug("WORLD: HandleStablePet - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + Pet *pet = _player->GetPet(); + + // can't place in stable dead pet + if (!pet||!pet->isAlive()||pet->getPetType() != HUNTER_PET) + { + WorldPacket data(SMSG_STABLE_RESULT, 1); + data << uint8(0x06); + SendPacket(&data); + return; + } + + uint32 free_slot = 1; + + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT owner,slot,id FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot ", + _player->GetGUIDLow(),PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT); + if (result) + { + do + { + Field *fields = result->Fetch(); + + uint32 slot = fields[1].GetUInt32(); + + // slots ordered in query, and if not equal then free + if (slot != free_slot) + break; + + // this slot not free, skip + ++free_slot; + }while (result->NextRow()); + } + + WorldPacket data(SMSG_STABLE_RESULT, 1); + if (free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots) + { + _player->RemovePet(pet,PetSaveMode(free_slot)); + data << uint8(0x08); + } + else + data << uint8(0x06); + + SendPacket(&data); +} + +void WorldSession::HandleUnstablePet(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Recv CMSG_UNSTABLE_PET."); + uint64 npcGUID; + uint32 petnumber; + + recv_data >> npcGUID >> petnumber; + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER); + if (!unit) + { + sLog.outDebug("WORLD: HandleUnstablePet - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + uint32 creature_id = 0; + + { + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot >='%u' AND slot <= '%u'", + _player->GetGUIDLow(),petnumber,PET_SAVE_FIRST_STABLE_SLOT,PET_SAVE_LAST_STABLE_SLOT); + if (result) + { + Field *fields = result->Fetch(); + creature_id = fields[0].GetUInt32(); + } + } + + if (!creature_id) + { + WorldPacket data(SMSG_STABLE_RESULT, 1); + data << uint8(0x06); + SendPacket(&data); + return; + } + + CreatureInfo const* creatureInfo = objmgr.GetCreatureTemplate(creature_id); + if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets())) + { + WorldPacket data(SMSG_STABLE_RESULT, 1); + data << uint8(0x06); + SendPacket(&data); + return; + } + + Pet* pet = _player->GetPet(); + if (pet && pet->isAlive()) + { + WorldPacket data(SMSG_STABLE_RESULT, 1); + data << uint8(0x06); + SendPacket(&data); + return; + } + + // delete dead pet + if (pet) + _player->RemovePet(pet,PET_SAVE_AS_DELETED); + + Pet *newpet = new Pet(_player, HUNTER_PET); + if (!newpet->LoadPetFromDB(_player,creature_id,petnumber)) + { + delete newpet; + newpet = NULL; + WorldPacket data(SMSG_STABLE_RESULT, 1); + data << uint8(0x06); + SendPacket(&data); + return; + } + + WorldPacket data(SMSG_STABLE_RESULT, 1); + data << uint8(0x09); + SendPacket(&data); +} + +void WorldSession::HandleBuyStableSlot(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Recv CMSG_BUY_STABLE_SLOT."); + uint64 npcGUID; + + recv_data >> npcGUID; + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER); + if (!unit) + { + sLog.outDebug("WORLD: HandleBuyStableSlot - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + WorldPacket data(SMSG_STABLE_RESULT, 200); + + if (GetPlayer()->m_stableSlots < MAX_PET_STABLES) + { + StableSlotPricesEntry const *SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1); + if (_player->GetMoney() >= SlotPrice->Price) + { + ++GetPlayer()->m_stableSlots; + _player->ModifyMoney(-int32(SlotPrice->Price)); + data << uint8(0x0A); // success buy + } + else + data << uint8(0x06); + } + else + data << uint8(0x06); + + SendPacket(&data); +} + +void WorldSession::HandleStableRevivePet(WorldPacket &/* recv_data */) +{ + sLog.outDebug("HandleStableRevivePet: Not implemented"); +} + +void WorldSession::HandleStableSwapPet(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Recv CMSG_STABLE_SWAP_PET."); + uint64 npcGUID; + uint32 pet_number; + + recv_data >> npcGUID >> pet_number; + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_STABLEMASTER); + if (!unit) + { + sLog.outDebug("WORLD: HandleStableSwapPet - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + WorldPacket data(SMSG_STABLE_RESULT, 200); // guess size + + Pet* pet = _player->GetPet(); + + if (!pet || pet->getPetType() != HUNTER_PET) + return; + + // find swapped pet slot in stable + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT slot,entry FROM character_pet WHERE owner = '%u' AND id = '%u'", + _player->GetGUIDLow(),pet_number); + if (!result) + return; + + Field *fields = result->Fetch(); + + uint32 slot = fields[0].GetUInt32(); + uint32 creature_id = fields[1].GetUInt32(); + + if (!creature_id) + { + WorldPacket data(SMSG_STABLE_RESULT, 1); + data << uint8(0x06); + SendPacket(&data); + return; + } + + CreatureInfo const* creatureInfo = objmgr.GetCreatureTemplate(creature_id); + if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets())) + { + WorldPacket data(SMSG_STABLE_RESULT, 1); + data << uint8(0x06); + SendPacket(&data); + return; + } + + // move alive pet to slot or delete dead pet + _player->RemovePet(pet,pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED); + + // summon unstabled pet + Pet *newpet = new Pet(_player); + if (!newpet->LoadPetFromDB(_player,creature_id,pet_number)) + { + delete newpet; + data << uint8(0x06); + } + else + data << uint8(0x09); + + SendPacket(&data); +} + +void WorldSession::HandleRepairItemOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_REPAIR_ITEM"); + + uint64 npcGUID, itemGUID; + uint8 guildBank; // new in 2.3.2, bool that means from guild bank money + + recv_data >> npcGUID >> itemGUID >> guildBank; + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_REPAIR); + if (!unit) + { + sLog.outDebug("WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + // reputation discount + float discountMod = _player->GetReputationPriceDiscount(unit); + + uint32 TotalCost = 0; + if (itemGUID) + { + sLog.outDebug("ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID)); + + Item* item = _player->GetItemByGuid(itemGUID); + + if (item) + TotalCost= _player->DurabilityRepair(item->GetPos(),true,discountMod,guildBank>0?true:false); + } + else + { + sLog.outDebug("ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID)); + + TotalCost = _player->DurabilityRepairAll(true,discountMod,guildBank>0?true:false); + } + if (guildBank) + { + uint32 GuildId = _player->GetGuildId(); + if (!GuildId) + return; + Guild *pGuild = objmgr.GetGuildById(GuildId); + if (!pGuild) + return; + pGuild->LogBankEvent(GUILD_BANK_LOG_REPAIR_MONEY, 0, _player->GetGUIDLow(), TotalCost); + pGuild->SendMoneyInfo(this, _player->GetGUIDLow()); + } +} + diff --git a/src/server/game/Server/Protocol/Handlers/NPCHandler.h b/src/server/game/Server/Protocol/Handlers/NPCHandler.h new file mode 100644 index 00000000000..98e2fd218d3 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/NPCHandler.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __NPCHANDLER_H +#define __NPCHANDLER_H + +// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform +#if defined(__GNUC__) +#pragma pack(1) +#else +#pragma pack(push,1) +#endif + +struct PageText +{ + uint32 Page_ID; + char * Text; + + uint32 Next_Page; +}; + +// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform +#if defined(__GNUC__) +#pragma pack() +#else +#pragma pack(pop) +#endif + +struct QEmote +{ + uint32 _Emote; + uint32 _Delay; +}; + +struct GossipTextOption +{ + std::string Text_0; + std::string Text_1; + uint32 Language; + float Probability; + QEmote Emotes[3]; +}; + +struct GossipText +{ + GossipTextOption Options[8]; +}; + +struct PageTextLocale +{ + std::vector Text; +}; + +struct NpcTextLocale +{ + NpcTextLocale() { Text_0.resize(8); Text_1.resize(8); } + + std::vector > Text_0; + std::vector > Text_1; +}; +#endif + diff --git a/src/server/game/Server/Protocol/Handlers/PetHandler.cpp b/src/server/game/Server/Protocol/Handlers/PetHandler.cpp new file mode 100644 index 00000000000..34e6845762b --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/PetHandler.cpp @@ -0,0 +1,813 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "Log.h" +#include "Opcodes.h" +#include "Spell.h" +#include "ObjectAccessor.h" +#include "CreatureAI.h" +#include "Util.h" +#include "Pet.h" +#include "World.h" + +void WorldSession::HandleDismissCritter(WorldPacket &recv_data) +{ + uint64 guid; + recv_data >> guid; + + sLog.outDebug("WORLD: Received CMSG_DISMISS_CRITTER for GUID %u", guid); + + Unit* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); + + if (!pet) + { + sLog.outError("Vanitypet %u does not exist", uint32(GUID_LOPART(guid))); + return; + } + + if (_player->GetCritterGUID() == pet->GetGUID()) + { + if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isSummon()) + pet->ToTempSummon()->UnSummon(); + } +} + +void WorldSession::HandlePetAction(WorldPacket & recv_data) +{ + uint64 guid1; + uint32 data; + uint64 guid2; + recv_data >> guid1; //pet guid + recv_data >> data; + recv_data >> guid2; //tag guid + + uint32 spellid = UNIT_ACTION_BUTTON_ACTION(data); + uint8 flag = UNIT_ACTION_BUTTON_TYPE(data); //delete = 0x07 CastSpell = C1 + + // used also for charmed creature + Unit* pet= ObjectAccessor::GetUnit(*_player, guid1); + sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.", uint32(GUID_LOPART(guid1)), uint32(flag), spellid, uint32(GUID_LOPART(guid2))); + if (!pet) + { + sLog.outError("Pet %u not exist.", uint32(GUID_LOPART(guid1))); + return; + } + + if (pet != GetPlayer()->GetFirstControlled()) + { + sLog.outError("HandlePetAction.Pet %u isn't pet of player %s.", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName()); + return; + } + + if (!pet->isAlive()) + return; + + //TODO: allow control charmed player? + if (pet->GetTypeId() == TYPEID_PLAYER && !(flag == ACT_COMMAND && spellid == COMMAND_ATTACK)) + return; + + if (GetPlayer()->m_Controlled.size() == 1) + HandlePetActionHelper(pet, guid1, spellid, flag, guid2); + else + { + //If a pet is dismissed, m_Controlled will change + std::vector controlled; + for (Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr) + if ((*itr)->GetEntry() == pet->GetEntry() && (*itr)->isAlive()) + controlled.push_back(*itr); + for (std::vector::iterator itr = controlled.begin(); itr != controlled.end(); ++itr) + HandlePetActionHelper(*itr, guid1, spellid, flag, guid2); + } +} + +void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid, uint16 flag, uint64 guid2) +{ + CharmInfo *charmInfo = pet->GetCharmInfo(); + if (!charmInfo) + { + sLog.outError("WorldSession::HandlePetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId()); + return; + } + + switch(flag) + { + case ACT_COMMAND: //0x07 + switch(spellid) + { + case COMMAND_STAY: //flat=1792 //STAY + pet->AttackStop(); + pet->InterruptNonMeleeSpells(false); + pet->GetMotionMaster()->MoveIdle(); + charmInfo->SetCommandState(COMMAND_STAY); + + charmInfo->SetIsCommandAttack(false); + charmInfo->SetIsAtStay(true); + charmInfo->SetIsFollowing(false); + charmInfo->SetIsReturning(false); + charmInfo->SaveStayPosition(); + break; + case COMMAND_FOLLOW: //spellid=1792 //FOLLOW + pet->AttackStop(); + pet->InterruptNonMeleeSpells(false); + pet->GetMotionMaster()->MoveFollow(_player,PET_FOLLOW_DIST,pet->GetFollowAngle()); + charmInfo->SetCommandState(COMMAND_FOLLOW); + + charmInfo->SetIsCommandAttack(false); + charmInfo->SetIsAtStay(false); + charmInfo->SetIsReturning(true); + charmInfo->SetIsFollowing(false); + break; + case COMMAND_ATTACK: //spellid=1792 //ATTACK + { + // Can't attack if owner is pacified + if (_player->HasAuraType(SPELL_AURA_MOD_PACIFY)) + { + //pet->SendPetCastFail(spellid, SPELL_FAILED_PACIFIED); + //TODO: Send proper error message to client + return; + } + + // only place where pet can be player + Unit *TargetUnit = ObjectAccessor::GetUnit(*_player, guid2); + if (!TargetUnit) + return; + + if (!pet->canAttack(TargetUnit)) + return; + + // Not let attack through obstructions + if (sWorld.getConfig(CONFIG_PET_LOS)) + { + + if (!pet->IsWithinLOSInMap(TargetUnit)) + return; + + } + + pet->clearUnitState(UNIT_STAT_FOLLOW); + // This is true if pet has no target or has target but targets differs. + if (pet->getVictim() != TargetUnit || (pet->getVictim() == TargetUnit && !pet->GetCharmInfo()->IsCommandAttack())) + { + if (pet->getVictim()) + pet->AttackStop(); + + if (pet->GetTypeId() != TYPEID_PLAYER && pet->ToCreature()->IsAIEnabled) + { + charmInfo->SetIsCommandAttack(true); + charmInfo->SetIsAtStay(false); + charmInfo->SetIsFollowing(false); + charmInfo->SetIsReturning(false); + + pet->ToCreature()->AI()->AttackStart(TargetUnit); + + //10% chance to play special pet attack talk, else growl + if (pet->ToCreature()->isPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10) + pet->SendPetTalk((uint32)PET_TALK_ATTACK); + else + { + // 90% chance for pet and 100% chance for charmed creature + pet->SendPetAIReaction(guid1); + } + } + else // charmed player + { + if (pet->getVictim() && pet->getVictim() != TargetUnit) + pet->AttackStop(); + + charmInfo->SetIsCommandAttack(true); + charmInfo->SetIsAtStay(false); + charmInfo->SetIsFollowing(false); + charmInfo->SetIsReturning(false); + + pet->Attack(TargetUnit,true); + pet->SendPetAIReaction(guid1); + } + } + break; + } + case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet) + if (pet->GetCharmerGUID() == GetPlayer()->GetGUID()) + _player->StopCastingCharm(); + else if (pet->GetOwnerGUID() == GetPlayer()->GetGUID()) + { + assert(pet->GetTypeId() == TYPEID_UNIT); + if (pet->isPet()) + { + if (((Pet*)pet)->getPetType() == HUNTER_PET) + GetPlayer()->RemovePet((Pet*)pet, PET_SAVE_AS_DELETED); + else + //dismissing a summoned pet is like killing them (this prevents returning a soulshard...) + pet->setDeathState(CORPSE); + } + else if (pet->HasUnitTypeMask(UNIT_MASK_MINION)) + { + ((Minion*)pet)->UnSummon(); + } + } + break; + default: + sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); + } + break; + case ACT_REACTION: // 0x6 + switch(spellid) + { + case REACT_PASSIVE: //passive + pet->AttackStop(); + + case REACT_DEFENSIVE: //recovery + case REACT_AGGRESSIVE: //activete + if (pet->GetTypeId() == TYPEID_UNIT) + pet->ToCreature()->SetReactState(ReactStates(spellid)); + break; + } + break; + case ACT_DISABLED: // 0x81 spell (disabled), ignore + case ACT_PASSIVE: // 0x01 + case ACT_ENABLED: // 0xC1 spell + { + Unit* unit_target = NULL; + + if (guid2) + unit_target = ObjectAccessor::GetUnit(*_player,guid2); + + // do not cast unknown spells + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid); + if (!spellInfo) + { + sLog.outError("WORLD: unknown PET spell id %i", spellid); + return; + } + + if (spellInfo->StartRecoveryCategory > 0) + if (pet->ToCreature()->GetGlobalCooldown() > 0) + return; + + for (uint32 i = 0; i < 3; ++i) + { + if (spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENEMY_SRC || spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENEMY_DST || spellInfo->EffectImplicitTargetA[i] == TARGET_DEST_DYNOBJ_ENEMY) + return; + } + + // do not cast not learned spells + if (!pet->HasSpell(spellid) || IsPassiveSpell(spellid)) + return; + + // Clear the flags as if owner clicked 'attack'. AI will reset them + // after AttackStart, even if spell failed + if (pet->GetCharmInfo()) + { + pet->GetCharmInfo()->SetIsAtStay(false); + pet->GetCharmInfo()->SetIsCommandAttack(true); + pet->GetCharmInfo()->SetIsReturning(false); + pet->GetCharmInfo()->SetIsFollowing(false); + } + + Spell *spell = new Spell(pet, spellInfo, false); + + SpellCastResult result = spell->CheckPetCast(unit_target); + + //auto turn to target unless possessed + if (result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->isPossessed() && !pet->IsVehicle()) + { + if (unit_target) + { + pet->SetInFront(unit_target); + if (unit_target->GetTypeId() == TYPEID_PLAYER) + pet->SendUpdateToPlayer((Player*)unit_target); + } + else if (Unit *unit_target2 = spell->m_targets.getUnitTarget()) + { + pet->SetInFront(unit_target2); + if (unit_target2->GetTypeId() == TYPEID_PLAYER) + pet->SendUpdateToPlayer((Player*)unit_target2); + } + if (Unit* powner = pet->GetCharmerOrOwner()) + if (powner->GetTypeId() == TYPEID_PLAYER) + pet->SendUpdateToPlayer(powner->ToPlayer()); + result = SPELL_CAST_OK; + } + + if (result == SPELL_CAST_OK) + { + pet->ToCreature()->AddCreatureSpellCooldown(spellid); + + unit_target = spell->m_targets.getUnitTarget(); + + //10% chance to play special pet attack talk, else growl + //actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell + if (pet->ToCreature()->isPet() && (((Pet*)pet)->getPetType() == SUMMON_PET) && (pet != unit_target) && (urand(0, 100) < 10)) + pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); + else + { + pet->SendPetAIReaction(guid1); + } + + if (unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->isPossessed() && !pet->IsVehicle()) + { + // This is true if pet has no target or has target but targets differs. + if (pet->getVictim() != unit_target) + { + if (pet->getVictim()) + pet->AttackStop(); + pet->GetMotionMaster()->Clear(); + if (pet->ToCreature()->IsAIEnabled) + pet->ToCreature()->AI()->AttackStart(unit_target); + } + } + + spell->prepare(&(spell->m_targets)); + } + else + { + if (pet->isPossessed() || pet->IsVehicle()) + Spell::SendCastResult(GetPlayer(),spellInfo,0,result); + else + pet->SendPetCastFail(spellid, result); + + if (!pet->ToCreature()->HasSpellCooldown(spellid)) + GetPlayer()->SendClearCooldown(spellid, pet); + + spell->finish(false); + delete spell; + + // reset specific flags in case of spell fail. AI will reset other flags + if (pet->GetCharmInfo()) + pet->GetCharmInfo()->SetIsCommandAttack(false); + } + break; + } + default: + sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); + } +} + +void WorldSession::HandlePetNameQuery(WorldPacket & recv_data) +{ + sLog.outDetail("HandlePetNameQuery. CMSG_PET_NAME_QUERY"); + + uint32 petnumber; + uint64 petguid; + + recv_data >> petnumber; + recv_data >> petguid; + + SendPetNameQuery(petguid,petnumber); +} + +void WorldSession::SendPetNameQuery(uint64 petguid, uint32 petnumber) +{ + Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, petguid); + if (!pet) + { + WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4+4+7+1)); + data << uint32(petnumber); + data << "Unknown"; + data << uint32(0); + data << uint8(0); + _player->GetSession()->SendPacket(&data); + return; + } + + std::string name = pet->GetName(); + + WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4+4+name.size()+1)); + data << uint32(petnumber); + data << name.c_str(); + data << uint32(pet->GetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP)); + + if (pet->isPet() && ((Pet*)pet)->GetDeclinedNames()) + { + data << uint8(1); + for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + data << ((Pet*)pet)->GetDeclinedNames()->name[i]; + } + else + data << uint8(0); + + _player->GetSession()->SendPacket(&data); +} + +void WorldSession::HandlePetSetAction(WorldPacket & recv_data) +{ + sLog.outDetail("HandlePetSetAction. CMSG_PET_SET_ACTION"); + + uint64 petguid; + uint8 count; + + recv_data >> petguid; + + Unit* pet = ObjectAccessor::GetUnit(*_player, petguid); + + if (!pet || pet != _player->GetFirstControlled()) + { + sLog.outError("HandlePetSetAction: Unknown pet or pet owner."); + return; + } + + CharmInfo *charmInfo = pet->GetCharmInfo(); + if (!charmInfo) + { + sLog.outError("WorldSession::HandlePetSetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId()); + return; + } + + count = (recv_data.size() == 24) ? 2 : 1; + + uint32 position[2]; + uint32 data[2]; + bool move_command = false; + + for (uint8 i = 0; i < count; ++i) + { + recv_data >> position[i]; + recv_data >> data[i]; + + uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]); + + //ignore invalid position + if (position[i] >= MAX_UNIT_ACTION_BAR_INDEX) + return; + + // in the normal case, command and reaction buttons can only be moved, not removed + // at moving count == 2, at removing count == 1 + // ignore attempt to remove command|reaction buttons (not possible at normal case) + if (act_state == ACT_COMMAND || act_state == ACT_REACTION) + { + if (count == 1) + return; + + move_command = true; + } + } + + // check swap (at command->spell swap client remove spell first in another packet, so check only command move correctness) + if (move_command) + { + uint8 act_state_0 = UNIT_ACTION_BUTTON_TYPE(data[0]); + if (act_state_0 == ACT_COMMAND || act_state_0 == ACT_REACTION) + { + uint32 spell_id_0 = UNIT_ACTION_BUTTON_ACTION(data[0]); + UnitActionBarEntry const* actionEntry_1 = charmInfo->GetActionBarEntry(position[1]); + if (!actionEntry_1 || spell_id_0 != actionEntry_1->GetAction() || + act_state_0 != actionEntry_1->GetType()) + return; + } + + uint8 act_state_1 = UNIT_ACTION_BUTTON_TYPE(data[1]); + if (act_state_1 == ACT_COMMAND || act_state_1 == ACT_REACTION) + { + uint32 spell_id_1 = UNIT_ACTION_BUTTON_ACTION(data[1]); + UnitActionBarEntry const* actionEntry_0 = charmInfo->GetActionBarEntry(position[0]); + if (!actionEntry_0 || spell_id_1 != actionEntry_0->GetAction() || + act_state_1 != actionEntry_0->GetType()) + return; + } + } + + for (uint8 i = 0; i < count; ++i) + { + uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(data[i]); + uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]); + + sLog.outDetail("Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), 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 + if (!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id))) + { + //sign for autocast + if (act_state == ACT_ENABLED && spell_id) + { + if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isPet()) + ((Pet*)pet)->ToggleAutocast(spell_id, true); + else + charmInfo->ToggleCreatureAutocast(spell_id, true); + } + //sign for no/turn off autocast + else if (act_state == ACT_DISABLED && spell_id) + { + if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isPet()) + ((Pet*)pet)->ToggleAutocast(spell_id, false); + else + charmInfo->ToggleCreatureAutocast(spell_id, false); + + } + + charmInfo->SetActionBar(position[i],spell_id,ActiveStates(act_state)); + } + } +} + +void WorldSession::HandlePetRename(WorldPacket & recv_data) +{ + sLog.outDetail("HandlePetRename. CMSG_PET_RENAME"); + + uint64 petguid; + uint8 isdeclined; + + std::string name; + DeclinedName declinedname; + + recv_data >> petguid; + recv_data >> name; + recv_data >> isdeclined; + + Pet* pet = ObjectAccessor::GetPet(petguid); + // check it! + if (!pet || !pet->isPet() || ((Pet*)pet)->getPetType()!= HUNTER_PET || + !pet->HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) || + pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo()) + return; + + PetNameInvalidReason res = ObjectMgr::CheckPetName(name); + if (res != PET_NAME_SUCCESS) + { + SendPetNameInvalid(res, name, NULL); + return; + } + + if (objmgr.IsReservedName(name)) + { + SendPetNameInvalid(PET_NAME_RESERVED, name, NULL); + return; + } + + pet->SetName(name); + + Unit *owner = pet->GetOwner(); + if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) + owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_NAME); + + pet->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED); + + if (isdeclined) + { + for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + { + recv_data >> declinedname.name[i]; + } + + std::wstring wname; + Utf8toWStr(name, wname); + if (!ObjectMgr::CheckDeclinedNames(GetMainPartOfName(wname,0),declinedname)) + { + SendPetNameInvalid(PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME, name, &declinedname); + return; + } + } + + CharacterDatabase.BeginTransaction(); + if (isdeclined) + { + for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + CharacterDatabase.escape_string(declinedname.name[i]); + CharacterDatabase.PExecute("DELETE FROM character_pet_declinedname WHERE owner = '%u' AND id = '%u'", _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber()); + CharacterDatabase.PExecute("INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u','%u','%s','%s','%s','%s','%s')", + pet->GetCharmInfo()->GetPetNumber(), _player->GetGUIDLow(), declinedname.name[0].c_str(), declinedname.name[1].c_str(), declinedname.name[2].c_str(), declinedname.name[3].c_str(), declinedname.name[4].c_str()); + } + + CharacterDatabase.escape_string(name); + CharacterDatabase.PExecute("UPDATE character_pet SET name = '%s', renamed = '1' WHERE owner = '%u' AND id = '%u'", name.c_str(), _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber()); + CharacterDatabase.CommitTransaction(); + + pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL)); +} + +void WorldSession::HandlePetAbandon(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; //pet guid + sLog.outDetail("HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(guid)); + + if (!_player->IsInWorld()) + return; + + // pet/charmed + Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); + if (pet) + { + if (pet->isPet()) + { + if (pet->GetGUID() == _player->GetPetGUID()) + { + uint32 feelty = pet->GetPower(POWER_HAPPINESS); + pet->SetPower(POWER_HAPPINESS ,(feelty-50000) > 0 ?(feelty-50000) : 0); + } + + _player->RemovePet((Pet*)pet,PET_SAVE_AS_DELETED); + } + else if (pet->GetGUID() == _player->GetCharmGUID()) + _player->StopCastingCharm(); + } +} + +void WorldSession::HandlePetSpellAutocastOpcode(WorldPacket& recvPacket) +{ + sLog.outDetail("CMSG_PET_SPELL_AUTOCAST"); + uint64 guid; + uint32 spellid; + uint8 state; //1 for on, 0 for off + recvPacket >> guid >> spellid >> state; + + if (!_player->GetGuardianPet() && !_player->GetCharm()) + return; + + if (ObjectAccessor::FindPlayer(guid)) + return; + + Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player,guid); + + if (!pet || (pet != _player->GetGuardianPet() && pet != _player->GetCharm())) + { + sLog.outError("HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName()); + return; + } + + // do not add not learned spells/ passive spells + if (!pet->HasSpell(spellid) || IsAutocastableSpell(spellid)) + return; + + CharmInfo *charmInfo = pet->GetCharmInfo(); + if (!charmInfo) + { + sLog.outError("WorldSession::HandlePetSpellAutocastOpcod: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId()); + return; + } + + if (pet->isPet()) + ((Pet*)pet)->ToggleAutocast(spellid, state); + else + pet->GetCharmInfo()->ToggleCreatureAutocast(spellid, state); + + charmInfo->SetSpellAutocast(spellid,state); +} + +void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) +{ + sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL"); + + uint64 guid; + uint32 spellid; + uint8 cast_count; + uint8 unk_flags; // flags (if 0x02 - some additional data are received) + + recvPacket >> guid >> cast_count >> spellid >> unk_flags; + + sLog.outDebug("WORLD: CMSG_PET_CAST_SPELL, cast_count: %u, spellid %u, unk_flags %u", cast_count, spellid, unk_flags); + + // This opcode is also sent from charmed and possessed units (players and creatures) + if (!_player->GetGuardianPet() && !_player->GetCharm()) + return; + + Unit* caster = ObjectAccessor::GetUnit(*_player, guid); + + if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm())) + { + sLog.outError("HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName()); + return; + } + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid); + if (!spellInfo) + { + sLog.outError("WORLD: unknown PET spell id %i", spellid); + return; + } + + if (spellInfo->StartRecoveryCategory > 0) //Check if spell is affected by GCD + if (caster->GetTypeId() == TYPEID_UNIT && caster->ToCreature()->GetGlobalCooldown() > 0) + { + caster->SendPetCastFail(spellid, SPELL_FAILED_NOT_READY); + return; + } + + // do not cast not learned spells + if (!caster->HasSpell(spellid) || IsPassiveSpell(spellid)) + return; + + SpellCastTargets targets; + if (!targets.read(&recvPacket,caster)) + return; + + caster->clearUnitState(UNIT_STAT_FOLLOW); + + Spell *spell = new Spell(caster, spellInfo, spellid == 33395); // water elemental can cast freeze as triggered + spell->m_cast_count = spellid == 33395 ? 0 : cast_count; // probably pending spell cast + spell->m_targets = targets; + + // TODO: need to check victim? + SpellCastResult result; + if (caster->m_movedPlayer) + result = spell->CheckPetCast(caster->m_movedPlayer->GetSelectedUnit()); + else + result = spell->CheckPetCast(NULL); + if (result == SPELL_CAST_OK) + { + if (caster->GetTypeId() == TYPEID_UNIT) + { + Creature* pet = caster->ToCreature(); + pet->AddCreatureSpellCooldown(spellid); + if (pet->isPet()) + { + Pet* p = (Pet*)pet; + // 10% chance to play special pet attack talk, else growl + // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell + if (p->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) + pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); + else + pet->SendPetAIReaction(guid); + } + } + + spell->prepare(&(spell->m_targets)); + } + else + { + caster->SendPetCastFail(spellid, result); + if (caster->GetTypeId() == TYPEID_PLAYER) + { + if (!caster->ToPlayer()->HasSpellCooldown(spellid)) + GetPlayer()->SendClearCooldown(spellid, caster); + } + else + { + if (!caster->ToCreature()->HasSpellCooldown(spellid)) + GetPlayer()->SendClearCooldown(spellid, caster); + } + + spell->finish(false); + delete spell; + } +} + +void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName *declinedName) +{ + WorldPacket data(SMSG_PET_NAME_INVALID, 4 + name.size() + 1 + 1); + data << uint32(error); + data << name; + if (declinedName) + { + data << uint8(1); + for (uint32 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + data << declinedName->name[i]; + } + else + data << uint8(0); + SendPacket(&data); +} + +void WorldSession::HandlePetLearnTalent(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_PET_LEARN_TALENT"); + + uint64 guid; + uint32 talent_id, requested_rank; + recv_data >> guid >> talent_id >> requested_rank; + + _player->LearnPetTalent(guid, talent_id, requested_rank); + _player->SendTalentsInfoData(true); +} + +void WorldSession::HandleLearnPreviewTalentsPet(WorldPacket & recv_data) +{ + sLog.outDebug("CMSG_LEARN_PREVIEW_TALENTS_PET"); + + uint64 guid; + recv_data >> guid; + + uint32 talentsCount; + recv_data >> talentsCount; + + uint32 talentId, talentRank; + + for (uint32 i = 0; i < talentsCount; ++i) + { + recv_data >> talentId >> talentRank; + + _player->LearnPetTalent(guid, talentId, talentRank); + } + + _player->SendTalentsInfoData(true); +} diff --git a/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp b/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp new file mode 100644 index 00000000000..7f578c22656 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp @@ -0,0 +1,938 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Language.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectMgr.h" +#include "Log.h" +#include "Opcodes.h" +#include "Guild.h" +#include "ArenaTeam.h" +#include "GossipDef.h" +#include "SocialMgr.h" + +/*enum PetitionType // dbc data +{ + PETITION_TYPE_GUILD = 1, + PETITION_TYPE_ARENA_TEAM = 3 +};*/ + +// Charters ID in item_template +#define GUILD_CHARTER 5863 +#define GUILD_CHARTER_COST 1000 // 10 S +#define ARENA_TEAM_CHARTER_2v2 23560 +#define ARENA_TEAM_CHARTER_2v2_COST 800000 // 80 G +#define ARENA_TEAM_CHARTER_3v3 23561 +#define ARENA_TEAM_CHARTER_3v3_COST 1200000 // 120 G +#define ARENA_TEAM_CHARTER_5v5 23562 +#define ARENA_TEAM_CHARTER_5v5_COST 2000000 // 200 G + +void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("Received opcode CMSG_PETITION_BUY"); + recv_data.hexlike(); + + uint64 guidNPC; + uint32 clientIndex; // 1 for guild and arenaslot+1 for arenas in client + std::string name; + + recv_data >> guidNPC; // NPC GUID + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data >> name; // name + recv_data.read_skip(); // some string + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + + for (int i = 0; i < 10; ++i) + recv_data.read_skip(); + + recv_data >> clientIndex; // index + recv_data.read_skip(); // 0 + + sLog.outDebug("Petitioner with GUID %u tried sell petition: name %s", GUID_LOPART(guidNPC), name.c_str()); + + // prevent cheating + Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guidNPC,UNIT_NPC_FLAG_PETITIONER); + if (!pCreature) + { + sLog.outDebug("WORLD: HandlePetitionBuyOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(guidNPC)); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + uint32 charterid = 0; + uint32 cost = 0; + uint32 type = 0; + if (pCreature->isTabardDesigner()) + { + // if tabard designer, then trying to buy a guild charter. + // do not let if already in guild. + if (_player->GetGuildId()) + return; + + charterid = GUILD_CHARTER; + cost = GUILD_CHARTER_COST; + type = 9; + } + else + { + // TODO: find correct opcode + if (_player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + SendNotification(LANG_ARENA_ONE_TOOLOW, sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)); + return; + } + + switch(clientIndex) // arenaSlot+1 as received from client (1 from 3 case) + { + case 1: + charterid = ARENA_TEAM_CHARTER_2v2; + cost = ARENA_TEAM_CHARTER_2v2_COST; + type = 2; // 2v2 + break; + case 2: + charterid = ARENA_TEAM_CHARTER_3v3; + cost = ARENA_TEAM_CHARTER_3v3_COST; + type = 3; // 3v3 + break; + case 3: + charterid = ARENA_TEAM_CHARTER_5v5; + cost = ARENA_TEAM_CHARTER_5v5_COST; + type = 5; // 5v5 + break; + default: + sLog.outDebug("unknown selection at buy arena petition: %u", clientIndex); + return; + } + + if (_player->GetArenaTeamId(clientIndex - 1)) // arenaSlot+1 as received from client + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM); + return; + } + } + + if (type == 9) + { + if (objmgr.GetGuildByName(name)) + { + SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_EXISTS_S); + return; + } + if (objmgr.IsReservedName(name) || !ObjectMgr::IsValidCharterName(name)) + { + SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_INVALID); + return; + } + } + else + { + if (objmgr.GetArenaTeamByName(name)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S); + return; + } + if (objmgr.IsReservedName(name) || !ObjectMgr::IsValidCharterName(name)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID); + return; + } + } + + ItemPrototype const *pProto = objmgr.GetItemPrototype(charterid); + if (!pProto) + { + _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, charterid, 0); + return; + } + + if (_player->GetMoney() < cost) + { //player hasn't got enough money + _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, charterid, 0); + return; + } + + ItemPosCountVec dest; + uint8 msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterid, pProto->BuyCount); + if (msg != EQUIP_ERR_OK) + { + _player->SendBuyError(msg, pCreature, charterid, 0); + return; + } + + _player->ModifyMoney(-(int32)cost); + Item *charter = _player->StoreNewItem(dest, charterid, true); + if (!charter) + return; + + charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1, charter->GetGUIDLow()); + // ITEM_FIELD_ENCHANTMENT_1_1 is guild/arenateam id + // ITEM_FIELD_ENCHANTMENT_1_1+1 is current signatures count (showed on item) + charter->SetState(ITEM_CHANGED, _player); + _player->SendNewItem(charter, 1, true, false); + + // a petition is invalid, if both the owner and the type matches + // we checked above, if this player is in an arenateam, so this must be + // datacorruption + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE ownerguid = '%u' AND type = '%u'", _player->GetGUIDLow(), type); + + std::ostringstream ssInvalidPetitionGUIDs; + + if (result) + { + do + { + Field *fields = result->Fetch(); + ssInvalidPetitionGUIDs << "'" << fields[0].GetUInt32() << "' , "; + } while (result->NextRow()); + } + + // delete petitions with the same guid as this one + ssInvalidPetitionGUIDs << "'" << charter->GetGUIDLow() << "'"; + + sLog.outDebug("Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str()); + CharacterDatabase.escape_string(name); + CharacterDatabase.BeginTransaction(); + CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); + CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); + CharacterDatabase.PExecute("INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES ('%u', '%u', '%s', '%u')", + _player->GetGUIDLow(), charter->GetGUIDLow(), name.c_str(), type); + CharacterDatabase.CommitTransaction(); +} + +void WorldSession::HandlePetitionShowSignOpcode(WorldPacket & recv_data) +{ + // ok + sLog.outDebug("Received opcode CMSG_PETITION_SHOW_SIGNATURES"); + //recv_data.hexlike(); + + uint8 signs = 0; + uint64 petitionguid; + recv_data >> petitionguid; // petition guid + + // solve (possible) some strange compile problems with explicit use GUID_LOPART(petitionguid) at some GCC versions (wrong code optimization in compiler?) + uint32 petitionguid_low = GUID_LOPART(petitionguid); + + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", petitionguid_low); + if (!result) + { + sLog.outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName()); + return; + } + Field *fields = result->Fetch(); + uint32 type = fields[0].GetUInt32(); + + // if guild petition and has guild => error, return; + if (type == 9 && _player->GetGuildId()) + return; + + result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", petitionguid_low); + + // result == NULL also correct in case no sign yet + if (result) + signs = result->GetRowCount(); + + sLog.outDebug("CMSG_PETITION_SHOW_SIGNATURES petition entry: '%u'", petitionguid_low); + + WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+1+signs*12)); + data << uint64(petitionguid); // petition guid + data << uint64(_player->GetGUID()); // owner guid + data << uint32(petitionguid_low); // guild guid (in mangos always same as GUID_LOPART(petitionguid) + data << uint8(signs); // sign's count + + for (uint8 i = 1; i <= signs; ++i) + { + Field *fields2 = result->Fetch(); + uint64 plguid = fields2[0].GetUInt64(); + + data << uint64(plguid); // Player GUID + data << (uint32)0; // there 0 ... + + result->NextRow(); + } + SendPacket(&data); +} + +void WorldSession::HandlePetitionQueryOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("Received opcode CMSG_PETITION_QUERY"); // ok + //recv_data.hexlike(); + + uint32 guildguid; + uint64 petitionguid; + recv_data >> guildguid; // in Trinity always same as GUID_LOPART(petitionguid) + recv_data >> petitionguid; // petition guid + sLog.outDebug("CMSG_PETITION_QUERY Petition GUID %u Guild GUID %u", GUID_LOPART(petitionguid), guildguid); + + SendPetitionQueryOpcode(petitionguid); +} + +void WorldSession::SendPetitionQueryOpcode(uint64 petitionguid) +{ + uint64 ownerguid = 0; + uint32 type; + std::string name = "NO_NAME_FOR_GUID"; + uint8 signs = 0; + + QueryResult_AutoPtr result = CharacterDatabase.PQuery( + "SELECT ownerguid, name, " + " (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs, " + " type " + "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid)); + + if (result) + { + Field* fields = result->Fetch(); + ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); + name = fields[1].GetCppString(); + signs = fields[2].GetUInt8(); + type = fields[3].GetUInt32(); + } + else + { + sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid)); + return; + } + + WorldPacket data(SMSG_PETITION_QUERY_RESPONSE, (4+8+name.size()+1+1+4*12+2+10)); + data << uint32(GUID_LOPART(petitionguid)); // guild/team guid (in Trinity always same as GUID_LOPART(petition guid) + data << uint64(ownerguid); // charter owner guid + data << name; // name (guild/arena team) + data << uint8(0); // some string + if (type == 9) + { + data << uint32(9); + data << uint32(9); + data << uint32(0); // bypass client - side limitation, a different value is needed here for each petition + } + else + { + data << uint32(type-1); + data << uint32(type-1); + data << uint32(type); // bypass client - side limitation, a different value is needed here for each petition + } + data << uint32(0); // 5 + data << uint32(0); // 6 + data << uint32(0); // 7 + data << uint32(0); // 8 + data << uint16(0); // 9 2 bytes field + data << uint32(0); // 10 + data << uint32(0); // 11 + data << uint32(0); // 13 count of next strings? + + for (int i = 0; i < 10; ++i) + data << uint8(0); // some string + + data << uint32(0); // 14 + + if (type == 9) + data << uint32(0); // 15 0 - guild, 1 - arena team + else + data << uint32(1); + + SendPacket(&data); +} + +void WorldSession::HandlePetitionRenameOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("Received opcode MSG_PETITION_RENAME"); // ok + //recv_data.hexlike(); + + uint64 petitionguid; + uint32 type; + std::string newname; + + recv_data >> petitionguid; // guid + recv_data >> newname; // new name + + Item *item = _player->GetItemByGuid(petitionguid); + if (!item) + return; + + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); + + if (result) + { + Field* fields = result->Fetch(); + type = fields[0].GetUInt32(); + } + else + { + sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid)); + return; + } + + if (type == 9) + { + if (objmgr.GetGuildByName(newname)) + { + SendGuildCommandResult(GUILD_CREATE_S, newname, ERR_GUILD_NAME_EXISTS_S); + return; + } + if (objmgr.IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname)) + { + SendGuildCommandResult(GUILD_CREATE_S, newname, ERR_GUILD_NAME_INVALID); + return; + } + } + else + { + if (objmgr.GetArenaTeamByName(newname)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_EXISTS_S); + return; + } + if (objmgr.IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_INVALID); + return; + } + } + + std::string db_newname = newname; + CharacterDatabase.escape_string(db_newname); + CharacterDatabase.PExecute("UPDATE petition SET name = '%s' WHERE petitionguid = '%u'", + db_newname.c_str(), GUID_LOPART(petitionguid)); + + sLog.outDebug("Petition (GUID: %u) renamed to '%s'", GUID_LOPART(petitionguid), newname.c_str()); + WorldPacket data(MSG_PETITION_RENAME, (8+newname.size()+1)); + data << uint64(petitionguid); + data << newname; + SendPacket(&data); +} + +void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("Received opcode CMSG_PETITION_SIGN"); // ok + //recv_data.hexlike(); + + Field *fields; + uint64 petitionguid; + uint8 unk; + recv_data >> petitionguid; // petition guid + recv_data >> unk; + + QueryResult_AutoPtr result = CharacterDatabase.PQuery( + "SELECT ownerguid, " + " (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs, " + " type " + "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid)); + + if (!result) + { + sLog.outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName()); + return; + } + + fields = result->Fetch(); + uint64 ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); + uint8 signs = fields[1].GetUInt8(); + uint32 type = fields[2].GetUInt32(); + + uint32 plguidlo = _player->GetGUIDLow(); + if (GUID_LOPART(ownerguid) == plguidlo) + return; + + // not let enemies sign guild charter + if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != objmgr.GetPlayerTeamByGUID(ownerguid)) + { + if (type != 9) + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); + else + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_NOT_ALLIED); + return; + } + + if (type != 9) + { + if (_player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", _player->GetName(), ERR_ARENA_TEAM_TARGET_TOO_LOW_S); + return; + } + + uint8 slot = ArenaTeam::GetSlotByType(type); + if (slot >= MAX_ARENA_SLOT) + return; + + if (_player->GetArenaTeamId(slot)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_IN_ARENA_TEAM_S); + return; + } + + if (_player->GetArenaTeamIdInvited()) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S); + return; + } + } + else + { + if (_player->GetGuildId()) + { + SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_IN_GUILD_S); + return; + } + if (_player->GetGuildIdInvited()) + { + SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_INVITED_TO_GUILD_S); + return; + } + } + + if (++signs > type) // client signs maximum + return; + + //client doesn't allow to sign petition two times by one character, but not check sign by another character from same account + //not allow sign another player from already sign player account + result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u' AND petitionguid = '%u'", GetAccountId(), GUID_LOPART(petitionguid)); + + if (result) + { + WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4)); + data << uint64(petitionguid); + data << uint64(_player->GetGUID()); + data << (uint32)PETITION_SIGN_ALREADY_SIGNED; + + // close at signer side + SendPacket(&data); + + // update for owner if online + if (Player *owner = objmgr.GetPlayer(ownerguid)) + owner->GetSession()->SendPacket(&data); + return; + } + + CharacterDatabase.PExecute("INSERT INTO petition_sign (ownerguid,petitionguid, playerguid, player_account) VALUES ('%u', '%u', '%u','%u')", GUID_LOPART(ownerguid),GUID_LOPART(petitionguid), plguidlo,GetAccountId()); + + sLog.outDebug("PETITION SIGN: GUID %u by player: %s (GUID: %u Account: %u)", GUID_LOPART(petitionguid), _player->GetName(),plguidlo,GetAccountId()); + + WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4)); + data << uint64(petitionguid); + data << uint64(_player->GetGUID()); + data << uint32(PETITION_SIGN_OK); + + // close at signer side + SendPacket(&data); + + // update signs count on charter, required testing... + //Item *item = _player->GetItemByGuid(petitionguid)); + //if (item) + // item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1+1, signs); + + // update for owner if online + if (Player *owner = objmgr.GetPlayer(ownerguid)) + owner->GetSession()->SendPacket(&data); +} + +void WorldSession::HandlePetitionDeclineOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("Received opcode MSG_PETITION_DECLINE"); // ok + //recv_data.hexlike(); + + uint64 petitionguid; + uint64 ownerguid; + recv_data >> petitionguid; // petition guid + sLog.outDebug("Petition %u declined by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow()); + + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT ownerguid FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); + if (!result) + return; + + Field *fields = result->Fetch(); + ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); + + Player *owner = objmgr.GetPlayer(ownerguid); + if (owner) // petition owner online + { + WorldPacket data(MSG_PETITION_DECLINE, 8); + data << uint64(_player->GetGUID()); + owner->GetSession()->SendPacket(&data); + } +} + +void WorldSession::HandleOfferPetitionOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("Received opcode CMSG_OFFER_PETITION"); // ok + //recv_data.hexlike(); + + uint8 signs = 0; + uint64 petitionguid, plguid; + uint32 type, junk; + Player *player; + recv_data >> junk; // this is not petition type! + recv_data >> petitionguid; // petition guid + recv_data >> plguid; // player guid + + player = ObjectAccessor::FindPlayer(plguid); + if (!player) + return; + + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); + if (!result) + return; + + Field *fields = result->Fetch(); + type = fields[0].GetUInt32(); + + sLog.outDebug("OFFER PETITION: type %u, GUID1 %u, to player id: %u", type, GUID_LOPART(petitionguid), GUID_LOPART(plguid)); + + if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam()) + { + if (type != 9) + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); + else + SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_NOT_ALLIED); + return; + } + + if (type != 9) + { + if (player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + // player is too low level to join an arena team + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ARENA_TEAM_TARGET_TOO_LOW_S); + return; + } + + uint8 slot = ArenaTeam::GetSlotByType(type); + if (slot >= MAX_ARENA_SLOT) + return; + + if (player->GetArenaTeamId(slot)) + { + // player is already in an arena team + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ALREADY_IN_ARENA_TEAM_S); + return; + } + + if (player->GetArenaTeamIdInvited()) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S); + return; + } + } + else + { + if (player->GetGuildId()) + { + SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_IN_GUILD_S); + return; + } + + if (player->GetGuildIdInvited()) + { + SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_INVITED_TO_GUILD_S); + return; + } + } + + result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); + // result == NULL also correct charter without signs + if (result) + signs = result->GetRowCount(); + + WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+signs+signs*12)); + data << uint64(petitionguid); // petition guid + data << uint64(_player->GetGUID()); // owner guid + data << uint32(GUID_LOPART(petitionguid)); // guild guid (in mangos always same as GUID_LOPART(petition guid) + data << uint8(signs); // sign's count + + for (uint8 i = 1; i <= signs; ++i) + { + Field *fields2 = result->Fetch(); + plguid = fields2[0].GetUInt64(); + + data << uint64(plguid); // Player GUID + data << (uint32)0; // there 0 ... + + result->NextRow(); + } + + player->GetSession()->SendPacket(&data); +} + +void WorldSession::HandleTurnInPetitionOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("Received opcode CMSG_TURN_IN_PETITION"); // ok + //recv_data.hexlike(); + + WorldPacket data; + uint64 petitionguid; + + uint32 ownerguidlo; + uint32 type; + std::string name; + + recv_data >> petitionguid; + + sLog.outDebug("Petition %u turned in by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow()); + + // data + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT ownerguid, name, type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); + if (result) + { + Field *fields = result->Fetch(); + ownerguidlo = fields[0].GetUInt32(); + name = fields[1].GetCppString(); + type = fields[2].GetUInt32(); + } + else + { + sLog.outError("petition table has broken data!"); + return; + } + + if (type == 9) + { + if (_player->GetGuildId()) + { + data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); + data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild + _player->GetSession()->SendPacket(&data); + return; + } + } + else + { + uint8 slot = ArenaTeam::GetSlotByType(type); + if (slot >= MAX_ARENA_SLOT) + return; + + if (_player->GetArenaTeamId(slot)) + { + //data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); + //data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild + //_player->GetSession()->SendPacket(&data); + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM); + return; + } + } + + if (_player->GetGUIDLow() != ownerguidlo) + return; + + // signs + uint8 signs; + result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); + if (result) + signs = result->GetRowCount(); + else + signs = 0; + + uint32 count; + //if (signs < sWorld.getConfig(CONFIG_MIN_PETITION_SIGNS)) + if (type == 9) + count = sWorld.getConfig(CONFIG_MIN_PETITION_SIGNS); + else + count = type-1; + if (signs < count) + { + data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); + data << (uint32)PETITION_TURN_NEED_MORE_SIGNATURES; // need more signatures... + SendPacket(&data); + return; + } + + if (type == 9) + { + if (objmgr.GetGuildByName(name)) + { + SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_EXISTS_S); + return; + } + } + else + { + if (objmgr.GetArenaTeamByName(name)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S); + return; + } + } + + // and at last charter item check + Item *item = _player->GetItemByGuid(petitionguid); + if (!item) + return; + + // OK! + + // delete charter item + _player->DestroyItem(item->GetBagSlot(),item->GetSlot(), true); + + if (type == 9) // create guild + { + Guild* guild = new Guild; + if (!guild->Create(_player, name)) + { + delete guild; + return; + } + + // register guild and add guildmaster + objmgr.AddGuild(guild); + + // add members + for (uint8 i = 0; i < signs; ++i) + { + Field* fields = result->Fetch(); + guild->AddMember(fields[0].GetUInt64(), guild->GetLowestRank()); + result->NextRow(); + } + } + else // or arena team + { + ArenaTeam* at = new ArenaTeam; + if (!at->Create(_player->GetGUID(), type, name)) + { + sLog.outError("PetitionsHandler: arena team create failed."); + delete at; + return; + } + + uint32 icon, iconcolor, border, bordercolor, backgroud; + recv_data >> backgroud >> icon >> iconcolor >> border >> bordercolor; + + at->SetEmblem(backgroud, icon, iconcolor, border, bordercolor); + + // register team and add captain + objmgr.AddArenaTeam(at); + sLog.outDebug("PetitonsHandler: arena team added to objmrg"); + + // add members + for (uint8 i = 0; i < signs; ++i) + { + Field* fields = result->Fetch(); + uint64 memberGUID = fields[0].GetUInt64(); + sLog.outDebug("PetitionsHandler: adding arena member %u", GUID_LOPART(memberGUID)); + at->AddMember(memberGUID); + result->NextRow(); + } + } + + CharacterDatabase.BeginTransaction(); + CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); + CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); + CharacterDatabase.CommitTransaction(); + + // created + sLog.outDebug("TURN IN PETITION GUID %u", GUID_LOPART(petitionguid)); + + data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); + data << (uint32)PETITION_TURN_OK; + SendPacket(&data); +} + +void WorldSession::HandlePetitionShowListOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("Received CMSG_PETITION_SHOWLIST"); // ok + //recv_data.hexlike(); + + uint64 guid; + recv_data >> guid; + + SendPetitionShowList(guid); +} + +void WorldSession::SendPetitionShowList(uint64 guid) +{ + Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_PETITIONER); + if (!pCreature) + { + sLog.outDebug("WORLD: HandlePetitionShowListOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + uint8 count = 0; + if (pCreature->isTabardDesigner()) + count = 1; + else + count = 3; + + WorldPacket data(SMSG_PETITION_SHOWLIST, 8+1+4*6); + data << guid; // npc guid + data << count; // count + if (count == 1) + { + data << uint32(1); // index + data << uint32(GUILD_CHARTER); // charter entry + data << uint32(16161); // charter display id + data << uint32(GUILD_CHARTER_COST); // charter cost + data << uint32(0); // unknown + data << uint32(9); // required signs? + } + else + { + // 2v2 + data << uint32(1); // index + data << uint32(ARENA_TEAM_CHARTER_2v2); // charter entry + data << uint32(16161); // charter display id + data << uint32(ARENA_TEAM_CHARTER_2v2_COST); // charter cost + data << uint32(2); // unknown + data << uint32(2); // required signs? + // 3v3 + data << uint32(2); // index + data << uint32(ARENA_TEAM_CHARTER_3v3); // charter entry + data << uint32(16161); // charter display id + data << uint32(ARENA_TEAM_CHARTER_3v3_COST); // charter cost + data << uint32(3); // unknown + data << uint32(3); // required signs? + // 5v5 + data << uint32(3); // index + data << uint32(ARENA_TEAM_CHARTER_5v5); // charter entry + data << uint32(16161); // charter display id + data << uint32(ARENA_TEAM_CHARTER_5v5_COST); // charter cost + data << uint32(5); // unknown + data << uint32(5); // required signs? + } + //for (uint8 i = 0; i < count; ++i) + //{ + // data << uint32(i); // index + // data << uint32(GUILD_CHARTER); // charter entry + // data << uint32(16161); // charter display id + // data << uint32(GUILD_CHARTER_COST+i); // charter cost + // data << uint32(0); // unknown + // data << uint32(9); // required signs? + //} + SendPacket(&data); + sLog.outDebug("Sent SMSG_PETITION_SHOWLIST"); +} diff --git a/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp b/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp new file mode 100644 index 00000000000..1067ad49bc4 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp @@ -0,0 +1,539 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Language.h" +#include "Database/DatabaseEnv.h" +#include "Database/DatabaseImpl.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" +#include "World.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "UpdateMask.h" +#include "NPCHandler.h" +#include "Pet.h" +#include "MapManager.h" + +void WorldSession::SendNameQueryOpcode(Player *p) +{ + if (!p) + return; + // guess size + WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8+1+1+1+1+1+10)); + data.append(p->GetPackGUID()); // player guid + data << uint8(0); // added in 3.1 + data << p->GetName(); // played name + data << uint8(0); // realm name for cross realm BG usage + data << uint8(p->getRace()); + data << uint8(p->getGender()); + data << uint8(p->getClass()); + if (DeclinedName const* names = p->GetDeclinedNames()) + { + data << uint8(1); // is declined + for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + data << names->name[i]; + } + else + data << uint8(0); // is not declined + + SendPacket(&data); +} + +void WorldSession::SendNameQueryOpcodeFromDB(uint64 guid) +{ + CharacterDatabase.AsyncPQuery(&WorldSession::SendNameQueryOpcodeFromDBCallBack, GetAccountId(), + !sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) ? + // ------- Query Without Declined Names -------- + // 0 1 2 3 4 + "SELECT guid, name, race, gender, class " + "FROM characters WHERE guid = '%u'" + : + // --------- Query With Declined Names --------- + // 0 1 2 3 4 + "SELECT characters.guid, name, race, gender, class, " + // 5 6 7 8 9 + "genitive, dative, accusative, instrumental, prepositional " + "FROM characters LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid WHERE characters.guid = '%u'", + GUID_LOPART(guid)); +} + +void WorldSession::SendNameQueryOpcodeFromDBCallBack(QueryResult_AutoPtr result, uint32 accountId) +{ + if (!result) + return; + + WorldSession * session = sWorld.FindSession(accountId); + if (!session) + return; + + Field *fields = result->Fetch(); + uint32 guid = fields[0].GetUInt32(); + std::string name = fields[1].GetCppString(); + uint8 pRace = 0, pGender = 0, pClass = 0; + if (name == "") + name = session->GetTrinityString(LANG_NON_EXIST_CHARACTER); + else + { + pRace = fields[2].GetUInt8(); + pGender = fields[3].GetUInt8(); + pClass = fields[4].GetUInt8(); + } + // guess size + WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8+1+1+1+1+1+1+10)); + data.appendPackGUID(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); + data << uint8(0); // added in 3.1 + data << name; + data << uint8(0); // realm name for cross realm BG usage + data << uint8(pRace); // race + data << uint8(pGender); // gender + data << uint8(pClass); // class + + // if the first declined name field (5) is empty, the rest must be too + if (sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) && fields[5].GetCppString() != "") + { + data << uint8(1); // is declined + for (int i = 5; i < MAX_DECLINED_NAME_CASES+5; ++i) + data << fields[i].GetCppString(); + } + else + data << uint8(0); // is not declined + + session->SendPacket(&data); +} + +void WorldSession::HandleNameQueryOpcode(WorldPacket & recv_data) +{ + uint64 guid; + + recv_data >> guid; + + Player *pChar = objmgr.GetPlayer(guid); + + if (pChar) + SendNameQueryOpcode(pChar); + else + SendNameQueryOpcodeFromDB(guid); +} + +void WorldSession::HandleQueryTimeOpcode(WorldPacket & /*recv_data*/) +{ + SendQueryTimeResponse(); +} + +void WorldSession::SendQueryTimeResponse() +{ + WorldPacket data(SMSG_QUERY_TIME_RESPONSE, 4+4); + data << uint32(time(NULL)); + data << uint32(sWorld.GetNextDailyQuestsResetTime() - time(NULL)); + SendPacket(&data); +} + +/// Only _static_ data send in this packet !!! +void WorldSession::HandleCreatureQueryOpcode(WorldPacket & recv_data) +{ + uint32 entry; + recv_data >> entry; + uint64 guid; + recv_data >> guid; + + CreatureInfo const *ci = objmgr.GetCreatureTemplate(entry); + if (ci) + { + + std::string Name, SubName; + Name = ci->Name; + SubName = ci->SubName; + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + CreatureLocale const *cl = objmgr.GetCreatureLocale(entry); + if (cl) + { + if (cl->Name.size() > size_t(loc_idx) && !cl->Name[loc_idx].empty()) + Name = cl->Name[loc_idx]; + if (cl->SubName.size() > size_t(loc_idx) && !cl->SubName[loc_idx].empty()) + SubName = cl->SubName[loc_idx]; + } + } + sLog.outDetail("WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u.", ci->Name, entry); + // guess size + WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 100); + data << uint32(entry); // creature entry + data << Name; + data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4, always empty + data << SubName; + data << ci->IconName; // "Directions" for guard, string for Icons 2.3.0 + data << uint32(ci->type_flags); // flags + data << uint32(ci->type); // CreatureType.dbc + data << uint32(ci->family); // CreatureFamily.dbc + data << uint32(ci->rank); // Creature Rank (elite, boss, etc) + data << uint32(ci->KillCredit[0]); // new in 3.1, kill credit + data << uint32(ci->KillCredit[1]); // new in 3.1, kill credit + data << uint32(ci->Modelid1); // Modelid1 + data << uint32(ci->Modelid2); // Modelid2 + data << uint32(ci->Modelid3); // Modelid3 + data << uint32(ci->Modelid4); // Modelid4 + data << float(ci->ModHealth); // dmg/hp modifier + data << float(ci->ModMana); // dmg/mana modifier + data << uint8(ci->RacialLeader); + for (uint32 i = 0; i < 6; ++i) + data << uint32(ci->questItems[i]); // itemId[6], quest drop + data << uint32(ci->movementId); // CreatureMovementInfo.dbc + SendPacket(&data); + sLog.outDebug("WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE"); + } + else + { + sLog.outDebug("WORLD: CMSG_CREATURE_QUERY - NO CREATURE INFO! (GUID: %u, ENTRY: %u)", + GUID_LOPART(guid), entry); + WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 4); + data << uint32(entry | 0x80000000); + SendPacket(&data); + sLog.outDebug("WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE"); + } +} + +/// Only _static_ data send in this packet !!! +void WorldSession::HandleGameObjectQueryOpcode(WorldPacket & recv_data) +{ + uint32 entryID; + recv_data >> entryID; + uint64 guid; + recv_data >> guid; + + const GameObjectInfo *info = objmgr.GetGameObjectInfo(entryID); + if (info) + { + std::string Name; + std::string IconName; + std::string CastBarCaption; + + Name = info->name; + IconName = info->IconName; + CastBarCaption = info->castBarCaption; + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + GameObjectLocale const *gl = objmgr.GetGameObjectLocale(entryID); + if (gl) + { + if (gl->Name.size() > size_t(loc_idx) && !gl->Name[loc_idx].empty()) + Name = gl->Name[loc_idx]; + if (gl->CastBarCaption.size() > size_t(loc_idx) && !gl->CastBarCaption[loc_idx].empty()) + CastBarCaption = gl->CastBarCaption[loc_idx]; + } + } + sLog.outDetail("WORLD: CMSG_GAMEOBJECT_QUERY '%s' - Entry: %u. ", info->name, entryID); + WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 150); + data << uint32(entryID); + data << uint32(info->type); + data << uint32(info->displayId); + data << Name; + data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4 + data << IconName; // 2.0.3, string. Icon name to use instead of default icon for go's (ex: "Attack" makes sword) + data << CastBarCaption; // 2.0.3, string. Text will appear in Cast Bar when using GO (ex: "Collecting") + data << info->unk1; // 2.0.3, string + data.append(info->raw.data, 24); + data << float(info->size); // go size + for (uint32 i = 0; i < 6; ++i) + data << uint32(info->questItems[i]); // itemId[6], quest drop + SendPacket(&data); + sLog.outDebug("WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE"); + } + else + { + sLog.outDebug("WORLD: CMSG_GAMEOBJECT_QUERY - Missing gameobject info for (GUID: %u, ENTRY: %u)", + GUID_LOPART(guid), entryID); + WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 4); + data << uint32(entryID | 0x80000000); + SendPacket(&data); + sLog.outDebug("WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE"); + } +} + +void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recv_data*/) +{ + sLog.outDetail("WORLD: Received MSG_CORPSE_QUERY"); + + Corpse *corpse = GetPlayer()->GetCorpse(); + + if (!corpse) + { + WorldPacket data(MSG_CORPSE_QUERY, 1); + data << uint8(0); // corpse not found + SendPacket(&data); + return; + } + + uint32 mapid = corpse->GetMapId(); + float x = corpse->GetPositionX(); + float y = corpse->GetPositionY(); + float z = corpse->GetPositionZ(); + uint32 corpsemapid = mapid; + + // if corpse at different map + if (mapid != _player->GetMapId()) + { + // search entrance map for proper show entrance + if (MapEntry const* corpseMapEntry = sMapStore.LookupEntry(mapid)) + { + if (corpseMapEntry->IsDungeon() && corpseMapEntry->entrance_map >= 0) + { + // if corpse map have entrance + if (Map const* entranceMap = MapManager::Instance().CreateBaseMap(corpseMapEntry->entrance_map)) + { + mapid = corpseMapEntry->entrance_map; + x = corpseMapEntry->entrance_x; + y = corpseMapEntry->entrance_y; + z = entranceMap->GetHeight(x, y, MAX_HEIGHT); + } + } + } + } + + WorldPacket data(MSG_CORPSE_QUERY, 1+(6*4)); + data << uint8(1); // corpse found + data << int32(mapid); + data << float(x); + data << float(y); + data << float(z); + data << int32(corpsemapid); + data << uint32(0); // unknown + SendPacket(&data); +} + +void WorldSession::HandleNpcTextQueryOpcode(WorldPacket & recv_data) +{ + uint32 textID; + uint64 guid; + + recv_data >> textID; + sLog.outDetail("WORLD: CMSG_NPC_TEXT_QUERY ID '%u'", textID); + + recv_data >> guid; + GetPlayer()->SetUInt64Value(UNIT_FIELD_TARGET, guid); + + GossipText const* pGossip = objmgr.GetGossipText(textID); + + WorldPacket data(SMSG_NPC_TEXT_UPDATE, 100); // guess size + data << textID; + + if (!pGossip) + { + for (uint32 i = 0; i < 8; ++i) + { + data << float(0); + data << "Greetings $N"; + data << "Greetings $N"; + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + } + } + else + { + std::string Text_0[8], Text_1[8]; + for (int i = 0; i < 8; ++i) + { + Text_0[i]=pGossip->Options[i].Text_0; + Text_1[i]=pGossip->Options[i].Text_1; + } + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textID); + if (nl) + { + for (int i = 0; i < 8; ++i) + { + if (nl->Text_0[i].size() > size_t(loc_idx) && !nl->Text_0[i][loc_idx].empty()) + Text_0[i]=nl->Text_0[i][loc_idx]; + if (nl->Text_1[i].size() > size_t(loc_idx) && !nl->Text_1[i][loc_idx].empty()) + Text_1[i]=nl->Text_1[i][loc_idx]; + } + } + } + + for (int i = 0; i < 8; ++i) + { + data << pGossip->Options[i].Probability; + + if (Text_0[i].empty()) + data << Text_1[i]; + else + data << Text_0[i]; + + if (Text_1[i].empty()) + data << Text_0[i]; + else + data << Text_1[i]; + + data << pGossip->Options[i].Language; + + for (int j = 0; j < 3; ++j) + { + data << pGossip->Options[i].Emotes[j]._Delay; + data << pGossip->Options[i].Emotes[j]._Emote; + } + } + } + + SendPacket(&data); + + sLog.outDebug("WORLD: Sent SMSG_NPC_TEXT_UPDATE"); +} + +void WorldSession::HandlePageTextQueryOpcode(WorldPacket & recv_data) +{ + sLog.outDetail("WORLD: Received CMSG_PAGE_TEXT_QUERY"); + recv_data.hexlike(); + + uint32 pageID; + recv_data >> pageID; + recv_data.read_skip(); // guid + + while (pageID) + { + PageText const *pPage = sPageTextStore.LookupEntry(pageID); + // guess size + WorldPacket data(SMSG_PAGE_TEXT_QUERY_RESPONSE, 50); + data << pageID; + + if (!pPage) + { + data << "Item page missing."; + data << uint32(0); + pageID = 0; + } + else + { + std::string Text = pPage->Text; + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + PageTextLocale const *pl = objmgr.GetPageTextLocale(pageID); + if (pl) + { + if (pl->Text.size() > size_t(loc_idx) && !pl->Text[loc_idx].empty()) + Text = pl->Text[loc_idx]; + } + } + + data << Text; + data << uint32(pPage->Next_Page); + pageID = pPage->Next_Page; + } + SendPacket(&data); + + sLog.outDebug("WORLD: Sent SMSG_PAGE_TEXT_QUERY_RESPONSE"); + } +} + +void WorldSession::HandleCorpseMapPositionQuery(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Recv CMSG_CORPSE_MAP_POSITION_QUERY"); + + uint32 unk; + recv_data >> unk; + + WorldPacket data(SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE, 4+4+4+4); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + SendPacket(&data); +} + +void WorldSession::HandleQuestPOIQuery(WorldPacket& recv_data) +{ + uint32 count; + recv_data >> count; // quest count, max=25 + + if (count >= MAX_QUEST_LOG_SIZE) + return; + + WorldPacket data(SMSG_QUEST_POI_QUERY_RESPONSE, 4+(4+4)*count); + data << uint32(count); // count + + for (int i = 0; i < count; ++i) + { + uint32 questId; + recv_data >> questId; // quest id + + bool questOk = false; + + uint16 questSlot = _player->FindQuestSlot(questId); + + if (questSlot != MAX_QUEST_LOG_SIZE) + questOk =_player->GetQuestSlotQuestId(questSlot) == questId; + + if (questOk) + { + QuestPOIVector const *POI = objmgr.GetQuestPOIVector(questId); + + if (POI) + { + data << uint32(questId); // quest ID + data << uint32(POI->size()); // POI count + + for (QuestPOIVector::const_iterator itr = POI->begin(); itr != POI->end(); ++itr) + { + data << uint32(itr->Id); // POI index + data << int32(itr->ObjectiveIndex); // objective index + data << uint32(itr->MapId); // mapid + data << uint32(itr->AreaId); // areaid + data << uint32(itr->Unk2); // unknown + data << uint32(itr->Unk3); // unknown + data << uint32(itr->Unk4); // unknown + data << uint32(itr->points.size()); // POI points count + + for (std::vector::const_iterator itr2 = itr->points.begin(); itr2 != itr->points.end(); ++itr2) + { + data << int32(itr2->x); // POI point x + data << int32(itr2->y); // POI point y + } + } + } + else + { + data << uint32(questId); // quest ID + data << uint32(0); // POI count + } + } + else + { + data << uint32(questId); // quest ID + data << uint32(0); // POI count + } + } + + SendPacket(&data); +} \ No newline at end of file diff --git a/src/server/game/Server/Protocol/Handlers/QuestHandler.cpp b/src/server/game/Server/Protocol/Handlers/QuestHandler.cpp new file mode 100644 index 00000000000..8043f5ed149 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/QuestHandler.cpp @@ -0,0 +1,721 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Log.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "World.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "GossipDef.h" +#include "QuestDef.h" +#include "ObjectAccessor.h" +#include "Group.h" +#include "BattleGround.h" +#include "BattleGroundAV.h" +#include "ScriptMgr.h" + +void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + uint8 questStatus = DIALOG_STATUS_NONE; + uint8 defstatus = DIALOG_STATUS_NONE; + + Object* questgiver = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); + if (!questgiver) + { + sLog.outDetail("Error in CMSG_QUESTGIVER_STATUS_QUERY, called for not found questgiver (Typeid: %u GUID: %u)",GuidHigh2TypeId(GUID_HIPART(guid)),GUID_LOPART(guid)); + return; + } + + switch(questgiver->GetTypeId()) + { + case TYPEID_UNIT: + { + sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for npc, guid = %u",uint32(GUID_LOPART(guid))); + Creature* cr_questgiver=questgiver->ToCreature(); + if (!cr_questgiver->IsHostileTo(_player)) // not show quest status to enemies + { + questStatus = sScriptMgr.NPCDialogStatus(_player, cr_questgiver); + if (questStatus > 6) + questStatus = getDialogStatus(_player, cr_questgiver, defstatus); + } + break; + } + case TYPEID_GAMEOBJECT: + { + sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for GameObject guid = %u",uint32(GUID_LOPART(guid))); + GameObject* go_questgiver=(GameObject*)questgiver; + questStatus = sScriptMgr.GODialogStatus(_player, go_questgiver); + if (questStatus > 6) + questStatus = getDialogStatus(_player, go_questgiver, defstatus); + break; + } + default: + sLog.outError("QuestGiver called for unexpected type %u", questgiver->GetTypeId()); + break; + } + + //inform client about status of quest + _player->PlayerTalkClass->SendQuestGiverStatus(questStatus, guid); +} + +void WorldSession::HandleQuestgiverHelloOpcode(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + + sLog.outDebug ("WORLD: Received CMSG_QUESTGIVER_HELLO npc = %u", GUID_LOPART(guid)); + + Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_NONE); + if (!pCreature) + { + sLog.outDebug ("WORLD: HandleQuestgiverHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", + GUID_LOPART(guid)); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + // Stop the npc if moving + pCreature->StopMoving(); + + if (sScriptMgr.GossipHello(_player, pCreature)) + return; + + _player->PrepareGossipMenu(pCreature, pCreature->GetCreatureInfo()->GossipMenuId, true); + _player->SendPreparedGossip(pCreature); +} + +void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPacket & recv_data) +{ + uint64 guid; + uint32 quest; + uint32 unk1; + recv_data >> guid >> quest >> unk1; + + if (!GetPlayer()->isAlive()) + return; + + sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_ACCEPT_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), quest, unk1); + + Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT|TYPEMASK_ITEM|TYPEMASK_PLAYER); + + // no or incorrect quest giver + if (!pObject + || (pObject->GetTypeId() != TYPEID_PLAYER && !pObject->hasQuest(quest)) + || (pObject->GetTypeId() == TYPEID_PLAYER && !pObject->ToPlayer()->CanShareQuest(quest)) +) + { + _player->PlayerTalkClass->CloseGossip(); + _player->SetDivider(0); + return; + } + + Quest const* qInfo = objmgr.GetQuestTemplate(quest); + if (qInfo) + { + // prevent cheating + if (!GetPlayer()->CanTakeQuest(qInfo,true)) + { + _player->PlayerTalkClass->CloseGossip(); + _player->SetDivider(0); + return; + } + + if (_player->GetDivider() != 0) + { + Player *pPlayer = ObjectAccessor::FindPlayer(_player->GetDivider()); + if (pPlayer) + { + pPlayer->SendPushToPartyResponse(_player, QUEST_PARTY_MSG_ACCEPT_QUEST); + _player->SetDivider(0); + } + } + + if (_player->CanAddQuest(qInfo, true)) + { + _player->AddQuest(qInfo, pObject); + + if (qInfo->HasFlag(QUEST_FLAGS_PARTY_ACCEPT)) + { + if (Group* pGroup = _player->GetGroup()) + { + for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* pPlayer = itr->getSource(); + + if (!pPlayer || pPlayer == _player) // not self + continue; + + if (pPlayer->CanTakeQuest(qInfo, true)) + { + pPlayer->SetDivider(_player->GetGUID()); + + //need confirmation that any gossip window will close + pPlayer->PlayerTalkClass->CloseGossip(); + + _player->SendQuestConfirmAccept(qInfo, pPlayer); + } + } + } + } + + if (_player->CanCompleteQuest(quest)) + _player->CompleteQuest(quest); + + switch(pObject->GetTypeId()) + { + case TYPEID_UNIT: + sScriptMgr.QuestAccept(_player, (pObject->ToCreature()), qInfo); + break; + case TYPEID_ITEM: + case TYPEID_CONTAINER: + { + sScriptMgr.ItemQuestAccept(_player, ((Item*)pObject), qInfo); + + // destroy not required for quest finish quest starting item + bool destroyItem = true; + for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) + { + if ((qInfo->ReqItemId[i] == ((Item*)pObject)->GetEntry()) && (((Item*)pObject)->GetProto()->MaxCount > 0)) + { + destroyItem = false; + break; + } + } + + if (destroyItem) + _player->DestroyItem(((Item*)pObject)->GetBagSlot(),((Item*)pObject)->GetSlot(),true); + + break; + } + case TYPEID_GAMEOBJECT: + sScriptMgr.GOQuestAccept(_player, ((GameObject*)pObject), qInfo); + break; + } + _player->PlayerTalkClass->CloseGossip(); + + if (qInfo->GetSrcSpell() > 0) + _player->CastSpell(_player, qInfo->GetSrcSpell(), true); + + return; + } + } + + _player->PlayerTalkClass->CloseGossip(); +} + +void WorldSession::HandleQuestgiverQueryQuestOpcode(WorldPacket & recv_data) +{ + uint64 guid; + uint32 quest; + uint8 unk1; + recv_data >> guid >> quest >> unk1; + sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_QUERY_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), quest, unk1); + + // Verify that the guid is valid and is a questgiver or involved in the requested quest + Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT|TYPEMASK_ITEM); + if (!pObject||!pObject->hasQuest(quest) && !pObject->hasInvolvedQuest(quest)) + { + _player->PlayerTalkClass->CloseGossip(); + return; + } + + Quest const* pQuest = objmgr.GetQuestTemplate(quest); + if (pQuest) + { + if (pQuest->HasFlag(QUEST_FLAGS_AUTO_ACCEPT) && _player->CanAddQuest(pQuest, true)) + { + _player->AddQuest(pQuest, pObject); + if (_player->CanCompleteQuest(quest)) + _player->CompleteQuest(quest); + } + + if (pQuest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)) + _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, pObject->GetGUID(), _player->CanCompleteQuest(pQuest->GetQuestId()), true); + else + _player->PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, pObject->GetGUID(), true); + } +} + +void WorldSession::HandleQuestQueryOpcode(WorldPacket & recv_data) +{ + uint32 quest; + recv_data >> quest; + sLog.outDebug("WORLD: Received CMSG_QUEST_QUERY quest = %u",quest); + + Quest const *pQuest = objmgr.GetQuestTemplate(quest); + if (pQuest) + { + _player->PlayerTalkClass->SendQuestQueryResponse(pQuest); + } +} + +void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket & recv_data) +{ + uint32 quest, reward; + uint64 guid; + recv_data >> guid >> quest >> reward; + + if (reward >= QUEST_REWARD_CHOICES_COUNT) + { + sLog.outError("Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player %s (guid %d) tried to get invalid reward (%u) (probably packet hacking)", _player->GetName(), _player->GetGUIDLow(), reward); + return; + } + + if (!GetPlayer()->isAlive()) + return; + + sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_CHOOSE_REWARD npc = %u, quest = %u, reward = %u",uint32(GUID_LOPART(guid)),quest,reward); + + Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); + if (!pObject) + return; + + if (!pObject->hasInvolvedQuest(quest)) + return; + + Quest const *pQuest = objmgr.GetQuestTemplate(quest); + if (pQuest) + { + if (_player->CanRewardQuest(pQuest, reward, true)) + { + _player->RewardQuest(pQuest, reward, pObject); + + switch(pObject->GetTypeId()) + { + case TYPEID_UNIT: + if (!(sScriptMgr.ChooseReward(_player, (pObject->ToCreature()), pQuest, reward))) + { + // Send next quest + if (Quest const* nextquest = _player->GetNextQuest(guid ,pQuest)) + _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextquest,guid,true); + } + break; + case TYPEID_GAMEOBJECT: + if (!sScriptMgr.GOChooseReward(_player, ((GameObject*)pObject), pQuest, reward)) + { + // Send next quest + if (Quest const* nextquest = _player->GetNextQuest(guid ,pQuest)) + _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextquest,guid,true); + } + break; + } + } + else + _player->PlayerTalkClass->SendQuestGiverOfferReward(pQuest, guid, true); + } +} + +void WorldSession::HandleQuestgiverRequestRewardOpcode(WorldPacket & recv_data) +{ + uint32 quest; + uint64 guid; + recv_data >> guid >> quest; + + if (!GetPlayer()->isAlive()) + return; + + sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_REQUEST_REWARD npc = %u, quest = %u",uint32(GUID_LOPART(guid)),quest); + + Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); + if (!pObject||!pObject->hasInvolvedQuest(quest)) + return; + + if (_player->CanCompleteQuest(quest)) + _player->CompleteQuest(quest); + + if (_player->GetQuestStatus(quest) != QUEST_STATUS_COMPLETE) + return; + + if (Quest const *pQuest = objmgr.GetQuestTemplate(quest)) + _player->PlayerTalkClass->SendQuestGiverOfferReward(pQuest, guid, true); +} + +void WorldSession::HandleQuestgiverCancel(WorldPacket& /*recv_data*/) +{ + sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_CANCEL"); + + _player->PlayerTalkClass->CloseGossip(); +} + +void WorldSession::HandleQuestLogSwapQuest(WorldPacket& recv_data) +{ + uint8 slot1, slot2; + recv_data >> slot1 >> slot2; + + if (slot1 == slot2 || slot1 >= MAX_QUEST_LOG_SIZE || slot2 >= MAX_QUEST_LOG_SIZE) + return; + + sLog.outDebug("WORLD: Received CMSG_QUESTLOG_SWAP_QUEST slot 1 = %u, slot 2 = %u", slot1, slot2); + + GetPlayer()->SwapQuestSlot(slot1,slot2); +} + +void WorldSession::HandleQuestLogRemoveQuest(WorldPacket& recv_data) +{ + uint8 slot; + recv_data >> slot; + + sLog.outDebug("WORLD: Received CMSG_QUESTLOG_REMOVE_QUEST slot = %u",slot); + + if (slot < MAX_QUEST_LOG_SIZE) + { + if (uint32 quest = _player->GetQuestSlotQuestId(slot)) + { + if (!_player->TakeQuestSourceItem(quest, true)) + return; // can't un-equip some items, reject quest cancel + + if (const Quest *pQuest = objmgr.GetQuestTemplate(quest)) + { + if (pQuest->HasFlag(QUEST_TRINITY_FLAGS_TIMED)) + _player->RemoveTimedQuest(quest); + } + + _player->TakeQuestSourceItem(quest, true); // remove quest src item from player + _player->SetQuestStatus(quest, QUEST_STATUS_NONE); + _player->GetAchievementMgr().RemoveTimedAchievement(ACHIEVEMENT_TIMED_TYPE_QUEST, quest); + } + + _player->SetQuestSlot(slot, 0); + + _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED, 1); + } +} + +void WorldSession::HandleQuestConfirmAccept(WorldPacket& recv_data) +{ + uint32 quest; + recv_data >> quest; + + sLog.outDebug("WORLD: Received CMSG_QUEST_CONFIRM_ACCEPT quest = %u", quest); + + if (const Quest* pQuest = objmgr.GetQuestTemplate(quest)) + { + if (!pQuest->HasFlag(QUEST_FLAGS_PARTY_ACCEPT)) + return; + + Player* pOriginalPlayer = ObjectAccessor::FindPlayer(_player->GetDivider()); + + if (!pOriginalPlayer) + return; + + if (pQuest->GetType() == QUEST_TYPE_RAID) + { + if (!_player->IsInSameRaidWith(pOriginalPlayer)) + return; + } + else + { + if (!_player->IsInSameGroupWith(pOriginalPlayer)) + return; + } + + if (_player->CanAddQuest(pQuest, true)) + _player->AddQuest(pQuest, NULL); // NULL, this prevent DB script from duplicate running + + _player->SetDivider(0); + } +} + +void WorldSession::HandleQuestgiverCompleteQuest(WorldPacket& recv_data) +{ + uint32 quest; + uint64 guid; + recv_data >> guid >> quest; + + if (!GetPlayer()->isAlive()) + return; + + sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %u, quest = %u",uint32(GUID_LOPART(guid)),quest); + + Quest const *pQuest = objmgr.GetQuestTemplate(quest); + if (pQuest) + { + // TODO: need a virtual function + if (GetPlayer()->InBattleGround()) + if (BattleGround* bg = GetPlayer()->GetBattleGround()) + if (bg->GetTypeID() == BATTLEGROUND_AV) + ((BattleGroundAV*)bg)->HandleQuestComplete(quest, GetPlayer()); + + if (_player->GetQuestStatus(quest) != QUEST_STATUS_COMPLETE) + { + if (pQuest->IsRepeatable()) + _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanCompleteRepeatableQuest(pQuest), false); + else + _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanRewardQuest(pQuest,false), false); + } + else + { + if (pQuest->GetReqItemsCount()) // some items required + _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanRewardQuest(pQuest,false), false); + else // no items required + _player->PlayerTalkClass->SendQuestGiverOfferReward(pQuest, guid, true); + } + } +} + +void WorldSession::HandleQuestgiverQuestAutoLaunch(WorldPacket& /*recvPacket*/) +{ + sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_QUEST_AUTOLAUNCH"); +} + +void WorldSession::HandlePushQuestToParty(WorldPacket& recvPacket) +{ + uint32 questId; + recvPacket >> questId; + + sLog.outDebug("WORLD: Received CMSG_PUSHQUESTTOPARTY quest = %u", questId); + + if (Quest const *pQuest = objmgr.GetQuestTemplate(questId)) + { + if (Group* pGroup = _player->GetGroup()) + { + for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player *pPlayer = itr->getSource(); + + if (!pPlayer || pPlayer == _player) // skip self + continue; + + _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_SHARING_QUEST); + + if (!pPlayer->SatisfyQuestStatus(pQuest, false)) + { + _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_HAVE_QUEST); + continue; + } + + if (pPlayer->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE) + { + _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_FINISH_QUEST); + continue; + } + + if (!pPlayer->CanTakeQuest(pQuest, false)) + { + _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_CANT_TAKE_QUEST); + continue; + } + + if (!pPlayer->SatisfyQuestLog(false)) + { + _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_LOG_FULL); + continue; + } + + if (pPlayer->GetDivider() != 0) + { + _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_BUSY); + continue; + } + + pPlayer->PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, _player->GetGUID(), true); + pPlayer->SetDivider(_player->GetGUID()); + } + } + } +} + +void WorldSession::HandleQuestPushResult(WorldPacket& recvPacket) +{ + uint64 guid; + uint8 msg; + recvPacket >> guid >> msg; + + sLog.outDebug("WORLD: Received MSG_QUEST_PUSH_RESULT"); + + if (_player->GetDivider() != 0) + { + Player *pPlayer = ObjectAccessor::FindPlayer(_player->GetDivider()); + if (pPlayer) + { + WorldPacket data(MSG_QUEST_PUSH_RESULT, (8+1)); + data << uint64(guid); + data << uint8(msg); // valid values: 0-8 + pPlayer->GetSession()->SendPacket(&data); + _player->SetDivider(0); + } + } +} + +uint32 WorldSession::getDialogStatus(Player *pPlayer, Object* questgiver, uint32 defstatus) +{ + uint32 result = defstatus; + + QuestRelations const* qir; + QuestRelations const* qr; + + switch(questgiver->GetTypeId()) + { + case TYPEID_GAMEOBJECT: + { + qir = &objmgr.mGOQuestInvolvedRelations; + qr = &objmgr.mGOQuestRelations; + break; + } + case TYPEID_UNIT: + { + qir = &objmgr.mCreatureQuestInvolvedRelations; + qr = &objmgr.mCreatureQuestRelations; + break; + } + default: + //its imposible, but check ^) + sLog.outError("Warning: GetDialogStatus called for unexpected type %u", questgiver->GetTypeId()); + return DIALOG_STATUS_NONE; + } + + for (QuestRelations::const_iterator i = qir->lower_bound(questgiver->GetEntry()); i != qir->upper_bound(questgiver->GetEntry()); ++i) + { + uint32 result2 = 0; + uint32 quest_id = i->second; + Quest const *pQuest = objmgr.GetQuestTemplate(quest_id); + if (!pQuest) continue; + + QuestStatus status = pPlayer->GetQuestStatus(quest_id); + if ((status == QUEST_STATUS_COMPLETE && !pPlayer->GetQuestRewardStatus(quest_id)) || + (pQuest->IsAutoComplete() && pPlayer->CanTakeQuest(pQuest, false))) + { + if (pQuest->IsAutoComplete() && pQuest->IsRepeatable()) + result2 = DIALOG_STATUS_REWARD_REP; + else + result2 = DIALOG_STATUS_REWARD; + } + else if (status == QUEST_STATUS_INCOMPLETE) + result2 = DIALOG_STATUS_INCOMPLETE; + + if (result2 > result) + result = result2; + } + + for (QuestRelations::const_iterator i = qr->lower_bound(questgiver->GetEntry()); i != qr->upper_bound(questgiver->GetEntry()); ++i) + { + uint32 result2 = 0; + uint32 quest_id = i->second; + Quest const *pQuest = objmgr.GetQuestTemplate(quest_id); + if (!pQuest) + continue; + + QuestStatus status = pPlayer->GetQuestStatus(quest_id); + if (status == QUEST_STATUS_NONE) + { + if (pPlayer->CanSeeStartQuest(pQuest)) + { + if (pPlayer->SatisfyQuestLevel(pQuest, false)) + { + if (pQuest->IsAutoComplete() || (pQuest->IsRepeatable() && pPlayer->getQuestStatusMap()[quest_id].m_rewarded)) + result2 = DIALOG_STATUS_REWARD_REP; + else if (pPlayer->getLevel() <= ((pPlayer->GetQuestLevel(pQuest) == -1) ? pPlayer->getLevel() : pPlayer->GetQuestLevel(pQuest) + sWorld.getConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF))) + { + if (pQuest->HasFlag(QUEST_FLAGS_DAILY) || pQuest->HasFlag(QUEST_FLAGS_WEEKLY)) + result2 = DIALOG_STATUS_AVAILABLE_REP; + else + result2 = DIALOG_STATUS_AVAILABLE; + } + else + result2 = DIALOG_STATUS_LOW_LEVEL_AVAILABLE; + } + else + result2 = DIALOG_STATUS_UNAVAILABLE; + } + } + + if (result2 > result) + result = result2; + } + + return result; +} + +void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket*/) +{ + sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY"); + + uint32 count = 0; + + WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4); + data << uint32(count); // placeholder + + for (Player::ClientGUIDs::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr) + { + uint8 questStatus = DIALOG_STATUS_NONE; + uint8 defstatus = DIALOG_STATUS_NONE; + + if (IS_CRE_OR_VEH_OR_PET_GUID(*itr)) + { + // need also pet quests case support + Creature *questgiver = ObjectAccessor::GetCreatureOrPetOrVehicle(*GetPlayer(),*itr); + if (!questgiver || questgiver->IsHostileTo(_player)) + continue; + if (!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) + continue; + questStatus = sScriptMgr.NPCDialogStatus(_player, questgiver); + if (questStatus > 6) + questStatus = getDialogStatus(_player, questgiver, defstatus); + + data << uint64(questgiver->GetGUID()); + data << uint8(questStatus); + ++count; + } + else if (IS_GAMEOBJECT_GUID(*itr)) + { + GameObject *questgiver = GetPlayer()->GetMap()->GetGameObject(*itr); + if (!questgiver) + continue; + if (questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER) + continue; + questStatus = sScriptMgr.GODialogStatus(_player, questgiver); + if (questStatus > 6) + questStatus = getDialogStatus(_player, questgiver, defstatus); + + data << uint64(questgiver->GetGUID()); + data << uint8(questStatus); + ++count; + } + } + + data.put(0, count); // write real count + SendPacket(&data); +} + +void WorldSession::HandleQueryQuestsCompleted(WorldPacket & /*recv_data*/) +{ + uint32 count = 0; + + WorldPacket data(SMSG_QUERY_QUESTS_COMPLETED_RESPONSE, 4+4*count); + data << uint32(count); + + for (QuestStatusMap::const_iterator itr = _player->getQuestStatusMap().begin(); itr != _player->getQuestStatusMap().end(); ++itr) + { + if (itr->second.m_rewarded) + { + data << uint32(itr->first); + count++; + } + } + data.put(0, count); + SendPacket(&data); +} diff --git a/src/server/game/Server/Protocol/Handlers/SkillHandler.cpp b/src/server/game/Server/Protocol/Handlers/SkillHandler.cpp new file mode 100644 index 00000000000..312065f9f13 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/SkillHandler.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "Opcodes.h" +#include "Log.h" +#include "Player.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "ObjectAccessor.h" +#include "UpdateMask.h" + +void WorldSession::HandleLearnTalentOpcode(WorldPacket & recv_data) +{ + uint32 talent_id, requested_rank; + recv_data >> talent_id >> requested_rank; + + _player->LearnTalent(talent_id, requested_rank); + _player->SendTalentsInfoData(false); +} + +void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket) +{ + sLog.outDebug("CMSG_LEARN_PREVIEW_TALENTS"); + + uint32 talentsCount; + recvPacket >> talentsCount; + + uint32 talentId, talentRank; + + for (uint32 i = 0; i < talentsCount; ++i) + { + recvPacket >> talentId >> talentRank; + + _player->LearnTalent(talentId, talentRank); + } + + _player->SendTalentsInfoData(false); +} + +void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket & recv_data) +{ + sLog.outDetail("MSG_TALENT_WIPE_CONFIRM"); + uint64 guid; + recv_data >> guid; + + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TRAINER); + if (!unit) + { + sLog.outDebug("WORLD: HandleTalentWipeConfirmOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + if (!(_player->resetTalents())) + { + WorldPacket data(MSG_TALENT_WIPE_CONFIRM, 8+4); //you have not any talent + data << uint64(0); + data << uint32(0); + SendPacket(&data); + return; + } + + _player->SendTalentsInfoData(false); + unit->CastSpell(_player, 14867, true); //spell: "Untalent Visual Effect" +} + +void WorldSession::HandleUnlearnSkillOpcode(WorldPacket & recv_data) +{ + uint32 skill_id; + recv_data >> skill_id; + GetPlayer()->SetSkill(skill_id, 0, 0, 0); +} + diff --git a/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp b/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp new file mode 100644 index 00000000000..b8a4a127824 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp @@ -0,0 +1,649 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "DBCStores.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "Log.h" +#include "Opcodes.h" +#include "Spell.h" +#include "Totem.h" +#include "TemporarySummon.h" +#include "SpellAuras.h" +#include "CreatureAI.h" +#include "ScriptMgr.h" + +void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) +{ + // TODO: add targets.read() check + Player* pUser = _player; + + // ignore for remote control state + if (pUser->m_mover != pUser) + return; + + uint8 bagIndex, slot; + uint8 unk_flags; // flags (if 0x02 - some additional data are received) + uint8 cast_count; // next cast if exists (single or not) + uint64 item_guid; + uint32 glyphIndex; // something to do with glyphs? + uint32 spellid; // casted spell id + + recvPacket >> bagIndex >> slot >> cast_count >> spellid >> item_guid >> glyphIndex >> unk_flags; + + if (glyphIndex >= MAX_GLYPH_SLOT_INDEX) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + Item *pItem = pUser->GetUseableItemByPos(bagIndex, slot); + if (!pItem) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + if (pItem->GetGUID() != item_guid) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + sLog.outDetail("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, cast_count: %u, spellid: %u, Item: %u, glyphIndex: %u, unk_flags: %u, data length = %i", bagIndex, slot, cast_count, spellid, pItem->GetEntry(), glyphIndex, unk_flags, (uint32)recvPacket.size()); + + ItemPrototype const *proto = pItem->GetProto(); + if (!proto) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); + return; + } + + // some item classes can be used only in equipped state + if (proto->InventoryType != INVTYPE_NON_EQUIP && !pItem->IsEquipped()) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); + return; + } + + uint8 msg = pUser->CanUseItem(pItem); + if (msg != EQUIP_ERR_OK) + { + pUser->SendEquipError(msg, pItem, NULL); + return; + } + + // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB) + if (proto->Class == ITEM_CLASS_CONSUMABLE && !(proto->Flags & ITEM_FLAGS_USEABLE_IN_ARENA) && pUser->InArena()) + { + pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH,pItem,NULL); + return; + } + + if (pUser->isInCombat()) + { + for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) + { + if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId)) + { + if (IsNonCombatSpell(spellInfo)) + { + pUser->SendEquipError(EQUIP_ERR_NOT_IN_COMBAT,pItem,NULL); + return; + } + } + } + } + + // check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory) + if (pItem->GetProto()->Bonding == BIND_WHEN_USE || pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetProto()->Bonding == BIND_QUEST_ITEM) + { + if (!pItem->IsSoulBound()) + { + pItem->SetState(ITEM_CHANGED, pUser); + pItem->SetBinding(true); + } + } + + SpellCastTargets targets; + if (!targets.read(&recvPacket, pUser)) + return; + + targets.Update(pUser); + + if (!pItem->IsTargetValidForItemUse(targets.getUnitTarget())) + { + // free gray item after use fail + pUser->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); + + // send spell error + if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid)) + { + // for implicit area/coord target spells + if (!targets.getUnitTarget()) + Spell::SendCastResult(_player,spellInfo,cast_count,SPELL_FAILED_NO_VALID_TARGETS); + // for explicit target spells + else + Spell::SendCastResult(_player,spellInfo,cast_count,SPELL_FAILED_BAD_TARGETS); + } + return; + } + + //Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state. + if (!sScriptMgr.ItemUse(pUser,pItem,targets)) + { + // no script or script not process request by self + pUser->CastItemUseSpell(pItem,targets,cast_count,glyphIndex); + } +} + +#define OPEN_CHEST 11437 +#define OPEN_SAFE 11535 +#define OPEN_CAGE 11792 +#define OPEN_BOOTY_CHEST 5107 +#define OPEN_STRONGBOX 8517 + +void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket) +{ + sLog.outDetail("WORLD: CMSG_OPEN_ITEM packet, data length = %i",(uint32)recvPacket.size()); + + Player* pUser = _player; + + // ignore for remote control state + if (pUser->m_mover != pUser) + return; + + uint8 bagIndex, slot; + + recvPacket >> bagIndex >> slot; + + sLog.outDetail("bagIndex: %u, slot: %u",bagIndex,slot); + + Item *pItem = pUser->GetItemByPos(bagIndex, slot); + if (!pItem) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + ItemPrototype const *proto = pItem->GetProto(); + if (!proto) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); + return; + } + + if (!pUser->GetSession()->HandleOnItemOpen(pItem)) + return; + + // locked item + uint32 lockId = proto->LockID; + if (lockId) + { + LockEntry const *lockInfo = sLockStore.LookupEntry(lockId); + + if (!lockInfo) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL); + sLog.outError("WORLD::OpenItem: item [guid = %u] has an unknown lockId: %u!", pItem->GetGUIDLow(), lockId); + return; + } + + // required picklocking + if (lockInfo->Skill[1] || lockInfo->Skill[0]) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL); + return; + } + } + + if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED))// wrapped? + { + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT entry, flags FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow()); + if (result) + { + Field *fields = result->Fetch(); + uint32 entry = fields[0].GetUInt32(); + uint32 flags = fields[1].GetUInt32(); + + pItem->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, 0); + pItem->SetEntry(entry); + pItem->SetUInt32Value(ITEM_FIELD_FLAGS, flags); + pItem->SetState(ITEM_CHANGED, pUser); + } + else + { + sLog.outError("Wrapped item %u don't have record in character_gifts table and will deleted", pItem->GetGUIDLow()); + pUser->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); + return; + } + CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow()); + } + else + pUser->SendLoot(pItem->GetGUID(),LOOT_CORPSE); +} + +void WorldSession::HandleGameObjectUseOpcode(WorldPacket & recv_data) +{ + uint64 guid; + + recv_data >> guid; + + sLog.outDebug("WORLD: Recvd CMSG_GAMEOBJ_USE Message [guid=%u]", GUID_LOPART(guid)); + + // ignore for remote control state + if (_player->m_mover != _player) + return; + + GameObject *obj = GetPlayer()->GetMap()->GetGameObject(guid); + + if (!obj) + return; + + if (sScriptMgr.GOHello(_player, obj)) + return; + + obj->Use(_player); +} + +void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket) +{ + uint64 guid; + recvPacket >> guid; + + sLog.outDebug("WORLD: Recvd CMSG_GAMEOBJ_REPORT_USE Message [in game guid: %u]", GUID_LOPART(guid)); + + // ignore for remote control state + if (_player->m_mover != _player) + return; + + GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid); + if (!go) + return; + + if (!go->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) + return; + + _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry()); +} + +void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) +{ + uint32 spellId; + uint8 cast_count, unk_flags; + recvPacket >> cast_count; + recvPacket >> spellId; + recvPacket >> unk_flags; // flags (if 0x02 - some additional data are received) + + // ignore for remote control state (for player case) + Unit* mover = _player->m_mover; + if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER) + { + recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet + return; + } + + sLog.outDebug("WORLD: got cast spell packet, spellId - %u, cast_count: %u, unk_flags %u, data length = %i", spellId, cast_count, unk_flags, (uint32)recvPacket.size()); + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); + + if (!spellInfo) + { + sLog.outError("WORLD: unknown spell id %u", spellId); + recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet + return; + } + + if (mover->GetTypeId() == TYPEID_PLAYER) + { + // not have spell in spellbook or spell passive and not casted by client + if (!mover->ToPlayer()->HasActiveSpell (spellId) || IsPassiveSpell(spellId)) + { + //cheater? kick? ban? + recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet + return; + } + } + else + { + // not have spell in spellbook or spell passive and not casted by client + if ((mover->GetTypeId() == TYPEID_UNIT && !mover->ToCreature()->HasSpell(spellId)) || IsPassiveSpell(spellId)) + { + //cheater? kick? ban? + recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet + return; + } + } + + // Client is resending autoshot cast opcode when other spell is casted during shoot rotation + // Skip it to prevent "interrupt" message + if (IsAutoRepeatRangedSpell(spellInfo) && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) + && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_spellInfo == spellInfo) + return; + + // can't use our own spells when we're in possession of another unit, + if (_player->isPossessing()) + return; + + // client provided targets + SpellCastTargets targets; + if (!targets.read(&recvPacket,mover)) + { + recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet + return; + } + + // some spell cast packet including more data (for projectiles?) + if (unk_flags & 0x02) + { + //recvPacket.read_skip(); // unk1, coords? + //recvPacket.read_skip(); // unk1, coords? + uint8 unk1; + recvPacket >> unk1; // >> 1 or 0 + if (unk1) + { + recvPacket.read_skip(); // >> MSG_MOVE_STOP + uint64 guid; // guid - unused + if (!recvPacket.readPackGUID(guid)) + return; + + MovementInfo movementInfo; + ReadMovementInfo(recvPacket, &movementInfo); + } + } + + // auto-selection buff level base at target level (in spellInfo) + if (targets.getUnitTarget()) + { + SpellEntry const *actualSpellInfo = spellmgr.SelectAuraRankForPlayerLevel(spellInfo,targets.getUnitTarget()->getLevel()); + + // if rank not found then function return NULL but in explicit cast case original spell can be casted and later failed with appropriate error message + if (actualSpellInfo) + spellInfo = actualSpellInfo; + } + + Spell *spell = new Spell(mover, spellInfo, false); + spell->m_cast_count = cast_count; // set count of casts + spell->prepare(&targets); +} + +void WorldSession::HandleCancelCastOpcode(WorldPacket& recvPacket) +{ + uint32 spellId; + + recvPacket.read_skip(); // counter, increments with every CANCEL packet, don't use for now + recvPacket >> spellId; + + if (_player->IsNonMeleeSpellCasted(false)) + _player->InterruptNonMeleeSpells(false,spellId,false); +} + +void WorldSession::HandleCancelAuraOpcode(WorldPacket& recvPacket) +{ + uint32 spellId; + recvPacket >> spellId; + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); + if (!spellInfo) + return; + + // not allow remove non positive spells and spells with attr SPELL_ATTR_CANT_CANCEL + if (!IsPositiveSpell(spellId) || (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL)) + return; + + // channeled spell case (it currently casted then) + if (IsChanneledSpell(spellInfo)) + { + if (Spell* curSpell = _player->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) + if (curSpell->m_spellInfo->Id == spellId) + _player->InterruptSpell(CURRENT_CHANNELED_SPELL); + return; + } + + // non channeled case + // maybe should only remove one buff when there are multiple? + _player->RemoveOwnedAura(spellId, 0, 0, AURA_REMOVE_BY_CANCEL); +} + +void WorldSession::HandlePetCancelAuraOpcode(WorldPacket& recvPacket) +{ + uint64 guid; + uint32 spellId; + + recvPacket >> guid; + recvPacket >> spellId; + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); + if (!spellInfo) + { + sLog.outError("WORLD: unknown PET spell id %u", spellId); + return; + } + + Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player,guid); + + if (!pet) + { + sLog.outError("Pet %u not exist.", uint32(GUID_LOPART(guid))); + return; + } + + if (pet != GetPlayer()->GetGuardianPet() && pet != GetPlayer()->GetCharm()) + { + sLog.outError("HandlePetCancelAura.Pet %u isn't pet of player %s", uint32(GUID_LOPART(guid)),GetPlayer()->GetName()); + return; + } + + if (!pet->isAlive()) + { + pet->SendPetActionFeedback(FEEDBACK_PET_DEAD); + return; + } + + pet->RemoveOwnedAura(spellId, 0, 0, AURA_REMOVE_BY_CANCEL); + + pet->AddCreatureSpellCooldown(spellId); +} + +void WorldSession::HandleCancelGrowthAuraOpcode(WorldPacket& /*recvPacket*/) +{ +} + +void WorldSession::HandleCancelAutoRepeatSpellOpcode(WorldPacket& /*recvPacket*/) +{ + // may be better send SMSG_CANCEL_AUTO_REPEAT? + // cancel and prepare for deleting + _player->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); +} + +void WorldSession::HandleCancelChanneling(WorldPacket & recv_data) +{ + recv_data.read_skip(); // spellid, not used + + // ignore for remote control state (for player case) + Unit* mover = _player->m_mover; + if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER) + return; + + mover->InterruptSpell(CURRENT_CHANNELED_SPELL); +} + +void WorldSession::HandleTotemDestroyed(WorldPacket& recvPacket) +{ + // ignore for remote control state + if (_player->m_mover != _player) + return; + + uint8 slotId; + + recvPacket >> slotId; + + ++slotId; + if (slotId >= MAX_TOTEM_SLOT) + return; + + if (!_player->m_SummonSlot[slotId]) + return; + + Creature* totem = GetPlayer()->GetMap()->GetCreature(_player->m_SummonSlot[slotId]); + // Don't unsummon sentry totem + if (totem && totem->isTotem() && totem->GetEntry() != SENTRY_TOTEM_ENTRY) + totem->ToTotem()->UnSummon(); +} + +void WorldSession::HandleSelfResOpcode(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("WORLD: CMSG_SELF_RES"); // empty opcode + + if (_player->GetUInt32Value(PLAYER_SELF_RES_SPELL)) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(_player->GetUInt32Value(PLAYER_SELF_RES_SPELL)); + if (spellInfo) + _player->CastSpell(_player,spellInfo,false,0); + + _player->SetUInt32Value(PLAYER_SELF_RES_SPELL, 0); + } +} + +void WorldSession::HandleSpellClick(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + + // this will get something not in world. crash + Creature *unit = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); + + if (!unit) + return; + + // TODO: Unit::SetCharmedBy: 28782 is not in world but 0 is trying to charm it! -> crash + if (!unit->IsInWorld()) + { + sLog.outCrash("Spell click target %u is not in world!", unit->GetEntry()); + assert(false); + return; + } + + SpellClickInfoMapBounds clickPair = objmgr.GetSpellClickInfoMapBounds(unit->GetEntry()); + for (SpellClickInfoMap::const_iterator itr = clickPair.first; itr != clickPair.second; ++itr) + { + if (itr->second.IsFitToRequirements(_player, unit)) + { + Unit *caster = (itr->second.castFlags & NPC_CLICK_CAST_CASTER_PLAYER) ? (Unit*)_player : (Unit*)unit; + Unit *target = (itr->second.castFlags & NPC_CLICK_CAST_TARGET_PLAYER) ? (Unit*)_player : (Unit*)unit; + uint64 origCasterGUID = (itr->second.castFlags & NPC_CLICK_CAST_ORIG_CASTER_OWNER) ? unit->GetOwnerGUID() : 0; + caster->CastSpell(target, itr->second.spellId, true, NULL, NULL, origCasterGUID); + } + } + + if (unit->IsVehicle()) + { + if (unit->CheckPlayerCondition(_player)) + _player->EnterVehicle(unit); + } + + unit->AI()->DoAction(EVENT_SPELLCLICK); +} + +void WorldSession::HandleMirrrorImageDataRequest(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_GET_MIRRORIMAGE_DATA"); + uint64 guid; + recv_data >> guid; + + // Get unit for which data is needed by client + Unit *unit = ObjectAccessor::GetObjectInWorld(guid, (Unit*)NULL); + if (!unit) + return; + + // Get creator of the unit + Unit *creator = ObjectAccessor::GetObjectInWorld(unit->GetCreatorGUID(),(Unit*)NULL); + if (!creator) + return; + + WorldPacket data(SMSG_MIRRORIMAGE_DATA, 68); + data << uint64(guid); + data << uint32(creator->GetDisplayId()); + if (creator->GetTypeId() == TYPEID_PLAYER) + { + Player * pCreator = creator->ToPlayer(); + data << uint8(pCreator->getRace()); + data << uint8(pCreator->getGender()); + data << uint8(pCreator->getClass()); + data << uint8(pCreator->GetByteValue(PLAYER_BYTES, 0)); // skin + data << uint8(pCreator->GetByteValue(PLAYER_BYTES, 1)); // face + data << uint8(pCreator->GetByteValue(PLAYER_BYTES, 2)); // hair + data << uint8(pCreator->GetByteValue(PLAYER_BYTES, 3)); // haircolor + data << uint8(pCreator->GetByteValue(PLAYER_BYTES_2, 0)); // facialhair + data << uint32(pCreator->GetGuildId()); // unk + + static const EquipmentSlots ItemSlots[] = + { + EQUIPMENT_SLOT_HEAD, + EQUIPMENT_SLOT_SHOULDERS, + EQUIPMENT_SLOT_BODY, + EQUIPMENT_SLOT_CHEST, + EQUIPMENT_SLOT_WAIST, + EQUIPMENT_SLOT_LEGS, + EQUIPMENT_SLOT_FEET, + EQUIPMENT_SLOT_WRISTS, + EQUIPMENT_SLOT_HANDS, + EQUIPMENT_SLOT_BACK, + EQUIPMENT_SLOT_TABARD, + EQUIPMENT_SLOT_END + }; + + // Display items in visible slots + for (EquipmentSlots const* itr = &ItemSlots[0]; *itr != EQUIPMENT_SLOT_END; ++itr) + { + if (*itr == EQUIPMENT_SLOT_HEAD && pCreator->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM)) + data << uint32(0); + else if (*itr == EQUIPMENT_SLOT_BACK && pCreator->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK)) + data << uint32(0); + else if (Item const *item = pCreator->GetItemByPos(INVENTORY_SLOT_BAG_0, *itr)) + data << uint32(item->GetProto()->DisplayInfoID); + else + data << uint32(0); + } + } + else + { + // Skip player data for creatures + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + } + + SendPacket(&data); +} diff --git a/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp b/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp new file mode 100644 index 00000000000..b0660527f71 --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "UpdateMask.h" +#include "Path.h" +#include "WaypointMovementGenerator.h" +#include "DestinationHolderImp.h" + +void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_TAXINODE_STATUS_QUERY"); + + uint64 guid; + + recv_data >> guid; + SendTaxiStatus(guid); +} + +void WorldSession::SendTaxiStatus(uint64 guid) +{ + // cheating checks + Creature *unit = GetPlayer()->GetMap()->GetCreature(guid); + if (!unit) + { + sLog.outDebug("WorldSession::SendTaxiStatus - Unit (GUID: %u) not found.", uint32(GUID_LOPART(guid))); + return; + } + + uint32 curloc = objmgr.GetNearestTaxiNode(unit->GetPositionX(),unit->GetPositionY(),unit->GetPositionZ(),unit->GetMapId(),GetPlayer()->GetTeam()); + + // not found nearest + if (curloc == 0) + return; + + sLog.outDebug("WORLD: current location %u ",curloc); + + WorldPacket data(SMSG_TAXINODE_STATUS, 9); + data << guid; + data << uint8(GetPlayer()->m_taxi.IsTaximaskNodeKnown(curloc) ? 1 : 0); + SendPacket(&data); + sLog.outDebug("WORLD: Sent SMSG_TAXINODE_STATUS"); +} + +void WorldSession::HandleTaxiQueryAvailableNodes(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_TAXIQUERYAVAILABLENODES"); + + uint64 guid; + recv_data >> guid; + + // cheating checks + Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); + if (!unit) + { + sLog.outDebug("WORLD: HandleTaxiQueryAvailableNodes - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + // unknown taxi node case + if (SendLearnNewTaxiNode(unit)) + return; + + // known taxi node case + SendTaxiMenu(unit); +} + +void WorldSession::SendTaxiMenu(Creature* unit) +{ + // find current node + uint32 curloc = objmgr.GetNearestTaxiNode(unit->GetPositionX(),unit->GetPositionY(),unit->GetPositionZ(),unit->GetMapId(),GetPlayer()->GetTeam()); + + if (curloc == 0) + return; + + bool lastTaxiCheaterState = GetPlayer()->isTaxiCheater(); + if (unit->GetEntry() == 29480) GetPlayer()->SetTaxiCheater(true); // Grimwing in Ebon Hold, special case. NOTE: Not perfect, Zul'Aman should not be included according to WoWhead, and I think taxicheat includes it. + + sLog.outDebug("WORLD: CMSG_TAXINODE_STATUS_QUERY %u ",curloc); + + WorldPacket data(SMSG_SHOWTAXINODES, (4+8+4+8*4)); + data << uint32(1); + data << uint64(unit->GetGUID()); + data << uint32(curloc); + GetPlayer()->m_taxi.AppendTaximaskTo(data,GetPlayer()->isTaxiCheater()); + SendPacket(&data); + + sLog.outDebug("WORLD: Sent SMSG_SHOWTAXINODES"); + + GetPlayer()->SetTaxiCheater(lastTaxiCheaterState); +} + +void WorldSession::SendDoFlight(uint32 mountDisplayId, uint32 path, uint32 pathNode) +{ + // remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + while (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) + GetPlayer()->GetMotionMaster()->MovementExpired(false); + + if (mountDisplayId) + GetPlayer()->Mount(mountDisplayId); + + GetPlayer()->GetMotionMaster()->MoveTaxiFlight(path,pathNode); +} + +bool WorldSession::SendLearnNewTaxiNode(Creature* unit) +{ + // find current node + uint32 curloc = objmgr.GetNearestTaxiNode(unit->GetPositionX(),unit->GetPositionY(),unit->GetPositionZ(),unit->GetMapId(),GetPlayer()->GetTeam()); + + if (curloc == 0) + return true; // `true` send to avoid WorldSession::SendTaxiMenu call with one more curlock seartch with same false result. + + if (GetPlayer()->m_taxi.SetTaximaskNode(curloc)) + { + WorldPacket msg(SMSG_NEW_TAXI_PATH, 0); + SendPacket(&msg); + + WorldPacket update(SMSG_TAXINODE_STATUS, 9); + update << uint64(unit->GetGUID()); + update << uint8(1); + SendPacket(&update); + + return true; + } + else + return false; +} + +void WorldSession::HandleActivateTaxiExpressOpcode (WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_ACTIVATETAXIEXPRESS"); + + uint64 guid; + uint32 node_count; + + recv_data >> guid >> node_count; + + Creature *npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); + if (!npc) + { + sLog.outDebug("WORLD: HandleActivateTaxiExpressOpcode - Unit (GUID: %u) not found or you can't interact with it.", uint32(GUID_LOPART(guid))); + return; + } + std::vector nodes; + + for (uint32 i = 0; i < node_count; ++i) + { + uint32 node; + recv_data >> node; + nodes.push_back(node); + } + + if (nodes.empty()) + return; + + sLog.outDebug("WORLD: Received CMSG_ACTIVATETAXIEXPRESS from %d to %d" ,nodes.front(),nodes.back()); + + GetPlayer()->ActivateTaxiPathTo(nodes, npc); +} + +void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_MOVE_SPLINE_DONE"); + + uint64 guid; // used only for proper packet read + if (!recv_data.readPackGUID(guid)) + return; + + MovementInfo movementInfo; // used only for proper packet read + ReadMovementInfo(recv_data, &movementInfo); + + recv_data.read_skip(); // unk + + // in taxi flight packet received in 2 case: + // 1) end taxi path in far (multi-node) flight + // 2) switch from one map to other in case multim-map taxi path + // we need process only (1) + + uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination(); + if (!curDest) + return; + + TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest); + + // far teleport case + if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId()) + { + if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) + { + // short preparations to continue flight + FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); + + flight->SetCurrentNodeAfterTeleport(); + Path::PathNode const& node = flight->GetPath()[flight->GetCurrentNode()]; + flight->SkipCurrentNode(); + + GetPlayer()->TeleportTo(curDestNode->map_id,node.x,node.y,node.z,GetPlayer()->GetOrientation()); + } + return; + } + + uint32 destinationnode = GetPlayer()->m_taxi.NextTaxiDestination(); + if (destinationnode > 0) // if more destinations to go + { + // current source node for next destination + uint32 sourcenode = GetPlayer()->m_taxi.GetTaxiSource(); + + // Add to taximask middle hubs in taxicheat mode (to prevent having player with disabled taxicheat and not having back flight path) + if (GetPlayer()->isTaxiCheater()) + { + if (GetPlayer()->m_taxi.SetTaximaskNode(sourcenode)) + { + WorldPacket data(SMSG_NEW_TAXI_PATH, 0); + _player->GetSession()->SendPacket(&data); + } + } + + sLog.outDebug("WORLD: Taxi has to go from %u to %u", sourcenode, destinationnode); + + uint32 mountDisplayId = objmgr.GetTaxiMountDisplayId(sourcenode, GetPlayer()->GetTeam()); + + uint32 path, cost; + objmgr.GetTaxiPath(sourcenode, destinationnode, path, cost); + + if (path && mountDisplayId) + SendDoFlight(mountDisplayId, path, 1); // skip start fly node + else + GetPlayer()->m_taxi.ClearTaxiDestinations(); // clear problematic path and next + return; + } + + GetPlayer()->CleanupAfterTaxiFlight(); + GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ()); + if (GetPlayer()->pvpInfo.inHostileArea) + GetPlayer()->CastSpell(GetPlayer(), 2479, true); +} + +void WorldSession::HandleActivateTaxiOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: Received CMSG_ACTIVATETAXI"); + + uint64 guid; + std::vector nodes; + nodes.resize(2); + + recv_data >> guid >> nodes[0] >> nodes[1]; + sLog.outDebug("WORLD: Received CMSG_ACTIVATETAXI from %d to %d" ,nodes[0],nodes[1]); + Creature *npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); + if (!npc) + { + sLog.outDebug("WORLD: HandleActivateTaxiOpcode - Unit (GUID: %u) not found or you can't interact with it.", uint32(GUID_LOPART(guid))); + return; + } + + GetPlayer()->ActivateTaxiPathTo(nodes, npc); +} diff --git a/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp b/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp new file mode 100644 index 00000000000..72ed25adbca --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Language.h" +#include "WorldPacket.h" +#include "Common.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "World.h" + +void WorldSession::HandleGMTicketCreateOpcode(WorldPacket & recv_data) +{ + if (GetPlayer()->getLevel() < sWorld.getConfig(CONFIG_TICKET_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_TICKET_REQ), sWorld.getConfig(CONFIG_TICKET_LEVEL_REQ)); + return; + } + + if (GM_Ticket *ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID())) + { + WorldPacket data(SMSG_GMTICKET_CREATE, 4); + data << uint32(1); // 1 - You already have GM ticket + SendPacket(&data); + return; + } + + uint32 map; + float x, y, z; + std::string ticketText, ticketText2; + + SendQueryTimeResponse(); + + WorldPacket data(SMSG_GMTICKET_CREATE, 4); + recv_data >> map; + recv_data >> x; + recv_data >> y; + recv_data >> z; + recv_data >> ticketText; + recv_data >> ticketText2; + + GM_Ticket *ticket = new GM_Ticket; + ticket->name = GetPlayer()->GetName(); + ticket->guid = objmgr.GenerateGMTicketId(); + ticket->playerGuid = GetPlayer()->GetGUID(); + ticket->message = ticketText; + ticket->createtime = time(NULL); + ticket->map = map; + ticket->pos_x = x; + ticket->pos_y = y; + ticket->pos_z = z; + ticket->timestamp = time(NULL); + ticket->closed = 0; + ticket->assignedToGM = 0; + ticket->comment = ""; + + objmgr.AddOrUpdateGMTicket(*ticket, true); + + data << uint32(2); + SendPacket(&data); + + sWorld.SendGMText(LANG_COMMAND_TICKETNEW, GetPlayer()->GetName(), ticket->guid); + +} + +void WorldSession::HandleGMTicketUpdateOpcode(WorldPacket & recv_data) +{ + WorldPacket data(SMSG_GMTICKET_UPDATETEXT, 4); + + std::string message; + recv_data >> message; + + GM_Ticket *ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); + if (!ticket) + { + data << uint32(1); + SendPacket(&data); + return; + } + + ticket->message = message; + ticket->timestamp = time(NULL); + + objmgr.AddOrUpdateGMTicket(*ticket); + + data << uint32(2); + SendPacket(&data); + + sWorld.SendGMText(LANG_COMMAND_TICKETUPDATED, GetPlayer()->GetName(), ticket->guid); + +} + +void WorldSession::HandleGMTicketDeleteOpcode(WorldPacket & /*recv_data*/) +{ + GM_Ticket* ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); + + if (ticket) + { + WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4); + data << uint32(9); + SendPacket(&data); + + sWorld.SendGMText(LANG_COMMAND_TICKETPLAYERABANDON, GetPlayer()->GetName(), ticket->guid); + objmgr.RemoveGMTicket(ticket, GetPlayer()->GetGUID(), false); + SendGMTicketGetTicket(0x0A, 0); + } +} + +void WorldSession::HandleGMTicketGetTicketOpcode(WorldPacket & /*recv_data*/) +{ + SendQueryTimeResponse(); + + GM_Ticket *ticket = objmgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); + if (ticket) + SendGMTicketGetTicket(0x06, ticket->message.c_str()); + else + SendGMTicketGetTicket(0x0A, 0); + +} + +void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPacket & /*recv_data*/) +{ + WorldPacket data(SMSG_GMTICKET_SYSTEMSTATUS, 4); + data << uint32(1); + SendPacket(&data); +} + +void WorldSession::SendGMTicketGetTicket(uint32 status, char const* text) +{ + int len = text ? strlen(text) : 0; + WorldPacket data(SMSG_GMTICKET_GETTICKET, (4+len+1+4+2+4+4)); + data << uint32(status); // standard 0x0A, 0x06 if text present + data << uint32(1); // unk flags, if 0, can't edit the ticket + if (status == 6) + { + data << text; // ticket text + data << uint8(0x7); // ticket category + data << float(0); // tickets in queue? + data << float(0); // if > "tickets in queue" then "We are currently experiencing a high volume of petitions." + data << float(0); // 0 - "Your ticket will be serviced soon", 1 - "Wait time currently unavailable" + data << uint8(0); // if == 2 and next field == 1 then "Your ticket has been escalated" + data << uint8(0); // const + } + SendPacket(&data); +} diff --git a/src/server/game/Server/Protocol/Handlers/TradeHandler.cpp b/src/server/game/Server/Protocol/Handlers/TradeHandler.cpp new file mode 100644 index 00000000000..448a6e0520d --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/TradeHandler.cpp @@ -0,0 +1,656 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectAccessor.h" +#include "Log.h" +#include "Opcodes.h" +#include "Player.h" +#include "Item.h" +#include "SocialMgr.h" +#include "Language.h" + +enum TradeStatus +{ + TRADE_STATUS_BUSY = 0, + TRADE_STATUS_BEGIN_TRADE = 1, + TRADE_STATUS_OPEN_WINDOW = 2, + TRADE_STATUS_TRADE_CANCELED = 3, + TRADE_STATUS_TRADE_ACCEPT = 4, + TRADE_STATUS_BUSY_2 = 5, + TRADE_STATUS_NO_TARGET = 6, + TRADE_STATUS_BACK_TO_TRADE = 7, + TRADE_STATUS_TRADE_COMPLETE = 8, + // 9? + TRADE_STATUS_TARGET_TO_FAR = 10, + TRADE_STATUS_WRONG_FACTION = 11, + TRADE_STATUS_CLOSE_WINDOW = 12, + // 13? + TRADE_STATUS_IGNORE_YOU = 14, + TRADE_STATUS_YOU_STUNNED = 15, + TRADE_STATUS_TARGET_STUNNED = 16, + TRADE_STATUS_YOU_DEAD = 17, + TRADE_STATUS_TARGET_DEAD = 18, + TRADE_STATUS_YOU_LOGOUT = 19, + TRADE_STATUS_TARGET_LOGOUT = 20, + TRADE_STATUS_TRIAL_ACCOUNT = 21, // Trial accounts can not perform that action + TRADE_STATUS_ONLY_CONJURED = 22 // You can only trade conjured items... (cross realm BG related). +}; + +void WorldSession::SendTradeStatus(uint32 status) +{ + WorldPacket data; + + switch(status) + { + case TRADE_STATUS_BEGIN_TRADE: + data.Initialize(SMSG_TRADE_STATUS, 4+8); + data << uint32(status); + data << uint64(0); + break; + case TRADE_STATUS_OPEN_WINDOW: + data.Initialize(SMSG_TRADE_STATUS, 4+4); + data << uint32(status); + data << uint32(0); // added in 2.4.0 + break; + case TRADE_STATUS_CLOSE_WINDOW: + data.Initialize(SMSG_TRADE_STATUS, 4+4+1+4); + data << uint32(status); + data << uint32(0); + data << uint8(0); + data << uint32(0); + break; + case TRADE_STATUS_ONLY_CONJURED: + data.Initialize(SMSG_TRADE_STATUS, 4+1); + data << uint32(status); + data << uint8(0); + break; + default: + data.Initialize(SMSG_TRADE_STATUS, 4); + data << uint32(status); + break; + } + + SendPacket(&data); +} + +void WorldSession::HandleIgnoreTradeOpcode(WorldPacket& /*recvPacket*/) +{ + sLog.outDebug("WORLD: Ignore Trade %u",_player->GetGUIDLow()); + // recvPacket.print_storage(); +} + +void WorldSession::HandleBusyTradeOpcode(WorldPacket& /*recvPacket*/) +{ + sLog.outDebug("WORLD: Busy Trade %u",_player->GetGUIDLow()); + // recvPacket.print_storage(); +} + +void WorldSession::SendUpdateTrade() +{ + Item *item = NULL; + + if (!_player || !_player->pTrader) + return; + + // reset trade status + if (_player->acceptTrade) + { + _player->acceptTrade = false; + SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); + } + + if (_player->pTrader->acceptTrade) + { + _player->pTrader->acceptTrade = false; + _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); + } + + WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, (100)); // guess size + data << (uint8) 1; // can be different (only seen 0 and 1) + data << (uint32) 0; // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) + data << (uint32) TRADE_SLOT_COUNT; // trade slots count/number?, = next field in most cases + data << (uint32) TRADE_SLOT_COUNT; // trade slots count/number?, = prev field in most cases + data << (uint32) _player->pTrader->tradeGold; // trader gold + data << (uint32) 0; // spell casted on lowest slot item + + for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) + { + item = (_player->pTrader->tradeItems[i] != 0 ? _player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]) : NULL); + + data << (uint8) i; // trade slot number, if not specified, then end of packet + + if (item) + { + data << (uint32) item->GetProto()->ItemId; // entry + // display id + data << (uint32) item->GetProto()->DisplayInfoID; + // stack count + data << (uint32) item->GetUInt32Value(ITEM_FIELD_STACK_COUNT); + data << (uint32) 0; // probably gift=1, created_by=0? + // gift creator + data << (uint64) item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR); + data << (uint32) item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT); + for (uint8 j = 0; j < 3; ++j) + data << (uint32) 0; // enchantment id (permanent/gems?) + // creator + data << (uint64) item->GetUInt64Value(ITEM_FIELD_CREATOR); + data << (uint32) item->GetSpellCharges(); // charges + data << (uint32) item->GetItemSuffixFactor(); // SuffixFactor + // random properties id + data << (int32) item->GetItemRandomPropertyId(); + data << (uint32) item->GetProto()->LockID; // lock id + // max durability + data << (uint32) item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); + // durability + data << (uint32) item->GetUInt32Value(ITEM_FIELD_DURABILITY); + } + else + { + for (uint8 j = 0; j < 18; j++) + data << uint32(0); + } + } + SendPacket(&data); +} + +//============================================================== +// transfer the items to the players + +void WorldSession::moveItems(Item* myItems[], Item* hisItems[]) +{ + for (int i=0; ipTrader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, myItems[i], false) == EQUIP_ERR_OK); + bool playerCanTrade = (hisItems[i] == NULL || _player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, hisItems[i], false) == EQUIP_ERR_OK); + if (traderCanTrade && playerCanTrade) + { + // Ok, if trade item exists and can be stored + // If we trade in both directions we had to check, if the trade will work before we actually do it + // A roll back is not possible after we stored it + if (myItems[i]) + { + // logging + sLog.outDebug("partner storing: %u",myItems[i]->GetGUIDLow()); + if (_player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) + { + sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)", + _player->GetName(),_player->GetSession()->GetAccountId(), + myItems[i]->GetProto()->Name1,myItems[i]->GetEntry(),myItems[i]->GetCount(), + _player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId()); + } + + // store + _player->pTrader->MoveItemToInventory(traderDst, myItems[i], true, true); + } + if (hisItems[i]) + { + // logging + sLog.outDebug("player storing: %u",hisItems[i]->GetGUIDLow()); + if (_player->pTrader->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) + { + sLog.outCommand(_player->pTrader->GetSession()->GetAccountId(),"GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)", + _player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId(), + hisItems[i]->GetProto()->Name1,hisItems[i]->GetEntry(),hisItems[i]->GetCount(), + _player->GetName(),_player->GetSession()->GetAccountId()); + } + + // store + _player->MoveItemToInventory(playerDst, hisItems[i], true, true); + } + } + else + { + // in case of fatal error log error message + // return the already removed items to the original owner + if (myItems[i]) + { + if (!traderCanTrade) + sLog.outError("trader can't store item: %u",myItems[i]->GetGUIDLow()); + if (_player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, myItems[i], false) == EQUIP_ERR_OK) + _player->MoveItemToInventory(playerDst, myItems[i], true, true); + else + sLog.outError("player can't take item back: %u",myItems[i]->GetGUIDLow()); + } + // return the already removed items to the original owner + if (hisItems[i]) + { + if (!playerCanTrade) + sLog.outError("player can't store item: %u",hisItems[i]->GetGUIDLow()); + if (_player->pTrader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, hisItems[i], false) == EQUIP_ERR_OK) + _player->pTrader->MoveItemToInventory(traderDst, hisItems[i], true, true); + else + sLog.outError("trader can't take item back: %u",hisItems[i]->GetGUIDLow()); + } + } + } +} + +//============================================================== + +void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) +{ + Item *myItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; + Item *hisItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; + bool myCanCompleteTrade=true,hisCanCompleteTrade=true; + + if (!GetPlayer()->pTrader) + return; + + // not accept case incorrect money amount + if (_player->tradeGold > _player->GetMoney()) + { + SendNotification(LANG_NOT_ENOUGH_GOLD); + _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); + _player->acceptTrade = false; + return; + } + + // not accept case incorrect money amount + if (_player->pTrader->tradeGold > _player->pTrader->GetMoney()) + { + _player->pTrader->GetSession()->SendNotification(LANG_NOT_ENOUGH_GOLD); + SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); + _player->pTrader->acceptTrade = false; + return; + } + + // not accept if some items now can't be trade (cheating) + for (int i=0; itradeItems[i] != 0) + { + if (Item* item =_player->GetItemByGuid(_player->tradeItems[i])) + { + if (!item->CanBeTraded()) + { + SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); + return; + } + } + } + if (_player->pTrader->tradeItems[i] != 0) + { + if (Item* item =_player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i])) + { + if (!item->CanBeTraded()) + { + SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); + return; + } + } + } + } + + _player->acceptTrade = true; + if (_player->pTrader->acceptTrade) + { + // inform partner client + _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); + + // store items in local list and set 'in-trade' flag + for (int i=0; itradeItems[i] != 0) + { + //Can return NULL + myItems[i] = _player->GetItemByGuid(_player->tradeItems[i]); + if (myItems[i]) + { + myItems[i]->SetInTrade(); + sLog.outDebug("Player trade item bag: %u slot: %u", myItems[i]->GetBagSlot(), myItems[i]->GetSlot()); + } + } + if (_player->pTrader->tradeItems[i] != 0) + { + //Can return NULL + hisItems[i]=_player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]); + if (hisItems[i]) + { + hisItems[i]->SetInTrade(); + sLog.outDebug("Player trade item bag: %u slot: %u", hisItems[i]->GetBagSlot(), hisItems[i]->GetSlot()); + } + } + } + + // test if item will fit in each inventory + hisCanCompleteTrade = (_player->pTrader->CanStoreItems(myItems,TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK); + myCanCompleteTrade = (_player->CanStoreItems(hisItems,TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK); + + // clear 'in-trade' flag + for (int i=0; iSetInTrade(false); + if (hisItems[i]) hisItems[i]->SetInTrade(false); + } + + // in case of missing space report error + if (!myCanCompleteTrade) + { + SendNotification(LANG_NOT_FREE_TRADE_SLOTS); + GetPlayer()->pTrader->GetSession()->SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); + SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); + _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); + return; + } + else if (!hisCanCompleteTrade) + { + SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); + GetPlayer()->pTrader->GetSession()->SendNotification(LANG_NOT_FREE_TRADE_SLOTS); + SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); + _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); + return; + } + + // execute trade: 1. remove + for (int i=0; iSetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); + iPtr = _player->GetItemByGuid(_player->tradeItems[i]); + _player->MoveItemFromInventory(iPtr->GetBagSlot(), iPtr->GetSlot(), true); + } + if (hisItems[i]) + { + hisItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR,_player->pTrader->GetGUID()); + iPtr = _player->pTrader->GetItemByGuid(_player->pTrader->tradeItems[i]); + _player->pTrader->MoveItemFromInventory(iPtr->GetBagSlot(), iPtr->GetSlot(), true); + } + } + + // execute trade: 2. store + moveItems(myItems, hisItems); + + // logging money + if (sWorld.getConfig(CONFIG_GM_LOG_TRADE)) + { + if (_player->GetSession()->GetSecurity() > SEC_PLAYER && _player->tradeGold > 0) + { + sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", + _player->GetName(),_player->GetSession()->GetAccountId(), + _player->tradeGold, + _player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId()); + } + if (_player->pTrader->GetSession()->GetSecurity() > SEC_PLAYER && _player->pTrader->tradeGold > 0) + { + sLog.outCommand(_player->pTrader->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", + _player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId(), + _player->pTrader->tradeGold, + _player->GetName(),_player->GetSession()->GetAccountId()); + } + } + + // update money + _player->ModifyMoney(-int32(_player->tradeGold)); + _player->ModifyMoney(_player->pTrader->tradeGold); + _player->pTrader->ModifyMoney(-int32(_player->pTrader->tradeGold)); + _player->pTrader->ModifyMoney(_player->tradeGold); + + _player->ClearTrade(); + _player->pTrader->ClearTrade(); + + // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards) + CharacterDatabase.BeginTransaction(); + _player->SaveInventoryAndGoldToDB(); + _player->pTrader->SaveInventoryAndGoldToDB(); + CharacterDatabase.CommitTransaction(); + + _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); + SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); + + _player->pTrader->pTrader = NULL; + _player->pTrader = NULL; + } + else + { + _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); + } +} + +void WorldSession::HandleUnacceptTradeOpcode(WorldPacket& /*recvPacket*/) +{ + if (!GetPlayer()->pTrader) + return; + + _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE); + _player->acceptTrade = false; +} + +void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/) +{ + if (!_player->pTrader) + return; + + _player->pTrader->GetSession()->SendTradeStatus(TRADE_STATUS_OPEN_WINDOW); + _player->pTrader->ClearTrade(); + + SendTradeStatus(TRADE_STATUS_OPEN_WINDOW); + _player->ClearTrade(); +} + +void WorldSession::SendCancelTrade() +{ + SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); +} + +void WorldSession::HandleCancelTradeOpcode(WorldPacket& /*recvPacket*/) +{ + // sended also after LOGOUT COMPLETE + if (_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT + _player->TradeCancel(true); +} + +void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) +{ + if (GetPlayer()->pTrader) + return; + + uint64 ID; + + if (!GetPlayer()->isAlive()) + { + SendTradeStatus(TRADE_STATUS_YOU_DEAD); + return; + } + + if (GetPlayer()->hasUnitState(UNIT_STAT_STUNNED)) + { + SendTradeStatus(TRADE_STATUS_YOU_STUNNED); + return; + } + + if (isLogingOut()) + { + SendTradeStatus(TRADE_STATUS_YOU_LOGOUT); + return; + } + + if (GetPlayer()->isInFlight()) + { + SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); + return; + } + + if (GetPlayer()->getLevel() < sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_TRADE_REQ), sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ)); + return; + } + + recvPacket >> ID; + + Player* pOther = ObjectAccessor::FindPlayer(ID); + + if (!pOther) + { + SendTradeStatus(TRADE_STATUS_NO_TARGET); + return; + } + + if (pOther == GetPlayer() || pOther->pTrader) + { + SendTradeStatus(TRADE_STATUS_BUSY); + return; + } + + if (!pOther->isAlive()) + { + SendTradeStatus(TRADE_STATUS_TARGET_DEAD); + return; + } + + if (pOther->isInFlight()) + { + SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); + return; + } + + if (pOther->hasUnitState(UNIT_STAT_STUNNED)) + { + SendTradeStatus(TRADE_STATUS_TARGET_STUNNED); + return; + } + + if (pOther->GetSession()->isLogingOut()) + { + SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT); + return; + } + + if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) + { + SendTradeStatus(TRADE_STATUS_IGNORE_YOU); + return; + } + + if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && pOther->GetTeam() !=_player->GetTeam()) + { + SendTradeStatus(TRADE_STATUS_WRONG_FACTION); + return; + } + + if (!pOther->IsWithinDistInMap(_player,10.0f,false)) + { + SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); + return; + } + + if (pOther->getLevel() < sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_TRADE_OTHER_REQ), sWorld.getConfig(CONFIG_TRADE_LEVEL_REQ)); + return; + } + + // OK start trade + _player->pTrader = pOther; + pOther->pTrader =_player; + + WorldPacket data(SMSG_TRADE_STATUS, 12); + data << (uint32) TRADE_STATUS_BEGIN_TRADE; + data << (uint64)_player->GetGUID(); + _player->pTrader->GetSession()->SendPacket(&data); +} + +void WorldSession::HandleSetTradeGoldOpcode(WorldPacket& recvPacket) +{ + if (!_player->pTrader) + return; + + uint32 gold; + + recvPacket >> gold; + + // gold can be incorrect, but this is checked at trade finished. + _player->tradeGold = gold; + + _player->pTrader->GetSession()->SendUpdateTrade(); +} + +void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket) +{ + if (!_player->pTrader) + return; + + // send update + uint8 tradeSlot; + uint8 bag; + uint8 slot; + + recvPacket >> tradeSlot; + recvPacket >> bag; + recvPacket >> slot; + + // invalid slot number + if (tradeSlot >= TRADE_SLOT_COUNT) + { + SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); + return; + } + + // check cheating, can't fail with correct client operations + Item* item = _player->GetItemByPos(bag,slot); + if (!item || (tradeSlot != TRADE_SLOT_NONTRADED && !item->CanBeTraded())) + { + SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); + return; + } + + uint64 iGUID = item->GetGUID(); + + // prevent place single item into many trade slots using cheating and client bugs + for (int i = 0; i < TRADE_SLOT_COUNT; ++i) + { + if (_player->tradeItems[i] == iGUID) + { + // cheating attempt + SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); + return; + } + } + + _player->tradeItems[tradeSlot] = iGUID; + + _player->pTrader->GetSession()->SendUpdateTrade(); +} + +void WorldSession::HandleClearTradeItemOpcode(WorldPacket& recvPacket) +{ + if (!_player->pTrader) + return; + + uint8 tradeSlot; + recvPacket >> tradeSlot; + + // invalid slot number + if (tradeSlot >= TRADE_SLOT_COUNT) + return; + + _player->tradeItems[tradeSlot] = 0; + + _player->pTrader->GetSession()->SendUpdateTrade(); +} + diff --git a/src/server/game/Server/Protocol/Handlers/VoiceChatHandler.cpp b/src/server/game/Server/Protocol/Handlers/VoiceChatHandler.cpp new file mode 100644 index 00000000000..78aafe1999b --- /dev/null +++ b/src/server/game/Server/Protocol/Handlers/VoiceChatHandler.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" + +void WorldSession::HandleVoiceSessionEnableOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_VOICE_SESSION_ENABLE"); + // uint8 isVoiceEnabled, uint8 isMicrophoneEnabled + recv_data.read_skip(); + recv_data.read_skip(); + recv_data.hexlike(); +} + +void WorldSession::HandleChannelVoiceOnOpcode(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_CHANNEL_VOICE_ON"); + // Enable Voice button in channel context menu + recv_data.hexlike(); +} + +void WorldSession::HandleSetActiveVoiceChannel(WorldPacket & recv_data) +{ + sLog.outDebug("WORLD: CMSG_SET_ACTIVE_VOICE_CHANNEL"); + recv_data.read_skip(); + recv_data.read_skip(); + recv_data.hexlike(); +} + diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp new file mode 100644 index 00000000000..0b67199b4ea --- /dev/null +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -0,0 +1,1338 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** \file + \ingroup u2w +*/ + +#include "Opcodes.h" +#include "WorldSession.h" + +/// Correspondence between opcodes and their names +OpcodeHandler opcodeTable[NUM_MSG_TYPES] = +{ + /*0x000*/ { "MSG_NULL_ACTION", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x001*/ { "CMSG_BOOTME", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x002*/ { "CMSG_DBLOOKUP", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x003*/ { "SMSG_DBLOOKUP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x004*/ { "CMSG_QUERY_OBJECT_POSITION", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x005*/ { "SMSG_QUERY_OBJECT_POSITION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x006*/ { "CMSG_QUERY_OBJECT_ROTATION", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x007*/ { "SMSG_QUERY_OBJECT_ROTATION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x008*/ { "CMSG_WORLD_TELEPORT", STATUS_LOGGEDIN, &WorldSession::HandleWorldTeleportOpcode }, + /*0x009*/ { "CMSG_TELEPORT_TO_UNIT", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x00A*/ { "CMSG_ZONE_MAP", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x00B*/ { "SMSG_ZONE_MAP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x00C*/ { "CMSG_DEBUG_CHANGECELLZONE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x00D*/ { "CMSG_MOVE_CHARACTER_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x00E*/ { "SMSG_MOVE_CHARACTER_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x00F*/ { "CMSG_RECHARGE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x010*/ { "CMSG_LEARN_SPELL", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x011*/ { "CMSG_CREATEMONSTER", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x012*/ { "CMSG_DESTROYMONSTER", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x013*/ { "CMSG_CREATEITEM", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x014*/ { "CMSG_CREATEGAMEOBJECT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x015*/ { "SMSG_CHECK_FOR_BOTS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x016*/ { "CMSG_MAKEMONSTERATTACKGUID", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x017*/ { "CMSG_BOT_DETECTED2", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x018*/ { "CMSG_FORCEACTION", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x019*/ { "CMSG_FORCEACTIONONOTHER", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x01A*/ { "CMSG_FORCEACTIONSHOW", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x01B*/ { "SMSG_FORCEACTIONSHOW", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x01C*/ { "CMSG_PETGODMODE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x01D*/ { "SMSG_PETGODMODE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x01E*/ { "SMSG_REFER_A_FRIEND_EXPIRED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x01F*/ { "CMSG_WEATHER_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x020*/ { "CMSG_UNDRESSPLAYER", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x021*/ { "CMSG_BEASTMASTER", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x022*/ { "CMSG_GODMODE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x023*/ { "SMSG_GODMODE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x024*/ { "CMSG_CHEAT_SETMONEY", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x025*/ { "CMSG_LEVEL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x026*/ { "CMSG_PET_LEVEL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x027*/ { "CMSG_SET_WORLDSTATE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x028*/ { "CMSG_COOLDOWN_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x029*/ { "CMSG_USE_SKILL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x02A*/ { "CMSG_FLAG_QUEST", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x02B*/ { "CMSG_FLAG_QUEST_FINISH", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x02C*/ { "CMSG_CLEAR_QUEST", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x02D*/ { "CMSG_SEND_EVENT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x02E*/ { "CMSG_DEBUG_AISTATE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x02F*/ { "SMSG_DEBUG_AISTATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x030*/ { "CMSG_DISABLE_PVP_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x031*/ { "CMSG_ADVANCE_SPAWN_TIME", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x032*/ { "SMSG_DESTRUCTIBLE_BUILDING_DAMAGE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x033*/ { "CMSG_AUTH_SRP6_BEGIN", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x034*/ { "CMSG_AUTH_SRP6_PROOF", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x035*/ { "CMSG_AUTH_SRP6_RECODE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x036*/ { "CMSG_CHAR_CREATE", STATUS_AUTHED, &WorldSession::HandleCharCreateOpcode }, + /*0x037*/ { "CMSG_CHAR_ENUM", STATUS_AUTHED, &WorldSession::HandleCharEnumOpcode }, + /*0x038*/ { "CMSG_CHAR_DELETE", STATUS_AUTHED, &WorldSession::HandleCharDeleteOpcode }, + /*0x039*/ { "SMSG_AUTH_SRP6_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x03A*/ { "SMSG_CHAR_CREATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x03B*/ { "SMSG_CHAR_ENUM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x03C*/ { "SMSG_CHAR_DELETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x03D*/ { "CMSG_PLAYER_LOGIN", STATUS_AUTHED, &WorldSession::HandlePlayerLoginOpcode }, + /*0x03E*/ { "SMSG_NEW_WORLD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x03F*/ { "SMSG_TRANSFER_PENDING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x040*/ { "SMSG_TRANSFER_ABORTED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x041*/ { "SMSG_CHARACTER_LOGIN_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x042*/ { "SMSG_LOGIN_SETTIMESPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x043*/ { "SMSG_GAMETIME_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x044*/ { "CMSG_GAMETIME_SET", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x045*/ { "SMSG_GAMETIME_SET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x046*/ { "CMSG_GAMESPEED_SET", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x047*/ { "SMSG_GAMESPEED_SET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x048*/ { "CMSG_SERVERTIME", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x049*/ { "SMSG_SERVERTIME", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x04A*/ { "CMSG_PLAYER_LOGOUT", STATUS_LOGGEDIN, &WorldSession::HandlePlayerLogoutOpcode }, + /*0x04B*/ { "CMSG_LOGOUT_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleLogoutRequestOpcode }, + /*0x04C*/ { "SMSG_LOGOUT_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x04D*/ { "SMSG_LOGOUT_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x04E*/ { "CMSG_LOGOUT_CANCEL", STATUS_LOGGEDIN, &WorldSession::HandleLogoutCancelOpcode }, + /*0x04F*/ { "SMSG_LOGOUT_CANCEL_ACK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x050*/ { "CMSG_NAME_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleNameQueryOpcode }, + /*0x051*/ { "SMSG_NAME_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x052*/ { "CMSG_PET_NAME_QUERY", STATUS_LOGGEDIN, &WorldSession::HandlePetNameQuery }, + /*0x053*/ { "SMSG_PET_NAME_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x054*/ { "CMSG_GUILD_QUERY", STATUS_AUTHED, &WorldSession::HandleGuildQueryOpcode }, + /*0x055*/ { "SMSG_GUILD_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x056*/ { "CMSG_ITEM_QUERY_SINGLE", STATUS_LOGGEDIN, &WorldSession::HandleItemQuerySingleOpcode }, + /*0x057*/ { "CMSG_ITEM_QUERY_MULTIPLE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x058*/ { "SMSG_ITEM_QUERY_SINGLE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x059*/ { "SMSG_ITEM_QUERY_MULTIPLE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x05A*/ { "CMSG_PAGE_TEXT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandlePageTextQueryOpcode }, + /*0x05B*/ { "SMSG_PAGE_TEXT_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x05C*/ { "CMSG_QUEST_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleQuestQueryOpcode }, + /*0x05D*/ { "SMSG_QUEST_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x05E*/ { "CMSG_GAMEOBJECT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleGameObjectQueryOpcode }, + /*0x05F*/ { "SMSG_GAMEOBJECT_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x060*/ { "CMSG_CREATURE_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleCreatureQueryOpcode }, + /*0x061*/ { "SMSG_CREATURE_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x062*/ { "CMSG_WHO", STATUS_LOGGEDIN, &WorldSession::HandleWhoOpcode }, + /*0x063*/ { "SMSG_WHO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x064*/ { "CMSG_WHOIS", STATUS_LOGGEDIN, &WorldSession::HandleWhoisOpcode }, + /*0x065*/ { "SMSG_WHOIS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x066*/ { "CMSG_CONTACT_LIST", STATUS_LOGGEDIN, &WorldSession::HandleContactListOpcode }, + /*0x067*/ { "SMSG_CONTACT_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x068*/ { "SMSG_FRIEND_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x069*/ { "CMSG_ADD_FRIEND", STATUS_LOGGEDIN, &WorldSession::HandleAddFriendOpcode }, + /*0x06A*/ { "CMSG_DEL_FRIEND", STATUS_LOGGEDIN, &WorldSession::HandleDelFriendOpcode }, + /*0x06B*/ { "CMSG_SET_CONTACT_NOTES", STATUS_LOGGEDIN, &WorldSession::HandleSetContactNotesOpcode }, + /*0x06C*/ { "CMSG_ADD_IGNORE", STATUS_LOGGEDIN, &WorldSession::HandleAddIgnoreOpcode }, + /*0x06D*/ { "CMSG_DEL_IGNORE", STATUS_LOGGEDIN, &WorldSession::HandleDelIgnoreOpcode }, + /*0x06E*/ { "CMSG_GROUP_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleGroupInviteOpcode }, + /*0x06F*/ { "SMSG_GROUP_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x070*/ { "CMSG_GROUP_CANCEL", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x071*/ { "SMSG_GROUP_CANCEL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x072*/ { "CMSG_GROUP_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleGroupAcceptOpcode }, + /*0x073*/ { "CMSG_GROUP_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandleGroupDeclineOpcode }, + /*0x074*/ { "SMSG_GROUP_DECLINE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x075*/ { "CMSG_GROUP_UNINVITE", STATUS_LOGGEDIN, &WorldSession::HandleGroupUninviteOpcode }, + /*0x076*/ { "CMSG_GROUP_UNINVITE_GUID", STATUS_LOGGEDIN, &WorldSession::HandleGroupUninviteGuidOpcode }, + /*0x077*/ { "SMSG_GROUP_UNINVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x078*/ { "CMSG_GROUP_SET_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGroupSetLeaderOpcode }, + /*0x079*/ { "SMSG_GROUP_SET_LEADER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x07A*/ { "CMSG_LOOT_METHOD", STATUS_LOGGEDIN, &WorldSession::HandleLootMethodOpcode }, + /*0x07B*/ { "CMSG_GROUP_DISBAND", STATUS_LOGGEDIN, &WorldSession::HandleGroupDisbandOpcode }, + /*0x07C*/ { "SMSG_GROUP_DESTROYED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x07D*/ { "SMSG_GROUP_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x07E*/ { "SMSG_PARTY_MEMBER_STATS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x07F*/ { "SMSG_PARTY_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x080*/ { "UMSG_UPDATE_GROUP_MEMBERS", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x081*/ { "CMSG_GUILD_CREATE", STATUS_LOGGEDIN, &WorldSession::HandleGuildCreateOpcode }, + /*0x082*/ { "CMSG_GUILD_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleGuildInviteOpcode }, + /*0x083*/ { "SMSG_GUILD_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x084*/ { "CMSG_GUILD_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleGuildAcceptOpcode }, + /*0x085*/ { "CMSG_GUILD_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandleGuildDeclineOpcode }, + /*0x086*/ { "SMSG_GUILD_DECLINE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x087*/ { "CMSG_GUILD_INFO", STATUS_LOGGEDIN, &WorldSession::HandleGuildInfoOpcode }, + /*0x088*/ { "SMSG_GUILD_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x089*/ { "CMSG_GUILD_ROSTER", STATUS_LOGGEDIN, &WorldSession::HandleGuildRosterOpcode }, + /*0x08A*/ { "SMSG_GUILD_ROSTER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x08B*/ { "CMSG_GUILD_PROMOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildPromoteOpcode }, + /*0x08C*/ { "CMSG_GUILD_DEMOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildDemoteOpcode }, + /*0x08D*/ { "CMSG_GUILD_LEAVE", STATUS_LOGGEDIN, &WorldSession::HandleGuildLeaveOpcode }, + /*0x08E*/ { "CMSG_GUILD_REMOVE", STATUS_LOGGEDIN, &WorldSession::HandleGuildRemoveOpcode }, + /*0x08F*/ { "CMSG_GUILD_DISBAND", STATUS_LOGGEDIN, &WorldSession::HandleGuildDisbandOpcode }, + /*0x090*/ { "CMSG_GUILD_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGuildLeaderOpcode }, + /*0x091*/ { "CMSG_GUILD_MOTD", STATUS_LOGGEDIN, &WorldSession::HandleGuildMOTDOpcode }, + /*0x092*/ { "SMSG_GUILD_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x093*/ { "SMSG_GUILD_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x094*/ { "UMSG_UPDATE_GUILD", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x095*/ { "CMSG_MESSAGECHAT", STATUS_LOGGEDIN, &WorldSession::HandleMessagechatOpcode }, + /*0x096*/ { "SMSG_MESSAGECHAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x097*/ { "CMSG_JOIN_CHANNEL", STATUS_LOGGEDIN, &WorldSession::HandleJoinChannel }, + /*0x098*/ { "CMSG_LEAVE_CHANNEL", STATUS_LOGGEDIN, &WorldSession::HandleLeaveChannel }, + /*0x099*/ { "SMSG_CHANNEL_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x09A*/ { "CMSG_CHANNEL_LIST", STATUS_LOGGEDIN, &WorldSession::HandleChannelList }, + /*0x09B*/ { "SMSG_CHANNEL_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x09C*/ { "CMSG_CHANNEL_PASSWORD", STATUS_LOGGEDIN, &WorldSession::HandleChannelPassword }, + /*0x09D*/ { "CMSG_CHANNEL_SET_OWNER", STATUS_LOGGEDIN, &WorldSession::HandleChannelSetOwner }, + /*0x09E*/ { "CMSG_CHANNEL_OWNER", STATUS_LOGGEDIN, &WorldSession::HandleChannelOwner }, + /*0x09F*/ { "CMSG_CHANNEL_MODERATOR", STATUS_LOGGEDIN, &WorldSession::HandleChannelModerator }, + /*0x0A0*/ { "CMSG_CHANNEL_UNMODERATOR", STATUS_LOGGEDIN, &WorldSession::HandleChannelUnmoderator }, + /*0x0A1*/ { "CMSG_CHANNEL_MUTE", STATUS_LOGGEDIN, &WorldSession::HandleChannelMute }, + /*0x0A2*/ { "CMSG_CHANNEL_UNMUTE", STATUS_LOGGEDIN, &WorldSession::HandleChannelUnmute }, + /*0x0A3*/ { "CMSG_CHANNEL_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleChannelInvite }, + /*0x0A4*/ { "CMSG_CHANNEL_KICK", STATUS_LOGGEDIN, &WorldSession::HandleChannelKick }, + /*0x0A5*/ { "CMSG_CHANNEL_BAN", STATUS_LOGGEDIN, &WorldSession::HandleChannelBan }, + /*0x0A6*/ { "CMSG_CHANNEL_UNBAN", STATUS_LOGGEDIN, &WorldSession::HandleChannelUnban }, + /*0x0A7*/ { "CMSG_CHANNEL_ANNOUNCEMENTS", STATUS_LOGGEDIN, &WorldSession::HandleChannelAnnouncements }, + /*0x0A8*/ { "CMSG_CHANNEL_MODERATE", STATUS_LOGGEDIN, &WorldSession::HandleChannelModerate }, + /*0x0A9*/ { "SMSG_UPDATE_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0AA*/ { "SMSG_DESTROY_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0AB*/ { "CMSG_USE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleUseItemOpcode }, + /*0x0AC*/ { "CMSG_OPEN_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleOpenItemOpcode }, + /*0x0AD*/ { "CMSG_READ_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleReadItem }, + /*0x0AE*/ { "SMSG_READ_ITEM_OK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0AF*/ { "SMSG_READ_ITEM_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0B0*/ { "SMSG_ITEM_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0B1*/ { "CMSG_GAMEOBJ_USE", STATUS_LOGGEDIN, &WorldSession::HandleGameObjectUseOpcode }, + /*0x0B2*/ { "CMSG_DESTROY_ITEMS", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0B3*/ { "SMSG_GAMEOBJECT_CUSTOM_ANIM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0B4*/ { "CMSG_AREATRIGGER", STATUS_LOGGEDIN, &WorldSession::HandleAreaTriggerOpcode }, + /*0x0B5*/ { "MSG_MOVE_START_FORWARD", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0B6*/ { "MSG_MOVE_START_BACKWARD", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0B7*/ { "MSG_MOVE_STOP", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0B8*/ { "MSG_MOVE_START_STRAFE_LEFT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0B9*/ { "MSG_MOVE_START_STRAFE_RIGHT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0BA*/ { "MSG_MOVE_STOP_STRAFE", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0BB*/ { "MSG_MOVE_JUMP", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0BC*/ { "MSG_MOVE_START_TURN_LEFT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0BD*/ { "MSG_MOVE_START_TURN_RIGHT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0BE*/ { "MSG_MOVE_STOP_TURN", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0BF*/ { "MSG_MOVE_START_PITCH_UP", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0C0*/ { "MSG_MOVE_START_PITCH_DOWN", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0C1*/ { "MSG_MOVE_STOP_PITCH", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0C2*/ { "MSG_MOVE_SET_RUN_MODE", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0C3*/ { "MSG_MOVE_SET_WALK_MODE", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0C4*/ { "MSG_MOVE_TOGGLE_LOGGING", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0C5*/ { "MSG_MOVE_TELEPORT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0C6*/ { "MSG_MOVE_TELEPORT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0C7*/ { "MSG_MOVE_TELEPORT_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveTeleportAck }, + /*0x0C8*/ { "MSG_MOVE_TOGGLE_FALL_LOGGING", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0C9*/ { "MSG_MOVE_FALL_LAND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0CA*/ { "MSG_MOVE_START_SWIM", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0CB*/ { "MSG_MOVE_STOP_SWIM", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0CC*/ { "MSG_MOVE_SET_RUN_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0CD*/ { "MSG_MOVE_SET_RUN_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0CE*/ { "MSG_MOVE_SET_RUN_BACK_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0CF*/ { "MSG_MOVE_SET_RUN_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0D0*/ { "MSG_MOVE_SET_WALK_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0D1*/ { "MSG_MOVE_SET_WALK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0D2*/ { "MSG_MOVE_SET_SWIM_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0D3*/ { "MSG_MOVE_SET_SWIM_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0D4*/ { "MSG_MOVE_SET_SWIM_BACK_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0D5*/ { "MSG_MOVE_SET_SWIM_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0D6*/ { "MSG_MOVE_SET_ALL_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0D7*/ { "MSG_MOVE_SET_TURN_RATE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0D8*/ { "MSG_MOVE_SET_TURN_RATE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0D9*/ { "MSG_MOVE_TOGGLE_COLLISION_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0DA*/ { "MSG_MOVE_SET_FACING", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0DB*/ { "MSG_MOVE_SET_PITCH", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0DC*/ { "MSG_MOVE_WORLDPORT_ACK", STATUS_TRANSFER, &WorldSession::HandleMoveWorldportAckOpcode }, + /*0x0DD*/ { "SMSG_MONSTER_MOVE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0DE*/ { "SMSG_MOVE_WATER_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0DF*/ { "SMSG_MOVE_LAND_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0E0*/ { "MSG_MOVE_SET_RAW_POSITION_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0E1*/ { "CMSG_MOVE_SET_RAW_POSITION", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0E2*/ { "SMSG_FORCE_RUN_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0E3*/ { "CMSG_FORCE_RUN_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, + /*0x0E4*/ { "SMSG_FORCE_RUN_BACK_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0E5*/ { "CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, + /*0x0E6*/ { "SMSG_FORCE_SWIM_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0E7*/ { "CMSG_FORCE_SWIM_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, + /*0x0E8*/ { "SMSG_FORCE_MOVE_ROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0E9*/ { "CMSG_FORCE_MOVE_ROOT_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveRootAck }, + /*0x0EA*/ { "SMSG_FORCE_MOVE_UNROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0EB*/ { "CMSG_FORCE_MOVE_UNROOT_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveUnRootAck }, + /*0x0EC*/ { "MSG_MOVE_ROOT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0ED*/ { "MSG_MOVE_UNROOT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0EE*/ { "MSG_MOVE_HEARTBEAT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x0EF*/ { "SMSG_MOVE_KNOCK_BACK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0F0*/ { "CMSG_MOVE_KNOCK_BACK_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveKnockBackAck }, + /*0x0F1*/ { "MSG_MOVE_KNOCK_BACK", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0F2*/ { "SMSG_MOVE_FEATHER_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0F3*/ { "SMSG_MOVE_NORMAL_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0F4*/ { "SMSG_MOVE_SET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0F5*/ { "SMSG_MOVE_UNSET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0F6*/ { "CMSG_MOVE_HOVER_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveHoverAck }, + /*0x0F7*/ { "MSG_MOVE_HOVER", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0F8*/ { "CMSG_TRIGGER_CINEMATIC_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0F9*/ { "CMSG_OPENING_CINEMATIC", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x0FA*/ { "SMSG_TRIGGER_CINEMATIC", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0FB*/ { "CMSG_NEXT_CINEMATIC_CAMERA", STATUS_LOGGEDIN, &WorldSession::HandleNextCinematicCamera }, + /*0x0FC*/ { "CMSG_COMPLETE_CINEMATIC", STATUS_LOGGEDIN, &WorldSession::HandleCompleteCinematic }, + /*0x0FD*/ { "SMSG_TUTORIAL_FLAGS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x0FE*/ { "CMSG_TUTORIAL_FLAG", STATUS_LOGGEDIN, &WorldSession::HandleTutorialFlag }, + /*0x0FF*/ { "CMSG_TUTORIAL_CLEAR", STATUS_LOGGEDIN, &WorldSession::HandleTutorialClear }, + /*0x100*/ { "CMSG_TUTORIAL_RESET", STATUS_LOGGEDIN, &WorldSession::HandleTutorialReset }, + /*0x101*/ { "CMSG_STANDSTATECHANGE", STATUS_LOGGEDIN, &WorldSession::HandleStandStateChangeOpcode }, + /*0x102*/ { "CMSG_EMOTE", STATUS_LOGGEDIN, &WorldSession::HandleEmoteOpcode }, + /*0x103*/ { "SMSG_EMOTE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x104*/ { "CMSG_TEXT_EMOTE", STATUS_LOGGEDIN, &WorldSession::HandleTextEmoteOpcode }, + /*0x105*/ { "SMSG_TEXT_EMOTE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x106*/ { "CMSG_AUTOEQUIP_GROUND_ITEM", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x107*/ { "CMSG_AUTOSTORE_GROUND_ITEM", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x108*/ { "CMSG_AUTOSTORE_LOOT_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutostoreLootItemOpcode }, + /*0x109*/ { "CMSG_STORE_LOOT_IN_SLOT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x10A*/ { "CMSG_AUTOEQUIP_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoEquipItemOpcode }, + /*0x10B*/ { "CMSG_AUTOSTORE_BAG_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoStoreBagItemOpcode }, + /*0x10C*/ { "CMSG_SWAP_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSwapItem }, + /*0x10D*/ { "CMSG_SWAP_INV_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSwapInvItemOpcode }, + /*0x10E*/ { "CMSG_SPLIT_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSplitItemOpcode }, + /*0x10F*/ { "CMSG_AUTOEQUIP_ITEM_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleAutoEquipItemSlotOpcode }, + /*0x110*/ { "OBSOLETE_DROP_ITEM", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x111*/ { "CMSG_DESTROYITEM", STATUS_LOGGEDIN, &WorldSession::HandleDestroyItemOpcode }, + /*0x112*/ { "SMSG_INVENTORY_CHANGE_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x113*/ { "SMSG_OPEN_CONTAINER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x114*/ { "CMSG_INSPECT", STATUS_LOGGEDIN, &WorldSession::HandleInspectOpcode }, + /*0x115*/ { "SMSG_INSPECT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x116*/ { "CMSG_INITIATE_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleInitiateTradeOpcode }, + /*0x117*/ { "CMSG_BEGIN_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleBeginTradeOpcode }, + /*0x118*/ { "CMSG_BUSY_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleBusyTradeOpcode }, + /*0x119*/ { "CMSG_IGNORE_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleIgnoreTradeOpcode }, + /*0x11A*/ { "CMSG_ACCEPT_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleAcceptTradeOpcode }, + /*0x11B*/ { "CMSG_UNACCEPT_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleUnacceptTradeOpcode }, + /*0x11C*/ { "CMSG_CANCEL_TRADE", STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, &WorldSession::HandleCancelTradeOpcode}, + /*0x11D*/ { "CMSG_SET_TRADE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSetTradeItemOpcode }, + /*0x11E*/ { "CMSG_CLEAR_TRADE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleClearTradeItemOpcode }, + /*0x11F*/ { "CMSG_SET_TRADE_GOLD", STATUS_LOGGEDIN, &WorldSession::HandleSetTradeGoldOpcode }, + /*0x120*/ { "SMSG_TRADE_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x121*/ { "SMSG_TRADE_STATUS_EXTENDED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x122*/ { "SMSG_INITIALIZE_FACTIONS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x123*/ { "SMSG_SET_FACTION_VISIBLE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x124*/ { "SMSG_SET_FACTION_STANDING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x125*/ { "CMSG_SET_FACTION_ATWAR", STATUS_LOGGEDIN, &WorldSession::HandleSetFactionAtWar }, + /*0x126*/ { "CMSG_SET_FACTION_CHEAT", STATUS_LOGGEDIN, &WorldSession::HandleSetFactionCheat }, + /*0x127*/ { "SMSG_SET_PROFICIENCY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x128*/ { "CMSG_SET_ACTION_BUTTON", STATUS_LOGGEDIN, &WorldSession::HandleSetActionButtonOpcode }, + /*0x129*/ { "SMSG_ACTION_BUTTONS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x12A*/ { "SMSG_INITIAL_SPELLS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x12B*/ { "SMSG_LEARNED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x12C*/ { "SMSG_SUPERCEDED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x12D*/ { "CMSG_NEW_SPELL_SLOT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x12E*/ { "CMSG_CAST_SPELL", STATUS_LOGGEDIN, &WorldSession::HandleCastSpellOpcode }, + /*0x12F*/ { "CMSG_CANCEL_CAST", STATUS_LOGGEDIN, &WorldSession::HandleCancelCastOpcode }, + /*0x130*/ { "SMSG_CAST_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x131*/ { "SMSG_SPELL_START", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x132*/ { "SMSG_SPELL_GO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x133*/ { "SMSG_SPELL_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x134*/ { "SMSG_SPELL_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x135*/ { "SMSG_COOLDOWN_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x136*/ { "CMSG_CANCEL_AURA", STATUS_LOGGEDIN, &WorldSession::HandleCancelAuraOpcode }, + /*0x137*/ { "SMSG_EQUIPMENT_SET_SAVED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x138*/ { "SMSG_PET_CAST_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x139*/ { "MSG_CHANNEL_START", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x13A*/ { "MSG_CHANNEL_UPDATE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x13B*/ { "CMSG_CANCEL_CHANNELLING", STATUS_LOGGEDIN, &WorldSession::HandleCancelChanneling }, + /*0x13C*/ { "SMSG_AI_REACTION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x13D*/ { "CMSG_SET_SELECTION", STATUS_LOGGEDIN, &WorldSession::HandleSetSelectionOpcode }, + /*0x13E*/ { "CMSG_EQUIPMENT_SET_DELETE", STATUS_LOGGEDIN, &WorldSession::HandleEquipmentSetDelete }, + /*0x13F*/ { "CMSG_INSTANCE_LOCK_WARNING_RESPONSE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x140*/ { "CMSG_UNUSED2", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x141*/ { "CMSG_ATTACKSWING", STATUS_LOGGEDIN, &WorldSession::HandleAttackSwingOpcode }, + /*0x142*/ { "CMSG_ATTACKSTOP", STATUS_LOGGEDIN, &WorldSession::HandleAttackStopOpcode }, + /*0x143*/ { "SMSG_ATTACKSTART", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x144*/ { "SMSG_ATTACKSTOP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x145*/ { "SMSG_ATTACKSWING_NOTINRANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x146*/ { "SMSG_ATTACKSWING_BADFACING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x147*/ { "SMSG_INSTANCE_LOCK_WARNING_QUERY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x148*/ { "SMSG_ATTACKSWING_DEADTARGET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x149*/ { "SMSG_ATTACKSWING_CANT_ATTACK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x14A*/ { "SMSG_ATTACKERSTATEUPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x14B*/ { "SMSG_BATTLEFIELD_PORT_DENIED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x14C*/ { "SMSG_DAMAGE_DONE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x14D*/ { "SMSG_DAMAGE_TAKEN_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x14E*/ { "SMSG_CANCEL_COMBAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x14F*/ { "SMSG_SPELLBREAKLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x150*/ { "SMSG_SPELLHEALLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x151*/ { "SMSG_SPELLENERGIZELOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x152*/ { "SMSG_BREAK_TARGET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x153*/ { "CMSG_SAVE_PLAYER", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x154*/ { "CMSG_SETDEATHBINDPOINT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x155*/ { "SMSG_BINDPOINTUPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x156*/ { "CMSG_GETDEATHBINDZONE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x157*/ { "SMSG_BINDZONEREPLY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x158*/ { "SMSG_PLAYERBOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x159*/ { "SMSG_CLIENT_CONTROL_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x15A*/ { "CMSG_REPOP_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleRepopRequestOpcode }, + /*0x15B*/ { "SMSG_RESURRECT_REQUEST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x15C*/ { "CMSG_RESURRECT_RESPONSE", STATUS_LOGGEDIN, &WorldSession::HandleResurrectResponseOpcode }, + /*0x15D*/ { "CMSG_LOOT", STATUS_LOGGEDIN, &WorldSession::HandleLootOpcode }, + /*0x15E*/ { "CMSG_LOOT_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleLootMoneyOpcode }, + /*0x15F*/ { "CMSG_LOOT_RELEASE", STATUS_LOGGEDIN, &WorldSession::HandleLootReleaseOpcode }, + /*0x160*/ { "SMSG_LOOT_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x161*/ { "SMSG_LOOT_RELEASE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x162*/ { "SMSG_LOOT_REMOVED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x163*/ { "SMSG_LOOT_MONEY_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x164*/ { "SMSG_LOOT_ITEM_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x165*/ { "SMSG_LOOT_CLEAR_MONEY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x166*/ { "SMSG_ITEM_PUSH_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x167*/ { "SMSG_DUEL_REQUESTED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x168*/ { "SMSG_DUEL_OUTOFBOUNDS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x169*/ { "SMSG_DUEL_INBOUNDS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x16A*/ { "SMSG_DUEL_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x16B*/ { "SMSG_DUEL_WINNER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x16C*/ { "CMSG_DUEL_ACCEPTED", STATUS_LOGGEDIN, &WorldSession::HandleDuelAcceptedOpcode }, + /*0x16D*/ { "CMSG_DUEL_CANCELLED", STATUS_LOGGEDIN, &WorldSession::HandleDuelCancelledOpcode }, + /*0x16E*/ { "SMSG_MOUNTRESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x16F*/ { "SMSG_DISMOUNTRESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x170*/ { "SMSG_PUREMOUNT_CANCELLED_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x171*/ { "CMSG_MOUNTSPECIAL_ANIM", STATUS_LOGGEDIN, &WorldSession::HandleMountSpecialAnimOpcode }, + /*0x172*/ { "SMSG_MOUNTSPECIAL_ANIM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x173*/ { "SMSG_PET_TAME_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x174*/ { "CMSG_PET_SET_ACTION", STATUS_LOGGEDIN, &WorldSession::HandlePetSetAction }, + /*0x175*/ { "CMSG_PET_ACTION", STATUS_LOGGEDIN, &WorldSession::HandlePetAction }, + /*0x176*/ { "CMSG_PET_ABANDON", STATUS_LOGGEDIN, &WorldSession::HandlePetAbandon }, + /*0x177*/ { "CMSG_PET_RENAME", STATUS_LOGGEDIN, &WorldSession::HandlePetRename }, + /*0x178*/ { "SMSG_PET_NAME_INVALID", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x179*/ { "SMSG_PET_SPELLS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x17A*/ { "SMSG_PET_MODE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x17B*/ { "CMSG_GOSSIP_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleGossipHelloOpcode }, + /*0x17C*/ { "CMSG_GOSSIP_SELECT_OPTION", STATUS_LOGGEDIN, &WorldSession::HandleGossipSelectOptionOpcode }, + /*0x17D*/ { "SMSG_GOSSIP_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x17E*/ { "SMSG_GOSSIP_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x17F*/ { "CMSG_NPC_TEXT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleNpcTextQueryOpcode }, + /*0x180*/ { "SMSG_NPC_TEXT_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x181*/ { "SMSG_NPC_WONT_TALK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x182*/ { "CMSG_QUESTGIVER_STATUS_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverStatusQueryOpcode}, + /*0x183*/ { "SMSG_QUESTGIVER_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x184*/ { "CMSG_QUESTGIVER_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverHelloOpcode }, + /*0x185*/ { "SMSG_QUESTGIVER_QUEST_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x186*/ { "CMSG_QUESTGIVER_QUERY_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverQueryQuestOpcode}, + /*0x187*/ { "CMSG_QUESTGIVER_QUEST_AUTOLAUNCH", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverQuestAutoLaunch }, + /*0x188*/ { "SMSG_QUESTGIVER_QUEST_DETAILS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x189*/ { "CMSG_QUESTGIVER_ACCEPT_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverAcceptQuestOpcode}, + /*0x18A*/ { "CMSG_QUESTGIVER_COMPLETE_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverCompleteQuest }, + /*0x18B*/ { "SMSG_QUESTGIVER_REQUEST_ITEMS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x18C*/ { "CMSG_QUESTGIVER_REQUEST_REWARD", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverRequestRewardOpcode}, + /*0x18D*/ { "SMSG_QUESTGIVER_OFFER_REWARD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x18E*/ { "CMSG_QUESTGIVER_CHOOSE_REWARD", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverChooseRewardOpcode}, + /*0x18F*/ { "SMSG_QUESTGIVER_QUEST_INVALID", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x190*/ { "CMSG_QUESTGIVER_CANCEL", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverCancel }, + /*0x191*/ { "SMSG_QUESTGIVER_QUEST_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x192*/ { "SMSG_QUESTGIVER_QUEST_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x193*/ { "CMSG_QUESTLOG_SWAP_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestLogSwapQuest }, + /*0x194*/ { "CMSG_QUESTLOG_REMOVE_QUEST", STATUS_LOGGEDIN, &WorldSession::HandleQuestLogRemoveQuest }, + /*0x195*/ { "SMSG_QUESTLOG_FULL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x196*/ { "SMSG_QUESTUPDATE_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x197*/ { "SMSG_QUESTUPDATE_FAILEDTIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x198*/ { "SMSG_QUESTUPDATE_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x199*/ { "SMSG_QUESTUPDATE_ADD_KILL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x19A*/ { "SMSG_QUESTUPDATE_ADD_ITEM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x19B*/ { "CMSG_QUEST_CONFIRM_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleQuestConfirmAccept }, + /*0x19C*/ { "SMSG_QUEST_CONFIRM_ACCEPT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x19D*/ { "CMSG_PUSHQUESTTOPARTY", STATUS_LOGGEDIN, &WorldSession::HandlePushQuestToParty }, + /*0x19E*/ { "CMSG_LIST_INVENTORY", STATUS_LOGGEDIN, &WorldSession::HandleListInventoryOpcode }, + /*0x19F*/ { "SMSG_LIST_INVENTORY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1A0*/ { "CMSG_SELL_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSellItemOpcode }, + /*0x1A1*/ { "SMSG_SELL_ITEM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1A2*/ { "CMSG_BUY_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleBuyItemOpcode }, + /*0x1A3*/ { "CMSG_BUY_ITEM_IN_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleBuyItemInSlotOpcode }, + /*0x1A4*/ { "SMSG_BUY_ITEM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1A5*/ { "SMSG_BUY_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1A6*/ { "CMSG_TAXICLEARALLNODES", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x1A7*/ { "CMSG_TAXIENABLEALLNODES", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x1A8*/ { "CMSG_TAXISHOWNODES", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x1A9*/ { "SMSG_SHOWTAXINODES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1AA*/ { "CMSG_TAXINODE_STATUS_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleTaxiNodeStatusQueryOpcode }, + /*0x1AB*/ { "SMSG_TAXINODE_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1AC*/ { "CMSG_TAXIQUERYAVAILABLENODES", STATUS_LOGGEDIN, &WorldSession::HandleTaxiQueryAvailableNodes }, + /*0x1AD*/ { "CMSG_ACTIVATETAXI", STATUS_LOGGEDIN, &WorldSession::HandleActivateTaxiOpcode }, + /*0x1AE*/ { "SMSG_ACTIVATETAXIREPLY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1AF*/ { "SMSG_NEW_TAXI_PATH", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1B0*/ { "CMSG_TRAINER_LIST", STATUS_LOGGEDIN, &WorldSession::HandleTrainerListOpcode }, + /*0x1B1*/ { "SMSG_TRAINER_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1B2*/ { "CMSG_TRAINER_BUY_SPELL", STATUS_LOGGEDIN, &WorldSession::HandleTrainerBuySpellOpcode }, + /*0x1B3*/ { "SMSG_TRAINER_BUY_SUCCEEDED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1B4*/ { "SMSG_TRAINER_BUY_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1B5*/ { "CMSG_BINDER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleBinderActivateOpcode }, + /*0x1B6*/ { "SMSG_PLAYERBINDERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1B7*/ { "CMSG_BANKER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleBankerActivateOpcode }, + /*0x1B8*/ { "SMSG_SHOW_BANK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1B9*/ { "CMSG_BUY_BANK_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleBuyBankSlotOpcode }, + /*0x1BA*/ { "SMSG_BUY_BANK_SLOT_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1BB*/ { "CMSG_PETITION_SHOWLIST", STATUS_LOGGEDIN, &WorldSession::HandlePetitionShowListOpcode }, + /*0x1BC*/ { "SMSG_PETITION_SHOWLIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1BD*/ { "CMSG_PETITION_BUY", STATUS_LOGGEDIN, &WorldSession::HandlePetitionBuyOpcode }, + /*0x1BE*/ { "CMSG_PETITION_SHOW_SIGNATURES", STATUS_LOGGEDIN, &WorldSession::HandlePetitionShowSignOpcode }, + /*0x1BF*/ { "SMSG_PETITION_SHOW_SIGNATURES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1C0*/ { "CMSG_PETITION_SIGN", STATUS_LOGGEDIN, &WorldSession::HandlePetitionSignOpcode }, + /*0x1C1*/ { "SMSG_PETITION_SIGN_RESULTS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1C2*/ { "MSG_PETITION_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandlePetitionDeclineOpcode }, + /*0x1C3*/ { "CMSG_OFFER_PETITION", STATUS_LOGGEDIN, &WorldSession::HandleOfferPetitionOpcode }, + /*0x1C4*/ { "CMSG_TURN_IN_PETITION", STATUS_LOGGEDIN, &WorldSession::HandleTurnInPetitionOpcode }, + /*0x1C5*/ { "SMSG_TURN_IN_PETITION_RESULTS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1C6*/ { "CMSG_PETITION_QUERY", STATUS_LOGGEDIN, &WorldSession::HandlePetitionQueryOpcode }, + /*0x1C7*/ { "SMSG_PETITION_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1C8*/ { "SMSG_FISH_NOT_HOOKED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1C9*/ { "SMSG_FISH_ESCAPED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1CA*/ { "CMSG_BUG", STATUS_LOGGEDIN, &WorldSession::HandleBugOpcode }, + /*0x1CB*/ { "SMSG_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1CC*/ { "CMSG_PLAYED_TIME", STATUS_LOGGEDIN, &WorldSession::HandlePlayedTime }, + /*0x1CD*/ { "SMSG_PLAYED_TIME", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1CE*/ { "CMSG_QUERY_TIME", STATUS_LOGGEDIN, &WorldSession::HandleQueryTimeOpcode }, + /*0x1CF*/ { "SMSG_QUERY_TIME_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1D0*/ { "SMSG_LOG_XPGAIN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1D1*/ { "SMSG_AURACASTLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1D2*/ { "CMSG_RECLAIM_CORPSE", STATUS_LOGGEDIN, &WorldSession::HandleReclaimCorpseOpcode }, + /*0x1D3*/ { "CMSG_WRAP_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleWrapItemOpcode }, + /*0x1D4*/ { "SMSG_LEVELUP_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1D5*/ { "MSG_MINIMAP_PING", STATUS_LOGGEDIN, &WorldSession::HandleMinimapPingOpcode }, + /*0x1D6*/ { "SMSG_RESISTLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1D7*/ { "SMSG_ENCHANTMENTLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1D8*/ { "CMSG_SET_SKILL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x1D9*/ { "SMSG_START_MIRROR_TIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1DA*/ { "SMSG_PAUSE_MIRROR_TIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1DB*/ { "SMSG_STOP_MIRROR_TIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1DC*/ { "CMSG_PING", STATUS_NEVER, &WorldSession::Handle_EarlyProccess }, + /*0x1DD*/ { "SMSG_PONG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1DE*/ { "SMSG_CLEAR_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1DF*/ { "SMSG_GAMEOBJECT_PAGETEXT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1E0*/ { "CMSG_SETSHEATHED", STATUS_LOGGEDIN, &WorldSession::HandleSetSheathedOpcode }, + /*0x1E1*/ { "SMSG_COOLDOWN_CHEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1E2*/ { "SMSG_SPELL_DELAYED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1E3*/ { "CMSG_QUEST_POI_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleQuestPOIQuery }, + /*0x1E4*/ { "SMSG_QUEST_POI_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1E5*/ { "CMSG_GHOST", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x1E6*/ { "CMSG_GM_INVIS", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x1E7*/ { "SMSG_INVALID_PROMOTION_CODE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1E8*/ { "MSG_GM_BIND_OTHER", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x1E9*/ { "MSG_GM_SUMMON", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x1EA*/ { "SMSG_ITEM_TIME_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1EB*/ { "SMSG_ITEM_ENCHANT_TIME_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1EC*/ { "SMSG_AUTH_CHALLENGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1ED*/ { "CMSG_AUTH_SESSION", STATUS_NEVER, &WorldSession::Handle_EarlyProccess }, + /*0x1EE*/ { "SMSG_AUTH_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1EF*/ { "MSG_GM_SHOWLABEL", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x1F0*/ { "CMSG_PET_CAST_SPELL", STATUS_LOGGEDIN, &WorldSession::HandlePetCastSpellOpcode }, + /*0x1F1*/ { "MSG_SAVE_GUILD_EMBLEM", STATUS_LOGGEDIN, &WorldSession::HandleSaveGuildEmblemOpcode }, + /*0x1F2*/ { "MSG_TABARDVENDOR_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleTabardVendorActivateOpcode}, + /*0x1F3*/ { "SMSG_PLAY_SPELL_VISUAL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1F4*/ { "CMSG_ZONEUPDATE", STATUS_LOGGEDIN, &WorldSession::HandleZoneUpdateOpcode }, + /*0x1F5*/ { "SMSG_PARTYKILLLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1F6*/ { "SMSG_COMPRESSED_UPDATE_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1F7*/ { "SMSG_PLAY_SPELL_IMPACT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1F8*/ { "SMSG_EXPLORATION_EXPERIENCE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1F9*/ { "CMSG_GM_SET_SECURITY_GROUP", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x1FA*/ { "CMSG_GM_NUKE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x1FB*/ { "MSG_RANDOM_ROLL", STATUS_LOGGEDIN, &WorldSession::HandleRandomRollOpcode }, + /*0x1FC*/ { "SMSG_ENVIRONMENTALDAMAGELOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1FD*/ { "CMSG_PLAYER_DIFFICULTY_CHANGE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x1FE*/ { "SMSG_RWHOIS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x1FF*/ { "SMSG_LFG_PLAYER_REWARD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x200*/ { "SMSG_LFG_TELEPORT_DENIED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x201*/ { "CMSG_UNLEARN_SPELL", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x202*/ { "CMSG_UNLEARN_SKILL", STATUS_LOGGEDIN, &WorldSession::HandleUnlearnSkillOpcode }, + /*0x203*/ { "SMSG_REMOVED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x204*/ { "CMSG_DECHARGE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x205*/ { "CMSG_GMTICKET_CREATE", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketCreateOpcode }, + /*0x206*/ { "SMSG_GMTICKET_CREATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x207*/ { "CMSG_GMTICKET_UPDATETEXT", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketUpdateOpcode }, + /*0x208*/ { "SMSG_GMTICKET_UPDATETEXT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x209*/ { "SMSG_ACCOUNT_DATA_TIMES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x20A*/ { "CMSG_REQUEST_ACCOUNT_DATA", STATUS_AUTHED, &WorldSession::HandleRequestAccountData }, + /*0x20B*/ { "CMSG_UPDATE_ACCOUNT_DATA", STATUS_AUTHED, &WorldSession::HandleUpdateAccountData }, + /*0x20C*/ { "SMSG_UPDATE_ACCOUNT_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x20D*/ { "SMSG_CLEAR_FAR_SIGHT_IMMEDIATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x20E*/ { "SMSG_PLAYER_DIFFICULTY_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x20F*/ { "CMSG_GM_TEACH", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x210*/ { "CMSG_GM_CREATE_ITEM_TARGET", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x211*/ { "CMSG_GMTICKET_GETTICKET", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketGetTicketOpcode }, + /*0x212*/ { "SMSG_GMTICKET_GETTICKET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x213*/ { "CMSG_UNLEARN_TALENTS", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x214*/ { "SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x215*/ { "SMSG_GAMEOBJECT_DESPAWN_ANIM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x216*/ { "MSG_CORPSE_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleCorpseQueryOpcode }, + /*0x217*/ { "CMSG_GMTICKET_DELETETICKET", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketDeleteOpcode }, + /*0x218*/ { "SMSG_GMTICKET_DELETETICKET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x219*/ { "SMSG_CHAT_WRONG_FACTION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x21A*/ { "CMSG_GMTICKET_SYSTEMSTATUS", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketSystemStatusOpcode}, + /*0x21B*/ { "SMSG_GMTICKET_SYSTEMSTATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x21C*/ { "CMSG_SPIRIT_HEALER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleSpiritHealerActivateOpcode}, + /*0x21D*/ { "CMSG_SET_STAT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x21E*/ { "SMSG_SET_REST_START_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x21F*/ { "CMSG_SKILL_BUY_STEP", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x220*/ { "CMSG_SKILL_BUY_RANK", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x221*/ { "CMSG_XP_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x222*/ { "SMSG_SPIRIT_HEALER_CONFIRM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x223*/ { "CMSG_CHARACTER_POINT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x224*/ { "SMSG_GOSSIP_POI", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x225*/ { "CMSG_CHAT_IGNORED", STATUS_LOGGEDIN, &WorldSession::HandleChatIgnoredOpcode }, + /*0x226*/ { "CMSG_GM_VISION", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x227*/ { "CMSG_SERVER_COMMAND", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x228*/ { "CMSG_GM_SILENCE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x229*/ { "CMSG_GM_REVEALTO", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x22A*/ { "CMSG_GM_RESURRECT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x22B*/ { "CMSG_GM_SUMMONMOB", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x22C*/ { "CMSG_GM_MOVECORPSE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x22D*/ { "CMSG_GM_FREEZE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x22E*/ { "CMSG_GM_UBERINVIS", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x22F*/ { "CMSG_GM_REQUEST_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x230*/ { "SMSG_GM_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x231*/ { "CMSG_GUILD_RANK", STATUS_LOGGEDIN, &WorldSession::HandleGuildRankOpcode }, + /*0x232*/ { "CMSG_GUILD_ADD_RANK", STATUS_LOGGEDIN, &WorldSession::HandleGuildAddRankOpcode }, + /*0x233*/ { "CMSG_GUILD_DEL_RANK", STATUS_LOGGEDIN, &WorldSession::HandleGuildDelRankOpcode }, + /*0x234*/ { "CMSG_GUILD_SET_PUBLIC_NOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildSetPublicNoteOpcode }, + /*0x235*/ { "CMSG_GUILD_SET_OFFICER_NOTE", STATUS_LOGGEDIN, &WorldSession::HandleGuildSetOfficerNoteOpcode }, + /*0x236*/ { "SMSG_LOGIN_VERIFY_WORLD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x237*/ { "CMSG_CLEAR_EXPLORATION", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x238*/ { "CMSG_SEND_MAIL", STATUS_LOGGEDIN, &WorldSession::HandleSendMail }, + /*0x239*/ { "SMSG_SEND_MAIL_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x23A*/ { "CMSG_GET_MAIL_LIST", STATUS_LOGGEDIN, &WorldSession::HandleGetMailList }, + /*0x23B*/ { "SMSG_MAIL_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x23C*/ { "CMSG_BATTLEFIELD_LIST", STATUS_LOGGEDIN, &WorldSession::HandleBattlefieldListOpcode }, + /*0x23D*/ { "SMSG_BATTLEFIELD_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x23E*/ { "CMSG_BATTLEFIELD_JOIN", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x23F*/ { "SMSG_BATTLEFIELD_WIN_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x240*/ { "SMSG_BATTLEFIELD_LOSE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x241*/ { "CMSG_TAXICLEARNODE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x242*/ { "CMSG_TAXIENABLENODE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x243*/ { "CMSG_ITEM_TEXT_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleItemTextQuery }, + /*0x244*/ { "SMSG_ITEM_TEXT_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x245*/ { "CMSG_MAIL_TAKE_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleMailTakeMoney }, + /*0x246*/ { "CMSG_MAIL_TAKE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleMailTakeItem }, + /*0x247*/ { "CMSG_MAIL_MARK_AS_READ", STATUS_LOGGEDIN, &WorldSession::HandleMailMarkAsRead }, + /*0x248*/ { "CMSG_MAIL_RETURN_TO_SENDER", STATUS_LOGGEDIN, &WorldSession::HandleMailReturnToSender }, + /*0x249*/ { "CMSG_MAIL_DELETE", STATUS_LOGGEDIN, &WorldSession::HandleMailDelete }, + /*0x24A*/ { "CMSG_MAIL_CREATE_TEXT_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleMailCreateTextItem }, + /*0x24B*/ { "SMSG_SPELLLOGMISS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x24C*/ { "SMSG_SPELLLOGEXECUTE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x24D*/ { "SMSG_DEBUGAURAPROC", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x24E*/ { "SMSG_PERIODICAURALOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x24F*/ { "SMSG_SPELLDAMAGESHIELD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x250*/ { "SMSG_SPELLNONMELEEDAMAGELOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x251*/ { "CMSG_LEARN_TALENT", STATUS_LOGGEDIN, &WorldSession::HandleLearnTalentOpcode }, + /*0x252*/ { "SMSG_RESURRECT_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x253*/ { "CMSG_TOGGLE_PVP", STATUS_LOGGEDIN, &WorldSession::HandleTogglePvP }, + /*0x254*/ { "SMSG_ZONE_UNDER_ATTACK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x255*/ { "MSG_AUCTION_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleAuctionHelloOpcode }, + /*0x256*/ { "CMSG_AUCTION_SELL_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAuctionSellItem }, + /*0x257*/ { "CMSG_AUCTION_REMOVE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAuctionRemoveItem }, + /*0x258*/ { "CMSG_AUCTION_LIST_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListItems }, + /*0x259*/ { "CMSG_AUCTION_LIST_OWNER_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListOwnerItems }, + /*0x25A*/ { "CMSG_AUCTION_PLACE_BID", STATUS_LOGGEDIN, &WorldSession::HandleAuctionPlaceBid }, + /*0x25B*/ { "SMSG_AUCTION_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x25C*/ { "SMSG_AUCTION_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x25D*/ { "SMSG_AUCTION_OWNER_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x25E*/ { "SMSG_AUCTION_BIDDER_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x25F*/ { "SMSG_AUCTION_OWNER_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x260*/ { "SMSG_PROCRESIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x261*/ { "SMSG_STANDSTATE_CHANGE_FAILURE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x262*/ { "SMSG_DISPEL_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x263*/ { "SMSG_SPELLORDAMAGE_IMMUNE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x264*/ { "CMSG_AUCTION_LIST_BIDDER_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListBidderItems }, + /*0x265*/ { "SMSG_AUCTION_BIDDER_LIST_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x266*/ { "SMSG_SET_FLAT_SPELL_MODIFIER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x267*/ { "SMSG_SET_PCT_SPELL_MODIFIER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x268*/ { "CMSG_SET_AMMO", STATUS_LOGGEDIN, &WorldSession::HandleSetAmmoOpcode }, + /*0x269*/ { "SMSG_CORPSE_RECLAIM_DELAY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x26A*/ { "CMSG_SET_ACTIVE_MOVER", STATUS_LOGGEDIN, &WorldSession::HandleSetActiveMoverOpcode }, + /*0x26B*/ { "CMSG_PET_CANCEL_AURA", STATUS_LOGGEDIN, &WorldSession::HandlePetCancelAuraOpcode }, + /*0x26C*/ { "CMSG_PLAYER_AI_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x26D*/ { "CMSG_CANCEL_AUTO_REPEAT_SPELL", STATUS_LOGGEDIN, &WorldSession::HandleCancelAutoRepeatSpellOpcode}, + /*0x26E*/ { "MSG_GM_ACCOUNT_ONLINE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x26F*/ { "MSG_LIST_STABLED_PETS", STATUS_LOGGEDIN, &WorldSession::HandleListStabledPetsOpcode }, + /*0x270*/ { "CMSG_STABLE_PET", STATUS_LOGGEDIN, &WorldSession::HandleStablePet }, + /*0x271*/ { "CMSG_UNSTABLE_PET", STATUS_LOGGEDIN, &WorldSession::HandleUnstablePet }, + /*0x272*/ { "CMSG_BUY_STABLE_SLOT", STATUS_LOGGEDIN, &WorldSession::HandleBuyStableSlot }, + /*0x273*/ { "SMSG_STABLE_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x274*/ { "CMSG_STABLE_REVIVE_PET", STATUS_LOGGEDIN, &WorldSession::HandleStableRevivePet }, + /*0x275*/ { "CMSG_STABLE_SWAP_PET", STATUS_LOGGEDIN, &WorldSession::HandleStableSwapPet }, + /*0x276*/ { "MSG_QUEST_PUSH_RESULT", STATUS_LOGGEDIN, &WorldSession::HandleQuestPushResult }, + /*0x277*/ { "SMSG_PLAY_MUSIC", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x278*/ { "SMSG_PLAY_OBJECT_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x279*/ { "CMSG_REQUEST_PET_INFO", STATUS_LOGGEDIN, &WorldSession::HandleRequestPetInfoOpcode }, + /*0x27A*/ { "CMSG_FAR_SIGHT", STATUS_LOGGEDIN, &WorldSession::HandleFarSightOpcode }, + /*0x27B*/ { "SMSG_SPELLDISPELLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x27C*/ { "SMSG_DAMAGE_CALC_LOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x27D*/ { "CMSG_ENABLE_DAMAGE_LOG", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x27E*/ { "CMSG_GROUP_CHANGE_SUB_GROUP", STATUS_LOGGEDIN, &WorldSession::HandleGroupChangeSubGroupOpcode }, + /*0x27F*/ { "CMSG_REQUEST_PARTY_MEMBER_STATS", STATUS_LOGGEDIN, &WorldSession::HandleRequestPartyMemberStatsOpcode}, + /*0x280*/ { "CMSG_GROUP_SWAP_SUB_GROUP", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x281*/ { "CMSG_RESET_FACTION_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x282*/ { "CMSG_AUTOSTORE_BANK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoStoreBankItemOpcode }, + /*0x283*/ { "CMSG_AUTOBANK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleAutoBankItemOpcode }, + /*0x284*/ { "MSG_QUERY_NEXT_MAIL_TIME", STATUS_LOGGEDIN, &WorldSession::HandleQueryNextMailTime }, + /*0x285*/ { "SMSG_RECEIVED_MAIL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x286*/ { "SMSG_RAID_GROUP_ONLY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x287*/ { "CMSG_SET_DURABILITY_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x288*/ { "CMSG_SET_PVP_RANK_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x289*/ { "CMSG_ADD_PVP_MEDAL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x28A*/ { "CMSG_DEL_PVP_MEDAL_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x28B*/ { "CMSG_SET_PVP_TITLE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x28C*/ { "SMSG_PVP_CREDIT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x28D*/ { "SMSG_AUCTION_REMOVED_NOTIFICATION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x28E*/ { "CMSG_GROUP_RAID_CONVERT", STATUS_LOGGEDIN, &WorldSession::HandleGroupRaidConvertOpcode }, + /*0x28F*/ { "CMSG_GROUP_ASSISTANT_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGroupAssistantLeaderOpcode}, + /*0x290*/ { "CMSG_BUYBACK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleBuybackItem }, + /*0x291*/ { "SMSG_SERVER_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x292*/ { "CMSG_SET_SAVED_INSTANCE_EXTEND", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x293*/ { "SMSG_LFG_OFFER_CONTINUE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x294*/ { "CMSG_MEETINGSTONE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x295*/ { "SMSG_MEETINGSTONE_SETQUEUE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x296*/ { "CMSG_MEETINGSTONE_INFO", STATUS_LOGGEDIN, &WorldSession::HandleMeetingStoneInfo }, + /*0x297*/ { "SMSG_MEETINGSTONE_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x298*/ { "SMSG_MEETINGSTONE_IN_PROGRESS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x299*/ { "SMSG_MEETINGSTONE_MEMBER_ADDED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x29A*/ { "CMSG_GMTICKETSYSTEM_TOGGLE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x29B*/ { "CMSG_CANCEL_GROWTH_AURA", STATUS_LOGGEDIN, &WorldSession::HandleCancelGrowthAuraOpcode }, + /*0x29C*/ { "SMSG_CANCEL_AUTO_REPEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x29D*/ { "SMSG_STANDSTATE_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x29E*/ { "SMSG_LOOT_ALL_PASSED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x29F*/ { "SMSG_LOOT_ROLL_WON", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2A0*/ { "CMSG_LOOT_ROLL", STATUS_LOGGEDIN, &WorldSession::HandleLootRoll }, + /*0x2A1*/ { "SMSG_LOOT_START_ROLL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2A2*/ { "SMSG_LOOT_ROLL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2A3*/ { "CMSG_LOOT_MASTER_GIVE", STATUS_LOGGEDIN, &WorldSession::HandleLootMasterGiveOpcode }, + /*0x2A4*/ { "SMSG_LOOT_MASTER_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2A5*/ { "SMSG_SET_FORCED_REACTIONS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2A6*/ { "SMSG_SPELL_FAILED_OTHER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2A7*/ { "SMSG_GAMEOBJECT_RESET_STATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2A8*/ { "CMSG_REPAIR_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleRepairItemOpcode }, + /*0x2A9*/ { "SMSG_CHAT_PLAYER_NOT_FOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2AA*/ { "MSG_TALENT_WIPE_CONFIRM", STATUS_LOGGEDIN, &WorldSession::HandleTalentWipeConfirmOpcode }, + /*0x2AB*/ { "SMSG_SUMMON_REQUEST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2AC*/ { "CMSG_SUMMON_RESPONSE", STATUS_LOGGEDIN, &WorldSession::HandleSummonResponseOpcode }, + /*0x2AD*/ { "MSG_MOVE_TOGGLE_GRAVITY_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x2AE*/ { "SMSG_MONSTER_MOVE_TRANSPORT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2AF*/ { "SMSG_PET_BROKEN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2B0*/ { "MSG_MOVE_FEATHER_FALL", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x2B1*/ { "MSG_MOVE_WATER_WALK", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x2B2*/ { "CMSG_SERVER_BROADCAST", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x2B3*/ { "CMSG_SELF_RES", STATUS_LOGGEDIN, &WorldSession::HandleSelfResOpcode }, + /*0x2B4*/ { "SMSG_FEIGN_DEATH_RESISTED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2B5*/ { "CMSG_RUN_SCRIPT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x2B6*/ { "SMSG_SCRIPT_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2B7*/ { "SMSG_DUEL_COUNTDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2B8*/ { "SMSG_AREA_TRIGGER_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2B9*/ { "CMSG_SHOWING_HELM", STATUS_LOGGEDIN, &WorldSession::HandleShowingHelmOpcode }, + /*0x2BA*/ { "CMSG_SHOWING_CLOAK", STATUS_LOGGEDIN, &WorldSession::HandleShowingCloakOpcode }, + /*0x2BB*/ { "SMSG_LFG_ROLE_CHOSEN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2BC*/ { "SMSG_PLAYER_SKINNED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2BD*/ { "SMSG_DURABILITY_DAMAGE_DEATH", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2BE*/ { "CMSG_SET_EXPLORATION", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x2BF*/ { "CMSG_SET_ACTIONBAR_TOGGLES", STATUS_AUTHED, &WorldSession::HandleSetActionBarToggles }, + /*0x2C0*/ { "UMSG_DELETE_GUILD_CHARTER", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x2C1*/ { "MSG_PETITION_RENAME", STATUS_LOGGEDIN, &WorldSession::HandlePetitionRenameOpcode }, + /*0x2C2*/ { "SMSG_INIT_WORLD_STATES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2C3*/ { "SMSG_UPDATE_WORLD_STATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2C4*/ { "CMSG_ITEM_NAME_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleItemNameQueryOpcode }, + /*0x2C5*/ { "SMSG_ITEM_NAME_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2C6*/ { "SMSG_PET_ACTION_FEEDBACK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2C7*/ { "CMSG_CHAR_RENAME", STATUS_AUTHED, &WorldSession::HandleCharRenameOpcode }, + /*0x2C8*/ { "SMSG_CHAR_RENAME", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2C9*/ { "CMSG_MOVE_SPLINE_DONE", STATUS_LOGGEDIN, &WorldSession::HandleMoveSplineDoneOpcode }, + /*0x2CA*/ { "CMSG_MOVE_FALL_RESET", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x2CB*/ { "SMSG_INSTANCE_SAVE_CREATED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2CC*/ { "SMSG_RAID_INSTANCE_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2CD*/ { "CMSG_REQUEST_RAID_INFO", STATUS_LOGGEDIN, &WorldSession::HandleRequestRaidInfoOpcode }, + /*0x2CE*/ { "CMSG_MOVE_TIME_SKIPPED", STATUS_LOGGEDIN, &WorldSession::HandleMoveTimeSkippedOpcode }, + /*0x2CF*/ { "CMSG_MOVE_FEATHER_FALL_ACK", STATUS_LOGGEDIN, &WorldSession::HandleFeatherFallAck }, + /*0x2D0*/ { "CMSG_MOVE_WATER_WALK_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveWaterWalkAck }, + /*0x2D1*/ { "CMSG_MOVE_NOT_ACTIVE_MOVER", STATUS_LOGGEDIN, &WorldSession::HandleMoveNotActiveMover }, + /*0x2D2*/ { "SMSG_PLAY_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2D3*/ { "CMSG_BATTLEFIELD_STATUS", STATUS_LOGGEDIN, &WorldSession::HandleBattlefieldStatusOpcode }, + /*0x2D4*/ { "SMSG_BATTLEFIELD_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2D5*/ { "CMSG_BATTLEFIELD_PORT", STATUS_LOGGEDIN, &WorldSession::HandleBattleFieldPortOpcode }, + /*0x2D6*/ { "MSG_INSPECT_HONOR_STATS", STATUS_LOGGEDIN, &WorldSession::HandleInspectHonorStatsOpcode }, + /*0x2D7*/ { "CMSG_BATTLEMASTER_HELLO", STATUS_LOGGEDIN, &WorldSession::HandleBattlemasterHelloOpcode }, + /*0x2D8*/ { "CMSG_MOVE_START_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x2D9*/ { "CMSG_MOVE_STOP_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x2DA*/ { "SMSG_FORCE_WALK_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2DB*/ { "CMSG_FORCE_WALK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, + /*0x2DC*/ { "SMSG_FORCE_SWIM_BACK_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2DD*/ { "CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, + /*0x2DE*/ { "SMSG_FORCE_TURN_RATE_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2DF*/ { "CMSG_FORCE_TURN_RATE_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, + /*0x2E0*/ { "MSG_PVP_LOG_DATA", STATUS_LOGGEDIN, &WorldSession::HandlePVPLogDataOpcode }, + /*0x2E1*/ { "CMSG_LEAVE_BATTLEFIELD", STATUS_LOGGEDIN, &WorldSession::HandleLeaveBattlefieldOpcode }, + /*0x2E2*/ { "CMSG_AREA_SPIRIT_HEALER_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleAreaSpiritHealerQueryOpcode}, + /*0x2E3*/ { "CMSG_AREA_SPIRIT_HEALER_QUEUE", STATUS_LOGGEDIN, &WorldSession::HandleAreaSpiritHealerQueueOpcode}, + /*0x2E4*/ { "SMSG_AREA_SPIRIT_HEALER_TIME", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2E5*/ { "CMSG_GM_UNTEACH", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x2E6*/ { "SMSG_WARDEN_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2E7*/ { "CMSG_WARDEN_DATA", STATUS_LOGGEDIN, &WorldSession::HandleWardenDataOpcode }, + /*0x2E8*/ { "SMSG_GROUP_JOINED_BATTLEGROUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2E9*/ { "MSG_BATTLEGROUND_PLAYER_POSITIONS", STATUS_LOGGEDIN, &WorldSession::HandleBattleGroundPlayerPositionsOpcode}, + /*0x2EA*/ { "CMSG_PET_STOP_ATTACK", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x2EB*/ { "SMSG_BINDER_CONFIRM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2EC*/ { "SMSG_BATTLEGROUND_PLAYER_JOINED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2ED*/ { "SMSG_BATTLEGROUND_PLAYER_LEFT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2EE*/ { "CMSG_BATTLEMASTER_JOIN", STATUS_LOGGEDIN, &WorldSession::HandleBattlemasterJoinOpcode }, + /*0x2EF*/ { "SMSG_ADDON_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2F0*/ { "CMSG_PET_UNLEARN", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x2F1*/ { "SMSG_PET_UNLEARN_CONFIRM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2F2*/ { "SMSG_PARTY_MEMBER_STATS_FULL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2F3*/ { "CMSG_PET_SPELL_AUTOCAST", STATUS_LOGGEDIN, &WorldSession::HandlePetSpellAutocastOpcode }, + /*0x2F4*/ { "SMSG_WEATHER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2F5*/ { "SMSG_PLAY_TIME_WARNING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2F6*/ { "SMSG_MINIGAME_SETUP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2F7*/ { "SMSG_MINIGAME_STATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2F8*/ { "CMSG_MINIGAME_MOVE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x2F9*/ { "SMSG_MINIGAME_MOVE_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2FA*/ { "SMSG_RAID_INSTANCE_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2FB*/ { "SMSG_COMPRESSED_MOVES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2FC*/ { "CMSG_GUILD_INFO_TEXT", STATUS_LOGGEDIN, &WorldSession::HandleGuildChangeInfoTextOpcode }, + /*0x2FD*/ { "SMSG_CHAT_RESTRICTED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2FE*/ { "SMSG_SPLINE_SET_RUN_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x2FF*/ { "SMSG_SPLINE_SET_RUN_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x300*/ { "SMSG_SPLINE_SET_SWIM_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x301*/ { "SMSG_SPLINE_SET_WALK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x302*/ { "SMSG_SPLINE_SET_SWIM_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x303*/ { "SMSG_SPLINE_SET_TURN_RATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x304*/ { "SMSG_SPLINE_MOVE_UNROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x305*/ { "SMSG_SPLINE_MOVE_FEATHER_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x306*/ { "SMSG_SPLINE_MOVE_NORMAL_FALL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x307*/ { "SMSG_SPLINE_MOVE_SET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x308*/ { "SMSG_SPLINE_MOVE_UNSET_HOVER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x309*/ { "SMSG_SPLINE_MOVE_WATER_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x30A*/ { "SMSG_SPLINE_MOVE_LAND_WALK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x30B*/ { "SMSG_SPLINE_MOVE_START_SWIM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x30C*/ { "SMSG_SPLINE_MOVE_STOP_SWIM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x30D*/ { "SMSG_SPLINE_MOVE_SET_RUN_MODE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x30E*/ { "SMSG_SPLINE_MOVE_SET_WALK_MODE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x30F*/ { "CMSG_GM_NUKE_ACCOUNT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x310*/ { "MSG_GM_DESTROY_CORPSE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x311*/ { "CMSG_GM_DESTROY_ONLINE_CORPSE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x312*/ { "CMSG_ACTIVATETAXIEXPRESS", STATUS_LOGGEDIN, &WorldSession::HandleActivateTaxiExpressOpcode }, + /*0x313*/ { "SMSG_SET_FACTION_ATWAR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x314*/ { "SMSG_GAMETIMEBIAS_SET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x315*/ { "CMSG_DEBUG_ACTIONS_START", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x316*/ { "CMSG_DEBUG_ACTIONS_STOP", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x317*/ { "CMSG_SET_FACTION_INACTIVE", STATUS_LOGGEDIN, &WorldSession::HandleSetFactionInactiveOpcode }, + /*0x318*/ { "CMSG_SET_WATCHED_FACTION", STATUS_LOGGEDIN, &WorldSession::HandleSetWatchedFactionOpcode }, + /*0x319*/ { "MSG_MOVE_TIME_SKIPPED", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x31A*/ { "SMSG_SPLINE_MOVE_ROOT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x31B*/ { "CMSG_SET_EXPLORATION_ALL", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x31C*/ { "SMSG_INVALIDATE_PLAYER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x31D*/ { "CMSG_RESET_INSTANCES", STATUS_LOGGEDIN, &WorldSession::HandleResetInstancesOpcode }, + /*0x31E*/ { "SMSG_INSTANCE_RESET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x31F*/ { "SMSG_INSTANCE_RESET_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x320*/ { "SMSG_UPDATE_LAST_INSTANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x321*/ { "MSG_RAID_TARGET_UPDATE", STATUS_LOGGEDIN, &WorldSession::HandleRaidTargetUpdateOpcode }, + /*0x322*/ { "MSG_RAID_READY_CHECK", STATUS_LOGGEDIN, &WorldSession::HandleRaidReadyCheckOpcode }, + /*0x323*/ { "CMSG_LUA_USAGE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x324*/ { "SMSG_PET_ACTION_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x325*/ { "SMSG_PET_DISMISS_SOUND", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x326*/ { "SMSG_GHOSTEE_GONE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x327*/ { "CMSG_GM_UPDATE_TICKET_STATUS", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x328*/ { "SMSG_GM_TICKET_STATUS_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x329*/ { "MSG_SET_DUNGEON_DIFFICULTY", STATUS_LOGGEDIN, &WorldSession::HandleSetDungeonDifficultyOpcode}, + /*0x32A*/ { "CMSG_GMSURVEY_SUBMIT", STATUS_NEVER, &WorldSession::Handle_NULL },//LOGGEDIN, &WorldSession::HandleGMSurveySubmit }, + /*0x32B*/ { "SMSG_UPDATE_INSTANCE_OWNERSHIP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x32C*/ { "CMSG_IGNORE_KNOCKBACK_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x32D*/ { "SMSG_CHAT_PLAYER_AMBIGUOUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x32E*/ { "MSG_DELAY_GHOST_TELEPORT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x32F*/ { "SMSG_SPELLINSTAKILLLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x330*/ { "SMSG_SPELL_UPDATE_CHAIN_TARGETS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x331*/ { "CMSG_CHAT_FILTERED", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x332*/ { "SMSG_EXPECTED_SPAM_RECORDS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x333*/ { "SMSG_SPELLSTEALLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x334*/ { "CMSG_LOTTERY_QUERY_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x335*/ { "SMSG_LOTTERY_QUERY_RESULT_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x336*/ { "CMSG_BUY_LOTTERY_TICKET_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x337*/ { "SMSG_LOTTERY_RESULT_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x338*/ { "SMSG_CHARACTER_PROFILE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x339*/ { "SMSG_CHARACTER_PROFILE_REALM_CONNECTED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x33A*/ { "SMSG_DEFENSE_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x33B*/ { "SMSG_INSTANCE_DIFFICULTY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x33C*/ { "MSG_GM_RESETINSTANCELIMIT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x33D*/ { "SMSG_MOTD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x33E*/ { "SMSG_MOVE_SET_FLIGHT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x33F*/ { "SMSG_MOVE_UNSET_FLIGHT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x340*/ { "CMSG_MOVE_FLIGHT_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x341*/ { "MSG_MOVE_START_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x342*/ { "MSG_MOVE_STOP_SWIM_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x343*/ { "SMSG_MOVE_SET_CAN_FLY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x344*/ { "SMSG_MOVE_UNSET_CAN_FLY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x345*/ { "CMSG_MOVE_SET_CAN_FLY_ACK", STATUS_LOGGEDIN, &WorldSession::HandleMoveSetCanFlyAckOpcode }, + /*0x346*/ { "CMSG_MOVE_SET_FLY", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x347*/ { "CMSG_SOCKET_GEMS", STATUS_LOGGEDIN, &WorldSession::HandleSocketOpcode }, + /*0x348*/ { "CMSG_ARENA_TEAM_CREATE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x349*/ { "SMSG_ARENA_TEAM_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x34A*/ { "UMSG_UPDATE_ARENA_TEAM_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x34B*/ { "CMSG_ARENA_TEAM_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamQueryOpcode }, + /*0x34C*/ { "SMSG_ARENA_TEAM_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x34D*/ { "CMSG_ARENA_TEAM_ROSTER", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamRosterOpcode }, + /*0x34E*/ { "SMSG_ARENA_TEAM_ROSTER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x34F*/ { "CMSG_ARENA_TEAM_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamInviteOpcode }, + /*0x350*/ { "SMSG_ARENA_TEAM_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x351*/ { "CMSG_ARENA_TEAM_ACCEPT", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamAcceptOpcode }, + /*0x352*/ { "CMSG_ARENA_TEAM_DECLINE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamDeclineOpcode }, + /*0x353*/ { "CMSG_ARENA_TEAM_LEAVE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamLeaveOpcode }, + /*0x354*/ { "CMSG_ARENA_TEAM_REMOVE", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamRemoveOpcode }, + /*0x355*/ { "CMSG_ARENA_TEAM_DISBAND", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamDisbandOpcode }, + /*0x356*/ { "CMSG_ARENA_TEAM_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleArenaTeamLeaderOpcode }, + /*0x357*/ { "SMSG_ARENA_TEAM_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x358*/ { "CMSG_BATTLEMASTER_JOIN_ARENA", STATUS_LOGGEDIN, &WorldSession::HandleBattlemasterJoinArena }, + /*0x359*/ { "MSG_MOVE_START_ASCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x35A*/ { "MSG_MOVE_STOP_ASCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x35B*/ { "SMSG_ARENA_TEAM_STATS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x35C*/ { "CMSG_LFG_JOIN", STATUS_LOGGEDIN, &WorldSession::HandleLfgJoinOpcode }, + /*0x35D*/ { "CMSG_LFG_LEAVE", STATUS_LOGGEDIN, &WorldSession::HandleLfgLeaveOpcode }, + /*0x35E*/ { "CMSG_SEARCH_LFG_JOIN", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x35F*/ { "CMSG_SEARCH_LFG_LEAVE", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x360*/ { "SMSG_UPDATE_LFG_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x361*/ { "SMSG_LFG_PROPOSAL_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x362*/ { "CMSG_LFG_PROPOSAL_RESULT", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x363*/ { "SMSG_LFG_ROLE_CHECK_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x364*/ { "SMSG_LFG_JOIN_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x365*/ { "SMSG_LFG_QUEUE_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x366*/ { "CMSG_SET_LFG_COMMENT", STATUS_LOGGEDIN, &WorldSession::HandleSetLfgCommentOpcode }, + /*0x367*/ { "SMSG_LFG_UPDATE_PLAYER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x368*/ { "SMSG_LFG_UPDATE_PARTY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x369*/ { "SMSG_LFG_UPDATE_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x36A*/ { "CMSG_LFG_SET_ROLES", STATUS_LOGGEDIN, &WorldSession::HandleLfgSetRolesOpcode }, + /*0x36B*/ { "CMSG_LFG_SET_NEEDS", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x36C*/ { "CMSG_LFG_SET_BOOT_VOTE", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x36D*/ { "SMSG_LFG_BOOT_PROPOSAL_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x36E*/ { "CMSG_LFD_PLAYER_LOCK_INFO_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleLfgPlayerLockInfoRequestOpcode}, + /*0x36F*/ { "SMSG_LFG_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x370*/ { "CMSG_LFG_TELEPORT", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x371*/ { "CMSG_LFD_PARTY_LOCK_INFO_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleLfgPartyLockInfoRequestOpcode}, + /*0x372*/ { "SMSG_LFG_PARTY_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x373*/ { "SMSG_TITLE_EARNED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x374*/ { "CMSG_SET_TITLE", STATUS_LOGGEDIN, &WorldSession::HandleSetTitleOpcode }, + /*0x375*/ { "CMSG_CANCEL_MOUNT_AURA", STATUS_LOGGEDIN, &WorldSession::HandleCancelMountAuraOpcode }, + /*0x376*/ { "SMSG_ARENA_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x377*/ { "MSG_INSPECT_ARENA_TEAMS", STATUS_LOGGEDIN, &WorldSession::HandleInspectArenaTeamsOpcode }, + /*0x378*/ { "SMSG_DEATH_RELEASE_LOC", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x379*/ { "CMSG_CANCEL_TEMP_ENCHANTMENT", STATUS_LOGGEDIN, &WorldSession::HandleCancelTempEnchantmentOpcode}, + /*0x37A*/ { "SMSG_FORCED_DEATH_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x37B*/ { "CMSG_CHEAT_SET_HONOR_CURRENCY", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x37C*/ { "CMSG_CHEAT_SET_ARENA_CURRENCY", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x37D*/ { "MSG_MOVE_SET_FLIGHT_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x37E*/ { "MSG_MOVE_SET_FLIGHT_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x37F*/ { "MSG_MOVE_SET_FLIGHT_BACK_SPEED_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x380*/ { "MSG_MOVE_SET_FLIGHT_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x381*/ { "SMSG_FORCE_FLIGHT_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x382*/ { "CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, + /*0x383*/ { "SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x384*/ { "CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK", STATUS_LOGGEDIN, &WorldSession::HandleForceSpeedChangeAck }, + /*0x385*/ { "SMSG_SPLINE_SET_FLIGHT_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x386*/ { "SMSG_SPLINE_SET_FLIGHT_BACK_SPEED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x387*/ { "CMSG_MAELSTROM_INVALIDATE_CACHE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x388*/ { "SMSG_FLIGHT_SPLINE_SYNC", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x389*/ { "CMSG_SET_TAXI_BENCHMARK_MODE", STATUS_AUTHED, &WorldSession::HandleSetTaxiBenchmarkOpcode }, + /*0x38A*/ { "SMSG_JOINED_BATTLEGROUND_QUEUE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x38B*/ { "SMSG_REALM_SPLIT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x38C*/ { "CMSG_REALM_SPLIT", STATUS_AUTHED, &WorldSession::HandleRealmSplitOpcode }, + /*0x38D*/ { "CMSG_MOVE_CHNG_TRANSPORT", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x38E*/ { "MSG_PARTY_ASSIGNMENT", STATUS_LOGGEDIN, &WorldSession::HandlePartyAssignmentOpcode }, + /*0x38F*/ { "SMSG_OFFER_PETITION_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x390*/ { "SMSG_TIME_SYNC_REQ", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x391*/ { "CMSG_TIME_SYNC_RESP", STATUS_LOGGEDIN, &WorldSession::HandleTimeSyncResp }, + /*0x392*/ { "CMSG_SEND_LOCAL_EVENT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x393*/ { "CMSG_SEND_GENERAL_TRIGGER", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x394*/ { "CMSG_SEND_COMBAT_TRIGGER", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x395*/ { "CMSG_MAELSTROM_GM_SENT_MAIL", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x396*/ { "SMSG_RESET_FAILED_NOTIFY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x397*/ { "SMSG_REAL_GROUP_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x398*/ { "SMSG_LFG_DISABLED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x399*/ { "CMSG_ACTIVE_PVP_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x39A*/ { "CMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x39B*/ { "SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x39C*/ { "SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE_WRITE_FILE",STATUS_NEVER,&WorldSession::Handle_ServerSide }, + /*0x39D*/ { "SMSG_UPDATE_COMBO_POINTS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x39E*/ { "SMSG_VOICE_SESSION_ROSTER_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x39F*/ { "SMSG_VOICE_SESSION_LEAVE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3A0*/ { "SMSG_VOICE_SESSION_ADJUST_PRIORITY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3A1*/ { "CMSG_VOICE_SET_TALKER_MUTED_REQUEST", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3A2*/ { "SMSG_VOICE_SET_TALKER_MUTED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3A3*/ { "SMSG_INIT_EXTRA_AURA_INFO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3A4*/ { "SMSG_SET_EXTRA_AURA_INFO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3A5*/ { "SMSG_SET_EXTRA_AURA_INFO_NEED_UPDATE_OBSOLETE",STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3A6*/ { "SMSG_CLEAR_EXTRA_AURA_INFO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3A7*/ { "MSG_MOVE_START_DESCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, + /*0x3A8*/ { "CMSG_IGNORE_REQUIREMENTS_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3A9*/ { "SMSG_IGNORE_REQUIREMENTS_CHEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3AA*/ { "SMSG_SPELL_CHANCE_PROC_LOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3AB*/ { "CMSG_MOVE_SET_RUN_SPEED", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3AC*/ { "SMSG_DISMOUNT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3AD*/ { "MSG_MOVE_UPDATE_CAN_FLY", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3AE*/ { "MSG_RAID_READY_CHECK_CONFIRM", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3AF*/ { "CMSG_VOICE_SESSION_ENABLE", STATUS_AUTHED, &WorldSession::HandleVoiceSessionEnableOpcode }, + /*0x3B0*/ { "SMSG_VOICE_SESSION_ENABLE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3B1*/ { "SMSG_VOICE_PARENTAL_CONTROLS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3B2*/ { "CMSG_GM_WHISPER", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3B3*/ { "SMSG_GM_MESSAGECHAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3B4*/ { "MSG_GM_GEARRATING", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3B5*/ { "CMSG_COMMENTATOR_ENABLE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3B6*/ { "SMSG_COMMENTATOR_STATE_CHANGED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3B7*/ { "CMSG_COMMENTATOR_GET_MAP_INFO", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3B8*/ { "SMSG_COMMENTATOR_MAP_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3B9*/ { "CMSG_COMMENTATOR_GET_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3BA*/ { "SMSG_COMMENTATOR_GET_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3BB*/ { "SMSG_COMMENTATOR_PLAYER_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3BC*/ { "CMSG_COMMENTATOR_ENTER_INSTANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3BD*/ { "CMSG_COMMENTATOR_EXIT_INSTANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3BE*/ { "CMSG_COMMENTATOR_INSTANCE_COMMAND", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3BF*/ { "SMSG_CLEAR_TARGET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3C0*/ { "CMSG_BOT_DETECTED", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3C1*/ { "SMSG_CROSSED_INEBRIATION_THRESHOLD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3C2*/ { "CMSG_CHEAT_PLAYER_LOGIN", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3C3*/ { "CMSG_CHEAT_PLAYER_LOOKUP", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3C4*/ { "SMSG_CHEAT_PLAYER_LOOKUP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3C5*/ { "SMSG_KICK_REASON", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3C6*/ { "MSG_RAID_READY_CHECK_FINISHED", STATUS_LOGGEDIN, &WorldSession::HandleRaidReadyCheckFinishedOpcode}, + /*0x3C7*/ { "CMSG_COMPLAIN", STATUS_LOGGEDIN, &WorldSession::HandleComplainOpcode }, + /*0x3C8*/ { "SMSG_COMPLAIN_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3C9*/ { "SMSG_FEATURE_SYSTEM_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3CA*/ { "CMSG_GM_SHOW_COMPLAINTS", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3CB*/ { "CMSG_GM_UNSQUELCH", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3CC*/ { "CMSG_CHANNEL_SILENCE_VOICE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3CD*/ { "CMSG_CHANNEL_SILENCE_ALL", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3CE*/ { "CMSG_CHANNEL_UNSILENCE_VOICE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3CF*/ { "CMSG_CHANNEL_UNSILENCE_ALL", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3D0*/ { "CMSG_TARGET_CAST", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3D1*/ { "CMSG_TARGET_SCRIPT_CAST", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3D2*/ { "CMSG_CHANNEL_DISPLAY_LIST", STATUS_LOGGEDIN, &WorldSession::HandleChannelDisplayListQuery }, + /*0x3D3*/ { "CMSG_SET_ACTIVE_VOICE_CHANNEL", STATUS_AUTHED, &WorldSession::HandleSetActiveVoiceChannel }, + /*0x3D4*/ { "CMSG_GET_CHANNEL_MEMBER_COUNT", STATUS_LOGGEDIN, &WorldSession::HandleGetChannelMemberCount }, + /*0x3D5*/ { "SMSG_CHANNEL_MEMBER_COUNT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3D6*/ { "CMSG_CHANNEL_VOICE_ON", STATUS_LOGGEDIN, &WorldSession::HandleChannelVoiceOnOpcode }, + /*0x3D7*/ { "CMSG_CHANNEL_VOICE_OFF", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3D8*/ { "CMSG_DEBUG_LIST_TARGETS", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3D9*/ { "SMSG_DEBUG_LIST_TARGETS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3DA*/ { "SMSG_AVAILABLE_VOICE_CHANNEL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3DB*/ { "CMSG_ADD_VOICE_IGNORE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3DC*/ { "CMSG_DEL_VOICE_IGNORE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3DD*/ { "CMSG_PARTY_SILENCE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3DE*/ { "CMSG_PARTY_UNSILENCE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3DF*/ { "MSG_NOTIFY_PARTY_SQUELCH", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3E0*/ { "SMSG_COMSAT_RECONNECT_TRY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3E1*/ { "SMSG_COMSAT_DISCONNECT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3E2*/ { "SMSG_COMSAT_CONNECT_FAIL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3E3*/ { "SMSG_VOICE_CHAT_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3E4*/ { "CMSG_REPORT_PVP_AFK", STATUS_LOGGEDIN, &WorldSession::HandleReportPvPAFK }, + /*0x3E5*/ { "SMSG_REPORT_PVP_AFK_RESULT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3E6*/ { "CMSG_GUILD_BANKER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankerActivate }, + /*0x3E7*/ { "CMSG_GUILD_BANK_QUERY_TAB", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankQueryTab }, + /*0x3E8*/ { "SMSG_GUILD_BANK_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3E9*/ { "CMSG_GUILD_BANK_SWAP_ITEMS", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankSwapItems }, + /*0x3EA*/ { "CMSG_GUILD_BANK_BUY_TAB", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankBuyTab }, + /*0x3EB*/ { "CMSG_GUILD_BANK_UPDATE_TAB", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankUpdateTab }, + /*0x3EC*/ { "CMSG_GUILD_BANK_DEPOSIT_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankDepositMoney }, + /*0x3ED*/ { "CMSG_GUILD_BANK_WITHDRAW_MONEY", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankWithdrawMoney }, + /*0x3EE*/ { "MSG_GUILD_BANK_LOG_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankLogQuery }, + /*0x3EF*/ { "CMSG_SET_CHANNEL_WATCH", STATUS_LOGGEDIN, &WorldSession::HandleSetChannelWatch }, + /*0x3F0*/ { "SMSG_USERLIST_ADD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3F1*/ { "SMSG_USERLIST_REMOVE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3F2*/ { "SMSG_USERLIST_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3F3*/ { "CMSG_CLEAR_CHANNEL_WATCH", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3F4*/ { "SMSG_INSPECT_TALENT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3F5*/ { "SMSG_GOGOGO_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3F6*/ { "SMSG_ECHO_PARTY_SQUELCH", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3F7*/ { "CMSG_SET_TITLE_SUFFIX", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3F8*/ { "CMSG_SPELLCLICK", STATUS_LOGGEDIN, &WorldSession::HandleSpellClick }, + /*0x3F9*/ { "SMSG_LOOT_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3FA*/ { "CMSG_GM_CHARACTER_RESTORE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3FB*/ { "CMSG_GM_CHARACTER_SAVE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3FC*/ { "SMSG_VOICESESSION_FULL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x3FD*/ { "MSG_GUILD_PERMISSIONS", STATUS_LOGGEDIN, &WorldSession::HandleGuildPermissions }, + /*0x3FE*/ { "MSG_GUILD_BANK_MONEY_WITHDRAWN", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankMoneyWithdrawn }, + /*0x3FF*/ { "MSG_GUILD_EVENT_LOG_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleGuildEventLogQueryOpcode }, + /*0x400*/ { "CMSG_MAELSTROM_RENAME_GUILD", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x401*/ { "CMSG_GET_MIRRORIMAGE_DATA", STATUS_LOGGEDIN, &WorldSession::HandleMirrrorImageDataRequest }, + /*0x402*/ { "SMSG_MIRRORIMAGE_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x403*/ { "SMSG_FORCE_DISPLAY_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x404*/ { "SMSG_SPELL_CHANCE_RESIST_PUSHBACK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x405*/ { "CMSG_IGNORE_DIMINISHING_RETURNS_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x406*/ { "SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x407*/ { "CMSG_KEEP_ALIVE", STATUS_NEVER, &WorldSession::Handle_EarlyProccess }, + /*0x408*/ { "SMSG_RAID_READY_CHECK_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x409*/ { "CMSG_OPT_OUT_OF_LOOT", STATUS_AUTHED, &WorldSession::HandleOptOutOfLootOpcode }, + /*0x40A*/ { "MSG_QUERY_GUILD_BANK_TEXT", STATUS_LOGGEDIN, &WorldSession::HandleQueryGuildBankTabText }, + /*0x40B*/ { "CMSG_SET_GUILD_BANK_TEXT", STATUS_LOGGEDIN, &WorldSession::HandleSetGuildBankTabText }, + /*0x40C*/ { "CMSG_SET_GRANTABLE_LEVELS", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x40D*/ { "CMSG_GRANT_LEVEL", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x40E*/ { "CMSG_REFER_A_FRIEND", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x40F*/ { "CMSG_DECLINE_CHANNEL_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleChannelDeclineInvite }, + /*0x410*/ { "CMSG_DECLINE_CHANNEL_INVITE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x411*/ { "SMSG_GROUPACTION_THROTTLED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x412*/ { "SMSG_OVERRIDE_LIGHT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x413*/ { "SMSG_TOTEM_CREATED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x414*/ { "CMSG_TOTEM_DESTROYED", STATUS_LOGGEDIN, &WorldSession::HandleTotemDestroyed }, + /*0x415*/ { "CMSG_EXPIRE_RAID_INSTANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x416*/ { "CMSG_NO_SPELL_VARIANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x417*/ { "CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleQuestgiverStatusMultipleQuery}, + /*0x418*/ { "SMSG_QUESTGIVER_STATUS_MULTIPLE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x419*/ { "CMSG_SET_PLAYER_DECLINED_NAMES", STATUS_AUTHED, &WorldSession::HandleSetPlayerDeclinedNames }, + /*0x41A*/ { "SMSG_SET_PLAYER_DECLINED_NAMES_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x41B*/ { "CMSG_QUERY_SERVER_BUCK_DATA", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x41C*/ { "CMSG_CLEAR_SERVER_BUCK_DATA", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x41D*/ { "SMSG_SERVER_BUCK_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x41E*/ { "SMSG_SEND_UNLEARN_SPELLS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x41F*/ { "SMSG_PROPOSE_LEVEL_GRANT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x420*/ { "CMSG_ACCEPT_LEVEL_GRANT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x421*/ { "SMSG_REFER_A_FRIEND_FAILURE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x422*/ { "SMSG_SPLINE_MOVE_SET_FLYING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x423*/ { "SMSG_SPLINE_MOVE_UNSET_FLYING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x424*/ { "SMSG_SUMMON_CANCEL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x425*/ { "CMSG_CHANGE_PERSONAL_ARENA_RATING", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x426*/ { "CMSG_ALTER_APPEARANCE", STATUS_LOGGEDIN, &WorldSession::HandleAlterAppearance }, + /*0x427*/ { "SMSG_ENABLE_BARBER_SHOP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x428*/ { "SMSG_BARBER_SHOP_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x429*/ { "CMSG_CALENDAR_GET_CALENDAR", STATUS_LOGGEDIN, &WorldSession::HandleCalendarGetCalendar }, + /*0x42A*/ { "CMSG_CALENDAR_GET_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarGetEvent }, + /*0x42B*/ { "CMSG_CALENDAR_GUILD_FILTER", STATUS_LOGGEDIN, &WorldSession::HandleCalendarGuildFilter }, + /*0x42C*/ { "CMSG_CALENDAR_ARENA_TEAM", STATUS_LOGGEDIN, &WorldSession::HandleCalendarArenaTeam }, + /*0x42D*/ { "CMSG_CALENDAR_ADD_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarAddEvent }, + /*0x42E*/ { "CMSG_CALENDAR_UPDATE_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarUpdateEvent }, + /*0x42F*/ { "CMSG_CALENDAR_REMOVE_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarRemoveEvent }, + /*0x430*/ { "CMSG_CALENDAR_COPY_EVENT", STATUS_LOGGEDIN, &WorldSession::HandleCalendarCopyEvent }, + /*0x431*/ { "CMSG_CALENDAR_EVENT_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventInvite }, + /*0x432*/ { "CMSG_CALENDAR_EVENT_RSVP", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventRsvp }, + /*0x433*/ { "CMSG_CALENDAR_EVENT_REMOVE_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventRemoveInvite }, + /*0x434*/ { "CMSG_CALENDAR_EVENT_STATUS", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventStatus }, + /*0x435*/ { "CMSG_CALENDAR_EVENT_MODERATOR_STATUS", STATUS_LOGGEDIN, &WorldSession::HandleCalendarEventModeratorStatus}, + /*0x436*/ { "SMSG_CALENDAR_SEND_CALENDAR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x437*/ { "SMSG_CALENDAR_SEND_EVENT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x438*/ { "SMSG_CALENDAR_FILTER_GUILD", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x439*/ { "SMSG_CALENDAR_ARENA_TEAM", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x43A*/ { "SMSG_CALENDAR_EVENT_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x43B*/ { "SMSG_CALENDAR_EVENT_INVITE_REMOVED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x43C*/ { "SMSG_CALENDAR_EVENT_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x43D*/ { "SMSG_CALENDAR_COMMAND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x43E*/ { "SMSG_CALENDAR_RAID_LOCKOUT_ADDED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x43F*/ { "SMSG_CALENDAR_RAID_LOCKOUT_REMOVED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x440*/ { "SMSG_CALENDAR_EVENT_INVITE_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x441*/ { "SMSG_CALENDAR_EVENT_INVITE_REMOVED_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x442*/ { "SMSG_CALENDAR_EVENT_INVITE_STATUS_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x443*/ { "SMSG_CALENDAR_EVENT_REMOVED_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x444*/ { "SMSG_CALENDAR_EVENT_UPDATED_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x445*/ { "SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x446*/ { "CMSG_CALENDAR_COMPLAIN", STATUS_LOGGEDIN, &WorldSession::HandleCalendarComplain }, + /*0x447*/ { "CMSG_CALENDAR_GET_NUM_PENDING", STATUS_LOGGEDIN, &WorldSession::HandleCalendarGetNumPending }, + /*0x448*/ { "SMSG_CALENDAR_SEND_NUM_PENDING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x449*/ { "CMSG_SAVE_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x44A*/ { "SMSG_NOTIFY_DANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x44B*/ { "CMSG_PLAY_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x44C*/ { "SMSG_PLAY_DANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x44D*/ { "CMSG_LOAD_DANCES", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x44E*/ { "CMSG_STOP_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x44F*/ { "SMSG_STOP_DANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x450*/ { "CMSG_SYNC_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x451*/ { "CMSG_DANCE_QUERY", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x452*/ { "SMSG_DANCE_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x453*/ { "SMSG_INVALIDATE_DANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x454*/ { "CMSG_DELETE_DANCE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x455*/ { "SMSG_LEARNED_DANCE_MOVES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x456*/ { "CMSG_LEARN_DANCE_MOVE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x457*/ { "CMSG_UNLEARN_DANCE_MOVE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x458*/ { "CMSG_SET_RUNE_COUNT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x459*/ { "CMSG_SET_RUNE_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x45A*/ { "MSG_MOVE_SET_PITCH_RATE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x45B*/ { "MSG_MOVE_SET_PITCH_RATE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x45C*/ { "SMSG_FORCE_PITCH_RATE_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x45D*/ { "CMSG_FORCE_PITCH_RATE_CHANGE_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x45E*/ { "SMSG_SPLINE_SET_PITCH_RATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x45F*/ { "SMSG_MOVE_ABANDON_TRANSPORT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x460*/ { "MSG_MOVE_ABANDON_TRANSPORT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x461*/ { "CMSG_MOVE_ABANDON_TRANSPORT_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x462*/ { "CMSG_UPDATE_MISSILE_TRAJECTORY", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x463*/ { "SMSG_UPDATE_ACCOUNT_DATA_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x464*/ { "SMSG_TRIGGER_MOVIE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x465*/ { "CMSG_COMPLETE_MOVIE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x466*/ { "CMSG_SET_GLYPH_SLOT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x467*/ { "CMSG_SET_GLYPH", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x468*/ { "SMSG_ACHIEVEMENT_EARNED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x469*/ { "SMSG_DYNAMIC_DROP_ROLL_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x46A*/ { "SMSG_CRITERIA_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x46B*/ { "CMSG_QUERY_INSPECT_ACHIEVEMENTS", STATUS_LOGGEDIN, &WorldSession::HandleQueryInspectAchievements }, + /*0x46C*/ { "SMSG_RESPOND_INSPECT_ACHIEVEMENTS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x46D*/ { "CMSG_DISMISS_CONTROLLED_VEHICLE", STATUS_LOGGEDIN, &WorldSession::HandleDismissControlledVehicle }, + /*0x46E*/ { "CMSG_COMPLETE_ACHIEVEMENT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x46F*/ { "SMSG_QUESTUPDATE_ADD_PVP_KILL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x470*/ { "CMSG_SET_CRITERIA_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x471*/ { "SMSG_GROUP_SWAP_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x472*/ { "CMSG_UNITANIMTIER_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x473*/ { "CMSG_CHAR_CUSTOMIZE", STATUS_AUTHED, &WorldSession::HandleCharCustomize }, + /*0x474*/ { "SMSG_CHAR_CUSTOMIZE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x475*/ { "SMSG_PET_RENAMEABLE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x476*/ { "CMSG_REQUEST_VEHICLE_EXIT", STATUS_LOGGEDIN, &WorldSession::HandleRequestVehicleExit }, + /*0x477*/ { "CMSG_REQUEST_VEHICLE_PREV_SEAT", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle}, + /*0x478*/ { "CMSG_REQUEST_VEHICLE_NEXT_SEAT", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle}, + /*0x479*/ { "CMSG_REQUEST_VEHICLE_SWITCH_SEAT", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle}, + /*0x47A*/ { "CMSG_PET_LEARN_TALENT", STATUS_LOGGEDIN, &WorldSession::HandlePetLearnTalent }, + /*0x47B*/ { "CMSG_PET_UNLEARN_TALENTS", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x47C*/ { "SMSG_SET_PHASE_SHIFT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x47D*/ { "SMSG_ALL_ACHIEVEMENT_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x47E*/ { "CMSG_FORCE_SAY_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x47F*/ { "SMSG_HEALTH_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x480*/ { "SMSG_POWER_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x481*/ { "CMSG_GAMEOBJ_REPORT_USE", STATUS_LOGGEDIN, &WorldSession::HandleGameobjectReportUse }, + /*0x482*/ { "SMSG_HIGHEST_THREAT_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x483*/ { "SMSG_THREAT_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x484*/ { "SMSG_THREAT_REMOVE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x485*/ { "SMSG_THREAT_CLEAR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x486*/ { "SMSG_CONVERT_RUNE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x487*/ { "SMSG_RESYNC_RUNES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x488*/ { "SMSG_ADD_RUNE_POWER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x489*/ { "CMSG_START_QUEST", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x48A*/ { "CMSG_REMOVE_GLYPH", STATUS_LOGGEDIN, &WorldSession::HandleRemoveGlyph }, + /*0x48B*/ { "CMSG_DUMP_OBJECTS", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x48C*/ { "SMSG_DUMP_OBJECTS_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x48D*/ { "CMSG_DISMISS_CRITTER", STATUS_LOGGEDIN, &WorldSession::HandleDismissCritter }, + /*0x48E*/ { "SMSG_NOTIFY_DEST_LOC_SPELL_CAST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x48F*/ { "CMSG_AUCTION_LIST_PENDING_SALES", STATUS_LOGGEDIN, &WorldSession::HandleAuctionListPendingSales }, + /*0x490*/ { "SMSG_AUCTION_LIST_PENDING_SALES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x491*/ { "SMSG_MODIFY_COOLDOWN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x492*/ { "SMSG_PET_UPDATE_COMBO_POINTS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x493*/ { "CMSG_ENABLETAXI", STATUS_LOGGEDIN, &WorldSession::HandleTaxiQueryAvailableNodes }, + /*0x494*/ { "SMSG_PRE_RESURRECT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x495*/ { "SMSG_AURA_UPDATE_ALL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x496*/ { "SMSG_AURA_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x497*/ { "CMSG_FLOOD_GRACE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x498*/ { "SMSG_SERVER_FIRST_ACHIEVEMENT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x499*/ { "SMSG_PET_LEARNED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x49A*/ { "SMSG_PET_REMOVED_SPELL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x49B*/ { "CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE", STATUS_LOGGEDIN, &WorldSession::HandleChangeSeatsOnControlledVehicle}, + /*0x49C*/ { "CMSG_HEARTH_AND_RESURRECT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x49D*/ { "SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x49E*/ { "SMSG_CRITERIA_DELETED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x49F*/ { "SMSG_ACHIEVEMENT_DELETED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4A0*/ { "CMSG_SERVER_INFO_QUERY", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4A1*/ { "SMSG_SERVER_INFO_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4A2*/ { "CMSG_CHECK_LOGIN_CRITERIA", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4A3*/ { "SMSG_SERVER_BUCK_DATA_START", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4A4*/ { "CMSG_QUERY_VEHICLE_STATUS", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4A5*/ { "UMSG_UNKNOWN_1189", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4A6*/ { "SMSG_BATTLEGROUND_INFO_THROTTLED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4A7*/ { "SMSG_PLAYER_VEHICLE_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4A8*/ { "CMSG_PLAYER_VEHICLE_ENTER", STATUS_LOGGEDIN, &WorldSession::HandleEnterPlayerVehicle }, + /*0x4A9*/ { "CMSG_EJECT_PASSENGER", STATUS_LOGGEDIN, &WorldSession::HandleEjectPasenger }, + /*0x4AA*/ { "SMSG_PET_GUIDS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4AB*/ { "SMSG_CLIENTCACHE_VERSION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4AC*/ { "UMSG_UNKNOWN_1196", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4AD*/ { "UMSG_UNKNOWN_1197", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4AE*/ { "UMSG_UNKNOWN_1198", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4AF*/ { "UMSG_UNKNOWN_1199", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4B0*/ { "UMSG_UNKNOWN_1200", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4B1*/ { "UMSG_UNKNOWN_1201", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4B2*/ { "SMSG_ITEM_REFUND_INFO_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4B3*/ { "CMSG_ITEM_REFUND_INFO", STATUS_LOGGEDIN, &WorldSession::HandleItemRefundInfoRequest }, + /*0x4B4*/ { "CMSG_ITEM_REFUND", STATUS_LOGGEDIN, &WorldSession::HandleItemRefund }, + /*0x4B5*/ { "SMSG_ITEM_REFUND_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4B6*/ { "CMSG_CORPSE_MAP_POSITION_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleCorpseMapPositionQuery }, + /*0x4B7*/ { "SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4B8*/ { "CMSG_LFG_SET_ROLES_2", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x4B9*/ { "UMSG_UNKNOWN_1209", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4BA*/ { "CMSG_CALENDAR_CONTEXT_EVENT_SIGNUP", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4BB*/ { "SMSG_CALENDAR_ACTION_PENDING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4BC*/ { "SMSG_EQUIPMENT_SET_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4BD*/ { "CMSG_EQUIPMENT_SET_SAVE", STATUS_LOGGEDIN, &WorldSession::HandleEquipmentSetSave }, + /*0x4BE*/ { "CMSG_UPDATE_PROJECTILE_POSITION", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4BF*/ { "SMSG_SET_PROJECTILE_POSITION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4C0*/ { "SMSG_TALENTS_INFO", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4C1*/ { "CMSG_LEARN_PREVIEW_TALENTS", STATUS_LOGGEDIN, &WorldSession::HandleLearnPreviewTalents }, + /*0x4C2*/ { "CMSG_LEARN_PREVIEW_TALENTS_PET", STATUS_LOGGEDIN, &WorldSession::HandleLearnPreviewTalentsPet }, + /*0x4C3*/ { "UMSG_UNKNOWN_1219", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4C4*/ { "UMSG_UNKNOWN_1220", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4C5*/ { "UMSG_UNKNOWN_1221", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4C6*/ { "UMSG_UNKNOWN_1222", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4C7*/ { "SMSG_ARENA_OPPONENT_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4C8*/ { "SMSG_ARENA_TEAM_CHANGE_FAILED_QUEUED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4C9*/ { "UMSG_UNKNOWN_1225", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4CA*/ { "UMSG_UNKNOWN_1226", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4CB*/ { "UMSG_UNKNOWN_1227", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4CC*/ { "UMSG_UNKNOWN_1228", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4CD*/ { "SMSG_MULTIPLE_PACKETS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4CE*/ { "SMSG_UNKNOWN_1230", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4CF*/ { "CMSG_UNKNOWN_1231_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4D0*/ { "SMSG_UNKNOWN_1232", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4D1*/ { "CMSG_UNKNOWN_1233_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4D2*/ { "SMSG_UNKNOWN_1234", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4D3*/ { "SMSG_UNKNOWN_1235", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4D4*/ { "SMSG_UNKNOWN_1236", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4D5*/ { "CMSG_EQUIPMENT_SET_USE", STATUS_LOGGEDIN, &WorldSession::HandleEquipmentSetUse }, + /*0x4D6*/ { "SMSG_EQUIPMENT_SET_USE_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4D7*/ { "UMSG_UNKNOWN_1239", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4D8*/ { "SMSG_UNKNOWN_1240", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4D9*/ { "CMSG_CHAR_FACTION_CHANGE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4DA*/ { "SMSG_CHAR_FACTION_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4DB*/ { "UMSG_UNKNOWN_1243", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4DC*/ { "UMSG_UNKNOWN_1244", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4DD*/ { "UMSG_UNKNOWN_1245", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4DE*/ { "SMSG_BATTLEFIELD_MGR_ENTRY_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4DF*/ { "CMSG_BATTLEFIELD_MGR_ENTRY_INVITE_RESPONS", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4E0*/ { "SMSG_BATTLEFIELD_MGR_ENTERED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4E1*/ { "SMSG_BATTLEFIELD_MGR_QUEUE_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4E2*/ { "CMSG_BATTLEFIELD_MGR_QUEUE_INVITE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4E3*/ { "CMSG_BATTLEFIELD_MGR_QUEUE_REQUEST", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4E4*/ { "SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4E5*/ { "SMSG_BATTLEFIELD_MGR_EJECT_PENDING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4E6*/ { "SMSG_BATTLEFIELD_MGR_EJECTED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4E7*/ { "CMSG_BATTLEFIELD_MGR_EXIT_REQUEST", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4E8*/ { "SMSG_BATTLEFIELD_MGR_STATE_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4E9*/ { "UMSG_UNKNOWN_1257", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4EA*/ { "UMSG_UNKNOWN_1258", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4EB*/ { "MSG_SET_RAID_DIFFICULTY", STATUS_LOGGEDIN, &WorldSession::HandleSetRaidDifficultyOpcode }, + /*0x4EC*/ { "UMSG_UNKNOWN_1260", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4ED*/ { "SMSG_TOGGLE_XP_GAIN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4EE*/ { "SMSG_GMRESPONSE_DB_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4EF*/ { "SMSG_GMRESPONSE_RECEIVED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4F0*/ { "CMSG_GMRESPONSE_RESOLVE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4F1*/ { "SMSG_GMRESPONSE_STATUS_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4F2*/ { "UMSG_UNKNOWN_1266", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4F3*/ { "UMSG_UNKNOWN_1267", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4F4*/ { "UMSG_UNKNOWN_1268", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4F5*/ { "UMSG_UNKNOWN_1269", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4F6*/ { "CMSG_WORLD_STATE_UI_TIMER_UPDATE", STATUS_LOGGEDIN, &WorldSession::HandleWorldStateUITimerUpdate }, + /*0x4F7*/ { "SMSG_WORLD_STATE_UI_TIMER_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4F8*/ { "CMSG_CHAR_RACE_CHANGE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4F9*/ { "UMSG_UNKNOWN_1273", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4FA*/ { "SMSG_TALENTS_INVOLUNTARILY_RESET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4FB*/ { "UMSG_UNKNOWN_1275", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4FC*/ { "SMSG_UNKNOWN_1276", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4FD*/ { "SMSG_LOOT_SLOT_CHANGED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4FE*/ { "UMSG_UNKNOWN_1278", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4FF*/ { "CMSG_READY_FOR_ACCOUNT_DATA_TIMES", STATUS_AUTHED, &WorldSession::HandleReadyForAccountDataTimes }, + /*0x500*/ { "CMSG_QUERY_QUESTS_COMPLETED", STATUS_LOGGEDIN, &WorldSession::HandleQueryQuestsCompleted }, + /*0x501*/ { "SMSG_QUERY_QUESTS_COMPLETED_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x502*/ { "CMSG_GM_REPORT_LAG", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x503*/ { "UMSG_UNKNOWN_1283", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x504*/ { "UMSG_UNKNOWN_1284", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x505*/ { "UMSG_UNKNOWN_1285", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x506*/ { "SMSG_CORPSE_NOT_IN_INSTANCE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x507*/ { "UMSG_UNKNOWN_1287", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x508*/ { "CMSG_SET_ALLOW_LOW_LEVEL_RAID1", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x509*/ { "CMSG_SET_ALLOW_LOW_LEVEL_RAID2", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x50A*/ { "SMSG_CAMERA_SHAKE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x50B*/ { "SMSG_UPDATE_ITEM_ENCHANTMENTS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x50C*/ { "UMSG_UNKNOWN_1292", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x50D*/ { "SMSG_REDIRECT_CLIENT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x50E*/ { "CMSG_REDIRECTION_FAILED", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x50F*/ { "SMSG_UNKNOWN_1295", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x510*/ { "CMSG_UNKNOWN_1296", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x511*/ { "SMSG_FORCE_SEND_QUEUED_PACKETS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x512*/ { "CMSG_REDIRECTION_AUTH_PROOF", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x513*/ { "UMSG_UNKNOWN_1299", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x514*/ { "SMSG_COMBAT_LOG_MULTIPLE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x515*/ { "SMSG_LFG_OPEN_FROM_GOSSIP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x516*/ { "SMSG_UNKNOWN_1302", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x517*/ { "CMSG_UNKNOWN_1303", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x518*/ { "SMSG_UNKNOWN_1304", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x519*/ { "UMSG_UNKNOWN_1305", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x51A*/ { "UMSG_UNKNOWN_1306", STATUS_NEVER, &WorldSession::Handle_NULL }, +}; diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h new file mode 100644 index 00000000000..4ae6931c3f5 --- /dev/null +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -0,0 +1,1378 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/// \addtogroup u2w +/// @{ +/// \file + +#ifndef _OPCODES_H +#define _OPCODES_H + +#include "Common.h" + +// Note: this include need for be sure have full definition of class WorldSession +// if this class definition not complite then VS for x64 release use different size for +// struct OpcodeHandler in this header and Opcode.cpp and get totally wrong data from +// table opcodeTable in source when Opcode.h included but WorldSession.h not included +#include "WorldSession.h" + +/// List of Opcodes +enum Opcodes +{ + MSG_NULL_ACTION = 0x000, + CMSG_BOOTME = 0x001, + CMSG_DBLOOKUP = 0x002, + SMSG_DBLOOKUP = 0x003, + CMSG_QUERY_OBJECT_POSITION = 0x004, + SMSG_QUERY_OBJECT_POSITION = 0x005, + CMSG_QUERY_OBJECT_ROTATION = 0x006, + SMSG_QUERY_OBJECT_ROTATION = 0x007, + CMSG_WORLD_TELEPORT = 0x008, + CMSG_TELEPORT_TO_UNIT = 0x009, + CMSG_ZONE_MAP = 0x00A, + SMSG_ZONE_MAP = 0x00B, + CMSG_DEBUG_CHANGECELLZONE = 0x00C, + CMSG_MOVE_CHARACTER_CHEAT = 0x00D, + SMSG_MOVE_CHARACTER_CHEAT = 0x00E, + CMSG_RECHARGE = 0x00F, + CMSG_LEARN_SPELL = 0x010, + CMSG_CREATEMONSTER = 0x011, + CMSG_DESTROYMONSTER = 0x012, + CMSG_CREATEITEM = 0x013, + CMSG_CREATEGAMEOBJECT = 0x014, + SMSG_CHECK_FOR_BOTS = 0x015, + CMSG_MAKEMONSTERATTACKGUID = 0x016, + CMSG_BOT_DETECTED2 = 0x017, + CMSG_FORCEACTION = 0x018, + CMSG_FORCEACTIONONOTHER = 0x019, + CMSG_FORCEACTIONSHOW = 0x01A, + SMSG_FORCEACTIONSHOW = 0x01B, + CMSG_PETGODMODE = 0x01C, + SMSG_PETGODMODE = 0x01D, + SMSG_REFER_A_FRIEND_EXPIRED = 0x01E, + CMSG_WEATHER_SPEED_CHEAT = 0x01F, + CMSG_UNDRESSPLAYER = 0x020, + CMSG_BEASTMASTER = 0x021, + CMSG_GODMODE = 0x022, + SMSG_GODMODE = 0x023, + CMSG_CHEAT_SETMONEY = 0x024, + CMSG_LEVEL_CHEAT = 0x025, + CMSG_PET_LEVEL_CHEAT = 0x026, + CMSG_SET_WORLDSTATE = 0x027, + CMSG_COOLDOWN_CHEAT = 0x028, + CMSG_USE_SKILL_CHEAT = 0x029, + CMSG_FLAG_QUEST = 0x02A, + CMSG_FLAG_QUEST_FINISH = 0x02B, + CMSG_CLEAR_QUEST = 0x02C, + CMSG_SEND_EVENT = 0x02D, + CMSG_DEBUG_AISTATE = 0x02E, + SMSG_DEBUG_AISTATE = 0x02F, + CMSG_DISABLE_PVP_CHEAT = 0x030, + CMSG_ADVANCE_SPAWN_TIME = 0x031, + SMSG_DESTRUCTIBLE_BUILDING_DAMAGE = 0x032, + CMSG_AUTH_SRP6_BEGIN = 0x033, + CMSG_AUTH_SRP6_PROOF = 0x034, + CMSG_AUTH_SRP6_RECODE = 0x035, + CMSG_CHAR_CREATE = 0x036, + CMSG_CHAR_ENUM = 0x037, + CMSG_CHAR_DELETE = 0x038, + SMSG_AUTH_SRP6_RESPONSE = 0x039, + SMSG_CHAR_CREATE = 0x03A, + SMSG_CHAR_ENUM = 0x03B, + SMSG_CHAR_DELETE = 0x03C, + CMSG_PLAYER_LOGIN = 0x03D, + SMSG_NEW_WORLD = 0x03E, + SMSG_TRANSFER_PENDING = 0x03F, + SMSG_TRANSFER_ABORTED = 0x040, + SMSG_CHARACTER_LOGIN_FAILED = 0x041, + SMSG_LOGIN_SETTIMESPEED = 0x042, + SMSG_GAMETIME_UPDATE = 0x043, + CMSG_GAMETIME_SET = 0x044, + SMSG_GAMETIME_SET = 0x045, + CMSG_GAMESPEED_SET = 0x046, + SMSG_GAMESPEED_SET = 0x047, + CMSG_SERVERTIME = 0x048, + SMSG_SERVERTIME = 0x049, + CMSG_PLAYER_LOGOUT = 0x04A, + CMSG_LOGOUT_REQUEST = 0x04B, + SMSG_LOGOUT_RESPONSE = 0x04C, + SMSG_LOGOUT_COMPLETE = 0x04D, + CMSG_LOGOUT_CANCEL = 0x04E, + SMSG_LOGOUT_CANCEL_ACK = 0x04F, + CMSG_NAME_QUERY = 0x050, + SMSG_NAME_QUERY_RESPONSE = 0x051, + CMSG_PET_NAME_QUERY = 0x052, + SMSG_PET_NAME_QUERY_RESPONSE = 0x053, + CMSG_GUILD_QUERY = 0x054, + SMSG_GUILD_QUERY_RESPONSE = 0x055, + CMSG_ITEM_QUERY_SINGLE = 0x056, + CMSG_ITEM_QUERY_MULTIPLE = 0x057, + SMSG_ITEM_QUERY_SINGLE_RESPONSE = 0x058, + SMSG_ITEM_QUERY_MULTIPLE_RESPONSE = 0x059, + CMSG_PAGE_TEXT_QUERY = 0x05A, + SMSG_PAGE_TEXT_QUERY_RESPONSE = 0x05B, + CMSG_QUEST_QUERY = 0x05C, + SMSG_QUEST_QUERY_RESPONSE = 0x05D, + CMSG_GAMEOBJECT_QUERY = 0x05E, + SMSG_GAMEOBJECT_QUERY_RESPONSE = 0x05F, + CMSG_CREATURE_QUERY = 0x060, + SMSG_CREATURE_QUERY_RESPONSE = 0x061, + CMSG_WHO = 0x062, + SMSG_WHO = 0x063, + CMSG_WHOIS = 0x064, + SMSG_WHOIS = 0x065, + CMSG_CONTACT_LIST = 0x066, + SMSG_CONTACT_LIST = 0x067, + SMSG_FRIEND_STATUS = 0x068, + CMSG_ADD_FRIEND = 0x069, + CMSG_DEL_FRIEND = 0x06A, + CMSG_SET_CONTACT_NOTES = 0x06B, + CMSG_ADD_IGNORE = 0x06C, + CMSG_DEL_IGNORE = 0x06D, + CMSG_GROUP_INVITE = 0x06E, + SMSG_GROUP_INVITE = 0x06F, + CMSG_GROUP_CANCEL = 0x070, + SMSG_GROUP_CANCEL = 0x071, + CMSG_GROUP_ACCEPT = 0x072, + CMSG_GROUP_DECLINE = 0x073, + SMSG_GROUP_DECLINE = 0x074, + CMSG_GROUP_UNINVITE = 0x075, + CMSG_GROUP_UNINVITE_GUID = 0x076, + SMSG_GROUP_UNINVITE = 0x077, + CMSG_GROUP_SET_LEADER = 0x078, + SMSG_GROUP_SET_LEADER = 0x079, + CMSG_LOOT_METHOD = 0x07A, + CMSG_GROUP_DISBAND = 0x07B, + SMSG_GROUP_DESTROYED = 0x07C, + SMSG_GROUP_LIST = 0x07D, + SMSG_PARTY_MEMBER_STATS = 0x07E, + SMSG_PARTY_COMMAND_RESULT = 0x07F, + UMSG_UPDATE_GROUP_MEMBERS = 0x080, + CMSG_GUILD_CREATE = 0x081, + CMSG_GUILD_INVITE = 0x082, + SMSG_GUILD_INVITE = 0x083, + CMSG_GUILD_ACCEPT = 0x084, + CMSG_GUILD_DECLINE = 0x085, + SMSG_GUILD_DECLINE = 0x086, + CMSG_GUILD_INFO = 0x087, + SMSG_GUILD_INFO = 0x088, + CMSG_GUILD_ROSTER = 0x089, + SMSG_GUILD_ROSTER = 0x08A, + CMSG_GUILD_PROMOTE = 0x08B, + CMSG_GUILD_DEMOTE = 0x08C, + CMSG_GUILD_LEAVE = 0x08D, + CMSG_GUILD_REMOVE = 0x08E, + CMSG_GUILD_DISBAND = 0x08F, + CMSG_GUILD_LEADER = 0x090, + CMSG_GUILD_MOTD = 0x091, + SMSG_GUILD_EVENT = 0x092, + SMSG_GUILD_COMMAND_RESULT = 0x093, + UMSG_UPDATE_GUILD = 0x094, + CMSG_MESSAGECHAT = 0x095, + SMSG_MESSAGECHAT = 0x096, + CMSG_JOIN_CHANNEL = 0x097, + CMSG_LEAVE_CHANNEL = 0x098, + SMSG_CHANNEL_NOTIFY = 0x099, + CMSG_CHANNEL_LIST = 0x09A, + SMSG_CHANNEL_LIST = 0x09B, + CMSG_CHANNEL_PASSWORD = 0x09C, + CMSG_CHANNEL_SET_OWNER = 0x09D, + CMSG_CHANNEL_OWNER = 0x09E, + CMSG_CHANNEL_MODERATOR = 0x09F, + CMSG_CHANNEL_UNMODERATOR = 0x0A0, + CMSG_CHANNEL_MUTE = 0x0A1, + CMSG_CHANNEL_UNMUTE = 0x0A2, + CMSG_CHANNEL_INVITE = 0x0A3, + CMSG_CHANNEL_KICK = 0x0A4, + CMSG_CHANNEL_BAN = 0x0A5, + CMSG_CHANNEL_UNBAN = 0x0A6, + CMSG_CHANNEL_ANNOUNCEMENTS = 0x0A7, + CMSG_CHANNEL_MODERATE = 0x0A8, + SMSG_UPDATE_OBJECT = 0x0A9, + SMSG_DESTROY_OBJECT = 0x0AA, + CMSG_USE_ITEM = 0x0AB, + CMSG_OPEN_ITEM = 0x0AC, + CMSG_READ_ITEM = 0x0AD, + SMSG_READ_ITEM_OK = 0x0AE, + SMSG_READ_ITEM_FAILED = 0x0AF, + SMSG_ITEM_COOLDOWN = 0x0B0, + CMSG_GAMEOBJ_USE = 0x0B1, + CMSG_DESTROY_ITEMS = 0x0B2, + SMSG_GAMEOBJECT_CUSTOM_ANIM = 0x0B3, + CMSG_AREATRIGGER = 0x0B4, + MSG_MOVE_START_FORWARD = 0x0B5, + MSG_MOVE_START_BACKWARD = 0x0B6, + MSG_MOVE_STOP = 0x0B7, + MSG_MOVE_START_STRAFE_LEFT = 0x0B8, + MSG_MOVE_START_STRAFE_RIGHT = 0x0B9, + MSG_MOVE_STOP_STRAFE = 0x0BA, + MSG_MOVE_JUMP = 0x0BB, + MSG_MOVE_START_TURN_LEFT = 0x0BC, + MSG_MOVE_START_TURN_RIGHT = 0x0BD, + MSG_MOVE_STOP_TURN = 0x0BE, + MSG_MOVE_START_PITCH_UP = 0x0BF, + MSG_MOVE_START_PITCH_DOWN = 0x0C0, + MSG_MOVE_STOP_PITCH = 0x0C1, + MSG_MOVE_SET_RUN_MODE = 0x0C2, + MSG_MOVE_SET_WALK_MODE = 0x0C3, + MSG_MOVE_TOGGLE_LOGGING = 0x0C4, + MSG_MOVE_TELEPORT = 0x0C5, + MSG_MOVE_TELEPORT_CHEAT = 0x0C6, + MSG_MOVE_TELEPORT_ACK = 0x0C7, + MSG_MOVE_TOGGLE_FALL_LOGGING = 0x0C8, + MSG_MOVE_FALL_LAND = 0x0C9, + MSG_MOVE_START_SWIM = 0x0CA, + MSG_MOVE_STOP_SWIM = 0x0CB, + MSG_MOVE_SET_RUN_SPEED_CHEAT = 0x0CC, + MSG_MOVE_SET_RUN_SPEED = 0x0CD, + MSG_MOVE_SET_RUN_BACK_SPEED_CHEAT = 0x0CE, + MSG_MOVE_SET_RUN_BACK_SPEED = 0x0CF, + MSG_MOVE_SET_WALK_SPEED_CHEAT = 0x0D0, + MSG_MOVE_SET_WALK_SPEED = 0x0D1, + MSG_MOVE_SET_SWIM_SPEED_CHEAT = 0x0D2, + MSG_MOVE_SET_SWIM_SPEED = 0x0D3, + MSG_MOVE_SET_SWIM_BACK_SPEED_CHEAT = 0x0D4, + MSG_MOVE_SET_SWIM_BACK_SPEED = 0x0D5, + MSG_MOVE_SET_ALL_SPEED_CHEAT = 0x0D6, + MSG_MOVE_SET_TURN_RATE_CHEAT = 0x0D7, + MSG_MOVE_SET_TURN_RATE = 0x0D8, + MSG_MOVE_TOGGLE_COLLISION_CHEAT = 0x0D9, + MSG_MOVE_SET_FACING = 0x0DA, + MSG_MOVE_SET_PITCH = 0x0DB, + MSG_MOVE_WORLDPORT_ACK = 0x0DC, + SMSG_MONSTER_MOVE = 0x0DD, + SMSG_MOVE_WATER_WALK = 0x0DE, + SMSG_MOVE_LAND_WALK = 0x0DF, + MSG_MOVE_SET_RAW_POSITION_ACK = 0x0E0, + CMSG_MOVE_SET_RAW_POSITION = 0x0E1, + SMSG_FORCE_RUN_SPEED_CHANGE = 0x0E2, + CMSG_FORCE_RUN_SPEED_CHANGE_ACK = 0x0E3, + SMSG_FORCE_RUN_BACK_SPEED_CHANGE = 0x0E4, + CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK = 0x0E5, + SMSG_FORCE_SWIM_SPEED_CHANGE = 0x0E6, + CMSG_FORCE_SWIM_SPEED_CHANGE_ACK = 0x0E7, + SMSG_FORCE_MOVE_ROOT = 0x0E8, + CMSG_FORCE_MOVE_ROOT_ACK = 0x0E9, + SMSG_FORCE_MOVE_UNROOT = 0x0EA, + CMSG_FORCE_MOVE_UNROOT_ACK = 0x0EB, + MSG_MOVE_ROOT = 0x0EC, + MSG_MOVE_UNROOT = 0x0ED, + MSG_MOVE_HEARTBEAT = 0x0EE, + SMSG_MOVE_KNOCK_BACK = 0x0EF, + CMSG_MOVE_KNOCK_BACK_ACK = 0x0F0, + MSG_MOVE_KNOCK_BACK = 0x0F1, + SMSG_MOVE_FEATHER_FALL = 0x0F2, + SMSG_MOVE_NORMAL_FALL = 0x0F3, + SMSG_MOVE_SET_HOVER = 0x0F4, + SMSG_MOVE_UNSET_HOVER = 0x0F5, + CMSG_MOVE_HOVER_ACK = 0x0F6, + MSG_MOVE_HOVER = 0x0F7, + CMSG_TRIGGER_CINEMATIC_CHEAT = 0x0F8, + CMSG_OPENING_CINEMATIC = 0x0F9, + SMSG_TRIGGER_CINEMATIC = 0x0FA, + CMSG_NEXT_CINEMATIC_CAMERA = 0x0FB, + CMSG_COMPLETE_CINEMATIC = 0x0FC, + SMSG_TUTORIAL_FLAGS = 0x0FD, + CMSG_TUTORIAL_FLAG = 0x0FE, + CMSG_TUTORIAL_CLEAR = 0x0FF, + CMSG_TUTORIAL_RESET = 0x100, + CMSG_STANDSTATECHANGE = 0x101, + CMSG_EMOTE = 0x102, + SMSG_EMOTE = 0x103, + CMSG_TEXT_EMOTE = 0x104, + SMSG_TEXT_EMOTE = 0x105, + CMSG_AUTOEQUIP_GROUND_ITEM = 0x106, + CMSG_AUTOSTORE_GROUND_ITEM = 0x107, + CMSG_AUTOSTORE_LOOT_ITEM = 0x108, + CMSG_STORE_LOOT_IN_SLOT = 0x109, + CMSG_AUTOEQUIP_ITEM = 0x10A, + CMSG_AUTOSTORE_BAG_ITEM = 0x10B, + CMSG_SWAP_ITEM = 0x10C, + CMSG_SWAP_INV_ITEM = 0x10D, + CMSG_SPLIT_ITEM = 0x10E, + CMSG_AUTOEQUIP_ITEM_SLOT = 0x10F, + OBSOLETE_DROP_ITEM = 0x110, + CMSG_DESTROYITEM = 0x111, + SMSG_INVENTORY_CHANGE_FAILURE = 0x112, + SMSG_OPEN_CONTAINER = 0x113, + CMSG_INSPECT = 0x114, + SMSG_INSPECT = 0x115, + CMSG_INITIATE_TRADE = 0x116, + CMSG_BEGIN_TRADE = 0x117, + CMSG_BUSY_TRADE = 0x118, + CMSG_IGNORE_TRADE = 0x119, + CMSG_ACCEPT_TRADE = 0x11A, + CMSG_UNACCEPT_TRADE = 0x11B, + CMSG_CANCEL_TRADE = 0x11C, + CMSG_SET_TRADE_ITEM = 0x11D, + CMSG_CLEAR_TRADE_ITEM = 0x11E, + CMSG_SET_TRADE_GOLD = 0x11F, + SMSG_TRADE_STATUS = 0x120, + SMSG_TRADE_STATUS_EXTENDED = 0x121, + SMSG_INITIALIZE_FACTIONS = 0x122, + SMSG_SET_FACTION_VISIBLE = 0x123, + SMSG_SET_FACTION_STANDING = 0x124, + CMSG_SET_FACTION_ATWAR = 0x125, + CMSG_SET_FACTION_CHEAT = 0x126, + SMSG_SET_PROFICIENCY = 0x127, + CMSG_SET_ACTION_BUTTON = 0x128, + SMSG_ACTION_BUTTONS = 0x129, + SMSG_INITIAL_SPELLS = 0x12A, + SMSG_LEARNED_SPELL = 0x12B, + SMSG_SUPERCEDED_SPELL = 0x12C, + CMSG_NEW_SPELL_SLOT = 0x12D, + CMSG_CAST_SPELL = 0x12E, + CMSG_CANCEL_CAST = 0x12F, + SMSG_CAST_FAILED = 0x130, + SMSG_SPELL_START = 0x131, + SMSG_SPELL_GO = 0x132, + SMSG_SPELL_FAILURE = 0x133, + SMSG_SPELL_COOLDOWN = 0x134, + SMSG_COOLDOWN_EVENT = 0x135, + CMSG_CANCEL_AURA = 0x136, + SMSG_EQUIPMENT_SET_SAVED = 0x137, + SMSG_PET_CAST_FAILED = 0x138, + MSG_CHANNEL_START = 0x139, + MSG_CHANNEL_UPDATE = 0x13A, + CMSG_CANCEL_CHANNELLING = 0x13B, + SMSG_AI_REACTION = 0x13C, + CMSG_SET_SELECTION = 0x13D, + CMSG_EQUIPMENT_SET_DELETE = 0x13E, + CMSG_INSTANCE_LOCK_WARNING_RESPONSE = 0x13F, + CMSG_UNUSED2 = 0x140, + CMSG_ATTACKSWING = 0x141, + CMSG_ATTACKSTOP = 0x142, + SMSG_ATTACKSTART = 0x143, + SMSG_ATTACKSTOP = 0x144, + SMSG_ATTACKSWING_NOTINRANGE = 0x145, + SMSG_ATTACKSWING_BADFACING = 0x146, + SMSG_INSTANCE_LOCK_WARNING_QUERY = 0x147, + SMSG_ATTACKSWING_DEADTARGET = 0x148, + SMSG_ATTACKSWING_CANT_ATTACK = 0x149, + SMSG_ATTACKERSTATEUPDATE = 0x14A, + SMSG_BATTLEFIELD_PORT_DENIED = 0x14B, + SMSG_DAMAGE_DONE_OBSOLETE = 0x14C, + SMSG_UNIT_SPELLCAST_START = 0x14D, + SMSG_CANCEL_COMBAT = 0x14E, + SMSG_SPELLBREAKLOG = 0x14F, + SMSG_SPELLHEALLOG = 0x150, + SMSG_SPELLENERGIZELOG = 0x151, + SMSG_BREAK_TARGET = 0x152, + CMSG_SAVE_PLAYER = 0x153, + CMSG_SETDEATHBINDPOINT = 0x154, + SMSG_BINDPOINTUPDATE = 0x155, + CMSG_GETDEATHBINDZONE = 0x156, + SMSG_BINDZONEREPLY = 0x157, + SMSG_PLAYERBOUND = 0x158, + SMSG_CLIENT_CONTROL_UPDATE = 0x159, + CMSG_REPOP_REQUEST = 0x15A, + SMSG_RESURRECT_REQUEST = 0x15B, + CMSG_RESURRECT_RESPONSE = 0x15C, + CMSG_LOOT = 0x15D, + CMSG_LOOT_MONEY = 0x15E, + CMSG_LOOT_RELEASE = 0x15F, + SMSG_LOOT_RESPONSE = 0x160, + SMSG_LOOT_RELEASE_RESPONSE = 0x161, + SMSG_LOOT_REMOVED = 0x162, + SMSG_LOOT_MONEY_NOTIFY = 0x163, + SMSG_LOOT_ITEM_NOTIFY = 0x164, + SMSG_LOOT_CLEAR_MONEY = 0x165, + SMSG_ITEM_PUSH_RESULT = 0x166, + SMSG_DUEL_REQUESTED = 0x167, + SMSG_DUEL_OUTOFBOUNDS = 0x168, + SMSG_DUEL_INBOUNDS = 0x169, + SMSG_DUEL_COMPLETE = 0x16A, + SMSG_DUEL_WINNER = 0x16B, + CMSG_DUEL_ACCEPTED = 0x16C, + CMSG_DUEL_CANCELLED = 0x16D, + SMSG_MOUNTRESULT = 0x16E, + SMSG_DISMOUNTRESULT = 0x16F, + SMSG_PUREMOUNT_CANCELLED_OBSOLETE = 0x170, // ERR_REMOVE_FROM_PVP_QUEUE_* events + CMSG_MOUNTSPECIAL_ANIM = 0x171, + SMSG_MOUNTSPECIAL_ANIM = 0x172, + SMSG_PET_TAME_FAILURE = 0x173, + CMSG_PET_SET_ACTION = 0x174, + CMSG_PET_ACTION = 0x175, + CMSG_PET_ABANDON = 0x176, + CMSG_PET_RENAME = 0x177, + SMSG_PET_NAME_INVALID = 0x178, + SMSG_PET_SPELLS = 0x179, + SMSG_PET_MODE = 0x17A, + CMSG_GOSSIP_HELLO = 0x17B, + CMSG_GOSSIP_SELECT_OPTION = 0x17C, + SMSG_GOSSIP_MESSAGE = 0x17D, + SMSG_GOSSIP_COMPLETE = 0x17E, + CMSG_NPC_TEXT_QUERY = 0x17F, + SMSG_NPC_TEXT_UPDATE = 0x180, + SMSG_NPC_WONT_TALK = 0x181, + CMSG_QUESTGIVER_STATUS_QUERY = 0x182, + SMSG_QUESTGIVER_STATUS = 0x183, + CMSG_QUESTGIVER_HELLO = 0x184, + SMSG_QUESTGIVER_QUEST_LIST = 0x185, + CMSG_QUESTGIVER_QUERY_QUEST = 0x186, + CMSG_QUESTGIVER_QUEST_AUTOLAUNCH = 0x187, + SMSG_QUESTGIVER_QUEST_DETAILS = 0x188, + CMSG_QUESTGIVER_ACCEPT_QUEST = 0x189, + CMSG_QUESTGIVER_COMPLETE_QUEST = 0x18A, + SMSG_QUESTGIVER_REQUEST_ITEMS = 0x18B, + CMSG_QUESTGIVER_REQUEST_REWARD = 0x18C, + SMSG_QUESTGIVER_OFFER_REWARD = 0x18D, + CMSG_QUESTGIVER_CHOOSE_REWARD = 0x18E, + SMSG_QUESTGIVER_QUEST_INVALID = 0x18F, + CMSG_QUESTGIVER_CANCEL = 0x190, + SMSG_QUESTGIVER_QUEST_COMPLETE = 0x191, + SMSG_QUESTGIVER_QUEST_FAILED = 0x192, + CMSG_QUESTLOG_SWAP_QUEST = 0x193, + CMSG_QUESTLOG_REMOVE_QUEST = 0x194, + SMSG_QUESTLOG_FULL = 0x195, + SMSG_QUESTUPDATE_FAILED = 0x196, + SMSG_QUESTUPDATE_FAILEDTIMER = 0x197, + SMSG_QUESTUPDATE_COMPLETE = 0x198, + SMSG_QUESTUPDATE_ADD_KILL = 0x199, + SMSG_QUESTUPDATE_ADD_ITEM = 0x19A, + CMSG_QUEST_CONFIRM_ACCEPT = 0x19B, + SMSG_QUEST_CONFIRM_ACCEPT = 0x19C, + CMSG_PUSHQUESTTOPARTY = 0x19D, + CMSG_LIST_INVENTORY = 0x19E, + SMSG_LIST_INVENTORY = 0x19F, + CMSG_SELL_ITEM = 0x1A0, + SMSG_SELL_ITEM = 0x1A1, + CMSG_BUY_ITEM = 0x1A2, + CMSG_BUY_ITEM_IN_SLOT = 0x1A3, + SMSG_BUY_ITEM = 0x1A4, + SMSG_BUY_FAILED = 0x1A5, + CMSG_TAXICLEARALLNODES = 0x1A6, + CMSG_TAXIENABLEALLNODES = 0x1A7, + CMSG_TAXISHOWNODES = 0x1A8, + SMSG_SHOWTAXINODES = 0x1A9, + CMSG_TAXINODE_STATUS_QUERY = 0x1AA, + SMSG_TAXINODE_STATUS = 0x1AB, + CMSG_TAXIQUERYAVAILABLENODES = 0x1AC, + CMSG_ACTIVATETAXI = 0x1AD, + SMSG_ACTIVATETAXIREPLY = 0x1AE, + SMSG_NEW_TAXI_PATH = 0x1AF, + CMSG_TRAINER_LIST = 0x1B0, + SMSG_TRAINER_LIST = 0x1B1, + CMSG_TRAINER_BUY_SPELL = 0x1B2, + SMSG_TRAINER_BUY_SUCCEEDED = 0x1B3, + SMSG_TRAINER_BUY_FAILED = 0x1B4, + CMSG_BINDER_ACTIVATE = 0x1B5, + SMSG_PLAYERBINDERROR = 0x1B6, + CMSG_BANKER_ACTIVATE = 0x1B7, + SMSG_SHOW_BANK = 0x1B8, + CMSG_BUY_BANK_SLOT = 0x1B9, + SMSG_BUY_BANK_SLOT_RESULT = 0x1BA, + CMSG_PETITION_SHOWLIST = 0x1BB, + SMSG_PETITION_SHOWLIST = 0x1BC, + CMSG_PETITION_BUY = 0x1BD, + CMSG_PETITION_SHOW_SIGNATURES = 0x1BE, + SMSG_PETITION_SHOW_SIGNATURES = 0x1BF, + CMSG_PETITION_SIGN = 0x1C0, + SMSG_PETITION_SIGN_RESULTS = 0x1C1, + MSG_PETITION_DECLINE = 0x1C2, + CMSG_OFFER_PETITION = 0x1C3, + CMSG_TURN_IN_PETITION = 0x1C4, + SMSG_TURN_IN_PETITION_RESULTS = 0x1C5, + CMSG_PETITION_QUERY = 0x1C6, + SMSG_PETITION_QUERY_RESPONSE = 0x1C7, + SMSG_FISH_NOT_HOOKED = 0x1C8, + SMSG_FISH_ESCAPED = 0x1C9, + CMSG_BUG = 0x1CA, + SMSG_NOTIFICATION = 0x1CB, + CMSG_PLAYED_TIME = 0x1CC, + SMSG_PLAYED_TIME = 0x1CD, + CMSG_QUERY_TIME = 0x1CE, + SMSG_QUERY_TIME_RESPONSE = 0x1CF, + SMSG_LOG_XPGAIN = 0x1D0, + SMSG_AURACASTLOG = 0x1D1, + CMSG_RECLAIM_CORPSE = 0x1D2, + CMSG_WRAP_ITEM = 0x1D3, + SMSG_LEVELUP_INFO = 0x1D4, + MSG_MINIMAP_PING = 0x1D5, + SMSG_RESISTLOG = 0x1D6, + SMSG_ENCHANTMENTLOG = 0x1D7, + CMSG_SET_SKILL_CHEAT = 0x1D8, + SMSG_START_MIRROR_TIMER = 0x1D9, + SMSG_PAUSE_MIRROR_TIMER = 0x1DA, + SMSG_STOP_MIRROR_TIMER = 0x1DB, + CMSG_PING = 0x1DC, + SMSG_PONG = 0x1DD, + SMSG_CLEAR_COOLDOWN = 0x1DE, + SMSG_GAMEOBJECT_PAGETEXT = 0x1DF, + CMSG_SETSHEATHED = 0x1E0, + SMSG_COOLDOWN_CHEAT = 0x1E1, + SMSG_SPELL_DELAYED = 0x1E2, + CMSG_QUEST_POI_QUERY = 0x1E3, + SMSG_QUEST_POI_QUERY_RESPONSE = 0x1E4, + CMSG_GHOST = 0x1E5, + CMSG_GM_INVIS = 0x1E6, + SMSG_INVALID_PROMOTION_CODE = 0x1E7, + MSG_GM_BIND_OTHER = 0x1E8, + MSG_GM_SUMMON = 0x1E9, + SMSG_ITEM_TIME_UPDATE = 0x1EA, + SMSG_ITEM_ENCHANT_TIME_UPDATE = 0x1EB, + SMSG_AUTH_CHALLENGE = 0x1EC, + CMSG_AUTH_SESSION = 0x1ED, + SMSG_AUTH_RESPONSE = 0x1EE, + MSG_GM_SHOWLABEL = 0x1EF, + CMSG_PET_CAST_SPELL = 0x1F0, + MSG_SAVE_GUILD_EMBLEM = 0x1F1, + MSG_TABARDVENDOR_ACTIVATE = 0x1F2, + SMSG_PLAY_SPELL_VISUAL = 0x1F3, + CMSG_ZONEUPDATE = 0x1F4, + SMSG_PARTYKILLLOG = 0x1F5, + SMSG_COMPRESSED_UPDATE_OBJECT = 0x1F6, + SMSG_PLAY_SPELL_IMPACT = 0x1F7, + SMSG_EXPLORATION_EXPERIENCE = 0x1F8, + CMSG_GM_SET_SECURITY_GROUP = 0x1F9, + CMSG_GM_NUKE = 0x1FA, + MSG_RANDOM_ROLL = 0x1FB, + SMSG_ENVIRONMENTALDAMAGELOG = 0x1FC, + CMSG_PLAYER_DIFFICULTY_CHANGE = 0x1FD, + SMSG_RWHOIS = 0x1FE, + SMSG_LFG_PLAYER_REWARD = 0x1FF, // uint32, uint8, uint32, uint32, uint32, uint32, uint32, uint8, for (uint8) {uint32,uint32,uint32} + SMSG_LFG_TELEPORT_DENIED = 0x200, // uint32 (1,2,4,6;0,5,7) + CMSG_UNLEARN_SPELL = 0x201, + CMSG_UNLEARN_SKILL = 0x202, + SMSG_REMOVED_SPELL = 0x203, + CMSG_DECHARGE = 0x204, + CMSG_GMTICKET_CREATE = 0x205, + SMSG_GMTICKET_CREATE = 0x206, + CMSG_GMTICKET_UPDATETEXT = 0x207, + SMSG_GMTICKET_UPDATETEXT = 0x208, + SMSG_ACCOUNT_DATA_TIMES = 0x209, + CMSG_REQUEST_ACCOUNT_DATA = 0x20A, + CMSG_UPDATE_ACCOUNT_DATA = 0x20B, + SMSG_UPDATE_ACCOUNT_DATA = 0x20C, + SMSG_CLEAR_FAR_SIGHT_IMMEDIATE = 0x20D, + SMSG_PLAYER_DIFFICULTY_CHANGE = 0x20E, + CMSG_GM_TEACH = 0x20F, + CMSG_GM_CREATE_ITEM_TARGET = 0x210, + CMSG_GMTICKET_GETTICKET = 0x211, + SMSG_GMTICKET_GETTICKET = 0x212, + CMSG_UNLEARN_TALENTS = 0x213, + SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE = 0x214, + SMSG_GAMEOBJECT_DESPAWN_ANIM = 0x215, + MSG_CORPSE_QUERY = 0x216, + CMSG_GMTICKET_DELETETICKET = 0x217, + SMSG_GMTICKET_DELETETICKET = 0x218, + SMSG_CHAT_WRONG_FACTION = 0x219, + CMSG_GMTICKET_SYSTEMSTATUS = 0x21A, + SMSG_GMTICKET_SYSTEMSTATUS = 0x21B, + CMSG_SPIRIT_HEALER_ACTIVATE = 0x21C, + CMSG_SET_STAT_CHEAT = 0x21D, + SMSG_QUEST_FORCE_REMOVE = 0x21E, // uint32 questid + CMSG_SKILL_BUY_STEP = 0x21F, + CMSG_SKILL_BUY_RANK = 0x220, + CMSG_XP_CHEAT = 0x221, + SMSG_SPIRIT_HEALER_CONFIRM = 0x222, + CMSG_CHARACTER_POINT_CHEAT = 0x223, + SMSG_GOSSIP_POI = 0x224, + CMSG_CHAT_IGNORED = 0x225, + CMSG_GM_VISION = 0x226, + CMSG_SERVER_COMMAND = 0x227, + CMSG_GM_SILENCE = 0x228, + CMSG_GM_REVEALTO = 0x229, + CMSG_GM_RESURRECT = 0x22A, + CMSG_GM_SUMMONMOB = 0x22B, + CMSG_GM_MOVECORPSE = 0x22C, + CMSG_GM_FREEZE = 0x22D, + CMSG_GM_UBERINVIS = 0x22E, + CMSG_GM_REQUEST_PLAYER_INFO = 0x22F, + SMSG_GM_PLAYER_INFO = 0x230, + CMSG_GUILD_RANK = 0x231, + CMSG_GUILD_ADD_RANK = 0x232, + CMSG_GUILD_DEL_RANK = 0x233, + CMSG_GUILD_SET_PUBLIC_NOTE = 0x234, + CMSG_GUILD_SET_OFFICER_NOTE = 0x235, + SMSG_LOGIN_VERIFY_WORLD = 0x236, + CMSG_CLEAR_EXPLORATION = 0x237, + CMSG_SEND_MAIL = 0x238, + SMSG_SEND_MAIL_RESULT = 0x239, + CMSG_GET_MAIL_LIST = 0x23A, + SMSG_MAIL_LIST_RESULT = 0x23B, + CMSG_BATTLEFIELD_LIST = 0x23C, + SMSG_BATTLEFIELD_LIST = 0x23D, + CMSG_BATTLEFIELD_JOIN = 0x23E, + SMSG_BATTLEFIELD_WIN_OBSOLETE = 0x23F, + SMSG_BATTLEFIELD_LOSE_OBSOLETE = 0x240, + CMSG_TAXICLEARNODE = 0x241, + CMSG_TAXIENABLENODE = 0x242, + CMSG_ITEM_TEXT_QUERY = 0x243, + SMSG_ITEM_TEXT_QUERY_RESPONSE = 0x244, + CMSG_MAIL_TAKE_MONEY = 0x245, + CMSG_MAIL_TAKE_ITEM = 0x246, + CMSG_MAIL_MARK_AS_READ = 0x247, + CMSG_MAIL_RETURN_TO_SENDER = 0x248, + CMSG_MAIL_DELETE = 0x249, + CMSG_MAIL_CREATE_TEXT_ITEM = 0x24A, + SMSG_SPELLLOGMISS = 0x24B, + SMSG_SPELLLOGEXECUTE = 0x24C, + SMSG_DEBUGAURAPROC = 0x24D, + SMSG_PERIODICAURALOG = 0x24E, + SMSG_SPELLDAMAGESHIELD = 0x24F, + SMSG_SPELLNONMELEEDAMAGELOG = 0x250, + CMSG_LEARN_TALENT = 0x251, + SMSG_RESURRECT_FAILED = 0x252, + CMSG_TOGGLE_PVP = 0x253, + SMSG_ZONE_UNDER_ATTACK = 0x254, + MSG_AUCTION_HELLO = 0x255, + CMSG_AUCTION_SELL_ITEM = 0x256, + CMSG_AUCTION_REMOVE_ITEM = 0x257, + CMSG_AUCTION_LIST_ITEMS = 0x258, + CMSG_AUCTION_LIST_OWNER_ITEMS = 0x259, + CMSG_AUCTION_PLACE_BID = 0x25A, + SMSG_AUCTION_COMMAND_RESULT = 0x25B, + SMSG_AUCTION_LIST_RESULT = 0x25C, + SMSG_AUCTION_OWNER_LIST_RESULT = 0x25D, + SMSG_AUCTION_BIDDER_NOTIFICATION = 0x25E, + SMSG_AUCTION_OWNER_NOTIFICATION = 0x25F, + SMSG_PROCRESIST = 0x260, + SMSG_STANDSTATE_CHANGE_FAILURE_OBSOLETE = 0x261, + SMSG_DISPEL_FAILED = 0x262, + SMSG_SPELLORDAMAGE_IMMUNE = 0x263, + CMSG_AUCTION_LIST_BIDDER_ITEMS = 0x264, + SMSG_AUCTION_BIDDER_LIST_RESULT = 0x265, + SMSG_SET_FLAT_SPELL_MODIFIER = 0x266, + SMSG_SET_PCT_SPELL_MODIFIER = 0x267, + CMSG_SET_AMMO = 0x268, + SMSG_CORPSE_RECLAIM_DELAY = 0x269, + CMSG_SET_ACTIVE_MOVER = 0x26A, + CMSG_PET_CANCEL_AURA = 0x26B, + CMSG_PLAYER_AI_CHEAT = 0x26C, + CMSG_CANCEL_AUTO_REPEAT_SPELL = 0x26D, + MSG_GM_ACCOUNT_ONLINE = 0x26E, + MSG_LIST_STABLED_PETS = 0x26F, + CMSG_STABLE_PET = 0x270, + CMSG_UNSTABLE_PET = 0x271, + CMSG_BUY_STABLE_SLOT = 0x272, + SMSG_STABLE_RESULT = 0x273, + CMSG_STABLE_REVIVE_PET = 0x274, + CMSG_STABLE_SWAP_PET = 0x275, + MSG_QUEST_PUSH_RESULT = 0x276, + SMSG_PLAY_MUSIC = 0x277, + SMSG_PLAY_OBJECT_SOUND = 0x278, + CMSG_REQUEST_PET_INFO = 0x279, + CMSG_FAR_SIGHT = 0x27A, + SMSG_SPELLDISPELLOG = 0x27B, + SMSG_DAMAGE_CALC_LOG = 0x27C, + CMSG_ENABLE_DAMAGE_LOG = 0x27D, + CMSG_GROUP_CHANGE_SUB_GROUP = 0x27E, + CMSG_REQUEST_PARTY_MEMBER_STATS = 0x27F, + CMSG_GROUP_SWAP_SUB_GROUP = 0x280, + CMSG_RESET_FACTION_CHEAT = 0x281, + CMSG_AUTOSTORE_BANK_ITEM = 0x282, + CMSG_AUTOBANK_ITEM = 0x283, + MSG_QUERY_NEXT_MAIL_TIME = 0x284, + SMSG_RECEIVED_MAIL = 0x285, + SMSG_RAID_GROUP_ONLY = 0x286, + CMSG_SET_DURABILITY_CHEAT = 0x287, + CMSG_SET_PVP_RANK_CHEAT = 0x288, + CMSG_ADD_PVP_MEDAL_CHEAT = 0x289, + CMSG_DEL_PVP_MEDAL_CHEAT = 0x28A, + CMSG_SET_PVP_TITLE = 0x28B, + SMSG_PVP_CREDIT = 0x28C, + SMSG_AUCTION_REMOVED_NOTIFICATION = 0x28D, + CMSG_GROUP_RAID_CONVERT = 0x28E, + CMSG_GROUP_ASSISTANT_LEADER = 0x28F, + CMSG_BUYBACK_ITEM = 0x290, + SMSG_SERVER_MESSAGE = 0x291, + CMSG_SET_SAVED_INSTANCE_EXTEND = 0x292, // lua: SetSavedInstanceExtend + SMSG_LFG_OFFER_CONTINUE = 0x293, + CMSG_MEETINGSTONE_CHEAT = 0x294, // not found 3.3 + SMSG_MEETINGSTONE_SETQUEUE = 0x295, // string, showed in console + CMSG_MEETINGSTONE_INFO = 0x296, // EVENT_LFG_UPDATE + SMSG_MEETINGSTONE_COMPLETE = 0x297, // EVENT_MAIL_SHOW + SMSG_MEETINGSTONE_IN_PROGRESS = 0x298, // uint32, some UPDATE_COOLDOWN events + SMSG_MEETINGSTONE_MEMBER_ADDED = 0x299, // uint32, errors: ERR_NOT_IN_GROUP (2,51) and ERR_NOT_IN_RAID (3,39,40) + CMSG_GMTICKETSYSTEM_TOGGLE = 0x29A, + CMSG_CANCEL_GROWTH_AURA = 0x29B, + SMSG_CANCEL_AUTO_REPEAT = 0x29C, + SMSG_STANDSTATE_UPDATE = 0x29D, + SMSG_LOOT_ALL_PASSED = 0x29E, + SMSG_LOOT_ROLL_WON = 0x29F, + CMSG_LOOT_ROLL = 0x2A0, + SMSG_LOOT_START_ROLL = 0x2A1, + SMSG_LOOT_ROLL = 0x2A2, + CMSG_LOOT_MASTER_GIVE = 0x2A3, + SMSG_LOOT_MASTER_LIST = 0x2A4, + SMSG_SET_FORCED_REACTIONS = 0x2A5, + SMSG_SPELL_FAILED_OTHER = 0x2A6, + SMSG_GAMEOBJECT_RESET_STATE = 0x2A7, + CMSG_REPAIR_ITEM = 0x2A8, + SMSG_CHAT_PLAYER_NOT_FOUND = 0x2A9, + MSG_TALENT_WIPE_CONFIRM = 0x2AA, + SMSG_SUMMON_REQUEST = 0x2AB, + CMSG_SUMMON_RESPONSE = 0x2AC, + MSG_MOVE_TOGGLE_GRAVITY_CHEAT = 0x2AD, + SMSG_MONSTER_MOVE_TRANSPORT = 0x2AE, + SMSG_PET_BROKEN = 0x2AF, + MSG_MOVE_FEATHER_FALL = 0x2B0, + MSG_MOVE_WATER_WALK = 0x2B1, + CMSG_SERVER_BROADCAST = 0x2B2, + CMSG_SELF_RES = 0x2B3, + SMSG_FEIGN_DEATH_RESISTED = 0x2B4, + CMSG_RUN_SCRIPT = 0x2B5, + SMSG_SCRIPT_MESSAGE = 0x2B6, + SMSG_DUEL_COUNTDOWN = 0x2B7, + SMSG_AREA_TRIGGER_MESSAGE = 0x2B8, + CMSG_SHOWING_HELM = 0x2B9, + CMSG_SHOWING_CLOAK = 0x2BA, + SMSG_LFG_ROLE_CHOSEN = 0x2BB, + SMSG_PLAYER_SKINNED = 0x2BC, + SMSG_DURABILITY_DAMAGE_DEATH = 0x2BD, + CMSG_SET_EXPLORATION = 0x2BE, + CMSG_SET_ACTIONBAR_TOGGLES = 0x2BF, + UMSG_DELETE_GUILD_CHARTER = 0x2C0, + MSG_PETITION_RENAME = 0x2C1, + SMSG_INIT_WORLD_STATES = 0x2C2, + SMSG_UPDATE_WORLD_STATE = 0x2C3, + CMSG_ITEM_NAME_QUERY = 0x2C4, + SMSG_ITEM_NAME_QUERY_RESPONSE = 0x2C5, + SMSG_PET_ACTION_FEEDBACK = 0x2C6, + CMSG_CHAR_RENAME = 0x2C7, + SMSG_CHAR_RENAME = 0x2C8, + CMSG_MOVE_SPLINE_DONE = 0x2C9, + CMSG_MOVE_FALL_RESET = 0x2CA, + SMSG_INSTANCE_SAVE_CREATED = 0x2CB, + SMSG_RAID_INSTANCE_INFO = 0x2CC, + CMSG_REQUEST_RAID_INFO = 0x2CD, + CMSG_MOVE_TIME_SKIPPED = 0x2CE, + CMSG_MOVE_FEATHER_FALL_ACK = 0x2CF, + CMSG_MOVE_WATER_WALK_ACK = 0x2D0, + CMSG_MOVE_NOT_ACTIVE_MOVER = 0x2D1, + SMSG_PLAY_SOUND = 0x2D2, + CMSG_BATTLEFIELD_STATUS = 0x2D3, + SMSG_BATTLEFIELD_STATUS = 0x2D4, + CMSG_BATTLEFIELD_PORT = 0x2D5, + MSG_INSPECT_HONOR_STATS = 0x2D6, + CMSG_BATTLEMASTER_HELLO = 0x2D7, + CMSG_MOVE_START_SWIM_CHEAT = 0x2D8, + CMSG_MOVE_STOP_SWIM_CHEAT = 0x2D9, + SMSG_FORCE_WALK_SPEED_CHANGE = 0x2DA, + CMSG_FORCE_WALK_SPEED_CHANGE_ACK = 0x2DB, + SMSG_FORCE_SWIM_BACK_SPEED_CHANGE = 0x2DC, + CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK = 0x2DD, + SMSG_FORCE_TURN_RATE_CHANGE = 0x2DE, + CMSG_FORCE_TURN_RATE_CHANGE_ACK = 0x2DF, + MSG_PVP_LOG_DATA = 0x2E0, + CMSG_LEAVE_BATTLEFIELD = 0x2E1, + CMSG_AREA_SPIRIT_HEALER_QUERY = 0x2E2, + CMSG_AREA_SPIRIT_HEALER_QUEUE = 0x2E3, + SMSG_AREA_SPIRIT_HEALER_TIME = 0x2E4, + CMSG_GM_UNTEACH = 0x2E5, + SMSG_WARDEN_DATA = 0x2E6, + CMSG_WARDEN_DATA = 0x2E7, + SMSG_GROUP_JOINED_BATTLEGROUND = 0x2E8, + MSG_BATTLEGROUND_PLAYER_POSITIONS = 0x2E9, + CMSG_PET_STOP_ATTACK = 0x2EA, + SMSG_BINDER_CONFIRM = 0x2EB, + SMSG_BATTLEGROUND_PLAYER_JOINED = 0x2EC, + SMSG_BATTLEGROUND_PLAYER_LEFT = 0x2ED, + CMSG_BATTLEMASTER_JOIN = 0x2EE, + SMSG_ADDON_INFO = 0x2EF, + CMSG_PET_UNLEARN = 0x2F0, // Deprecated 3.x + SMSG_PET_UNLEARN_CONFIRM = 0x2F1, // Deprecated 3.x + SMSG_PARTY_MEMBER_STATS_FULL = 0x2F2, + CMSG_PET_SPELL_AUTOCAST = 0x2F3, + SMSG_WEATHER = 0x2F4, + SMSG_PLAY_TIME_WARNING = 0x2F5, + SMSG_MINIGAME_SETUP = 0x2F6, + SMSG_MINIGAME_STATE = 0x2F7, + CMSG_MINIGAME_MOVE = 0x2F8, + SMSG_MINIGAME_MOVE_FAILED = 0x2F9, + SMSG_RAID_INSTANCE_MESSAGE = 0x2FA, + SMSG_COMPRESSED_MOVES = 0x2FB, + CMSG_GUILD_INFO_TEXT = 0x2FC, + SMSG_CHAT_RESTRICTED = 0x2FD, + SMSG_SPLINE_SET_RUN_SPEED = 0x2FE, + SMSG_SPLINE_SET_RUN_BACK_SPEED = 0x2FF, + SMSG_SPLINE_SET_SWIM_SPEED = 0x300, + SMSG_SPLINE_SET_WALK_SPEED = 0x301, + SMSG_SPLINE_SET_SWIM_BACK_SPEED = 0x302, + SMSG_SPLINE_SET_TURN_RATE = 0x303, + SMSG_SPLINE_MOVE_UNROOT = 0x304, + SMSG_SPLINE_MOVE_FEATHER_FALL = 0x305, + SMSG_SPLINE_MOVE_NORMAL_FALL = 0x306, + SMSG_SPLINE_MOVE_SET_HOVER = 0x307, + SMSG_SPLINE_MOVE_UNSET_HOVER = 0x308, + SMSG_SPLINE_MOVE_WATER_WALK = 0x309, + SMSG_SPLINE_MOVE_LAND_WALK = 0x30A, + SMSG_SPLINE_MOVE_START_SWIM = 0x30B, + SMSG_SPLINE_MOVE_STOP_SWIM = 0x30C, + SMSG_SPLINE_MOVE_SET_RUN_MODE = 0x30D, + SMSG_SPLINE_MOVE_SET_WALK_MODE = 0x30E, + CMSG_GM_NUKE_ACCOUNT = 0x30F, + MSG_GM_DESTROY_CORPSE = 0x310, + CMSG_GM_DESTROY_ONLINE_CORPSE = 0x311, + CMSG_ACTIVATETAXIEXPRESS = 0x312, + SMSG_SET_FACTION_ATWAR = 0x313, + SMSG_GAMETIMEBIAS_SET = 0x314, + CMSG_DEBUG_ACTIONS_START = 0x315, + CMSG_DEBUG_ACTIONS_STOP = 0x316, + CMSG_SET_FACTION_INACTIVE = 0x317, + CMSG_SET_WATCHED_FACTION = 0x318, + MSG_MOVE_TIME_SKIPPED = 0x319, + SMSG_SPLINE_MOVE_ROOT = 0x31A, + CMSG_SET_EXPLORATION_ALL = 0x31B, + SMSG_INVALIDATE_PLAYER = 0x31C, + CMSG_RESET_INSTANCES = 0x31D, + SMSG_INSTANCE_RESET = 0x31E, + SMSG_INSTANCE_RESET_FAILED = 0x31F, + SMSG_UPDATE_LAST_INSTANCE = 0x320, + MSG_RAID_TARGET_UPDATE = 0x321, + MSG_RAID_READY_CHECK = 0x322, + CMSG_LUA_USAGE = 0x323, + SMSG_PET_ACTION_SOUND = 0x324, + SMSG_PET_DISMISS_SOUND = 0x325, + SMSG_GHOSTEE_GONE = 0x326, + CMSG_GM_UPDATE_TICKET_STATUS = 0x327, + SMSG_GM_TICKET_STATUS_UPDATE = 0x328, + MSG_SET_DUNGEON_DIFFICULTY = 0x329, + CMSG_GMSURVEY_SUBMIT = 0x32A, + SMSG_UPDATE_INSTANCE_OWNERSHIP = 0x32B, + CMSG_IGNORE_KNOCKBACK_CHEAT = 0x32C, + SMSG_CHAT_PLAYER_AMBIGUOUS = 0x32D, + MSG_DELAY_GHOST_TELEPORT = 0x32E, + SMSG_SPELLINSTAKILLLOG = 0x32F, + SMSG_SPELL_UPDATE_CHAIN_TARGETS = 0x330, + CMSG_CHAT_FILTERED = 0x331, + SMSG_EXPECTED_SPAM_RECORDS = 0x332, + SMSG_SPELLSTEALLOG = 0x333, + CMSG_LOTTERY_QUERY_OBSOLETE = 0x334, + SMSG_LOTTERY_QUERY_RESULT_OBSOLETE = 0x335, + CMSG_BUY_LOTTERY_TICKET_OBSOLETE = 0x336, + SMSG_LOTTERY_RESULT_OBSOLETE = 0x337, + SMSG_CHARACTER_PROFILE = 0x338, + SMSG_CHARACTER_PROFILE_REALM_CONNECTED = 0x339, + SMSG_DEFENSE_MESSAGE = 0x33A, + SMSG_INSTANCE_DIFFICULTY = 0x33B, + MSG_GM_RESETINSTANCELIMIT = 0x33C, + SMSG_MOTD = 0x33D, + SMSG_MOVE_SET_FLIGHT = 0x33E, + SMSG_MOVE_UNSET_FLIGHT = 0x33F, + CMSG_MOVE_FLIGHT_ACK = 0x340, + MSG_MOVE_START_SWIM_CHEAT = 0x341, + MSG_MOVE_STOP_SWIM_CHEAT = 0x342, + SMSG_MOVE_SET_CAN_FLY = 0x343, + SMSG_MOVE_UNSET_CAN_FLY = 0x344, + CMSG_MOVE_SET_CAN_FLY_ACK = 0x345, + CMSG_MOVE_SET_FLY = 0x346, + CMSG_SOCKET_GEMS = 0x347, + CMSG_ARENA_TEAM_CREATE = 0x348, + SMSG_ARENA_TEAM_COMMAND_RESULT = 0x349, + UMSG_UPDATE_ARENA_TEAM_OBSOLETE = 0x34A, + CMSG_ARENA_TEAM_QUERY = 0x34B, + SMSG_ARENA_TEAM_QUERY_RESPONSE = 0x34C, + CMSG_ARENA_TEAM_ROSTER = 0x34D, + SMSG_ARENA_TEAM_ROSTER = 0x34E, + CMSG_ARENA_TEAM_INVITE = 0x34F, + SMSG_ARENA_TEAM_INVITE = 0x350, + CMSG_ARENA_TEAM_ACCEPT = 0x351, + CMSG_ARENA_TEAM_DECLINE = 0x352, + CMSG_ARENA_TEAM_LEAVE = 0x353, + CMSG_ARENA_TEAM_REMOVE = 0x354, + CMSG_ARENA_TEAM_DISBAND = 0x355, + CMSG_ARENA_TEAM_LEADER = 0x356, + SMSG_ARENA_TEAM_EVENT = 0x357, + CMSG_BATTLEMASTER_JOIN_ARENA = 0x358, + MSG_MOVE_START_ASCEND = 0x359, + MSG_MOVE_STOP_ASCEND = 0x35A, + SMSG_ARENA_TEAM_STATS = 0x35B, + CMSG_LFG_JOIN = 0x35C, // CMSG JoinLFG + CMSG_LFG_LEAVE = 0x35D, // CMSG LeaveLFG + CMSG_SEARCH_LFG_JOIN = 0x35E, // CMSG SearchLFGJoin + CMSG_SEARCH_LFG_LEAVE = 0x35F, // CMSG SearchLFGLeave + SMSG_UPDATE_LFG_LIST = 0x360, // SMSG uint32, uint32, if (uint8) { uint32 count, for (count) { uint64} }, uint32 count2, uint32, for (count2) { uint64, uint32 flags, if (flags & 0x2) {string}, if (flags & 0x10) {for (3) uint8}, if (flags & 0x80) {uint64, uint32}}, uint32 count3, uint32, for (count3) {uint64, uint32 flags, if (flags & 0x1) {uint8, uint8, uint8, for (3) uint8, uint32, uint32, uint32, uint32, uint32, uint32, float, float, uint32, uint32, uint32, uint32, uint32, float, uint32, uint32, uint32, uint32, uint32, uint32}, if (flags&0x2) string, if (flags&0x4) uint8, if (flags&0x8) uint64, if (flags&0x10) uint8, if (flags&0x20) uint32, if (flags&0x40) uint8, if (flags& 0x80) {uint64, uint32}} + SMSG_LFG_PROPOSAL_UPDATE = 0x361, // SMSG uint32, uint8, uint32, uint32, uint8, for (uint8) {uint32,uint8,uint8,uint8,uint8} + CMSG_LFG_PROPOSAL_RESULT = 0x362, // CMSG AcceptProposal, RejectProposal + SMSG_LFG_ROLE_CHECK_UPDATE = 0x363, // SMSG uint32, uint8, for (uint8) uint32, uint8, for (uint8) { uint64, uint8, uint32, uint8, } + SMSG_LFG_JOIN_RESULT = 0x364, // SMSG uint32 unk, uint32, if (unk == 6) { uint8 count, for (count) uint64 } + SMSG_LFG_QUEUE_STATUS = 0x365, // SMSG uint32 dungeon, uint32 lfgtype, uint32, uint32, uint32, uint32, uint8, uint8, uint8, uint8 + CMSG_SET_LFG_COMMENT = 0x366, // CMSG SetLFGComment + SMSG_LFG_UPDATE_PLAYER = 0x367, // SMSG uint8, if (uint8) { uint8, uint8, uint8, uint8, if (uint8) for (uint8) uint32, string} + SMSG_LFG_UPDATE_PARTY = 0x368, // SMSG uint8, if (uint8) { uint8, uint8, uint8, for (3) uint8, uint8, if (uint8) for (uint8) uint32, string} + SMSG_LFG_UPDATE_SEARCH = 0x369, // SMSG uint8 + CMSG_LFG_SET_ROLES = 0x36A, // CMSG SetLFGRoles + CMSG_LFG_SET_NEEDS = 0x36B, // CMSG SetLFGNeeds + CMSG_LFG_SET_BOOT_VOTE = 0x36C, // CMSG SetLFGBootVote + SMSG_LFG_BOOT_PLAYER = 0x36D, // SMSG uint8, uint8, uint8, uint64, uint32, uint32, uint32, uint32 + CMSG_LFD_PLAYER_LOCK_INFO_REQUEST = 0x36E, // CMSG RequestLFDPlayerLockInfo + SMSG_LFG_PLAYER_INFO = 0x36F, // SMSG uint8, for (uint8) { uint32, uint8, uint32, uint32, uint32, uint32, uint8, for (uint8) {uint32,uint32, uint32}}, uint32, for (uint32) {uint32,uint32} + CMSG_LFG_TELEPORT = 0x370, // CMSG LFGTeleport + CMSG_LFD_PARTY_LOCK_INFO_REQUEST = 0x371, // CMSG RequestLFDPartyLockInfo + SMSG_LFG_PARTY_INFO = 0x372, // SMSG uint8, for (uint8) uint64 + SMSG_TITLE_EARNED = 0x373, + CMSG_SET_TITLE = 0x374, + CMSG_CANCEL_MOUNT_AURA = 0x375, + SMSG_ARENA_ERROR = 0x376, + MSG_INSPECT_ARENA_TEAMS = 0x377, + SMSG_DEATH_RELEASE_LOC = 0x378, + CMSG_CANCEL_TEMP_ENCHANTMENT = 0x379, + SMSG_FORCED_DEATH_UPDATE = 0x37A, + CMSG_CHEAT_SET_HONOR_CURRENCY = 0x37B, + CMSG_CHEAT_SET_ARENA_CURRENCY = 0x37C, + MSG_MOVE_SET_FLIGHT_SPEED_CHEAT = 0x37D, + MSG_MOVE_SET_FLIGHT_SPEED = 0x37E, + MSG_MOVE_SET_FLIGHT_BACK_SPEED_CHEAT = 0x37F, + MSG_MOVE_SET_FLIGHT_BACK_SPEED = 0x380, + SMSG_FORCE_FLIGHT_SPEED_CHANGE = 0x381, + CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK = 0x382, + SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE = 0x383, + CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK = 0x384, + SMSG_SPLINE_SET_FLIGHT_SPEED = 0x385, + SMSG_SPLINE_SET_FLIGHT_BACK_SPEED = 0x386, + CMSG_MAELSTROM_INVALIDATE_CACHE = 0x387, + SMSG_FLIGHT_SPLINE_SYNC = 0x388, + CMSG_SET_TAXI_BENCHMARK_MODE = 0x389, + SMSG_JOINED_BATTLEGROUND_QUEUE = 0x38A, + SMSG_REALM_SPLIT = 0x38B, + CMSG_REALM_SPLIT = 0x38C, + CMSG_MOVE_CHNG_TRANSPORT = 0x38D, + MSG_PARTY_ASSIGNMENT = 0x38E, + SMSG_OFFER_PETITION_ERROR = 0x38F, + SMSG_TIME_SYNC_REQ = 0x390, + CMSG_TIME_SYNC_RESP = 0x391, + CMSG_SEND_LOCAL_EVENT = 0x392, + CMSG_SEND_GENERAL_TRIGGER = 0x393, + CMSG_SEND_COMBAT_TRIGGER = 0x394, + CMSG_MAELSTROM_GM_SENT_MAIL = 0x395, + SMSG_RESET_FAILED_NOTIFY = 0x396, + SMSG_REAL_GROUP_UPDATE = 0x397, + SMSG_LFG_DISABLED = 0x398, + CMSG_ACTIVE_PVP_CHEAT = 0x399, + CMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY = 0x39A, + SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE = 0x39B, + SMSG_CHEAT_DUMP_ITEMS_DEBUG_ONLY_RESPONSE_WRITE_FILE = 0x39C, + SMSG_UPDATE_COMBO_POINTS = 0x39D, + SMSG_VOICE_SESSION_ROSTER_UPDATE = 0x39E, + SMSG_VOICE_SESSION_LEAVE = 0x39F, + SMSG_VOICE_SESSION_ADJUST_PRIORITY = 0x3A0, + CMSG_VOICE_SET_TALKER_MUTED_REQUEST = 0x3A1, + SMSG_VOICE_SET_TALKER_MUTED = 0x3A2, + SMSG_INIT_EXTRA_AURA_INFO_OBSOLETE = 0x3A3, + SMSG_SET_EXTRA_AURA_INFO_OBSOLETE = 0x3A4, + SMSG_SET_EXTRA_AURA_INFO_NEED_UPDATE_OBSOLETE = 0x3A5, + SMSG_CLEAR_EXTRA_AURA_INFO_OBSOLETE = 0x3A6, + MSG_MOVE_START_DESCEND = 0x3A7, + CMSG_IGNORE_REQUIREMENTS_CHEAT = 0x3A8, + SMSG_IGNORE_REQUIREMENTS_CHEAT = 0x3A9, + SMSG_SPELL_CHANCE_PROC_LOG = 0x3AA, + CMSG_MOVE_SET_RUN_SPEED = 0x3AB, + SMSG_DISMOUNT = 0x3AC, + MSG_MOVE_UPDATE_CAN_FLY = 0x3AD, + MSG_RAID_READY_CHECK_CONFIRM = 0x3AE, + CMSG_VOICE_SESSION_ENABLE = 0x3AF, + SMSG_VOICE_SESSION_ENABLE = 0x3B0, + SMSG_VOICE_PARENTAL_CONTROLS = 0x3B1, + CMSG_GM_WHISPER = 0x3B2, + SMSG_GM_MESSAGECHAT = 0x3B3, + MSG_GM_GEARRATING = 0x3B4, + CMSG_COMMENTATOR_ENABLE = 0x3B5, + SMSG_COMMENTATOR_STATE_CHANGED = 0x3B6, + CMSG_COMMENTATOR_GET_MAP_INFO = 0x3B7, + SMSG_COMMENTATOR_MAP_INFO = 0x3B8, + CMSG_COMMENTATOR_GET_PLAYER_INFO = 0x3B9, + SMSG_COMMENTATOR_GET_PLAYER_INFO = 0x3BA, + SMSG_COMMENTATOR_PLAYER_INFO = 0x3BB, + CMSG_COMMENTATOR_ENTER_INSTANCE = 0x3BC, + CMSG_COMMENTATOR_EXIT_INSTANCE = 0x3BD, + CMSG_COMMENTATOR_INSTANCE_COMMAND = 0x3BE, + SMSG_CLEAR_TARGET = 0x3BF, + CMSG_BOT_DETECTED = 0x3C0, + SMSG_CROSSED_INEBRIATION_THRESHOLD = 0x3C1, + CMSG_CHEAT_PLAYER_LOGIN = 0x3C2, + CMSG_CHEAT_PLAYER_LOOKUP = 0x3C3, + SMSG_CHEAT_PLAYER_LOOKUP = 0x3C4, + SMSG_KICK_REASON = 0x3C5, + MSG_RAID_READY_CHECK_FINISHED = 0x3C6, + CMSG_COMPLAIN = 0x3C7, + SMSG_COMPLAIN_RESULT = 0x3C8, + SMSG_FEATURE_SYSTEM_STATUS = 0x3C9, + CMSG_GM_SHOW_COMPLAINTS = 0x3CA, + CMSG_GM_UNSQUELCH = 0x3CB, + CMSG_CHANNEL_SILENCE_VOICE = 0x3CC, + CMSG_CHANNEL_SILENCE_ALL = 0x3CD, + CMSG_CHANNEL_UNSILENCE_VOICE = 0x3CE, + CMSG_CHANNEL_UNSILENCE_ALL = 0x3CF, + CMSG_TARGET_CAST = 0x3D0, + CMSG_TARGET_SCRIPT_CAST = 0x3D1, + CMSG_CHANNEL_DISPLAY_LIST = 0x3D2, + CMSG_SET_ACTIVE_VOICE_CHANNEL = 0x3D3, + CMSG_GET_CHANNEL_MEMBER_COUNT = 0x3D4, + SMSG_CHANNEL_MEMBER_COUNT = 0x3D5, + CMSG_CHANNEL_VOICE_ON = 0x3D6, + CMSG_CHANNEL_VOICE_OFF = 0x3D7, + CMSG_DEBUG_LIST_TARGETS = 0x3D8, + SMSG_DEBUG_LIST_TARGETS = 0x3D9, + SMSG_AVAILABLE_VOICE_CHANNEL = 0x3DA, + CMSG_ADD_VOICE_IGNORE = 0x3DB, + CMSG_DEL_VOICE_IGNORE = 0x3DC, + CMSG_PARTY_SILENCE = 0x3DD, + CMSG_PARTY_UNSILENCE = 0x3DE, + MSG_NOTIFY_PARTY_SQUELCH = 0x3DF, + SMSG_COMSAT_RECONNECT_TRY = 0x3E0, + SMSG_COMSAT_DISCONNECT = 0x3E1, + SMSG_COMSAT_CONNECT_FAIL = 0x3E2, + SMSG_VOICE_CHAT_STATUS = 0x3E3, + CMSG_REPORT_PVP_AFK = 0x3E4, + SMSG_REPORT_PVP_AFK_RESULT = 0x3E5, // SMSG? + CMSG_GUILD_BANKER_ACTIVATE = 0x3E6, + CMSG_GUILD_BANK_QUERY_TAB = 0x3E7, + SMSG_GUILD_BANK_LIST = 0x3E8, + CMSG_GUILD_BANK_SWAP_ITEMS = 0x3E9, + CMSG_GUILD_BANK_BUY_TAB = 0x3EA, + CMSG_GUILD_BANK_UPDATE_TAB = 0x3EB, + CMSG_GUILD_BANK_DEPOSIT_MONEY = 0x3EC, + CMSG_GUILD_BANK_WITHDRAW_MONEY = 0x3ED, + MSG_GUILD_BANK_LOG_QUERY = 0x3EE, + CMSG_SET_CHANNEL_WATCH = 0x3EF, + SMSG_USERLIST_ADD = 0x3F0, + SMSG_USERLIST_REMOVE = 0x3F1, + SMSG_USERLIST_UPDATE = 0x3F2, + CMSG_CLEAR_CHANNEL_WATCH = 0x3F3, + SMSG_INSPECT_TALENT = 0x3F4, + SMSG_GOGOGO_OBSOLETE = 0x3F5, + SMSG_ECHO_PARTY_SQUELCH = 0x3F6, + CMSG_SET_TITLE_SUFFIX = 0x3F7, + CMSG_SPELLCLICK = 0x3F8, + SMSG_LOOT_LIST = 0x3F9, + CMSG_GM_CHARACTER_RESTORE = 0x3FA, + CMSG_GM_CHARACTER_SAVE = 0x3FB, + SMSG_VOICESESSION_FULL = 0x3FC, + MSG_GUILD_PERMISSIONS = 0x3FD, + MSG_GUILD_BANK_MONEY_WITHDRAWN = 0x3FE, + MSG_GUILD_EVENT_LOG_QUERY = 0x3FF, + CMSG_MAELSTROM_RENAME_GUILD = 0x400, + CMSG_GET_MIRRORIMAGE_DATA = 0x401, + SMSG_MIRRORIMAGE_DATA = 0x402, + SMSG_FORCE_DISPLAY_UPDATE = 0x403, + SMSG_SPELL_CHANCE_RESIST_PUSHBACK = 0x404, + CMSG_IGNORE_DIMINISHING_RETURNS_CHEAT = 0x405, + SMSG_IGNORE_DIMINISHING_RETURNS_CHEAT = 0x406, + CMSG_KEEP_ALIVE = 0x407, + SMSG_RAID_READY_CHECK_ERROR = 0x408, + CMSG_OPT_OUT_OF_LOOT = 0x409, + MSG_QUERY_GUILD_BANK_TEXT = 0x40A, + CMSG_SET_GUILD_BANK_TEXT = 0x40B, + CMSG_SET_GRANTABLE_LEVELS = 0x40C, + CMSG_GRANT_LEVEL = 0x40D, + CMSG_REFER_A_FRIEND = 0x40E, + MSG_GM_CHANGE_ARENA_RATING = 0x40F, + CMSG_DECLINE_CHANNEL_INVITE = 0x410, + SMSG_GROUPACTION_THROTTLED = 0x411, // SMSG? + SMSG_OVERRIDE_LIGHT = 0x412, + SMSG_TOTEM_CREATED = 0x413, + CMSG_TOTEM_DESTROYED = 0x414, + CMSG_EXPIRE_RAID_INSTANCE = 0x415, + CMSG_NO_SPELL_VARIANCE = 0x416, + CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY = 0x417, + SMSG_QUESTGIVER_STATUS_MULTIPLE = 0x418, + CMSG_SET_PLAYER_DECLINED_NAMES = 0x419, + SMSG_SET_PLAYER_DECLINED_NAMES_RESULT = 0x41A, + CMSG_QUERY_SERVER_BUCK_DATA = 0x41B, + CMSG_CLEAR_SERVER_BUCK_DATA = 0x41C, + SMSG_SERVER_BUCK_DATA = 0x41D, + SMSG_SEND_UNLEARN_SPELLS = 0x41E, + SMSG_PROPOSE_LEVEL_GRANT = 0x41F, + CMSG_ACCEPT_LEVEL_GRANT = 0x420, + SMSG_REFER_A_FRIEND_FAILURE = 0x421, + SMSG_SPLINE_MOVE_SET_FLYING = 0x422, + SMSG_SPLINE_MOVE_UNSET_FLYING = 0x423, + SMSG_SUMMON_CANCEL = 0x424, + CMSG_CHANGE_PERSONAL_ARENA_RATING = 0x425, + CMSG_ALTER_APPEARANCE = 0x426, + SMSG_ENABLE_BARBER_SHOP = 0x427, + SMSG_BARBER_SHOP_RESULT = 0x428, + CMSG_CALENDAR_GET_CALENDAR = 0x429, + CMSG_CALENDAR_GET_EVENT = 0x42A, + CMSG_CALENDAR_GUILD_FILTER = 0x42B, + CMSG_CALENDAR_ARENA_TEAM = 0x42C, + CMSG_CALENDAR_ADD_EVENT = 0x42D, + CMSG_CALENDAR_UPDATE_EVENT = 0x42E, + CMSG_CALENDAR_REMOVE_EVENT = 0x42F, + CMSG_CALENDAR_COPY_EVENT = 0x430, + CMSG_CALENDAR_EVENT_INVITE = 0x431, + CMSG_CALENDAR_EVENT_RSVP = 0x432, + CMSG_CALENDAR_EVENT_REMOVE_INVITE = 0x433, + CMSG_CALENDAR_EVENT_STATUS = 0x434, + CMSG_CALENDAR_EVENT_MODERATOR_STATUS = 0x435, + SMSG_CALENDAR_SEND_CALENDAR = 0x436, + SMSG_CALENDAR_SEND_EVENT = 0x437, + SMSG_CALENDAR_FILTER_GUILD = 0x438, + SMSG_CALENDAR_ARENA_TEAM = 0x439, + SMSG_CALENDAR_EVENT_INVITE = 0x43A, + SMSG_CALENDAR_EVENT_INVITE_REMOVED = 0x43B, + SMSG_CALENDAR_EVENT_STATUS = 0x43C, + SMSG_CALENDAR_COMMAND_RESULT = 0x43D, + SMSG_CALENDAR_RAID_LOCKOUT_ADDED = 0x43E, + SMSG_CALENDAR_RAID_LOCKOUT_REMOVED = 0x43F, + SMSG_CALENDAR_EVENT_INVITE_ALERT = 0x440, + SMSG_CALENDAR_EVENT_INVITE_REMOVED_ALERT = 0x441, + SMSG_CALENDAR_EVENT_INVITE_STATUS_ALERT = 0x442, + SMSG_CALENDAR_EVENT_REMOVED_ALERT = 0x443, + SMSG_CALENDAR_EVENT_UPDATED_ALERT = 0x444, + SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT = 0x445, + CMSG_CALENDAR_COMPLAIN = 0x446, + CMSG_CALENDAR_GET_NUM_PENDING = 0x447, + SMSG_CALENDAR_SEND_NUM_PENDING = 0x448, + CMSG_SAVE_DANCE = 0x449, + SMSG_NOTIFY_DANCE = 0x44A, + CMSG_PLAY_DANCE = 0x44B, + SMSG_PLAY_DANCE = 0x44C, + CMSG_LOAD_DANCES = 0x44D, + CMSG_STOP_DANCE = 0x44E, + SMSG_STOP_DANCE = 0x44F, + CMSG_SYNC_DANCE = 0x450, + CMSG_DANCE_QUERY = 0x451, + SMSG_DANCE_QUERY_RESPONSE = 0x452, + SMSG_INVALIDATE_DANCE = 0x453, + CMSG_DELETE_DANCE = 0x454, + SMSG_LEARNED_DANCE_MOVES = 0x455, + CMSG_LEARN_DANCE_MOVE = 0x456, + CMSG_UNLEARN_DANCE_MOVE = 0x457, + CMSG_SET_RUNE_COUNT = 0x458, + CMSG_SET_RUNE_COOLDOWN = 0x459, + MSG_MOVE_SET_PITCH_RATE_CHEAT = 0x45A, + MSG_MOVE_SET_PITCH_RATE = 0x45B, + SMSG_FORCE_PITCH_RATE_CHANGE = 0x45C, + CMSG_FORCE_PITCH_RATE_CHANGE_ACK = 0x45D, + SMSG_SPLINE_SET_PITCH_RATE = 0x45E, + SMSG_MOVE_ABANDON_TRANSPORT = 0x45F, + SMSG_CALENDAR_UPDATE_INVITE_LIST = 0x460, + SMSG_CALENDAR_UPDATE_INVITE_LIST2 = 0x461, + CMSG_UPDATE_MISSILE_TRAJECTORY = 0x462, + SMSG_UPDATE_ACCOUNT_DATA_COMPLETE = 0x463, + SMSG_TRIGGER_MOVIE = 0x464, + CMSG_COMPLETE_MOVIE = 0x465, + CMSG_SET_GLYPH_SLOT = 0x466, + CMSG_SET_GLYPH = 0x467, + SMSG_ACHIEVEMENT_EARNED = 0x468, + SMSG_DYNAMIC_DROP_ROLL_RESULT = 0x469, + SMSG_CRITERIA_UPDATE = 0x46A, + CMSG_QUERY_INSPECT_ACHIEVEMENTS = 0x46B, + SMSG_RESPOND_INSPECT_ACHIEVEMENTS = 0x46C, + CMSG_DISMISS_CONTROLLED_VEHICLE = 0x46D, + CMSG_COMPLETE_ACHIEVEMENT_CHEAT = 0x46E, + SMSG_QUESTUPDATE_ADD_PVP_KILL = 0x46F, + CMSG_SET_CRITERIA_CHEAT = 0x470, + SMSG_CALENDAR_UPDATE_INVITE_LIST3 = 0x471, + CMSG_UNITANIMTIER_CHEAT = 0x472, + CMSG_CHAR_CUSTOMIZE = 0x473, + SMSG_CHAR_CUSTOMIZE = 0x474, + SMSG_PET_RENAMEABLE = 0x475, + CMSG_REQUEST_VEHICLE_EXIT = 0x476, + CMSG_REQUEST_VEHICLE_PREV_SEAT = 0x477, + CMSG_REQUEST_VEHICLE_NEXT_SEAT = 0x478, + CMSG_REQUEST_VEHICLE_SWITCH_SEAT = 0x479, + CMSG_PET_LEARN_TALENT = 0x47A, + CMSG_PET_UNLEARN_TALENTS = 0x47B, + SMSG_SET_PHASE_SHIFT = 0x47C, + SMSG_ALL_ACHIEVEMENT_DATA = 0x47D, + CMSG_FORCE_SAY_CHEAT = 0x47E, + SMSG_HEALTH_UPDATE = 0x47F, + SMSG_POWER_UPDATE = 0x480, + CMSG_GAMEOBJ_REPORT_USE = 0x481, + SMSG_HIGHEST_THREAT_UPDATE = 0x482, + SMSG_THREAT_UPDATE = 0x483, + SMSG_THREAT_REMOVE = 0x484, + SMSG_THREAT_CLEAR = 0x485, + SMSG_CONVERT_RUNE = 0x486, + SMSG_RESYNC_RUNES = 0x487, + SMSG_ADD_RUNE_POWER = 0x488, + CMSG_START_QUEST = 0x489, + CMSG_REMOVE_GLYPH = 0x48A, + CMSG_DUMP_OBJECTS = 0x48B, + SMSG_DUMP_OBJECTS_DATA = 0x48C, + CMSG_DISMISS_CRITTER = 0x48D, + SMSG_NOTIFY_DEST_LOC_SPELL_CAST = 0x48E, + CMSG_AUCTION_LIST_PENDING_SALES = 0x48F, + SMSG_AUCTION_LIST_PENDING_SALES = 0x490, + SMSG_MODIFY_COOLDOWN = 0x491, + SMSG_PET_UPDATE_COMBO_POINTS = 0x492, + CMSG_ENABLETAXI = 0x493, + SMSG_PRE_RESURRECT = 0x494, + SMSG_AURA_UPDATE_ALL = 0x495, + SMSG_AURA_UPDATE = 0x496, + CMSG_FLOOD_GRACE_CHEAT = 0x497, + SMSG_SERVER_FIRST_ACHIEVEMENT = 0x498, + SMSG_PET_LEARNED_SPELL = 0x499, + SMSG_PET_REMOVED_SPELL = 0x49A, + CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE = 0x49B, + CMSG_HEARTH_AND_RESURRECT = 0x49C, // not changed in 3.1 + SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA = 0x49D, // not changed 9626 + SMSG_CRITERIA_DELETED = 0x49E, // not changed 9626 + SMSG_ACHIEVEMENT_DELETED = 0x49F, // not changed 9626 + CMSG_SERVER_INFO_QUERY = 0x4A0, // not found + SMSG_SERVER_INFO_RESPONSE = 0x4A1, // not found + CMSG_CHECK_LOGIN_CRITERIA = 0x4A2, // not found + SMSG_SERVER_BUCK_DATA_START = 0x4A3, // not found + CMSG_QUERY_VEHICLE_STATUS = 0x4A4, // not found + UMSG_UNKNOWN_1189 = 0x4A5, // not found, old SMSG_PET_GUIDS + SMSG_BATTLEGROUND_INFO_THROTTLED = 0x4A6, // empty, "You can't do that yet" + SMSG_PLAYER_VEHICLE_DATA = 0x4A7, // smsg guid+uint32 (vehicle) + CMSG_PLAYER_VEHICLE_ENTER = 0x4A8, // cmsg uint64 + CMSG_EJECT_PASSENGER = 0x4A9, // cmsg uint64 + SMSG_PET_GUIDS = 0x4AA, // shifted+5 + SMSG_CLIENTCACHE_VERSION = 0x4AB, // shifted+5 + UMSG_UNKNOWN_1196 = 0x4AC, // not found + UMSG_UNKNOWN_1197 = 0x4AD, // not found + UMSG_UNKNOWN_1198 = 0x4AE, // not found + UMSG_UNKNOWN_1199 = 0x4AF, // not found + UMSG_UNKNOWN_1200 = 0x4B0, // not found + UMSG_UNKNOWN_1201 = 0x4B1, // not found + SMSG_ITEM_REFUND_INFO_RESPONSE = 0x4B2, // refund item info + CMSG_ITEM_REFUND_INFO = 0x4B3, // refund request? + CMSG_ITEM_REFUND = 0x4B4, // lua: ContainerRefundItemPurchase + SMSG_ITEM_REFUND_RESULT = 0x4B5, // refund item result + CMSG_CORPSE_MAP_POSITION_QUERY = 0x4B6, // CMSG, uint32 + SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE = 0x4B7, // SMSG, 3*float+float + UMSG_UNKNOWN_1208 = 0x4B8, // not found + UMSG_UNKNOWN_1209 = 0x4B9, // not found + CMSG_CALENDAR_CONTEXT_EVENT_SIGNUP = 0x4BA, // CMSG, uint64, lua: CalendarContextEventSignUp + SMSG_CALENDAR_ACTION_PENDING = 0x4BB, // SMSG, calendar related EVENT_CALENDAR_ACTION_PENDING + SMSG_EQUIPMENT_SET_LIST = 0x4BC, // SMSG, equipment manager list? + CMSG_EQUIPMENT_SET_SAVE = 0x4BD, // CMSG, lua: SaveEquipmentSet + CMSG_UPDATE_PROJECTILE_POSITION = 0x4BE, // CMSG, uint64 caster, uint32 spellId, uint8 castId, vector3 position + SMSG_SET_PROJECTILE_POSITION = 0x4BF, // SMSG, uint64 caster, uint8 castId, vector3 position + SMSG_TALENTS_INFO = 0x4C0, // SMSG, talents related + CMSG_LEARN_PREVIEW_TALENTS = 0x4C1, // CMSG, lua: LearnPreviewTalents (for player?) + CMSG_LEARN_PREVIEW_TALENTS_PET = 0x4C2, // CMSG, lua: LearnPreviewTalents (for pet?) + UMSG_UNKNOWN_1219 = 0x4C3, // not found 3.2 + UMSG_UNKNOWN_1220 = 0x4C4, // not found 3.2 + UMSG_UNKNOWN_1221 = 0x4C5, // not found 3.2 + UMSG_UNKNOWN_1222 = 0x4C6, // not found 3.2 + SMSG_ARENA_OPPONENT_UPDATE = 0x4C7, // uint64, EVENT_ARENA_OPPONENT_UPDATE + SMSG_ARENA_TEAM_CHANGE_FAILED_QUEUED = 0x4C8, // uint32 "Can't modify arena team while queued or in a match." 3.2 + UMSG_UNKNOWN_1225 = 0x4C9, // not found 3.2 + UMSG_UNKNOWN_1226 = 0x4CA, // not found 3.2 + UMSG_UNKNOWN_1227 = 0x4CB, // not found 3.2 + UMSG_UNKNOWN_1228 = 0x4CC, // not found 3.2 + SMSG_MULTIPLE_PACKETS = 0x4CD, // SMSG, handles any opcode + SMSG_FORCE_UNK1_SPEED_CHANGE = 0x4CE, // SMSG, movement related + CMSG_FORCE_UNK1_SPEED_CHANGE_ACK = 0x4CF, // movement related + SMSG_FORCE_UNK2_SPEED_CHANGE = 0x4D0, // SMSG, movement related + CMSG_FORCE_UNK2_SPEED_CHANGE_ACK = 0x4D1, // movement related + MSG_MOVE_UNKNOWN_1234 = 0x4D2, // SMSG, movement related + SMSG_SPLINE_MOVE_UNKNOWN_1235 = 0x4D3, // SMSG, movement related + SMSG_SPLINE_MOVE_UNKNOWN_1236 = 0x4D4, // SMSG, movement related + CMSG_EQUIPMENT_SET_USE = 0x4D5, // CMSG, lua: UseEquipmentSet + SMSG_EQUIPMENT_SET_USE_RESULT = 0x4D6, // SMSG, UseEquipmentSetResult? + UMSG_UNKNOWN_1239 = 0x4D7, // not found 3.2 + SMSG_UNKNOWN_1240 = 0x4D8, // SMSG, uint64, string, doing nothing + CMSG_CHAR_FACTION_CHANGE = 0x4D9, // lua: CreateCharacter (PFC client response) + SMSG_CHAR_FACTION_CHANGE = 0x4DA, // response to 1241 (PFC server response) + UMSG_UNKNOWN_1243 = 0x4DB, // not found 3.2 + UMSG_UNKNOWN_1244 = 0x4DC, // not found 3.2 + UMSG_UNKNOWN_1245 = 0x4DD, // not found 3.2 + SMSG_BATTLEFIELD_MGR_ENTRY_INVITE = 0x4DE, // uint32, EVENT_BATTLEFIELD_MGR_ENTRY_INVITE + CMSG_BATTLEFIELD_MGR_ENTRY_INVITE_RESPONSE = 0x4DF, // lua: BattlefieldMgrEntryInviteResponse + SMSG_BATTLEFIELD_MGR_ENTERED = 0x4E0, // uint32, uint8, uint8 EVENT_BATTLEFIELD_MGR_ENTERED + SMSG_BATTLEFIELD_MGR_QUEUE_INVITE = 0x4E1, // uint32 EVENT_BATTLEFIELD_MGR_QUEUE_INVITE + CMSG_BATTLEFIELD_MGR_QUEUE_INVITE_RESPONSE = 0x4E2, // lua: BattlefieldMgrQueueInviteResponse + CMSG_BATTLEFIELD_MGR_QUEUE_REQUEST = 0x4E3, // lua: BattlefieldMgrQueueRequest + SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE = 0x4E4, // uint32, uint8 EVENT_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE + SMSG_BATTLEFIELD_MGR_EJECT_PENDING = 0x4E5, // uint32 EVENT_BATTLEFIELD_MGR_EJECT_PENDING + SMSG_BATTLEFIELD_MGR_EJECTED = 0x4E6, // uint32, uint32, uint8 EVENT_BATTLEFIELD_MGR_EJECTED + CMSG_BATTLEFIELD_MGR_EXIT_REQUEST = 0x4E7, // lua: BattlefieldMgrExitRequest + SMSG_BATTLEFIELD_MGR_STATE_CHANGE = 0x4E8, // uint32, uint32 EVENT_BATTLEFIELD_MGR_STATE_CHANGE + UMSG_UNKNOWN_1257 = 0x4E9, // not found 3.2 + UMSG_UNKNOWN_1258 = 0x4EA, // not found 3.2 + MSG_SET_RAID_DIFFICULTY = 0x4EB, // lua: SetRaidDifficulty + UMSG_UNKNOWN_1260 = 0x4EC, // not found 3.2 + SMSG_TOGGLE_XP_GAIN = 0x4ED, // enable/disable XP gain console message + SMSG_GMRESPONSE_DB_ERROR = 0x4EE, // empty + SMSG_GMRESPONSE_RECEIVED = 0x4EF, // uint32, uint32, string[2000], string[4000][4] + CMSG_GMRESPONSE_RESOLVE = 0x4F0, // lua: GMResponseResolve + SMSG_GMRESPONSE_STATUS_UPDATE = 0x4F1, // uint8 (1 - EVENT_GMSURVEY_DISPLAY, 0 - EVENT_UPDATE_TICKET) + UMSG_UNKNOWN_1266 = 0x4F2, // not found 3.2 + UMSG_UNKNOWN_1267 = 0x4F3, // not found 3.2 + UMSG_UNKNOWN_1268 = 0x4F4, // not found 3.2 + UMSG_UNKNOWN_1269 = 0x4F5, // not found 3.2 + CMSG_WORLD_STATE_UI_TIMER_UPDATE = 0x4F6, + SMSG_WORLD_STATE_UI_TIMER_UPDATE = 0x4F7, + CMSG_CHAR_RACE_CHANGE = 0x4F8, // called from lua: CreateCharacter, paid race change + UMSG_UNKNOWN_1273 = 0x4F9, // not found 10554 + SMSG_TALENTS_INVOLUNTARILY_RESET = 0x4FA, // uint8 EVENT_TALENTS_INVOLUNTARILY_RESET + UMSG_UNKNOWN_1275 = 0x4FB, // not found 10554 + SMSG_UNKNOWN_1276 = 0x4FC, // does nothing in 10554 + SMSG_LOOT_SLOT_CHANGED = 0x4FD, // EVENT_LOOT_SLOT_CHANGED + UMSG_UNKNOWN_1278 = 0x4FE, // not found 10596 + CMSG_READY_FOR_ACCOUNT_DATA_TIMES = 0x4FF, // lua: ReadyForAccountDataTimes + CMSG_QUERY_QUESTS_COMPLETED = 0x500, // lua: QueryQuestsCompleted + SMSG_QUERY_QUESTS_COMPLETED_RESPONSE = 0x501, // response to 0x500 + CMSG_GM_REPORT_LAG = 0x502, // lua: GMReportLag + UMSG_UNKNOWN_1283 = 0x503, + UMSG_UNKNOWN_1284 = 0x504, + UMSG_UNKNOWN_1285 = 0x505, + SMSG_CORPSE_NOT_IN_INSTANCE = 0x506, + UMSG_UNKNOWN_1287 = 0x507, // not found + CMSG_SET_ALLOW_LOW_LEVEL_RAID1 = 0x508, // lua: SetAllowLowLevelRaid + CMSG_SET_ALLOW_LOW_LEVEL_RAID2 = 0x509, // lua: SetAllowLowLevelRaid + SMSG_CAMERA_SHAKE = 0x50A, // uint32 SpellEffectCameraShakes.dbc index, uint32 + SMSG_UPDATE_ITEM_ENCHANTMENTS = 0x50B, // some item update packet? + UMSG_UNKNOWN_1292 = 0x50C, // not found + SMSG_REDIRECT_CLIENT = 0x50D, // uint32 ip, uint16 port, uint32 unk, uint8[20] hash (ip + port, seed=sessionkey) + CMSG_REDIRECTION_FAILED = 0x50E, // something with networking + SMSG_UNKNOWN_1295 = 0x50F, // not found - disconnect + CMSG_UNKNOWN_1296 = 0x510, // something with networking + SMSG_FORCE_SEND_QUEUED_PACKETS = 0x511, // not found - crash + CMSG_REDIRECTION_AUTH_PROOF = 0x512, // something with networking + UMSG_UNKNOWN_1299 = 0x513, // not found + SMSG_UNKNOWN_1300 = 0x514, // SMSG + SMSG_UNKNOWN_1301 = 0x515, // event 0x204 (opens dungeon finder, probably for outdoor bosses) + SMSG_UNKNOWN_1302 = 0x516, // something with player movement (move event 58?) + CMSG_UNKNOWN_1303 = 0x517, // something with player movement (move event 58?) + SMSG_UNKNOWN_1304 = 0x518, // something with player movement (move event 58?), speed packet + UMSG_UNKNOWN_1305 = 0x519, // not found + UMSG_UNKNOWN_1306 = 0x51A, // not found + NUM_MSG_TYPES = 0x51B +}; + +/// Player state +enum SessionStatus +{ + STATUS_AUTHED = 0, ///< Player authenticated (_player == NULL, m_playerRecentlyLogout = false or will be reset before handler call, m_GUID have garbage) + STATUS_LOGGEDIN, ///< Player in game (_player != NULL, m_GUID == _player->GetGUID(), inWorld()) + STATUS_TRANSFER, ///< Player transferring to another map (_player != NULL, m_GUID == _player->GetGUID(), !inWorld()) + STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, ///< _player!= NULL or _player == NULL && m_playerRecentlyLogout, m_GUID store last _player guid) + STATUS_NEVER ///< Opcode not accepted from client (deprecated or server side only) +}; + +class WorldPacket; + +struct OpcodeHandler +{ + char const* name; + SessionStatus status; + void (WorldSession::*handler)(WorldPacket& recvPacket); +}; + +extern OpcodeHandler opcodeTable[NUM_MSG_TYPES]; + +/// Lookup opcode name for human understandable logging +inline const char* LookupOpcodeName(uint16 id) +{ + if (id >= NUM_MSG_TYPES) + return "Received unknown opcode, it's more than max!"; + return opcodeTable[id].name; +} +#endif +/// @} diff --git a/src/server/game/Server/Protocol/WorldLog.cpp b/src/server/game/Server/Protocol/WorldLog.cpp new file mode 100644 index 00000000000..7c6c4020336 --- /dev/null +++ b/src/server/game/Server/Protocol/WorldLog.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** \file + \ingroup u2w +*/ + +#include "WorldLog.h" +#include "Policies/SingletonImp.h" +#include "Config/ConfigEnv.h" +#include "Log.h" + +#define CLASS_LOCK Trinity::ClassLevelLockable +INSTANTIATE_SINGLETON_2(WorldLog, CLASS_LOCK); +INSTANTIATE_CLASS_MUTEX(WorldLog, ACE_Thread_Mutex); + +WorldLog::WorldLog() : i_file(NULL) +{ + Initialize(); +} + +WorldLog::~WorldLog() +{ + if (i_file != NULL) + fclose(i_file); + i_file = NULL; +} + +/// Open the log file (if specified so in the configuration file) +void WorldLog::Initialize() +{ + std::string logsDir = sConfig.GetStringDefault("LogsDir",""); + + if (!logsDir.empty()) + { + if ((logsDir.at(logsDir.length()-1) != '/') && (logsDir.at(logsDir.length()-1) != '\\')) + logsDir.append("/"); + } + + std::string logname = sConfig.GetStringDefault("WorldLogFile", ""); + if (!logname.empty()) + { + i_file = fopen((logsDir+logname).c_str(), "w"); + } + + m_dbWorld = sConfig.GetBoolDefault("LogDB.World", false); // can be VERY heavy if enabled +} + +void WorldLog::outTimestampLog(char const *fmt, ...) +{ + if (LogWorld()) + { + Guard guard(*this); + ASSERT(i_file); + + Log::outTimestamp(i_file); + va_list args; + va_start(args, fmt); + vfprintf(i_file, fmt, args); + //fprintf(i_file, "\n"); + va_end(args); + + fflush(i_file); + } + + if (sLog.GetLogDB() && m_dbWorld) + { + va_list ap2; + va_start(ap2, fmt); + char nnew_str[MAX_QUERY_LEN]; + vsnprintf(nnew_str, MAX_QUERY_LEN, fmt, ap2); + sLog.outDB(LOG_TYPE_WORLD, nnew_str); + va_end(ap2); + } +} + +void WorldLog::outLog(char const *fmt, ...) +{ + if (LogWorld()) + { + Guard guard(*this); + ASSERT(i_file); + + va_list args; + va_start(args, fmt); + vfprintf(i_file, fmt, args); + //fprintf(i_file, "\n"); + va_end(args); + + fflush(i_file); + } + + if (sLog.GetLogDB() && m_dbWorld) + { + va_list ap2; + va_start(ap2, fmt); + char nnew_str[MAX_QUERY_LEN]; + vsnprintf(nnew_str, MAX_QUERY_LEN, fmt, ap2); + sLog.outDB(LOG_TYPE_WORLD, nnew_str); + va_end(ap2); + } +} + +#define sWorldLog WorldLog::Instance() + diff --git a/src/server/game/Server/Protocol/WorldLog.h b/src/server/game/Server/Protocol/WorldLog.h new file mode 100644 index 00000000000..4ee9bb178ec --- /dev/null +++ b/src/server/game/Server/Protocol/WorldLog.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/// \addtogroup u2w +/// @{ +/// \file + +#ifndef TRINITY_WORLDLOG_H +#define TRINITY_WORLDLOG_H + +#include "Common.h" +#include "Policies/Singleton.h" +#include "Errors.h" + +#include + +/// %Log packets to a file +class WorldLog : public Trinity::Singleton > +{ + friend class Trinity::OperatorNew; + WorldLog(); + WorldLog(const WorldLog &); + WorldLog& operator=(const WorldLog &); + typedef Trinity::ClassLevelLockable::Lock Guard; + + /// Close the file in destructor + ~WorldLog(); + + public: + void Initialize(); + /// Is the world logger active? + bool LogWorld(void) const { return (i_file != NULL); } + /// %Log to the file + void outLog(char const *fmt, ...); + void outTimestampLog(char const *fmt, ...); + + private: + FILE *i_file; + + bool m_dbWorld; +}; + +#define sWorldLog WorldLog::Instance() +#endif +/// @} + diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp new file mode 100644 index 00000000000..bc737717840 --- /dev/null +++ b/src/server/game/Server/WorldSession.cpp @@ -0,0 +1,959 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** \file + \ingroup u2w +*/ + +#include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it +#include "Common.h" +#include "Database/DatabaseEnv.h" +#include "Log.h" +#include "Opcodes.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Player.h" +#include "Vehicle.h" +#include "ObjectMgr.h" +#include "Group.h" +#include "Guild.h" +#include "World.h" +#include "ObjectAccessor.h" +#include "BattleGroundMgr.h" +#include "OutdoorPvPMgr.h" +#include "MapManager.h" +#include "SocialMgr.h" +#include "zlib/zlib.h" +#include "ScriptMgr.h" +#include "LFGMgr.h" + +/// WorldSession constructor +WorldSession::WorldSession(uint32 id, WorldSocket *sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale) : +LookingForGroup_auto_join(false), LookingForGroup_auto_add(false), m_muteTime(mute_time), +_player(NULL), m_Socket(sock),_security(sec), _accountId(id), m_expansion(expansion), +m_sessionDbcLocale(sWorld.GetAvailableDbcLocale(locale)), m_sessionDbLocaleIndex(objmgr.GetIndexForLocale(locale)), +_logoutTime(0), m_inQueue(false), m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), m_playerSave(false), +m_latency(0), m_TutorialsChanged(false), m_timeOutTime(0) +{ + if (sock) + { + m_Address = sock->GetRemoteAddress (); + sock->AddReference (); + ResetTimeOutTime(); + LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = %u;", GetAccountId()); + } +} + +/// WorldSession destructor +WorldSession::~WorldSession() +{ + ///- unload player if not unloaded + if (_player) + LogoutPlayer (true); + + /// - If have unclosed socket, close it + if (m_Socket) + { + m_Socket->CloseSocket (); + m_Socket->RemoveReference (); + m_Socket = NULL; + } + + ///- empty incoming packet queue + WorldPacket* packet; + while (_recvQueue.next(packet)) + delete packet; + + LoginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = %u;", GetAccountId()); + CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = %u;", GetAccountId()); +} + +void WorldSession::SizeError(WorldPacket const& packet, uint32 size) const +{ + sLog.outError("Client (account %u) send packet %s (%u) with size " SIZEFMTD " but expected %u (attempt crash server?), skipped", + GetAccountId(),LookupOpcodeName(packet.GetOpcode()),packet.GetOpcode(),packet.size(),size); +} + +/// Get the player name +char const* WorldSession::GetPlayerName() const +{ + return GetPlayer() ? GetPlayer()->GetName() : ""; +} + +/// Send a packet to the client +void WorldSession::SendPacket(WorldPacket const* packet) +{ + if (!m_Socket) + return; + + #ifdef TRINITY_DEBUG + + // Code for network use statistic + static uint64 sendPacketCount = 0; + static uint64 sendPacketBytes = 0; + + static time_t firstTime = time(NULL); + static time_t lastTime = firstTime; // next 60 secs start time + + static uint64 sendLastPacketCount = 0; + static uint64 sendLastPacketBytes = 0; + + time_t cur_time = time(NULL); + + if ((cur_time - lastTime) < 60) + { + sendPacketCount+=1; + sendPacketBytes+=packet->size(); + + sendLastPacketCount+=1; + sendLastPacketBytes+=packet->size(); + } + else + { + uint64 minTime = uint64(cur_time - lastTime); + uint64 fullTime = uint64(lastTime - firstTime); + sLog.outDetail("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)); + sLog.outDetail("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; + sendLastPacketBytes = packet->wpos(); // wpos is real written size + } + + #endif // !TRINITY_DEBUG + + if (m_Socket->SendPacket (*packet) == -1) + m_Socket->CloseSocket (); +} + +/// Add an incoming packet to the queue +void WorldSession::QueuePacket(WorldPacket* new_packet) +{ + _recvQueue.add(new_packet); +} + +/// Logging helper for unexpected opcodes +void WorldSession::LogUnexpectedOpcode(WorldPacket* packet, const char *reason) +{ + sLog.outError("SESSION: received unexpected opcode %s (0x%.4X) %s", + LookupOpcodeName(packet->GetOpcode()), + packet->GetOpcode(), + reason); +} + +/// Logging helper for unexpected opcodes +void WorldSession::LogUnprocessedTail(WorldPacket *packet) +{ + sLog.outError("SESSION: opcode %s (0x%.4X) have unprocessed tail data (read stop at %u from %u)", + LookupOpcodeName(packet->GetOpcode()), + packet->GetOpcode(), + packet->rpos(),packet->wpos()); + + packet->print_storage(); +} + +/// Update the WorldSession (triggered by World update) +bool WorldSession::Update(uint32 diff) +{ + /// Update Timeout timer. + UpdateTimeOutTime(diff); + + ///- Before we process anything: + /// If necessary, kick the player from the character select screen + if (IsConnectionIdle()) + m_Socket->CloseSocket(); + + ///- Retrieve packets from the receive queue and call the appropriate handlers + /// not proccess packets if socket already closed + WorldPacket* packet; + while (m_Socket && !m_Socket->IsClosed() && _recvQueue.next(packet)) + { + /*#if 1 + sLog.outError("MOEP: %s (0x%.4X)", + LookupOpcodeName(packet->GetOpcode()), + packet->GetOpcode()); + #endif*/ + + if (packet->GetOpcode() >= NUM_MSG_TYPES) + { + sLog.outError("SESSION: received non-existed opcode %s (0x%.4X)", + LookupOpcodeName(packet->GetOpcode()), + packet->GetOpcode()); + } + else + { + OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()]; + try + { + switch (opHandle.status) + { + case STATUS_LOGGEDIN: + if (!_player) + { + // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets + if (!m_playerRecentlyLogout) + LogUnexpectedOpcode(packet, "the player has not logged in yet"); + } + else if (_player->IsInWorld()) + { + (this->*opHandle.handler)(*packet); + if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) + LogUnprocessedTail(packet); + } + // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer + break; + case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT: + if (!_player && !m_playerRecentlyLogout) + { + LogUnexpectedOpcode(packet, "the player has not logged in yet and not recently logout"); + } + else + { + // not expected _player or must checked in packet hanlder + (this->*opHandle.handler)(*packet); + if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) + LogUnprocessedTail(packet); + } + break; + case STATUS_TRANSFER: + if (!_player) + LogUnexpectedOpcode(packet, "the player has not logged in yet"); + else if (_player->IsInWorld()) + LogUnexpectedOpcode(packet, "the player is still in world"); + else + { + (this->*opHandle.handler)(*packet); + if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) + LogUnprocessedTail(packet); + } + break; + case STATUS_AUTHED: + // prevent cheating with skip queue wait + if (m_inQueue) + { + LogUnexpectedOpcode(packet, "the player not pass queue yet"); + break; + } + + // single from authed time opcodes send in to after logout time + // and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes. + if (packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL) + m_playerRecentlyLogout = false; + + (this->*opHandle.handler)(*packet); + if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) + LogUnprocessedTail(packet); + break; + case STATUS_NEVER: + /* + sLog.outError("SESSION: received not allowed opcode %s (0x%.4X)", + LookupOpcodeName(packet->GetOpcode()), + packet->GetOpcode()); + */ + break; + } + } + catch(ByteBufferException &) + { + sLog.outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", + packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); + if (sLog.IsOutDebug()) + { + sLog.outDebug("Dumping error causing packet:"); + packet->hexlike(); + } + } + } + + delete packet; + } + + time_t currTime = time(NULL); + ///- If necessary, log the player out + if (ShouldLogOut(currTime) && !m_playerLoading) + LogoutPlayer(true); + + ///- Cleanup socket pointer if need + if (m_Socket && m_Socket->IsClosed()) + { + m_Socket->RemoveReference(); + m_Socket = NULL; + } + + if (!m_Socket) + return false; //Will remove this session from the world session map + + return true; +} + +/// %Log the player out +void WorldSession::LogoutPlayer(bool Save) +{ + // finish pending transfers before starting the logout + while (_player && _player->IsBeingTeleportedFar()) + HandleMoveWorldportAckOpcode(); + + m_playerLogout = true; + m_playerSave = Save; + + if (_player) + { + sLFGMgr.Leave(_player); + GetPlayer()->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); + GetPlayer()->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); + GetPlayer()->GetSession()->SendLfgUpdateSearch(false); + + if (uint64 lguid = GetPlayer()->GetLootGUID()) + DoLootRelease(lguid); + + ///- If the player just died before logging out, make him appear as a ghost + //FIXME: logout must be delayed in case lost connection with client in time of combat + if (_player->GetDeathTimer()) + { + _player->getHostileRefManager().deleteReferences(); + _player->BuildPlayerRepop(); + _player->RepopAtGraveyard(); + } + else if (!_player->getAttackers().empty()) + { + _player->CombatStop(); + _player->getHostileRefManager().setOnlineOfflineState(false); + _player->RemoveAllAurasOnDeath(); + + // build set of player who attack _player or who have pet attacking of _player + std::set aset; + for (Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr) + { + Unit* owner = (*itr)->GetOwner(); // including player controlled case + if (owner) + { + if (owner->GetTypeId() == TYPEID_PLAYER) + aset.insert(owner->ToPlayer()); + } + else + if ((*itr)->GetTypeId() == TYPEID_PLAYER) + aset.insert((Player*)(*itr)); + } + + _player->SetPvPDeath(!aset.empty()); + _player->KillPlayer(); + _player->BuildPlayerRepop(); + _player->RepopAtGraveyard(); + + // give honor to all attackers from set like group case + for (std::set::const_iterator itr = aset.begin(); itr != aset.end(); ++itr) + (*itr)->RewardHonor(_player,aset.size()); + + // give bg rewards and update counters like kill by first from attackers + // this can't be called for all attackers. + if (!aset.empty()) + if (BattleGround *bg = _player->GetBattleGround()) + bg->HandleKillPlayer(_player,*aset.begin()); + } + else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) + { + // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION + _player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); + //_player->SetDeathPvP(*); set at SPELL_AURA_SPIRIT_OF_REDEMPTION apply time + _player->KillPlayer(); + _player->BuildPlayerRepop(); + _player->RepopAtGraveyard(); + } + //drop a flag if player is carrying it + if (BattleGround *bg = _player->GetBattleGround()) + bg->EventPlayerLoggedOut(_player); + + ///- Teleport to home if the player is in an invalid instance + if (!_player->m_InstanceValid && !_player->isGameMaster()) + _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation()); + + sOutdoorPvPMgr.HandlePlayerLeaveZone(_player,_player->GetZoneId()); + + for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) + { + if (BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i)) + { + _player->RemoveBattleGroundQueueId(bgQueueTypeId); + sBattleGroundMgr.m_BattleGroundQueues[ bgQueueTypeId ].RemovePlayer(_player->GetGUID(), true); + } + } + + // Repop at GraveYard or other player far teleport will prevent saving player because of not present map + // Teleport player immediately for correct player save + while (_player->IsBeingTeleportedFar()) + HandleMoveWorldportAckOpcode(); + + ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members + Guild *guild = objmgr.GetGuildById(_player->GetGuildId()); + if (guild) + { + guild->SetMemberStats(_player->GetGUID()); + guild->UpdateLogoutTime(_player->GetGUID()); + + guild->BroadcastEvent(GE_SIGNED_OFF, _player->GetGUID(), 1, _player->GetName(), "", ""); + } + + ///- Remove pet + _player->RemovePet(NULL,PET_SAVE_AS_CURRENT, true); + + ///- empty buyback items and save the player in the database + // some save parts only correctly work in case player present in map/player_lists (pets, etc) + if (Save) + { + uint32 eslot; + for (int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; ++j) + { + eslot = j - BUYBACK_SLOT_START; + _player->SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), 0); + _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0); + _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0); + } + _player->SaveToDB(); + } + + ///- Leave all channels before player delete... + _player->CleanupChannels(); + + ///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group. + _player->UninviteFromGroup(); + + // remove player from the group if he is: + // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) + if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket) + _player->RemoveFromGroup(); + + ///- Send update to group and reset stored max enchanting level + if (_player->GetGroup()) + { + _player->GetGroup()->SendUpdate(); + _player->GetGroup()->ResetMaxEnchantingLevel(); + } + + ///- Broadcast a logout message to the player's friends + sSocialMgr.SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true); + sSocialMgr.RemovePlayerSocial (_player->GetGUIDLow ()); + + ///- Remove the player from the world + // the player may not be in the world when logging out + // e.g if he got disconnected during a transfer to another map + // calls to GetMap in this case may cause crashes + _player->CleanupsBeforeDelete(); + sLog.outChar("Account: %d (IP: %s) Logout Character:[%s] (GUID: %u)", GetAccountId(), GetRemoteAddress().c_str(), _player->GetName() ,_player->GetGUIDLow()); + Map* _map = _player->GetMap(); + _map->Remove(_player, true); + SetPlayer(NULL); // deleted in Remove call + + ///- Send the 'logout complete' packet to the client + WorldPacket data(SMSG_LOGOUT_COMPLETE, 0); + SendPacket(&data); + + ///- Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline + //No SQL injection as AccountId is uint32 + CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = '%u'", + GetAccountId()); + sLog.outDebug("SESSION: Sent SMSG_LOGOUT_COMPLETE Message"); + } + + //Hook for OnLogout Event + sScriptMgr.OnLogout(_player); + + m_playerLogout = false; + m_playerSave = false; + m_playerRecentlyLogout = true; + LogoutRequest(0); +} + +/// Kick a player out of the World +void WorldSession::KickPlayer() +{ + if (m_Socket) + m_Socket->CloseSocket (); +} + +void WorldSession::SendNotification(const char *format,...) +{ + if (format) + { + va_list ap; + char szStr [1024]; + szStr[0] = '\0'; + va_start(ap, format); + vsnprintf(szStr, 1024, format, ap); + va_end(ap); + + WorldPacket data(SMSG_NOTIFICATION, (strlen(szStr)+1)); + data << szStr; + SendPacket(&data); + } +} + +void WorldSession::SendNotification(int32 string_id,...) +{ + char const* format = GetTrinityString(string_id); + if (format) + { + va_list ap; + char szStr [1024]; + szStr[0] = '\0'; + va_start(ap, string_id); + vsnprintf(szStr, 1024, format, ap); + va_end(ap); + + WorldPacket data(SMSG_NOTIFICATION, (strlen(szStr)+1)); + data << szStr; + SendPacket(&data); + } +} + +const char * WorldSession::GetTrinityString(int32 entry) const +{ + return objmgr.GetTrinityString(entry,GetSessionDbLocaleIndex()); +} + +void WorldSession::Handle_NULL(WorldPacket& recvPacket) +{ + sLog.outError("SESSION: received unhandled opcode %s (0x%.4X)", + LookupOpcodeName(recvPacket.GetOpcode()), + recvPacket.GetOpcode()); +} + +void WorldSession::Handle_EarlyProccess(WorldPacket& recvPacket) +{ + sLog.outError("SESSION: received opcode %s (0x%.4X) that must be processed in WorldSocket::OnRead", + LookupOpcodeName(recvPacket.GetOpcode()), + recvPacket.GetOpcode()); +} + +void WorldSession::Handle_ServerSide(WorldPacket& recvPacket) +{ + sLog.outError("SESSION: received server-side opcode %s (0x%.4X)", + LookupOpcodeName(recvPacket.GetOpcode()), + recvPacket.GetOpcode()); +} + +void WorldSession::Handle_Deprecated(WorldPacket& recvPacket) +{ + sLog.outError("SESSION: received deprecated opcode %s (0x%.4X)", + LookupOpcodeName(recvPacket.GetOpcode()), + recvPacket.GetOpcode()); +} + +void WorldSession::SendAuthWaitQue(uint32 position) +{ + if (position == 0) + { + WorldPacket packet(SMSG_AUTH_RESPONSE, 1); + packet << uint8(AUTH_OK); + SendPacket(&packet); + } + else + { + WorldPacket packet(SMSG_AUTH_RESPONSE, 6); + packet << uint8(AUTH_WAIT_QUEUE); + packet << uint32(position); + packet << uint8(0); // unk + SendPacket(&packet); + } +} + +void WorldSession::LoadGlobalAccountData() +{ + LoadAccountData( + CharacterDatabase.PQuery("SELECT type, time, data FROM account_data WHERE account='%u'", GetAccountId()), + GLOBAL_CACHE_MASK +); +} + +void WorldSession::LoadAccountData(QueryResult_AutoPtr result, uint32 mask) +{ + for (uint32 i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i) + if (mask & (1 << i)) + m_accountData[i] = AccountData(); + + if (!result) + return; + + do + { + Field *fields = result->Fetch(); + + uint32 type = fields[0].GetUInt32(); + if (type >= NUM_ACCOUNT_DATA_TYPES) + { + sLog.outError("Table `%s` have invalid account data type (%u), ignore.", + mask == GLOBAL_CACHE_MASK ? "account_data" : "character_account_data", type); + continue; + } + + if ((mask & (1 << type)) == 0) + { + sLog.outError("Table `%s` have non appropriate for table account data type (%u), ignore.", + mask == GLOBAL_CACHE_MASK ? "account_data" : "character_account_data", type); + continue; + } + + m_accountData[type].Time = fields[1].GetUInt32(); + m_accountData[type].Data = fields[2].GetCppString(); + + } while (result->NextRow()); +} + +void WorldSession::SetAccountData(AccountDataType type, time_t time_, std::string data) +{ + if ((1 << type) & GLOBAL_CACHE_MASK) + { + uint32 acc = GetAccountId(); + + CharacterDatabase.BeginTransaction (); + CharacterDatabase.PExecute("DELETE FROM account_data WHERE account='%u' AND type='%u'", acc, type); + CharacterDatabase.escape_string(data); + CharacterDatabase.PExecute("INSERT INTO account_data VALUES ('%u','%u','%u','%s')", acc, type, (uint32)time_, data.c_str()); + CharacterDatabase.CommitTransaction (); + } + else + { + // _player can be NULL and packet received after logout but m_GUID still store correct guid + if (!m_GUIDLow) + return; + + CharacterDatabase.BeginTransaction (); + CharacterDatabase.PExecute("DELETE FROM character_account_data WHERE guid='%u' AND type='%u'", m_GUIDLow, type); + CharacterDatabase.escape_string(data); + CharacterDatabase.PExecute("INSERT INTO character_account_data VALUES ('%u','%u','%u','%s')", m_GUIDLow, type, (uint32)time_, data.c_str()); + CharacterDatabase.CommitTransaction (); + } + + m_accountData[type].Time = time_; + m_accountData[type].Data = data; +} + +void WorldSession::SendAccountDataTimes(uint32 mask) +{ + WorldPacket data(SMSG_ACCOUNT_DATA_TIMES, 4+1+4+8*4); // changed in WotLK + data << uint32(time(NULL)); // unix time of something + data << uint8(1); + data << uint32(mask); // type mask + for (uint32 i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i) + if (mask & (1 << i)) + data << uint32(GetAccountData(AccountDataType(i))->Time);// also unix time + SendPacket(&data); +} + +void WorldSession::LoadTutorialsData() +{ + for (int aX = 0 ; aX < 8 ; ++aX) + m_Tutorials[ aX ] = 0; + + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7 FROM character_tutorial WHERE account = '%u'", GetAccountId()); + + if (result) + { + do + { + Field *fields = result->Fetch(); + + for (int iI = 0; iI < 8; ++iI) + m_Tutorials[iI] = fields[iI].GetUInt32(); + } + while (result->NextRow()); + } + m_TutorialsChanged = false; +} + +void WorldSession::SendTutorialsData() +{ + WorldPacket data(SMSG_TUTORIAL_FLAGS, 4*8); + for (uint32 i = 0; i < 8; ++i) + data << m_Tutorials[i]; + SendPacket(&data); +} + +void WorldSession::SaveTutorialsData() +{ + if (!m_TutorialsChanged) + return; + + uint32 Rows=0; + // it's better than rebuilding indexes multiple times + QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT count(*) AS r FROM character_tutorial WHERE account = '%u'", GetAccountId()); + if (result) + Rows = result->Fetch()[0].GetUInt32(); + + if (Rows) + { + CharacterDatabase.PExecute("UPDATE character_tutorial SET tut0='%u', tut1='%u', tut2='%u', tut3='%u', tut4='%u', tut5='%u', tut6='%u', tut7='%u' WHERE account = '%u'", + m_Tutorials[0], m_Tutorials[1], m_Tutorials[2], m_Tutorials[3], m_Tutorials[4], m_Tutorials[5], m_Tutorials[6], m_Tutorials[7], GetAccountId()); + } + else + { + CharacterDatabase.PExecute("INSERT INTO character_tutorial (account,tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7) VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", GetAccountId(), m_Tutorials[0], m_Tutorials[1], m_Tutorials[2], m_Tutorials[3], m_Tutorials[4], m_Tutorials[5], m_Tutorials[6], m_Tutorials[7]); + } + + m_TutorialsChanged = false; +} + +void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo *mi) +{ + data >> mi->flags; + data >> mi->unk1; + data >> mi->time; + data >> mi->x; + data >> mi->y; + data >> mi->z; + data >> mi->o; + + if (mi->flags & MOVEMENTFLAG_ONTRANSPORT) + { + if (!data.readPackGUID(mi->t_guid)) + return; + + data >> mi->t_x; + data >> mi->t_y; + data >> mi->t_z; + data >> mi->t_o; + data >> mi->t_time; + data >> mi->t_seat; + } + + if ((mi->flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || (mi->unk1 & 0x20)) + { + data >> mi->s_pitch; + } + + data >> mi->fallTime; + + if (mi->flags & MOVEMENTFLAG_JUMPING) + { + data >> mi->j_zspeed; + data >> mi->j_sinAngle; + data >> mi->j_cosAngle; + data >> mi->j_xyspeed; + } + + if (mi->flags & MOVEMENTFLAG_SPLINE) + { + data >> mi->u_unk1; + } +} + +void WorldSession::WriteMovementInfo(WorldPacket *data, MovementInfo *mi) +{ + data->appendPackGUID(mi->guid); + + *data << mi->flags; + *data << mi->unk1; + *data << mi->time; + *data << mi->x; + *data << mi->y; + *data << mi->z; + *data << mi->o; + + if (mi->HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT)) + { + data->appendPackGUID(mi->t_guid); + + *data << mi->t_x; + *data << mi->t_y; + *data << mi->t_z; + *data << mi->t_o; + *data << mi->t_time; + *data << mi->t_seat; + } + + if ((mi->HasMovementFlag(MovementFlags(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING))) || (mi->unk1 & 0x20)) + { + *data << mi->s_pitch; + } + + *data << mi->fallTime; + + if (mi->HasMovementFlag(MOVEMENTFLAG_JUMPING)) + { + *data << mi->j_zspeed; + *data << mi->j_sinAngle; + *data << mi->j_cosAngle; + *data << mi->j_xyspeed; + } + + if (mi->HasMovementFlag(MOVEMENTFLAG_SPLINE)) + { + *data << mi->u_unk1; + } +} + +void WorldSession::ReadAddonsInfo(WorldPacket &data) +{ + if (data.rpos() + 4 > data.size()) + return; + uint32 size; + data >> size; + + if (!size) + return; + + if (size > 0xFFFFF) + { + sLog.outError("WorldSession::ReadAddonsInfo addon info too big, size %u", size); + return; + } + + uLongf uSize = size; + + uint32 pos = data.rpos(); + + ByteBuffer addonInfo; + addonInfo.resize(size); + + if (uncompress(const_cast(addonInfo.contents()), &uSize, const_cast(data.contents() + pos), data.size() - pos) == Z_OK) + { + uint32 addonsCount; + addonInfo >> addonsCount; // addons count + + for (uint32 i = 0; i < addonsCount; ++i) + { + std::string addonName; + uint8 enabled; + uint32 crc, unk1; + + // check next addon data format correctness + if (addonInfo.rpos()+1 > addonInfo.size()) + return; + + addonInfo >> addonName; + + addonInfo >> enabled >> crc >> unk1; + + sLog.outDetail("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); + + SavedAddon const* savedAddon = sAddonMgr.GetAddonInfo(addonName); + if (savedAddon) + { + bool match = true; + + if (addon.CRC != savedAddon->CRC) + match = false; + + if (!match) + sLog.outDetail("ADDON: %s was known, but didn't match known CRC (0x%x)!", addon.Name.c_str(), savedAddon->CRC); + else + sLog.outDetail("ADDON: %s was known, CRC is correct (0x%x)", addon.Name.c_str(), savedAddon->CRC); + } + else + { + sAddonMgr.SaveAddon(addon); + + sLog.outDetail("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. + m_addonsList.push_back(addon); + } + + uint32 currentTime; + addonInfo >> currentTime; + sLog.outDebug("ADDON: CurrentTime: %u", currentTime); + + if (addonInfo.rpos() != addonInfo.size()) + sLog.outDebug("packet under-read!"); + } + else + sLog.outError("Addon packet uncompress error!"); +} + +void WorldSession::SendAddonsInfo() +{ + uint8 addonPublicKey[256] = + { + 0xC3, 0x5B, 0x50, 0x84, 0xB9, 0x3E, 0x32, 0x42, 0x8C, 0xD0, 0xC7, 0x48, 0xFA, 0x0E, 0x5D, 0x54, + 0x5A, 0xA3, 0x0E, 0x14, 0xBA, 0x9E, 0x0D, 0xB9, 0x5D, 0x8B, 0xEE, 0xB6, 0x84, 0x93, 0x45, 0x75, + 0xFF, 0x31, 0xFE, 0x2F, 0x64, 0x3F, 0x3D, 0x6D, 0x07, 0xD9, 0x44, 0x9B, 0x40, 0x85, 0x59, 0x34, + 0x4E, 0x10, 0xE1, 0xE7, 0x43, 0x69, 0xEF, 0x7C, 0x16, 0xFC, 0xB4, 0xED, 0x1B, 0x95, 0x28, 0xA8, + 0x23, 0x76, 0x51, 0x31, 0x57, 0x30, 0x2B, 0x79, 0x08, 0x50, 0x10, 0x1C, 0x4A, 0x1A, 0x2C, 0xC8, + 0x8B, 0x8F, 0x05, 0x2D, 0x22, 0x3D, 0xDB, 0x5A, 0x24, 0x7A, 0x0F, 0x13, 0x50, 0x37, 0x8F, 0x5A, + 0xCC, 0x9E, 0x04, 0x44, 0x0E, 0x87, 0x01, 0xD4, 0xA3, 0x15, 0x94, 0x16, 0x34, 0xC6, 0xC2, 0xC3, + 0xFB, 0x49, 0xFE, 0xE1, 0xF9, 0xDA, 0x8C, 0x50, 0x3C, 0xBE, 0x2C, 0xBB, 0x57, 0xED, 0x46, 0xB9, + 0xAD, 0x8B, 0xC6, 0xDF, 0x0E, 0xD6, 0x0F, 0xBE, 0x80, 0xB3, 0x8B, 0x1E, 0x77, 0xCF, 0xAD, 0x22, + 0xCF, 0xB7, 0x4B, 0xCF, 0xFB, 0xF0, 0x6B, 0x11, 0x45, 0x2D, 0x7A, 0x81, 0x18, 0xF2, 0x92, 0x7E, + 0x98, 0x56, 0x5D, 0x5E, 0x69, 0x72, 0x0A, 0x0D, 0x03, 0x0A, 0x85, 0xA2, 0x85, 0x9C, 0xCB, 0xFB, + 0x56, 0x6E, 0x8F, 0x44, 0xBB, 0x8F, 0x02, 0x22, 0x68, 0x63, 0x97, 0xBC, 0x85, 0xBA, 0xA8, 0xF7, + 0xB5, 0x40, 0x68, 0x3C, 0x77, 0x86, 0x6F, 0x4B, 0xD7, 0x88, 0xCA, 0x8A, 0xD7, 0xCE, 0x36, 0xF0, + 0x45, 0x6E, 0xD5, 0x64, 0x79, 0x0F, 0x17, 0xFC, 0x64, 0xDD, 0x10, 0x6F, 0xF3, 0xF5, 0xE0, 0xA6, + 0xC3, 0xFB, 0x1B, 0x8C, 0x29, 0xEF, 0x8E, 0xE5, 0x34, 0xCB, 0xD1, 0x2A, 0xCE, 0x79, 0xC3, 0x9A, + 0x0D, 0x36, 0xEA, 0x01, 0xE0, 0xAA, 0x91, 0x20, 0x54, 0xF0, 0x72, 0xD8, 0x1E, 0xC7, 0x89, 0xD2 + }; + + WorldPacket data(SMSG_ADDON_INFO, 4); + + for (AddonsList::iterator itr = m_addonsList.begin(); itr != m_addonsList.end(); ++itr) + { + data << uint8(itr->State); + + uint8 crcpub = itr->UsePublicKeyOrCRC; + data << uint8(crcpub); + if (crcpub) + { + uint8 usepk = (itr->CRC != STANDARD_ADDON_CRC); // If addon is Standard addon CRC + data << uint8(usepk); + if (usepk) // if CRC is wrong, add public key (client need it) + { + sLog.outDetail("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)); + } + + data << uint32(/*itr->CRC*/ 0); // TODO: Find out the meaning of this. + } + + uint8 unk3 = 0; // 0 is sent here + data << uint8(unk3); + if (unk3) + { + // String, length 256 (null terminated) + data << uint8(0); + } + } + + m_addonsList.clear(); + + uint32 count = 0; + data << uint32(count); + /*for (uint32 i = 0; i < count; ++i) + { + uint32 + string (16 bytes) + string (16 bytes) + uint32 + uint32 + }*/ + + SendPacket(&data); +} + +void WorldSession::SetPlayer(Player *plr) +{ + _player = plr; + + // set m_GUID that can be used while player loggined and later until m_playerRecentlyLogout not reset + if (_player) + m_GUIDLow = _player->GetGUIDLow(); +} diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h new file mode 100644 index 00000000000..c17f3e3f3e6 --- /dev/null +++ b/src/server/game/Server/WorldSession.h @@ -0,0 +1,829 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/// \addtogroup u2w +/// @{ +/// \file + +#ifndef __WORLDSESSION_H +#define __WORLDSESSION_H + +#include "Common.h" +#include "SharedDefines.h" +#include "AddonMgr.h" +#include "QueryResult.h" +#include "World.h" + +struct ItemPrototype; +struct AuctionEntry; +struct DeclinedName; +struct MovementInfo; + +class Creature; +class Item; +class Object; +class Player; +class Unit; +class GameObject; +class WorldPacket; +class WorldSocket; +class QueryResult; +class LoginQueryHolder; +class CharacterHandler; +struct AreaTableEntry; + +enum AccountDataType +{ + GLOBAL_CONFIG_CACHE = 0, // 0x01 g + PER_CHARACTER_CONFIG_CACHE = 1, // 0x02 p + GLOBAL_BINDINGS_CACHE = 2, // 0x04 g + PER_CHARACTER_BINDINGS_CACHE = 3, // 0x08 p + GLOBAL_MACROS_CACHE = 4, // 0x10 g + PER_CHARACTER_MACROS_CACHE = 5, // 0x20 p + PER_CHARACTER_LAYOUT_CACHE = 6, // 0x40 p + PER_CHARACTER_CHAT_CACHE = 7, // 0x80 p +}; + +#define NUM_ACCOUNT_DATA_TYPES 8 + +#define GLOBAL_CACHE_MASK 0x15 +#define PER_CHARACTER_CACHE_MASK 0xEA + +struct AccountData +{ + AccountData() : Time(0), Data("") {} + + time_t Time; + std::string Data; +}; + +enum PartyOperation +{ + PARTY_OP_INVITE = 0, + PARTY_OP_UNINVITE = 1, + PARTY_OP_LEAVE = 2, + PARTY_OP_SWAP = 4 +}; + +enum PartyResult +{ + ERR_PARTY_RESULT_OK = 0, + ERR_BAD_PLAYER_NAME_S = 1, + ERR_TARGET_NOT_IN_GROUP_S = 2, + ERR_TARGET_NOT_IN_INSTANCE_S = 3, + ERR_GROUP_FULL = 4, + ERR_ALREADY_IN_GROUP_S = 5, + ERR_NOT_IN_GROUP = 6, + ERR_NOT_LEADER = 7, + ERR_PLAYER_WRONG_FACTION = 8, + ERR_IGNORING_YOU_S = 9, + ERR_LFG_PENDING = 12, + ERR_INVITE_RESTRICTED = 13, + ERR_GROUP_SWAP_FAILED = 14, // if (PartyOperation == PARTY_OP_SWAP) ERR_GROUP_SWAP_FAILED else ERR_INVITE_IN_COMBAT + ERR_INVITE_UNKNOWN_REALM = 15, + ERR_INVITE_NO_PARTY_SERVER = 16, + ERR_INVITE_PARTY_BUSY = 17, + ERR_PARTY_TARGET_AMBIGUOUS = 18, + ERR_PARTY_LFG_INVITE_RAID_LOCKED = 19, + ERR_PARTY_LFG_BOOT_LIMIT = 20, + ERR_PARTY_LFG_BOOT_COOLDOWN_S = 21, + ERR_PARTY_LFG_BOOT_IN_PROGRESS = 22, + ERR_PARTY_LFG_BOOT_TOO_FEW_PLAYERS = 23, + ERR_PARTY_LFG_BOOT_NOT_ELIGIBLE_S = 24, + ERR_RAID_DISALLOWED_BY_LEVEL = 25, + ERR_PARTY_LFG_BOOT_IN_COMBAT = 26, + ERR_VOTE_KICK_REASON_NEEDED = 27, + ERR_PARTY_LFG_BOOT_DUNGEON_COMPLETE = 28, + ERR_PARTY_LFG_BOOT_LOOT_ROLLS = 29, + ERR_PARTY_LFG_TELEPORT_IN_COMBAT = 30 +}; + +enum ChatRestrictionType +{ + ERR_CHAT_RESTRICTED = 0, + ERR_CHAT_THROTTLED = 1, + ERR_USER_SQUELCHED = 2, + ERR_YELL_RESTRICTED = 3 +}; + +/// Player session in the World +class WorldSession +{ + friend class CharacterHandler; + public: + WorldSession(uint32 id, WorldSocket *sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale); + ~WorldSession(); + + bool PlayerLoading() const { return m_playerLoading; } + bool PlayerLogout() const { return m_playerLogout; } + bool PlayerLogoutWithSave() const { return m_playerLogout && m_playerSave; } + + void SizeError(WorldPacket const& packet, uint32 size) const; + + void ReadAddonsInfo(WorldPacket &data); + void SendAddonsInfo(); + + void ReadMovementInfo(WorldPacket &data, MovementInfo *mi); + void WriteMovementInfo(WorldPacket *data, MovementInfo *mi); + + void SendPacket(WorldPacket const* packet); + void SendNotification(const char *format,...) ATTR_PRINTF(2,3); + void SendNotification(int32 string_id,...); + void SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName *declinedName); + void SendPartyResult(PartyOperation operation, const std::string& member, PartyResult res); + void SendAreaTriggerMessage(const char* Text, ...) ATTR_PRINTF(2,3); + void SendSetPhaseShift(uint32 phaseShift); + void SendQueryTimeResponse(); + + AccountTypes GetSecurity() const { return _security; } + uint32 GetAccountId() const { return _accountId; } + Player* GetPlayer() const { return _player; } + char const* GetPlayerName() const; + void SetSecurity(AccountTypes security) { _security = security; } + std::string const& GetRemoteAddress() { return m_Address; } + void SetPlayer(Player *plr); + uint8 Expansion() const { return m_expansion; } + + /// Session in auth.queue currently + void SetInQueue(bool state) { m_inQueue = state; } + + /// Is the user engaged in a log out process? + bool isLogingOut() const { return _logoutTime || m_playerLogout; } + + /// Engage the logout process for the user + void LogoutRequest(time_t requestTime) + { + _logoutTime = requestTime; + } + + /// Is logout cooldown expired? + bool ShouldLogOut(time_t currTime) const + { + return (_logoutTime > 0 && currTime >= _logoutTime + 20); + } + + void LogoutPlayer(bool Save); + void KickPlayer(); + + void QueuePacket(WorldPacket* new_packet); + bool Update(uint32 diff); + + /// Handle the authentication waiting queue (to be completed) + void SendAuthWaitQue(uint32 position); + + //void SendTestCreatureQueryOpcode(uint32 entry, uint64 guid, uint32 testvalue); + void SendNameQueryOpcode(Player* p); + void SendNameQueryOpcodeFromDB(uint64 guid); + static void SendNameQueryOpcodeFromDBCallBack(QueryResult_AutoPtr result, uint32 accountId); + + void SendTrainerList(uint64 guid); + void SendTrainerList(uint64 guid, const std::string& strTitle); + void SendListInventory(uint64 guid); + void SendShowBank(uint64 guid); + void SendTabardVendorActivate(uint64 guid); + void SendSpiritResurrect(); + void SendBindPoint(Creature* npc); + + void SendAttackStop(Unit const* enemy); + + void SendBattlegGroundList(uint64 guid, BattleGroundTypeId bgTypeId); + + void SendTradeStatus(uint32 status); + void SendCancelTrade(); + + void SendStablePet(uint64 guid); + void SendPetitionQueryOpcode(uint64 petitionguid); + void SendUpdateTrade(); + + //pet + void SendPetNameQuery(uint64 guid, uint32 petnumber); + + // Account Data + AccountData *GetAccountData(AccountDataType type) { return &m_accountData[type]; } + void SetAccountData(AccountDataType type, time_t time_, std::string data); + void SendAccountDataTimes(uint32 mask); + void LoadGlobalAccountData(); + void LoadAccountData(QueryResult_AutoPtr result, uint32 mask); + void LoadTutorialsData(); + void SendTutorialsData(); + void SaveTutorialsData(); + uint32 GetTutorialInt(uint32 intId) + { + return m_Tutorials[intId]; + } + + void SetTutorialInt(uint32 intId, uint32 value) + { + if (m_Tutorials[intId] != value) + { + m_Tutorials[intId] = value; + m_TutorialsChanged = true; + } + } + //used with item_page table + bool SendItemInfo(uint32 itemid, WorldPacket data); + //auction + void SendAuctionHello(uint64 guid, Creature * unit); + void SendAuctionCommandResult(uint32 auctionId, uint32 Action, uint32 ErrorCode, uint32 bidError = 0); + void SendAuctionBidderNotification(uint32 location, uint32 auctionId, uint64 bidder, uint32 bidSum, uint32 diff, uint32 item_template); + void SendAuctionOwnerNotification(AuctionEntry * auction); + void SendAuctionOutbiddedMail(AuctionEntry * auction, uint32 newPrice); + void SendAuctionCancelledToBidderMail(AuctionEntry* auction); + + //Item Enchantment + void SendEnchantmentLog(uint64 Target, uint64 Caster,uint32 ItemID,uint32 SpellID); + void SendItemEnchantTimeUpdate(uint64 Playerguid, uint64 Itemguid,uint32 slot,uint32 Duration); + + //Taxi + void SendTaxiStatus(uint64 guid); + void SendTaxiMenu(Creature* unit); + void SendDoFlight(uint32 mountDisplayId, uint32 path, uint32 pathNode = 0); + bool SendLearnNewTaxiNode(Creature* unit); + + // Guild/Arena Team + void SendGuildCommandResult(uint32 typecmd, const std::string& str, uint32 cmdresult); + void SendArenaTeamCommandResult(uint32 team_action, const std::string& team, const std::string& player, uint32 error_id); + void SendNotInArenaTeamPacket(uint8 type); + void SendPetitionShowList(uint64 guid); + void SendSaveGuildEmblem(uint32 msg); + // Looking For Group + // TRUE values set by client sending CMSG_LFG_SET_AUTOJOIN and CMSG_LFM_CLEAR_AUTOFILL before player login + bool LookingForGroup_auto_join; + bool LookingForGroup_auto_add; + + void BuildPartyMemberStatsChangedPacket(Player *player, WorldPacket *data); + + void DoLootRelease(uint64 lguid); + + // Account mute time + time_t m_muteTime; + + // Locales + LocaleConstant GetSessionDbcLocale() const { return m_sessionDbcLocale; } + int GetSessionDbLocaleIndex() const { return m_sessionDbLocaleIndex; } + const char *GetTrinityString(int32 entry) const; + + uint32 GetLatency() const { return m_latency; } + void SetLatency(uint32 latency) { m_latency = latency; } + uint32 getDialogStatus(Player *pPlayer, Object* questgiver, uint32 defstatus); + + time_t m_timeOutTime; + void UpdateTimeOutTime(uint32 diff) + { + if (diff > m_timeOutTime) + m_timeOutTime = 0; + else + m_timeOutTime -= diff; + } + void ResetTimeOutTime() + { + m_timeOutTime = sWorld.getConfig(CONFIG_SOCKET_TIMEOUTTIME); + } + bool IsConnectionIdle() const + { + if (m_timeOutTime <= 0 && !m_inQueue) + return true; + return false; + } + + + public: // opcodes handlers + + void Handle_NULL(WorldPacket& recvPacket); // not used + void Handle_EarlyProccess(WorldPacket& recvPacket);// just mark packets processed in WorldSocket::OnRead + void Handle_ServerSide(WorldPacket& recvPacket); // sever side only, can't be accepted from client + void Handle_Deprecated(WorldPacket& recvPacket); // never used anymore by client + + void HandleCharEnumOpcode(WorldPacket& recvPacket); + void HandleCharDeleteOpcode(WorldPacket& recvPacket); + void HandleCharCreateOpcode(WorldPacket& recvPacket); + void HandlePlayerLoginOpcode(WorldPacket& recvPacket); + void HandleCharEnum(QueryResult_AutoPtr result); + void HandlePlayerLogin(LoginQueryHolder * holder); + + // played time + void HandlePlayedTime(WorldPacket& recvPacket); + + // new + void HandleMoveUnRootAck(WorldPacket& recvPacket); + void HandleMoveRootAck(WorldPacket& recvPacket); + void HandleLookingForGroup(WorldPacket& recvPacket); + + // new inspect + void HandleInspectOpcode(WorldPacket& recvPacket); + + // new party stats + void HandleInspectHonorStatsOpcode(WorldPacket& recvPacket); + + void HandleMoveWaterWalkAck(WorldPacket& recvPacket); + void HandleFeatherFallAck(WorldPacket &recv_data); + + void HandleMoveHoverAck(WorldPacket & recv_data); + + void HandleMountSpecialAnimOpcode(WorldPacket &recvdata); + + // character view + void HandleShowingHelmOpcode(WorldPacket& recv_data); + void HandleShowingCloakOpcode(WorldPacket& recv_data); + + // repair + void HandleRepairItemOpcode(WorldPacket& recvPacket); + + // Knockback + void HandleMoveKnockBackAck(WorldPacket& recvPacket); + + void HandleMoveTeleportAck(WorldPacket& recvPacket); + void HandleForceSpeedChangeAck(WorldPacket & recv_data); + + void HandlePingOpcode(WorldPacket& recvPacket); + void HandleAuthSessionOpcode(WorldPacket& recvPacket); + void HandleRepopRequestOpcode(WorldPacket& recvPacket); + void HandleAutostoreLootItemOpcode(WorldPacket& recvPacket); + void HandleLootMoneyOpcode(WorldPacket& recvPacket); + void HandleLootOpcode(WorldPacket& recvPacket); + void HandleLootReleaseOpcode(WorldPacket& recvPacket); + void HandleLootMasterGiveOpcode(WorldPacket& recvPacket); + void HandleWhoOpcode(WorldPacket& recvPacket); + void HandleLogoutRequestOpcode(WorldPacket& recvPacket); + void HandlePlayerLogoutOpcode(WorldPacket& recvPacket); + void HandleLogoutCancelOpcode(WorldPacket& recvPacket); + + // GM Ticket opcodes + void HandleGMTicketCreateOpcode(WorldPacket& recvPacket); + void HandleGMTicketUpdateOpcode(WorldPacket& recvPacket); + void HandleGMTicketDeleteOpcode(WorldPacket& recvPacket); + void HandleGMTicketGetTicketOpcode(WorldPacket& recvPacket); + void HandleGMTicketSystemStatusOpcode(WorldPacket& recvPacket); + void SendGMTicketGetTicket(uint32 status, char const* text); + + //void HandleGMSurveySubmit(WorldPacket& recvPacket); + + void HandleTogglePvP(WorldPacket& recvPacket); + + void HandleZoneUpdateOpcode(WorldPacket& recvPacket); + void HandleSetTargetOpcode(WorldPacket& recvPacket); + void HandleSetSelectionOpcode(WorldPacket& recvPacket); + void HandleStandStateChangeOpcode(WorldPacket& recvPacket); + void HandleEmoteOpcode(WorldPacket& recvPacket); + void HandleContactListOpcode(WorldPacket& recvPacket); + void HandleAddFriendOpcode(WorldPacket& recvPacket); + static void HandleAddFriendOpcodeCallBack(QueryResult_AutoPtr result, uint32 accountId, std::string friendNote); + void HandleDelFriendOpcode(WorldPacket& recvPacket); + void HandleAddIgnoreOpcode(WorldPacket& recvPacket); + static void HandleAddIgnoreOpcodeCallBack(QueryResult_AutoPtr result, uint32 accountId); + void HandleDelIgnoreOpcode(WorldPacket& recvPacket); + void HandleSetContactNotesOpcode(WorldPacket& recvPacket); + void HandleBugOpcode(WorldPacket& recvPacket); + void HandleSetAmmoOpcode(WorldPacket& recvPacket); + void HandleItemNameQueryOpcode(WorldPacket& recvPacket); + + void HandleAreaTriggerOpcode(WorldPacket& recvPacket); + + void HandleSetFactionAtWar(WorldPacket & recv_data); + void HandleSetFactionCheat(WorldPacket & recv_data); + void HandleSetWatchedFactionOpcode(WorldPacket & recv_data); + void HandleSetFactionInactiveOpcode(WorldPacket & recv_data); + + void HandleUpdateAccountData(WorldPacket& recvPacket); + void HandleRequestAccountData(WorldPacket& recvPacket); + void HandleSetActionButtonOpcode(WorldPacket& recvPacket); + + void HandleGameObjectUseOpcode(WorldPacket& recPacket); + void HandleMeetingStoneInfo(WorldPacket& recPacket); + void HandleGameobjectReportUse(WorldPacket& recvPacket); + + void HandleNameQueryOpcode(WorldPacket& recvPacket); + + void HandleQueryTimeOpcode(WorldPacket& recvPacket); + + void HandleCreatureQueryOpcode(WorldPacket& recvPacket); + + void HandleGameObjectQueryOpcode(WorldPacket& recvPacket); + + void HandleMoveWorldportAckOpcode(WorldPacket& recvPacket); + void HandleMoveWorldportAckOpcode(); // for server-side calls + + void HandleMovementOpcodes(WorldPacket& recvPacket); + void HandleSetActiveMoverOpcode(WorldPacket &recv_data); + void HandleMoveNotActiveMover(WorldPacket &recv_data); + void HandleDismissControlledVehicle(WorldPacket &recv_data); + void HandleRequestVehicleExit(WorldPacket &recv_data); + void HandleChangeSeatsOnControlledVehicle(WorldPacket &recv_data); + void HandleMoveTimeSkippedOpcode(WorldPacket &recv_data); + + void HandleRequestRaidInfoOpcode(WorldPacket & recv_data); + + void HandleBattlefieldStatusOpcode(WorldPacket &recv_data); + void HandleBattleMasterHelloOpcode(WorldPacket &recv_data); + + void HandleGroupInviteOpcode(WorldPacket& recvPacket); + //void HandleGroupCancelOpcode(WorldPacket& recvPacket); + void HandleGroupAcceptOpcode(WorldPacket& recvPacket); + void HandleGroupDeclineOpcode(WorldPacket& recvPacket); + void HandleGroupUninviteOpcode(WorldPacket& recvPacket); + void HandleGroupUninviteGuidOpcode(WorldPacket& recvPacket); + void HandleGroupSetLeaderOpcode(WorldPacket& recvPacket); + void HandleGroupDisbandOpcode(WorldPacket& recvPacket); + void HandleOptOutOfLootOpcode(WorldPacket &recv_data); + void HandleLootMethodOpcode(WorldPacket& recvPacket); + void HandleLootRoll(WorldPacket &recv_data); + void HandleRequestPartyMemberStatsOpcode(WorldPacket &recv_data); + void HandleRaidTargetUpdateOpcode(WorldPacket & recv_data); + void HandleRaidReadyCheckOpcode(WorldPacket & recv_data); + void HandleRaidReadyCheckFinishedOpcode(WorldPacket & recv_data); + void HandleGroupRaidConvertOpcode(WorldPacket & recv_data); + void HandleGroupChangeSubGroupOpcode(WorldPacket & recv_data); + void HandleGroupAssistantLeaderOpcode(WorldPacket & recv_data); + void HandlePartyAssignmentOpcode(WorldPacket & recv_data); + + void HandlePetitionBuyOpcode(WorldPacket& recv_data); + void HandlePetitionShowSignOpcode(WorldPacket& recv_data); + void HandlePetitionQueryOpcode(WorldPacket& recv_data); + void HandlePetitionRenameOpcode(WorldPacket& recv_data); + void HandlePetitionSignOpcode(WorldPacket& recv_data); + void HandlePetitionDeclineOpcode(WorldPacket& recv_data); + void HandleOfferPetitionOpcode(WorldPacket& recv_data); + void HandleTurnInPetitionOpcode(WorldPacket& recv_data); + + void HandleGuildQueryOpcode(WorldPacket& recvPacket); + void HandleGuildCreateOpcode(WorldPacket& recvPacket); + void HandleGuildInviteOpcode(WorldPacket& recvPacket); + void HandleGuildRemoveOpcode(WorldPacket& recvPacket); + void HandleGuildAcceptOpcode(WorldPacket& recvPacket); + void HandleGuildDeclineOpcode(WorldPacket& recvPacket); + void HandleGuildInfoOpcode(WorldPacket& recvPacket); + void HandleGuildEventLogQueryOpcode(WorldPacket& recvPacket); + void HandleGuildRosterOpcode(WorldPacket& recvPacket); + void HandleGuildPromoteOpcode(WorldPacket& recvPacket); + void HandleGuildDemoteOpcode(WorldPacket& recvPacket); + void HandleGuildLeaveOpcode(WorldPacket& recvPacket); + void HandleGuildDisbandOpcode(WorldPacket& recvPacket); + void HandleGuildLeaderOpcode(WorldPacket& recvPacket); + void HandleGuildMOTDOpcode(WorldPacket& recvPacket); + void HandleGuildSetPublicNoteOpcode(WorldPacket& recvPacket); + void HandleGuildSetOfficerNoteOpcode(WorldPacket& recvPacket); + void HandleGuildRankOpcode(WorldPacket& recvPacket); + void HandleGuildAddRankOpcode(WorldPacket& recvPacket); + void HandleGuildDelRankOpcode(WorldPacket& recvPacket); + void HandleGuildChangeInfoTextOpcode(WorldPacket& recvPacket); + void HandleSaveGuildEmblemOpcode(WorldPacket& recvPacket); + + void HandleTaxiNodeStatusQueryOpcode(WorldPacket& recvPacket); + void HandleTaxiQueryAvailableNodes(WorldPacket& recvPacket); + void HandleActivateTaxiOpcode(WorldPacket& recvPacket); + void HandleActivateTaxiExpressOpcode(WorldPacket& recvPacket); + void HandleMoveSplineDoneOpcode(WorldPacket& recvPacket); + + void HandleTabardVendorActivateOpcode(WorldPacket& recvPacket); + void HandleBankerActivateOpcode(WorldPacket& recvPacket); + void HandleBuyBankSlotOpcode(WorldPacket& recvPacket); + void HandleTrainerListOpcode(WorldPacket& recvPacket); + void HandleTrainerBuySpellOpcode(WorldPacket& recvPacket); + void HandlePetitionShowListOpcode(WorldPacket& recvPacket); + void HandleGossipHelloOpcode(WorldPacket& recvPacket); + void HandleGossipSelectOptionOpcode(WorldPacket& recvPacket); + void HandleSpiritHealerActivateOpcode(WorldPacket& recvPacket); + void HandleNpcTextQueryOpcode(WorldPacket& recvPacket); + void HandleBinderActivateOpcode(WorldPacket& recvPacket); + void HandleListStabledPetsOpcode(WorldPacket& recvPacket); + void HandleStablePet(WorldPacket& recvPacket); + void HandleUnstablePet(WorldPacket& recvPacket); + void HandleBuyStableSlot(WorldPacket& recvPacket); + void HandleStableRevivePet(WorldPacket& recvPacket); + void HandleStableSwapPet(WorldPacket& recvPacket); + + void HandleDuelAcceptedOpcode(WorldPacket& recvPacket); + void HandleDuelCancelledOpcode(WorldPacket& recvPacket); + + void HandleAcceptTradeOpcode(WorldPacket& recvPacket); + void HandleBeginTradeOpcode(WorldPacket& recvPacket); + void HandleBusyTradeOpcode(WorldPacket& recvPacket); + void HandleCancelTradeOpcode(WorldPacket& recvPacket); + void HandleClearTradeItemOpcode(WorldPacket& recvPacket); + void HandleIgnoreTradeOpcode(WorldPacket& recvPacket); + void HandleInitiateTradeOpcode(WorldPacket& recvPacket); + void HandleSetTradeGoldOpcode(WorldPacket& recvPacket); + void HandleSetTradeItemOpcode(WorldPacket& recvPacket); + void HandleUnacceptTradeOpcode(WorldPacket& recvPacket); + + void HandleAuctionHelloOpcode(WorldPacket& recvPacket); + void HandleAuctionListItems(WorldPacket & recv_data); + void HandleAuctionListBidderItems(WorldPacket & recv_data); + void HandleAuctionSellItem(WorldPacket & recv_data); + void HandleAuctionRemoveItem(WorldPacket & recv_data); + void HandleAuctionListOwnerItems(WorldPacket & recv_data); + void HandleAuctionPlaceBid(WorldPacket & recv_data); + void HandleAuctionListPendingSales(WorldPacket & recv_data); + + void HandleGetMailList(WorldPacket & recv_data); + void HandleSendMail(WorldPacket & recv_data); + void HandleMailTakeMoney(WorldPacket & recv_data); + void HandleMailTakeItem(WorldPacket & recv_data); + void HandleMailMarkAsRead(WorldPacket & recv_data); + void HandleMailReturnToSender(WorldPacket & recv_data); + void HandleMailDelete(WorldPacket & recv_data); + void HandleItemTextQuery(WorldPacket & recv_data); + void HandleMailCreateTextItem(WorldPacket & recv_data); + void HandleQueryNextMailTime(WorldPacket & recv_data); + void HandleCancelChanneling(WorldPacket & recv_data); + + void SendItemPageInfo(ItemPrototype *itemProto); + void HandleSplitItemOpcode(WorldPacket& recvPacket); + void HandleSwapInvItemOpcode(WorldPacket& recvPacket); + void HandleDestroyItemOpcode(WorldPacket& recvPacket); + void HandleAutoEquipItemOpcode(WorldPacket& recvPacket); + void HandleItemQuerySingleOpcode(WorldPacket& recvPacket); + void HandleSellItemOpcode(WorldPacket& recvPacket); + void HandleBuyItemInSlotOpcode(WorldPacket& recvPacket); + void HandleBuyItemOpcode(WorldPacket& recvPacket); + void HandleListInventoryOpcode(WorldPacket& recvPacket); + void HandleAutoStoreBagItemOpcode(WorldPacket& recvPacket); + void HandleReadItem(WorldPacket& recvPacket); + void HandleAutoEquipItemSlotOpcode(WorldPacket & recvPacket); + void HandleSwapItem(WorldPacket & recvPacket); + void HandleBuybackItem(WorldPacket & recvPacket); + void HandleAutoBankItemOpcode(WorldPacket& recvPacket); + void HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket); + void HandleWrapItemOpcode(WorldPacket& recvPacket); + + void HandleAttackSwingOpcode(WorldPacket& recvPacket); + void HandleAttackStopOpcode(WorldPacket& recvPacket); + void HandleSetSheathedOpcode(WorldPacket& recvPacket); + + void HandleUseItemOpcode(WorldPacket& recvPacket); + void HandleOpenItemOpcode(WorldPacket& recvPacket); + void HandleCastSpellOpcode(WorldPacket& recvPacket); + void HandleCancelCastOpcode(WorldPacket& recvPacket); + void HandleCancelAuraOpcode(WorldPacket& recvPacket); + void HandleCancelGrowthAuraOpcode(WorldPacket& recvPacket); + void HandleCancelAutoRepeatSpellOpcode(WorldPacket& recvPacket); + + void HandleLearnTalentOpcode(WorldPacket& recvPacket); + void HandleLearnPreviewTalents(WorldPacket& recvPacket); + void HandleTalentWipeConfirmOpcode(WorldPacket& recvPacket); + void HandleUnlearnSkillOpcode(WorldPacket& recvPacket); + + void HandleQuestgiverStatusQueryOpcode(WorldPacket& recvPacket); + void HandleQuestgiverStatusMultipleQuery(WorldPacket& recvPacket); + void HandleQuestgiverHelloOpcode(WorldPacket& recvPacket); + void HandleQuestgiverAcceptQuestOpcode(WorldPacket& recvPacket); + void HandleQuestgiverQueryQuestOpcode(WorldPacket& recvPacket); + void HandleQuestgiverChooseRewardOpcode(WorldPacket& recvPacket); + void HandleQuestgiverRequestRewardOpcode(WorldPacket& recvPacket); + void HandleQuestQueryOpcode(WorldPacket& recvPacket); + void HandleQuestgiverCancel(WorldPacket& recv_data); + void HandleQuestLogSwapQuest(WorldPacket& recv_data); + void HandleQuestLogRemoveQuest(WorldPacket& recv_data); + void HandleQuestConfirmAccept(WorldPacket& recv_data); + void HandleQuestgiverCompleteQuest(WorldPacket& recv_data); + void HandleQuestgiverQuestAutoLaunch(WorldPacket& recvPacket); + void HandlePushQuestToParty(WorldPacket& recvPacket); + void HandleQuestPushResult(WorldPacket& recvPacket); + + bool processChatmessageFurtherAfterSecurityChecks(std::string&, uint32); + void HandleMessagechatOpcode(WorldPacket& recvPacket); + void SendPlayerNotFoundNotice(std::string name); + void SendPlayerAmbiguousNotice(std::string name); + void SendWrongFactionNotice(); + void SendChatRestrictedNotice(ChatRestrictionType restriction); + void HandleTextEmoteOpcode(WorldPacket& recvPacket); + void HandleChatIgnoredOpcode(WorldPacket& recvPacket); + + void HandleReclaimCorpseOpcode(WorldPacket& recvPacket); + void HandleCorpseQueryOpcode(WorldPacket& recvPacket); + void HandleCorpseMapPositionQuery(WorldPacket& recvPacket); + void HandleResurrectResponseOpcode(WorldPacket& recvPacket); + void HandleSummonResponseOpcode(WorldPacket& recv_data); + + void HandleJoinChannel(WorldPacket& recvPacket); + void HandleLeaveChannel(WorldPacket& recvPacket); + void HandleChannelList(WorldPacket& recvPacket); + void HandleChannelPassword(WorldPacket& recvPacket); + void HandleChannelSetOwner(WorldPacket& recvPacket); + void HandleChannelOwner(WorldPacket& recvPacket); + void HandleChannelModerator(WorldPacket& recvPacket); + void HandleChannelUnmoderator(WorldPacket& recvPacket); + void HandleChannelMute(WorldPacket& recvPacket); + void HandleChannelUnmute(WorldPacket& recvPacket); + void HandleChannelInvite(WorldPacket& recvPacket); + void HandleChannelKick(WorldPacket& recvPacket); + void HandleChannelBan(WorldPacket& recvPacket); + void HandleChannelUnban(WorldPacket& recvPacket); + void HandleChannelAnnouncements(WorldPacket& recvPacket); + void HandleChannelModerate(WorldPacket& recvPacket); + void HandleChannelDeclineInvite(WorldPacket& recvPacket); + void HandleChannelDisplayListQuery(WorldPacket& recvPacket); + void HandleGetChannelMemberCount(WorldPacket& recvPacket); + void HandleSetChannelWatch(WorldPacket& recvPacket); + + void HandleCompleteCinematic(WorldPacket& recvPacket); + void HandleNextCinematicCamera(WorldPacket& recvPacket); + + void HandlePageQuerySkippedOpcode(WorldPacket& recvPacket); + void HandlePageTextQueryOpcode(WorldPacket& recvPacket); + + void HandleTutorialFlag (WorldPacket & recv_data); + void HandleTutorialClear(WorldPacket & recv_data); + void HandleTutorialReset(WorldPacket & recv_data); + + //Pet + void HandlePetAction(WorldPacket & recv_data); + void HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid, uint16 flag, uint64 guid2); + void HandlePetNameQuery(WorldPacket & recv_data); + void HandlePetSetAction(WorldPacket & recv_data); + void HandlePetAbandon(WorldPacket & recv_data); + void HandlePetRename(WorldPacket & recv_data); + void HandlePetCancelAuraOpcode(WorldPacket& recvPacket); + void HandlePetUnlearnOpcode(WorldPacket& recvPacket); + void HandlePetSpellAutocastOpcode(WorldPacket& recvPacket); + void HandlePetCastSpellOpcode(WorldPacket& recvPacket); + void HandlePetLearnTalent(WorldPacket& recvPacket); + void HandleLearnPreviewTalentsPet(WorldPacket& recvPacket); + + void HandleSetActionBarToggles(WorldPacket& recv_data); + + void HandleCharRenameOpcode(WorldPacket& recv_data); + static void HandleChangePlayerNameOpcodeCallBack(QueryResult_AutoPtr result, uint32 accountId, std::string newname); + void HandleSetPlayerDeclinedNames(WorldPacket& recv_data); + + void HandleTotemDestroyed(WorldPacket& recv_data); + void HandleDismissCritter(WorldPacket& recv_data); + + //BattleGround + void HandleBattlemasterHelloOpcode(WorldPacket &recv_data); + void HandleBattlemasterJoinOpcode(WorldPacket &recv_data); + void HandleBattleGroundPlayerPositionsOpcode(WorldPacket& recv_data); + void HandlePVPLogDataOpcode(WorldPacket &recv_data); + void HandleBattleFieldPortOpcode(WorldPacket &recv_data); + void HandleBattlefieldListOpcode(WorldPacket &recv_data); + void HandleLeaveBattlefieldOpcode(WorldPacket &recv_data); + void HandleBattlemasterJoinArena(WorldPacket &recv_data); + void HandleReportPvPAFK(WorldPacket &recv_data); + + void HandleWardenDataOpcode(WorldPacket& recv_data); + void HandleWorldTeleportOpcode(WorldPacket& recv_data); + void HandleMinimapPingOpcode(WorldPacket& recv_data); + void HandleRandomRollOpcode(WorldPacket& recv_data); + void HandleFarSightOpcode(WorldPacket& recv_data); + void HandleSetDungeonDifficultyOpcode(WorldPacket& recv_data); + void HandleSetRaidDifficultyOpcode(WorldPacket& recv_data); + void HandleMoveSetCanFlyAckOpcode(WorldPacket& recv_data); + void HandleSetTitleOpcode(WorldPacket& recv_data); + void HandleRealmSplitOpcode(WorldPacket& recv_data); + void HandleTimeSyncResp(WorldPacket& recv_data); + void HandleWhoisOpcode(WorldPacket& recv_data); + void HandleResetInstancesOpcode(WorldPacket& recv_data); + + // Looking for Dungeon/Raid + void HandleSetLfgCommentOpcode(WorldPacket & recv_data); + void HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& recv_data); + void HandleLfgPartyLockInfoRequestOpcode(WorldPacket& recv_data); + void HandleLfgJoinOpcode(WorldPacket &recv_data); + void HandleLfgLeaveOpcode(WorldPacket & /*recv_data*/); + void HandleLfgSetRolesOpcode(WorldPacket &recv_data); + void SendLfgUpdatePlayer(uint8 updateType); + void SendLfgUpdateParty(uint8 updateType); + void SendLfgRoleChosen(uint64 guid, uint8 roles); + void SendLfgUpdateSearch(bool update); + void SendLfgJoinResult(uint8 checkResult, uint8 checkValue); + void SendLfgQueueStatus(uint32 dungeon, int32 waitTime, int32 avgWaitTime, int32 waitTimeTanks, int32 waitTimeHealer, int32 waitTimeDps, uint32 queuedTime, uint8 tanks, uint8 healers, uint8 dps); + + // Arena Team + void HandleInspectArenaTeamsOpcode(WorldPacket& recv_data); + void HandleArenaTeamQueryOpcode(WorldPacket& recv_data); + void HandleArenaTeamRosterOpcode(WorldPacket& recv_data); + void HandleArenaTeamInviteOpcode(WorldPacket& recv_data); + void HandleArenaTeamAcceptOpcode(WorldPacket& recv_data); + void HandleArenaTeamDeclineOpcode(WorldPacket& recv_data); + void HandleArenaTeamLeaveOpcode(WorldPacket& recv_data); + void HandleArenaTeamRemoveOpcode(WorldPacket& recv_data); + void HandleArenaTeamDisbandOpcode(WorldPacket& recv_data); + void HandleArenaTeamLeaderOpcode(WorldPacket& recv_data); + + void HandleAreaSpiritHealerQueryOpcode(WorldPacket& recv_data); + void HandleAreaSpiritHealerQueueOpcode(WorldPacket& recv_data); + void HandleCancelMountAuraOpcode(WorldPacket& recv_data); + void HandleSelfResOpcode(WorldPacket& recv_data); + void HandleComplainOpcode(WorldPacket& recv_data); + void HandleRequestPetInfoOpcode(WorldPacket& recv_data); + + // Socket gem + void HandleSocketOpcode(WorldPacket& recv_data); + + void HandleCancelTempEnchantmentOpcode(WorldPacket& recv_data); + + void HandleItemRefundInfoRequest(WorldPacket& recv_data); + void HandleItemRefund(WorldPacket& recv_data); + + void HandleChannelVoiceOnOpcode(WorldPacket & recv_data); + void HandleVoiceSessionEnableOpcode(WorldPacket& recv_data); + void HandleSetActiveVoiceChannel(WorldPacket& recv_data); + void HandleSetTaxiBenchmarkOpcode(WorldPacket& recv_data); + + // Guild Bank + void HandleGuildPermissions(WorldPacket& recv_data); + void HandleGuildBankMoneyWithdrawn(WorldPacket& recv_data); + void HandleGuildBankerActivate(WorldPacket& recv_data); + void HandleGuildBankQueryTab(WorldPacket& recv_data); + void HandleGuildBankLogQuery(WorldPacket& recv_data); + void HandleGuildBankDepositMoney(WorldPacket& recv_data); + void HandleGuildBankWithdrawMoney(WorldPacket& recv_data); + void HandleGuildBankSwapItems(WorldPacket& recv_data); + + void HandleGuildBankUpdateTab(WorldPacket& recv_data); + void HandleGuildBankBuyTab(WorldPacket& recv_data); + void HandleQueryGuildBankTabText(WorldPacket& recv_data); + void HandleSetGuildBankTabText(WorldPacket& recv_data); + + // Calendar + void HandleCalendarGetCalendar(WorldPacket& recv_data); + void HandleCalendarGetEvent(WorldPacket& recv_data); + void HandleCalendarGuildFilter(WorldPacket& recv_data); + void HandleCalendarArenaTeam(WorldPacket& recv_data); + void HandleCalendarAddEvent(WorldPacket& recv_data); + void HandleCalendarUpdateEvent(WorldPacket& recv_data); + void HandleCalendarRemoveEvent(WorldPacket& recv_data); + void HandleCalendarCopyEvent(WorldPacket& recv_data); + void HandleCalendarEventInvite(WorldPacket& recv_data); + void HandleCalendarEventRsvp(WorldPacket& recv_data); + void HandleCalendarEventRemoveInvite(WorldPacket& recv_data); + void HandleCalendarEventStatus(WorldPacket& recv_data); + void HandleCalendarEventModeratorStatus(WorldPacket& recv_data); + void HandleCalendarComplain(WorldPacket& recv_data); + void HandleCalendarGetNumPending(WorldPacket& recv_data); + + void HandleSpellClick(WorldPacket& recv_data); + void HandleMirrrorImageDataRequest(WorldPacket & recv_data); + void HandleAlterAppearance(WorldPacket& recv_data); + void HandleRemoveGlyph(WorldPacket& recv_data); + void HandleCharCustomize(WorldPacket& recv_data); + void HandleQueryInspectAchievements(WorldPacket& recv_data); + void HandleEquipmentSetSave(WorldPacket& recv_data); + void HandleEquipmentSetDelete(WorldPacket& recv_data); + void HandleEquipmentSetUse(WorldPacket& recv_data); + void HandleWorldStateUITimerUpdate(WorldPacket& recv_data); + void HandleReadyForAccountDataTimes(WorldPacket& recv_data); + void HandleQueryQuestsCompleted(WorldPacket& recv_data); + void HandleQuestPOIQuery(WorldPacket& recv_data); + void HandleOnPVPKill(Player *killed); + bool HandleOnPlayerChat(const char *text); + uint32 HandleOnGetXP(uint32 amount); + int32 HandleOnGetMoney(int32 amount); + void HandleOnAreaChange(AreaTableEntry const *pArea); + bool HandleOnItemClick(Item *pItem); + bool HandleOnItemOpen(Item *pItem); + bool HandleOnGoClick(GameObject *pGameObject); + void HandleOnCreatureKill(Creature *pCreature); + void HandleEjectPasenger(WorldPacket &data); + void HandleEnterPlayerVehicle(WorldPacket &data); + private: + // private trade methods + void moveItems(Item* myItems[], Item* hisItems[]); + + // logging helper + void LogUnexpectedOpcode(WorldPacket *packet, const char * reason); + void LogUnprocessedTail(WorldPacket *packet); + + uint32 m_GUIDLow; // set loggined or recently logout player (while m_playerRecentlyLogout set) + Player *_player; + WorldSocket *m_Socket; + std::string m_Address; + + AccountTypes _security; + uint32 _accountId; + uint8 m_expansion; + + time_t _logoutTime; + bool m_inQueue; // session wait in auth.queue + bool m_playerLoading; // code processed in LoginPlayer + bool m_playerLogout; // code processed in LogoutPlayer + bool m_playerRecentlyLogout; + bool m_playerSave; + LocaleConstant m_sessionDbcLocale; + int m_sessionDbLocaleIndex; + uint32 m_latency; + AccountData m_accountData[NUM_ACCOUNT_DATA_TYPES]; + uint32 m_Tutorials[8]; + bool m_TutorialsChanged; + AddonsList m_addonsList; + ACE_Based::LockedQueue _recvQueue; +}; +#endif +/// @} diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp new file mode 100644 index 00000000000..c07b369d0b9 --- /dev/null +++ b/src/server/game/Server/WorldSocket.cpp @@ -0,0 +1,1064 @@ +/* +* Copyright (C) 2005-2009 MaNGOS +* +* Copyright (C) 2008-2010 Trinity +* +* 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, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "WorldSocket.h" +#include "Common.h" + +#include "Util.h" +#include "World.h" +#include "WorldPacket.h" +#include "SharedDefines.h" +#include "ByteBuffer.h" +#include "Opcodes.h" +#include "Database/DatabaseEnv.h" +#include "Auth/BigNumber.h" +#include "Auth/Sha1.h" +#include "WorldSession.h" +#include "WorldSocketMgr.h" +#include "Log.h" +#include "WorldLog.h" + +#if defined(__GNUC__) +#pragma pack(1) +#else +#pragma pack(push,1) +#endif + +struct ServerPktHeader +{ + /** + * size is the length of the payload _plus_ the length of the opcode + */ + ServerPktHeader(uint32 size, uint16 cmd) : size(size) + { + uint8 headerIndex=0; + if (isLargePacket()) + { + sLog.outDebug("initializing large server to client packet. Size: %u, cmd: %u", size, cmd); + header[headerIndex++] = 0x80|(0xFF &(size>>16)); + } + header[headerIndex++] = 0xFF &(size>>8); + header[headerIndex++] = 0xFF &size; + + header[headerIndex++] = 0xFF & cmd; + header[headerIndex++] = 0xFF & (cmd>>8); + } + + uint8 getHeaderLength() + { + // cmd = 2 bytes, size= 2||3bytes + return 2+(isLargePacket()?3:2); + } + + bool isLargePacket() + { + return size > 0x7FFF; + } + + const uint32 size; + uint8 header[5]; +}; + +struct ClientPktHeader +{ + uint16 size; + uint32 cmd; +}; + +#if defined(__GNUC__) +#pragma pack() +#else +#pragma pack(pop) +#endif + +WorldSocket::WorldSocket (void) : +WorldHandler(), +m_Session(0), +m_RecvWPct(0), +m_RecvPct(), +m_Header(sizeof (ClientPktHeader)), +m_OutBuffer(0), +m_OutBufferSize(65536), +m_OutActive(false), +m_Seed(static_cast (rand32())), +m_OverSpeedPings(0), +m_LastPingTime(ACE_Time_Value::zero) +{ + reference_counting_policy().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED); + + msg_queue()->high_water_mark(8*1024*1024); + msg_queue()->low_water_mark(8*1024*1024); +} + +WorldSocket::~WorldSocket (void) +{ + if (m_RecvWPct) + delete m_RecvWPct; + + if (m_OutBuffer) + m_OutBuffer->release(); + + closing_ = true; + + peer().close(); +} + +bool WorldSocket::IsClosed (void) const +{ + return closing_; +} + +void WorldSocket::CloseSocket (void) +{ + { + ACE_GUARD (LockType, Guard, m_OutBufferLock); + + if (closing_) + return; + + closing_ = true; + peer().close_writer(); + } + + { + ACE_GUARD (LockType, Guard, m_SessionLock); + + m_Session = NULL; + } +} + +const std::string& WorldSocket::GetRemoteAddress (void) const +{ + return m_Address; +} + +int WorldSocket::SendPacket (const WorldPacket& pct) +{ + ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); + + if (closing_) + return -1; + + // Dump outgoing packet. + if (sWorldLog.LogWorld()) + { + sWorldLog.outTimestampLog ("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", + (uint32) get_handle(), + pct.size(), + LookupOpcodeName (pct.GetOpcode()), + pct.GetOpcode()); + + uint32 p = 0; + while (p < pct.size()) + { + for (uint32 j = 0; j < 16 && p < pct.size(); j++) + sWorldLog.outLog("%.2X ", const_cast(pct)[p++]); + + sWorldLog.outLog("\n"); + } + sWorldLog.outLog("\n"); + } + + ServerPktHeader header(pct.size()+2, pct.GetOpcode()); + m_Crypt.EncryptSend ((uint8*)header.header, header.getHeaderLength()); + + if (m_OutBuffer->space() >= pct.size() + header.getHeaderLength() && msg_queue()->is_empty()) + { + // Put the packet on the buffer. + if (m_OutBuffer->copy((char*) header.header, header.getHeaderLength()) == -1) + ACE_ASSERT (false); + + if (!pct.empty()) + if (m_OutBuffer->copy((char*) pct.contents(), pct.size()) == -1) + ACE_ASSERT (false); + } + else + { + // Enqueue the packet. + ACE_Message_Block* mb; + + ACE_NEW_RETURN(mb, ACE_Message_Block(pct.size() + header.getHeaderLength()), -1); + + mb->copy((char*) header.header, header.getHeaderLength()); + + if (!pct.empty()) + mb->copy((const char*)pct.contents(), pct.size()); + + if (msg_queue()->enqueue_tail(mb,(ACE_Time_Value*)&ACE_Time_Value::zero) == -1) + { + sLog.outError("WorldSocket::SendPacket enqueue_tail failed"); + mb->release(); + return -1; + } + } + + return 0; +} + +long WorldSocket::AddReference (void) +{ + return static_cast (add_reference()); +} + +long WorldSocket::RemoveReference (void) +{ + return static_cast (remove_reference()); +} + +int WorldSocket::open (void *a) +{ + ACE_UNUSED_ARG (a); + + // Prevent double call to this func. + if (m_OutBuffer) + return -1; + + // This will also prevent the socket from being Updated + // while we are initializing it. + m_OutActive = true; + + // Hook for the manager. + if (sWorldSocketMgr->OnSocketOpen(this) == -1) + return -1; + + // Allocate the buffer. + ACE_NEW_RETURN (m_OutBuffer, ACE_Message_Block (m_OutBufferSize), -1); + + // Store peer address. + ACE_INET_Addr remote_addr; + + if (peer().get_remote_addr(remote_addr) == -1) + { + sLog.outError ("WorldSocket::open: peer().get_remote_addr errno = %s", ACE_OS::strerror (errno)); + return -1; + } + + m_Address = remote_addr.get_host_addr(); + + // Send startup packet. + WorldPacket packet (SMSG_AUTH_CHALLENGE, 24); + packet << uint32(1); // 1...31 + packet << m_Seed; + + BigNumber seed1; + seed1.SetRand(16 * 8); + packet.append(seed1.AsByteArray(16), 16); // new encryption seeds + + BigNumber seed2; + seed2.SetRand(16 * 8); + packet.append(seed2.AsByteArray(16), 16); // new encryption seeds + + if (SendPacket(packet) == -1) + return -1; + + // Register with ACE Reactor + if (reactor()->register_handler(this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK) == -1) + { + sLog.outError ("WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno)); + return -1; + } + + // reactor takes care of the socket from now on + remove_reference(); + + return 0; +} + +int WorldSocket::close (int) +{ + shutdown(); + + closing_ = true; + + remove_reference(); + + return 0; +} + +int WorldSocket::handle_input (ACE_HANDLE) +{ + if (closing_) + return -1; + + switch (handle_input_missing_data()) + { + case -1 : + { + if ((errno == EWOULDBLOCK) || + (errno == EAGAIN)) + { + return Update(); // interesting line ,isn't it ? + } + + DEBUG_LOG("WorldSocket::handle_input: Peer error closing connection errno = %s", ACE_OS::strerror (errno)); + + errno = ECONNRESET; + return -1; + } + case 0: + { + DEBUG_LOG("WorldSocket::handle_input: Peer has closed connection"); + + errno = ECONNRESET; + return -1; + } + case 1: + return 1; + default: + return Update(); // another interesting line ;) + } + + ACE_NOTREACHED(return -1); +} + +int WorldSocket::handle_output (ACE_HANDLE) +{ + ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); + + if (closing_) + return -1; + + size_t send_len = m_OutBuffer->length(); + + if (send_len == 0) + return handle_output_queue(Guard); + +#ifdef MSG_NOSIGNAL + ssize_t n = peer().send (m_OutBuffer->rd_ptr(), send_len, MSG_NOSIGNAL); +#else + ssize_t n = peer().send (m_OutBuffer->rd_ptr(), send_len); +#endif // MSG_NOSIGNAL + + if (n == 0) + return -1; + else if (n == -1) + { + if (errno == EWOULDBLOCK || errno == EAGAIN) + return schedule_wakeup_output (Guard); + + return -1; + } + else if (n < (ssize_t)send_len) //now n > 0 + { + m_OutBuffer->rd_ptr (static_cast (n)); + + // move the data to the base of the buffer + m_OutBuffer->crunch(); + + return schedule_wakeup_output (Guard); + } + else //now n == send_len + { + m_OutBuffer->reset(); + + return handle_output_queue (Guard); + } + + ACE_NOTREACHED (return 0); +} + +int WorldSocket::handle_output_queue (GuardType& g) +{ + if (msg_queue()->is_empty()) + return cancel_wakeup_output(g); + + ACE_Message_Block *mblk; + + if (msg_queue()->dequeue_head(mblk, (ACE_Time_Value*)&ACE_Time_Value::zero) == -1) + { + sLog.outError("WorldSocket::handle_output_queue dequeue_head"); + return -1; + } + + const size_t send_len = mblk->length(); + +#ifdef MSG_NOSIGNAL + ssize_t n = peer().send (mblk->rd_ptr(), send_len, MSG_NOSIGNAL); +#else + ssize_t n = peer().send (mblk->rd_ptr(), send_len); +#endif // MSG_NOSIGNAL + + if (n == 0) + { + mblk->release(); + + return -1; + } + else if (n == -1) + { + if (errno == EWOULDBLOCK || errno == EAGAIN) + { + msg_queue()->enqueue_head(mblk, (ACE_Time_Value*) &ACE_Time_Value::zero); + return schedule_wakeup_output (g); + } + + mblk->release(); + return -1; + } + else if (n < (ssize_t)send_len) //now n > 0 + { + mblk->rd_ptr(static_cast (n)); + + if (msg_queue()->enqueue_head(mblk, (ACE_Time_Value*) &ACE_Time_Value::zero) == -1) + { + sLog.outError("WorldSocket::handle_output_queue enqueue_head"); + mblk->release(); + return -1; + } + + return schedule_wakeup_output (g); + } + else //now n == send_len + { + mblk->release(); + + return msg_queue()->is_empty() ? cancel_wakeup_output(g) : ACE_Event_Handler::WRITE_MASK; + } + + ACE_NOTREACHED(return -1); +} + +int WorldSocket::handle_close (ACE_HANDLE h, ACE_Reactor_Mask) +{ + // Critical section + { + ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); + + closing_ = true; + + if (h == ACE_INVALID_HANDLE) + peer().close_writer(); + } + + // Critical section + { + ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); + + m_Session = NULL; + } + + return 0; +} + +int WorldSocket::Update (void) +{ + if (closing_) + return -1; + + if (m_OutActive || (m_OutBuffer->length() == 0 && msg_queue()->is_empty())) + return 0; + + int ret; + do + ret = handle_output (get_handle()); + while (ret > 0); + + return ret; +} + +int WorldSocket::handle_input_header (void) +{ + ACE_ASSERT (m_RecvWPct == NULL); + + ACE_ASSERT (m_Header.length() == sizeof(ClientPktHeader)); + + m_Crypt.DecryptRecv ((uint8*) m_Header.rd_ptr(), sizeof(ClientPktHeader)); + + ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr()); + + EndianConvertReverse(header.size); + EndianConvert(header.cmd); + + if ((header.size < 4) || (header.size > 10240) || (header.cmd > 10240)) + { + sLog.outError ("WorldSocket::handle_input_header: client sent malformed packet size = %d , cmd = %d", + header.size, header.cmd); + + errno = EINVAL; + return -1; + } + + header.size -= 4; + + ACE_NEW_RETURN (m_RecvWPct, WorldPacket ((uint16) header.cmd, header.size), -1); + + if (header.size > 0) + { + m_RecvWPct->resize (header.size); + m_RecvPct.base ((char*) m_RecvWPct->contents(), m_RecvWPct->size()); + } + else + { + ACE_ASSERT(m_RecvPct.space() == 0); + } + + return 0; +} + +int WorldSocket::handle_input_payload (void) +{ + // set errno properly here on error !!! + // now have a header and payload + + ACE_ASSERT (m_RecvPct.space() == 0); + ACE_ASSERT (m_Header.space() == 0); + ACE_ASSERT (m_RecvWPct != NULL); + + const int ret = ProcessIncoming (m_RecvWPct); + + m_RecvPct.base (NULL, 0); + m_RecvPct.reset(); + m_RecvWPct = NULL; + + m_Header.reset(); + + if (ret == -1) + errno = EINVAL; + + return ret; +} + +int WorldSocket::handle_input_missing_data (void) +{ + char buf [4096]; + + ACE_Data_Block db (sizeof (buf), + ACE_Message_Block::MB_DATA, + buf, + 0, + 0, + ACE_Message_Block::DONT_DELETE, + 0); + + ACE_Message_Block message_block(&db, + ACE_Message_Block::DONT_DELETE, + 0); + + const size_t recv_size = message_block.space(); + + const ssize_t n = peer().recv (message_block.wr_ptr(), + recv_size); + + if (n <= 0) + return n; + + message_block.wr_ptr (n); + + while (message_block.length() > 0) + { + if (m_Header.space() > 0) + { + //need to receive the header + const size_t to_header = (message_block.length() > m_Header.space() ? m_Header.space() : message_block.length()); + m_Header.copy (message_block.rd_ptr(), to_header); + message_block.rd_ptr (to_header); + + if (m_Header.space() > 0) + { + // Couldn't receive the whole header this time. + ACE_ASSERT (message_block.length() == 0); + errno = EWOULDBLOCK; + return -1; + } + + // We just received nice new header + if (handle_input_header() == -1) + { + ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); + return -1; + } + } + + // Its possible on some error situations that this happens + // for example on closing when epoll receives more chunked data and stuff + // hope this is not hack ,as proper m_RecvWPct is asserted around + if (!m_RecvWPct) + { + sLog.outError ("Forcing close on input m_RecvWPct = NULL"); + errno = EINVAL; + return -1; + } + + // We have full read header, now check the data payload + if (m_RecvPct.space() > 0) + { + //need more data in the payload + const size_t to_data = (message_block.length() > m_RecvPct.space() ? m_RecvPct.space() : message_block.length()); + m_RecvPct.copy (message_block.rd_ptr(), to_data); + message_block.rd_ptr (to_data); + + if (m_RecvPct.space() > 0) + { + // Couldn't receive the whole data this time. + ACE_ASSERT (message_block.length() == 0); + errno = EWOULDBLOCK; + return -1; + } + } + + //just received fresh new payload + if (handle_input_payload() == -1) + { + ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); + return -1; + } + } + + return n == recv_size ? 1 : 2; +} + +int WorldSocket::cancel_wakeup_output (GuardType& g) +{ + if (!m_OutActive) + return 0; + + m_OutActive = false; + + g.release(); + + if (reactor()->cancel_wakeup + (this, ACE_Event_Handler::WRITE_MASK) == -1) + { + // would be good to store errno from reactor with errno guard + sLog.outError ("WorldSocket::cancel_wakeup_output"); + return -1; + } + + return 0; +} + +int WorldSocket::schedule_wakeup_output (GuardType& g) +{ + if (m_OutActive) + return 0; + + m_OutActive = true; + + g.release(); + + if (reactor()->schedule_wakeup + (this, ACE_Event_Handler::WRITE_MASK) == -1) + { + sLog.outError ("WorldSocket::schedule_wakeup_output"); + return -1; + } + + return 0; +} + +int WorldSocket::ProcessIncoming (WorldPacket* new_pct) +{ + ACE_ASSERT (new_pct); + + // manage memory ;) + ACE_Auto_Ptr aptr (new_pct); + + const ACE_UINT16 opcode = new_pct->GetOpcode(); + + if (closing_) + return -1; + + // Dump received packet. + if (sWorldLog.LogWorld()) + { + sWorldLog.outTimestampLog ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", + (uint32) get_handle(), + new_pct->size(), + LookupOpcodeName (new_pct->GetOpcode()), + new_pct->GetOpcode()); + + uint32 p = 0; + while (p < new_pct->size()) + { + for (uint32 j = 0; j < 16 && p < new_pct->size(); j++) + sWorldLog.outLog ("%.2X ", (*new_pct)[p++]); + + sWorldLog.outLog ("\n"); + } + sWorldLog.outLog ("\n"); + } + + try { + switch(opcode) + { + case CMSG_PING: + return HandlePing (*new_pct); + case CMSG_AUTH_SESSION: + if (m_Session) + { + sLog.outError ("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again"); + return -1; + } + + return HandleAuthSession (*new_pct); + case CMSG_KEEP_ALIVE: + DEBUG_LOG ("CMSG_KEEP_ALIVE ,size: %d", new_pct->size()); + + return 0; + default: + { + ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); + + if (m_Session != NULL) + { + // Our Idle timer will reset on any non PING opcodes. + // Catches people idling on the login screen and any lingering ingame connections. + m_Session->ResetTimeOutTime(); + + // OK ,give the packet to WorldSession + aptr.release(); + // WARNINIG here we call it with locks held. + // Its possible to cause deadlock if QueuePacket calls back + m_Session->QueuePacket (new_pct); + return 0; + } + else + { + sLog.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = %u", uint32(opcode)); + return -1; + } + } + } + } + catch(ByteBufferException &) + { + sLog.outError("WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet (opcode: %u) from client %s, accountid=%i. Disconnected client.", + opcode, GetRemoteAddress().c_str(), m_Session?m_Session->GetAccountId():-1); + if (sLog.IsOutDebug()) + { + sLog.outDebug("Dumping error causing packet:"); + new_pct->hexlike(); + } + + return -1; + } + + ACE_NOTREACHED (return 0); +} + +int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) +{ + // NOTE: ATM the socket is singlethread, have this in mind ... + uint8 digest[20]; + uint32 clientSeed; + uint32 unk2, unk3; + uint64 unk4; + uint32 BuiltNumberClient; + uint32 id, security; + //uint8 expansion = 0; + LocaleConstant locale; + std::string account; + Sha1Hash sha1; + BigNumber v, s, g, N; + WorldPacket packet, SendAddonPacked; + + BigNumber K; + + if (sWorld.IsClosed()) + { + packet.Initialize(SMSG_AUTH_RESPONSE, 1); + packet << uint8(AUTH_REJECT); + SendPacket (packet); + + sLog.outError ("WorldSocket::HandleAuthSession: World closed, denying client (%s).", m_Session->GetRemoteAddress().c_str()); + return -1; + } + + // Read the content of the packet + recvPacket >> BuiltNumberClient; // for now no use + recvPacket >> unk2; + recvPacket >> account; + recvPacket >> unk3; + recvPacket >> clientSeed; + recvPacket >> unk4; + recvPacket.read (digest, 20); + + DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, unk3 %u, clientseed %u", + BuiltNumberClient, + unk2, + account.c_str(), + unk3, + clientSeed); + + // Get the account information from the realmd database + std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below + LoginDatabase.escape_string (safe_account); + // No SQL injection, username escaped. + + QueryResult_AutoPtr result = + LoginDatabase.PQuery ("SELECT " + "id, " //0 + "sessionkey, " //1 + "last_ip, " //2 + "locked, " //3 + "v, " //4 + "s, " //5 + "expansion, " //6 + "mutetime, " //7 + "locale " //8 + "FROM account " + "WHERE username = '%s'", + safe_account.c_str()); + + // Stop if the account is not found + if (!result) + { + packet.Initialize (SMSG_AUTH_RESPONSE, 1); + packet << uint8 (AUTH_UNKNOWN_ACCOUNT); + + SendPacket (packet); + + sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); + return -1; + } + + Field* fields = result->Fetch(); + + uint8 expansion = fields[6].GetUInt8(); + uint32 world_expansion = sWorld.getConfig(CONFIG_EXPANSION); + if (expansion > world_expansion) + expansion = world_expansion; + //expansion = ((sWorld.getConfig(CONFIG_EXPANSION) > fields[6].GetUInt8()) ? fields[6].GetUInt8() : sWorld.getConfig(CONFIG_EXPANSION)); + + N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); + g.SetDword (7); + + v.SetHexStr(fields[4].GetString()); + s.SetHexStr (fields[5].GetString()); + + const char* sStr = s.AsHexStr(); //Must be freed by OPENSSL_free() + const char* vStr = v.AsHexStr(); //Must be freed by OPENSSL_free() + + DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v: %s", + sStr, + vStr); + + OPENSSL_free ((void*) sStr); + OPENSSL_free ((void*) vStr); + + ///- Re-check ip locking (same check as in realmd). + if (fields[3].GetUInt8() == 1) // if ip is locked + { + if (strcmp (fields[2].GetString(), GetRemoteAddress().c_str())) + { + packet.Initialize (SMSG_AUTH_RESPONSE, 1); + packet << uint8 (AUTH_FAILED); + SendPacket (packet); + + sLog.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)."); + return -1; + } + } + + id = fields[0].GetUInt32(); + /* + if (security > SEC_ADMINISTRATOR) // prevent invalid security settings in DB + security = SEC_ADMINISTRATOR; + */ + + K.SetHexStr (fields[1].GetString()); + + time_t mutetime = time_t (fields[7].GetUInt64()); + + locale = LocaleConstant (fields[8].GetUInt8()); + if (locale >= MAX_LOCALE) + locale = LOCALE_enUS; + + // Checks gmlevel per Realm + result = + LoginDatabase.PQuery ("SELECT " + "RealmID, " //0 + "gmlevel " //1 + "FROM account_access " + "WHERE id = '%d'" + " AND (RealmID = '%d'" + " OR RealmID = '-1')", + id, realmID); + if (!result) + security = 0; + else + { + fields = result->Fetch(); + security = fields[1].GetInt32(); + } + + // Re-check account ban (same check as in realmd) + QueryResult_AutoPtr banresult = + LoginDatabase.PQuery ("SELECT 1 FROM account_banned WHERE id = %u AND active = 1 " + "UNION " + "SELECT 1 FROM ip_banned WHERE ip = '%s'", + id, GetRemoteAddress().c_str()); + + if (banresult) // if account banned + { + packet.Initialize (SMSG_AUTH_RESPONSE, 1); + packet << uint8 (AUTH_BANNED); + SendPacket (packet); + + sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); + return -1; + } + + // Check locked state for server + sWorld.UpdateAllowedSecurity(); + AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit(); + sLog.outDebug("Allowed Level: %u Player Level %u", allowedAccountType, AccountTypes(security)); + if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType) + { + WorldPacket Packet (SMSG_AUTH_RESPONSE, 1); + Packet << uint8 (AUTH_UNAVAILABLE); + + SendPacket (packet); + + sLog.outDetail ("WorldSocket::HandleAuthSession: User tries to login but his security level is not enough"); + return -1; + } + + // Check that Key and account name are the same on client and server + Sha1Hash sha; + + uint32 t = 0; + uint32 seed = m_Seed; + + sha.UpdateData (account); + sha.UpdateData ((uint8 *) & t, 4); + sha.UpdateData ((uint8 *) & clientSeed, 4); + sha.UpdateData ((uint8 *) & seed, 4); + sha.UpdateBigNumbers (&K, NULL); + sha.Finalize(); + + if (memcmp (sha.GetDigest(), digest, 20)) + { + packet.Initialize (SMSG_AUTH_RESPONSE, 1); + packet << uint8 (AUTH_FAILED); + + SendPacket (packet); + + sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed)."); + return -1; + } + + std::string address = GetRemoteAddress(); + + DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", + account.c_str(), + address.c_str()); + + // Update the last_ip in the database + // No SQL injection, username escaped. + LoginDatabase.escape_string (address); + + LoginDatabase.PExecute ("UPDATE account " + "SET last_ip = '%s' " + "WHERE username = '%s'", + address.c_str(), + safe_account.c_str()); + + // NOTE ATM the socket is single-threaded, have this in mind ... + ACE_NEW_RETURN (m_Session, WorldSession (id, this, AccountTypes(security), expansion, mutetime, locale), -1); + + m_Crypt.Init(&K); + + m_Session->LoadGlobalAccountData(); + m_Session->LoadTutorialsData(); + m_Session->ReadAddonsInfo(recvPacket); + + // Sleep this Network thread for + uint32 sleepTime = sWorld.getConfig(CONFIG_SESSION_ADD_DELAY); + ACE_OS::sleep (ACE_Time_Value (0, sleepTime)); + + sWorld.AddSession (m_Session); + + return 0; +} + +int WorldSocket::HandlePing (WorldPacket& recvPacket) +{ + uint32 ping; + uint32 latency; + + // Get the ping packet content + recvPacket >> ping; + recvPacket >> latency; + + if (m_LastPingTime == ACE_Time_Value::zero) + m_LastPingTime = ACE_OS::gettimeofday(); // for 1st ping + else + { + ACE_Time_Value cur_time = ACE_OS::gettimeofday(); + ACE_Time_Value diff_time (cur_time); + diff_time -= m_LastPingTime; + m_LastPingTime = cur_time; + + if (diff_time < ACE_Time_Value (27)) + { + ++m_OverSpeedPings; + + uint32 max_count = sWorld.getConfig (CONFIG_MAX_OVERSPEED_PINGS); + + if (max_count && m_OverSpeedPings > max_count) + { + ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); + + if (m_Session && m_Session->GetSecurity() == SEC_PLAYER) + { + sLog.outError ("WorldSocket::HandlePing: Player kicked for " + "over-speed pings address = %s", + GetRemoteAddress().c_str()); + + return -1; + } + } + } + else + m_OverSpeedPings = 0; + } + + // critical section + { + ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); + + if (m_Session) + m_Session->SetLatency (latency); + else + { + sLog.outError ("WorldSocket::HandlePing: peer sent CMSG_PING, " + "but is not authenticated or got recently kicked," + " address = %s", + GetRemoteAddress().c_str()); + return -1; + } + } + + WorldPacket packet (SMSG_PONG, 4); + packet << ping; + return SendPacket (packet); +} diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h new file mode 100644 index 00000000000..70654274215 --- /dev/null +++ b/src/server/game/Server/WorldSocket.h @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** \addtogroup u2w User to World Communication + * @{ + * \file WorldSocket.h + * \author Derex + */ + +#ifndef _WORLDSOCKET_H +#define _WORLDSOCKET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "Common.h" +#include "Auth/AuthCrypt.h" + +class ACE_Message_Block; +class WorldPacket; +class WorldSession; + +/// Handler that can communicate over stream sockets. +typedef ACE_Svc_Handler WorldHandler; + +/** + * WorldSocket. + * + * This class is responsible for the communication with + * remote clients. + * Most methods return -1 on failure. + * The class uses reference counting. + * + * For output the class uses one buffer (64K usually) and + * a queue where it stores packet if there is no place on + * the queue. The reason this is done, is because the server + * does really a lot of small-size writes to it, and it doesn't + * scale well to allocate memory for every. When something is + * written to the output buffer the socket is not immediately + * activated for output (again for the same reason), there + * is 10ms celling (thats why there is Update() method). + * This concept is similar to TCP_CORK, but TCP_CORK + * uses 200ms celling. As result overhead generated by + * sending packets from "producer" threads is minimal, + * and doing a lot of writes with small size is tolerated. + * + * The calls to Update() method are managed by WorldSocketMgr + * and ReactorRunnable. + * + * For input ,the class uses one 1024 bytes buffer on stack + * to which it does recv() calls. And then received data is + * distributed where its needed. 1024 matches pretty well the + * traffic generated by client for now. + * + * The input/output do speculative reads/writes (AKA it tryes + * to read all data available in the kernel buffer or tryes to + * write everything available in userspace buffer), + * which is ok for using with Level and Edge Triggered IO + * notification. + * + */ +class WorldSocket : protected WorldHandler +{ + public: + /// Declare some friends + friend class ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR >; + friend class WorldSocketMgr; + friend class ReactorRunnable; + + /// Declare the acceptor for this class + typedef ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR > Acceptor; + + /// Mutex type used for various synchronizations. + typedef ACE_Thread_Mutex LockType; + typedef ACE_Guard GuardType; + + /// Check if socket is closed. + bool IsClosed (void) const; + + /// Close the socket. + void CloseSocket (void); + + /// Get address of connected peer. + const std::string& GetRemoteAddress (void) const; + + /// Send A packet on the socket, this function is reentrant. + /// @param pct packet to send + /// @return -1 of failure + int SendPacket (const WorldPacket& pct); + + /// Add reference to this object. + long AddReference (void); + + /// Remove reference to this object. + long RemoveReference (void); + + protected: + /// things called by ACE framework. + WorldSocket (void); + virtual ~WorldSocket (void); + + /// Called on open ,the void* is the acceptor. + virtual int open (void *); + + /// Called on failures inside of the acceptor, don't call from your code. + virtual int close (int); + + /// Called when we can read from the socket. + virtual int handle_input (ACE_HANDLE = ACE_INVALID_HANDLE); + + /// Called when the socket can write. + virtual int handle_output (ACE_HANDLE = ACE_INVALID_HANDLE); + + /// Called when connection is closed or error happens. + virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); + + /// Called by WorldSocketMgr/ReactorRunnable. + int Update (void); + + private: + /// Helper functions for processing incoming data. + int handle_input_header (void); + int handle_input_payload (void); + int handle_input_missing_data (void); + + /// Help functions to mark/unmark the socket for output. + /// @param g the guard is for m_OutBufferLock, the function will release it + int cancel_wakeup_output (GuardType& g); + int schedule_wakeup_output (GuardType& g); + + /// Drain the queue if its not empty. + int handle_output_queue (GuardType& g); + + /// process one incoming packet. + /// @param new_pct received packet ,note that you need to delete it. + int ProcessIncoming (WorldPacket* new_pct); + + /// Called by ProcessIncoming() on CMSG_AUTH_SESSION. + int HandleAuthSession (WorldPacket& recvPacket); + + /// Called by ProcessIncoming() on CMSG_PING. + int HandlePing (WorldPacket& recvPacket); + + private: + /// Time in which the last ping was received + ACE_Time_Value m_LastPingTime; + + /// Keep track of over-speed pings ,to prevent ping flood. + uint32 m_OverSpeedPings; + + /// Address of the remote peer + std::string m_Address; + + /// Class used for managing encryption of the headers + AuthCrypt m_Crypt; + + /// Mutex lock to protect m_Session + LockType m_SessionLock; + + /// Session to which received packets are routed + WorldSession* m_Session; + + /// here are stored the fragments of the received data + WorldPacket* m_RecvWPct; + + /// This block actually refers to m_RecvWPct contents, + /// which allows easy and safe writing to it. + /// It wont free memory when its deleted. m_RecvWPct takes care of freeing. + ACE_Message_Block m_RecvPct; + + /// Fragment of the received header. + ACE_Message_Block m_Header; + + /// Mutex for protecting output related data. + LockType m_OutBufferLock; + + /// Buffer used for writing output. + ACE_Message_Block *m_OutBuffer; + + /// Size of the m_OutBuffer. + size_t m_OutBufferSize; + + /// True if the socket is registered with the reactor for output + bool m_OutActive; + + uint32 m_Seed; + +}; + +#endif /* _WORLDSOCKET_H */ + +/// @} + diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp new file mode 100644 index 00000000000..c23d08e6f78 --- /dev/null +++ b/src/server/game/Server/WorldSocketMgr.cpp @@ -0,0 +1,369 @@ +/* +* Copyright (C) 2005-2008,2007 MaNGOS +* +* Copyright (C) 2008-2010 Trinity +* +* 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, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** \file WorldSocketMgr.cpp +* \ingroup u2w +* \author Derex +*/ + +#include "WorldSocketMgr.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "Log.h" +#include "Common.h" +#include "Config/ConfigEnv.h" +#include "Database/DatabaseEnv.h" +#include "WorldSocket.h" + +/** +* This is a helper class to WorldSocketMgr ,that manages +* network threads, and assigning connections from acceptor thread +* to other network threads +*/ +class ReactorRunnable : protected ACE_Task_Base +{ + public: + + ReactorRunnable() : + m_ThreadId(-1), + m_Connections(0), + m_Reactor(0) + { + ACE_Reactor_Impl* imp = 0; + + #if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) + + imp = new ACE_Dev_Poll_Reactor(); + + imp->max_notify_iterations (128); + imp->restart (1); + + #else + + imp = new ACE_TP_Reactor(); + imp->max_notify_iterations (128); + + #endif + + m_Reactor = new ACE_Reactor (imp, 1); + } + + virtual ~ReactorRunnable() + { + Stop(); + Wait(); + + if (m_Reactor) + delete m_Reactor; + } + + void Stop() + { + m_Reactor->end_reactor_event_loop(); + } + + int Start() + { + if (m_ThreadId != -1) + return -1; + + return (m_ThreadId = activate()); + } + + void Wait() { ACE_Task_Base::wait(); } + + long Connections() + { + return static_cast (m_Connections.value()); + } + + int AddSocket (WorldSocket* sock) + { + ACE_GUARD_RETURN (ACE_Thread_Mutex, Guard, m_NewSockets_Lock, -1); + + ++m_Connections; + sock->AddReference(); + sock->reactor (m_Reactor); + m_NewSockets.insert (sock); + + return 0; + } + + ACE_Reactor* GetReactor() + { + return m_Reactor; + } + + protected: + + void AddNewSockets() + { + ACE_GUARD (ACE_Thread_Mutex, Guard, m_NewSockets_Lock); + + if (m_NewSockets.empty()) + return; + + for (SocketSet::const_iterator i = m_NewSockets.begin(); i != m_NewSockets.end(); ++i) + { + WorldSocket* sock = (*i); + + if (sock->IsClosed()) + { + sock->RemoveReference(); + --m_Connections; + } + else + m_Sockets.insert (sock); + } + + m_NewSockets.clear(); + } + + virtual int svc() + { + DEBUG_LOG ("Network Thread Starting"); + + WorldDatabase.ThreadStart(); + + ACE_ASSERT (m_Reactor); + + SocketSet::iterator i, t; + + while (!m_Reactor->reactor_event_loop_done()) + { + // dont be too smart to move this outside the loop + // the run_reactor_event_loop will modify interval + ACE_Time_Value interval (0, 10000); + + if (m_Reactor->run_reactor_event_loop (interval) == -1) + break; + + AddNewSockets(); + + for (i = m_Sockets.begin(); i != m_Sockets.end();) + { + if ((*i)->Update() == -1) + { + t = i; + ++i; + (*t)->CloseSocket(); + (*t)->RemoveReference(); + --m_Connections; + m_Sockets.erase (t); + } + else + ++i; + } + } + + WorldDatabase.ThreadEnd(); + + DEBUG_LOG ("Network Thread Exitting"); + + return 0; + } + + private: + typedef ACE_Atomic_Op AtomicInt; + typedef std::set SocketSet; + + ACE_Reactor* m_Reactor; + AtomicInt m_Connections; + int m_ThreadId; + + SocketSet m_Sockets; + + SocketSet m_NewSockets; + ACE_Thread_Mutex m_NewSockets_Lock; +}; + +WorldSocketMgr::WorldSocketMgr() : + m_NetThreadsCount(0), + m_NetThreads(0), + m_SockOutKBuff(-1), + m_SockOutUBuff(65536), + m_UseNoDelay(true), + m_Acceptor (0) +{ +} + +WorldSocketMgr::~WorldSocketMgr() +{ + if (m_NetThreads) + delete [] m_NetThreads; + + if (m_Acceptor) + delete m_Acceptor; +} + +int +WorldSocketMgr::StartReactiveIO (ACE_UINT16 port, const char* address) +{ + m_UseNoDelay = sConfig.GetBoolDefault ("Network.TcpNodelay", true); + + int num_threads = sConfig.GetIntDefault ("Network.Threads", 1); + + if (num_threads <= 0) + { + sLog.outError ("Network.Threads is wrong in your config file"); + return -1; + } + + m_NetThreadsCount = static_cast (num_threads + 1); + + m_NetThreads = new ReactorRunnable[m_NetThreadsCount]; + + sLog.outBasic ("Max allowed socket connections %d", ACE::max_handles()); + + // -1 means use default + m_SockOutKBuff = sConfig.GetIntDefault ("Network.OutKBuff", -1); + + m_SockOutUBuff = sConfig.GetIntDefault ("Network.OutUBuff", 65536); + + if (m_SockOutUBuff <= 0) + { + sLog.outError ("Network.OutUBuff is wrong in your config file"); + return -1; + } + + WorldSocket::Acceptor *acc = new WorldSocket::Acceptor; + m_Acceptor = acc; + + ACE_INET_Addr listen_addr (port, address); + + if (acc->open(listen_addr, m_NetThreads[0].GetReactor(), ACE_NONBLOCK) == -1) + { + sLog.outError ("Failed to open acceptor ,check if the port is free"); + return -1; + } + + for (size_t i = 0; i < m_NetThreadsCount; ++i) + m_NetThreads[i].Start(); + + return 0; +} + +int +WorldSocketMgr::StartNetwork (ACE_UINT16 port, const char* address) +{ + if (!sLog.IsOutDebug()) + ACE_Log_Msg::instance()->priority_mask (LM_ERROR, ACE_Log_Msg::PROCESS); + + if (StartReactiveIO(port, address) == -1) + return -1; + + return 0; +} + +void +WorldSocketMgr::StopNetwork() +{ + if (m_Acceptor) + { + WorldSocket::Acceptor* acc = dynamic_cast (m_Acceptor); + + if (acc) + acc->close(); + } + + if (m_NetThreadsCount != 0) + { + for (size_t i = 0; i < m_NetThreadsCount; ++i) + m_NetThreads[i].Stop(); + } + + Wait(); +} + +void +WorldSocketMgr::Wait() +{ + if (m_NetThreadsCount != 0) + { + for (size_t i = 0; i < m_NetThreadsCount; ++i) + m_NetThreads[i].Wait(); + } +} + +int +WorldSocketMgr::OnSocketOpen (WorldSocket* sock) +{ + // set some options here + if (m_SockOutKBuff >= 0) + { + if (sock->peer().set_option (SOL_SOCKET, + SO_SNDBUF, + (void*) & m_SockOutKBuff, + sizeof (int)) == -1 && errno != ENOTSUP) + { + sLog.outError ("WorldSocketMgr::OnSocketOpen set_option SO_SNDBUF"); + return -1; + } + } + + static const int ndoption = 1; + + // Set TCP_NODELAY. + if (m_UseNoDelay) + { + if (sock->peer().set_option (ACE_IPPROTO_TCP, + TCP_NODELAY, + (void*)&ndoption, + sizeof (int)) == -1) + { + sLog.outError ("WorldSocketMgr::OnSocketOpen: peer().set_option TCP_NODELAY errno = %s", ACE_OS::strerror (errno)); + return -1; + } + } + + sock->m_OutBufferSize = static_cast (m_SockOutUBuff); + + // we skip the Acceptor Thread + size_t min = 1; + + ACE_ASSERT (m_NetThreadsCount >= 1); + + for (size_t i = 1; i < m_NetThreadsCount; ++i) + if (m_NetThreads[i].Connections() < m_NetThreads[min].Connections()) + min = i; + + return m_NetThreads[min].AddSocket (sock); +} + +WorldSocketMgr* +WorldSocketMgr::Instance() +{ + return ACE_Singleton::instance(); +} + diff --git a/src/server/game/Server/WorldSocketMgr.h b/src/server/game/Server/WorldSocketMgr.h new file mode 100644 index 00000000000..11345304962 --- /dev/null +++ b/src/server/game/Server/WorldSocketMgr.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * Copyright (C) 2008-2010 Trinity + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** \addtogroup u2w User to World Communication + * @{ + * \file WorldSocketMgr.h + * \author Derex + */ + +#ifndef __WORLDSOCKETMGR_H +#define __WORLDSOCKETMGR_H + +#include +#include +#include + +class WorldSocket; +class ReactorRunnable; +class ACE_Event_Handler; + +/// Manages all sockets connected to peers and network threads +class WorldSocketMgr +{ +public: + friend class WorldSocket; + friend class ACE_Singleton; + + /// Start network, listen at address:port . + int StartNetwork (ACE_UINT16 port, const char* address); + + /// Stops all network threads, It will wait for all running threads . + void StopNetwork(); + + /// Wait untill all network threads have "joined" . + void Wait(); + + /// Make this class singleton . + static WorldSocketMgr* Instance(); + +private: + int OnSocketOpen(WorldSocket* sock); + + int StartReactiveIO(ACE_UINT16 port, const char* address); + +private: + WorldSocketMgr(); + virtual ~WorldSocketMgr(); + + ReactorRunnable* m_NetThreads; + size_t m_NetThreadsCount; + + int m_SockOutKBuff; + int m_SockOutUBuff; + bool m_UseNoDelay; + + ACE_Event_Handler* m_Acceptor; +}; + +#define sWorldSocketMgr WorldSocketMgr::Instance() + +#endif +/// @} + diff --git a/src/server/game/Skills/SkillHandler.cpp b/src/server/game/Skills/SkillHandler.cpp deleted file mode 100644 index 312065f9f13..00000000000 --- a/src/server/game/Skills/SkillHandler.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "Opcodes.h" -#include "Log.h" -#include "Player.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "ObjectAccessor.h" -#include "UpdateMask.h" - -void WorldSession::HandleLearnTalentOpcode(WorldPacket & recv_data) -{ - uint32 talent_id, requested_rank; - recv_data >> talent_id >> requested_rank; - - _player->LearnTalent(talent_id, requested_rank); - _player->SendTalentsInfoData(false); -} - -void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket) -{ - sLog.outDebug("CMSG_LEARN_PREVIEW_TALENTS"); - - uint32 talentsCount; - recvPacket >> talentsCount; - - uint32 talentId, talentRank; - - for (uint32 i = 0; i < talentsCount; ++i) - { - recvPacket >> talentId >> talentRank; - - _player->LearnTalent(talentId, talentRank); - } - - _player->SendTalentsInfoData(false); -} - -void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket & recv_data) -{ - sLog.outDetail("MSG_TALENT_WIPE_CONFIRM"); - uint64 guid; - recv_data >> guid; - - Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_TRAINER); - if (!unit) - { - sLog.outDebug("WORLD: HandleTalentWipeConfirmOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - if (!(_player->resetTalents())) - { - WorldPacket data(MSG_TALENT_WIPE_CONFIRM, 8+4); //you have not any talent - data << uint64(0); - data << uint32(0); - SendPacket(&data); - return; - } - - _player->SendTalentsInfoData(false); - unit->CastSpell(_player, 14867, true); //spell: "Untalent Visual Effect" -} - -void WorldSession::HandleUnlearnSkillOpcode(WorldPacket & recv_data) -{ - uint32 skill_id; - recv_data >> skill_id; - GetPlayer()->SetSkill(skill_id, 0, 0, 0); -} - diff --git a/src/server/game/Spells/SpellHandler.cpp b/src/server/game/Spells/SpellHandler.cpp deleted file mode 100644 index b8a4a127824..00000000000 --- a/src/server/game/Spells/SpellHandler.cpp +++ /dev/null @@ -1,649 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "Common.h" -#include "DBCStores.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "Log.h" -#include "Opcodes.h" -#include "Spell.h" -#include "Totem.h" -#include "TemporarySummon.h" -#include "SpellAuras.h" -#include "CreatureAI.h" -#include "ScriptMgr.h" - -void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) -{ - // TODO: add targets.read() check - Player* pUser = _player; - - // ignore for remote control state - if (pUser->m_mover != pUser) - return; - - uint8 bagIndex, slot; - uint8 unk_flags; // flags (if 0x02 - some additional data are received) - uint8 cast_count; // next cast if exists (single or not) - uint64 item_guid; - uint32 glyphIndex; // something to do with glyphs? - uint32 spellid; // casted spell id - - recvPacket >> bagIndex >> slot >> cast_count >> spellid >> item_guid >> glyphIndex >> unk_flags; - - if (glyphIndex >= MAX_GLYPH_SLOT_INDEX) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - Item *pItem = pUser->GetUseableItemByPos(bagIndex, slot); - if (!pItem) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - if (pItem->GetGUID() != item_guid) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - sLog.outDetail("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, cast_count: %u, spellid: %u, Item: %u, glyphIndex: %u, unk_flags: %u, data length = %i", bagIndex, slot, cast_count, spellid, pItem->GetEntry(), glyphIndex, unk_flags, (uint32)recvPacket.size()); - - ItemPrototype const *proto = pItem->GetProto(); - if (!proto) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); - return; - } - - // some item classes can be used only in equipped state - if (proto->InventoryType != INVTYPE_NON_EQUIP && !pItem->IsEquipped()) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); - return; - } - - uint8 msg = pUser->CanUseItem(pItem); - if (msg != EQUIP_ERR_OK) - { - pUser->SendEquipError(msg, pItem, NULL); - return; - } - - // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB) - if (proto->Class == ITEM_CLASS_CONSUMABLE && !(proto->Flags & ITEM_FLAGS_USEABLE_IN_ARENA) && pUser->InArena()) - { - pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH,pItem,NULL); - return; - } - - if (pUser->isInCombat()) - { - for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) - { - if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId)) - { - if (IsNonCombatSpell(spellInfo)) - { - pUser->SendEquipError(EQUIP_ERR_NOT_IN_COMBAT,pItem,NULL); - return; - } - } - } - } - - // check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory) - if (pItem->GetProto()->Bonding == BIND_WHEN_USE || pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetProto()->Bonding == BIND_QUEST_ITEM) - { - if (!pItem->IsSoulBound()) - { - pItem->SetState(ITEM_CHANGED, pUser); - pItem->SetBinding(true); - } - } - - SpellCastTargets targets; - if (!targets.read(&recvPacket, pUser)) - return; - - targets.Update(pUser); - - if (!pItem->IsTargetValidForItemUse(targets.getUnitTarget())) - { - // free gray item after use fail - pUser->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); - - // send spell error - if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid)) - { - // for implicit area/coord target spells - if (!targets.getUnitTarget()) - Spell::SendCastResult(_player,spellInfo,cast_count,SPELL_FAILED_NO_VALID_TARGETS); - // for explicit target spells - else - Spell::SendCastResult(_player,spellInfo,cast_count,SPELL_FAILED_BAD_TARGETS); - } - return; - } - - //Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state. - if (!sScriptMgr.ItemUse(pUser,pItem,targets)) - { - // no script or script not process request by self - pUser->CastItemUseSpell(pItem,targets,cast_count,glyphIndex); - } -} - -#define OPEN_CHEST 11437 -#define OPEN_SAFE 11535 -#define OPEN_CAGE 11792 -#define OPEN_BOOTY_CHEST 5107 -#define OPEN_STRONGBOX 8517 - -void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket) -{ - sLog.outDetail("WORLD: CMSG_OPEN_ITEM packet, data length = %i",(uint32)recvPacket.size()); - - Player* pUser = _player; - - // ignore for remote control state - if (pUser->m_mover != pUser) - return; - - uint8 bagIndex, slot; - - recvPacket >> bagIndex >> slot; - - sLog.outDetail("bagIndex: %u, slot: %u",bagIndex,slot); - - Item *pItem = pUser->GetItemByPos(bagIndex, slot); - if (!pItem) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - ItemPrototype const *proto = pItem->GetProto(); - if (!proto) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); - return; - } - - if (!pUser->GetSession()->HandleOnItemOpen(pItem)) - return; - - // locked item - uint32 lockId = proto->LockID; - if (lockId) - { - LockEntry const *lockInfo = sLockStore.LookupEntry(lockId); - - if (!lockInfo) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL); - sLog.outError("WORLD::OpenItem: item [guid = %u] has an unknown lockId: %u!", pItem->GetGUIDLow(), lockId); - return; - } - - // required picklocking - if (lockInfo->Skill[1] || lockInfo->Skill[0]) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL); - return; - } - } - - if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED))// wrapped? - { - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT entry, flags FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow()); - if (result) - { - Field *fields = result->Fetch(); - uint32 entry = fields[0].GetUInt32(); - uint32 flags = fields[1].GetUInt32(); - - pItem->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, 0); - pItem->SetEntry(entry); - pItem->SetUInt32Value(ITEM_FIELD_FLAGS, flags); - pItem->SetState(ITEM_CHANGED, pUser); - } - else - { - sLog.outError("Wrapped item %u don't have record in character_gifts table and will deleted", pItem->GetGUIDLow()); - pUser->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); - return; - } - CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow()); - } - else - pUser->SendLoot(pItem->GetGUID(),LOOT_CORPSE); -} - -void WorldSession::HandleGameObjectUseOpcode(WorldPacket & recv_data) -{ - uint64 guid; - - recv_data >> guid; - - sLog.outDebug("WORLD: Recvd CMSG_GAMEOBJ_USE Message [guid=%u]", GUID_LOPART(guid)); - - // ignore for remote control state - if (_player->m_mover != _player) - return; - - GameObject *obj = GetPlayer()->GetMap()->GetGameObject(guid); - - if (!obj) - return; - - if (sScriptMgr.GOHello(_player, obj)) - return; - - obj->Use(_player); -} - -void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket) -{ - uint64 guid; - recvPacket >> guid; - - sLog.outDebug("WORLD: Recvd CMSG_GAMEOBJ_REPORT_USE Message [in game guid: %u]", GUID_LOPART(guid)); - - // ignore for remote control state - if (_player->m_mover != _player) - return; - - GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid); - if (!go) - return; - - if (!go->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) - return; - - _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry()); -} - -void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) -{ - uint32 spellId; - uint8 cast_count, unk_flags; - recvPacket >> cast_count; - recvPacket >> spellId; - recvPacket >> unk_flags; // flags (if 0x02 - some additional data are received) - - // ignore for remote control state (for player case) - Unit* mover = _player->m_mover; - if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER) - { - recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet - return; - } - - sLog.outDebug("WORLD: got cast spell packet, spellId - %u, cast_count: %u, unk_flags %u, data length = %i", spellId, cast_count, unk_flags, (uint32)recvPacket.size()); - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); - - if (!spellInfo) - { - sLog.outError("WORLD: unknown spell id %u", spellId); - recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet - return; - } - - if (mover->GetTypeId() == TYPEID_PLAYER) - { - // not have spell in spellbook or spell passive and not casted by client - if (!mover->ToPlayer()->HasActiveSpell (spellId) || IsPassiveSpell(spellId)) - { - //cheater? kick? ban? - recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet - return; - } - } - else - { - // not have spell in spellbook or spell passive and not casted by client - if ((mover->GetTypeId() == TYPEID_UNIT && !mover->ToCreature()->HasSpell(spellId)) || IsPassiveSpell(spellId)) - { - //cheater? kick? ban? - recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet - return; - } - } - - // Client is resending autoshot cast opcode when other spell is casted during shoot rotation - // Skip it to prevent "interrupt" message - if (IsAutoRepeatRangedSpell(spellInfo) && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) - && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_spellInfo == spellInfo) - return; - - // can't use our own spells when we're in possession of another unit, - if (_player->isPossessing()) - return; - - // client provided targets - SpellCastTargets targets; - if (!targets.read(&recvPacket,mover)) - { - recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet - return; - } - - // some spell cast packet including more data (for projectiles?) - if (unk_flags & 0x02) - { - //recvPacket.read_skip(); // unk1, coords? - //recvPacket.read_skip(); // unk1, coords? - uint8 unk1; - recvPacket >> unk1; // >> 1 or 0 - if (unk1) - { - recvPacket.read_skip(); // >> MSG_MOVE_STOP - uint64 guid; // guid - unused - if (!recvPacket.readPackGUID(guid)) - return; - - MovementInfo movementInfo; - ReadMovementInfo(recvPacket, &movementInfo); - } - } - - // auto-selection buff level base at target level (in spellInfo) - if (targets.getUnitTarget()) - { - SpellEntry const *actualSpellInfo = spellmgr.SelectAuraRankForPlayerLevel(spellInfo,targets.getUnitTarget()->getLevel()); - - // if rank not found then function return NULL but in explicit cast case original spell can be casted and later failed with appropriate error message - if (actualSpellInfo) - spellInfo = actualSpellInfo; - } - - Spell *spell = new Spell(mover, spellInfo, false); - spell->m_cast_count = cast_count; // set count of casts - spell->prepare(&targets); -} - -void WorldSession::HandleCancelCastOpcode(WorldPacket& recvPacket) -{ - uint32 spellId; - - recvPacket.read_skip(); // counter, increments with every CANCEL packet, don't use for now - recvPacket >> spellId; - - if (_player->IsNonMeleeSpellCasted(false)) - _player->InterruptNonMeleeSpells(false,spellId,false); -} - -void WorldSession::HandleCancelAuraOpcode(WorldPacket& recvPacket) -{ - uint32 spellId; - recvPacket >> spellId; - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); - if (!spellInfo) - return; - - // not allow remove non positive spells and spells with attr SPELL_ATTR_CANT_CANCEL - if (!IsPositiveSpell(spellId) || (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL)) - return; - - // channeled spell case (it currently casted then) - if (IsChanneledSpell(spellInfo)) - { - if (Spell* curSpell = _player->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) - if (curSpell->m_spellInfo->Id == spellId) - _player->InterruptSpell(CURRENT_CHANNELED_SPELL); - return; - } - - // non channeled case - // maybe should only remove one buff when there are multiple? - _player->RemoveOwnedAura(spellId, 0, 0, AURA_REMOVE_BY_CANCEL); -} - -void WorldSession::HandlePetCancelAuraOpcode(WorldPacket& recvPacket) -{ - uint64 guid; - uint32 spellId; - - recvPacket >> guid; - recvPacket >> spellId; - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); - if (!spellInfo) - { - sLog.outError("WORLD: unknown PET spell id %u", spellId); - return; - } - - Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player,guid); - - if (!pet) - { - sLog.outError("Pet %u not exist.", uint32(GUID_LOPART(guid))); - return; - } - - if (pet != GetPlayer()->GetGuardianPet() && pet != GetPlayer()->GetCharm()) - { - sLog.outError("HandlePetCancelAura.Pet %u isn't pet of player %s", uint32(GUID_LOPART(guid)),GetPlayer()->GetName()); - return; - } - - if (!pet->isAlive()) - { - pet->SendPetActionFeedback(FEEDBACK_PET_DEAD); - return; - } - - pet->RemoveOwnedAura(spellId, 0, 0, AURA_REMOVE_BY_CANCEL); - - pet->AddCreatureSpellCooldown(spellId); -} - -void WorldSession::HandleCancelGrowthAuraOpcode(WorldPacket& /*recvPacket*/) -{ -} - -void WorldSession::HandleCancelAutoRepeatSpellOpcode(WorldPacket& /*recvPacket*/) -{ - // may be better send SMSG_CANCEL_AUTO_REPEAT? - // cancel and prepare for deleting - _player->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); -} - -void WorldSession::HandleCancelChanneling(WorldPacket & recv_data) -{ - recv_data.read_skip(); // spellid, not used - - // ignore for remote control state (for player case) - Unit* mover = _player->m_mover; - if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER) - return; - - mover->InterruptSpell(CURRENT_CHANNELED_SPELL); -} - -void WorldSession::HandleTotemDestroyed(WorldPacket& recvPacket) -{ - // ignore for remote control state - if (_player->m_mover != _player) - return; - - uint8 slotId; - - recvPacket >> slotId; - - ++slotId; - if (slotId >= MAX_TOTEM_SLOT) - return; - - if (!_player->m_SummonSlot[slotId]) - return; - - Creature* totem = GetPlayer()->GetMap()->GetCreature(_player->m_SummonSlot[slotId]); - // Don't unsummon sentry totem - if (totem && totem->isTotem() && totem->GetEntry() != SENTRY_TOTEM_ENTRY) - totem->ToTotem()->UnSummon(); -} - -void WorldSession::HandleSelfResOpcode(WorldPacket & /*recv_data*/) -{ - sLog.outDebug("WORLD: CMSG_SELF_RES"); // empty opcode - - if (_player->GetUInt32Value(PLAYER_SELF_RES_SPELL)) - { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(_player->GetUInt32Value(PLAYER_SELF_RES_SPELL)); - if (spellInfo) - _player->CastSpell(_player,spellInfo,false,0); - - _player->SetUInt32Value(PLAYER_SELF_RES_SPELL, 0); - } -} - -void WorldSession::HandleSpellClick(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - - // this will get something not in world. crash - Creature *unit = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); - - if (!unit) - return; - - // TODO: Unit::SetCharmedBy: 28782 is not in world but 0 is trying to charm it! -> crash - if (!unit->IsInWorld()) - { - sLog.outCrash("Spell click target %u is not in world!", unit->GetEntry()); - assert(false); - return; - } - - SpellClickInfoMapBounds clickPair = objmgr.GetSpellClickInfoMapBounds(unit->GetEntry()); - for (SpellClickInfoMap::const_iterator itr = clickPair.first; itr != clickPair.second; ++itr) - { - if (itr->second.IsFitToRequirements(_player, unit)) - { - Unit *caster = (itr->second.castFlags & NPC_CLICK_CAST_CASTER_PLAYER) ? (Unit*)_player : (Unit*)unit; - Unit *target = (itr->second.castFlags & NPC_CLICK_CAST_TARGET_PLAYER) ? (Unit*)_player : (Unit*)unit; - uint64 origCasterGUID = (itr->second.castFlags & NPC_CLICK_CAST_ORIG_CASTER_OWNER) ? unit->GetOwnerGUID() : 0; - caster->CastSpell(target, itr->second.spellId, true, NULL, NULL, origCasterGUID); - } - } - - if (unit->IsVehicle()) - { - if (unit->CheckPlayerCondition(_player)) - _player->EnterVehicle(unit); - } - - unit->AI()->DoAction(EVENT_SPELLCLICK); -} - -void WorldSession::HandleMirrrorImageDataRequest(WorldPacket & recv_data) -{ - sLog.outDebug("WORLD: CMSG_GET_MIRRORIMAGE_DATA"); - uint64 guid; - recv_data >> guid; - - // Get unit for which data is needed by client - Unit *unit = ObjectAccessor::GetObjectInWorld(guid, (Unit*)NULL); - if (!unit) - return; - - // Get creator of the unit - Unit *creator = ObjectAccessor::GetObjectInWorld(unit->GetCreatorGUID(),(Unit*)NULL); - if (!creator) - return; - - WorldPacket data(SMSG_MIRRORIMAGE_DATA, 68); - data << uint64(guid); - data << uint32(creator->GetDisplayId()); - if (creator->GetTypeId() == TYPEID_PLAYER) - { - Player * pCreator = creator->ToPlayer(); - data << uint8(pCreator->getRace()); - data << uint8(pCreator->getGender()); - data << uint8(pCreator->getClass()); - data << uint8(pCreator->GetByteValue(PLAYER_BYTES, 0)); // skin - data << uint8(pCreator->GetByteValue(PLAYER_BYTES, 1)); // face - data << uint8(pCreator->GetByteValue(PLAYER_BYTES, 2)); // hair - data << uint8(pCreator->GetByteValue(PLAYER_BYTES, 3)); // haircolor - data << uint8(pCreator->GetByteValue(PLAYER_BYTES_2, 0)); // facialhair - data << uint32(pCreator->GetGuildId()); // unk - - static const EquipmentSlots ItemSlots[] = - { - EQUIPMENT_SLOT_HEAD, - EQUIPMENT_SLOT_SHOULDERS, - EQUIPMENT_SLOT_BODY, - EQUIPMENT_SLOT_CHEST, - EQUIPMENT_SLOT_WAIST, - EQUIPMENT_SLOT_LEGS, - EQUIPMENT_SLOT_FEET, - EQUIPMENT_SLOT_WRISTS, - EQUIPMENT_SLOT_HANDS, - EQUIPMENT_SLOT_BACK, - EQUIPMENT_SLOT_TABARD, - EQUIPMENT_SLOT_END - }; - - // Display items in visible slots - for (EquipmentSlots const* itr = &ItemSlots[0]; *itr != EQUIPMENT_SLOT_END; ++itr) - { - if (*itr == EQUIPMENT_SLOT_HEAD && pCreator->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM)) - data << uint32(0); - else if (*itr == EQUIPMENT_SLOT_BACK && pCreator->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK)) - data << uint32(0); - else if (Item const *item = pCreator->GetItemByPos(INVENTORY_SLOT_BAG_0, *itr)) - data << uint32(item->GetProto()->DisplayInfoID); - else - data << uint32(0); - } - } - else - { - // Skip player data for creatures - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - } - - SendPacket(&data); -} diff --git a/src/server/game/World/WorldLog.cpp b/src/server/game/World/WorldLog.cpp deleted file mode 100644 index 7c6c4020336..00000000000 --- a/src/server/game/World/WorldLog.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** \file - \ingroup u2w -*/ - -#include "WorldLog.h" -#include "Policies/SingletonImp.h" -#include "Config/ConfigEnv.h" -#include "Log.h" - -#define CLASS_LOCK Trinity::ClassLevelLockable -INSTANTIATE_SINGLETON_2(WorldLog, CLASS_LOCK); -INSTANTIATE_CLASS_MUTEX(WorldLog, ACE_Thread_Mutex); - -WorldLog::WorldLog() : i_file(NULL) -{ - Initialize(); -} - -WorldLog::~WorldLog() -{ - if (i_file != NULL) - fclose(i_file); - i_file = NULL; -} - -/// Open the log file (if specified so in the configuration file) -void WorldLog::Initialize() -{ - std::string logsDir = sConfig.GetStringDefault("LogsDir",""); - - if (!logsDir.empty()) - { - if ((logsDir.at(logsDir.length()-1) != '/') && (logsDir.at(logsDir.length()-1) != '\\')) - logsDir.append("/"); - } - - std::string logname = sConfig.GetStringDefault("WorldLogFile", ""); - if (!logname.empty()) - { - i_file = fopen((logsDir+logname).c_str(), "w"); - } - - m_dbWorld = sConfig.GetBoolDefault("LogDB.World", false); // can be VERY heavy if enabled -} - -void WorldLog::outTimestampLog(char const *fmt, ...) -{ - if (LogWorld()) - { - Guard guard(*this); - ASSERT(i_file); - - Log::outTimestamp(i_file); - va_list args; - va_start(args, fmt); - vfprintf(i_file, fmt, args); - //fprintf(i_file, "\n"); - va_end(args); - - fflush(i_file); - } - - if (sLog.GetLogDB() && m_dbWorld) - { - va_list ap2; - va_start(ap2, fmt); - char nnew_str[MAX_QUERY_LEN]; - vsnprintf(nnew_str, MAX_QUERY_LEN, fmt, ap2); - sLog.outDB(LOG_TYPE_WORLD, nnew_str); - va_end(ap2); - } -} - -void WorldLog::outLog(char const *fmt, ...) -{ - if (LogWorld()) - { - Guard guard(*this); - ASSERT(i_file); - - va_list args; - va_start(args, fmt); - vfprintf(i_file, fmt, args); - //fprintf(i_file, "\n"); - va_end(args); - - fflush(i_file); - } - - if (sLog.GetLogDB() && m_dbWorld) - { - va_list ap2; - va_start(ap2, fmt); - char nnew_str[MAX_QUERY_LEN]; - vsnprintf(nnew_str, MAX_QUERY_LEN, fmt, ap2); - sLog.outDB(LOG_TYPE_WORLD, nnew_str); - va_end(ap2); - } -} - -#define sWorldLog WorldLog::Instance() - diff --git a/src/server/game/World/WorldLog.h b/src/server/game/World/WorldLog.h deleted file mode 100644 index 4ee9bb178ec..00000000000 --- a/src/server/game/World/WorldLog.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/// \addtogroup u2w -/// @{ -/// \file - -#ifndef TRINITY_WORLDLOG_H -#define TRINITY_WORLDLOG_H - -#include "Common.h" -#include "Policies/Singleton.h" -#include "Errors.h" - -#include - -/// %Log packets to a file -class WorldLog : public Trinity::Singleton > -{ - friend class Trinity::OperatorNew; - WorldLog(); - WorldLog(const WorldLog &); - WorldLog& operator=(const WorldLog &); - typedef Trinity::ClassLevelLockable::Lock Guard; - - /// Close the file in destructor - ~WorldLog(); - - public: - void Initialize(); - /// Is the world logger active? - bool LogWorld(void) const { return (i_file != NULL); } - /// %Log to the file - void outLog(char const *fmt, ...); - void outTimestampLog(char const *fmt, ...); - - private: - FILE *i_file; - - bool m_dbWorld; -}; - -#define sWorldLog WorldLog::Instance() -#endif -/// @} - diff --git a/src/server/game/World/WorldSession.cpp b/src/server/game/World/WorldSession.cpp deleted file mode 100644 index bc737717840..00000000000 --- a/src/server/game/World/WorldSession.cpp +++ /dev/null @@ -1,959 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** \file - \ingroup u2w -*/ - -#include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "Log.h" -#include "Opcodes.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Player.h" -#include "Vehicle.h" -#include "ObjectMgr.h" -#include "Group.h" -#include "Guild.h" -#include "World.h" -#include "ObjectAccessor.h" -#include "BattleGroundMgr.h" -#include "OutdoorPvPMgr.h" -#include "MapManager.h" -#include "SocialMgr.h" -#include "zlib/zlib.h" -#include "ScriptMgr.h" -#include "LFGMgr.h" - -/// WorldSession constructor -WorldSession::WorldSession(uint32 id, WorldSocket *sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale) : -LookingForGroup_auto_join(false), LookingForGroup_auto_add(false), m_muteTime(mute_time), -_player(NULL), m_Socket(sock),_security(sec), _accountId(id), m_expansion(expansion), -m_sessionDbcLocale(sWorld.GetAvailableDbcLocale(locale)), m_sessionDbLocaleIndex(objmgr.GetIndexForLocale(locale)), -_logoutTime(0), m_inQueue(false), m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), m_playerSave(false), -m_latency(0), m_TutorialsChanged(false), m_timeOutTime(0) -{ - if (sock) - { - m_Address = sock->GetRemoteAddress (); - sock->AddReference (); - ResetTimeOutTime(); - LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = %u;", GetAccountId()); - } -} - -/// WorldSession destructor -WorldSession::~WorldSession() -{ - ///- unload player if not unloaded - if (_player) - LogoutPlayer (true); - - /// - If have unclosed socket, close it - if (m_Socket) - { - m_Socket->CloseSocket (); - m_Socket->RemoveReference (); - m_Socket = NULL; - } - - ///- empty incoming packet queue - WorldPacket* packet; - while (_recvQueue.next(packet)) - delete packet; - - LoginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = %u;", GetAccountId()); - CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = %u;", GetAccountId()); -} - -void WorldSession::SizeError(WorldPacket const& packet, uint32 size) const -{ - sLog.outError("Client (account %u) send packet %s (%u) with size " SIZEFMTD " but expected %u (attempt crash server?), skipped", - GetAccountId(),LookupOpcodeName(packet.GetOpcode()),packet.GetOpcode(),packet.size(),size); -} - -/// Get the player name -char const* WorldSession::GetPlayerName() const -{ - return GetPlayer() ? GetPlayer()->GetName() : ""; -} - -/// Send a packet to the client -void WorldSession::SendPacket(WorldPacket const* packet) -{ - if (!m_Socket) - return; - - #ifdef TRINITY_DEBUG - - // Code for network use statistic - static uint64 sendPacketCount = 0; - static uint64 sendPacketBytes = 0; - - static time_t firstTime = time(NULL); - static time_t lastTime = firstTime; // next 60 secs start time - - static uint64 sendLastPacketCount = 0; - static uint64 sendLastPacketBytes = 0; - - time_t cur_time = time(NULL); - - if ((cur_time - lastTime) < 60) - { - sendPacketCount+=1; - sendPacketBytes+=packet->size(); - - sendLastPacketCount+=1; - sendLastPacketBytes+=packet->size(); - } - else - { - uint64 minTime = uint64(cur_time - lastTime); - uint64 fullTime = uint64(lastTime - firstTime); - sLog.outDetail("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)); - sLog.outDetail("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; - sendLastPacketBytes = packet->wpos(); // wpos is real written size - } - - #endif // !TRINITY_DEBUG - - if (m_Socket->SendPacket (*packet) == -1) - m_Socket->CloseSocket (); -} - -/// Add an incoming packet to the queue -void WorldSession::QueuePacket(WorldPacket* new_packet) -{ - _recvQueue.add(new_packet); -} - -/// Logging helper for unexpected opcodes -void WorldSession::LogUnexpectedOpcode(WorldPacket* packet, const char *reason) -{ - sLog.outError("SESSION: received unexpected opcode %s (0x%.4X) %s", - LookupOpcodeName(packet->GetOpcode()), - packet->GetOpcode(), - reason); -} - -/// Logging helper for unexpected opcodes -void WorldSession::LogUnprocessedTail(WorldPacket *packet) -{ - sLog.outError("SESSION: opcode %s (0x%.4X) have unprocessed tail data (read stop at %u from %u)", - LookupOpcodeName(packet->GetOpcode()), - packet->GetOpcode(), - packet->rpos(),packet->wpos()); - - packet->print_storage(); -} - -/// Update the WorldSession (triggered by World update) -bool WorldSession::Update(uint32 diff) -{ - /// Update Timeout timer. - UpdateTimeOutTime(diff); - - ///- Before we process anything: - /// If necessary, kick the player from the character select screen - if (IsConnectionIdle()) - m_Socket->CloseSocket(); - - ///- Retrieve packets from the receive queue and call the appropriate handlers - /// not proccess packets if socket already closed - WorldPacket* packet; - while (m_Socket && !m_Socket->IsClosed() && _recvQueue.next(packet)) - { - /*#if 1 - sLog.outError("MOEP: %s (0x%.4X)", - LookupOpcodeName(packet->GetOpcode()), - packet->GetOpcode()); - #endif*/ - - if (packet->GetOpcode() >= NUM_MSG_TYPES) - { - sLog.outError("SESSION: received non-existed opcode %s (0x%.4X)", - LookupOpcodeName(packet->GetOpcode()), - packet->GetOpcode()); - } - else - { - OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()]; - try - { - switch (opHandle.status) - { - case STATUS_LOGGEDIN: - if (!_player) - { - // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets - if (!m_playerRecentlyLogout) - LogUnexpectedOpcode(packet, "the player has not logged in yet"); - } - else if (_player->IsInWorld()) - { - (this->*opHandle.handler)(*packet); - if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) - LogUnprocessedTail(packet); - } - // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer - break; - case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT: - if (!_player && !m_playerRecentlyLogout) - { - LogUnexpectedOpcode(packet, "the player has not logged in yet and not recently logout"); - } - else - { - // not expected _player or must checked in packet hanlder - (this->*opHandle.handler)(*packet); - if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) - LogUnprocessedTail(packet); - } - break; - case STATUS_TRANSFER: - if (!_player) - LogUnexpectedOpcode(packet, "the player has not logged in yet"); - else if (_player->IsInWorld()) - LogUnexpectedOpcode(packet, "the player is still in world"); - else - { - (this->*opHandle.handler)(*packet); - if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) - LogUnprocessedTail(packet); - } - break; - case STATUS_AUTHED: - // prevent cheating with skip queue wait - if (m_inQueue) - { - LogUnexpectedOpcode(packet, "the player not pass queue yet"); - break; - } - - // single from authed time opcodes send in to after logout time - // and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes. - if (packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL) - m_playerRecentlyLogout = false; - - (this->*opHandle.handler)(*packet); - if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) - LogUnprocessedTail(packet); - break; - case STATUS_NEVER: - /* - sLog.outError("SESSION: received not allowed opcode %s (0x%.4X)", - LookupOpcodeName(packet->GetOpcode()), - packet->GetOpcode()); - */ - break; - } - } - catch(ByteBufferException &) - { - sLog.outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", - packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); - if (sLog.IsOutDebug()) - { - sLog.outDebug("Dumping error causing packet:"); - packet->hexlike(); - } - } - } - - delete packet; - } - - time_t currTime = time(NULL); - ///- If necessary, log the player out - if (ShouldLogOut(currTime) && !m_playerLoading) - LogoutPlayer(true); - - ///- Cleanup socket pointer if need - if (m_Socket && m_Socket->IsClosed()) - { - m_Socket->RemoveReference(); - m_Socket = NULL; - } - - if (!m_Socket) - return false; //Will remove this session from the world session map - - return true; -} - -/// %Log the player out -void WorldSession::LogoutPlayer(bool Save) -{ - // finish pending transfers before starting the logout - while (_player && _player->IsBeingTeleportedFar()) - HandleMoveWorldportAckOpcode(); - - m_playerLogout = true; - m_playerSave = Save; - - if (_player) - { - sLFGMgr.Leave(_player); - GetPlayer()->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); - GetPlayer()->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); - GetPlayer()->GetSession()->SendLfgUpdateSearch(false); - - if (uint64 lguid = GetPlayer()->GetLootGUID()) - DoLootRelease(lguid); - - ///- If the player just died before logging out, make him appear as a ghost - //FIXME: logout must be delayed in case lost connection with client in time of combat - if (_player->GetDeathTimer()) - { - _player->getHostileRefManager().deleteReferences(); - _player->BuildPlayerRepop(); - _player->RepopAtGraveyard(); - } - else if (!_player->getAttackers().empty()) - { - _player->CombatStop(); - _player->getHostileRefManager().setOnlineOfflineState(false); - _player->RemoveAllAurasOnDeath(); - - // build set of player who attack _player or who have pet attacking of _player - std::set aset; - for (Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr) - { - Unit* owner = (*itr)->GetOwner(); // including player controlled case - if (owner) - { - if (owner->GetTypeId() == TYPEID_PLAYER) - aset.insert(owner->ToPlayer()); - } - else - if ((*itr)->GetTypeId() == TYPEID_PLAYER) - aset.insert((Player*)(*itr)); - } - - _player->SetPvPDeath(!aset.empty()); - _player->KillPlayer(); - _player->BuildPlayerRepop(); - _player->RepopAtGraveyard(); - - // give honor to all attackers from set like group case - for (std::set::const_iterator itr = aset.begin(); itr != aset.end(); ++itr) - (*itr)->RewardHonor(_player,aset.size()); - - // give bg rewards and update counters like kill by first from attackers - // this can't be called for all attackers. - if (!aset.empty()) - if (BattleGround *bg = _player->GetBattleGround()) - bg->HandleKillPlayer(_player,*aset.begin()); - } - else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) - { - // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION - _player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); - //_player->SetDeathPvP(*); set at SPELL_AURA_SPIRIT_OF_REDEMPTION apply time - _player->KillPlayer(); - _player->BuildPlayerRepop(); - _player->RepopAtGraveyard(); - } - //drop a flag if player is carrying it - if (BattleGround *bg = _player->GetBattleGround()) - bg->EventPlayerLoggedOut(_player); - - ///- Teleport to home if the player is in an invalid instance - if (!_player->m_InstanceValid && !_player->isGameMaster()) - _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation()); - - sOutdoorPvPMgr.HandlePlayerLeaveZone(_player,_player->GetZoneId()); - - for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) - { - if (BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i)) - { - _player->RemoveBattleGroundQueueId(bgQueueTypeId); - sBattleGroundMgr.m_BattleGroundQueues[ bgQueueTypeId ].RemovePlayer(_player->GetGUID(), true); - } - } - - // Repop at GraveYard or other player far teleport will prevent saving player because of not present map - // Teleport player immediately for correct player save - while (_player->IsBeingTeleportedFar()) - HandleMoveWorldportAckOpcode(); - - ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members - Guild *guild = objmgr.GetGuildById(_player->GetGuildId()); - if (guild) - { - guild->SetMemberStats(_player->GetGUID()); - guild->UpdateLogoutTime(_player->GetGUID()); - - guild->BroadcastEvent(GE_SIGNED_OFF, _player->GetGUID(), 1, _player->GetName(), "", ""); - } - - ///- Remove pet - _player->RemovePet(NULL,PET_SAVE_AS_CURRENT, true); - - ///- empty buyback items and save the player in the database - // some save parts only correctly work in case player present in map/player_lists (pets, etc) - if (Save) - { - uint32 eslot; - for (int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; ++j) - { - eslot = j - BUYBACK_SLOT_START; - _player->SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), 0); - _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0); - _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0); - } - _player->SaveToDB(); - } - - ///- Leave all channels before player delete... - _player->CleanupChannels(); - - ///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group. - _player->UninviteFromGroup(); - - // remove player from the group if he is: - // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) - if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket) - _player->RemoveFromGroup(); - - ///- Send update to group and reset stored max enchanting level - if (_player->GetGroup()) - { - _player->GetGroup()->SendUpdate(); - _player->GetGroup()->ResetMaxEnchantingLevel(); - } - - ///- Broadcast a logout message to the player's friends - sSocialMgr.SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true); - sSocialMgr.RemovePlayerSocial (_player->GetGUIDLow ()); - - ///- Remove the player from the world - // the player may not be in the world when logging out - // e.g if he got disconnected during a transfer to another map - // calls to GetMap in this case may cause crashes - _player->CleanupsBeforeDelete(); - sLog.outChar("Account: %d (IP: %s) Logout Character:[%s] (GUID: %u)", GetAccountId(), GetRemoteAddress().c_str(), _player->GetName() ,_player->GetGUIDLow()); - Map* _map = _player->GetMap(); - _map->Remove(_player, true); - SetPlayer(NULL); // deleted in Remove call - - ///- Send the 'logout complete' packet to the client - WorldPacket data(SMSG_LOGOUT_COMPLETE, 0); - SendPacket(&data); - - ///- Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline - //No SQL injection as AccountId is uint32 - CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = '%u'", - GetAccountId()); - sLog.outDebug("SESSION: Sent SMSG_LOGOUT_COMPLETE Message"); - } - - //Hook for OnLogout Event - sScriptMgr.OnLogout(_player); - - m_playerLogout = false; - m_playerSave = false; - m_playerRecentlyLogout = true; - LogoutRequest(0); -} - -/// Kick a player out of the World -void WorldSession::KickPlayer() -{ - if (m_Socket) - m_Socket->CloseSocket (); -} - -void WorldSession::SendNotification(const char *format,...) -{ - if (format) - { - va_list ap; - char szStr [1024]; - szStr[0] = '\0'; - va_start(ap, format); - vsnprintf(szStr, 1024, format, ap); - va_end(ap); - - WorldPacket data(SMSG_NOTIFICATION, (strlen(szStr)+1)); - data << szStr; - SendPacket(&data); - } -} - -void WorldSession::SendNotification(int32 string_id,...) -{ - char const* format = GetTrinityString(string_id); - if (format) - { - va_list ap; - char szStr [1024]; - szStr[0] = '\0'; - va_start(ap, string_id); - vsnprintf(szStr, 1024, format, ap); - va_end(ap); - - WorldPacket data(SMSG_NOTIFICATION, (strlen(szStr)+1)); - data << szStr; - SendPacket(&data); - } -} - -const char * WorldSession::GetTrinityString(int32 entry) const -{ - return objmgr.GetTrinityString(entry,GetSessionDbLocaleIndex()); -} - -void WorldSession::Handle_NULL(WorldPacket& recvPacket) -{ - sLog.outError("SESSION: received unhandled opcode %s (0x%.4X)", - LookupOpcodeName(recvPacket.GetOpcode()), - recvPacket.GetOpcode()); -} - -void WorldSession::Handle_EarlyProccess(WorldPacket& recvPacket) -{ - sLog.outError("SESSION: received opcode %s (0x%.4X) that must be processed in WorldSocket::OnRead", - LookupOpcodeName(recvPacket.GetOpcode()), - recvPacket.GetOpcode()); -} - -void WorldSession::Handle_ServerSide(WorldPacket& recvPacket) -{ - sLog.outError("SESSION: received server-side opcode %s (0x%.4X)", - LookupOpcodeName(recvPacket.GetOpcode()), - recvPacket.GetOpcode()); -} - -void WorldSession::Handle_Deprecated(WorldPacket& recvPacket) -{ - sLog.outError("SESSION: received deprecated opcode %s (0x%.4X)", - LookupOpcodeName(recvPacket.GetOpcode()), - recvPacket.GetOpcode()); -} - -void WorldSession::SendAuthWaitQue(uint32 position) -{ - if (position == 0) - { - WorldPacket packet(SMSG_AUTH_RESPONSE, 1); - packet << uint8(AUTH_OK); - SendPacket(&packet); - } - else - { - WorldPacket packet(SMSG_AUTH_RESPONSE, 6); - packet << uint8(AUTH_WAIT_QUEUE); - packet << uint32(position); - packet << uint8(0); // unk - SendPacket(&packet); - } -} - -void WorldSession::LoadGlobalAccountData() -{ - LoadAccountData( - CharacterDatabase.PQuery("SELECT type, time, data FROM account_data WHERE account='%u'", GetAccountId()), - GLOBAL_CACHE_MASK -); -} - -void WorldSession::LoadAccountData(QueryResult_AutoPtr result, uint32 mask) -{ - for (uint32 i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i) - if (mask & (1 << i)) - m_accountData[i] = AccountData(); - - if (!result) - return; - - do - { - Field *fields = result->Fetch(); - - uint32 type = fields[0].GetUInt32(); - if (type >= NUM_ACCOUNT_DATA_TYPES) - { - sLog.outError("Table `%s` have invalid account data type (%u), ignore.", - mask == GLOBAL_CACHE_MASK ? "account_data" : "character_account_data", type); - continue; - } - - if ((mask & (1 << type)) == 0) - { - sLog.outError("Table `%s` have non appropriate for table account data type (%u), ignore.", - mask == GLOBAL_CACHE_MASK ? "account_data" : "character_account_data", type); - continue; - } - - m_accountData[type].Time = fields[1].GetUInt32(); - m_accountData[type].Data = fields[2].GetCppString(); - - } while (result->NextRow()); -} - -void WorldSession::SetAccountData(AccountDataType type, time_t time_, std::string data) -{ - if ((1 << type) & GLOBAL_CACHE_MASK) - { - uint32 acc = GetAccountId(); - - CharacterDatabase.BeginTransaction (); - CharacterDatabase.PExecute("DELETE FROM account_data WHERE account='%u' AND type='%u'", acc, type); - CharacterDatabase.escape_string(data); - CharacterDatabase.PExecute("INSERT INTO account_data VALUES ('%u','%u','%u','%s')", acc, type, (uint32)time_, data.c_str()); - CharacterDatabase.CommitTransaction (); - } - else - { - // _player can be NULL and packet received after logout but m_GUID still store correct guid - if (!m_GUIDLow) - return; - - CharacterDatabase.BeginTransaction (); - CharacterDatabase.PExecute("DELETE FROM character_account_data WHERE guid='%u' AND type='%u'", m_GUIDLow, type); - CharacterDatabase.escape_string(data); - CharacterDatabase.PExecute("INSERT INTO character_account_data VALUES ('%u','%u','%u','%s')", m_GUIDLow, type, (uint32)time_, data.c_str()); - CharacterDatabase.CommitTransaction (); - } - - m_accountData[type].Time = time_; - m_accountData[type].Data = data; -} - -void WorldSession::SendAccountDataTimes(uint32 mask) -{ - WorldPacket data(SMSG_ACCOUNT_DATA_TIMES, 4+1+4+8*4); // changed in WotLK - data << uint32(time(NULL)); // unix time of something - data << uint8(1); - data << uint32(mask); // type mask - for (uint32 i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i) - if (mask & (1 << i)) - data << uint32(GetAccountData(AccountDataType(i))->Time);// also unix time - SendPacket(&data); -} - -void WorldSession::LoadTutorialsData() -{ - for (int aX = 0 ; aX < 8 ; ++aX) - m_Tutorials[ aX ] = 0; - - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7 FROM character_tutorial WHERE account = '%u'", GetAccountId()); - - if (result) - { - do - { - Field *fields = result->Fetch(); - - for (int iI = 0; iI < 8; ++iI) - m_Tutorials[iI] = fields[iI].GetUInt32(); - } - while (result->NextRow()); - } - m_TutorialsChanged = false; -} - -void WorldSession::SendTutorialsData() -{ - WorldPacket data(SMSG_TUTORIAL_FLAGS, 4*8); - for (uint32 i = 0; i < 8; ++i) - data << m_Tutorials[i]; - SendPacket(&data); -} - -void WorldSession::SaveTutorialsData() -{ - if (!m_TutorialsChanged) - return; - - uint32 Rows=0; - // it's better than rebuilding indexes multiple times - QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT count(*) AS r FROM character_tutorial WHERE account = '%u'", GetAccountId()); - if (result) - Rows = result->Fetch()[0].GetUInt32(); - - if (Rows) - { - CharacterDatabase.PExecute("UPDATE character_tutorial SET tut0='%u', tut1='%u', tut2='%u', tut3='%u', tut4='%u', tut5='%u', tut6='%u', tut7='%u' WHERE account = '%u'", - m_Tutorials[0], m_Tutorials[1], m_Tutorials[2], m_Tutorials[3], m_Tutorials[4], m_Tutorials[5], m_Tutorials[6], m_Tutorials[7], GetAccountId()); - } - else - { - CharacterDatabase.PExecute("INSERT INTO character_tutorial (account,tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7) VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", GetAccountId(), m_Tutorials[0], m_Tutorials[1], m_Tutorials[2], m_Tutorials[3], m_Tutorials[4], m_Tutorials[5], m_Tutorials[6], m_Tutorials[7]); - } - - m_TutorialsChanged = false; -} - -void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo *mi) -{ - data >> mi->flags; - data >> mi->unk1; - data >> mi->time; - data >> mi->x; - data >> mi->y; - data >> mi->z; - data >> mi->o; - - if (mi->flags & MOVEMENTFLAG_ONTRANSPORT) - { - if (!data.readPackGUID(mi->t_guid)) - return; - - data >> mi->t_x; - data >> mi->t_y; - data >> mi->t_z; - data >> mi->t_o; - data >> mi->t_time; - data >> mi->t_seat; - } - - if ((mi->flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || (mi->unk1 & 0x20)) - { - data >> mi->s_pitch; - } - - data >> mi->fallTime; - - if (mi->flags & MOVEMENTFLAG_JUMPING) - { - data >> mi->j_zspeed; - data >> mi->j_sinAngle; - data >> mi->j_cosAngle; - data >> mi->j_xyspeed; - } - - if (mi->flags & MOVEMENTFLAG_SPLINE) - { - data >> mi->u_unk1; - } -} - -void WorldSession::WriteMovementInfo(WorldPacket *data, MovementInfo *mi) -{ - data->appendPackGUID(mi->guid); - - *data << mi->flags; - *data << mi->unk1; - *data << mi->time; - *data << mi->x; - *data << mi->y; - *data << mi->z; - *data << mi->o; - - if (mi->HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT)) - { - data->appendPackGUID(mi->t_guid); - - *data << mi->t_x; - *data << mi->t_y; - *data << mi->t_z; - *data << mi->t_o; - *data << mi->t_time; - *data << mi->t_seat; - } - - if ((mi->HasMovementFlag(MovementFlags(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING))) || (mi->unk1 & 0x20)) - { - *data << mi->s_pitch; - } - - *data << mi->fallTime; - - if (mi->HasMovementFlag(MOVEMENTFLAG_JUMPING)) - { - *data << mi->j_zspeed; - *data << mi->j_sinAngle; - *data << mi->j_cosAngle; - *data << mi->j_xyspeed; - } - - if (mi->HasMovementFlag(MOVEMENTFLAG_SPLINE)) - { - *data << mi->u_unk1; - } -} - -void WorldSession::ReadAddonsInfo(WorldPacket &data) -{ - if (data.rpos() + 4 > data.size()) - return; - uint32 size; - data >> size; - - if (!size) - return; - - if (size > 0xFFFFF) - { - sLog.outError("WorldSession::ReadAddonsInfo addon info too big, size %u", size); - return; - } - - uLongf uSize = size; - - uint32 pos = data.rpos(); - - ByteBuffer addonInfo; - addonInfo.resize(size); - - if (uncompress(const_cast(addonInfo.contents()), &uSize, const_cast(data.contents() + pos), data.size() - pos) == Z_OK) - { - uint32 addonsCount; - addonInfo >> addonsCount; // addons count - - for (uint32 i = 0; i < addonsCount; ++i) - { - std::string addonName; - uint8 enabled; - uint32 crc, unk1; - - // check next addon data format correctness - if (addonInfo.rpos()+1 > addonInfo.size()) - return; - - addonInfo >> addonName; - - addonInfo >> enabled >> crc >> unk1; - - sLog.outDetail("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); - - SavedAddon const* savedAddon = sAddonMgr.GetAddonInfo(addonName); - if (savedAddon) - { - bool match = true; - - if (addon.CRC != savedAddon->CRC) - match = false; - - if (!match) - sLog.outDetail("ADDON: %s was known, but didn't match known CRC (0x%x)!", addon.Name.c_str(), savedAddon->CRC); - else - sLog.outDetail("ADDON: %s was known, CRC is correct (0x%x)", addon.Name.c_str(), savedAddon->CRC); - } - else - { - sAddonMgr.SaveAddon(addon); - - sLog.outDetail("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. - m_addonsList.push_back(addon); - } - - uint32 currentTime; - addonInfo >> currentTime; - sLog.outDebug("ADDON: CurrentTime: %u", currentTime); - - if (addonInfo.rpos() != addonInfo.size()) - sLog.outDebug("packet under-read!"); - } - else - sLog.outError("Addon packet uncompress error!"); -} - -void WorldSession::SendAddonsInfo() -{ - uint8 addonPublicKey[256] = - { - 0xC3, 0x5B, 0x50, 0x84, 0xB9, 0x3E, 0x32, 0x42, 0x8C, 0xD0, 0xC7, 0x48, 0xFA, 0x0E, 0x5D, 0x54, - 0x5A, 0xA3, 0x0E, 0x14, 0xBA, 0x9E, 0x0D, 0xB9, 0x5D, 0x8B, 0xEE, 0xB6, 0x84, 0x93, 0x45, 0x75, - 0xFF, 0x31, 0xFE, 0x2F, 0x64, 0x3F, 0x3D, 0x6D, 0x07, 0xD9, 0x44, 0x9B, 0x40, 0x85, 0x59, 0x34, - 0x4E, 0x10, 0xE1, 0xE7, 0x43, 0x69, 0xEF, 0x7C, 0x16, 0xFC, 0xB4, 0xED, 0x1B, 0x95, 0x28, 0xA8, - 0x23, 0x76, 0x51, 0x31, 0x57, 0x30, 0x2B, 0x79, 0x08, 0x50, 0x10, 0x1C, 0x4A, 0x1A, 0x2C, 0xC8, - 0x8B, 0x8F, 0x05, 0x2D, 0x22, 0x3D, 0xDB, 0x5A, 0x24, 0x7A, 0x0F, 0x13, 0x50, 0x37, 0x8F, 0x5A, - 0xCC, 0x9E, 0x04, 0x44, 0x0E, 0x87, 0x01, 0xD4, 0xA3, 0x15, 0x94, 0x16, 0x34, 0xC6, 0xC2, 0xC3, - 0xFB, 0x49, 0xFE, 0xE1, 0xF9, 0xDA, 0x8C, 0x50, 0x3C, 0xBE, 0x2C, 0xBB, 0x57, 0xED, 0x46, 0xB9, - 0xAD, 0x8B, 0xC6, 0xDF, 0x0E, 0xD6, 0x0F, 0xBE, 0x80, 0xB3, 0x8B, 0x1E, 0x77, 0xCF, 0xAD, 0x22, - 0xCF, 0xB7, 0x4B, 0xCF, 0xFB, 0xF0, 0x6B, 0x11, 0x45, 0x2D, 0x7A, 0x81, 0x18, 0xF2, 0x92, 0x7E, - 0x98, 0x56, 0x5D, 0x5E, 0x69, 0x72, 0x0A, 0x0D, 0x03, 0x0A, 0x85, 0xA2, 0x85, 0x9C, 0xCB, 0xFB, - 0x56, 0x6E, 0x8F, 0x44, 0xBB, 0x8F, 0x02, 0x22, 0x68, 0x63, 0x97, 0xBC, 0x85, 0xBA, 0xA8, 0xF7, - 0xB5, 0x40, 0x68, 0x3C, 0x77, 0x86, 0x6F, 0x4B, 0xD7, 0x88, 0xCA, 0x8A, 0xD7, 0xCE, 0x36, 0xF0, - 0x45, 0x6E, 0xD5, 0x64, 0x79, 0x0F, 0x17, 0xFC, 0x64, 0xDD, 0x10, 0x6F, 0xF3, 0xF5, 0xE0, 0xA6, - 0xC3, 0xFB, 0x1B, 0x8C, 0x29, 0xEF, 0x8E, 0xE5, 0x34, 0xCB, 0xD1, 0x2A, 0xCE, 0x79, 0xC3, 0x9A, - 0x0D, 0x36, 0xEA, 0x01, 0xE0, 0xAA, 0x91, 0x20, 0x54, 0xF0, 0x72, 0xD8, 0x1E, 0xC7, 0x89, 0xD2 - }; - - WorldPacket data(SMSG_ADDON_INFO, 4); - - for (AddonsList::iterator itr = m_addonsList.begin(); itr != m_addonsList.end(); ++itr) - { - data << uint8(itr->State); - - uint8 crcpub = itr->UsePublicKeyOrCRC; - data << uint8(crcpub); - if (crcpub) - { - uint8 usepk = (itr->CRC != STANDARD_ADDON_CRC); // If addon is Standard addon CRC - data << uint8(usepk); - if (usepk) // if CRC is wrong, add public key (client need it) - { - sLog.outDetail("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)); - } - - data << uint32(/*itr->CRC*/ 0); // TODO: Find out the meaning of this. - } - - uint8 unk3 = 0; // 0 is sent here - data << uint8(unk3); - if (unk3) - { - // String, length 256 (null terminated) - data << uint8(0); - } - } - - m_addonsList.clear(); - - uint32 count = 0; - data << uint32(count); - /*for (uint32 i = 0; i < count; ++i) - { - uint32 - string (16 bytes) - string (16 bytes) - uint32 - uint32 - }*/ - - SendPacket(&data); -} - -void WorldSession::SetPlayer(Player *plr) -{ - _player = plr; - - // set m_GUID that can be used while player loggined and later until m_playerRecentlyLogout not reset - if (_player) - m_GUIDLow = _player->GetGUIDLow(); -} diff --git a/src/server/game/World/WorldSession.h b/src/server/game/World/WorldSession.h deleted file mode 100644 index c17f3e3f3e6..00000000000 --- a/src/server/game/World/WorldSession.h +++ /dev/null @@ -1,829 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/// \addtogroup u2w -/// @{ -/// \file - -#ifndef __WORLDSESSION_H -#define __WORLDSESSION_H - -#include "Common.h" -#include "SharedDefines.h" -#include "AddonMgr.h" -#include "QueryResult.h" -#include "World.h" - -struct ItemPrototype; -struct AuctionEntry; -struct DeclinedName; -struct MovementInfo; - -class Creature; -class Item; -class Object; -class Player; -class Unit; -class GameObject; -class WorldPacket; -class WorldSocket; -class QueryResult; -class LoginQueryHolder; -class CharacterHandler; -struct AreaTableEntry; - -enum AccountDataType -{ - GLOBAL_CONFIG_CACHE = 0, // 0x01 g - PER_CHARACTER_CONFIG_CACHE = 1, // 0x02 p - GLOBAL_BINDINGS_CACHE = 2, // 0x04 g - PER_CHARACTER_BINDINGS_CACHE = 3, // 0x08 p - GLOBAL_MACROS_CACHE = 4, // 0x10 g - PER_CHARACTER_MACROS_CACHE = 5, // 0x20 p - PER_CHARACTER_LAYOUT_CACHE = 6, // 0x40 p - PER_CHARACTER_CHAT_CACHE = 7, // 0x80 p -}; - -#define NUM_ACCOUNT_DATA_TYPES 8 - -#define GLOBAL_CACHE_MASK 0x15 -#define PER_CHARACTER_CACHE_MASK 0xEA - -struct AccountData -{ - AccountData() : Time(0), Data("") {} - - time_t Time; - std::string Data; -}; - -enum PartyOperation -{ - PARTY_OP_INVITE = 0, - PARTY_OP_UNINVITE = 1, - PARTY_OP_LEAVE = 2, - PARTY_OP_SWAP = 4 -}; - -enum PartyResult -{ - ERR_PARTY_RESULT_OK = 0, - ERR_BAD_PLAYER_NAME_S = 1, - ERR_TARGET_NOT_IN_GROUP_S = 2, - ERR_TARGET_NOT_IN_INSTANCE_S = 3, - ERR_GROUP_FULL = 4, - ERR_ALREADY_IN_GROUP_S = 5, - ERR_NOT_IN_GROUP = 6, - ERR_NOT_LEADER = 7, - ERR_PLAYER_WRONG_FACTION = 8, - ERR_IGNORING_YOU_S = 9, - ERR_LFG_PENDING = 12, - ERR_INVITE_RESTRICTED = 13, - ERR_GROUP_SWAP_FAILED = 14, // if (PartyOperation == PARTY_OP_SWAP) ERR_GROUP_SWAP_FAILED else ERR_INVITE_IN_COMBAT - ERR_INVITE_UNKNOWN_REALM = 15, - ERR_INVITE_NO_PARTY_SERVER = 16, - ERR_INVITE_PARTY_BUSY = 17, - ERR_PARTY_TARGET_AMBIGUOUS = 18, - ERR_PARTY_LFG_INVITE_RAID_LOCKED = 19, - ERR_PARTY_LFG_BOOT_LIMIT = 20, - ERR_PARTY_LFG_BOOT_COOLDOWN_S = 21, - ERR_PARTY_LFG_BOOT_IN_PROGRESS = 22, - ERR_PARTY_LFG_BOOT_TOO_FEW_PLAYERS = 23, - ERR_PARTY_LFG_BOOT_NOT_ELIGIBLE_S = 24, - ERR_RAID_DISALLOWED_BY_LEVEL = 25, - ERR_PARTY_LFG_BOOT_IN_COMBAT = 26, - ERR_VOTE_KICK_REASON_NEEDED = 27, - ERR_PARTY_LFG_BOOT_DUNGEON_COMPLETE = 28, - ERR_PARTY_LFG_BOOT_LOOT_ROLLS = 29, - ERR_PARTY_LFG_TELEPORT_IN_COMBAT = 30 -}; - -enum ChatRestrictionType -{ - ERR_CHAT_RESTRICTED = 0, - ERR_CHAT_THROTTLED = 1, - ERR_USER_SQUELCHED = 2, - ERR_YELL_RESTRICTED = 3 -}; - -/// Player session in the World -class WorldSession -{ - friend class CharacterHandler; - public: - WorldSession(uint32 id, WorldSocket *sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale); - ~WorldSession(); - - bool PlayerLoading() const { return m_playerLoading; } - bool PlayerLogout() const { return m_playerLogout; } - bool PlayerLogoutWithSave() const { return m_playerLogout && m_playerSave; } - - void SizeError(WorldPacket const& packet, uint32 size) const; - - void ReadAddonsInfo(WorldPacket &data); - void SendAddonsInfo(); - - void ReadMovementInfo(WorldPacket &data, MovementInfo *mi); - void WriteMovementInfo(WorldPacket *data, MovementInfo *mi); - - void SendPacket(WorldPacket const* packet); - void SendNotification(const char *format,...) ATTR_PRINTF(2,3); - void SendNotification(int32 string_id,...); - void SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName *declinedName); - void SendPartyResult(PartyOperation operation, const std::string& member, PartyResult res); - void SendAreaTriggerMessage(const char* Text, ...) ATTR_PRINTF(2,3); - void SendSetPhaseShift(uint32 phaseShift); - void SendQueryTimeResponse(); - - AccountTypes GetSecurity() const { return _security; } - uint32 GetAccountId() const { return _accountId; } - Player* GetPlayer() const { return _player; } - char const* GetPlayerName() const; - void SetSecurity(AccountTypes security) { _security = security; } - std::string const& GetRemoteAddress() { return m_Address; } - void SetPlayer(Player *plr); - uint8 Expansion() const { return m_expansion; } - - /// Session in auth.queue currently - void SetInQueue(bool state) { m_inQueue = state; } - - /// Is the user engaged in a log out process? - bool isLogingOut() const { return _logoutTime || m_playerLogout; } - - /// Engage the logout process for the user - void LogoutRequest(time_t requestTime) - { - _logoutTime = requestTime; - } - - /// Is logout cooldown expired? - bool ShouldLogOut(time_t currTime) const - { - return (_logoutTime > 0 && currTime >= _logoutTime + 20); - } - - void LogoutPlayer(bool Save); - void KickPlayer(); - - void QueuePacket(WorldPacket* new_packet); - bool Update(uint32 diff); - - /// Handle the authentication waiting queue (to be completed) - void SendAuthWaitQue(uint32 position); - - //void SendTestCreatureQueryOpcode(uint32 entry, uint64 guid, uint32 testvalue); - void SendNameQueryOpcode(Player* p); - void SendNameQueryOpcodeFromDB(uint64 guid); - static void SendNameQueryOpcodeFromDBCallBack(QueryResult_AutoPtr result, uint32 accountId); - - void SendTrainerList(uint64 guid); - void SendTrainerList(uint64 guid, const std::string& strTitle); - void SendListInventory(uint64 guid); - void SendShowBank(uint64 guid); - void SendTabardVendorActivate(uint64 guid); - void SendSpiritResurrect(); - void SendBindPoint(Creature* npc); - - void SendAttackStop(Unit const* enemy); - - void SendBattlegGroundList(uint64 guid, BattleGroundTypeId bgTypeId); - - void SendTradeStatus(uint32 status); - void SendCancelTrade(); - - void SendStablePet(uint64 guid); - void SendPetitionQueryOpcode(uint64 petitionguid); - void SendUpdateTrade(); - - //pet - void SendPetNameQuery(uint64 guid, uint32 petnumber); - - // Account Data - AccountData *GetAccountData(AccountDataType type) { return &m_accountData[type]; } - void SetAccountData(AccountDataType type, time_t time_, std::string data); - void SendAccountDataTimes(uint32 mask); - void LoadGlobalAccountData(); - void LoadAccountData(QueryResult_AutoPtr result, uint32 mask); - void LoadTutorialsData(); - void SendTutorialsData(); - void SaveTutorialsData(); - uint32 GetTutorialInt(uint32 intId) - { - return m_Tutorials[intId]; - } - - void SetTutorialInt(uint32 intId, uint32 value) - { - if (m_Tutorials[intId] != value) - { - m_Tutorials[intId] = value; - m_TutorialsChanged = true; - } - } - //used with item_page table - bool SendItemInfo(uint32 itemid, WorldPacket data); - //auction - void SendAuctionHello(uint64 guid, Creature * unit); - void SendAuctionCommandResult(uint32 auctionId, uint32 Action, uint32 ErrorCode, uint32 bidError = 0); - void SendAuctionBidderNotification(uint32 location, uint32 auctionId, uint64 bidder, uint32 bidSum, uint32 diff, uint32 item_template); - void SendAuctionOwnerNotification(AuctionEntry * auction); - void SendAuctionOutbiddedMail(AuctionEntry * auction, uint32 newPrice); - void SendAuctionCancelledToBidderMail(AuctionEntry* auction); - - //Item Enchantment - void SendEnchantmentLog(uint64 Target, uint64 Caster,uint32 ItemID,uint32 SpellID); - void SendItemEnchantTimeUpdate(uint64 Playerguid, uint64 Itemguid,uint32 slot,uint32 Duration); - - //Taxi - void SendTaxiStatus(uint64 guid); - void SendTaxiMenu(Creature* unit); - void SendDoFlight(uint32 mountDisplayId, uint32 path, uint32 pathNode = 0); - bool SendLearnNewTaxiNode(Creature* unit); - - // Guild/Arena Team - void SendGuildCommandResult(uint32 typecmd, const std::string& str, uint32 cmdresult); - void SendArenaTeamCommandResult(uint32 team_action, const std::string& team, const std::string& player, uint32 error_id); - void SendNotInArenaTeamPacket(uint8 type); - void SendPetitionShowList(uint64 guid); - void SendSaveGuildEmblem(uint32 msg); - // Looking For Group - // TRUE values set by client sending CMSG_LFG_SET_AUTOJOIN and CMSG_LFM_CLEAR_AUTOFILL before player login - bool LookingForGroup_auto_join; - bool LookingForGroup_auto_add; - - void BuildPartyMemberStatsChangedPacket(Player *player, WorldPacket *data); - - void DoLootRelease(uint64 lguid); - - // Account mute time - time_t m_muteTime; - - // Locales - LocaleConstant GetSessionDbcLocale() const { return m_sessionDbcLocale; } - int GetSessionDbLocaleIndex() const { return m_sessionDbLocaleIndex; } - const char *GetTrinityString(int32 entry) const; - - uint32 GetLatency() const { return m_latency; } - void SetLatency(uint32 latency) { m_latency = latency; } - uint32 getDialogStatus(Player *pPlayer, Object* questgiver, uint32 defstatus); - - time_t m_timeOutTime; - void UpdateTimeOutTime(uint32 diff) - { - if (diff > m_timeOutTime) - m_timeOutTime = 0; - else - m_timeOutTime -= diff; - } - void ResetTimeOutTime() - { - m_timeOutTime = sWorld.getConfig(CONFIG_SOCKET_TIMEOUTTIME); - } - bool IsConnectionIdle() const - { - if (m_timeOutTime <= 0 && !m_inQueue) - return true; - return false; - } - - - public: // opcodes handlers - - void Handle_NULL(WorldPacket& recvPacket); // not used - void Handle_EarlyProccess(WorldPacket& recvPacket);// just mark packets processed in WorldSocket::OnRead - void Handle_ServerSide(WorldPacket& recvPacket); // sever side only, can't be accepted from client - void Handle_Deprecated(WorldPacket& recvPacket); // never used anymore by client - - void HandleCharEnumOpcode(WorldPacket& recvPacket); - void HandleCharDeleteOpcode(WorldPacket& recvPacket); - void HandleCharCreateOpcode(WorldPacket& recvPacket); - void HandlePlayerLoginOpcode(WorldPacket& recvPacket); - void HandleCharEnum(QueryResult_AutoPtr result); - void HandlePlayerLogin(LoginQueryHolder * holder); - - // played time - void HandlePlayedTime(WorldPacket& recvPacket); - - // new - void HandleMoveUnRootAck(WorldPacket& recvPacket); - void HandleMoveRootAck(WorldPacket& recvPacket); - void HandleLookingForGroup(WorldPacket& recvPacket); - - // new inspect - void HandleInspectOpcode(WorldPacket& recvPacket); - - // new party stats - void HandleInspectHonorStatsOpcode(WorldPacket& recvPacket); - - void HandleMoveWaterWalkAck(WorldPacket& recvPacket); - void HandleFeatherFallAck(WorldPacket &recv_data); - - void HandleMoveHoverAck(WorldPacket & recv_data); - - void HandleMountSpecialAnimOpcode(WorldPacket &recvdata); - - // character view - void HandleShowingHelmOpcode(WorldPacket& recv_data); - void HandleShowingCloakOpcode(WorldPacket& recv_data); - - // repair - void HandleRepairItemOpcode(WorldPacket& recvPacket); - - // Knockback - void HandleMoveKnockBackAck(WorldPacket& recvPacket); - - void HandleMoveTeleportAck(WorldPacket& recvPacket); - void HandleForceSpeedChangeAck(WorldPacket & recv_data); - - void HandlePingOpcode(WorldPacket& recvPacket); - void HandleAuthSessionOpcode(WorldPacket& recvPacket); - void HandleRepopRequestOpcode(WorldPacket& recvPacket); - void HandleAutostoreLootItemOpcode(WorldPacket& recvPacket); - void HandleLootMoneyOpcode(WorldPacket& recvPacket); - void HandleLootOpcode(WorldPacket& recvPacket); - void HandleLootReleaseOpcode(WorldPacket& recvPacket); - void HandleLootMasterGiveOpcode(WorldPacket& recvPacket); - void HandleWhoOpcode(WorldPacket& recvPacket); - void HandleLogoutRequestOpcode(WorldPacket& recvPacket); - void HandlePlayerLogoutOpcode(WorldPacket& recvPacket); - void HandleLogoutCancelOpcode(WorldPacket& recvPacket); - - // GM Ticket opcodes - void HandleGMTicketCreateOpcode(WorldPacket& recvPacket); - void HandleGMTicketUpdateOpcode(WorldPacket& recvPacket); - void HandleGMTicketDeleteOpcode(WorldPacket& recvPacket); - void HandleGMTicketGetTicketOpcode(WorldPacket& recvPacket); - void HandleGMTicketSystemStatusOpcode(WorldPacket& recvPacket); - void SendGMTicketGetTicket(uint32 status, char const* text); - - //void HandleGMSurveySubmit(WorldPacket& recvPacket); - - void HandleTogglePvP(WorldPacket& recvPacket); - - void HandleZoneUpdateOpcode(WorldPacket& recvPacket); - void HandleSetTargetOpcode(WorldPacket& recvPacket); - void HandleSetSelectionOpcode(WorldPacket& recvPacket); - void HandleStandStateChangeOpcode(WorldPacket& recvPacket); - void HandleEmoteOpcode(WorldPacket& recvPacket); - void HandleContactListOpcode(WorldPacket& recvPacket); - void HandleAddFriendOpcode(WorldPacket& recvPacket); - static void HandleAddFriendOpcodeCallBack(QueryResult_AutoPtr result, uint32 accountId, std::string friendNote); - void HandleDelFriendOpcode(WorldPacket& recvPacket); - void HandleAddIgnoreOpcode(WorldPacket& recvPacket); - static void HandleAddIgnoreOpcodeCallBack(QueryResult_AutoPtr result, uint32 accountId); - void HandleDelIgnoreOpcode(WorldPacket& recvPacket); - void HandleSetContactNotesOpcode(WorldPacket& recvPacket); - void HandleBugOpcode(WorldPacket& recvPacket); - void HandleSetAmmoOpcode(WorldPacket& recvPacket); - void HandleItemNameQueryOpcode(WorldPacket& recvPacket); - - void HandleAreaTriggerOpcode(WorldPacket& recvPacket); - - void HandleSetFactionAtWar(WorldPacket & recv_data); - void HandleSetFactionCheat(WorldPacket & recv_data); - void HandleSetWatchedFactionOpcode(WorldPacket & recv_data); - void HandleSetFactionInactiveOpcode(WorldPacket & recv_data); - - void HandleUpdateAccountData(WorldPacket& recvPacket); - void HandleRequestAccountData(WorldPacket& recvPacket); - void HandleSetActionButtonOpcode(WorldPacket& recvPacket); - - void HandleGameObjectUseOpcode(WorldPacket& recPacket); - void HandleMeetingStoneInfo(WorldPacket& recPacket); - void HandleGameobjectReportUse(WorldPacket& recvPacket); - - void HandleNameQueryOpcode(WorldPacket& recvPacket); - - void HandleQueryTimeOpcode(WorldPacket& recvPacket); - - void HandleCreatureQueryOpcode(WorldPacket& recvPacket); - - void HandleGameObjectQueryOpcode(WorldPacket& recvPacket); - - void HandleMoveWorldportAckOpcode(WorldPacket& recvPacket); - void HandleMoveWorldportAckOpcode(); // for server-side calls - - void HandleMovementOpcodes(WorldPacket& recvPacket); - void HandleSetActiveMoverOpcode(WorldPacket &recv_data); - void HandleMoveNotActiveMover(WorldPacket &recv_data); - void HandleDismissControlledVehicle(WorldPacket &recv_data); - void HandleRequestVehicleExit(WorldPacket &recv_data); - void HandleChangeSeatsOnControlledVehicle(WorldPacket &recv_data); - void HandleMoveTimeSkippedOpcode(WorldPacket &recv_data); - - void HandleRequestRaidInfoOpcode(WorldPacket & recv_data); - - void HandleBattlefieldStatusOpcode(WorldPacket &recv_data); - void HandleBattleMasterHelloOpcode(WorldPacket &recv_data); - - void HandleGroupInviteOpcode(WorldPacket& recvPacket); - //void HandleGroupCancelOpcode(WorldPacket& recvPacket); - void HandleGroupAcceptOpcode(WorldPacket& recvPacket); - void HandleGroupDeclineOpcode(WorldPacket& recvPacket); - void HandleGroupUninviteOpcode(WorldPacket& recvPacket); - void HandleGroupUninviteGuidOpcode(WorldPacket& recvPacket); - void HandleGroupSetLeaderOpcode(WorldPacket& recvPacket); - void HandleGroupDisbandOpcode(WorldPacket& recvPacket); - void HandleOptOutOfLootOpcode(WorldPacket &recv_data); - void HandleLootMethodOpcode(WorldPacket& recvPacket); - void HandleLootRoll(WorldPacket &recv_data); - void HandleRequestPartyMemberStatsOpcode(WorldPacket &recv_data); - void HandleRaidTargetUpdateOpcode(WorldPacket & recv_data); - void HandleRaidReadyCheckOpcode(WorldPacket & recv_data); - void HandleRaidReadyCheckFinishedOpcode(WorldPacket & recv_data); - void HandleGroupRaidConvertOpcode(WorldPacket & recv_data); - void HandleGroupChangeSubGroupOpcode(WorldPacket & recv_data); - void HandleGroupAssistantLeaderOpcode(WorldPacket & recv_data); - void HandlePartyAssignmentOpcode(WorldPacket & recv_data); - - void HandlePetitionBuyOpcode(WorldPacket& recv_data); - void HandlePetitionShowSignOpcode(WorldPacket& recv_data); - void HandlePetitionQueryOpcode(WorldPacket& recv_data); - void HandlePetitionRenameOpcode(WorldPacket& recv_data); - void HandlePetitionSignOpcode(WorldPacket& recv_data); - void HandlePetitionDeclineOpcode(WorldPacket& recv_data); - void HandleOfferPetitionOpcode(WorldPacket& recv_data); - void HandleTurnInPetitionOpcode(WorldPacket& recv_data); - - void HandleGuildQueryOpcode(WorldPacket& recvPacket); - void HandleGuildCreateOpcode(WorldPacket& recvPacket); - void HandleGuildInviteOpcode(WorldPacket& recvPacket); - void HandleGuildRemoveOpcode(WorldPacket& recvPacket); - void HandleGuildAcceptOpcode(WorldPacket& recvPacket); - void HandleGuildDeclineOpcode(WorldPacket& recvPacket); - void HandleGuildInfoOpcode(WorldPacket& recvPacket); - void HandleGuildEventLogQueryOpcode(WorldPacket& recvPacket); - void HandleGuildRosterOpcode(WorldPacket& recvPacket); - void HandleGuildPromoteOpcode(WorldPacket& recvPacket); - void HandleGuildDemoteOpcode(WorldPacket& recvPacket); - void HandleGuildLeaveOpcode(WorldPacket& recvPacket); - void HandleGuildDisbandOpcode(WorldPacket& recvPacket); - void HandleGuildLeaderOpcode(WorldPacket& recvPacket); - void HandleGuildMOTDOpcode(WorldPacket& recvPacket); - void HandleGuildSetPublicNoteOpcode(WorldPacket& recvPacket); - void HandleGuildSetOfficerNoteOpcode(WorldPacket& recvPacket); - void HandleGuildRankOpcode(WorldPacket& recvPacket); - void HandleGuildAddRankOpcode(WorldPacket& recvPacket); - void HandleGuildDelRankOpcode(WorldPacket& recvPacket); - void HandleGuildChangeInfoTextOpcode(WorldPacket& recvPacket); - void HandleSaveGuildEmblemOpcode(WorldPacket& recvPacket); - - void HandleTaxiNodeStatusQueryOpcode(WorldPacket& recvPacket); - void HandleTaxiQueryAvailableNodes(WorldPacket& recvPacket); - void HandleActivateTaxiOpcode(WorldPacket& recvPacket); - void HandleActivateTaxiExpressOpcode(WorldPacket& recvPacket); - void HandleMoveSplineDoneOpcode(WorldPacket& recvPacket); - - void HandleTabardVendorActivateOpcode(WorldPacket& recvPacket); - void HandleBankerActivateOpcode(WorldPacket& recvPacket); - void HandleBuyBankSlotOpcode(WorldPacket& recvPacket); - void HandleTrainerListOpcode(WorldPacket& recvPacket); - void HandleTrainerBuySpellOpcode(WorldPacket& recvPacket); - void HandlePetitionShowListOpcode(WorldPacket& recvPacket); - void HandleGossipHelloOpcode(WorldPacket& recvPacket); - void HandleGossipSelectOptionOpcode(WorldPacket& recvPacket); - void HandleSpiritHealerActivateOpcode(WorldPacket& recvPacket); - void HandleNpcTextQueryOpcode(WorldPacket& recvPacket); - void HandleBinderActivateOpcode(WorldPacket& recvPacket); - void HandleListStabledPetsOpcode(WorldPacket& recvPacket); - void HandleStablePet(WorldPacket& recvPacket); - void HandleUnstablePet(WorldPacket& recvPacket); - void HandleBuyStableSlot(WorldPacket& recvPacket); - void HandleStableRevivePet(WorldPacket& recvPacket); - void HandleStableSwapPet(WorldPacket& recvPacket); - - void HandleDuelAcceptedOpcode(WorldPacket& recvPacket); - void HandleDuelCancelledOpcode(WorldPacket& recvPacket); - - void HandleAcceptTradeOpcode(WorldPacket& recvPacket); - void HandleBeginTradeOpcode(WorldPacket& recvPacket); - void HandleBusyTradeOpcode(WorldPacket& recvPacket); - void HandleCancelTradeOpcode(WorldPacket& recvPacket); - void HandleClearTradeItemOpcode(WorldPacket& recvPacket); - void HandleIgnoreTradeOpcode(WorldPacket& recvPacket); - void HandleInitiateTradeOpcode(WorldPacket& recvPacket); - void HandleSetTradeGoldOpcode(WorldPacket& recvPacket); - void HandleSetTradeItemOpcode(WorldPacket& recvPacket); - void HandleUnacceptTradeOpcode(WorldPacket& recvPacket); - - void HandleAuctionHelloOpcode(WorldPacket& recvPacket); - void HandleAuctionListItems(WorldPacket & recv_data); - void HandleAuctionListBidderItems(WorldPacket & recv_data); - void HandleAuctionSellItem(WorldPacket & recv_data); - void HandleAuctionRemoveItem(WorldPacket & recv_data); - void HandleAuctionListOwnerItems(WorldPacket & recv_data); - void HandleAuctionPlaceBid(WorldPacket & recv_data); - void HandleAuctionListPendingSales(WorldPacket & recv_data); - - void HandleGetMailList(WorldPacket & recv_data); - void HandleSendMail(WorldPacket & recv_data); - void HandleMailTakeMoney(WorldPacket & recv_data); - void HandleMailTakeItem(WorldPacket & recv_data); - void HandleMailMarkAsRead(WorldPacket & recv_data); - void HandleMailReturnToSender(WorldPacket & recv_data); - void HandleMailDelete(WorldPacket & recv_data); - void HandleItemTextQuery(WorldPacket & recv_data); - void HandleMailCreateTextItem(WorldPacket & recv_data); - void HandleQueryNextMailTime(WorldPacket & recv_data); - void HandleCancelChanneling(WorldPacket & recv_data); - - void SendItemPageInfo(ItemPrototype *itemProto); - void HandleSplitItemOpcode(WorldPacket& recvPacket); - void HandleSwapInvItemOpcode(WorldPacket& recvPacket); - void HandleDestroyItemOpcode(WorldPacket& recvPacket); - void HandleAutoEquipItemOpcode(WorldPacket& recvPacket); - void HandleItemQuerySingleOpcode(WorldPacket& recvPacket); - void HandleSellItemOpcode(WorldPacket& recvPacket); - void HandleBuyItemInSlotOpcode(WorldPacket& recvPacket); - void HandleBuyItemOpcode(WorldPacket& recvPacket); - void HandleListInventoryOpcode(WorldPacket& recvPacket); - void HandleAutoStoreBagItemOpcode(WorldPacket& recvPacket); - void HandleReadItem(WorldPacket& recvPacket); - void HandleAutoEquipItemSlotOpcode(WorldPacket & recvPacket); - void HandleSwapItem(WorldPacket & recvPacket); - void HandleBuybackItem(WorldPacket & recvPacket); - void HandleAutoBankItemOpcode(WorldPacket& recvPacket); - void HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket); - void HandleWrapItemOpcode(WorldPacket& recvPacket); - - void HandleAttackSwingOpcode(WorldPacket& recvPacket); - void HandleAttackStopOpcode(WorldPacket& recvPacket); - void HandleSetSheathedOpcode(WorldPacket& recvPacket); - - void HandleUseItemOpcode(WorldPacket& recvPacket); - void HandleOpenItemOpcode(WorldPacket& recvPacket); - void HandleCastSpellOpcode(WorldPacket& recvPacket); - void HandleCancelCastOpcode(WorldPacket& recvPacket); - void HandleCancelAuraOpcode(WorldPacket& recvPacket); - void HandleCancelGrowthAuraOpcode(WorldPacket& recvPacket); - void HandleCancelAutoRepeatSpellOpcode(WorldPacket& recvPacket); - - void HandleLearnTalentOpcode(WorldPacket& recvPacket); - void HandleLearnPreviewTalents(WorldPacket& recvPacket); - void HandleTalentWipeConfirmOpcode(WorldPacket& recvPacket); - void HandleUnlearnSkillOpcode(WorldPacket& recvPacket); - - void HandleQuestgiverStatusQueryOpcode(WorldPacket& recvPacket); - void HandleQuestgiverStatusMultipleQuery(WorldPacket& recvPacket); - void HandleQuestgiverHelloOpcode(WorldPacket& recvPacket); - void HandleQuestgiverAcceptQuestOpcode(WorldPacket& recvPacket); - void HandleQuestgiverQueryQuestOpcode(WorldPacket& recvPacket); - void HandleQuestgiverChooseRewardOpcode(WorldPacket& recvPacket); - void HandleQuestgiverRequestRewardOpcode(WorldPacket& recvPacket); - void HandleQuestQueryOpcode(WorldPacket& recvPacket); - void HandleQuestgiverCancel(WorldPacket& recv_data); - void HandleQuestLogSwapQuest(WorldPacket& recv_data); - void HandleQuestLogRemoveQuest(WorldPacket& recv_data); - void HandleQuestConfirmAccept(WorldPacket& recv_data); - void HandleQuestgiverCompleteQuest(WorldPacket& recv_data); - void HandleQuestgiverQuestAutoLaunch(WorldPacket& recvPacket); - void HandlePushQuestToParty(WorldPacket& recvPacket); - void HandleQuestPushResult(WorldPacket& recvPacket); - - bool processChatmessageFurtherAfterSecurityChecks(std::string&, uint32); - void HandleMessagechatOpcode(WorldPacket& recvPacket); - void SendPlayerNotFoundNotice(std::string name); - void SendPlayerAmbiguousNotice(std::string name); - void SendWrongFactionNotice(); - void SendChatRestrictedNotice(ChatRestrictionType restriction); - void HandleTextEmoteOpcode(WorldPacket& recvPacket); - void HandleChatIgnoredOpcode(WorldPacket& recvPacket); - - void HandleReclaimCorpseOpcode(WorldPacket& recvPacket); - void HandleCorpseQueryOpcode(WorldPacket& recvPacket); - void HandleCorpseMapPositionQuery(WorldPacket& recvPacket); - void HandleResurrectResponseOpcode(WorldPacket& recvPacket); - void HandleSummonResponseOpcode(WorldPacket& recv_data); - - void HandleJoinChannel(WorldPacket& recvPacket); - void HandleLeaveChannel(WorldPacket& recvPacket); - void HandleChannelList(WorldPacket& recvPacket); - void HandleChannelPassword(WorldPacket& recvPacket); - void HandleChannelSetOwner(WorldPacket& recvPacket); - void HandleChannelOwner(WorldPacket& recvPacket); - void HandleChannelModerator(WorldPacket& recvPacket); - void HandleChannelUnmoderator(WorldPacket& recvPacket); - void HandleChannelMute(WorldPacket& recvPacket); - void HandleChannelUnmute(WorldPacket& recvPacket); - void HandleChannelInvite(WorldPacket& recvPacket); - void HandleChannelKick(WorldPacket& recvPacket); - void HandleChannelBan(WorldPacket& recvPacket); - void HandleChannelUnban(WorldPacket& recvPacket); - void HandleChannelAnnouncements(WorldPacket& recvPacket); - void HandleChannelModerate(WorldPacket& recvPacket); - void HandleChannelDeclineInvite(WorldPacket& recvPacket); - void HandleChannelDisplayListQuery(WorldPacket& recvPacket); - void HandleGetChannelMemberCount(WorldPacket& recvPacket); - void HandleSetChannelWatch(WorldPacket& recvPacket); - - void HandleCompleteCinematic(WorldPacket& recvPacket); - void HandleNextCinematicCamera(WorldPacket& recvPacket); - - void HandlePageQuerySkippedOpcode(WorldPacket& recvPacket); - void HandlePageTextQueryOpcode(WorldPacket& recvPacket); - - void HandleTutorialFlag (WorldPacket & recv_data); - void HandleTutorialClear(WorldPacket & recv_data); - void HandleTutorialReset(WorldPacket & recv_data); - - //Pet - void HandlePetAction(WorldPacket & recv_data); - void HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid, uint16 flag, uint64 guid2); - void HandlePetNameQuery(WorldPacket & recv_data); - void HandlePetSetAction(WorldPacket & recv_data); - void HandlePetAbandon(WorldPacket & recv_data); - void HandlePetRename(WorldPacket & recv_data); - void HandlePetCancelAuraOpcode(WorldPacket& recvPacket); - void HandlePetUnlearnOpcode(WorldPacket& recvPacket); - void HandlePetSpellAutocastOpcode(WorldPacket& recvPacket); - void HandlePetCastSpellOpcode(WorldPacket& recvPacket); - void HandlePetLearnTalent(WorldPacket& recvPacket); - void HandleLearnPreviewTalentsPet(WorldPacket& recvPacket); - - void HandleSetActionBarToggles(WorldPacket& recv_data); - - void HandleCharRenameOpcode(WorldPacket& recv_data); - static void HandleChangePlayerNameOpcodeCallBack(QueryResult_AutoPtr result, uint32 accountId, std::string newname); - void HandleSetPlayerDeclinedNames(WorldPacket& recv_data); - - void HandleTotemDestroyed(WorldPacket& recv_data); - void HandleDismissCritter(WorldPacket& recv_data); - - //BattleGround - void HandleBattlemasterHelloOpcode(WorldPacket &recv_data); - void HandleBattlemasterJoinOpcode(WorldPacket &recv_data); - void HandleBattleGroundPlayerPositionsOpcode(WorldPacket& recv_data); - void HandlePVPLogDataOpcode(WorldPacket &recv_data); - void HandleBattleFieldPortOpcode(WorldPacket &recv_data); - void HandleBattlefieldListOpcode(WorldPacket &recv_data); - void HandleLeaveBattlefieldOpcode(WorldPacket &recv_data); - void HandleBattlemasterJoinArena(WorldPacket &recv_data); - void HandleReportPvPAFK(WorldPacket &recv_data); - - void HandleWardenDataOpcode(WorldPacket& recv_data); - void HandleWorldTeleportOpcode(WorldPacket& recv_data); - void HandleMinimapPingOpcode(WorldPacket& recv_data); - void HandleRandomRollOpcode(WorldPacket& recv_data); - void HandleFarSightOpcode(WorldPacket& recv_data); - void HandleSetDungeonDifficultyOpcode(WorldPacket& recv_data); - void HandleSetRaidDifficultyOpcode(WorldPacket& recv_data); - void HandleMoveSetCanFlyAckOpcode(WorldPacket& recv_data); - void HandleSetTitleOpcode(WorldPacket& recv_data); - void HandleRealmSplitOpcode(WorldPacket& recv_data); - void HandleTimeSyncResp(WorldPacket& recv_data); - void HandleWhoisOpcode(WorldPacket& recv_data); - void HandleResetInstancesOpcode(WorldPacket& recv_data); - - // Looking for Dungeon/Raid - void HandleSetLfgCommentOpcode(WorldPacket & recv_data); - void HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& recv_data); - void HandleLfgPartyLockInfoRequestOpcode(WorldPacket& recv_data); - void HandleLfgJoinOpcode(WorldPacket &recv_data); - void HandleLfgLeaveOpcode(WorldPacket & /*recv_data*/); - void HandleLfgSetRolesOpcode(WorldPacket &recv_data); - void SendLfgUpdatePlayer(uint8 updateType); - void SendLfgUpdateParty(uint8 updateType); - void SendLfgRoleChosen(uint64 guid, uint8 roles); - void SendLfgUpdateSearch(bool update); - void SendLfgJoinResult(uint8 checkResult, uint8 checkValue); - void SendLfgQueueStatus(uint32 dungeon, int32 waitTime, int32 avgWaitTime, int32 waitTimeTanks, int32 waitTimeHealer, int32 waitTimeDps, uint32 queuedTime, uint8 tanks, uint8 healers, uint8 dps); - - // Arena Team - void HandleInspectArenaTeamsOpcode(WorldPacket& recv_data); - void HandleArenaTeamQueryOpcode(WorldPacket& recv_data); - void HandleArenaTeamRosterOpcode(WorldPacket& recv_data); - void HandleArenaTeamInviteOpcode(WorldPacket& recv_data); - void HandleArenaTeamAcceptOpcode(WorldPacket& recv_data); - void HandleArenaTeamDeclineOpcode(WorldPacket& recv_data); - void HandleArenaTeamLeaveOpcode(WorldPacket& recv_data); - void HandleArenaTeamRemoveOpcode(WorldPacket& recv_data); - void HandleArenaTeamDisbandOpcode(WorldPacket& recv_data); - void HandleArenaTeamLeaderOpcode(WorldPacket& recv_data); - - void HandleAreaSpiritHealerQueryOpcode(WorldPacket& recv_data); - void HandleAreaSpiritHealerQueueOpcode(WorldPacket& recv_data); - void HandleCancelMountAuraOpcode(WorldPacket& recv_data); - void HandleSelfResOpcode(WorldPacket& recv_data); - void HandleComplainOpcode(WorldPacket& recv_data); - void HandleRequestPetInfoOpcode(WorldPacket& recv_data); - - // Socket gem - void HandleSocketOpcode(WorldPacket& recv_data); - - void HandleCancelTempEnchantmentOpcode(WorldPacket& recv_data); - - void HandleItemRefundInfoRequest(WorldPacket& recv_data); - void HandleItemRefund(WorldPacket& recv_data); - - void HandleChannelVoiceOnOpcode(WorldPacket & recv_data); - void HandleVoiceSessionEnableOpcode(WorldPacket& recv_data); - void HandleSetActiveVoiceChannel(WorldPacket& recv_data); - void HandleSetTaxiBenchmarkOpcode(WorldPacket& recv_data); - - // Guild Bank - void HandleGuildPermissions(WorldPacket& recv_data); - void HandleGuildBankMoneyWithdrawn(WorldPacket& recv_data); - void HandleGuildBankerActivate(WorldPacket& recv_data); - void HandleGuildBankQueryTab(WorldPacket& recv_data); - void HandleGuildBankLogQuery(WorldPacket& recv_data); - void HandleGuildBankDepositMoney(WorldPacket& recv_data); - void HandleGuildBankWithdrawMoney(WorldPacket& recv_data); - void HandleGuildBankSwapItems(WorldPacket& recv_data); - - void HandleGuildBankUpdateTab(WorldPacket& recv_data); - void HandleGuildBankBuyTab(WorldPacket& recv_data); - void HandleQueryGuildBankTabText(WorldPacket& recv_data); - void HandleSetGuildBankTabText(WorldPacket& recv_data); - - // Calendar - void HandleCalendarGetCalendar(WorldPacket& recv_data); - void HandleCalendarGetEvent(WorldPacket& recv_data); - void HandleCalendarGuildFilter(WorldPacket& recv_data); - void HandleCalendarArenaTeam(WorldPacket& recv_data); - void HandleCalendarAddEvent(WorldPacket& recv_data); - void HandleCalendarUpdateEvent(WorldPacket& recv_data); - void HandleCalendarRemoveEvent(WorldPacket& recv_data); - void HandleCalendarCopyEvent(WorldPacket& recv_data); - void HandleCalendarEventInvite(WorldPacket& recv_data); - void HandleCalendarEventRsvp(WorldPacket& recv_data); - void HandleCalendarEventRemoveInvite(WorldPacket& recv_data); - void HandleCalendarEventStatus(WorldPacket& recv_data); - void HandleCalendarEventModeratorStatus(WorldPacket& recv_data); - void HandleCalendarComplain(WorldPacket& recv_data); - void HandleCalendarGetNumPending(WorldPacket& recv_data); - - void HandleSpellClick(WorldPacket& recv_data); - void HandleMirrrorImageDataRequest(WorldPacket & recv_data); - void HandleAlterAppearance(WorldPacket& recv_data); - void HandleRemoveGlyph(WorldPacket& recv_data); - void HandleCharCustomize(WorldPacket& recv_data); - void HandleQueryInspectAchievements(WorldPacket& recv_data); - void HandleEquipmentSetSave(WorldPacket& recv_data); - void HandleEquipmentSetDelete(WorldPacket& recv_data); - void HandleEquipmentSetUse(WorldPacket& recv_data); - void HandleWorldStateUITimerUpdate(WorldPacket& recv_data); - void HandleReadyForAccountDataTimes(WorldPacket& recv_data); - void HandleQueryQuestsCompleted(WorldPacket& recv_data); - void HandleQuestPOIQuery(WorldPacket& recv_data); - void HandleOnPVPKill(Player *killed); - bool HandleOnPlayerChat(const char *text); - uint32 HandleOnGetXP(uint32 amount); - int32 HandleOnGetMoney(int32 amount); - void HandleOnAreaChange(AreaTableEntry const *pArea); - bool HandleOnItemClick(Item *pItem); - bool HandleOnItemOpen(Item *pItem); - bool HandleOnGoClick(GameObject *pGameObject); - void HandleOnCreatureKill(Creature *pCreature); - void HandleEjectPasenger(WorldPacket &data); - void HandleEnterPlayerVehicle(WorldPacket &data); - private: - // private trade methods - void moveItems(Item* myItems[], Item* hisItems[]); - - // logging helper - void LogUnexpectedOpcode(WorldPacket *packet, const char * reason); - void LogUnprocessedTail(WorldPacket *packet); - - uint32 m_GUIDLow; // set loggined or recently logout player (while m_playerRecentlyLogout set) - Player *_player; - WorldSocket *m_Socket; - std::string m_Address; - - AccountTypes _security; - uint32 _accountId; - uint8 m_expansion; - - time_t _logoutTime; - bool m_inQueue; // session wait in auth.queue - bool m_playerLoading; // code processed in LoginPlayer - bool m_playerLogout; // code processed in LogoutPlayer - bool m_playerRecentlyLogout; - bool m_playerSave; - LocaleConstant m_sessionDbcLocale; - int m_sessionDbLocaleIndex; - uint32 m_latency; - AccountData m_accountData[NUM_ACCOUNT_DATA_TYPES]; - uint32 m_Tutorials[8]; - bool m_TutorialsChanged; - AddonsList m_addonsList; - ACE_Based::LockedQueue _recvQueue; -}; -#endif -/// @} diff --git a/src/server/game/World/WorldSocket.cpp b/src/server/game/World/WorldSocket.cpp deleted file mode 100644 index c07b369d0b9..00000000000 --- a/src/server/game/World/WorldSocket.cpp +++ /dev/null @@ -1,1064 +0,0 @@ -/* -* Copyright (C) 2005-2009 MaNGOS -* -* Copyright (C) 2008-2010 Trinity -* -* 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, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "WorldSocket.h" -#include "Common.h" - -#include "Util.h" -#include "World.h" -#include "WorldPacket.h" -#include "SharedDefines.h" -#include "ByteBuffer.h" -#include "Opcodes.h" -#include "Database/DatabaseEnv.h" -#include "Auth/BigNumber.h" -#include "Auth/Sha1.h" -#include "WorldSession.h" -#include "WorldSocketMgr.h" -#include "Log.h" -#include "WorldLog.h" - -#if defined(__GNUC__) -#pragma pack(1) -#else -#pragma pack(push,1) -#endif - -struct ServerPktHeader -{ - /** - * size is the length of the payload _plus_ the length of the opcode - */ - ServerPktHeader(uint32 size, uint16 cmd) : size(size) - { - uint8 headerIndex=0; - if (isLargePacket()) - { - sLog.outDebug("initializing large server to client packet. Size: %u, cmd: %u", size, cmd); - header[headerIndex++] = 0x80|(0xFF &(size>>16)); - } - header[headerIndex++] = 0xFF &(size>>8); - header[headerIndex++] = 0xFF &size; - - header[headerIndex++] = 0xFF & cmd; - header[headerIndex++] = 0xFF & (cmd>>8); - } - - uint8 getHeaderLength() - { - // cmd = 2 bytes, size= 2||3bytes - return 2+(isLargePacket()?3:2); - } - - bool isLargePacket() - { - return size > 0x7FFF; - } - - const uint32 size; - uint8 header[5]; -}; - -struct ClientPktHeader -{ - uint16 size; - uint32 cmd; -}; - -#if defined(__GNUC__) -#pragma pack() -#else -#pragma pack(pop) -#endif - -WorldSocket::WorldSocket (void) : -WorldHandler(), -m_Session(0), -m_RecvWPct(0), -m_RecvPct(), -m_Header(sizeof (ClientPktHeader)), -m_OutBuffer(0), -m_OutBufferSize(65536), -m_OutActive(false), -m_Seed(static_cast (rand32())), -m_OverSpeedPings(0), -m_LastPingTime(ACE_Time_Value::zero) -{ - reference_counting_policy().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED); - - msg_queue()->high_water_mark(8*1024*1024); - msg_queue()->low_water_mark(8*1024*1024); -} - -WorldSocket::~WorldSocket (void) -{ - if (m_RecvWPct) - delete m_RecvWPct; - - if (m_OutBuffer) - m_OutBuffer->release(); - - closing_ = true; - - peer().close(); -} - -bool WorldSocket::IsClosed (void) const -{ - return closing_; -} - -void WorldSocket::CloseSocket (void) -{ - { - ACE_GUARD (LockType, Guard, m_OutBufferLock); - - if (closing_) - return; - - closing_ = true; - peer().close_writer(); - } - - { - ACE_GUARD (LockType, Guard, m_SessionLock); - - m_Session = NULL; - } -} - -const std::string& WorldSocket::GetRemoteAddress (void) const -{ - return m_Address; -} - -int WorldSocket::SendPacket (const WorldPacket& pct) -{ - ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); - - if (closing_) - return -1; - - // Dump outgoing packet. - if (sWorldLog.LogWorld()) - { - sWorldLog.outTimestampLog ("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", - (uint32) get_handle(), - pct.size(), - LookupOpcodeName (pct.GetOpcode()), - pct.GetOpcode()); - - uint32 p = 0; - while (p < pct.size()) - { - for (uint32 j = 0; j < 16 && p < pct.size(); j++) - sWorldLog.outLog("%.2X ", const_cast(pct)[p++]); - - sWorldLog.outLog("\n"); - } - sWorldLog.outLog("\n"); - } - - ServerPktHeader header(pct.size()+2, pct.GetOpcode()); - m_Crypt.EncryptSend ((uint8*)header.header, header.getHeaderLength()); - - if (m_OutBuffer->space() >= pct.size() + header.getHeaderLength() && msg_queue()->is_empty()) - { - // Put the packet on the buffer. - if (m_OutBuffer->copy((char*) header.header, header.getHeaderLength()) == -1) - ACE_ASSERT (false); - - if (!pct.empty()) - if (m_OutBuffer->copy((char*) pct.contents(), pct.size()) == -1) - ACE_ASSERT (false); - } - else - { - // Enqueue the packet. - ACE_Message_Block* mb; - - ACE_NEW_RETURN(mb, ACE_Message_Block(pct.size() + header.getHeaderLength()), -1); - - mb->copy((char*) header.header, header.getHeaderLength()); - - if (!pct.empty()) - mb->copy((const char*)pct.contents(), pct.size()); - - if (msg_queue()->enqueue_tail(mb,(ACE_Time_Value*)&ACE_Time_Value::zero) == -1) - { - sLog.outError("WorldSocket::SendPacket enqueue_tail failed"); - mb->release(); - return -1; - } - } - - return 0; -} - -long WorldSocket::AddReference (void) -{ - return static_cast (add_reference()); -} - -long WorldSocket::RemoveReference (void) -{ - return static_cast (remove_reference()); -} - -int WorldSocket::open (void *a) -{ - ACE_UNUSED_ARG (a); - - // Prevent double call to this func. - if (m_OutBuffer) - return -1; - - // This will also prevent the socket from being Updated - // while we are initializing it. - m_OutActive = true; - - // Hook for the manager. - if (sWorldSocketMgr->OnSocketOpen(this) == -1) - return -1; - - // Allocate the buffer. - ACE_NEW_RETURN (m_OutBuffer, ACE_Message_Block (m_OutBufferSize), -1); - - // Store peer address. - ACE_INET_Addr remote_addr; - - if (peer().get_remote_addr(remote_addr) == -1) - { - sLog.outError ("WorldSocket::open: peer().get_remote_addr errno = %s", ACE_OS::strerror (errno)); - return -1; - } - - m_Address = remote_addr.get_host_addr(); - - // Send startup packet. - WorldPacket packet (SMSG_AUTH_CHALLENGE, 24); - packet << uint32(1); // 1...31 - packet << m_Seed; - - BigNumber seed1; - seed1.SetRand(16 * 8); - packet.append(seed1.AsByteArray(16), 16); // new encryption seeds - - BigNumber seed2; - seed2.SetRand(16 * 8); - packet.append(seed2.AsByteArray(16), 16); // new encryption seeds - - if (SendPacket(packet) == -1) - return -1; - - // Register with ACE Reactor - if (reactor()->register_handler(this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK) == -1) - { - sLog.outError ("WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno)); - return -1; - } - - // reactor takes care of the socket from now on - remove_reference(); - - return 0; -} - -int WorldSocket::close (int) -{ - shutdown(); - - closing_ = true; - - remove_reference(); - - return 0; -} - -int WorldSocket::handle_input (ACE_HANDLE) -{ - if (closing_) - return -1; - - switch (handle_input_missing_data()) - { - case -1 : - { - if ((errno == EWOULDBLOCK) || - (errno == EAGAIN)) - { - return Update(); // interesting line ,isn't it ? - } - - DEBUG_LOG("WorldSocket::handle_input: Peer error closing connection errno = %s", ACE_OS::strerror (errno)); - - errno = ECONNRESET; - return -1; - } - case 0: - { - DEBUG_LOG("WorldSocket::handle_input: Peer has closed connection"); - - errno = ECONNRESET; - return -1; - } - case 1: - return 1; - default: - return Update(); // another interesting line ;) - } - - ACE_NOTREACHED(return -1); -} - -int WorldSocket::handle_output (ACE_HANDLE) -{ - ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); - - if (closing_) - return -1; - - size_t send_len = m_OutBuffer->length(); - - if (send_len == 0) - return handle_output_queue(Guard); - -#ifdef MSG_NOSIGNAL - ssize_t n = peer().send (m_OutBuffer->rd_ptr(), send_len, MSG_NOSIGNAL); -#else - ssize_t n = peer().send (m_OutBuffer->rd_ptr(), send_len); -#endif // MSG_NOSIGNAL - - if (n == 0) - return -1; - else if (n == -1) - { - if (errno == EWOULDBLOCK || errno == EAGAIN) - return schedule_wakeup_output (Guard); - - return -1; - } - else if (n < (ssize_t)send_len) //now n > 0 - { - m_OutBuffer->rd_ptr (static_cast (n)); - - // move the data to the base of the buffer - m_OutBuffer->crunch(); - - return schedule_wakeup_output (Guard); - } - else //now n == send_len - { - m_OutBuffer->reset(); - - return handle_output_queue (Guard); - } - - ACE_NOTREACHED (return 0); -} - -int WorldSocket::handle_output_queue (GuardType& g) -{ - if (msg_queue()->is_empty()) - return cancel_wakeup_output(g); - - ACE_Message_Block *mblk; - - if (msg_queue()->dequeue_head(mblk, (ACE_Time_Value*)&ACE_Time_Value::zero) == -1) - { - sLog.outError("WorldSocket::handle_output_queue dequeue_head"); - return -1; - } - - const size_t send_len = mblk->length(); - -#ifdef MSG_NOSIGNAL - ssize_t n = peer().send (mblk->rd_ptr(), send_len, MSG_NOSIGNAL); -#else - ssize_t n = peer().send (mblk->rd_ptr(), send_len); -#endif // MSG_NOSIGNAL - - if (n == 0) - { - mblk->release(); - - return -1; - } - else if (n == -1) - { - if (errno == EWOULDBLOCK || errno == EAGAIN) - { - msg_queue()->enqueue_head(mblk, (ACE_Time_Value*) &ACE_Time_Value::zero); - return schedule_wakeup_output (g); - } - - mblk->release(); - return -1; - } - else if (n < (ssize_t)send_len) //now n > 0 - { - mblk->rd_ptr(static_cast (n)); - - if (msg_queue()->enqueue_head(mblk, (ACE_Time_Value*) &ACE_Time_Value::zero) == -1) - { - sLog.outError("WorldSocket::handle_output_queue enqueue_head"); - mblk->release(); - return -1; - } - - return schedule_wakeup_output (g); - } - else //now n == send_len - { - mblk->release(); - - return msg_queue()->is_empty() ? cancel_wakeup_output(g) : ACE_Event_Handler::WRITE_MASK; - } - - ACE_NOTREACHED(return -1); -} - -int WorldSocket::handle_close (ACE_HANDLE h, ACE_Reactor_Mask) -{ - // Critical section - { - ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); - - closing_ = true; - - if (h == ACE_INVALID_HANDLE) - peer().close_writer(); - } - - // Critical section - { - ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); - - m_Session = NULL; - } - - return 0; -} - -int WorldSocket::Update (void) -{ - if (closing_) - return -1; - - if (m_OutActive || (m_OutBuffer->length() == 0 && msg_queue()->is_empty())) - return 0; - - int ret; - do - ret = handle_output (get_handle()); - while (ret > 0); - - return ret; -} - -int WorldSocket::handle_input_header (void) -{ - ACE_ASSERT (m_RecvWPct == NULL); - - ACE_ASSERT (m_Header.length() == sizeof(ClientPktHeader)); - - m_Crypt.DecryptRecv ((uint8*) m_Header.rd_ptr(), sizeof(ClientPktHeader)); - - ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr()); - - EndianConvertReverse(header.size); - EndianConvert(header.cmd); - - if ((header.size < 4) || (header.size > 10240) || (header.cmd > 10240)) - { - sLog.outError ("WorldSocket::handle_input_header: client sent malformed packet size = %d , cmd = %d", - header.size, header.cmd); - - errno = EINVAL; - return -1; - } - - header.size -= 4; - - ACE_NEW_RETURN (m_RecvWPct, WorldPacket ((uint16) header.cmd, header.size), -1); - - if (header.size > 0) - { - m_RecvWPct->resize (header.size); - m_RecvPct.base ((char*) m_RecvWPct->contents(), m_RecvWPct->size()); - } - else - { - ACE_ASSERT(m_RecvPct.space() == 0); - } - - return 0; -} - -int WorldSocket::handle_input_payload (void) -{ - // set errno properly here on error !!! - // now have a header and payload - - ACE_ASSERT (m_RecvPct.space() == 0); - ACE_ASSERT (m_Header.space() == 0); - ACE_ASSERT (m_RecvWPct != NULL); - - const int ret = ProcessIncoming (m_RecvWPct); - - m_RecvPct.base (NULL, 0); - m_RecvPct.reset(); - m_RecvWPct = NULL; - - m_Header.reset(); - - if (ret == -1) - errno = EINVAL; - - return ret; -} - -int WorldSocket::handle_input_missing_data (void) -{ - char buf [4096]; - - ACE_Data_Block db (sizeof (buf), - ACE_Message_Block::MB_DATA, - buf, - 0, - 0, - ACE_Message_Block::DONT_DELETE, - 0); - - ACE_Message_Block message_block(&db, - ACE_Message_Block::DONT_DELETE, - 0); - - const size_t recv_size = message_block.space(); - - const ssize_t n = peer().recv (message_block.wr_ptr(), - recv_size); - - if (n <= 0) - return n; - - message_block.wr_ptr (n); - - while (message_block.length() > 0) - { - if (m_Header.space() > 0) - { - //need to receive the header - const size_t to_header = (message_block.length() > m_Header.space() ? m_Header.space() : message_block.length()); - m_Header.copy (message_block.rd_ptr(), to_header); - message_block.rd_ptr (to_header); - - if (m_Header.space() > 0) - { - // Couldn't receive the whole header this time. - ACE_ASSERT (message_block.length() == 0); - errno = EWOULDBLOCK; - return -1; - } - - // We just received nice new header - if (handle_input_header() == -1) - { - ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); - return -1; - } - } - - // Its possible on some error situations that this happens - // for example on closing when epoll receives more chunked data and stuff - // hope this is not hack ,as proper m_RecvWPct is asserted around - if (!m_RecvWPct) - { - sLog.outError ("Forcing close on input m_RecvWPct = NULL"); - errno = EINVAL; - return -1; - } - - // We have full read header, now check the data payload - if (m_RecvPct.space() > 0) - { - //need more data in the payload - const size_t to_data = (message_block.length() > m_RecvPct.space() ? m_RecvPct.space() : message_block.length()); - m_RecvPct.copy (message_block.rd_ptr(), to_data); - message_block.rd_ptr (to_data); - - if (m_RecvPct.space() > 0) - { - // Couldn't receive the whole data this time. - ACE_ASSERT (message_block.length() == 0); - errno = EWOULDBLOCK; - return -1; - } - } - - //just received fresh new payload - if (handle_input_payload() == -1) - { - ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); - return -1; - } - } - - return n == recv_size ? 1 : 2; -} - -int WorldSocket::cancel_wakeup_output (GuardType& g) -{ - if (!m_OutActive) - return 0; - - m_OutActive = false; - - g.release(); - - if (reactor()->cancel_wakeup - (this, ACE_Event_Handler::WRITE_MASK) == -1) - { - // would be good to store errno from reactor with errno guard - sLog.outError ("WorldSocket::cancel_wakeup_output"); - return -1; - } - - return 0; -} - -int WorldSocket::schedule_wakeup_output (GuardType& g) -{ - if (m_OutActive) - return 0; - - m_OutActive = true; - - g.release(); - - if (reactor()->schedule_wakeup - (this, ACE_Event_Handler::WRITE_MASK) == -1) - { - sLog.outError ("WorldSocket::schedule_wakeup_output"); - return -1; - } - - return 0; -} - -int WorldSocket::ProcessIncoming (WorldPacket* new_pct) -{ - ACE_ASSERT (new_pct); - - // manage memory ;) - ACE_Auto_Ptr aptr (new_pct); - - const ACE_UINT16 opcode = new_pct->GetOpcode(); - - if (closing_) - return -1; - - // Dump received packet. - if (sWorldLog.LogWorld()) - { - sWorldLog.outTimestampLog ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", - (uint32) get_handle(), - new_pct->size(), - LookupOpcodeName (new_pct->GetOpcode()), - new_pct->GetOpcode()); - - uint32 p = 0; - while (p < new_pct->size()) - { - for (uint32 j = 0; j < 16 && p < new_pct->size(); j++) - sWorldLog.outLog ("%.2X ", (*new_pct)[p++]); - - sWorldLog.outLog ("\n"); - } - sWorldLog.outLog ("\n"); - } - - try { - switch(opcode) - { - case CMSG_PING: - return HandlePing (*new_pct); - case CMSG_AUTH_SESSION: - if (m_Session) - { - sLog.outError ("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again"); - return -1; - } - - return HandleAuthSession (*new_pct); - case CMSG_KEEP_ALIVE: - DEBUG_LOG ("CMSG_KEEP_ALIVE ,size: %d", new_pct->size()); - - return 0; - default: - { - ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); - - if (m_Session != NULL) - { - // Our Idle timer will reset on any non PING opcodes. - // Catches people idling on the login screen and any lingering ingame connections. - m_Session->ResetTimeOutTime(); - - // OK ,give the packet to WorldSession - aptr.release(); - // WARNINIG here we call it with locks held. - // Its possible to cause deadlock if QueuePacket calls back - m_Session->QueuePacket (new_pct); - return 0; - } - else - { - sLog.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = %u", uint32(opcode)); - return -1; - } - } - } - } - catch(ByteBufferException &) - { - sLog.outError("WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet (opcode: %u) from client %s, accountid=%i. Disconnected client.", - opcode, GetRemoteAddress().c_str(), m_Session?m_Session->GetAccountId():-1); - if (sLog.IsOutDebug()) - { - sLog.outDebug("Dumping error causing packet:"); - new_pct->hexlike(); - } - - return -1; - } - - ACE_NOTREACHED (return 0); -} - -int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) -{ - // NOTE: ATM the socket is singlethread, have this in mind ... - uint8 digest[20]; - uint32 clientSeed; - uint32 unk2, unk3; - uint64 unk4; - uint32 BuiltNumberClient; - uint32 id, security; - //uint8 expansion = 0; - LocaleConstant locale; - std::string account; - Sha1Hash sha1; - BigNumber v, s, g, N; - WorldPacket packet, SendAddonPacked; - - BigNumber K; - - if (sWorld.IsClosed()) - { - packet.Initialize(SMSG_AUTH_RESPONSE, 1); - packet << uint8(AUTH_REJECT); - SendPacket (packet); - - sLog.outError ("WorldSocket::HandleAuthSession: World closed, denying client (%s).", m_Session->GetRemoteAddress().c_str()); - return -1; - } - - // Read the content of the packet - recvPacket >> BuiltNumberClient; // for now no use - recvPacket >> unk2; - recvPacket >> account; - recvPacket >> unk3; - recvPacket >> clientSeed; - recvPacket >> unk4; - recvPacket.read (digest, 20); - - DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, unk3 %u, clientseed %u", - BuiltNumberClient, - unk2, - account.c_str(), - unk3, - clientSeed); - - // Get the account information from the realmd database - std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below - LoginDatabase.escape_string (safe_account); - // No SQL injection, username escaped. - - QueryResult_AutoPtr result = - LoginDatabase.PQuery ("SELECT " - "id, " //0 - "sessionkey, " //1 - "last_ip, " //2 - "locked, " //3 - "v, " //4 - "s, " //5 - "expansion, " //6 - "mutetime, " //7 - "locale " //8 - "FROM account " - "WHERE username = '%s'", - safe_account.c_str()); - - // Stop if the account is not found - if (!result) - { - packet.Initialize (SMSG_AUTH_RESPONSE, 1); - packet << uint8 (AUTH_UNKNOWN_ACCOUNT); - - SendPacket (packet); - - sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); - return -1; - } - - Field* fields = result->Fetch(); - - uint8 expansion = fields[6].GetUInt8(); - uint32 world_expansion = sWorld.getConfig(CONFIG_EXPANSION); - if (expansion > world_expansion) - expansion = world_expansion; - //expansion = ((sWorld.getConfig(CONFIG_EXPANSION) > fields[6].GetUInt8()) ? fields[6].GetUInt8() : sWorld.getConfig(CONFIG_EXPANSION)); - - N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); - g.SetDword (7); - - v.SetHexStr(fields[4].GetString()); - s.SetHexStr (fields[5].GetString()); - - const char* sStr = s.AsHexStr(); //Must be freed by OPENSSL_free() - const char* vStr = v.AsHexStr(); //Must be freed by OPENSSL_free() - - DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v: %s", - sStr, - vStr); - - OPENSSL_free ((void*) sStr); - OPENSSL_free ((void*) vStr); - - ///- Re-check ip locking (same check as in realmd). - if (fields[3].GetUInt8() == 1) // if ip is locked - { - if (strcmp (fields[2].GetString(), GetRemoteAddress().c_str())) - { - packet.Initialize (SMSG_AUTH_RESPONSE, 1); - packet << uint8 (AUTH_FAILED); - SendPacket (packet); - - sLog.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)."); - return -1; - } - } - - id = fields[0].GetUInt32(); - /* - if (security > SEC_ADMINISTRATOR) // prevent invalid security settings in DB - security = SEC_ADMINISTRATOR; - */ - - K.SetHexStr (fields[1].GetString()); - - time_t mutetime = time_t (fields[7].GetUInt64()); - - locale = LocaleConstant (fields[8].GetUInt8()); - if (locale >= MAX_LOCALE) - locale = LOCALE_enUS; - - // Checks gmlevel per Realm - result = - LoginDatabase.PQuery ("SELECT " - "RealmID, " //0 - "gmlevel " //1 - "FROM account_access " - "WHERE id = '%d'" - " AND (RealmID = '%d'" - " OR RealmID = '-1')", - id, realmID); - if (!result) - security = 0; - else - { - fields = result->Fetch(); - security = fields[1].GetInt32(); - } - - // Re-check account ban (same check as in realmd) - QueryResult_AutoPtr banresult = - LoginDatabase.PQuery ("SELECT 1 FROM account_banned WHERE id = %u AND active = 1 " - "UNION " - "SELECT 1 FROM ip_banned WHERE ip = '%s'", - id, GetRemoteAddress().c_str()); - - if (banresult) // if account banned - { - packet.Initialize (SMSG_AUTH_RESPONSE, 1); - packet << uint8 (AUTH_BANNED); - SendPacket (packet); - - sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); - return -1; - } - - // Check locked state for server - sWorld.UpdateAllowedSecurity(); - AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit(); - sLog.outDebug("Allowed Level: %u Player Level %u", allowedAccountType, AccountTypes(security)); - if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType) - { - WorldPacket Packet (SMSG_AUTH_RESPONSE, 1); - Packet << uint8 (AUTH_UNAVAILABLE); - - SendPacket (packet); - - sLog.outDetail ("WorldSocket::HandleAuthSession: User tries to login but his security level is not enough"); - return -1; - } - - // Check that Key and account name are the same on client and server - Sha1Hash sha; - - uint32 t = 0; - uint32 seed = m_Seed; - - sha.UpdateData (account); - sha.UpdateData ((uint8 *) & t, 4); - sha.UpdateData ((uint8 *) & clientSeed, 4); - sha.UpdateData ((uint8 *) & seed, 4); - sha.UpdateBigNumbers (&K, NULL); - sha.Finalize(); - - if (memcmp (sha.GetDigest(), digest, 20)) - { - packet.Initialize (SMSG_AUTH_RESPONSE, 1); - packet << uint8 (AUTH_FAILED); - - SendPacket (packet); - - sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed)."); - return -1; - } - - std::string address = GetRemoteAddress(); - - DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", - account.c_str(), - address.c_str()); - - // Update the last_ip in the database - // No SQL injection, username escaped. - LoginDatabase.escape_string (address); - - LoginDatabase.PExecute ("UPDATE account " - "SET last_ip = '%s' " - "WHERE username = '%s'", - address.c_str(), - safe_account.c_str()); - - // NOTE ATM the socket is single-threaded, have this in mind ... - ACE_NEW_RETURN (m_Session, WorldSession (id, this, AccountTypes(security), expansion, mutetime, locale), -1); - - m_Crypt.Init(&K); - - m_Session->LoadGlobalAccountData(); - m_Session->LoadTutorialsData(); - m_Session->ReadAddonsInfo(recvPacket); - - // Sleep this Network thread for - uint32 sleepTime = sWorld.getConfig(CONFIG_SESSION_ADD_DELAY); - ACE_OS::sleep (ACE_Time_Value (0, sleepTime)); - - sWorld.AddSession (m_Session); - - return 0; -} - -int WorldSocket::HandlePing (WorldPacket& recvPacket) -{ - uint32 ping; - uint32 latency; - - // Get the ping packet content - recvPacket >> ping; - recvPacket >> latency; - - if (m_LastPingTime == ACE_Time_Value::zero) - m_LastPingTime = ACE_OS::gettimeofday(); // for 1st ping - else - { - ACE_Time_Value cur_time = ACE_OS::gettimeofday(); - ACE_Time_Value diff_time (cur_time); - diff_time -= m_LastPingTime; - m_LastPingTime = cur_time; - - if (diff_time < ACE_Time_Value (27)) - { - ++m_OverSpeedPings; - - uint32 max_count = sWorld.getConfig (CONFIG_MAX_OVERSPEED_PINGS); - - if (max_count && m_OverSpeedPings > max_count) - { - ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); - - if (m_Session && m_Session->GetSecurity() == SEC_PLAYER) - { - sLog.outError ("WorldSocket::HandlePing: Player kicked for " - "over-speed pings address = %s", - GetRemoteAddress().c_str()); - - return -1; - } - } - } - else - m_OverSpeedPings = 0; - } - - // critical section - { - ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); - - if (m_Session) - m_Session->SetLatency (latency); - else - { - sLog.outError ("WorldSocket::HandlePing: peer sent CMSG_PING, " - "but is not authenticated or got recently kicked," - " address = %s", - GetRemoteAddress().c_str()); - return -1; - } - } - - WorldPacket packet (SMSG_PONG, 4); - packet << ping; - return SendPacket (packet); -} diff --git a/src/server/game/World/WorldSocket.h b/src/server/game/World/WorldSocket.h deleted file mode 100644 index 70654274215..00000000000 --- a/src/server/game/World/WorldSocket.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** \addtogroup u2w User to World Communication - * @{ - * \file WorldSocket.h - * \author Derex - */ - -#ifndef _WORLDSOCKET_H -#define _WORLDSOCKET_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -#pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#include "Common.h" -#include "Auth/AuthCrypt.h" - -class ACE_Message_Block; -class WorldPacket; -class WorldSession; - -/// Handler that can communicate over stream sockets. -typedef ACE_Svc_Handler WorldHandler; - -/** - * WorldSocket. - * - * This class is responsible for the communication with - * remote clients. - * Most methods return -1 on failure. - * The class uses reference counting. - * - * For output the class uses one buffer (64K usually) and - * a queue where it stores packet if there is no place on - * the queue. The reason this is done, is because the server - * does really a lot of small-size writes to it, and it doesn't - * scale well to allocate memory for every. When something is - * written to the output buffer the socket is not immediately - * activated for output (again for the same reason), there - * is 10ms celling (thats why there is Update() method). - * This concept is similar to TCP_CORK, but TCP_CORK - * uses 200ms celling. As result overhead generated by - * sending packets from "producer" threads is minimal, - * and doing a lot of writes with small size is tolerated. - * - * The calls to Update() method are managed by WorldSocketMgr - * and ReactorRunnable. - * - * For input ,the class uses one 1024 bytes buffer on stack - * to which it does recv() calls. And then received data is - * distributed where its needed. 1024 matches pretty well the - * traffic generated by client for now. - * - * The input/output do speculative reads/writes (AKA it tryes - * to read all data available in the kernel buffer or tryes to - * write everything available in userspace buffer), - * which is ok for using with Level and Edge Triggered IO - * notification. - * - */ -class WorldSocket : protected WorldHandler -{ - public: - /// Declare some friends - friend class ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR >; - friend class WorldSocketMgr; - friend class ReactorRunnable; - - /// Declare the acceptor for this class - typedef ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR > Acceptor; - - /// Mutex type used for various synchronizations. - typedef ACE_Thread_Mutex LockType; - typedef ACE_Guard GuardType; - - /// Check if socket is closed. - bool IsClosed (void) const; - - /// Close the socket. - void CloseSocket (void); - - /// Get address of connected peer. - const std::string& GetRemoteAddress (void) const; - - /// Send A packet on the socket, this function is reentrant. - /// @param pct packet to send - /// @return -1 of failure - int SendPacket (const WorldPacket& pct); - - /// Add reference to this object. - long AddReference (void); - - /// Remove reference to this object. - long RemoveReference (void); - - protected: - /// things called by ACE framework. - WorldSocket (void); - virtual ~WorldSocket (void); - - /// Called on open ,the void* is the acceptor. - virtual int open (void *); - - /// Called on failures inside of the acceptor, don't call from your code. - virtual int close (int); - - /// Called when we can read from the socket. - virtual int handle_input (ACE_HANDLE = ACE_INVALID_HANDLE); - - /// Called when the socket can write. - virtual int handle_output (ACE_HANDLE = ACE_INVALID_HANDLE); - - /// Called when connection is closed or error happens. - virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, - ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); - - /// Called by WorldSocketMgr/ReactorRunnable. - int Update (void); - - private: - /// Helper functions for processing incoming data. - int handle_input_header (void); - int handle_input_payload (void); - int handle_input_missing_data (void); - - /// Help functions to mark/unmark the socket for output. - /// @param g the guard is for m_OutBufferLock, the function will release it - int cancel_wakeup_output (GuardType& g); - int schedule_wakeup_output (GuardType& g); - - /// Drain the queue if its not empty. - int handle_output_queue (GuardType& g); - - /// process one incoming packet. - /// @param new_pct received packet ,note that you need to delete it. - int ProcessIncoming (WorldPacket* new_pct); - - /// Called by ProcessIncoming() on CMSG_AUTH_SESSION. - int HandleAuthSession (WorldPacket& recvPacket); - - /// Called by ProcessIncoming() on CMSG_PING. - int HandlePing (WorldPacket& recvPacket); - - private: - /// Time in which the last ping was received - ACE_Time_Value m_LastPingTime; - - /// Keep track of over-speed pings ,to prevent ping flood. - uint32 m_OverSpeedPings; - - /// Address of the remote peer - std::string m_Address; - - /// Class used for managing encryption of the headers - AuthCrypt m_Crypt; - - /// Mutex lock to protect m_Session - LockType m_SessionLock; - - /// Session to which received packets are routed - WorldSession* m_Session; - - /// here are stored the fragments of the received data - WorldPacket* m_RecvWPct; - - /// This block actually refers to m_RecvWPct contents, - /// which allows easy and safe writing to it. - /// It wont free memory when its deleted. m_RecvWPct takes care of freeing. - ACE_Message_Block m_RecvPct; - - /// Fragment of the received header. - ACE_Message_Block m_Header; - - /// Mutex for protecting output related data. - LockType m_OutBufferLock; - - /// Buffer used for writing output. - ACE_Message_Block *m_OutBuffer; - - /// Size of the m_OutBuffer. - size_t m_OutBufferSize; - - /// True if the socket is registered with the reactor for output - bool m_OutActive; - - uint32 m_Seed; - -}; - -#endif /* _WORLDSOCKET_H */ - -/// @} - diff --git a/src/server/game/World/WorldSocketMgr.cpp b/src/server/game/World/WorldSocketMgr.cpp deleted file mode 100644 index c23d08e6f78..00000000000 --- a/src/server/game/World/WorldSocketMgr.cpp +++ /dev/null @@ -1,369 +0,0 @@ -/* -* Copyright (C) 2005-2008,2007 MaNGOS -* -* Copyright (C) 2008-2010 Trinity -* -* 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, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** \file WorldSocketMgr.cpp -* \ingroup u2w -* \author Derex -*/ - -#include "WorldSocketMgr.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "Log.h" -#include "Common.h" -#include "Config/ConfigEnv.h" -#include "Database/DatabaseEnv.h" -#include "WorldSocket.h" - -/** -* This is a helper class to WorldSocketMgr ,that manages -* network threads, and assigning connections from acceptor thread -* to other network threads -*/ -class ReactorRunnable : protected ACE_Task_Base -{ - public: - - ReactorRunnable() : - m_ThreadId(-1), - m_Connections(0), - m_Reactor(0) - { - ACE_Reactor_Impl* imp = 0; - - #if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) - - imp = new ACE_Dev_Poll_Reactor(); - - imp->max_notify_iterations (128); - imp->restart (1); - - #else - - imp = new ACE_TP_Reactor(); - imp->max_notify_iterations (128); - - #endif - - m_Reactor = new ACE_Reactor (imp, 1); - } - - virtual ~ReactorRunnable() - { - Stop(); - Wait(); - - if (m_Reactor) - delete m_Reactor; - } - - void Stop() - { - m_Reactor->end_reactor_event_loop(); - } - - int Start() - { - if (m_ThreadId != -1) - return -1; - - return (m_ThreadId = activate()); - } - - void Wait() { ACE_Task_Base::wait(); } - - long Connections() - { - return static_cast (m_Connections.value()); - } - - int AddSocket (WorldSocket* sock) - { - ACE_GUARD_RETURN (ACE_Thread_Mutex, Guard, m_NewSockets_Lock, -1); - - ++m_Connections; - sock->AddReference(); - sock->reactor (m_Reactor); - m_NewSockets.insert (sock); - - return 0; - } - - ACE_Reactor* GetReactor() - { - return m_Reactor; - } - - protected: - - void AddNewSockets() - { - ACE_GUARD (ACE_Thread_Mutex, Guard, m_NewSockets_Lock); - - if (m_NewSockets.empty()) - return; - - for (SocketSet::const_iterator i = m_NewSockets.begin(); i != m_NewSockets.end(); ++i) - { - WorldSocket* sock = (*i); - - if (sock->IsClosed()) - { - sock->RemoveReference(); - --m_Connections; - } - else - m_Sockets.insert (sock); - } - - m_NewSockets.clear(); - } - - virtual int svc() - { - DEBUG_LOG ("Network Thread Starting"); - - WorldDatabase.ThreadStart(); - - ACE_ASSERT (m_Reactor); - - SocketSet::iterator i, t; - - while (!m_Reactor->reactor_event_loop_done()) - { - // dont be too smart to move this outside the loop - // the run_reactor_event_loop will modify interval - ACE_Time_Value interval (0, 10000); - - if (m_Reactor->run_reactor_event_loop (interval) == -1) - break; - - AddNewSockets(); - - for (i = m_Sockets.begin(); i != m_Sockets.end();) - { - if ((*i)->Update() == -1) - { - t = i; - ++i; - (*t)->CloseSocket(); - (*t)->RemoveReference(); - --m_Connections; - m_Sockets.erase (t); - } - else - ++i; - } - } - - WorldDatabase.ThreadEnd(); - - DEBUG_LOG ("Network Thread Exitting"); - - return 0; - } - - private: - typedef ACE_Atomic_Op AtomicInt; - typedef std::set SocketSet; - - ACE_Reactor* m_Reactor; - AtomicInt m_Connections; - int m_ThreadId; - - SocketSet m_Sockets; - - SocketSet m_NewSockets; - ACE_Thread_Mutex m_NewSockets_Lock; -}; - -WorldSocketMgr::WorldSocketMgr() : - m_NetThreadsCount(0), - m_NetThreads(0), - m_SockOutKBuff(-1), - m_SockOutUBuff(65536), - m_UseNoDelay(true), - m_Acceptor (0) -{ -} - -WorldSocketMgr::~WorldSocketMgr() -{ - if (m_NetThreads) - delete [] m_NetThreads; - - if (m_Acceptor) - delete m_Acceptor; -} - -int -WorldSocketMgr::StartReactiveIO (ACE_UINT16 port, const char* address) -{ - m_UseNoDelay = sConfig.GetBoolDefault ("Network.TcpNodelay", true); - - int num_threads = sConfig.GetIntDefault ("Network.Threads", 1); - - if (num_threads <= 0) - { - sLog.outError ("Network.Threads is wrong in your config file"); - return -1; - } - - m_NetThreadsCount = static_cast (num_threads + 1); - - m_NetThreads = new ReactorRunnable[m_NetThreadsCount]; - - sLog.outBasic ("Max allowed socket connections %d", ACE::max_handles()); - - // -1 means use default - m_SockOutKBuff = sConfig.GetIntDefault ("Network.OutKBuff", -1); - - m_SockOutUBuff = sConfig.GetIntDefault ("Network.OutUBuff", 65536); - - if (m_SockOutUBuff <= 0) - { - sLog.outError ("Network.OutUBuff is wrong in your config file"); - return -1; - } - - WorldSocket::Acceptor *acc = new WorldSocket::Acceptor; - m_Acceptor = acc; - - ACE_INET_Addr listen_addr (port, address); - - if (acc->open(listen_addr, m_NetThreads[0].GetReactor(), ACE_NONBLOCK) == -1) - { - sLog.outError ("Failed to open acceptor ,check if the port is free"); - return -1; - } - - for (size_t i = 0; i < m_NetThreadsCount; ++i) - m_NetThreads[i].Start(); - - return 0; -} - -int -WorldSocketMgr::StartNetwork (ACE_UINT16 port, const char* address) -{ - if (!sLog.IsOutDebug()) - ACE_Log_Msg::instance()->priority_mask (LM_ERROR, ACE_Log_Msg::PROCESS); - - if (StartReactiveIO(port, address) == -1) - return -1; - - return 0; -} - -void -WorldSocketMgr::StopNetwork() -{ - if (m_Acceptor) - { - WorldSocket::Acceptor* acc = dynamic_cast (m_Acceptor); - - if (acc) - acc->close(); - } - - if (m_NetThreadsCount != 0) - { - for (size_t i = 0; i < m_NetThreadsCount; ++i) - m_NetThreads[i].Stop(); - } - - Wait(); -} - -void -WorldSocketMgr::Wait() -{ - if (m_NetThreadsCount != 0) - { - for (size_t i = 0; i < m_NetThreadsCount; ++i) - m_NetThreads[i].Wait(); - } -} - -int -WorldSocketMgr::OnSocketOpen (WorldSocket* sock) -{ - // set some options here - if (m_SockOutKBuff >= 0) - { - if (sock->peer().set_option (SOL_SOCKET, - SO_SNDBUF, - (void*) & m_SockOutKBuff, - sizeof (int)) == -1 && errno != ENOTSUP) - { - sLog.outError ("WorldSocketMgr::OnSocketOpen set_option SO_SNDBUF"); - return -1; - } - } - - static const int ndoption = 1; - - // Set TCP_NODELAY. - if (m_UseNoDelay) - { - if (sock->peer().set_option (ACE_IPPROTO_TCP, - TCP_NODELAY, - (void*)&ndoption, - sizeof (int)) == -1) - { - sLog.outError ("WorldSocketMgr::OnSocketOpen: peer().set_option TCP_NODELAY errno = %s", ACE_OS::strerror (errno)); - return -1; - } - } - - sock->m_OutBufferSize = static_cast (m_SockOutUBuff); - - // we skip the Acceptor Thread - size_t min = 1; - - ACE_ASSERT (m_NetThreadsCount >= 1); - - for (size_t i = 1; i < m_NetThreadsCount; ++i) - if (m_NetThreads[i].Connections() < m_NetThreads[min].Connections()) - min = i; - - return m_NetThreads[min].AddSocket (sock); -} - -WorldSocketMgr* -WorldSocketMgr::Instance() -{ - return ACE_Singleton::instance(); -} - diff --git a/src/server/game/World/WorldSocketMgr.h b/src/server/game/World/WorldSocketMgr.h deleted file mode 100644 index 11345304962..00000000000 --- a/src/server/game/World/WorldSocketMgr.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS - * - * Copyright (C) 2008-2010 Trinity - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** \addtogroup u2w User to World Communication - * @{ - * \file WorldSocketMgr.h - * \author Derex - */ - -#ifndef __WORLDSOCKETMGR_H -#define __WORLDSOCKETMGR_H - -#include -#include -#include - -class WorldSocket; -class ReactorRunnable; -class ACE_Event_Handler; - -/// Manages all sockets connected to peers and network threads -class WorldSocketMgr -{ -public: - friend class WorldSocket; - friend class ACE_Singleton; - - /// Start network, listen at address:port . - int StartNetwork (ACE_UINT16 port, const char* address); - - /// Stops all network threads, It will wait for all running threads . - void StopNetwork(); - - /// Wait untill all network threads have "joined" . - void Wait(); - - /// Make this class singleton . - static WorldSocketMgr* Instance(); - -private: - int OnSocketOpen(WorldSocket* sock); - - int StartReactiveIO(ACE_UINT16 port, const char* address); - -private: - WorldSocketMgr(); - virtual ~WorldSocketMgr(); - - ReactorRunnable* m_NetThreads; - size_t m_NetThreadsCount; - - int m_SockOutKBuff; - int m_SockOutUBuff; - bool m_UseNoDelay; - - ACE_Event_Handler* m_Acceptor; -}; - -#define sWorldSocketMgr WorldSocketMgr::Instance() - -#endif -/// @} - -- cgit v1.2.3