aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/authserver/CMakeLists.txt6
-rw-r--r--src/server/authserver/Main.cpp165
-rw-r--r--src/server/authserver/authserver.conf.dist84
-rw-r--r--src/server/collision/CMakeLists.txt3
-rw-r--r--src/server/collision/Management/MMapManager.cpp14
-rw-r--r--src/server/collision/Management/VMapManager2.cpp2
-rw-r--r--src/server/collision/Maps/MapTree.cpp5
-rw-r--r--src/server/collision/Maps/TileAssembler.cpp1
-rw-r--r--src/server/collision/Models/GameObjectModel.cpp2
-rw-r--r--src/server/collision/Models/ModelInstance.cpp1
-rw-r--r--src/server/collision/Models/WorldModel.cpp1
-rw-r--r--src/server/game/AI/CoreAI/GuardAI.cpp3
-rw-r--r--src/server/game/AI/CoreAI/PassiveAI.cpp1
-rw-r--r--src/server/game/AI/CoreAI/PetAI.cpp9
-rw-r--r--src/server/game/AI/CoreAI/ReactorAI.cpp4
-rw-r--r--src/server/game/AI/CoreAI/TotemAI.cpp2
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.cpp6
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.h2
-rw-r--r--src/server/game/AI/CreatureAISelector.cpp1
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.cpp2
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp8
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp40
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h32
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp36
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h21
-rw-r--r--src/server/game/Accounts/RBAC.h6
-rw-r--r--src/server/game/Achievements/AchievementMgr.cpp2
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp3
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp2
-rw-r--r--src/server/game/Battlefield/Battlefield.cpp1
-rw-r--r--src/server/game/Battlefield/BattlefieldMgr.cpp1
-rw-r--r--src/server/game/Battlegrounds/ArenaTeam.cpp2
-rw-r--r--src/server/game/Battlegrounds/Battleground.cpp4
-rw-r--r--src/server/game/Battlegrounds/BattlegroundMgr.cpp2
-rw-r--r--src/server/game/Battlegrounds/BattlegroundQueue.cpp9
-rw-r--r--src/server/game/Battlegrounds/BattlegroundQueue.h2
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp2
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp1
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp1
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp1
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp123
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundSA.h6
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp2
-rw-r--r--src/server/game/CMakeLists.txt4
-rw-r--r--src/server/game/Chat/Channels/Channel.h2
-rw-r--r--src/server/game/Chat/Chat.cpp33
-rw-r--r--src/server/game/Chat/Chat.h22
-rw-r--r--src/server/game/Chat/ChatLink.cpp2
-rw-r--r--src/server/game/Combat/HostileRefManager.cpp1
-rw-r--r--src/server/game/Combat/ThreatManager.cpp4
-rw-r--r--src/server/game/Conditions/ConditionMgr.cpp35
-rw-r--r--src/server/game/Conditions/ConditionMgr.h4
-rw-r--r--src/server/game/DataStores/DBCStores.cpp27
-rw-r--r--src/server/game/DataStores/DBCStores.h2
-rw-r--r--src/server/game/DataStores/DBCStructure.h64
-rw-r--r--src/server/game/DataStores/DBCfmt.h1
-rw-r--r--src/server/game/DungeonFinding/LFG.cpp3
-rw-r--r--src/server/game/DungeonFinding/LFG.h4
-rw-r--r--src/server/game/DungeonFinding/LFGGroupData.cpp12
-rw-r--r--src/server/game/DungeonFinding/LFGGroupData.h4
-rw-r--r--src/server/game/DungeonFinding/LFGMgr.cpp48
-rw-r--r--src/server/game/DungeonFinding/LFGMgr.h3
-rw-r--r--src/server/game/DungeonFinding/LFGQueue.cpp5
-rw-r--r--src/server/game/DungeonFinding/LFGScripts.cpp10
-rw-r--r--src/server/game/Entities/Corpse/Corpse.cpp4
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp126
-rw-r--r--src/server/game/Entities/Creature/Creature.h34
-rw-r--r--src/server/game/Entities/Creature/TemporarySummon.cpp1
-rw-r--r--src/server/game/Entities/DynamicObject/DynamicObject.cpp2
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp36
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h10
-rw-r--r--src/server/game/Entities/Item/Item.h2
-rw-r--r--src/server/game/Entities/Object/Object.cpp187
-rw-r--r--src/server/game/Entities/Object/Object.h136
-rw-r--r--src/server/game/Entities/Object/ObjectGuid.cpp1
-rw-r--r--src/server/game/Entities/Object/ObjectGuid.h14
-rw-r--r--src/server/game/Entities/Object/Position.cpp184
-rw-r--r--src/server/game/Entities/Object/Position.h225
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp110
-rw-r--r--src/server/game/Entities/Pet/Pet.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp760
-rw-r--r--src/server/game/Entities/Player/Player.h49
-rw-r--r--src/server/game/Entities/Totem/Totem.cpp5
-rw-r--r--src/server/game/Entities/Transport/Transport.cpp104
-rw-r--r--src/server/game/Entities/Transport/Transport.h5
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp344
-rw-r--r--src/server/game/Entities/Unit/Unit.h67
-rwxr-xr-xsrc/server/game/Entities/Vehicle/Vehicle.cpp4
-rw-r--r--src/server/game/Events/GameEventMgr.cpp1
-rw-r--r--src/server/game/Events/GameEventMgr.h2
-rw-r--r--src/server/game/Globals/ObjectAccessor.cpp8
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp103
-rw-r--r--src/server/game/Globals/ObjectMgr.h13
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.cpp5
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.h2
-rw-r--r--src/server/game/Grids/ObjectGridLoader.cpp1
-rw-r--r--src/server/game/Groups/Group.cpp4
-rw-r--r--src/server/game/Groups/Group.h2
-rw-r--r--src/server/game/Handlers/AddonHandler.cpp1
-rw-r--r--src/server/game/Handlers/BattleGroundHandler.cpp8
-rw-r--r--src/server/game/Handlers/BattlefieldHandler.cpp2
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp31
-rw-r--r--src/server/game/Handlers/ChatHandler.cpp1
-rw-r--r--src/server/game/Handlers/CombatHandler.cpp2
-rw-r--r--src/server/game/Handlers/DuelHandler.cpp2
-rw-r--r--src/server/game/Handlers/GuildHandler.cpp3
-rw-r--r--src/server/game/Handlers/ItemHandler.cpp2
-rw-r--r--src/server/game/Handlers/LFGHandler.cpp4
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp8
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp1
-rw-r--r--src/server/game/Handlers/NPCHandler.cpp2
-rw-r--r--src/server/game/Handlers/PetHandler.cpp22
-rw-r--r--src/server/game/Handlers/PetitionsHandler.cpp2
-rw-r--r--src/server/game/Handlers/QueryHandler.cpp2
-rw-r--r--src/server/game/Handlers/QuestHandler.cpp2
-rw-r--r--src/server/game/Handlers/SkillHandler.cpp2
-rw-r--r--src/server/game/Handlers/SpellHandler.cpp7
-rw-r--r--src/server/game/Handlers/TaxiHandler.cpp3
-rw-r--r--src/server/game/Handlers/VoiceChatHandler.cpp1
-rw-r--r--src/server/game/Instances/InstanceSaveMgr.cpp3
-rw-r--r--src/server/game/Instances/InstanceScript.cpp27
-rw-r--r--src/server/game/Instances/InstanceScript.h9
-rw-r--r--src/server/game/Loot/LootMgr.cpp4
-rw-r--r--src/server/game/Maps/Map.cpp36
-rw-r--r--src/server/game/Maps/Map.h9
-rw-r--r--src/server/game/Maps/MapManager.cpp1
-rw-r--r--src/server/game/Maps/TransportMgr.cpp24
-rw-r--r--src/server/game/Maps/TransportMgr.h2
-rw-r--r--src/server/game/Maps/ZoneScript.h4
-rw-r--r--src/server/game/Miscellaneous/Language.h3
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h8
-rw-r--r--src/server/game/Movement/MotionMaster.cpp38
-rw-r--r--src/server/game/Movement/MotionMaster.h3
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp2
-rw-r--r--src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp1
-rw-r--r--src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp1
-rw-r--r--src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp2
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp27
-rw-r--r--src/server/game/Movement/Spline/MoveSpline.cpp2
-rw-r--r--src/server/game/Movement/Spline/MoveSplineFlag.h8
-rw-r--r--src/server/game/Movement/Spline/MoveSplineInit.cpp1
-rw-r--r--src/server/game/Movement/Spline/MovementUtil.cpp1
-rw-r--r--src/server/game/OutdoorPvP/OutdoorPvP.cpp3
-rw-r--r--src/server/game/Pools/PoolMgr.cpp2
-rw-r--r--src/server/game/Reputation/ReputationMgr.cpp3
-rw-r--r--src/server/game/Reputation/ReputationMgr.h4
-rw-r--r--src/server/game/Scripting/MapScripts.cpp2
-rw-r--r--src/server/game/Scripting/ScriptLoader.cpp8
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp3
-rw-r--r--src/server/game/Scripting/ScriptMgr.h2
-rw-r--r--src/server/game/Server/Protocol/Opcodes.h8
-rw-r--r--src/server/game/Server/WorldSession.cpp33
-rw-r--r--src/server/game/Server/WorldSocket.cpp113
-rw-r--r--src/server/game/Server/WorldSocket.h12
-rw-r--r--src/server/game/Server/WorldSocketMgr.cpp3
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp88
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp41
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h4
-rw-r--r--src/server/game/Spells/Spell.cpp242
-rw-r--r--src/server/game/Spells/Spell.h1
-rw-r--r--src/server/game/Spells/SpellEffects.cpp37
-rw-r--r--src/server/game/Spells/SpellHistory.cpp643
-rw-r--r--src/server/game/Spells/SpellHistory.h137
-rw-r--r--src/server/game/Spells/SpellInfo.cpp108
-rw-r--r--src/server/game/Spells/SpellInfo.h11
-rw-r--r--src/server/game/Spells/SpellMgr.cpp17
-rw-r--r--src/server/game/Spells/SpellScript.cpp1
-rw-r--r--src/server/game/Texts/CreatureTextMgr.cpp26
-rw-r--r--src/server/game/Texts/CreatureTextMgr.h6
-rw-r--r--src/server/game/Warden/Warden.cpp2
-rw-r--r--src/server/game/Warden/Warden.h8
-rw-r--r--src/server/game/Warden/WardenCheckMgr.cpp1
-rw-r--r--src/server/game/Warden/WardenWin.cpp1
-rw-r--r--src/server/game/Warden/WardenWin.h8
-rw-r--r--src/server/game/Weather/Weather.cpp9
-rw-r--r--src/server/game/Weather/WeatherMgr.cpp6
-rw-r--r--src/server/game/World/World.cpp31
-rw-r--r--src/server/game/World/World.h3
-rw-r--r--src/server/scripts/CMakeLists.txt4
-rw-r--r--src/server/scripts/Commands/cs_account.cpp2
-rw-r--r--src/server/scripts/Commands/cs_lfg.cpp64
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp24
-rw-r--r--src/server/scripts/Commands/cs_modify.cpp46
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp71
-rw-r--r--src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp6
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/ShadowfangKeep/instance_shadowfang_keep.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/SunkenTemple/sunken_temple.cpp26
-rw-r--r--src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp27
-rw-r--r--src/server/scripts/EasternKingdoms/Uldaman/boss_ironaya.cpp8
-rw-r--r--src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp29
-rw-r--r--src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/zone_arathi_highlands.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/zone_hinterlands.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/zone_undercity.cpp242
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp150
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp2
-rw-r--r--src/server/scripts/Kalimdor/RazorfenKraul/instance_razorfen_kraul.cpp2
-rw-r--r--src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp2
-rw-r--r--src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp10
-rw-r--r--src/server/scripts/Kalimdor/ZulFarrak/instance_zulfarrak.cpp2
-rw-r--r--src/server/scripts/Kalimdor/zone_ashenvale.cpp133
-rw-r--r--src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp2
-rw-r--r--src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp730
-rw-r--r--src/server/scripts/Kalimdor/zone_desolace.cpp8
-rw-r--r--src/server/scripts/Kalimdor/zone_moonglade.cpp2
-rw-r--r--src/server/scripts/Kalimdor/zone_winterspring.cpp10
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp2
-rw-r--r--src/server/scripts/Northrend/CMakeLists.txt3
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp2
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp2
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp8
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp18
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp27
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp17
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp51
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp6
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp1
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h12
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp4
-rw-r--r--src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp2
-rw-r--r--src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp44
-rw-r--r--src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h3
-rw-r--r--src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp6
-rw-r--r--src/server/scripts/Northrend/Nexus/Nexus/boss_commander_kolurg.cpp80
-rw-r--r--src/server/scripts/Northrend/Nexus/Nexus/boss_commander_stoutbeard.cpp72
-rw-r--r--src/server/scripts/Northrend/Nexus/Nexus/boss_nexus_commanders.cpp110
-rw-r--r--src/server/scripts/Northrend/Nexus/Nexus/boss_ormorok.cpp2
-rw-r--r--src/server/scripts/Northrend/Nexus/Nexus/nexus.h23
-rw-r--r--src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp4
-rw-r--r--src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp17
-rw-r--r--src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.h2
-rw-r--r--src/server/scripts/Northrend/Ulduar/HallsOfStone/instance_halls_of_stone.cpp10
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp39
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp43
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp55
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h1
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp2
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp43
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_erekem.cpp45
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp70
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp56
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_moragg.cpp34
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp75
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp40
-rw-r--r--src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp474
-rw-r--r--src/server/scripts/Northrend/VioletHold/violet_hold.cpp190
-rw-r--r--src/server/scripts/Northrend/VioletHold/violet_hold.h71
-rw-r--r--src/server/scripts/Northrend/zone_borean_tundra.cpp7
-rw-r--r--src/server/scripts/Northrend/zone_dragonblight.cpp2
-rw-r--r--src/server/scripts/Northrend/zone_grizzly_hills.cpp39
-rw-r--r--src/server/scripts/Northrend/zone_icecrown.cpp48
-rw-r--r--src/server/scripts/Northrend/zone_storm_peaks.cpp93
-rw-r--r--src/server/scripts/OutdoorPvP/OutdoorPvPNA.h8
-rw-r--r--src/server/scripts/OutdoorPvP/OutdoorPvPZM.h10
-rw-r--r--src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp2
-rw-r--r--src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_ambassador_hellmaw.cpp2
-rw-r--r--src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/instance_shadow_labyrinth.cpp2
-rw-r--r--src/server/scripts/Outland/CMakeLists.txt1
-rw-r--r--src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp2
-rw-r--r--src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp4
-rw-r--r--src/server/scripts/Outland/CoilfangReservoir/SteamVault/instance_steam_vault.cpp2
-rw-r--r--src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp2
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp4
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp7
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp28
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp230
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp255
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h80
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp21
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp39
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp75
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp22
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp123
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/the_eye.h30
-rw-r--r--src/server/scripts/Outland/TempestKeep/Mechanar/instance_mechanar.cpp2
-rw-r--r--src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp5
-rw-r--r--src/server/scripts/Outland/zone_blades_edge_mountains.cpp196
-rw-r--r--src/server/scripts/Outland/zone_hellfire_peninsula.cpp474
-rw-r--r--src/server/scripts/Outland/zone_shadowmoon_valley.cpp327
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp45
-rw-r--r--src/server/scripts/Spells/spell_hunter.cpp19
-rw-r--r--src/server/scripts/Spells/spell_item.cpp19
-rw-r--r--src/server/scripts/Spells/spell_mage.cpp19
-rw-r--r--src/server/scripts/Spells/spell_paladin.cpp5
-rw-r--r--src/server/scripts/Spells/spell_quest.cpp54
-rw-r--r--src/server/scripts/Spells/spell_rogue.cpp45
-rw-r--r--src/server/scripts/Spells/spell_shaman.cpp7
-rw-r--r--src/server/scripts/Spells/spell_warrior.cpp3
-rw-r--r--src/server/scripts/World/npcs_special.cpp57
-rw-r--r--src/server/shared/CMakeLists.txt8
-rw-r--r--src/server/shared/Configuration/Config.cpp1
-rw-r--r--src/server/shared/Cryptography/ARC4.cpp1
-rw-r--r--src/server/shared/Cryptography/BigNumber.cpp8
-rw-r--r--src/server/shared/Cryptography/SHA1.h4
-rw-r--r--src/server/shared/Database/AdhocStatement.h2
-rw-r--r--src/server/shared/Database/DatabaseLoader.cpp191
-rw-r--r--src/server/shared/Database/DatabaseLoader.h71
-rw-r--r--src/server/shared/Database/DatabaseWorker.cpp2
-rw-r--r--src/server/shared/Database/DatabaseWorkerPool.h147
-rw-r--r--src/server/shared/Database/Field.h8
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp11
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.h5
-rw-r--r--src/server/shared/Database/MySQLConnection.cpp26
-rw-r--r--src/server/shared/Database/MySQLConnection.h5
-rw-r--r--src/server/shared/Database/QueryHolder.cpp23
-rw-r--r--src/server/shared/Database/QueryHolder.h5
-rw-r--r--src/server/shared/Database/Transaction.cpp11
-rw-r--r--src/server/shared/Database/Transaction.h8
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.cpp227
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.h7
-rw-r--r--src/server/shared/Define.h6
-rw-r--r--src/server/shared/Dynamic/ObjectRegistry.h4
-rw-r--r--src/server/shared/Logging/Appender.cpp35
-rw-r--r--src/server/shared/Logging/Appender.h18
-rw-r--r--src/server/shared/Logging/AppenderConsole.cpp10
-rw-r--r--src/server/shared/Logging/AppenderConsole.h2
-rw-r--r--src/server/shared/Logging/AppenderDB.cpp12
-rw-r--r--src/server/shared/Logging/AppenderDB.h2
-rw-r--r--src/server/shared/Logging/AppenderFile.cpp14
-rw-r--r--src/server/shared/Logging/AppenderFile.h2
-rw-r--r--src/server/shared/Logging/Log.cpp52
-rw-r--r--src/server/shared/Logging/Log.h67
-rw-r--r--src/server/shared/Logging/LogOperation.cpp8
-rw-r--r--src/server/shared/Logging/LogOperation.h10
-rw-r--r--src/server/shared/Logging/Logger.cpp4
-rw-r--r--src/server/shared/Logging/Logger.h2
-rw-r--r--src/server/shared/Networking/MessageBuffer.h4
-rw-r--r--src/server/shared/Networking/Socket.h31
-rw-r--r--src/server/shared/Networking/SocketMgr.h2
-rw-r--r--src/server/shared/PrecompiledHeaders/sharedPCH.h1
-rw-r--r--src/server/shared/Threading/ProducerConsumerQueue.h4
-rw-r--r--src/server/shared/Updater/DBUpdater.cpp414
-rw-r--r--src/server/shared/Updater/DBUpdater.h79
-rw-r--r--src/server/shared/Updater/UpdateFetcher.cpp401
-rw-r--r--src/server/shared/Updater/UpdateFetcher.h132
-rw-r--r--src/server/shared/Utilities/ServiceWin32.cpp2
-rw-r--r--src/server/shared/Utilities/StringFormat.h34
-rw-r--r--src/server/shared/Utilities/TaskScheduler.cpp208
-rw-r--r--src/server/shared/Utilities/TaskScheduler.h627
-rw-r--r--src/server/shared/Utilities/Util.h7
-rw-r--r--src/server/worldserver/CMakeLists.txt6
-rw-r--r--src/server/worldserver/CommandLine/CliRunnable.cpp7
-rw-r--r--src/server/worldserver/Main.cpp104
-rw-r--r--src/server/worldserver/RemoteAccess/RASession.h2
-rw-r--r--src/server/worldserver/worldserver.conf.dist91
-rw-r--r--src/tools/map_extractor/System.cpp37
-rw-r--r--src/tools/map_extractor/mpq_libmpq.cpp2
-rw-r--r--src/tools/map_extractor/mpq_libmpq04.h2
-rw-r--r--src/tools/vmap4_assembler/CMakeLists.txt1
-rw-r--r--src/tools/vmap4_extractor/adtfile.cpp2
-rw-r--r--src/tools/vmap4_extractor/mpq_libmpq.cpp2
-rw-r--r--src/tools/vmap4_extractor/mpq_libmpq04.h2
-rw-r--r--src/tools/vmap4_extractor/vec3d.h4
-rw-r--r--src/tools/vmap4_extractor/vmapexport.cpp25
-rw-r--r--src/tools/vmap4_extractor/wdtfile.cpp1
363 files changed, 9032 insertions, 5445 deletions
diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt
index edd87a5c347..7c76df5d06c 100644
--- a/src/server/authserver/CMakeLists.txt
+++ b/src/server/authserver/CMakeLists.txt
@@ -43,6 +43,8 @@ endif()
include_directories(
${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/dep/cppformat
+ ${CMAKE_SOURCE_DIR}/dep/process
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
${CMAKE_SOURCE_DIR}/src/server/shared/Database
@@ -53,6 +55,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/server/shared/Logging
${CMAKE_SOURCE_DIR}/src/server/shared/Networking
${CMAKE_SOURCE_DIR}/src/server/shared/Threading
+ ${CMAKE_SOURCE_DIR}/src/server/shared/Updater
${CMAKE_SOURCE_DIR}/src/server/shared/Utilities
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/Authentication
@@ -63,6 +66,8 @@ include_directories(
${VALGRIND_INCLUDE_DIR}
)
+GroupSources(${CMAKE_CURRENT_SOURCE_DIR})
+
add_executable(authserver
${authserver_SRCS}
${authserver_PCH_SRC}
@@ -78,6 +83,7 @@ endif()
target_link_libraries(authserver
shared
+ format
${MYSQL_LIBRARY}
${OPENSSL_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp
index c57f8254d9c..15ab1c38925 100644
--- a/src/server/authserver/Main.cpp
+++ b/src/server/authserver/Main.cpp
@@ -28,14 +28,13 @@
#include "Common.h"
#include "Config.h"
#include "DatabaseEnv.h"
+#include "DatabaseLoader.h"
#include "Log.h"
#include "ProcessPriority.h"
#include "RealmList.h"
#include "SystemConfig.h"
#include "Util.h"
-#include <cstdlib>
#include <iostream>
-#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/program_options.hpp>
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
@@ -47,25 +46,52 @@ using namespace boost::program_options;
# define _TRINITY_REALM_CONFIG "authserver.conf"
#endif
+#if PLATFORM == PLATFORM_WINDOWS
+#include "ServiceWin32.h"
+char serviceName[] = "authserver";
+char serviceLongName[] = "TrinityCore auth service";
+char serviceDescription[] = "TrinityCore World of Warcraft emulator auth service";
+/*
+* -1 - not in service mode
+* 0 - stopped
+* 1 - running
+* 2 - paused
+*/
+int m_ServiceStatus = -1;
+
+boost::asio::deadline_timer* _serviceStatusWatchTimer;
+void ServiceStatusWatcher(boost::system::error_code const& error);
+#endif
+
bool StartDB();
void StopDB();
void SignalHandler(const boost::system::error_code& error, int signalNumber);
void KeepDatabaseAliveHandler(const boost::system::error_code& error);
-variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile);
+variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile, std::string& configService);
-boost::asio::io_service _ioService;
-boost::asio::deadline_timer _dbPingTimer(_ioService);
+boost::asio::io_service* _ioService;
+boost::asio::deadline_timer* _dbPingTimer;
uint32 _dbPingInterval;
LoginDatabaseWorkerPool LoginDatabase;
-int mainImpl(int argc, char** argv)
+int main(int argc, char** argv)
{
std::string configFile = _TRINITY_REALM_CONFIG;
- auto vm = GetConsoleArguments(argc, argv, configFile);
+ std::string configService;
+ auto vm = GetConsoleArguments(argc, argv, configFile, configService);
// exit if help is enabled
if (vm.count("help"))
return 0;
+#if PLATFORM == PLATFORM_WINDOWS
+ if (configService.compare("install") == 0)
+ return WinServiceInstall() == true ? 0 : 1;
+ else if (configService.compare("uninstall") == 0)
+ return WinServiceUninstall() == true ? 0 : 1;
+ else if (configService.compare("run") == 0)
+ return WinServiceRun() ? 0 : 1;
+#endif
+
std::string configError;
if (!sConfigMgr->LoadInitial(configFile, configError))
{
@@ -96,13 +122,16 @@ int mainImpl(int argc, char** argv)
if (!StartDB())
return 1;
+ _ioService = new boost::asio::io_service();
+
// Get the list of realms for the server
- sRealmList->Initialize(_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20));
+ sRealmList->Initialize(*_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20));
if (sRealmList->size() == 0)
{
TC_LOG_ERROR("server.authserver", "No valid realms specified.");
StopDB();
+ delete _ioService;
return 1;
}
@@ -112,15 +141,16 @@ int mainImpl(int argc, char** argv)
{
TC_LOG_ERROR("server.authserver", "Specified port out of allowed range (1-65535)");
StopDB();
+ delete _ioService;
return 1;
}
std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
- sAuthSocketMgr.StartNetwork(_ioService, bindIp, port);
+ sAuthSocketMgr.StartNetwork(*_ioService, bindIp, port);
// Set signal handlers
- boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM);
+ boost::asio::signal_set signals(*_ioService, SIGINT, SIGTERM);
#if PLATFORM == PLATFORM_WINDOWS
signals.add(SIGBREAK);
#endif
@@ -131,36 +161,36 @@ int mainImpl(int argc, char** argv)
// Enabled a timed callback for handling the database keep alive ping
_dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30);
- _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval));
- _dbPingTimer.async_wait(KeepDatabaseAliveHandler);
+ _dbPingTimer = new boost::asio::deadline_timer(*_ioService);
+ _dbPingTimer->expires_from_now(boost::posix_time::minutes(_dbPingInterval));
+ _dbPingTimer->async_wait(KeepDatabaseAliveHandler);
+
+#if PLATFORM == PLATFORM_WINDOWS
+ if (m_ServiceStatus != -1)
+ {
+ _serviceStatusWatchTimer = new boost::asio::deadline_timer(*_ioService);
+ _serviceStatusWatchTimer->expires_from_now(boost::posix_time::seconds(1));
+ _serviceStatusWatchTimer->async_wait(ServiceStatusWatcher);
+ }
+#endif
// Start the io service worker loop
- _ioService.run();
+ _ioService->run();
+
+ _dbPingTimer->cancel();
+
+ sAuthSocketMgr.StopNetwork();
// Close the Database Pool and library
StopDB();
TC_LOG_INFO("server.authserver", "Halting process...");
- return 0;
-}
-/// Launch the Trinity server
-extern int main(int argc, char** argv)
-{
- try
- {
- return mainImpl(argc, argv);
- }
- catch (std::exception& ex)
- {
- std::cerr << "Top-level exception caught:" << ex.what() << "\n";
+ signals.cancel();
-#ifndef NDEBUG // rethrow exception for the debugger
- throw;
-#else
- return 1;
-#endif
- }
+ delete _dbPingTimer;
+ delete _ioService;
+ return 0;
}
/// Initialize connection to the database
@@ -168,33 +198,15 @@ bool StartDB()
{
MySQL::Library_Init();
- std::string dbstring = sConfigMgr->GetStringDefault("LoginDatabaseInfo", "");
- if (dbstring.empty())
- {
- TC_LOG_ERROR("server.authserver", "Database not specified");
- return false;
- }
-
- int32 worker_threads = sConfigMgr->GetIntDefault("LoginDatabase.WorkerThreads", 1);
- if (worker_threads < 1 || worker_threads > 32)
- {
- TC_LOG_ERROR("server.authserver", "Improper value specified for LoginDatabase.WorkerThreads, defaulting to 1.");
- worker_threads = 1;
- }
-
- int32 synch_threads = sConfigMgr->GetIntDefault("LoginDatabase.SynchThreads", 1);
- if (synch_threads < 1 || synch_threads > 32)
- {
- TC_LOG_ERROR("server.authserver", "Improper value specified for LoginDatabase.SynchThreads, defaulting to 1.");
- synch_threads = 1;
- }
+ // Load databases
+ // NOTE: While authserver is singlethreaded you should keep synch_threads == 1.
+ // Increasing it is just silly since only 1 will be used ever.
+ DatabaseLoader loader("server.authserver", DatabaseLoader::DATABASE_NONE);
+ loader
+ .AddDatabase(LoginDatabase, "Login");
- // NOTE: While authserver is singlethreaded you should keep synch_threads == 1. Increasing it is just silly since only 1 will be used ever.
- if (!LoginDatabase.Open(dbstring, uint8(worker_threads), uint8(synch_threads)))
- {
- TC_LOG_ERROR("server.authserver", "Cannot connect to database");
+ if (!loader.Load())
return false;
- }
TC_LOG_INFO("server.authserver", "Started auth database connection pool.");
sLog->SetRealmId(0); // Enables DB appenders when realm is set.
@@ -211,7 +223,7 @@ void StopDB()
void SignalHandler(const boost::system::error_code& error, int /*signalNumber*/)
{
if (!error)
- _ioService.stop();
+ _ioService->stop();
}
void KeepDatabaseAliveHandler(const boost::system::error_code& error)
@@ -221,31 +233,58 @@ void KeepDatabaseAliveHandler(const boost::system::error_code& error)
TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive");
LoginDatabase.KeepAlive();
- _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval));
- _dbPingTimer.async_wait(KeepDatabaseAliveHandler);
+ _dbPingTimer->expires_from_now(boost::posix_time::minutes(_dbPingInterval));
+ _dbPingTimer->async_wait(KeepDatabaseAliveHandler);
}
}
-variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile)
+#if PLATFORM == PLATFORM_WINDOWS
+void ServiceStatusWatcher(boost::system::error_code const& error)
+{
+ if (!error)
+ {
+ if (m_ServiceStatus == 0)
+ {
+ _ioService->stop();
+ delete _serviceStatusWatchTimer;
+ }
+ else
+ {
+ _serviceStatusWatchTimer->expires_from_now(boost::posix_time::seconds(1));
+ _serviceStatusWatchTimer->async_wait(ServiceStatusWatcher);
+ }
+ }
+}
+#endif
+
+variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile, std::string& configService)
{
options_description all("Allowed options");
all.add_options()
("help,h", "print usage message")
("config,c", value<std::string>(&configFile)->default_value(_TRINITY_REALM_CONFIG), "use <arg> as configuration file")
;
+#if PLATFORM == PLATFORM_WINDOWS
+ options_description win("Windows platform specific options");
+ win.add_options()
+ ("service,s", value<std::string>(&configService)->default_value(""), "Windows service options: [install | uninstall]")
+ ;
+
+ all.add(win);
+#endif
variables_map variablesMap;
try
{
store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), variablesMap);
notify(variablesMap);
}
- catch (std::exception& e) {
+ catch (std::exception& e)
+ {
std::cerr << e.what() << "\n";
}
- if (variablesMap.count("help")) {
+ if (variablesMap.count("help"))
std::cout << all << "\n";
- }
return variablesMap;
}
diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist
index b7dee9ac08b..ba9cb5b23b4 100644
--- a/src/server/authserver/authserver.conf.dist
+++ b/src/server/authserver/authserver.conf.dist
@@ -9,6 +9,7 @@
# EXAMPLE CONFIG
# AUTH SERVER SETTINGS
# MYSQL SETTINGS
+# UPDATE SETTINGS
# LOGGING SYSTEM SETTINGS
#
###################################################################################################
@@ -158,6 +159,89 @@ Wrong.Password.Login.Logging = 0
###################################################################################################
###################################################################################################
+# UPDATE SETTINGS
+#
+# Updates.EnableDatabases
+# Description: A mask that describes which databases shall be updated.
+#
+# Following flags are available
+# DATABASE_LOGIN = 1, // Auth database
+#
+# Default: 0 - (All Disabled)
+# 1 - (All Enabled)
+
+Updates.EnableDatabases = 0
+
+#
+# Updates.SourcePath
+# Description: The path to your TrinityCore source directory.
+# If the path is left empty, built-in CMAKE_SOURCE_DIR is used.
+# Example: "../TrinityCore"
+# Default: ""
+
+Updates.SourcePath = ""
+
+#
+# Updates.SourcePath
+# Description: The path to your mysql cli binary.
+# If the path is left empty, built-in path from cmake is used.
+# Example: "C:/Program Files/MySQL/MySQL Server 5.6/bin/mysql.exe"
+# "mysql.exe"
+# "/usr/bin/mysql"
+# Default: ""
+
+Updates.MySqlCLIPath = ""
+
+#
+# Updates.AutoSetup
+# Description: Auto populate empty databases.
+# Default: 1 - (Enabled)
+# 0 - (Disabled)
+
+Updates.AutoSetup = 1
+
+#
+# Updates.Redundancy
+# Description: Perform data redundancy checks through hashing
+# to detect changes on sql updates and reapply it.
+# Default: 1 - (Enabled)
+# 0 - (Disabled)
+
+Updates.Redundancy = 1
+
+#
+# Updates.ArchivedRedundancy
+# Description: Check hashes of archived updates (slows down startup).
+# Default: 0 - (Disabled)
+# 1 - (Enabled)
+
+Updates.ArchivedRedundancy = 0
+
+#
+# Updates.AllowRehash
+# Description: Inserts the current file hash in the database if it is left empty.
+# Useful if you want to mark a file as applied but you don't know its hash.
+# Default: 1 - (Enabled)
+# 0 - (Disabled)
+
+Updates.AllowRehash = 1
+
+#
+# Updates.CleanDeadRefMaxCount
+# Description: Cleans dead/ orphaned references that occur if an update was removed or renamed and edited in one step.
+# It only starts the clean up if the count of the missing updates is below or equal the Updates.CleanDeadRefMaxCount value.
+# This way prevents erasing of the update history due to wrong source directory state (maybe wrong branch or bad revision).
+# Disable this if you want to know if the database is in a possible "dirty state".
+# Default: 3 - (Enabled)
+# 0 - (Disabled)
+# -1 - (Enabled - unlimited)
+
+Updates.CleanDeadRefMaxCount = 3
+
+#
+###################################################################################################
+
+###################################################################################################
#
# LOGGING SYSTEM SETTINGS
#
diff --git a/src/server/collision/CMakeLists.txt b/src/server/collision/CMakeLists.txt
index e3c77736d5e..f394fe791be 100644
--- a/src/server/collision/CMakeLists.txt
+++ b/src/server/collision/CMakeLists.txt
@@ -35,6 +35,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include
+ ${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
@@ -79,6 +80,8 @@ include_directories(
${VALGRIND_INCLUDE_DIR}
)
+GroupSources(${CMAKE_CURRENT_SOURCE_DIR})
+
add_library(collision STATIC
${collision_STAT_SRCS}
${collision_STAT_PCH_SRC}
diff --git a/src/server/collision/Management/MMapManager.cpp b/src/server/collision/Management/MMapManager.cpp
index 170350d4de4..847b7bbd001 100644
--- a/src/server/collision/Management/MMapManager.cpp
+++ b/src/server/collision/Management/MMapManager.cpp
@@ -73,7 +73,7 @@ namespace MMAP
delete [] fileName;
- TC_LOG_INFO("maps", "MMAP:loadMapData: Loaded %03i.mmap", mapId);
+ TC_LOG_DEBUG("maps", "MMAP:loadMapData: Loaded %03i.mmap", mapId);
// store inside our map list
MMapData* mmap_data = new MMapData(mesh);
@@ -156,7 +156,7 @@ namespace MMAP
{
mmap->mmapLoadedTiles.insert(std::pair<uint32, dtTileRef>(packedGridPos, tileRef));
++loadedTiles;
- TC_LOG_INFO("maps", "MMAP:loadMap: Loaded mmtile %03i[%02i, %02i] into %03i[%02i, %02i]", mapId, x, y, mapId, header->x, header->y);
+ TC_LOG_DEBUG("maps", "MMAP:loadMap: Loaded mmtile %03i[%02i, %02i] into %03i[%02i, %02i]", mapId, x, y, mapId, header->x, header->y);
return true;
}
else
@@ -205,7 +205,7 @@ namespace MMAP
{
mmap->mmapLoadedTiles.erase(packedGridPos);
--loadedTiles;
- TC_LOG_INFO("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId);
+ TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId);
return true;
}
@@ -232,13 +232,13 @@ namespace MMAP
else
{
--loadedTiles;
- TC_LOG_INFO("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId);
+ TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId);
}
}
delete mmap;
loadedMMaps.erase(mapId);
- TC_LOG_INFO("maps", "MMAP:unloadMap: Unloaded %03i.mmap", mapId);
+ TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded %03i.mmap", mapId);
return true;
}
@@ -264,7 +264,7 @@ namespace MMAP
dtFreeNavMeshQuery(query);
mmap->navMeshQueries.erase(instanceId);
- TC_LOG_INFO("maps", "MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId);
+ TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId);
return true;
}
@@ -295,7 +295,7 @@ namespace MMAP
return NULL;
}
- TC_LOG_INFO("maps", "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
+ TC_LOG_DEBUG("maps", "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
mmap->navMeshQueries.insert(std::pair<uint32, dtNavMeshQuery*>(instanceId, query));
}
diff --git a/src/server/collision/Management/VMapManager2.cpp b/src/server/collision/Management/VMapManager2.cpp
index f85fceb7b39..f9fcff96ad2 100644
--- a/src/server/collision/Management/VMapManager2.cpp
+++ b/src/server/collision/Management/VMapManager2.cpp
@@ -236,9 +236,11 @@ namespace VMAP
{
floor = info.ground_Z;
ASSERT(floor < std::numeric_limits<float>::max());
+ ASSERT(info.hitModel);
type = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
if (reqLiquidType && !(GetLiquidFlagsPtr(type) & reqLiquidType))
return false;
+ ASSERT(info.hitInstance);
if (info.hitInstance->GetLiquidLevel(pos, info, level))
return true;
}
diff --git a/src/server/collision/Maps/MapTree.cpp b/src/server/collision/Maps/MapTree.cpp
index 72435594ad0..b493ec18f5f 100644
--- a/src/server/collision/Maps/MapTree.cpp
+++ b/src/server/collision/Maps/MapTree.cpp
@@ -386,13 +386,12 @@ namespace VMAP
{
if (!iLoadedSpawns.count(referencedVal))
{
-#ifdef VMAP_DEBUG
if (referencedVal > iNTreeValues)
{
- TC_LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : invalid tree element (%u/%u)", referencedVal, iNTreeValues);
+ VMAP_ERROR_LOG("maps", "StaticMapTree::LoadMapTile() : invalid tree element (%u/%u) referenced in tile %s", referencedVal, iNTreeValues, tilefile.c_str());
continue;
}
-#endif
+
iTreeValues[referencedVal] = ModelInstance(spawn, model);
iLoadedSpawns[referencedVal] = 1;
}
diff --git a/src/server/collision/Maps/TileAssembler.cpp b/src/server/collision/Maps/TileAssembler.cpp
index ee978211577..ec7b759f975 100644
--- a/src/server/collision/Maps/TileAssembler.cpp
+++ b/src/server/collision/Maps/TileAssembler.cpp
@@ -24,7 +24,6 @@
#include <set>
#include <iomanip>
#include <sstream>
-#include <iomanip>
using G3D::Vector3;
using G3D::AABox;
diff --git a/src/server/collision/Models/GameObjectModel.cpp b/src/server/collision/Models/GameObjectModel.cpp
index 05bd5d360c6..0355d2e848c 100644
--- a/src/server/collision/Models/GameObjectModel.cpp
+++ b/src/server/collision/Models/GameObjectModel.cpp
@@ -24,8 +24,6 @@
#include "GameObjectModel.h"
#include "Log.h"
#include "GameObject.h"
-#include "Creature.h"
-#include "TemporarySummon.h"
#include "Object.h"
#include "DBCStores.h"
#include "World.h"
diff --git a/src/server/collision/Models/ModelInstance.cpp b/src/server/collision/Models/ModelInstance.cpp
index 025352eeb58..45440a99666 100644
--- a/src/server/collision/Models/ModelInstance.cpp
+++ b/src/server/collision/Models/ModelInstance.cpp
@@ -19,7 +19,6 @@
#include "ModelInstance.h"
#include "WorldModel.h"
#include "MapTree.h"
-#include "VMapDefinitions.h"
using G3D::Vector3;
using G3D::Ray;
diff --git a/src/server/collision/Models/WorldModel.cpp b/src/server/collision/Models/WorldModel.cpp
index 3af120045cb..86ab9366c71 100644
--- a/src/server/collision/Models/WorldModel.cpp
+++ b/src/server/collision/Models/WorldModel.cpp
@@ -17,7 +17,6 @@
*/
#include "WorldModel.h"
-#include "ModelInstance.h"
#include "VMapDefinitions.h"
#include "MapTree.h"
diff --git a/src/server/game/AI/CoreAI/GuardAI.cpp b/src/server/game/AI/CoreAI/GuardAI.cpp
index 14e5faaf723..7fd1493cbde 100644
--- a/src/server/game/AI/CoreAI/GuardAI.cpp
+++ b/src/server/game/AI/CoreAI/GuardAI.cpp
@@ -19,9 +19,6 @@
#include "GuardAI.h"
#include "Errors.h"
#include "Player.h"
-#include "ObjectAccessor.h"
-#include "World.h"
-#include "CreatureAIImpl.h"
int GuardAI::Permissible(Creature const* creature)
{
diff --git a/src/server/game/AI/CoreAI/PassiveAI.cpp b/src/server/game/AI/CoreAI/PassiveAI.cpp
index fb16d39dab3..5c482120b21 100644
--- a/src/server/game/AI/CoreAI/PassiveAI.cpp
+++ b/src/server/game/AI/CoreAI/PassiveAI.cpp
@@ -18,7 +18,6 @@
#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); }
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp
index f532e4cd862..2522c97de25 100644
--- a/src/server/game/AI/CoreAI/PetAI.cpp
+++ b/src/server/game/AI/CoreAI/PetAI.cpp
@@ -20,12 +20,11 @@
#include "Errors.h"
#include "Pet.h"
#include "Player.h"
-#include "DBCStores.h"
#include "Spell.h"
#include "ObjectAccessor.h"
+#include "SpellHistory.h"
#include "SpellMgr.h"
#include "Creature.h"
-#include "World.h"
#include "Util.h"
#include "Group.h"
#include "SpellInfo.h"
@@ -148,15 +147,15 @@ void PetAI::UpdateAI(uint32 diff)
if (!spellInfo)
continue;
- if (me->GetCharmInfo() && me->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo))
+ if (me->GetCharmInfo() && me->GetSpellHistory()->HasGlobalCooldown(spellInfo))
continue;
if (spellInfo->IsPositive())
{
if (spellInfo->CanBeUsedInCombat())
{
- // check spell cooldown
- if (me->HasSpellCooldown(spellInfo->Id))
+ // check spell cooldown & school lock
+ if (!me->GetSpellHistory()->IsReady(spellInfo))
continue;
// Check if we're in combat or commanded to attack
diff --git a/src/server/game/AI/CoreAI/ReactorAI.cpp b/src/server/game/AI/CoreAI/ReactorAI.cpp
index ebb57038737..9ab86047dc8 100644
--- a/src/server/game/AI/CoreAI/ReactorAI.cpp
+++ b/src/server/game/AI/CoreAI/ReactorAI.cpp
@@ -18,10 +18,6 @@
#include "ByteBuffer.h"
#include "ReactorAI.h"
-#include "Errors.h"
-#include "Log.h"
-#include "ObjectAccessor.h"
-#include "CreatureAIImpl.h"
int ReactorAI::Permissible(const Creature* creature)
{
diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp
index 983e212b33c..57e926744e2 100644
--- a/src/server/game/AI/CoreAI/TotemAI.cpp
+++ b/src/server/game/AI/CoreAI/TotemAI.cpp
@@ -19,10 +19,8 @@
#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"
diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp
index e7d39d715eb..5aa6ea8ea7a 100644
--- a/src/server/game/AI/CoreAI/UnitAI.cpp
+++ b/src/server/game/AI/CoreAI/UnitAI.cpp
@@ -141,7 +141,7 @@ void UnitAI::DoCast(uint32 spellId)
{
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId))
{
- bool playerOnly = (spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS) != 0;
+ bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS);
target = SelectTarget(SELECT_TARGET_RANDOM, 0, spellInfo->GetMaxRange(false), playerOnly);
}
break;
@@ -156,7 +156,7 @@ void UnitAI::DoCast(uint32 spellId)
{
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId))
{
- bool playerOnly = (spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS) != 0;
+ bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS);
float range = spellInfo->GetMaxRange(false);
DefaultTargetSelector targetSelector(me, range, playerOnly, -(int32)spellId);
@@ -213,7 +213,7 @@ void UnitAI::FillAISpellInfo()
if (!spellInfo)
continue;
- if (spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD))
AIInfo->condition = AICOND_DIE;
else if (spellInfo->IsPassive() || spellInfo->GetDuration() == -1)
AIInfo->condition = AICOND_AGGRO;
diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h
index 9eafcc30c81..efe55830b1b 100644
--- a/src/server/game/AI/CoreAI/UnitAI.h
+++ b/src/server/game/AI/CoreAI/UnitAI.h
@@ -128,7 +128,7 @@ class UnitAI
virtual void InitializeAI() { if (!me->isDead()) Reset(); }
- virtual void Reset() { };
+ virtual void Reset() { }
// Called when unit is charmed
virtual void OnCharmed(bool apply) = 0;
diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp
index 9d025e3c2e2..07bd49bdcc6 100644
--- a/src/server/game/AI/CreatureAISelector.cpp
+++ b/src/server/game/AI/CreatureAISelector.cpp
@@ -21,7 +21,6 @@
#include "PassiveAI.h"
#include "MovementGenerator.h"
-#include "Pet.h"
#include "TemporarySummon.h"
#include "CreatureAIFactory.h"
#include "ScriptMgr.h"
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
index 135a0fcee93..aa7ec3b847f 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
@@ -17,14 +17,12 @@
*/
#include "ScriptedCreature.h"
-#include "Item.h"
#include "Spell.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "Cell.h"
#include "CellImpl.h"
#include "ObjectMgr.h"
-#include "TemporarySummon.h"
// Spell summary for ScriptedAI::SelectSpell
struct TSpellSummary
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index 76f08952664..21a15fa4f99 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -21,11 +21,7 @@
#include "GridDefines.h"
#include "GridNotifiers.h"
#include "SpellMgr.h"
-#include "GridNotifiersImpl.h"
#include "Cell.h"
-#include "CellImpl.h"
-#include "InstanceScript.h"
-#include "ScriptedCreature.h"
#include "Group.h"
#include "SmartAI.h"
#include "ScriptMgr.h"
@@ -585,7 +581,11 @@ void SmartAI::JustDied(Unit* killer)
{
GetScript()->ProcessEventsFor(SMART_EVENT_DEATH, killer);
if (HasEscortState(SMART_ESCORT_ESCORTING))
+ {
EndPath(true);
+ me->StopMoving();//force stop
+ me->GetMotionMaster()->MoveIdle();
+ }
}
void SmartAI::KilledUnit(Unit* victim)
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index e7e5f53f7a2..267c038faaf 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -35,7 +35,6 @@
#include "SmartScript.h"
#include "SpellMgr.h"
#include "Vehicle.h"
-#include "MoveSplineInit.h"
#include "GameEventMgr.h"
SmartScript::SmartScript()
@@ -61,6 +60,7 @@ SmartScript::~SmartScript()
delete itr->second;
delete mTargetStorage;
+ mCounterList.clear();
}
void SmartScript::OnReset()
@@ -77,6 +77,7 @@ void SmartScript::OnReset()
}
ProcessEventsFor(SMART_EVENT_RESET);
mLastInvoker.Clear();
+ mCounterList.clear();
}
void SmartScript::ProcessEventsFor(SMART_EVENT e, Unit* unit, uint32 var0, uint32 var1, bool bvar, const SpellInfo* spell, GameObject* gob)
@@ -1318,6 +1319,35 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
ENSURE_AI(SmartAI, me->AI())->SetSwim(e.action.setSwim.swim != 0);
break;
}
+ case SMART_ACTION_SET_COUNTER:
+ {
+ if (ObjectList* targets = GetTargets(e, unit))
+ {
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ {
+ if (IsCreature(*itr))
+ {
+ if (SmartAI* ai = CAST_AI(SmartAI, (*itr)->ToCreature()->AI()))
+ ai->GetScript()->StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset);
+ else
+ TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartAI, skipping");
+ }
+ else if (IsGameObject(*itr))
+ {
+ if (SmartGameObjectAI* ai = CAST_AI(SmartGameObjectAI, (*itr)->ToGameObject()->AI()))
+ ai->GetScript()->StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset);
+ else
+ TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartGameObjectAI, skipping");
+ }
+ }
+
+ delete targets;
+ }
+ else
+ StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset);
+
+ break;
+ }
case SMART_ACTION_WP_START:
{
if (!IsSmart())
@@ -3167,7 +3197,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
std::list<Creature*> list;
me->GetCreatureListWithEntryInGrid(list, e.event.distance.entry, (float)e.event.distance.dist);
- if (list.size() > 0)
+ if (!list.empty())
creature = list.front();
}
@@ -3198,7 +3228,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
std::list<GameObject*> list;
me->GetGameObjectListWithEntryInGrid(list, e.event.distance.entry, (float)e.event.distance.dist);
- if (list.size() > 0)
+ if (!list.empty())
gameobject = list.front();
}
@@ -3207,6 +3237,10 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
break;
}
+ case SMART_EVENT_COUNTER_SET:
+ if (GetCounterId(e.event.counter.id) != 0 && GetCounterValue(e.event.counter.id) == e.event.counter.value)
+ ProcessTimedAction(e, e.event.counter.cooldownMin, e.event.counter.cooldownMax);
+ break;
default:
TC_LOG_ERROR("sql.sql", "SmartScript::ProcessEvent: Unhandled Event type %u", e.GetEventType());
break;
diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h
index ed1c63de207..a3d75f1889b 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.h
+++ b/src/server/game/AI/SmartScripts/SmartScript.h
@@ -145,6 +145,36 @@ class SmartScript
return NULL;
}
+ void StoreCounter(uint32 id, uint32 value, uint32 reset)
+ {
+ CounterMap::const_iterator itr = mCounterList.find(id);
+ if (itr != mCounterList.end())
+ {
+ if (reset == 0)
+ value += GetCounterValue(id);
+ mCounterList.erase(id);
+ }
+
+ mCounterList.insert(std::make_pair(id, value));
+ ProcessEventsFor(SMART_EVENT_COUNTER_SET);
+ }
+
+ uint32 GetCounterId(uint32 id)
+ {
+ CounterMap::iterator itr = mCounterList.find(id);
+ if (itr != mCounterList.end())
+ return itr->first;
+ return 0;
+ }
+
+ uint32 GetCounterValue(uint32 id)
+ {
+ CounterMap::iterator itr = mCounterList.find(id);
+ if (itr != mCounterList.end())
+ return itr->second;
+ return 0;
+ }
+
GameObject* FindGameObjectNear(WorldObject* searchObject, uint32 guid) const
{
GameObject* gameObject = NULL;
@@ -205,6 +235,8 @@ class SmartScript
void SetScript9(SmartScriptHolder& e, uint32 entry);
Unit* GetLastInvoker();
ObjectGuid mLastInvoker;
+ typedef std::unordered_map<uint32, uint32> CounterMap;
+ CounterMap mCounterList;
private:
void IncPhase(int32 p = 1)
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index becc3bd92cd..37187d9b04c 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -17,18 +17,12 @@
#include "DatabaseEnv.h"
#include "ObjectMgr.h"
-#include "ObjectDefines.h"
#include "GridDefines.h"
#include "GridNotifiers.h"
#include "SpellMgr.h"
-#include "GridNotifiersImpl.h"
#include "Cell.h"
-#include "CellImpl.h"
-#include "InstanceScript.h"
-#include "ScriptedCreature.h"
#include "GameEventMgr.h"
#include "CreatureTextMgr.h"
-#include "SpellMgr.h"
#include "SpellInfo.h"
#include "SmartScriptMgr.h"
@@ -695,6 +689,22 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
return false;
}
break;
+ case SMART_EVENT_COUNTER_SET:
+ if (!IsMinMaxValid(e, e.event.counter.cooldownMin, e.event.counter.cooldownMax))
+ return false;
+
+ if (e.event.counter.id == 0)
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_COUNTER_SET using invalid counter id %u, skipped.", e.event.counter.id);
+ return false;
+ }
+
+ if (e.event.counter.value == 0)
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_COUNTER_SET using invalid value %u, skipped.", e.event.counter.value);
+ return false;
+ }
+ break;
case SMART_EVENT_LINK:
case SMART_EVENT_GO_STATE_CHANGED:
case SMART_EVENT_GO_EVENT_INFORM:
@@ -998,6 +1008,20 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
return false;
}
break;
+ case SMART_ACTION_SET_COUNTER:
+ if (e.action.setCounter.counterId == 0)
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses wrong counterId %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.setCounter.counterId);
+ return false;
+ }
+
+ if (e.action.setCounter.value == 0)
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses wrong value %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.setCounter.value);
+ return false;
+ }
+
+ break;
case SMART_ACTION_INSTALL_AI_TEMPLATE:
if (e.action.installTtemplate.id >= SMARTAI_TEMPLATE_END)
{
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 0ed8542c72a..1f4891d6c24 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -167,8 +167,9 @@ enum SMART_EVENT
SMART_EVENT_FRIENDLY_HEALTH_PCT = 74, // minHpPct, maxHpPct, repeatMin, repeatMax
SMART_EVENT_DISTANCE_CREATURE = 75, // guid, entry, distance, repeat
SMART_EVENT_DISTANCE_GAMEOBJECT = 76, // guid, entry, distance, repeat
+ SMART_EVENT_COUNTER_SET = 77, // id, value, cooldownMin, cooldownMax
- SMART_EVENT_END = 77
+ SMART_EVENT_END = 78
};
struct SmartEvent
@@ -398,6 +399,14 @@ struct SmartEvent
struct
{
+ uint32 id;
+ uint32 value;
+ uint32 cooldownMin;
+ uint32 cooldownMax;
+ } counter;
+
+ struct
+ {
uint32 param1;
uint32 param2;
uint32 param3;
@@ -479,7 +488,7 @@ enum SMART_ACTION
SMART_ACTION_SET_FLY = 60, // 0/1
SMART_ACTION_SET_SWIM = 61, // 0/1
SMART_ACTION_TELEPORT = 62, // mapID,
- // 63 unused
+ SMART_ACTION_SET_COUNTER = 63, // id, value, reset (0/1)
SMART_ACTION_STORE_TARGET_LIST = 64, // varID,
SMART_ACTION_WP_RESUME = 65, // none
SMART_ACTION_SET_ORIENTATION = 66, //
@@ -824,6 +833,13 @@ struct SmartAction
struct
{
+ uint32 counterId;
+ uint32 value;
+ uint32 reset;
+ } setCounter;
+
+ struct
+ {
uint32 id;
uint32 number;
} storeVar;
@@ -1294,6 +1310,7 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] =
{SMART_EVENT_FRIENDLY_HEALTH_PCT, SMART_SCRIPT_TYPE_MASK_CREATURE },
{SMART_EVENT_DISTANCE_CREATURE, SMART_SCRIPT_TYPE_MASK_CREATURE },
{SMART_EVENT_DISTANCE_GAMEOBJECT, SMART_SCRIPT_TYPE_MASK_CREATURE },
+ {SMART_EVENT_COUNTER_SET, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }
};
enum SmartEventFlags
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index 8f9db8d5a27..339788dee01 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -802,6 +802,7 @@ class RBACData
* @return Success or failure (with reason) to grant the permission
*
* Example Usage:
+ * @code
* // previously defined "RBACData* rbac" with proper initialization
* uint32 permissionId = 2;
* if (rbac->GrantRole(permissionId) == RBAC_IN_DENIED_LIST)
@@ -825,6 +826,7 @@ class RBACData
* @return Success or failure (with reason) to deny the permission
*
* Example Usage:
+ * @code
* // previously defined "RBACData* rbac" with proper initialization
* uint32 permissionId = 2;
* if (rbac->DenyRole(permissionId) == RBAC_ID_DOES_NOT_EXISTS)
@@ -849,6 +851,7 @@ class RBACData
* @return Success or failure (with reason) to remove the permission
*
* Example Usage:
+ * @code
* // previously defined "RBACData* rbac" with proper initialization
* uint32 permissionId = 2;
* if (rbac->RevokeRole(permissionId) == RBAC_OK)
@@ -939,9 +942,6 @@ class RBACData
*
* Given a list of permissions, gets all the inherited permissions
* @param permissions The list of permissions to expand
- *
- * @return new list of permissions containing original permissions and
- * all other pemissions that are linked to the original ones
*/
void ExpandPermissions(RBACPermissionContainer& permissions);
diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp
index 4f4302f823c..51106d7cfe1 100644
--- a/src/server/game/Achievements/AchievementMgr.cpp
+++ b/src/server/game/Achievements/AchievementMgr.cpp
@@ -1508,7 +1508,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement)
if (achievement->flags & ACHIEVEMENT_FLAG_COUNTER || HasAchieved(achievement->ID))
return;
- TC_LOG_INFO("achievement", "AchievementMgr::CompletedAchievement(%u). Player: %s (%u)",
+ TC_LOG_DEBUG("achievement", "AchievementMgr::CompletedAchievement(%u). Player: %s (%u)",
achievement->ID, m_player->GetName().c_str(), m_player->GetGUIDLow());
SendAchievementEarned(achievement);
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index e8c91479cc2..16d5f4b6959 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -30,7 +30,6 @@
#include "Item.h"
#include "Language.h"
#include "Log.h"
-#include <vector>
enum eAuctionHouse
{
@@ -440,8 +439,6 @@ bool AuctionHouseObject::RemoveAuction(AuctionEntry* auction)
// we need to delete the entry, it is not referenced any more
delete auction;
- auction = NULL;
-
return wasInMap;
}
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp
index bd5defe2bc3..64463948574 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp
@@ -64,7 +64,7 @@ void AuctionBotBuyer::LoadConfig()
}
}
-void AuctionBotBuyer::LoadBuyerValues(BuyerConfiguration& config)
+void AuctionBotBuyer::LoadBuyerValues(BuyerConfiguration& /* config */)
{
}
diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp
index ba52c8db2f5..a22db18fa7e 100644
--- a/src/server/game/Battlefield/Battlefield.cpp
+++ b/src/server/game/Battlefield/Battlefield.cpp
@@ -21,7 +21,6 @@
#include "CellImpl.h"
#include "CreatureTextMgr.h"
#include "GridNotifiers.h"
-#include "GridNotifiersImpl.h"
#include "Group.h"
#include "GroupMgr.h"
#include "Map.h"
diff --git a/src/server/game/Battlefield/BattlefieldMgr.cpp b/src/server/game/Battlefield/BattlefieldMgr.cpp
index 066588aa6e8..0060cf4f304 100644
--- a/src/server/game/Battlefield/BattlefieldMgr.cpp
+++ b/src/server/game/Battlefield/BattlefieldMgr.cpp
@@ -17,7 +17,6 @@
#include "BattlefieldMgr.h"
#include "BattlefieldWG.h"
-#include "ObjectMgr.h"
#include "Player.h"
BattlefieldMgr::BattlefieldMgr()
diff --git a/src/server/game/Battlegrounds/ArenaTeam.cpp b/src/server/game/Battlegrounds/ArenaTeam.cpp
index 7ed05205f39..3b7e9ac3f33 100644
--- a/src/server/game/Battlegrounds/ArenaTeam.cpp
+++ b/src/server/game/Battlegrounds/ArenaTeam.cpp
@@ -179,7 +179,7 @@ bool ArenaTeam::AddMember(ObjectGuid playerGuid)
player->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_MEMBER, 1);
}
- TC_LOG_INFO("bg.arena", "Player: %s [%s] joined arena team type: %u [Id: %u, Name: %s].", playerName.c_str(), playerGuid.ToString().c_str(), GetType(), GetId(), GetName().c_str());
+ TC_LOG_DEBUG("bg.arena", "Player: %s [%s] joined arena team type: %u [Id: %u, Name: %s].", playerName.c_str(), playerGuid.ToString().c_str(), GetType(), GetId(), GetName().c_str());
return true;
}
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp
index e091df160a3..3e9b68d4611 100644
--- a/src/server/game/Battlegrounds/Battleground.cpp
+++ b/src/server/game/Battlegrounds/Battleground.cpp
@@ -26,12 +26,10 @@
#include "Formulas.h"
#include "GridNotifiersImpl.h"
#include "Group.h"
-#include "MapManager.h"
#include "Object.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "ReputationMgr.h"
-#include "SpellAuraEffects.h"
#include "SpellAuras.h"
#include "Util.h"
#include "WorldPacket.h"
@@ -510,7 +508,7 @@ inline void Battleground::_ProcessJoin(uint32 diff)
if (!aura->IsPermanent()
&& aura->GetDuration() <= 30*IN_MILLISECONDS
&& aurApp->IsPositive()
- && (!(aura->GetSpellInfo()->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
+ && (!aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
&& (!aura->HasEffectType(SPELL_AURA_MOD_INVISIBILITY)))
player->RemoveAura(iter);
else
diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp
index e98cf979cb6..95a51f6d915 100644
--- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp
+++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp
@@ -22,7 +22,6 @@
#include "World.h"
#include "WorldPacket.h"
-#include "ArenaTeam.h"
#include "BattlegroundMgr.h"
#include "BattlegroundAV.h"
#include "BattlegroundAB.h"
@@ -37,7 +36,6 @@
#include "BattlegroundIC.h"
#include "Chat.h"
#include "Map.h"
-#include "MapInstanced.h"
#include "MapManager.h"
#include "Player.h"
#include "GameEventMgr.h"
diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.cpp b/src/server/game/Battlegrounds/BattlegroundQueue.cpp
index 05bcc08f433..43b7acde925 100644
--- a/src/server/game/Battlegrounds/BattlegroundQueue.cpp
+++ b/src/server/game/Battlegrounds/BattlegroundQueue.cpp
@@ -24,8 +24,8 @@
#include "Group.h"
#include "Log.h"
#include "Language.h"
-#include "ObjectMgr.h"
#include "Player.h"
+#include "ObjectAccessor.h"
/*********************************************************/
/*** BATTLEGROUND QUEUE SYSTEM ***/
@@ -889,7 +889,8 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 /*diff*/, BattlegroundTyp
// (after what time the ratings aren't taken into account when making teams) then
// the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
// else leave the discard time on 0, this way all ratings will be discarded
- uint32 discardTime = getMSTime() - sBattlegroundMgr->GetRatingDiscardTimer();
+ // this has to be signed value - when the server starts, this value would be negative and thus overflow
+ int32 discardTime = getMSTime() - sBattlegroundMgr->GetRatingDiscardTimer();
// we need to find 2 teams which will play next game
GroupsQueueType::iterator itr_teams[BG_TEAMS_COUNT];
@@ -905,7 +906,7 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 /*diff*/, BattlegroundTyp
// if group match conditions, then add it to pool
if (!(*itr2)->IsInvitedToBGInstanceGUID
&& (((*itr2)->ArenaMatchmakerRating >= arenaMinRating && (*itr2)->ArenaMatchmakerRating <= arenaMaxRating)
- || (*itr2)->JoinTime < discardTime))
+ || (int32)(*itr2)->JoinTime < discardTime))
{
itr_teams[found++] = itr2;
team = i;
@@ -923,7 +924,7 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 /*diff*/, BattlegroundTyp
{
if (!(*itr3)->IsInvitedToBGInstanceGUID
&& (((*itr3)->ArenaMatchmakerRating >= arenaMinRating && (*itr3)->ArenaMatchmakerRating <= arenaMaxRating)
- || (*itr3)->JoinTime < discardTime)
+ || (int32)(*itr3)->JoinTime < discardTime)
&& (*itr_teams[0])->ArenaTeamId != (*itr3)->ArenaTeamId)
{
itr_teams[found++] = itr3;
diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.h b/src/server/game/Battlegrounds/BattlegroundQueue.h
index b0adaa4078d..7e8debfd24d 100644
--- a/src/server/game/Battlegrounds/BattlegroundQueue.h
+++ b/src/server/game/Battlegrounds/BattlegroundQueue.h
@@ -106,7 +106,7 @@ class BattlegroundQueue
class SelectionPool
{
public:
- SelectionPool(): PlayerCount(0) { };
+ SelectionPool(): PlayerCount(0) { }
void Init();
bool AddGroup(GroupQueueInfo* ginfo, uint32 desiredCount);
bool KickGroup(uint32 size);
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
index 2aec542effb..00b6862369d 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
@@ -17,9 +17,7 @@
*/
#include "BattlegroundAB.h"
-#include "World.h"
#include "WorldPacket.h"
-#include "ObjectMgr.h"
#include "BattlegroundMgr.h"
#include "Creature.h"
#include "Language.h"
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
index b6569a9f52d..a92cda0817b 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
@@ -26,7 +26,6 @@
#include "Language.h"
#include "Player.h"
#include "ScriptedCreature.h"
-#include "SpellAuras.h"
#include "WorldSession.h"
BattlegroundAV::BattlegroundAV()
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
index 92f5c72fdae..ef2e2b15411 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
@@ -18,7 +18,6 @@
#include "BattlegroundEY.h"
#include "ObjectMgr.h"
-#include "World.h"
#include "WorldPacket.h"
#include "BattlegroundMgr.h"
#include "Creature.h"
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
index ef5a604c509..3432c740c1f 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp
@@ -25,7 +25,6 @@
#include "ObjectMgr.h"
#include "Vehicle.h"
#include "Transport.h"
-#include "WorldSession.h"
#include "ScriptedCreature.h"
BattlegroundIC::BattlegroundIC()
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
index cbc0c0e445d..f267bf7c6c6 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
@@ -23,7 +23,6 @@
#include "Player.h"
#include "ScriptedCreature.h"
#include "WorldPacket.h"
-#include "WorldSession.h"
BattlegroundSA::BattlegroundSA()
{
@@ -100,7 +99,7 @@ bool BattlegroundSA::ResetObjs()
for (uint8 i = BG_SA_MAXNPC; i < BG_SA_MAXNPC + BG_SA_MAX_GY; i++)
DelCreature(i);
- for (uint8 i = 0; i < 6; i++)
+ for (uint8 i = 0; i < MAX_GATES; ++i)
GateStatus[i] = BG_SA_GATE_OK;
if (!AddCreature(BG_SA_NpcEntries[BG_SA_NPC_KANRETHAD], BG_SA_NPC_KANRETHAD, BG_SA_NpcSpawnlocs[BG_SA_NPC_KANRETHAD]))
@@ -180,9 +179,6 @@ bool BattlegroundSA::ResetObjs()
GetBGObject(BG_SA_TITAN_RELIC)->SetFaction(atF);
GetBGObject(BG_SA_TITAN_RELIC)->Refresh();
- for (uint8 i = 0; i <= 5; i++)
- GateStatus[i] = BG_SA_GATE_OK;
-
TotalTime = 0;
ShipsStarted = false;
@@ -222,6 +218,8 @@ bool BattlegroundSA::ResetObjs()
GetBGObject(i)->SetFaction(atF);
}
+ UpdateObjectInteractionFlags();
+
for (uint8 i = BG_SA_BOMB; i < BG_SA_MAXOBJ; i++)
{
if (!AddObject(i, BG_SA_ObjEntries[BG_SA_BOMB], BG_SA_ObjSpawnlocs[i], 0, 0, 0, 0, RESPAWN_ONE_DAY))
@@ -482,28 +480,7 @@ void BattlegroundSA::AddPlayer(Player* player)
SendTransportInit(player);
- if (!ShipsStarted)
- {
- if (player->GetTeamId() == Attackers)
- {
- player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
-
- if (urand(0, 1))
- player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f, 0);
- else
- player->TeleportTo(607, 2577.003f, 980.261f, 15.0f, 0.807f, 0);
-
- }
- else
- player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0);
- }
- else
- {
- if (player->GetTeamId() == Attackers)
- player->TeleportTo(607, 1600.381f, -106.263f, 8.8745f, 3.78f, 0);
- else
- player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0);
- }
+ TeleportToEntrancePosition(player);
}
void BattlegroundSA::RemovePlayer(Player* /*player*/, ObjectGuid /*guid*/, uint32 /*team*/) { }
@@ -534,23 +511,31 @@ void BattlegroundSA::TeleportPlayers()
player->ResetAllPowers();
player->CombatStopWithPets(true);
- for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
- if (Player* p = ObjectAccessor::FindPlayer(itr->first))
- p->CastSpell(p, SPELL_PREPARATION, true);
+ player->CastSpell(player, SPELL_PREPARATION, true);
- if (player->GetTeamId() == Attackers)
- {
- player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ TeleportToEntrancePosition(player);
+ }
+ }
+}
- if (urand(0, 1))
- player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f, 0);
- else
- player->TeleportTo(607, 2577.003f, 980.261f, 15.0f, 0.807f, 0);
- }
+void BattlegroundSA::TeleportToEntrancePosition(Player* player)
+{
+ if (player->GetTeamId() == Attackers)
+ {
+ if (!ShipsStarted)
+ {
+ player->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+
+ if (urand(0, 1))
+ player->TeleportTo(607, 2682.936f, -830.368f, 15.0f, 2.895f, 0);
else
- player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0);
+ player->TeleportTo(607, 2577.003f, 980.261f, 15.0f, 0.807f, 0);
}
+ else
+ player->TeleportTo(607, 1600.381f, -106.263f, 8.8745f, 3.78f, 0);
}
+ else
+ player->TeleportTo(607, 1209.7f, -65.16f, 70.1f, 0.0f, 0);
}
void BattlegroundSA::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker /*= NULL*/)
@@ -629,6 +614,8 @@ void BattlegroundSA::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject*
}
}
}
+
+ UpdateObjectInteractionFlags();
}
else
break;
@@ -712,7 +699,7 @@ WorldSafeLocsEntry const* BattlegroundSA::GetClosestGraveYard(Player* player)
safeloc = BG_SA_GYEntries[BG_SA_DEFENDER_LAST_GY];
closest = sWorldSafeLocsStore.LookupEntry(safeloc);
- nearest = std::sqrt((closest->x - x)*(closest->x - x) + (closest->y - y)*(closest->y - y) + (closest->z - z)*(closest->z - z));
+ nearest = player->GetExactDistSq(closest->x, closest->y, closest->z);
for (uint8 i = BG_SA_RIGHT_CAPTURABLE_GY; i < BG_SA_MAX_GY; i++)
{
@@ -720,7 +707,7 @@ WorldSafeLocsEntry const* BattlegroundSA::GetClosestGraveYard(Player* player)
continue;
ret = sWorldSafeLocsStore.LookupEntry(BG_SA_GYEntries[i]);
- dist = std::sqrt((ret->x - x)*(ret->x - x) + (ret->y - y)*(ret->y - y) + (ret->z - z)*(ret->z - z));
+ dist = player->GetExactDistSq(ret->x, ret->y, ret->z);
if (dist < nearest)
{
closest = ret;
@@ -739,23 +726,66 @@ void BattlegroundSA::SendTime()
UpdateWorldState(BG_SA_TIMER_SEC_DECS, ((end_of_round%60000)%10000)/1000);
}
+bool BattlegroundSA::CanInteractWithObject(uint32 objectId)
+{
+ switch (objectId)
+ {
+ case BG_SA_TITAN_RELIC:
+ if (GateStatus[BG_SA_ANCIENT_GATE] != BG_SA_GATE_DESTROYED || GateStatus[BG_SA_YELLOW_GATE] != BG_SA_GATE_DESTROYED)
+ return false;
+ // no break
+ case BG_SA_CENTRAL_FLAG:
+ if (GateStatus[BG_SA_RED_GATE] != BG_SA_GATE_DESTROYED && GateStatus[BG_SA_PURPLE_GATE] != BG_SA_GATE_DESTROYED)
+ return false;
+ // no break
+ case BG_SA_LEFT_FLAG:
+ case BG_SA_RIGHT_FLAG:
+ if (GateStatus[BG_SA_GREEN_GATE] != BG_SA_GATE_DESTROYED && GateStatus[BG_SA_BLUE_GATE] != BG_SA_GATE_DESTROYED)
+ return false;
+ break;
+ default:
+ ASSERT(false);
+ break;
+ }
+
+ return true;
+}
+
+void BattlegroundSA::UpdateObjectInteractionFlags(uint32 objectId)
+{
+ if (GameObject* go = GetBGObject(objectId))
+ {
+ if (CanInteractWithObject(objectId))
+ go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
+ else
+ go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
+ }
+}
+
+void BattlegroundSA::UpdateObjectInteractionFlags()
+{
+ for (uint8 i = BG_SA_CENTRAL_FLAG; i <= BG_SA_LEFT_FLAG; ++i)
+ UpdateObjectInteractionFlags(i);
+ UpdateObjectInteractionFlags(BG_SA_TITAN_RELIC);
+}
+
void BattlegroundSA::EventPlayerClickedOnFlag(Player* source, GameObject* go)
{
switch (go->GetEntry())
{
case 191307:
case 191308:
- if (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED)
+ if (CanInteractWithObject(BG_SA_LEFT_FLAG))
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)
+ if (CanInteractWithObject(BG_SA_RIGHT_FLAG))
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))
+ if (CanInteractWithObject(BG_SA_CENTRAL_FLAG))
CaptureGraveyard(BG_SA_CENTRAL_CAPTURABLE_GY, source);
break;
default:
@@ -857,10 +887,7 @@ void BattlegroundSA::TitanRelicActivated(Player* clicker)
if (!clicker)
return;
- if (GateStatus[BG_SA_ANCIENT_GATE] == BG_SA_GATE_DESTROYED &&
- GateStatus[BG_SA_YELLOW_GATE] == BG_SA_GATE_DESTROYED &&
- (GateStatus[BG_SA_PURPLE_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_RED_GATE] == BG_SA_GATE_DESTROYED) &&
- (GateStatus[BG_SA_GREEN_GATE] == BG_SA_GATE_DESTROYED || GateStatus[BG_SA_BLUE_GATE] == BG_SA_GATE_DESTROYED))
+ if (CanInteractWithObject(BG_SA_TITAN_RELIC))
{
if (clicker->GetTeamId() == Attackers)
{
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h
index 7f9a656c979..118cea41a7b 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h
@@ -620,6 +620,7 @@ class BattlegroundSA : public Battleground
* -Teleport all players to good location
*/
void TeleportPlayers();
+ void TeleportToEntrancePosition(Player* player);
/**
* \brief Called on start and between the two round
* -Update faction of all vehicle
@@ -627,6 +628,11 @@ class BattlegroundSA : public Battleground
void OverrideGunFaction();
/// Set selectable or not demolisher, called on battle start, when boats arrive to dock
void DemolisherStartState(bool start);
+ /// Checks if a player can interact with the given object
+ bool CanInteractWithObject(uint32 objectId);
+ /// Updates interaction flags of specific objects
+ void UpdateObjectInteractionFlags(uint32 objectId);
+ void UpdateObjectInteractionFlags();
/**
* \brief Called when a gate is destroy
* -Give honor to player witch destroy it
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp
index 1fff334a27c..378ce22ba3e 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp
@@ -17,14 +17,12 @@
*/
#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
diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt
index eb8627efa44..91380b085ea 100644
--- a/src/server/game/CMakeLists.txt
+++ b/src/server/game/CMakeLists.txt
@@ -110,6 +110,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/SFMT
+ ${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/zlib
${CMAKE_SOURCE_DIR}/src/server/collision
${CMAKE_SOURCE_DIR}/src/server/collision/Management
@@ -128,6 +129,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/server/shared/Networking
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
${CMAKE_SOURCE_DIR}/src/server/shared/Threading
+ ${CMAKE_SOURCE_DIR}/src/server/shared/Updater
${CMAKE_SOURCE_DIR}/src/server/shared/Utilities
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/Accounts
@@ -206,6 +208,8 @@ include_directories(
${VALGRIND_INCLUDE_DIR}
)
+GroupSources(${CMAKE_CURRENT_SOURCE_DIR})
+
add_library(game STATIC
${game_STAT_SRCS}
${game_STAT_PCH_SRC}
diff --git a/src/server/game/Chat/Channels/Channel.h b/src/server/game/Chat/Channels/Channel.h
index 9b9c2f1e514..0f2a940e3b4 100644
--- a/src/server/game/Chat/Channels/Channel.h
+++ b/src/server/game/Chat/Channels/Channel.h
@@ -184,7 +184,7 @@ class Channel
void DeVoice(ObjectGuid guid1, ObjectGuid guid2);
void JoinNotify(ObjectGuid guid); // invisible notify
void LeaveNotify(ObjectGuid guid); // invisible notify
- void SetOwnership(bool ownership) { _ownership = ownership; };
+ void SetOwnership(bool ownership) { _ownership = ownership; }
static void CleanOldChannelsInDB();
private:
diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp
index 44df1097dd4..1716aa73525 100644
--- a/src/server/game/Chat/Chat.cpp
+++ b/src/server/game/Chat/Chat.cpp
@@ -32,7 +32,6 @@
#include "Opcodes.h"
#include "Player.h"
#include "UpdateMask.h"
-#include "SpellMgr.h"
#include "ScriptMgr.h"
#include "ChatLink.h"
@@ -104,17 +103,6 @@ ChatCommand* ChatHandler::getCommandTable()
return commandTableCache;
}
-std::string ChatHandler::PGetParseString(uint32 entry, ...) const
-{
- const char *format = GetTrinityString(entry);
- char str[1024];
- va_list ap;
- va_start(ap, entry);
- vsnprintf(str, 1024, format, ap);
- va_end(ap);
- return std::string(str);
-}
-
char const* ChatHandler::GetTrinityString(uint32 entry) const
{
return m_session->GetTrinityString(entry);
@@ -258,27 +246,6 @@ void ChatHandler::SendSysMessage(uint32 entry)
SendSysMessage(GetTrinityString(entry));
}
-void ChatHandler::PSendSysMessage(uint32 entry, ...)
-{
- const char *format = GetTrinityString(entry);
- va_list ap;
- char str [2048];
- va_start(ap, entry);
- vsnprintf(str, 2048, format, ap);
- va_end(ap);
- SendSysMessage(str);
-}
-
-void ChatHandler::PSendSysMessage(const char *format, ...)
-{
- va_list ap;
- char str [2048];
- va_start(ap, format);
- vsnprintf(str, 2048, format, ap);
- va_end(ap);
- SendSysMessage(str);
-}
-
bool ChatHandler::ExecuteCommandInTable(ChatCommand* table, const char* text, std::string const& fullcmd)
{
char const* oldtext = text;
diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h
index d712740bd7d..ba59245cdaa 100644
--- a/src/server/game/Chat/Chat.h
+++ b/src/server/game/Chat/Chat.h
@@ -20,6 +20,7 @@
#define TRINITYCORE_CHAT_H
#include "SharedDefines.h"
+#include "StringFormat.h"
#include "WorldSession.h"
#include "RBAC.h"
@@ -68,9 +69,24 @@ class ChatHandler
virtual void SendSysMessage(char const* str);
void SendSysMessage(uint32 entry);
- void PSendSysMessage(char const* format, ...) ATTR_PRINTF(2, 3);
- void PSendSysMessage(uint32 entry, ...);
- std::string PGetParseString(uint32 entry, ...) const;
+
+ template<typename... Args>
+ void PSendSysMessage(const char* fmt, Args const&... args)
+ {
+ SendSysMessage(Trinity::StringFormat(fmt, args...).c_str());
+ }
+
+ template<typename... Args>
+ void PSendSysMessage(uint32 entry, Args const&... args)
+ {
+ SendSysMessage(PGetParseString(entry, args...).c_str());
+ }
+
+ template<typename... Args>
+ std::string PGetParseString(uint32 entry, Args const&... args) const
+ {
+ return Trinity::StringFormat(GetTrinityString(entry), args...);
+ }
bool ParseCommands(const char* text);
diff --git a/src/server/game/Chat/ChatLink.cpp b/src/server/game/Chat/ChatLink.cpp
index 1eb330cc9e1..732a770645b 100644
--- a/src/server/game/Chat/ChatLink.cpp
+++ b/src/server/game/Chat/ChatLink.cpp
@@ -285,7 +285,7 @@ bool SpellChatLink::ValidateName(char* buffer, const char* context)
ChatLink::ValidateName(buffer, context);
// spells with that flag have a prefix of "$PROFESSION: "
- if (_spell->Attributes & SPELL_ATTR0_TRADESPELL)
+ if (_spell->HasAttribute(SPELL_ATTR0_TRADESPELL))
{
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(_spell->Id);
if (bounds.first == bounds.second)
diff --git a/src/server/game/Combat/HostileRefManager.cpp b/src/server/game/Combat/HostileRefManager.cpp
index 85afdf64607..245cc77eec3 100644
--- a/src/server/game/Combat/HostileRefManager.cpp
+++ b/src/server/game/Combat/HostileRefManager.cpp
@@ -20,7 +20,6 @@
#include "ThreatManager.h"
#include "Unit.h"
#include "DBCStructure.h"
-#include "SpellMgr.h"
#include "SpellInfo.h"
HostileRefManager::~HostileRefManager()
diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp
index 43057409b9b..2ec84c946f6 100644
--- a/src/server/game/Combat/ThreatManager.cpp
+++ b/src/server/game/Combat/ThreatManager.cpp
@@ -19,8 +19,6 @@
#include "ThreatManager.h"
#include "Unit.h"
#include "Creature.h"
-#include "CreatureAI.h"
-#include "Map.h"
#include "Player.h"
#include "ObjectAccessor.h"
#include "UnitEvents.h"
@@ -79,7 +77,7 @@ bool ThreatCalcHelper::isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellIn
return false;
// spell not causing threat
- if (threatSpell && threatSpell->AttributesEx & SPELL_ATTR1_NO_THREAT)
+ if (threatSpell && threatSpell->HasAttribute(SPELL_ATTR1_NO_THREAT))
return false;
ASSERT(hatingUnit->GetTypeId() == TYPEID_UNIT);
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index eb3d1708675..25fbef2ca86 100644
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -99,7 +99,9 @@ ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[COND
{ "Distance", true, true, true },
{ "Alive", false, false, false },
{ "Health Value", true, true, false },
- { "Health Pct", true, true, false }
+ { "Health Pct", true, true, false },
+ { "Realm Achievement", true, false, false },
+ { "In Water", false, false, false }
};
// Checks if object meets the condition
@@ -416,6 +418,19 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
condMeets = creature->GetCreatureTemplate()->type == ConditionValue1;
break;
}
+ case CONDITION_REALM_ACHIEVEMENT:
+ {
+ AchievementEntry const* achievement = sAchievementMgr->GetAchievement(ConditionValue1);
+ if (achievement && sAchievementMgr->IsRealmCompleted(achievement, std::numeric_limits<uint32>::max()))
+ condMeets = true;
+ break;
+ }
+ case CONDITION_IN_WATER:
+ {
+ if (Unit* unit = object->ToUnit())
+ condMeets = unit->IsInWater();
+ break;
+ }
default:
condMeets = false;
break;
@@ -580,6 +595,12 @@ uint32 Condition::GetSearcherTypeMaskForCondition()
case CONDITION_CREATURE_TYPE:
mask |= GRID_MAP_TYPE_MASK_CREATURE;
break;
+ case CONDITION_REALM_ACHIEVEMENT:
+ mask |= GRID_MAP_TYPE_MASK_ALL;
+ break;
+ case CONDITION_IN_WATER:
+ mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
+ break;
default:
ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!");
break;
@@ -2056,6 +2077,18 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
case CONDITION_PHASEMASK:
case CONDITION_ALIVE:
break;
+ case CONDITION_REALM_ACHIEVEMENT:
+ {
+ AchievementEntry const* achievement = sAchievementMgr->GetAchievement(cond->ConditionValue1);
+ if (!achievement)
+ {
+ TC_LOG_ERROR("sql.sql", "%s has non existing realm first achivement id (%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_IN_WATER:
+ break;
default:
break;
}
diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h
index 4ca27f0d986..27983782bdc 100644
--- a/src/server/game/Conditions/ConditionMgr.h
+++ b/src/server/game/Conditions/ConditionMgr.h
@@ -72,7 +72,9 @@ enum ConditionTypes
CONDITION_ALIVE = 36, // 0 0 0 true if unit is alive
CONDITION_HP_VAL = 37, // hpVal ComparisonType 0 true if unit's hp matches given value
CONDITION_HP_PCT = 38, // hpPct ComparisonType 0 true if unit's hp matches given pct
- CONDITION_MAX = 39 // MAX
+ CONDITION_REALM_ACHIEVEMENT = 39, // achievement_id 0 0 true if realm achievement is complete
+ CONDITION_IN_WATER = 40, // 0 0 0 true if unit in water
+ CONDITION_MAX = 41 // MAX
};
/*! Documentation on implementing a new ConditionSourceType:
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index 4dd38face72..5cd9b363ae0 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -48,6 +48,7 @@ struct WMOAreaTableTripple
};
typedef std::map<WMOAreaTableTripple, WMOAreaTableEntry const*> WMOAreaInfoByTripple;
+typedef std::multimap<uint32, CharSectionsEntry const*> CharSectionsMap;
DBCStorage <AreaTableEntry> sAreaStore(AreaTableEntryfmt);
DBCStorage <AreaGroupEntry> sAreaGroupStore(AreaGroupEntryfmt);
@@ -67,6 +68,8 @@ DBCStorage <BattlemasterListEntry> sBattlemasterListStore(BattlemasterListEntryf
DBCStorage <BarberShopStyleEntry> sBarberShopStyleStore(BarberShopStyleEntryfmt);
DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore(CharStartOutfitEntryfmt);
std::map<uint32, CharStartOutfitEntry const*> sCharStartOutfitMap;
+DBCStorage <CharSectionsEntry> sCharSectionsStore(CharSectionsEntryfmt);
+CharSectionsMap sCharSectionMap;
DBCStorage <CharTitlesEntry> sCharTitlesStore(CharTitlesEntryfmt);
DBCStorage <ChatChannelsEntry> sChatChannelsStore(ChatChannelsEntryfmt);
DBCStorage <ChrClassesEntry> sChrClassesStore(ChrClassesEntryfmt);
@@ -305,6 +308,12 @@ void LoadDBCStores(const std::string& dataPath)
if (CharStartOutfitEntry const* outfit = sCharStartOutfitStore.LookupEntry(i))
sCharStartOutfitMap[outfit->Race | (outfit->Class << 8) | (outfit->Gender << 16)] = outfit;
+ LoadDBC(availableDbcLocales, bad_dbc_files, sCharSectionsStore, dbcPath, "CharSections.dbc");
+ for (uint32 i = 0; i < sCharSectionsStore.GetNumRows(); ++i)
+ if (CharSectionsEntry const* entry = sCharSectionsStore.LookupEntry(i))
+ if (entry->Race && ((1 << (entry->Race - 1)) & RACEMASK_ALL_PLAYABLE) != 0) //ignore Nonplayable races
+ sCharSectionMap.insert({ entry->GenType | (entry->Gender << 8) | (entry->Race << 16), entry });
+
LoadDBC(availableDbcLocales, bad_dbc_files, sCharTitlesStore, dbcPath, "CharTitles.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sChatChannelsStore, dbcPath, "ChatChannels.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sChrClassesStore, dbcPath, "ChrClasses.dbc");
@@ -551,8 +560,8 @@ void LoadDBCStores(const std::string& dataPath)
for (uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i)
if (TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i))
{
- if (pathLength[entry->path] < entry->index + 1)
- pathLength[entry->path] = entry->index + 1;
+ if (pathLength[entry->PathID] < entry->NodeIndex + 1)
+ pathLength[entry->PathID] = entry->NodeIndex + 1;
}
// Set path length
sTaxiPathNodesByPath.resize(pathCount); // 0 and some other indexes not used
@@ -561,7 +570,7 @@ void LoadDBCStores(const std::string& dataPath)
// fill data
for (uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i)
if (TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i))
- sTaxiPathNodesByPath[entry->path].set(entry->index, entry);
+ sTaxiPathNodesByPath[entry->PathID].set(entry->NodeIndex, entry);
// Initialize global taxinodes mask
// include existed nodes that have at least single not spell base (scripted) path
@@ -945,6 +954,18 @@ CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, ui
return itr->second;
}
+CharSectionsEntry const* GetCharSectionEntry(uint8 race, CharSectionType genType, uint8 gender, uint8 type, uint8 color)
+{
+ std::pair<CharSectionsMap::const_iterator, CharSectionsMap::const_iterator> eqr = sCharSectionMap.equal_range(uint32(genType) | uint32(gender << 8) | uint32(race << 16));
+ for (CharSectionsMap::const_iterator itr = eqr.first; itr != eqr.second; ++itr)
+ {
+ if (itr->second->Type == type && itr->second->Color == color)
+ return itr->second;
+ }
+
+ return NULL;
+}
+
/// Returns LFGDungeonEntry for a specific map and difficulty. Will return first found entry if multiple dungeons use the same map (such as Scarlet Monastery)
LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty)
{
diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
index 655de86b7e1..d955e9581ab 100644
--- a/src/server/game/DataStores/DBCStores.h
+++ b/src/server/game/DataStores/DBCStores.h
@@ -69,6 +69,7 @@ PvPDifficultyEntry const* GetBattlegroundBracketByLevel(uint32 mapid, uint32 lev
PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id);
CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender);
+CharSectionsEntry const* GetCharSectionEntry(uint8 race, CharSectionType genType, uint8 gender, uint8 type, uint8 color);
LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty);
@@ -91,6 +92,7 @@ extern DBCStorage <BarberShopStyleEntry> sBarberShopStyleStore;
extern DBCStorage <BattlemasterListEntry> sBattlemasterListStore;
extern DBCStorage <ChatChannelsEntry> sChatChannelsStore;
extern DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore;
+extern DBCStorage <CharSectionsEntry> sCharSectionsStore;
extern DBCStorage <CharTitlesEntry> sCharTitlesStore;
extern DBCStorage <ChrClassesEntry> sChrClassesStore;
extern DBCStorage <ChrRacesEntry> sChrRacesStore;
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index 1e6c8218489..5ccd5d2b7e5 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -30,13 +30,7 @@
#include <vector>
// Structures using to access raw DBC data and required packing to portability
-
-// 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 AchievementEntry
{
@@ -647,6 +641,33 @@ struct CharStartOutfitEntry
//int32 ItemInventorySlot[MAX_OUTFIT_ITEMS]; // 53-76 not required at server side
};
+enum CharSectionFlags
+{
+ SECTION_FLAG_PLAYER = 0x01,
+ SECTION_FLAG_DEATH_KNIGHT = 0x04
+};
+
+enum CharSectionType
+{
+ SECTION_TYPE_SKIN = 0,
+ SECTION_TYPE_FACE = 1,
+ SECTION_TYPE_FACIAL_HAIR = 2,
+ SECTION_TYPE_HAIR = 3,
+ SECTION_TYPE_UNDERWEAR = 4
+};
+
+struct CharSectionsEntry
+{
+ //uint32 Id;
+ uint32 Race;
+ uint32 Gender;
+ uint32 GenType;
+ //char* TexturePath[3];
+ uint32 Flags;
+ uint32 Type;
+ uint32 Color;
+};
+
struct CharTitlesEntry
{
uint32 ID; // 0, title ids, for example in Quest::GetCharTitleId()
@@ -1521,9 +1542,9 @@ struct ScalingStatValuesEntry
return 0;
}
- uint32 getFeralBonus(uint32 mask) const // removed in 3.2.x?
+ uint32 getFeralBonus(uint32 /*mask*/) const // removed in 3.2.x?
{
- if (mask & 0x00010000) return 0; // not used?
+ //if (mask & 0x00010000) return 0; // not used?
return 0;
}
};
@@ -1912,17 +1933,17 @@ struct TaxiPathEntry
struct TaxiPathNodeEntry
{
- // 0 m_ID
- uint32 path; // 1 m_PathID
- uint32 index; // 2 m_NodeIndex
- uint32 mapid; // 3 m_ContinentID
- float x; // 4 m_LocX
- float y; // 5 m_LocY
- float z; // 6 m_LocZ
- uint32 actionFlag; // 7 m_flags
- uint32 delay; // 8 m_delay
- uint32 arrivalEventID; // 9 m_arrivalEventID
- uint32 departureEventID; // 10 m_departureEventID
+ // 0 ID
+ uint32 PathID; // 1
+ uint32 NodeIndex; // 2
+ uint32 MapID; // 3
+ float LocX; // 4
+ float LocY; // 5
+ float LocZ; // 6
+ uint32 Flags; // 7
+ uint32 Delay; // 8
+ uint32 ArrivalEventID; // 9
+ uint32 DepartureEventID; // 10
};
struct TeamContributionPointsEntry
@@ -2150,12 +2171,7 @@ struct WorldStateUI
};
*/
-// 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
// Structures not used for casting to loaded DBC data and not required then packing
struct MapDifficulty
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index 44db2a35d73..5c24e6f938a 100644
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -33,6 +33,7 @@ char const BannedAddOnsfmt[] = "nxxxxxxxxxx";
char const BarberShopStyleEntryfmt[] = "nixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiii";
char const BattlemasterListEntryfmt[] = "niiiiiiiiixssssssssssssssssxiixx";
char const CharStartOutfitEntryfmt[] = "dbbbXiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+char const CharSectionsEntryfmt[] = "diiixxxiii";
char const CharTitlesEntryfmt[] = "nxssssssssssssssssxssssssssssssssssxi";
char const ChatChannelsEntryfmt[] = "nixssssssssssssssssxxxxxxxxxxxxxxxxxx";
char const ChrClassesEntryfmt[] = "nxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixii";
diff --git a/src/server/game/DungeonFinding/LFG.cpp b/src/server/game/DungeonFinding/LFG.cpp
index ab06eff7148..8ec638128d8 100644
--- a/src/server/game/DungeonFinding/LFG.cpp
+++ b/src/server/game/DungeonFinding/LFG.cpp
@@ -91,9 +91,6 @@ std::string GetStateString(LfgState state)
case LFG_STATE_DUNGEON:
entry = LANG_LFG_STATE_DUNGEON;
break;
- case LFG_STATE_BOOT:
- entry = LANG_LFG_STATE_BOOT;
- break;
case LFG_STATE_FINISHED_DUNGEON:
entry = LANG_LFG_STATE_FINISHED_DUNGEON;
break;
diff --git a/src/server/game/DungeonFinding/LFG.h b/src/server/game/DungeonFinding/LFG.h
index 6145a2324b1..84a25ee49ad 100644
--- a/src/server/game/DungeonFinding/LFG.h
+++ b/src/server/game/DungeonFinding/LFG.h
@@ -64,8 +64,8 @@ enum LfgState
LFG_STATE_ROLECHECK, // Rolecheck active
LFG_STATE_QUEUED, // Queued
LFG_STATE_PROPOSAL, // Proposal active
- LFG_STATE_BOOT, // Vote kick active
- LFG_STATE_DUNGEON, // In LFG Group, in a Dungeon
+ //LFG_STATE_BOOT, // Vote kick active
+ LFG_STATE_DUNGEON = 5, // In LFG Group, in a Dungeon
LFG_STATE_FINISHED_DUNGEON, // In LFG Group, in a finished Dungeon
LFG_STATE_RAIDBROWSER // Using Raid finder
};
diff --git a/src/server/game/DungeonFinding/LFGGroupData.cpp b/src/server/game/DungeonFinding/LFGGroupData.cpp
index 2ab1e0b1e7e..aa6916a39a4 100644
--- a/src/server/game/DungeonFinding/LFGGroupData.cpp
+++ b/src/server/game/DungeonFinding/LFGGroupData.cpp
@@ -22,7 +22,7 @@ namespace lfg
{
LfgGroupData::LfgGroupData(): m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE),
- m_Leader(), m_Dungeon(0), m_KicksLeft(LFG_GROUP_MAX_KICKS)
+ m_Leader(), m_Dungeon(0), m_KicksLeft(LFG_GROUP_MAX_KICKS), m_VoteKickActive(false)
{ }
LfgGroupData::~LfgGroupData()
@@ -126,4 +126,14 @@ uint8 LfgGroupData::GetKicksLeft() const
return m_KicksLeft;
}
+void LfgGroupData::SetVoteKick(bool active)
+{
+ m_VoteKickActive = active;
+}
+
+bool LfgGroupData::IsVoteKickActive() const
+{
+ return m_VoteKickActive;
+}
+
} // namespace lfg
diff --git a/src/server/game/DungeonFinding/LFGGroupData.h b/src/server/game/DungeonFinding/LFGGroupData.h
index 8d8f1dc0f3d..b573e7c309e 100644
--- a/src/server/game/DungeonFinding/LFGGroupData.h
+++ b/src/server/game/DungeonFinding/LFGGroupData.h
@@ -66,6 +66,9 @@ class LfgGroupData
// VoteKick
uint8 GetKicksLeft() const;
+ void SetVoteKick(bool active);
+ bool IsVoteKickActive() const;
+
private:
// General
LfgState m_State; ///< State if group in LFG
@@ -76,6 +79,7 @@ class LfgGroupData
uint32 m_Dungeon; ///< Dungeon entry
// Vote Kick
uint8 m_KicksLeft; ///< Number of kicks left
+ bool m_VoteKickActive;
};
} // namespace lfg
diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp
index 9b3ccc05280..5ad94948cd0 100644
--- a/src/server/game/DungeonFinding/LFGMgr.cpp
+++ b/src/server/game/DungeonFinding/LFGMgr.cpp
@@ -21,7 +21,6 @@
#include "DisableMgr.h"
#include "ObjectMgr.h"
#include "SocialMgr.h"
-#include "Language.h"
#include "LFGMgr.h"
#include "LFGScripts.h"
#include "LFGGroupData.h"
@@ -311,9 +310,8 @@ void LFGMgr::Update(uint32 diff)
ObjectGuid pguid = itVotes->first;
if (pguid != boot.victim)
SendLfgBootProposalUpdate(pguid, boot);
- SetState(pguid, LFG_STATE_DUNGEON);
}
- SetState(itBoot->first, LFG_STATE_DUNGEON);
+ SetVoteKick(itBoot->first, false);
BootsStore.erase(itBoot);
}
}
@@ -412,6 +410,8 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const
joinData.result = LFG_JOIN_RANDOM_COOLDOWN;
else if (dungeons.empty())
joinData.result = LFG_JOIN_NOT_MEET_REQS;
+ else if (player->HasAura(9454)) // check Freeze debuff
+ joinData.result = LFG_JOIN_NOT_MEET_REQS;
else if (grp)
{
if (grp->GetMembersCount() > MAXGROUPSIZE)
@@ -431,6 +431,8 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const
joinData.result = LFG_JOIN_PARTY_RANDOM_COOLDOWN;
else if (plrg->InBattleground() || plrg->InArena() || plrg->InBattlegroundQueue())
joinData.result = LFG_JOIN_USING_BG_SYSTEM;
+ else if (plrg->HasAura(9454)) // check Freeze debuff
+ joinData.result = LFG_JOIN_PARTY_NOT_MEET_REQS;
++memberCount;
players.insert(plrg->GetGUID());
}
@@ -643,7 +645,6 @@ void LFGMgr::LeaveLfg(ObjectGuid guid)
break;
case LFG_STATE_DUNGEON:
case LFG_STATE_FINISHED_DUNGEON:
- case LFG_STATE_BOOT:
if (guid != gguid) // Player
SetState(guid, LFG_STATE_NONE);
break;
@@ -783,10 +784,10 @@ void LFGMgr::GetCompatibleDungeons(LfgDungeonSet& dungeons, GuidSet const& playe
}
}
}
-
+
if (eraseDungeon)
dungeons.erase(itDungeon);
-
+
lockMap[guid][dungeonId] = it2->second;
}
}
@@ -1156,7 +1157,7 @@ void LFGMgr::RemoveProposal(LfgProposalContainer::iterator itProposal, LfgUpdate
*/
void LFGMgr::InitBoot(ObjectGuid gguid, ObjectGuid kicker, ObjectGuid victim, std::string const& reason)
{
- SetState(gguid, LFG_STATE_BOOT);
+ SetVoteKick(gguid, true);
LfgPlayerBoot& boot = BootsStore[gguid];
boot.inProgress = true;
@@ -1170,7 +1171,6 @@ void LFGMgr::InitBoot(ObjectGuid gguid, ObjectGuid kicker, ObjectGuid victim, st
for (GuidSet::const_iterator itr = players.begin(); itr != players.end(); ++itr)
{
ObjectGuid guid = (*itr);
- SetState(guid, LFG_STATE_BOOT);
boot.votes[guid] = LFG_ANSWER_PENDING;
}
@@ -1227,13 +1227,10 @@ void LFGMgr::UpdateBoot(ObjectGuid guid, bool accept)
{
ObjectGuid pguid = itVotes->first;
if (pguid != boot.victim)
- {
- SetState(pguid, LFG_STATE_DUNGEON);
SendLfgBootProposalUpdate(pguid, boot);
- }
}
- SetState(gguid, LFG_STATE_DUNGEON);
+ SetVoteKick(gguid, false);
if (agreeNum == LFG_GROUP_KICK_VOTES_NEEDED) // Vote passed - Kick player
{
if (Group* group = sGroupMgr->GetGroupByGUID(gguid.GetCounter()))
@@ -1288,6 +1285,8 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
error = LFG_TELEPORTERROR_IN_VEHICLE;
else if (player->GetCharmGUID())
error = LFG_TELEPORTERROR_CHARMING;
+ else if (player->HasAura(9454)) // check Freeze debuff
+ error = LFG_TELEPORTERROR_INVALID_LOCATION;
else if (player->GetMapId() != uint32(dungeon->map)) // Do not teleport players in dungeon to the entrance
{
uint32 mapid = dungeon->map;
@@ -1495,12 +1494,12 @@ LfgState LFGMgr::GetState(ObjectGuid guid)
if (guid.IsGroup())
{
state = GroupsStore[guid].GetState();
- TC_LOG_TRACE("lfg.data.group.state.get", "Group: %s, State: %u", guid.ToString().c_str(), state);
+ TC_LOG_TRACE("lfg.data.group.state.get", "Group: %s, State: %s", guid.ToString().c_str(), GetStateString(state).c_str());
}
else
{
state = PlayersStore[guid].GetState();
- TC_LOG_TRACE("lfg.data.player.state.get", "Player: %s, State: %u", guid.ToString().c_str(), state);
+ TC_LOG_TRACE("lfg.data.player.state.get", "Player: %s, State: %s", guid.ToString().c_str(), GetStateString(state).c_str());
}
return state;
@@ -1523,6 +1522,16 @@ LfgState LFGMgr::GetOldState(ObjectGuid guid)
return state;
}
+bool LFGMgr::IsVoteKickActive(ObjectGuid gguid)
+{
+ ASSERT(gguid.IsGroup());
+
+ bool active = GroupsStore[gguid].IsVoteKickActive();
+ TC_LOG_TRACE("lfg.data.group.votekick.get", "Group: %s, Active: %d", gguid.ToString().c_str(), active);
+
+ return active;
+}
+
uint32 LFGMgr::GetDungeon(ObjectGuid guid, bool asId /*= true */)
{
uint32 dungeon = GroupsStore[guid].GetDungeon(asId);
@@ -1683,6 +1692,17 @@ void LFGMgr::SetState(ObjectGuid guid, LfgState state)
}
}
+void LFGMgr::SetVoteKick(ObjectGuid gguid, bool active)
+{
+ ASSERT(gguid.IsGroup());
+
+ LfgGroupData& data = GroupsStore[gguid];
+ TC_LOG_TRACE("lfg.data.group.votekick.set", "Group: %s, New state: %d, Previous: %d",
+ gguid.ToString().c_str(), active, data.IsVoteKickActive());
+
+ data.SetVoteKick(active);
+}
+
void LFGMgr::SetDungeon(ObjectGuid guid, uint32 dungeon)
{
TC_LOG_TRACE("lfg.data.group.dungeon.set", "Group: %s, Dungeon: %u", guid.ToString().c_str(), dungeon);
diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h
index 0e5fadc85cc..fda9a8b7ce9 100644
--- a/src/server/game/DungeonFinding/LFGMgr.h
+++ b/src/server/game/DungeonFinding/LFGMgr.h
@@ -322,6 +322,8 @@ class LFGMgr
LfgDungeonSet const& GetSelectedDungeons(ObjectGuid guid);
/// Get current lfg state
LfgState GetState(ObjectGuid guid);
+ /// Get current vote kick state
+ bool IsVoteKickActive(ObjectGuid gguid);
/// Get current dungeon
uint32 GetDungeon(ObjectGuid guid, bool asId = true);
/// Get the map id of the current dungeon
@@ -425,6 +427,7 @@ class LFGMgr
void SetSelectedDungeons(ObjectGuid guid, LfgDungeonSet const& dungeons);
void DecreaseKicksLeft(ObjectGuid guid);
void SetState(ObjectGuid guid, LfgState state);
+ void SetVoteKick(ObjectGuid gguid, bool active);
void RemovePlayerData(ObjectGuid guid);
void GetCompatibleDungeons(LfgDungeonSet& dungeons, GuidSet const& players, LfgLockPartyMap& lockMap, bool isContinue);
void _SaveToDB(ObjectGuid guid, uint32 db_guid);
diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp
index 683590cebe8..6ac20541574 100644
--- a/src/server/game/DungeonFinding/LFGQueue.cpp
+++ b/src/server/game/DungeonFinding/LFGQueue.cpp
@@ -23,9 +23,6 @@
#include "LFGQueue.h"
#include "LFGMgr.h"
#include "Log.h"
-#include "ObjectMgr.h"
-#include "World.h"
-#include "GroupMgr.h"
namespace lfg
{
@@ -377,7 +374,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check)
// Group with less that MAXGROUPSIZE members always compatible
if (check.size() == 1 && numPlayers != MAXGROUPSIZE)
{
- TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) sigle group. Compatibles", strGuids.c_str());
+ TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) single group. Compatibles", strGuids.c_str());
LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(check.front());
LfgCompatibilityData data(LFG_COMPATIBLES_WITH_LESS_PLAYERS);
diff --git a/src/server/game/DungeonFinding/LFGScripts.cpp b/src/server/game/DungeonFinding/LFGScripts.cpp
index ae64e59936f..852eb7d8c5f 100644
--- a/src/server/game/DungeonFinding/LFGScripts.cpp
+++ b/src/server/game/DungeonFinding/LFGScripts.cpp
@@ -99,7 +99,17 @@ void LFGPlayerScript::OnMapChanged(Player* player)
player->CastSpell(player, LFG_SPELL_LUCK_OF_THE_DRAW, true);
}
else
+ {
+ Group* group = player->GetGroup();
+ if (group && group->GetMembersCount() == 1)
+ {
+ sLFGMgr->LeaveLfg(group->GetGUID());
+ group->Disband();
+ TC_LOG_DEBUG("lfg", "LFGPlayerScript::OnMapChanged, Player %s(%s) is last in the lfggroup so we disband the group.",
+ player->GetName().c_str(), player->GetGUID().ToString().c_str());
+ }
player->RemoveAurasDueToSpell(LFG_SPELL_LUCK_OF_THE_DRAW);
+ }
}
LFGGroupScript::LFGGroupScript() : GroupScript("LFGGroupScript") { }
diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp
index 1e967928265..192a897238a 100644
--- a/src/server/game/Entities/Corpse/Corpse.cpp
+++ b/src/server/game/Entities/Corpse/Corpse.cpp
@@ -22,9 +22,6 @@
#include "UpdateMask.h"
#include "ObjectAccessor.h"
#include "DatabaseEnv.h"
-#include "Opcodes.h"
-#include "GossipDef.h"
-#include "World.h"
Corpse::Corpse(CorpseType type) : WorldObject(type != CORPSE_BONES), m_type(type)
{
@@ -172,6 +169,7 @@ bool Corpse::LoadCorpseFromDB(uint32 guid, Field* fields)
Object::_Create(guid, 0, HIGHGUID_CORPSE);
+ SetObjectScale(1.0f);
SetUInt32Value(CORPSE_FIELD_DISPLAY_ID, fields[5].GetUInt32());
_LoadIntoDataField(fields[6].GetCString(), CORPSE_FIELD_ITEM, EQUIPMENT_SLOT_END);
SetUInt32Value(CORPSE_FIELD_BYTES_1, fields[7].GetUInt32());
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index a44ca68f79b..809c76c260a 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -34,12 +34,9 @@
#include "InstanceScript.h"
#include "Log.h"
#include "LootMgr.h"
-#include "MapManager.h"
#include "MoveSpline.h"
-#include "MoveSplineInit.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
-#include "OutdoorPvPMgr.h"
#include "Player.h"
#include "PoolMgr.h"
#include "QuestDef.h"
@@ -48,10 +45,8 @@
#include "TemporarySummon.h"
#include "Util.h"
#include "Vehicle.h"
-#include "WaypointMovementGenerator.h"
#include "World.h"
#include "WorldPacket.h"
-
#include "Transport.h"
TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const
@@ -155,8 +150,6 @@ m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(
for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i)
m_spells[i] = 0;
- m_CreatureSpellCooldowns.clear();
- m_CreatureCategoryCooldowns.clear();
DisableReputationGain = false;
m_SightDistance = sWorld->getFloatConfig(CONFIG_SIGHT_MONSTER);
@@ -1377,9 +1370,6 @@ bool Creature::CanStartAttack(Unit const* who, bool force) const
if (IsCivilian())
return false;
- if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC))
- return false;
-
// Do not attack non-combat pets
if (who->GetTypeId() == TYPEID_UNIT && who->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET)
return false;
@@ -1484,6 +1474,8 @@ void Creature::setDeathState(DeathState s)
SetTarget(ObjectGuid::Empty); // remove target selection in any cases (can be set at aura remove in Unit::setDeathState)
SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
+ SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0); // if creature is mounted on a virtual mount, remove it at death
+
setActive(false);
if (HasSearchedAssistance())
@@ -2159,88 +2151,6 @@ uint32 Creature::GetShieldBlockValue() const //dunno mob block
return (getLevel()/2 + uint32(GetStat(STAT_STRENGTH)/20));
}
-void Creature::_AddCreatureSpellCooldown(uint32 spell_id, time_t end_time)
-{
- m_CreatureSpellCooldowns[spell_id] = end_time;
-}
-
-void Creature::_AddCreatureCategoryCooldown(uint32 category, time_t apply_time)
-{
- m_CreatureCategoryCooldowns[category] = apply_time;
-}
-
-void Creature::AddCreatureSpellCooldown(uint32 spellid)
-{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid);
- if (!spellInfo)
- return;
-
- uint32 cooldown = spellInfo->GetRecoveryTime();
- if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellid, SPELLMOD_COOLDOWN, cooldown);
-
- if (cooldown)
- _AddCreatureSpellCooldown(spellid, time(NULL) + cooldown/IN_MILLISECONDS);
-
- if (spellInfo->GetCategory())
- _AddCreatureCategoryCooldown(spellInfo->GetCategory(), time(NULL));
-}
-
-bool Creature::HasCategoryCooldown(uint32 spell_id) const
-{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id);
- if (!spellInfo)
- return false;
-
- CreatureSpellCooldowns::const_iterator itr = m_CreatureCategoryCooldowns.find(spellInfo->GetCategory());
- return(itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / IN_MILLISECONDS)) > time(NULL));
-}
-
-uint32 Creature::GetCreatureSpellCooldownDelay(uint32 spellId) const
-{
- CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spellId);
- time_t t = time(NULL);
- return uint32(itr != m_CreatureSpellCooldowns.end() && itr->second > t ? itr->second - t : 0);
-}
-
-bool Creature::HasSpellCooldown(uint32 spell_id) const
-{
- CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spell_id);
- return (itr != m_CreatureSpellCooldowns.end() && itr->second > time(NULL)) || HasCategoryCooldown(spell_id);
-}
-
-void Creature::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs)
-{
- time_t curTime = time(NULL);
- for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i)
- {
- if (m_spells[i] == 0)
- continue;
-
- uint32 unSpellId = m_spells[i];
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(unSpellId);
- if (!spellInfo)
- {
- ASSERT(spellInfo);
- continue;
- }
-
- // Not send cooldown for this spells
- if (spellInfo->IsCooldownStartedOnEvent())
- continue;
-
- if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE)
- continue;
-
- if ((idSchoolMask & spellInfo->GetSchoolMask()) && GetCreatureSpellCooldownDelay(unSpellId) < unTimeMs)
- {
- _AddCreatureSpellCooldown(unSpellId, curTime + unTimeMs/IN_MILLISECONDS);
- if (UnitAI* ai = GetAI())
- ai->SpellInterrupted(unSpellId, unTimeMs);
- }
- }
-}
-
bool Creature::HasSpell(uint32 spellID) const
{
uint8 i;
@@ -2502,7 +2412,7 @@ bool Creature::SetSwim(bool enable)
return true;
}
-bool Creature::SetCanFly(bool enable)
+bool Creature::SetCanFly(bool enable, bool /*packetOnly = false */)
{
if (!Unit::SetCanFly(enable))
return false;
@@ -2697,7 +2607,7 @@ void Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target)
_focusSpell = focusSpell;
SetGuidValue(UNIT_FIELD_TARGET, target->GetGUID());
- if (focusSpell->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_DONT_TURN_DURING_CAST)
+ if (focusSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST))
AddUnitState(UNIT_STATE_ROTATING);
// Set serverside orientation if needed (needs to be after attribute check)
@@ -2716,7 +2626,7 @@ void Creature::ReleaseFocus(Spell const* focusSpell)
else
SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty);
- if (focusSpell->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_DONT_TURN_DURING_CAST)
+ if (focusSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST))
ClearUnitState(UNIT_STATE_ROTATING);
}
@@ -2725,3 +2635,29 @@ void Creature::StartPickPocketRefillTimer()
_pickpocketLootRestore = time(NULL) + sWorld->getIntConfig(CONFIG_CREATURE_PICKPOCKET_REFILL);
}
+void Creature::SetTextRepeatId(uint8 textGroup, uint8 id)
+{
+ CreatureTextRepeatIds& repeats = m_textRepeat[textGroup];
+ if (std::find(repeats.begin(), repeats.end(), id) == repeats.end())
+ repeats.push_back(id);
+ else
+ TC_LOG_ERROR("sql.sql", "CreatureTextMgr: TextGroup %u for Creature(%s) GuidLow %u Entry %u, id %u already added", uint32(textGroup), GetName().c_str(), GetGUIDLow(), GetEntry(), uint32(id));
+}
+
+CreatureTextRepeatIds Creature::GetTextRepeatGroup(uint8 textGroup)
+{
+ CreatureTextRepeatIds ids;
+
+ CreatureTextRepeatGroup::const_iterator groupItr = m_textRepeat.find(textGroup);
+ if (groupItr != m_textRepeat.end())
+ ids = groupItr->second;
+
+ return ids;
+}
+
+void Creature::ClearTextRepeatGroup(uint8 textGroup)
+{
+ CreatureTextRepeatGroup::iterator groupItr = m_textRepeat.find(textGroup);
+ if (groupItr != m_textRepeat.end())
+ groupItr->second.clear();
+}
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index ec06bf90595..585bc137e0b 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -170,12 +170,7 @@ struct CreatureTemplate
// Benchmarked: Faster than std::map (insert/find)
typedef std::unordered_map<uint32, CreatureTemplate> CreatureTemplateContainer;
-// 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
// Defines base stats for creatures (used to calculate HP/mana/armor/attackpower/rangedattackpower/all damage).
struct CreatureBaseStats
@@ -307,12 +302,7 @@ enum ChatType
CHAT_TYPE_END = 255
};
-// 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
// `creature_addon` table
struct CreatureAddon
@@ -414,13 +404,15 @@ struct TrainerSpellData
TrainerSpell const* Find(uint32 spell_id) const;
};
-typedef std::map<uint32, time_t> CreatureSpellCooldowns;
-
// max different by z coordinate for creature aggro reaction
#define CREATURE_Z_ATTACK_RANGE 3
#define MAX_VENDOR_ITEMS 150 // Limitation in 3.x.x item count in SMSG_LIST_INVENTORY
+//used for handling non-repeatable random texts
+typedef std::vector<uint8> CreatureTextRepeatIds;
+typedef std::unordered_map<uint8, CreatureTextRepeatIds> CreatureTextRepeatGroup;
+
class Creature : public Unit, public GridObject<Creature>, public MapObject
{
public:
@@ -484,7 +476,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
bool SetWalk(bool enable) override;
bool SetDisableGravity(bool disable, bool packetOnly = false) override;
bool SetSwim(bool enable) override;
- bool SetCanFly(bool enable) override;
+ bool SetCanFly(bool enable, bool packetOnly = false) override;
bool SetWaterWalking(bool enable, bool packetOnly = false) override;
bool SetFeatherFall(bool enable, bool packetOnly = false) override;
bool SetHover(bool enable, bool packetOnly = false) override;
@@ -494,14 +486,6 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
SpellSchoolMask GetMeleeDamageSchoolMask() const override { return m_meleeDamageSchoolMask; }
void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); }
- void _AddCreatureSpellCooldown(uint32 spell_id, time_t end_time);
- void _AddCreatureCategoryCooldown(uint32 category, time_t apply_time);
- void AddCreatureSpellCooldown(uint32 spellid);
- bool HasSpellCooldown(uint32 spell_id) const;
- bool HasCategoryCooldown(uint32 spell_id) const;
- uint32 GetCreatureSpellCooldownDelay(uint32 spellId) const;
- virtual void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) override;
-
bool HasSpell(uint32 spellID) const override;
bool UpdateEntry(uint32 entry, CreatureData const* data = nullptr);
@@ -575,8 +559,6 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
SpellInfo const* reachWithSpellCure(Unit* victim);
uint32 m_spells[CREATURE_MAX_SPELLS];
- CreatureSpellCooldowns m_CreatureSpellCooldowns;
- CreatureSpellCooldowns m_CreatureCategoryCooldowns;
bool CanStartAttack(Unit const* u, bool force) const;
float GetAttackDistance(Unit const* player) const;
@@ -678,6 +660,10 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
void FocusTarget(Spell const* focusSpell, WorldObject const* target);
void ReleaseFocus(Spell const* focusSpell);
+ CreatureTextRepeatIds GetTextRepeatGroup(uint8 textGroup);
+ void SetTextRepeatId(uint8 textGroup, uint8 id);
+ void ClearTextRepeatGroup(uint8 textGroup);
+
protected:
bool CreateFromProto(uint32 guidlow, uint32 entry, CreatureData const* data = nullptr, uint32 vehId = 0);
bool InitEntry(uint32 entry, CreatureData const* data = nullptr);
@@ -742,6 +728,8 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
bool TriggerJustRespawned;
Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing
+
+ CreatureTextRepeatGroup m_textRepeat;
};
class AssistDelayEvent : public BasicEvent
diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp
index fc7b85aa73e..2a3e91b7574 100644
--- a/src/server/game/Entities/Creature/TemporarySummon.cpp
+++ b/src/server/game/Entities/Creature/TemporarySummon.cpp
@@ -19,7 +19,6 @@
#include "Log.h"
#include "ObjectAccessor.h"
#include "CreatureAI.h"
-#include "ObjectMgr.h"
#include "TemporarySummon.h"
#include "Pet.h"
#include "Player.h"
diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp
index 60accf8ad92..71d0f13488c 100644
--- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp
+++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp
@@ -18,12 +18,10 @@
#include "Common.h"
#include "UpdateMask.h"
-#include "Opcodes.h"
#include "World.h"
#include "ObjectAccessor.h"
#include "DatabaseEnv.h"
#include "GridNotifiers.h"
-#include "CellImpl.h"
#include "GridNotifiersImpl.h"
#include "ScriptMgr.h"
#include "Transport.h"
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 6ca5ab4ae5b..a4b140b9878 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -20,7 +20,6 @@
#include "Battleground.h"
#include "CellImpl.h"
#include "CreatureAISelector.h"
-#include "DynamicTree.h"
#include "GameObjectModel.h"
#include "GridNotifiersImpl.h"
#include "Group.h"
@@ -33,7 +32,6 @@
#include "UpdateFieldFlags.h"
#include "World.h"
#include "Transport.h"
-#include <G3D/Quat.h>
GameObject::GameObject() : WorldObject(false), MapObject(),
m_model(NULL), m_goValue(), m_AI(NULL)
@@ -192,6 +190,12 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa
return false;
}
+ if (goinfo->type == GAMEOBJECT_TYPE_MO_TRANSPORT)
+ {
+ TC_LOG_ERROR("sql.sql", "Gameobject (GUID: %u Entry: %u) not created: gameobject type GAMEOBJECT_TYPE_MO_TRANSPORT cannot be manually created.", guidlow, name_id);
+ return false;
+ }
+
if (goinfo->type == GAMEOBJECT_TYPE_TRANSPORT)
m_updateFlag = (m_updateFlag | UPDATEFLAG_TRANSPORT) & ~UPDATEFLAG_POSITION;
@@ -267,6 +271,16 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa
SetGoAnimProgress(animprogress);
break;
}
+
+ if (GameObjectAddon const* addon = sObjectMgr->GetGameObjectAddon(guidlow))
+ {
+ if (addon->InvisibilityValue)
+ {
+ m_invisibility.AddFlag(addon->invisibilityType);
+ m_invisibility.AddValue(addon->invisibilityType, addon->InvisibilityValue);
+ }
+ }
+
LastUsedScriptID = GetGOInfo()->ScriptId;
AIM_Initialize();
@@ -2070,6 +2084,15 @@ void GameObject::SetGoState(GOState state)
}
}
+uint32 GameObject::GetTransportPeriod() const
+{
+ ASSERT(GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT);
+ if (m_goValue.Transport.AnimationInfo)
+ return m_goValue.Transport.AnimationInfo->TotalTime;
+
+ return 0;
+}
+
void GameObject::SetDisplayId(uint32 displayid)
{
SetUInt32Value(GAMEOBJECT_DISPLAYID, displayid);
@@ -2208,9 +2231,16 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
if (ActivateToQuest(target))
dynFlags |= GO_DYNFLAG_LO_SPARKLE;
break;
+ case GAMEOBJECT_TYPE_TRANSPORT:
case GAMEOBJECT_TYPE_MO_TRANSPORT:
- pathProgress = int16(float(m_goValue.Transport.PathProgress) / float(GetUInt32Value(GAMEOBJECT_LEVEL)) * 65535.0f);
+ {
+ if (uint32 transportPeriod = GetTransportPeriod())
+ {
+ float timer = float(m_goValue.Transport.PathProgress % transportPeriod);
+ pathProgress = int16(timer / float(transportPeriod) * 65535.0f);
+ }
break;
+ }
default:
break;
}
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index 844674b2210..5f1d2c793e6 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -576,6 +576,15 @@ struct GameObjectLocale
StringVector CastBarCaption;
};
+// `gameobject_addon` table
+struct GameObjectAddon
+{
+ InvisibilityType invisibilityType;
+ uint32 InvisibilityValue;
+};
+
+typedef std::unordered_map<ObjectGuid::LowType, GameObjectAddon> GameObjectAddonContainer;
+
// client side GO show states
enum GOState
{
@@ -717,6 +726,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map
void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); }
GOState GetGoState() const { return GOState(GetByteValue(GAMEOBJECT_BYTES_1, 0)); }
void SetGoState(GOState state);
+ virtual uint32 GetTransportPeriod() const;
uint8 GetGoArtKit() const { return GetByteValue(GAMEOBJECT_BYTES_1, 2); }
void SetGoArtKit(uint8 artkit);
uint8 GetGoAnimProgress() const { return GetByteValue(GAMEOBJECT_BYTES_1, 3); }
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index c82ae723f4c..b832aeb5614 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -201,8 +201,6 @@ enum ItemUpdateState
ITEM_REMOVED = 3
};
-#define MAX_ITEM_SPELLS 5
-
bool ItemCanGoIntoBag(ItemTemplate const* proto, ItemTemplate const* pBagProto);
class Item : public Object
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 53ec842b053..6392c3ee51b 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -30,27 +30,19 @@
#include "UpdateData.h"
#include "UpdateMask.h"
#include "Util.h"
-#include "MapManager.h"
#include "ObjectAccessor.h"
-#include "Log.h"
#include "Transport.h"
-#include "TargetedMovementGenerator.h"
-#include "WaypointMovementGenerator.h"
#include "VMapFactory.h"
#include "CellImpl.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
-#include "SpellAuraEffects.h"
#include "UpdateFieldFlags.h"
#include "TemporarySummon.h"
#include "Totem.h"
#include "OutdoorPvPMgr.h"
#include "MovementPacketBuilder.h"
-#include "DynamicTree.h"
-#include "Group.h"
#include "BattlefieldMgr.h"
#include "Battleground.h"
-#include "Chat.h"
Object::Object() : m_PackGUID(sizeof(uint64)+1)
{
@@ -500,6 +492,7 @@ void Object::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* targe
uint32* flags = NULL;
uint32 visibleFlag = GetUpdateFieldData(target, flags);
+ ASSERT(flags);
for (uint16 index = 0; index < m_valuesCount; ++index)
{
@@ -1015,89 +1008,34 @@ bool Object::PrintIndexError(uint32 index, bool set) const
return false;
}
-bool Position::operator==(Position const &a)
-{
- return (G3D::fuzzyEq(a.m_positionX, m_positionX) &&
- G3D::fuzzyEq(a.m_positionY, m_positionY) &&
- G3D::fuzzyEq(a.m_positionZ, m_positionZ) &&
- G3D::fuzzyEq(a.m_orientation, m_orientation));
-}
-
-bool Position::HasInLine(WorldObject const* target, float width) const
-{
- if (!HasInArc(float(M_PI), target))
- return false;
- width += target->GetObjectSize();
- float angle = GetRelativeAngle(target);
- return std::fabs(std::sin(angle)) * GetExactDist2d(target->GetPositionX(), target->GetPositionY()) < width;
-}
-
-std::string Position::ToString() const
-{
- std::stringstream sstr;
- sstr << "X: " << m_positionX << " Y: " << m_positionY << " Z: " << m_positionZ << " O: " << m_orientation;
- return sstr.str();
-}
-
-ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer)
-{
- float x, y, z, o;
- buf >> x >> y >> z >> o;
- streamer.m_pos->Relocate(x, y, z, o);
- return buf;
-}
-ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer)
-{
- float x, y, z;
- streamer.m_pos->GetPosition(x, y, z);
- buf << x << y << z;
- return buf;
-}
-
-ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer)
-{
- float x, y, z;
- buf >> x >> y >> z;
- streamer.m_pos->Relocate(x, y, z);
- return buf;
-}
-
-ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer)
-{
- float x, y, z, o;
- streamer.m_pos->GetPosition(x, y, z, o);
- buf << x << y << z << o;
- return buf;
-}
-
void MovementInfo::OutDebug()
{
- TC_LOG_INFO("misc", "MOVEMENT INFO");
- TC_LOG_INFO("misc", "%s", guid.ToString().c_str());
- TC_LOG_INFO("misc", "flags %u", flags);
- TC_LOG_INFO("misc", "flags2 %u", flags2);
- TC_LOG_INFO("misc", "time %u current time " UI64FMTD "", flags2, uint64(::time(NULL)));
- TC_LOG_INFO("misc", "position: `%s`", pos.ToString().c_str());
+ TC_LOG_DEBUG("misc", "MOVEMENT INFO");
+ TC_LOG_DEBUG("misc", "%s", guid.ToString().c_str());
+ TC_LOG_DEBUG("misc", "flags %u", flags);
+ TC_LOG_DEBUG("misc", "flags2 %u", flags2);
+ TC_LOG_DEBUG("misc", "time %u current time " UI64FMTD "", flags2, uint64(::time(NULL)));
+ TC_LOG_DEBUG("misc", "position: `%s`", pos.ToString().c_str());
if (flags & MOVEMENTFLAG_ONTRANSPORT)
{
- TC_LOG_INFO("misc", "TRANSPORT:");
- TC_LOG_INFO("misc", "%s", transport.guid.ToString().c_str());
- TC_LOG_INFO("misc", "position: `%s`", transport.pos.ToString().c_str());
- TC_LOG_INFO("misc", "seat: %i", transport.seat);
- TC_LOG_INFO("misc", "time: %u", transport.time);
+ TC_LOG_DEBUG("misc", "TRANSPORT:");
+ TC_LOG_DEBUG("misc", "%s", transport.guid.ToString().c_str());
+ TC_LOG_DEBUG("misc", "position: `%s`", transport.pos.ToString().c_str());
+ TC_LOG_DEBUG("misc", "seat: %i", transport.seat);
+ TC_LOG_DEBUG("misc", "time: %u", transport.time);
if (flags2 & MOVEMENTFLAG2_INTERPOLATED_MOVEMENT)
- TC_LOG_INFO("misc", "time2: %u", transport.time2);
+ TC_LOG_DEBUG("misc", "time2: %u", transport.time2);
}
if ((flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || (flags2 & MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING))
- TC_LOG_INFO("misc", "pitch: %f", pitch);
+ TC_LOG_DEBUG("misc", "pitch: %f", pitch);
- TC_LOG_INFO("misc", "fallTime: %u", fallTime);
+ TC_LOG_DEBUG("misc", "fallTime: %u", fallTime);
if (flags & MOVEMENTFLAG_FALLING)
- TC_LOG_INFO("misc", "j_zspeed: %f j_sinAngle: %f j_cosAngle: %f j_xyspeed: %f", jump.zspeed, jump.sinAngle, jump.cosAngle, jump.xyspeed);
+ TC_LOG_DEBUG("misc", "j_zspeed: %f j_sinAngle: %f j_cosAngle: %f j_xyspeed: %f", jump.zspeed, jump.sinAngle, jump.cosAngle, jump.xyspeed);
if (flags & MOVEMENTFLAG_SPLINE_ELEVATION)
- TC_LOG_INFO("misc", "splineElevation: %f", splineElevation);
+ TC_LOG_DEBUG("misc", "splineElevation: %f", splineElevation);
}
WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), LastUsedScriptID(0),
@@ -1430,92 +1368,6 @@ bool WorldObject::IsInRange3d(float x, float y, float z, float minRange, float m
return distsq < maxdist * maxdist;
}
-void Position::RelocateOffset(const Position & offset)
-{
- m_positionX = GetPositionX() + (offset.GetPositionX() * std::cos(GetOrientation()) + offset.GetPositionY() * std::sin(GetOrientation() + float(M_PI)));
- m_positionY = GetPositionY() + (offset.GetPositionY() * std::cos(GetOrientation()) + offset.GetPositionX() * std::sin(GetOrientation()));
- m_positionZ = GetPositionZ() + offset.GetPositionZ();
- SetOrientation(GetOrientation() + offset.GetOrientation());
-}
-
-void Position::GetPositionOffsetTo(const Position & endPos, Position & retOffset) const
-{
- float dx = endPos.GetPositionX() - GetPositionX();
- float dy = endPos.GetPositionY() - GetPositionY();
-
- retOffset.m_positionX = dx * std::cos(GetOrientation()) + dy * std::sin(GetOrientation());
- retOffset.m_positionY = dy * std::cos(GetOrientation()) - dx * std::sin(GetOrientation());
- retOffset.m_positionZ = endPos.GetPositionZ() - GetPositionZ();
- retOffset.SetOrientation(endPos.GetOrientation() - GetOrientation());
-}
-
-Position Position::GetPositionWithOffset(Position const& offset) const
-{
- Position ret(*this);
- ret.RelocateOffset(offset);
- return ret;
-}
-
-float Position::GetAngle(const Position* obj) const
-{
- if (!obj)
- return 0;
-
- return GetAngle(obj->GetPositionX(), obj->GetPositionY());
-}
-
-// Return angle in range 0..2*pi
-float Position::GetAngle(const float x, const float y) const
-{
- float dx = x - GetPositionX();
- float dy = y - GetPositionY();
-
- float ang = std::atan2(dy, dx);
- ang = (ang >= 0) ? ang : 2 * float(M_PI) + ang;
- return ang;
-}
-
-void Position::GetSinCos(const float x, const float y, float &vsin, float &vcos) const
-{
- float dx = GetPositionX() - x;
- float dy = GetPositionY() - y;
-
- if (std::fabs(dx) < 0.001f && std::fabs(dy) < 0.001f)
- {
- float angle = (float)rand_norm()*static_cast<float>(2*M_PI);
- vcos = std::cos(angle);
- vsin = std::sin(angle);
- }
- else
- {
- float dist = std::sqrt((dx*dx) + (dy*dy));
- vcos = dx / dist;
- vsin = dy / dist;
- }
-}
-
-bool Position::HasInArc(float arc, const Position* obj, float border) const
-{
- // always have self in arc
- if (obj == this)
- return true;
-
- // move arc to range 0.. 2*pi
- arc = NormalizeOrientation(arc);
-
- float angle = GetAngle(obj);
- angle -= m_orientation;
-
- // move angle to range -pi ... +pi
- angle = NormalizeOrientation(angle);
- if (angle > float(M_PI))
- angle -= 2.0f * float(M_PI);
-
- float lborder = -1 * (arc/border); // in range -pi..0
- float rborder = (arc/border); // in range 0..pi
- return ((angle >= lborder) && (angle <= rborder));
-}
-
bool WorldObject::IsInBetween(const WorldObject* obj1, const WorldObject* obj2, float size) const
{
if (!obj1 || !obj2)
@@ -1649,11 +1501,6 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const
}
}
-bool Position::IsPositionValid() const
-{
- return Trinity::IsValidMapCoord(m_positionX, m_positionY, m_positionZ, m_orientation);
-}
-
float WorldObject::GetGridActivationRange() const
{
if (ToPlayer())
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index c48d8ff4d18..a560afa7f1b 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -20,6 +20,7 @@
#define _OBJECT_H
#include "Common.h"
+#include "Position.h"
#include "UpdateMask.h"
#include "GridReference.h"
#include "ObjectDefines.h"
@@ -246,141 +247,6 @@ class Object
Object& operator=(Object const& right) = delete;
};
-struct Position
-{
- Position(float x = 0, float y = 0, float z = 0, float o = 0)
- : m_positionX(x), m_positionY(y), m_positionZ(z), m_orientation(NormalizeOrientation(o)) { }
-
- Position(const Position &loc) { Relocate(loc); }
-
- struct PositionXYZStreamer
- {
- explicit PositionXYZStreamer(Position& pos) : m_pos(&pos) { }
- Position* m_pos;
- };
-
- struct PositionXYZOStreamer
- {
- explicit PositionXYZOStreamer(Position& pos) : m_pos(&pos) { }
- Position* m_pos;
- };
-
- float m_positionX;
- float m_positionY;
- float m_positionZ;
-// Better to limit access to m_orientation field, but this will be hard to achieve with many scripts using array initialization for this structure
-//private:
- float m_orientation;
-//public:
-
- bool operator==(Position const &a);
-
- inline bool operator!=(Position const &a)
- {
- return !(operator==(a));
- }
-
- void Relocate(float x, float y)
- { m_positionX = x; m_positionY = y;}
- void Relocate(float x, float y, float z)
- { m_positionX = x; m_positionY = y; m_positionZ = z; }
- void Relocate(float x, float y, float z, float orientation)
- { m_positionX = x; m_positionY = y; m_positionZ = z; SetOrientation(orientation); }
- void Relocate(Position const &pos)
- { m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; SetOrientation(pos.m_orientation); }
- void Relocate(Position const* pos)
- { m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; SetOrientation(pos->m_orientation); }
- void RelocateOffset(Position const &offset);
- void SetOrientation(float orientation)
- { m_orientation = NormalizeOrientation(orientation); }
-
- float GetPositionX() const { return m_positionX; }
- float GetPositionY() const { return m_positionY; }
- float GetPositionZ() const { return m_positionZ; }
- float GetOrientation() const { return m_orientation; }
-
- void GetPosition(float &x, float &y) const
- { x = m_positionX; y = m_positionY; }
- void GetPosition(float &x, float &y, float &z) const
- { x = m_positionX; y = m_positionY; z = m_positionZ; }
- void GetPosition(float &x, float &y, float &z, float &o) const
- { x = m_positionX; y = m_positionY; z = m_positionZ; o = m_orientation; }
-
- Position GetPosition() const
- {
- return *this;
- }
-
- Position::PositionXYZStreamer PositionXYZStream()
- {
- return PositionXYZStreamer(*this);
- }
- Position::PositionXYZOStreamer PositionXYZOStream()
- {
- return PositionXYZOStreamer(*this);
- }
-
- bool IsPositionValid() const;
-
- float GetExactDist2dSq(float x, float y) const
- { float dx = m_positionX - x; float dy = m_positionY - y; return dx*dx + dy*dy; }
- float GetExactDist2d(const float x, const float y) const
- { return std::sqrt(GetExactDist2dSq(x, y)); }
- float GetExactDist2dSq(Position const* pos) const
- { float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy; }
- float GetExactDist2d(Position const* pos) const
- { return std::sqrt(GetExactDist2dSq(pos)); }
- float GetExactDistSq(float x, float y, float z) const
- { float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz; }
- float GetExactDist(float x, float y, float z) const
- { return std::sqrt(GetExactDistSq(x, y, z)); }
- float GetExactDistSq(Position const* pos) const
- { float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; float dz = m_positionZ - pos->m_positionZ; return dx*dx + dy*dy + dz*dz; }
- float GetExactDist(Position const* pos) const
- { return std::sqrt(GetExactDistSq(pos)); }
-
- void GetPositionOffsetTo(Position const & endPos, Position & retOffset) const;
- Position GetPositionWithOffset(Position const& offset) const;
-
- float GetAngle(Position const* pos) const;
- float GetAngle(float x, float y) const;
- float GetRelativeAngle(Position const* pos) const
- { return GetAngle(pos) - m_orientation; }
- float GetRelativeAngle(float x, float y) const { return GetAngle(x, y) - m_orientation; }
- void GetSinCos(float x, float y, float &vsin, float &vcos) const;
-
- bool IsInDist2d(float x, float y, float dist) const
- { return GetExactDist2dSq(x, y) < dist * dist; }
- bool IsInDist2d(Position const* pos, float dist) const
- { return GetExactDist2dSq(pos) < dist * dist; }
- bool IsInDist(float x, float y, float z, float dist) const
- { return GetExactDistSq(x, y, z) < dist * dist; }
- bool IsInDist(Position const* pos, float dist) const
- { return GetExactDistSq(pos) < dist * dist; }
- bool HasInArc(float arcangle, Position const* pos, float border = 2.0f) const;
- bool HasInLine(WorldObject const* target, float width) const;
- std::string ToString() const;
-
- // modulos a radian orientation to the range of 0..2PI
- static float NormalizeOrientation(float o)
- {
- // fmod only supports positive numbers. Thus we have
- // to emulate negative numbers
- if (o < 0)
- {
- float mod = o *-1;
- mod = std::fmod(mod, 2.0f * static_cast<float>(M_PI));
- mod = -mod + 2.0f * static_cast<float>(M_PI);
- return mod;
- }
- return std::fmod(o, 2.0f * static_cast<float>(M_PI));
- }
-};
-ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
-ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer);
-ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer);
-ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
-
struct MovementInfo
{
// common
diff --git a/src/server/game/Entities/Object/ObjectGuid.cpp b/src/server/game/Entities/Object/ObjectGuid.cpp
index b86a253a84d..c15668c3887 100644
--- a/src/server/game/Entities/Object/ObjectGuid.cpp
+++ b/src/server/game/Entities/Object/ObjectGuid.cpp
@@ -18,7 +18,6 @@
#include "ObjectGuid.h"
#include "World.h"
-#include "ObjectMgr.h"
#include <sstream>
#include <iomanip>
diff --git a/src/server/game/Entities/Object/ObjectGuid.h b/src/server/game/Entities/Object/ObjectGuid.h
index be292751811..45881ddab6d 100644
--- a/src/server/game/Entities/Object/ObjectGuid.h
+++ b/src/server/game/Entities/Object/ObjectGuid.h
@@ -23,6 +23,7 @@
#include "ByteBuffer.h"
#include <functional>
+#include <unordered_set>
enum TypeID
{
@@ -82,10 +83,12 @@ class ObjectGuid
public:
static ObjectGuid const Empty;
+ typedef uint32 LowType;
+
ObjectGuid() : _guid(0) { }
explicit ObjectGuid(uint64 guid) : _guid(guid) { }
- ObjectGuid(HighGuid hi, uint32 entry, uint32 counter) : _guid(counter ? uint64(counter) | (uint64(entry) << 24) | (uint64(hi) << 48) : 0) { }
- ObjectGuid(HighGuid hi, uint32 counter) : _guid(counter ? uint64(counter) | (uint64(hi) << 48) : 0) { }
+ ObjectGuid(HighGuid hi, uint32 entry, LowType counter) : _guid(counter ? uint64(counter) | (uint64(entry) << 24) | (uint64(hi) << 48) : 0) { }
+ ObjectGuid(HighGuid hi, LowType counter) : _guid(counter ? uint64(counter) | (uint64(hi) << 48) : 0) { }
operator uint64() const { return _guid; }
PackedGuidReader ReadAsPacked() { return PackedGuidReader(*this); }
@@ -98,11 +101,11 @@ class ObjectGuid
uint64 GetRawValue() const { return _guid; }
HighGuid GetHigh() const { return HighGuid((_guid >> 48) & 0x0000FFFF); }
uint32 GetEntry() const { return HasEntry() ? uint32((_guid >> 24) & UI64LIT(0x0000000000FFFFFF)) : 0; }
- uint32 GetCounter() const
+ LowType GetCounter() const
{
return HasEntry()
- ? uint32(_guid & UI64LIT(0x0000000000FFFFFF))
- : uint32(_guid & UI64LIT(0x00000000FFFFFFFF));
+ ? LowType(_guid & UI64LIT(0x0000000000FFFFFF))
+ : LowType(_guid & UI64LIT(0x00000000FFFFFFFF));
}
static uint32 GetMaxCounter(HighGuid high)
@@ -202,6 +205,7 @@ typedef std::set<ObjectGuid> GuidSet;
typedef std::list<ObjectGuid> GuidList;
typedef std::deque<ObjectGuid> GuidDeque;
typedef std::vector<ObjectGuid> GuidVector;
+typedef std::unordered_set<ObjectGuid> GuidUnorderedSet;
// minimum buffer size for packed guid is 9 bytes
#define PACKED_GUID_MIN_BUFFER_SIZE 9
diff --git a/src/server/game/Entities/Object/Position.cpp b/src/server/game/Entities/Object/Position.cpp
new file mode 100644
index 00000000000..530e51cd8f5
--- /dev/null
+++ b/src/server/game/Entities/Object/Position.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Position.h"
+#include "ByteBuffer.h"
+#include "G3D/g3dmath.h"
+#include "GridDefines.h"
+
+bool Position::operator==(Position const &a)
+{
+ return (G3D::fuzzyEq(a.m_positionX, m_positionX) &&
+ G3D::fuzzyEq(a.m_positionY, m_positionY) &&
+ G3D::fuzzyEq(a.m_positionZ, m_positionZ) &&
+ G3D::fuzzyEq(a.m_orientation, m_orientation));
+}
+
+void Position::RelocateOffset(const Position & offset)
+{
+ m_positionX = GetPositionX() + (offset.GetPositionX() * std::cos(GetOrientation()) + offset.GetPositionY() * std::sin(GetOrientation() + float(M_PI)));
+ m_positionY = GetPositionY() + (offset.GetPositionY() * std::cos(GetOrientation()) + offset.GetPositionX() * std::sin(GetOrientation()));
+ m_positionZ = GetPositionZ() + offset.GetPositionZ();
+ SetOrientation(GetOrientation() + offset.GetOrientation());
+}
+
+bool Position::IsPositionValid() const
+{
+ return Trinity::IsValidMapCoord(m_positionX, m_positionY, m_positionZ, m_orientation);
+}
+
+void Position::GetPositionOffsetTo(const Position & endPos, Position & retOffset) const
+{
+ float dx = endPos.GetPositionX() - GetPositionX();
+ float dy = endPos.GetPositionY() - GetPositionY();
+
+ retOffset.m_positionX = dx * std::cos(GetOrientation()) + dy * std::sin(GetOrientation());
+ retOffset.m_positionY = dy * std::cos(GetOrientation()) - dx * std::sin(GetOrientation());
+ retOffset.m_positionZ = endPos.GetPositionZ() - GetPositionZ();
+ retOffset.SetOrientation(endPos.GetOrientation() - GetOrientation());
+}
+
+Position Position::GetPositionWithOffset(Position const& offset) const
+{
+ Position ret(*this);
+ ret.RelocateOffset(offset);
+ return ret;
+}
+
+float Position::GetAngle(const Position* obj) const
+{
+ if (!obj)
+ return 0;
+
+ return GetAngle(obj->GetPositionX(), obj->GetPositionY());
+}
+
+// Return angle in range 0..2*pi
+float Position::GetAngle(float x, float y) const
+{
+ float dx = x - GetPositionX();
+ float dy = y - GetPositionY();
+
+ float ang = std::atan2(dy, dx);
+ ang = (ang >= 0) ? ang : 2 * float(M_PI) + ang;
+ return ang;
+}
+
+void Position::GetSinCos(const float x, const float y, float &vsin, float &vcos) const
+{
+ float dx = GetPositionX() - x;
+ float dy = GetPositionY() - y;
+
+ if (std::fabs(dx) < 0.001f && std::fabs(dy) < 0.001f)
+ {
+ float angle = (float)rand_norm()*static_cast<float>(2 * M_PI);
+ vcos = std::cos(angle);
+ vsin = std::sin(angle);
+ }
+ else
+ {
+ float dist = std::sqrt((dx*dx) + (dy*dy));
+ vcos = dx / dist;
+ vsin = dy / dist;
+ }
+}
+
+bool Position::HasInArc(float arc, const Position* obj, float border) const
+{
+ // always have self in arc
+ if (obj == this)
+ return true;
+
+ // move arc to range 0.. 2*pi
+ arc = NormalizeOrientation(arc);
+
+ float angle = GetAngle(obj);
+ angle -= m_orientation;
+
+ // move angle to range -pi ... +pi
+ angle = NormalizeOrientation(angle);
+ if (angle > float(M_PI))
+ angle -= 2.0f * float(M_PI);
+
+ float lborder = -1 * (arc / border); // in range -pi..0
+ float rborder = (arc / border); // in range 0..pi
+ return ((angle >= lborder) && (angle <= rborder));
+}
+
+bool Position::HasInLine(Position const* pos, float width) const
+{
+ if (!HasInArc(float(M_PI), pos))
+ return false;
+
+ float angle = GetRelativeAngle(pos);
+ return std::fabs(std::sin(angle)) * GetExactDist2d(pos->GetPositionX(), pos->GetPositionY()) < width;
+}
+
+std::string Position::ToString() const
+{
+ std::stringstream sstr;
+ sstr << "X: " << m_positionX << " Y: " << m_positionY << " Z: " << m_positionZ << " O: " << m_orientation;
+ return sstr.str();
+}
+
+ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer)
+{
+ buf << streamer.Pos->GetPositionX();
+ buf << streamer.Pos->GetPositionY();
+ return buf;
+}
+
+ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYStreamer const& streamer)
+{
+ float x, y;
+ buf >> x >> y;
+ streamer.Pos->Relocate(x, y);
+ return buf;
+}
+
+ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer)
+{
+ buf << streamer.Pos->GetPositionX();
+ buf << streamer.Pos->GetPositionY();
+ buf << streamer.Pos->GetPositionZ();
+ return buf;
+}
+
+ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer)
+{
+ float x, y, z;
+ buf >> x >> y >> z;
+ streamer.Pos->Relocate(x, y, z);
+ return buf;
+}
+
+ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer)
+{
+ buf << streamer.Pos->GetPositionX();
+ buf << streamer.Pos->GetPositionY();
+ buf << streamer.Pos->GetPositionZ();
+ buf << streamer.Pos->GetOrientation();
+ return buf;
+}
+
+ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer)
+{
+ float x, y, z, o;
+ buf >> x >> y >> z >> o;
+ streamer.Pos->Relocate(x, y, z, o);
+ return buf;
+}
diff --git a/src/server/game/Entities/Object/Position.h b/src/server/game/Entities/Object/Position.h
new file mode 100644
index 00000000000..5bd37567811
--- /dev/null
+++ b/src/server/game/Entities/Object/Position.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef Trinity_game_Position_h__
+#define Trinity_game_Position_h__
+
+#include "Common.h"
+
+class ByteBuffer;
+
+struct Position
+{
+ Position(float x = 0, float y = 0, float z = 0, float o = 0)
+ : m_positionX(x), m_positionY(y), m_positionZ(z), m_orientation(NormalizeOrientation(o)) { }
+
+ Position(Position const& loc) { Relocate(loc); }
+
+ struct PositionXYStreamer
+ {
+ explicit PositionXYStreamer(Position& pos) : Pos(&pos) { }
+ Position* Pos;
+ };
+
+ struct PositionXYZStreamer
+ {
+ explicit PositionXYZStreamer(Position& pos) : Pos(&pos) { }
+ Position* Pos;
+ };
+
+ struct PositionXYZOStreamer
+ {
+ explicit PositionXYZOStreamer(Position& pos) : Pos(&pos) { }
+ Position* Pos;
+ };
+
+ float m_positionX;
+ float m_positionY;
+ float m_positionZ;
+ // Better to limit access to _orientation field, to guarantee the value is normalized
+private:
+ float m_orientation;
+
+public:
+ bool operator==(Position const &a);
+
+ inline bool operator!=(Position const &a)
+ {
+ return !(operator==(a));
+ }
+
+ void Relocate(float x, float y)
+ {
+ m_positionX = x; m_positionY = y;
+ }
+
+ void Relocate(float x, float y, float z)
+ {
+ m_positionX = x; m_positionY = y; m_positionZ = z;
+ }
+
+ void Relocate(float x, float y, float z, float orientation)
+ {
+ m_positionX = x; m_positionY = y; m_positionZ = z; SetOrientation(orientation);
+ }
+
+ void Relocate(Position const &pos)
+ {
+ m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; SetOrientation(pos.m_orientation);
+ }
+
+ void Relocate(Position const* pos)
+ {
+ m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; SetOrientation(pos->m_orientation);
+ }
+
+ void RelocateOffset(Position const &offset);
+
+ void SetOrientation(float orientation)
+ {
+ m_orientation = NormalizeOrientation(orientation);
+ }
+
+ float GetPositionX() const { return m_positionX; }
+ float GetPositionY() const { return m_positionY; }
+ float GetPositionZ() const { return m_positionZ; }
+ float GetOrientation() const { return m_orientation; }
+
+ void GetPosition(float &x, float &y) const
+ {
+ x = m_positionX; y = m_positionY;
+ }
+
+ void GetPosition(float &x, float &y, float &z) const
+ {
+ x = m_positionX; y = m_positionY; z = m_positionZ;
+ }
+
+ void GetPosition(float &x, float &y, float &z, float &o) const
+ {
+ x = m_positionX; y = m_positionY; z = m_positionZ; o = m_orientation;
+ }
+
+ Position GetPosition() const { return *this; }
+
+ Position::PositionXYStreamer PositionXYStream() { return PositionXYStreamer(*this); }
+ Position::PositionXYZStreamer PositionXYZStream() { return PositionXYZStreamer(*this); }
+ Position::PositionXYZOStreamer PositionXYZOStream() { return PositionXYZOStreamer(*this); }
+
+ bool IsPositionValid() const;
+
+ float GetExactDist2dSq(float x, float y) const
+ {
+ float dx = m_positionX - x; float dy = m_positionY - y; return dx*dx + dy*dy;
+ }
+
+ float GetExactDist2d(const float x, const float y) const
+ {
+ return std::sqrt(GetExactDist2dSq(x, y));
+ }
+
+ float GetExactDist2dSq(Position const* pos) const
+ {
+ float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy;
+ }
+
+ float GetExactDist2d(Position const* pos) const
+ {
+ return std::sqrt(GetExactDist2dSq(pos));
+ }
+
+ float GetExactDistSq(float x, float y, float z) const
+ {
+ float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz;
+ }
+
+ float GetExactDist(float x, float y, float z) const
+ {
+ return std::sqrt(GetExactDistSq(x, y, z));
+ }
+
+ float GetExactDistSq(Position const* pos) const
+ {
+ float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; float dz = m_positionZ - pos->m_positionZ; return dx*dx + dy*dy + dz*dz;
+ }
+
+ float GetExactDist(Position const* pos) const
+ {
+ return std::sqrt(GetExactDistSq(pos));
+ }
+
+ void GetPositionOffsetTo(Position const & endPos, Position & retOffset) const;
+ Position GetPositionWithOffset(Position const& offset) const;
+
+ float GetAngle(Position const* pos) const;
+ float GetAngle(float x, float y) const;
+ float GetRelativeAngle(Position const* pos) const
+ {
+ return GetAngle(pos) - m_orientation;
+ }
+
+ float GetRelativeAngle(float x, float y) const { return GetAngle(x, y) - m_orientation; }
+ void GetSinCos(float x, float y, float &vsin, float &vcos) const;
+
+ bool IsInDist2d(float x, float y, float dist) const
+ {
+ return GetExactDist2dSq(x, y) < dist * dist;
+ }
+
+ bool IsInDist2d(Position const* pos, float dist) const
+ {
+ return GetExactDist2dSq(pos) < dist * dist;
+ }
+
+ bool IsInDist(float x, float y, float z, float dist) const
+ {
+ return GetExactDistSq(x, y, z) < dist * dist;
+ }
+
+ bool IsInDist(Position const* pos, float dist) const
+ {
+ return GetExactDistSq(pos) < dist * dist;
+ }
+
+ bool HasInArc(float arcangle, Position const* pos, float border = 2.0f) const;
+ bool HasInLine(Position const* pos, float width) const;
+ std::string ToString() const;
+
+ // modulos a radian orientation to the range of 0..2PI
+ static float NormalizeOrientation(float o)
+ {
+ // fmod only supports positive numbers. Thus we have
+ // to emulate negative numbers
+ if (o < 0)
+ {
+ float mod = o *-1;
+ mod = std::fmod(mod, 2.0f * static_cast<float>(M_PI));
+ mod = -mod + 2.0f * static_cast<float>(M_PI);
+ return mod;
+ }
+ return std::fmod(o, 2.0f * static_cast<float>(M_PI));
+ }
+};
+
+ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer);
+ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYStreamer const& streamer);
+ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer);
+ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer);
+ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
+ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
+
+#endif // Trinity_game_Position_h__
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index 5084031880d..97cdb0cf1df 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -24,9 +24,9 @@
#include "SpellMgr.h"
#include "Pet.h"
#include "Formulas.h"
+#include "SpellHistory.h"
#include "SpellAuras.h"
#include "SpellAuraEffects.h"
-#include "CreatureAI.h"
#include "Unit.h"
#include "Util.h"
#include "Group.h"
@@ -408,7 +408,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
RemoveAllAuras();
_SaveSpells(trans);
- _SaveSpellCooldowns(trans);
+ GetSpellHistory()->SaveToDB<Pet>(trans);
CharacterDatabase.CommitTransaction(trans);
// current/stable/not_in_slot
@@ -1107,77 +1107,11 @@ uint32 Pet::GetCurrentFoodBenefitLevel(uint32 itemlevel) const
void Pet::_LoadSpellCooldowns()
{
- m_CreatureSpellCooldowns.clear();
- m_CreatureCategoryCooldowns.clear();
-
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL_COOLDOWN);
stmt->setUInt32(0, m_charmInfo->GetPetNumber());
- PreparedQueryResult result = CharacterDatabase.Query(stmt);
-
- if (result)
- {
- time_t curTime = time(NULL);
-
- PacketCooldowns cooldowns;
- WorldPacket data;
-
- do
- {
- Field* fields = result->Fetch();
-
- uint32 spell_id = fields[0].GetUInt32();
- time_t db_time = time_t(fields[1].GetUInt32());
-
- if (!sSpellMgr->GetSpellInfo(spell_id))
- {
- TC_LOG_ERROR("entities.pet", "Pet %u have unknown spell %u in `pet_spell_cooldown`, skipping.", m_charmInfo->GetPetNumber(), spell_id);
- continue;
- }
+ PreparedQueryResult cooldownsResult = CharacterDatabase.Query(stmt);
- // skip outdated cooldown
- if (db_time <= curTime)
- continue;
-
- cooldowns[spell_id] = uint32(db_time - curTime)*IN_MILLISECONDS;
-
- _AddCreatureSpellCooldown(spell_id, db_time);
-
- TC_LOG_DEBUG("entities.pet", "Pet (Number: %u) spell %u cooldown loaded (%u secs).", m_charmInfo->GetPetNumber(), spell_id, uint32(db_time-curTime));
- }
- while (result->NextRow());
-
- if (!cooldowns.empty())
- {
- BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, cooldowns);
- GetOwner()->GetSession()->SendPacket(&data);
- }
- }
-}
-
-void Pet::_SaveSpellCooldowns(SQLTransaction& trans)
-{
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PET_SPELL_COOLDOWNS);
- stmt->setUInt32(0, m_charmInfo->GetPetNumber());
- trans->Append(stmt);
-
- time_t curTime = time(NULL);
-
- // remove oudated and save active
- for (CreatureSpellCooldowns::iterator itr = m_CreatureSpellCooldowns.begin(); itr != m_CreatureSpellCooldowns.end();)
- {
- if (itr->second <= curTime)
- m_CreatureSpellCooldowns.erase(itr++);
- else
- {
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET_SPELL_COOLDOWN);
- stmt->setUInt32(0, m_charmInfo->GetPetNumber());
- stmt->setUInt32(1, itr->first);
- stmt->setUInt32(2, uint32(itr->second));
- trans->Append(stmt);
-
- ++itr;
- }
- }
+ GetSpellHistory()->LoadFromDB<Pet>(cooldownsResult);
}
void Pet::_LoadSpells()
@@ -1314,7 +1248,7 @@ void Pet::_LoadAuras(uint32 timediff)
}
aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, &damage[0]);
aura->ApplyForTargets();
- TC_LOG_INFO("entities.pet", "Added aura spellid %u, effectmask %u", spellInfo->Id, effmask);
+ TC_LOG_DEBUG("entities.pet", "Added aura spellid %u, effectmask %u", spellInfo->Id, effmask);
}
}
while (result->NextRow());
@@ -2026,40 +1960,6 @@ void Pet::SynchronizeLevelWithOwner()
}
}
-void Pet::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs)
-{
- PacketCooldowns cooldowns;
- WorldPacket data;
- time_t curTime = time(NULL);
- for (PetSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
- {
- if (itr->second.state == PETSPELL_REMOVED)
- continue;
-
- uint32 unSpellId = itr->first;
- SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(unSpellId);
-
- // Not send cooldown for this spells
- if (spellInfo->IsCooldownStartedOnEvent())
- continue;
-
- if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE)
- continue;
-
- if ((idSchoolMask & spellInfo->GetSchoolMask()) && GetCreatureSpellCooldownDelay(unSpellId) < unTimeMs)
- {
- cooldowns[unSpellId] = unTimeMs;
- _AddCreatureSpellCooldown(unSpellId, curTime + unTimeMs/IN_MILLISECONDS);
- }
- }
-
- if (!cooldowns.empty())
- {
- BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, cooldowns);
- GetOwner()->GetSession()->SendPacket(&data);
- }
-}
-
Player* Pet::GetOwner() const
{
return Minion::GetOwner()->ToPlayer();
diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h
index 62d82aaab1b..1cc86ea2a20 100644
--- a/src/server/game/Entities/Pet/Pet.h
+++ b/src/server/game/Entities/Pet/Pet.h
@@ -108,7 +108,6 @@ class Pet : public Guardian
bool IsPetAura(Aura const* aura);
void _LoadSpellCooldowns();
- void _SaveSpellCooldowns(SQLTransaction& trans);
void _LoadAuras(uint32 timediff);
void _SaveAuras(SQLTransaction& trans);
void _LoadSpells();
@@ -121,7 +120,6 @@ class Pet : public Guardian
bool unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true);
bool removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true);
void CleanupActionBar();
- virtual void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) override;
PetSpellMap m_spells;
AutoSpellList m_autospells;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 87cff6f2c37..275dbf92dca 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -51,7 +51,6 @@
#include "LFGMgr.h"
#include "Language.h"
#include "Log.h"
-#include "MapInstanced.h"
#include "MapManager.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
@@ -68,12 +67,12 @@
#include "SpellAuraEffects.h"
#include "SpellAuras.h"
#include "SpellMgr.h"
+#include "SpellHistory.h"
#include "Transport.h"
#include "UpdateData.h"
#include "UpdateFieldFlags.h"
#include "UpdateMask.h"
#include "Util.h"
-#include "Vehicle.h"
#include "Weather.h"
#include "WeatherMgr.h"
#include "World.h"
@@ -966,8 +965,6 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo)
{
//FIXME: outfitId not used in player creating
/// @todo need more checks against packet modifications
- // should check that skin, face, hair* are valid via DBC per race/class
- // also do it in Player::BuildEnumData, Player::LoadFromDB
Object::_Create(guidlow, 0, HIGHGUID_PLAYER);
@@ -1009,6 +1006,13 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo)
return false;
}
+ if (!ValidateAppearance(createInfo->Race, createInfo->Class, createInfo->Gender, createInfo->HairStyle, createInfo->HairColor, createInfo->Face, createInfo->FacialHair, createInfo->Skin, true))
+ {
+ TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking-attempt: Account %u tried creating a character named '%s' with invalid appearance attributes - refusing to do so",
+ GetSession()->GetAccountId(), m_name.c_str());
+ return false;
+ }
+
uint32 RaceClassGender = (createInfo->Race) | (createInfo->Class << 8) | (createInfo->Gender << 16);
SetUInt32Value(UNIT_FIELD_BYTES_0, (RaceClassGender | (powertype << 24)));
@@ -1981,12 +1985,29 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data)
*data << uint8(gender); // gender
uint32 playerBytes = fields[5].GetUInt32();
+ uint32 playerBytes2 = fields[6].GetUInt32();
+
+ uint16 atLoginFlags = fields[15].GetUInt16();
+
+ if (!ValidateAppearance(uint8(plrRace), uint8(plrClass), gender, uint8(playerBytes >> 16), uint8(playerBytes >> 24), uint8(playerBytes >> 8), uint8(playerBytes2), uint8(playerBytes)))
+ {
+ TC_LOG_ERROR("entities.player.loading", "Player %u has wrong Appearance values (Hair/Skin/Color), forcing recustomize", guid);
+
+ if (!(atLoginFlags & AT_LOGIN_CUSTOMIZE))
+ {
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
+ stmt->setUInt16(0, uint16(AT_LOGIN_CUSTOMIZE));
+ stmt->setUInt32(1, guid);
+ CharacterDatabase.Execute(stmt);
+ atLoginFlags |= AT_LOGIN_CUSTOMIZE;
+ }
+ }
+
*data << uint8(playerBytes); // skin
*data << uint8(playerBytes >> 8); // face
*data << uint8(playerBytes >> 16); // hair style
*data << uint8(playerBytes >> 24); // hair color
- uint32 playerBytes2 = fields[6].GetUInt32();
*data << uint8(playerBytes2 & 0xFF); // facial hair
*data << uint8(fields[7].GetUInt8()); // level
@@ -2001,7 +2022,6 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data)
uint32 charFlags = 0;
uint32 playerFlags = fields[14].GetUInt32();
- uint16 atLoginFlags = fields[15].GetUInt16();
if (playerFlags & PLAYER_FLAGS_HIDE_HELM)
charFlags |= CHARACTER_FLAG_HIDE_HELM;
if (playerFlags & PLAYER_FLAGS_HIDE_CLOAK)
@@ -3326,12 +3346,10 @@ void Player::InitStatsForLevel(bool reapplyMods)
void Player::SendInitialSpells()
{
- time_t curTime = time(NULL);
- time_t infTime = curTime + infinityCooldownDelayCheck;
-
+ uint16 spellCooldowns = GetSpellHistory()->GetCooldownsSizeForPacket();
uint16 spellCount = 0;
- WorldPacket data(SMSG_INITIAL_SPELLS, (1+2+4*m_spells.size()+2+m_spellCooldowns.size()*(2+2+2+4+4)));
+ WorldPacket data(SMSG_INITIAL_SPELLS, (1 + 2 + 4 * m_spells.size() + 2 + spellCooldowns * (2 + 2 + 2 + 4 + 4)));
data << uint8(0);
size_t countPos = data.wpos();
@@ -3353,40 +3371,7 @@ void Player::SendInitialSpells()
data.put<uint16>(countPos, spellCount); // write real count value
- uint16 spellCooldowns = m_spellCooldowns.size();
- data << uint16(spellCooldowns);
- for (SpellCooldowns::const_iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); ++itr)
- {
- SpellInfo const* sEntry = sSpellMgr->GetSpellInfo(itr->first);
- if (!sEntry)
- continue;
-
- data << uint32(itr->first);
-
- data << uint16(itr->second.itemid); // cast item id
- data << uint16(sEntry->GetCategory()); // spell category
-
- // send infinity cooldown in special format
- if (itr->second.end >= infTime)
- {
- data << uint32(1); // cooldown
- data << uint32(0x80000000); // category cooldown
- continue;
- }
-
- time_t cooldown = itr->second.end > curTime ? (itr->second.end-curTime)*IN_MILLISECONDS : 0;
-
- if (sEntry->GetCategory()) // may be wrong, but anyway better than nothing...
- {
- data << uint32(0); // cooldown
- data << uint32(cooldown); // category cooldown
- }
- else
- {
- data << uint32(cooldown); // cooldown
- data << uint32(0); // category cooldown
- }
- }
+ GetSpellHistory()->WritePacket<Player>(data);
GetSession()->SendPacket(&data);
@@ -3902,7 +3887,7 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const
// talent dependent passives activated at form apply have proper stance data
ShapeshiftForm form = GetShapeshiftForm();
bool need_cast = (!spellInfo->Stances || (form && (spellInfo->Stances & (1 << (form - 1)))) ||
- (!form && (spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_NEED_SHAPESHIFT)));
+ (!form && spellInfo->HasAttribute(SPELL_ATTR2_NOT_NEED_SHAPESHIFT)));
//Check CasterAuraStates
return need_cast && (!spellInfo->CasterAuraState || HasAuraState(AuraStateType(spellInfo->CasterAuraState)));
@@ -4183,154 +4168,19 @@ bool Player::Has310Flyer(bool checkAllSpells, uint32 excludeSpellId)
return false;
}
-void Player::RemoveSpellCooldown(uint32 spell_id, bool update /* = false */)
-{
- m_spellCooldowns.erase(spell_id);
-
- if (update)
- SendClearCooldown(spell_id, this);
-}
-
-// I am not sure which one is more efficient
-void Player::RemoveCategoryCooldown(uint32 cat)
-{
- SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(cat);
- if (i_scstore != sSpellsByCategoryStore.end())
- for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
- RemoveSpellCooldown(*i_scset, true);
-}
-
-void Player::RemoveSpellCategoryCooldown(uint32 cat, bool update /* = false */)
-{
- SpellCategoryStore::const_iterator ct = sSpellsByCategoryStore.find(cat);
- if (ct == sSpellsByCategoryStore.end())
- return;
-
- const SpellCategorySet& ct_set = ct->second;
- for (SpellCooldowns::const_iterator i = m_spellCooldowns.begin(); i != m_spellCooldowns.end();)
- {
- if (ct_set.find(i->first) != ct_set.end())
- RemoveSpellCooldown((i++)->first, update);
- else
- ++i;
- }
-}
-
void Player::RemoveArenaSpellCooldowns(bool removeActivePetCooldowns)
{
// remove cooldowns on spells that have < 10 min CD
-
- SpellCooldowns::iterator itr, next;
- for (itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); itr = next)
+ GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
{
- next = itr;
- ++next;
- SpellInfo const* entry = sSpellMgr->GetSpellInfo(itr->first);
- // check if spellentry is present and if the cooldown is less than 10 min
- if (entry &&
- entry->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS &&
- entry->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS)
- {
- // remove & notify
- RemoveSpellCooldown(itr->first, true);
- }
- }
+ SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
+ return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS;
+ }, true);
// pet cooldowns
if (removeActivePetCooldowns)
if (Pet* pet = GetPet())
- {
- // notify player
- for (CreatureSpellCooldowns::const_iterator itr2 = pet->m_CreatureSpellCooldowns.begin(); itr2 != pet->m_CreatureSpellCooldowns.end(); ++itr2)
- SendClearCooldown(itr2->first, pet);
-
- // actually clear cooldowns
- pet->m_CreatureSpellCooldowns.clear();
- }
-}
-
-void Player::RemoveAllSpellCooldown()
-{
- if (!m_spellCooldowns.empty())
- {
- for (SpellCooldowns::const_iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); ++itr)
- SendClearCooldown(itr->first, this);
-
- m_spellCooldowns.clear();
- }
-}
-
-void Player::_LoadSpellCooldowns(PreparedQueryResult result)
-{
- // some cooldowns can be already set at aura loading...
-
- //QueryResult* result = CharacterDatabase.PQuery("SELECT spell, item, time FROM character_spell_cooldown WHERE guid = '%u'", GetGUIDLow());
-
- if (result)
- {
- time_t curTime = time(NULL);
-
- do
- {
- Field* fields = result->Fetch();
- uint32 spell_id = fields[0].GetUInt32();
- uint32 item_id = fields[1].GetUInt32();
- time_t db_time = time_t(fields[2].GetUInt32());
-
- if (!sSpellMgr->GetSpellInfo(spell_id))
- {
- TC_LOG_ERROR("entities.player.loading", "Player %u has unknown spell %u in `character_spell_cooldown`, skipping.", GetGUIDLow(), spell_id);
- continue;
- }
-
- // skip outdated cooldown
- if (db_time <= curTime)
- continue;
-
- AddSpellCooldown(spell_id, item_id, db_time);
-
- TC_LOG_DEBUG("entities.player.loading", "Player (GUID: %u) spell %u, item %u cooldown loaded (%u secs).", GetGUIDLow(), spell_id, item_id, uint32(db_time-curTime));
- }
- while (result->NextRow());
- }
-}
-
-void Player::_SaveSpellCooldowns(SQLTransaction& trans)
-{
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN);
- stmt->setUInt32(0, GetGUIDLow());
- trans->Append(stmt);
-
- time_t curTime = time(NULL);
- time_t infTime = curTime + infinityCooldownDelayCheck;
-
- bool first_round = true;
- std::ostringstream ss;
-
- // remove outdated and save active
- for (SpellCooldowns::iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end();)
- {
- if (itr->second.end <= curTime)
- m_spellCooldowns.erase(itr++);
- else if (itr->second.end <= infTime) // not save locked cooldowns, it will be reset or set at reload
- {
- if (first_round)
- {
- ss << "INSERT INTO character_spell_cooldown (guid, spell, item, time) VALUES ";
- first_round = false;
- }
- // next new/changed record prefix
- else
- ss << ',';
- ss << '(' << GetGUIDLow() << ',' << itr->first << ',' << itr->second.itemid << ',' << uint64(itr->second.end) << ')';
- ++itr;
- }
- else
- ++itr;
- }
- // if something changed execute
- if (!first_round)
- trans->Append(ss.str().c_str());
+ pet->GetSpellHistory()->ResetAllCooldowns();
}
uint32 Player::ResetTalentsCost() const
@@ -4830,10 +4680,22 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt32(0, guid);
trans->Append(stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_ARENA_STATS);
+ stmt->setUInt32(0, guid);
+ trans->Append(stmt);
+
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA);
stmt->setUInt32(0, guid);
trans->Append(stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_BGDATA);
+ stmt->setUInt32(0, guid);
+ trans->Append(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_BATTLEGROUND_RANDOM);
+ stmt->setUInt32(0, guid);
+ trans->Append(stmt);
+
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GIFT);
stmt->setUInt32(0, guid);
trans->Append(stmt);
@@ -4866,7 +4728,7 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt32(0, guid);
trans->Append(stmt);
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWNS);
stmt->setUInt32(0, guid);
trans->Append(stmt);
@@ -4923,10 +4785,6 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt32(0, guid);
trans->Append(stmt);
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_BGDATA);
- stmt->setUInt32(0, guid);
- trans->Append(stmt);
-
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GLYPHS);
stmt->setUInt32(0, guid);
trans->Append(stmt);
@@ -4955,6 +4813,10 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt32(0, guid);
trans->Append(stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_STATS);
+ stmt->setUInt32(0, guid);
+ trans->Append(stmt);
+
CharacterDatabase.CommitTransaction(trans);
break;
}
@@ -5002,7 +4864,7 @@ void Player::DeleteOldCharacters()
*/
void Player::DeleteOldCharacters(uint32 keepDays)
{
- TC_LOG_INFO("entities.player", "Player::DeleteOldChars: Deleting all characters which have been deleted %u days before...", keepDays);
+ TC_LOG_INFO("entities.player", "Player::DeleteOldChars: Removing characters older than %u day(s)", keepDays);
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_OLD_CHARS);
stmt->setUInt32(0, uint32(time(NULL) - time_t(keepDays * DAY)));
@@ -5010,7 +4872,7 @@ void Player::DeleteOldCharacters(uint32 keepDays)
if (result)
{
- TC_LOG_DEBUG("entities.player", "Player::DeleteOldChars: Found " UI64FMTD " character(s) to delete", result->GetRowCount());
+ TC_LOG_DEBUG("entities.player", "Player::DeleteOldChars: " UI64FMTD " character(s) to remove", result->GetRowCount());
do
{
Field* fields = result->Fetch();
@@ -6636,20 +6498,20 @@ void Player::SendActionButtons(uint32 state) const
}
GetSession()->SendPacket(&data);
- TC_LOG_INFO("network", "SMSG_ACTION_BUTTONS sent '%u' spec '%u' Sent", GetGUIDLow(), m_activeSpec);
+ TC_LOG_DEBUG("network", "SMSG_ACTION_BUTTONS sent '%u' spec '%u' Sent", GetGUIDLow(), m_activeSpec);
}
bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type)
{
if (button >= MAX_ACTION_BUTTONS)
{
- TC_LOG_ERROR("entities.player", "Action %u not added into button %u for player %s (GUID: %u): button must be < %u", action, button, GetName().c_str(), GetGUIDLow(), MAX_ACTION_BUTTONS );
+ TC_LOG_DEBUG("entities.player", "Action %u not added into button %u for player %s (GUID: %u): button must be < %u", action, button, GetName().c_str(), GetGUIDLow(), MAX_ACTION_BUTTONS );
return false;
}
if (action >= MAX_ACTION_BUTTON_ACTION_VALUE)
{
- TC_LOG_ERROR("entities.player", "Action %u not added into button %u for player %s (GUID: %u): action must be < %u", action, button, GetName().c_str(), GetGUIDLow(), MAX_ACTION_BUTTON_ACTION_VALUE);
+ TC_LOG_DEBUG("entities.player", "Action %u not added into button %u for player %s (GUID: %u): action must be < %u", action, button, GetName().c_str(), GetGUIDLow(), MAX_ACTION_BUTTON_ACTION_VALUE);
return false;
}
@@ -6658,20 +6520,20 @@ bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type)
case ACTION_BUTTON_SPELL:
if (!sSpellMgr->GetSpellInfo(action))
{
- TC_LOG_ERROR("entities.player", "Spell action %u not added into button %u for player %s (GUID: %u): spell not exist", action, button, GetName().c_str(), GetGUIDLow());
+ TC_LOG_DEBUG("entities.player", "Spell action %u not added into button %u for player %s (GUID: %u): spell not exist", action, button, GetName().c_str(), GetGUIDLow());
return false;
}
if (!HasSpell(action))
{
- TC_LOG_ERROR("entities.player", "Spell action %u not added into button %u for player %s (GUID: %u): player don't known this spell", action, button, GetName().c_str(), GetGUIDLow());
+ TC_LOG_DEBUG("entities.player", "Spell action %u not added into button %u for player %s (GUID: %u): player don't known this spell", action, button, GetName().c_str(), GetGUIDLow());
return false;
}
break;
case ACTION_BUTTON_ITEM:
if (!sObjectMgr->GetItemTemplate(action))
{
- TC_LOG_ERROR("entities.player", "Item action %u not added into button %u for player %s (GUID: %u): item not exist", action, button, GetName().c_str(), GetGUIDLow());
+ TC_LOG_DEBUG("entities.player", "Item action %u not added into button %u for player %s (GUID: %u): item not exist", action, button, GetName().c_str(), GetGUIDLow());
return false;
}
break;
@@ -6681,7 +6543,7 @@ bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type)
case ACTION_BUTTON_EQSET:
break;
default:
- TC_LOG_ERROR("entities.player", "Unknown action type %u", type);
+ TC_LOG_DEBUG("entities.player", "Unknown action type %u", type);
return false; // other cases not checked at this moment
}
@@ -6883,7 +6745,7 @@ void Player::CheckAreaExploreAndOutdoor()
GiveXP(XP, NULL);
SendExplorationExperience(area, XP);
}
- TC_LOG_INFO("entities.player", "Player %u discovered a new area: %u", GetGUIDLow(), area);
+ TC_LOG_DEBUG("entities.player", "Player %u discovered a new area: %u", GetGUIDLow(), area);
}
}
}
@@ -7763,7 +7625,7 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply)
if (item->IsBroken())
return;
- TC_LOG_INFO("entities.player.items", "applying mods for item %u ", item->GetGUIDLow());
+ TC_LOG_DEBUG("entities.player.items", "applying mods for item %u ", item->GetGUIDLow());
uint8 attacktype = Player::GetAttackBySlot(slot);
@@ -8351,7 +8213,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
if (procVictim & PROC_FLAG_TAKEN_DAMAGE)
//if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
{
- for (uint8 i = 0; i < MAX_ITEM_SPELLS; ++i)
+ for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
_Spell const& spellData = proto->Spells[i];
@@ -9774,7 +9636,7 @@ uint32 Player::GetXPRestBonus(uint32 xp)
SetRestBonus(GetRestBonus() - rested_bonus);
- TC_LOG_INFO("entities.player", "Player gain %u xp (+ %u Rested Bonus). Rested points=%f", xp+rested_bonus, rested_bonus, GetRestBonus());
+ TC_LOG_DEBUG("entities.player", "GetXPRestBonus: Player %s (%u) gain %u xp (+%u Rested Bonus). Rested points=%f", GetName().c_str(), GetGUIDLow(), xp+rested_bonus, rested_bonus, GetRestBonus());
return rested_bonus;
}
@@ -12394,10 +12256,9 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
{
m_weaponChangeTimer = spellProto->StartRecoveryTime;
- GetGlobalCooldownMgr().AddGlobalCooldown(spellProto, m_weaponChangeTimer);
-
+ GetSpellHistory()->AddGlobalCooldown(spellProto, m_weaponChangeTimer);
WorldPacket data;
- BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_INCLUDE_GCD, cooldownSpell, 0);
+ GetSpellHistory()->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_INCLUDE_GCD, cooldownSpell, 0);
GetSession()->SendPacket(&data);
}
}
@@ -16361,6 +16222,8 @@ void Player::AreaExploredOrEventHappens(uint32 questId)
{
q_status.Explored = true;
m_QuestStatusSave[questId] = QUEST_DEFAULT_SAVE_TYPE;
+ SetQuestSlotState(log_slot, QUEST_STATE_COMPLETE);
+ SendQuestComplete(questId);
}
}
if (CanCompleteQuest(questId))
@@ -17280,6 +17143,20 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
SetUInt32Value(PLAYER_BYTES_2, fields[10].GetUInt32());
SetByteValue(PLAYER_BYTES_3, 0, fields[5].GetUInt8());
SetByteValue(PLAYER_BYTES_3, 1, fields[49].GetUInt8());
+
+ if (!ValidateAppearance(
+ fields[3].GetUInt8(), // race
+ fields[4].GetUInt8(), // class
+ gender, GetByteValue(PLAYER_BYTES, 2), // hair type
+ GetByteValue(PLAYER_BYTES, 3), //hair color
+ uint8(fields[9].GetUInt32() >> 8), // face
+ GetByteValue(PLAYER_BYTES_2, 0), // facial hair
+ GetByteValue(PLAYER_BYTES, 0))) // skin color
+ {
+ TC_LOG_ERROR("entities.player", "Player %s has wrong Appearance values (Hair/Skin/Color), can't be loaded.", guid.ToString().c_str());
+ return false;
+ }
+
SetUInt32Value(PLAYER_FLAGS, fields[11].GetUInt32());
SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fields[48].GetUInt32());
@@ -17764,7 +17641,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
// has to be called after last Relocate() in Player::LoadFromDB
SetFallInformation(0, GetPositionZ());
- _LoadSpellCooldowns(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS));
+ GetSpellHistory()->LoadFromDB<Player>(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS));
// Spell code allow apply any auras to dead character in load time in aura/spell/item loading
// Do now before stats re-calculation cleanup for ghost state unexpected auras
@@ -17999,7 +17876,7 @@ void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff)
aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, &damage[0]);
aura->ApplyForTargets();
- TC_LOG_INFO("entities.player", "Added aura spellid %u, effectmask %u", spellInfo->Id, effmask);
+ TC_LOG_DEBUG("entities.player", "Added aura spellid %u, effectmask %u", spellInfo->Id, effmask);
}
}
while (result->NextRow());
@@ -19470,7 +19347,7 @@ void Player::SaveToDB(bool create /*=false*/)
_SaveMonthlyQuestStatus(trans);
_SaveTalents(trans);
_SaveSpells(trans);
- _SaveSpellCooldowns(trans);
+ GetSpellHistory()->SaveToDB<Player>(trans);
_SaveActions(trans);
_SaveAuras(trans);
_SaveSkills(trans);
@@ -19732,6 +19609,7 @@ void Player::_SaveInventory(SQLTransaction& trans)
m_itemUpdateQueue.clear();
}
+
void Player::_SaveMail(SQLTransaction& trans)
{
if (!m_mailsLoaded)
@@ -20670,8 +20548,6 @@ void Player::PetSpellInitialize()
if (!pet)
return;
- TC_LOG_DEBUG("entities.pet", "Pet Spells Groups");
-
CharmInfo* charmInfo = pet->GetCharmInfo();
WorldPacket data(SMSG_PET_SPELLS, 8+2+4+4+4*MAX_UNIT_ACTION_BAR_INDEX+1+1);
@@ -20682,6 +20558,8 @@ void Player::PetSpellInitialize()
data << uint8(charmInfo->GetCommandState());
data << uint16(0); // Flags, mostly unknown
+ TC_LOG_DEBUG("entities.pet", "Player::PetspellInitialize: Creating spellgroups for summoned pet");
+
// action bar loop
charmInfo->BuildActionBar(&data);
@@ -20706,41 +20584,8 @@ void Player::PetSpellInitialize()
data.put<uint8>(spellsCountPos, addlist);
- uint8 cooldownsCount = pet->m_CreatureSpellCooldowns.size() + pet->m_CreatureCategoryCooldowns.size();
- data << uint8(cooldownsCount);
-
- time_t curTime = time(NULL);
-
- for (CreatureSpellCooldowns::const_iterator itr = pet->m_CreatureSpellCooldowns.begin(); itr != pet->m_CreatureSpellCooldowns.end(); ++itr)
- {
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
- if (!spellInfo)
- {
- data << uint32(0);
- data << uint16(0);
- data << uint32(0);
- data << uint32(0);
- continue;
- }
-
- time_t cooldown = (itr->second > curTime) ? (itr->second - curTime) * IN_MILLISECONDS : 0;
- data << uint32(itr->first); // spell ID
-
- CreatureSpellCooldowns::const_iterator categoryitr = pet->m_CreatureCategoryCooldowns.find(spellInfo->GetCategory());
- if (categoryitr != pet->m_CreatureCategoryCooldowns.end())
- {
- time_t categoryCooldown = (categoryitr->second > curTime) ? (categoryitr->second - curTime) * IN_MILLISECONDS : 0;
- data << uint16(spellInfo->GetCategory()); // spell category
- data << uint32(cooldown); // spell cooldown
- data << uint32(categoryCooldown); // category cooldown
- }
- else
- {
- data << uint16(0);
- data << uint32(cooldown);
- data << uint32(0);
- }
- }
+ //Cooldowns
+ pet->GetSpellHistory()->WritePacket<Pet>(data);
GetSession()->SendPacket(&data);
}
@@ -20779,7 +20624,7 @@ void Player::VehicleSpellInitialize()
if (!vehicle)
return;
- uint8 cooldownCount = vehicle->m_CreatureSpellCooldowns.size();
+ uint8 cooldownCount = vehicle->GetSpellHistory()->GetCooldownsSizeForPacket();
WorldPacket data(SMSG_PET_SPELLS, 8 + 2 + 4 + 4 + 4 * 10 + 1 + 1 + cooldownCount * (4 + 2 + 4 + 4));
data << uint64(vehicle->GetGUID()); // Guid
@@ -20820,41 +20665,7 @@ void Player::VehicleSpellInitialize()
data << uint8(0); // Auras?
// Cooldowns
- data << uint8(cooldownCount);
-
- time_t now = sWorld->GetGameTime();
-
- for (CreatureSpellCooldowns::const_iterator itr = vehicle->m_CreatureSpellCooldowns.begin(); itr != vehicle->m_CreatureSpellCooldowns.end(); ++itr)
- {
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
- if (!spellInfo)
- {
- data << uint32(0);
- data << uint16(0);
- data << uint32(0);
- data << uint32(0);
- continue;
- }
-
- time_t cooldown = (itr->second > now) ? (itr->second - now) * IN_MILLISECONDS : 0;
- data << uint32(itr->first); // spell ID
-
- CreatureSpellCooldowns::const_iterator categoryitr = vehicle->m_CreatureCategoryCooldowns.find(spellInfo->GetCategory());
- if (categoryitr != vehicle->m_CreatureCategoryCooldowns.end())
- {
- time_t categoryCooldown = (categoryitr->second > now) ? (categoryitr->second - now) * IN_MILLISECONDS : 0;
- data << uint16(spellInfo->GetCategory()); // spell category
- data << uint32(cooldown); // spell cooldown
- data << uint32(categoryCooldown); // category cooldown
- }
- else
- {
- data << uint16(0);
- data << uint32(cooldown);
- data << uint32(0);
- }
- }
-
+ vehicle->GetSpellHistory()->WritePacket<Pet>(data);
GetSession()->SendPacket(&data);
}
@@ -21474,9 +21285,9 @@ void Player::ContinueTaxiFlight()
float distPrev = MAP_SIZE*MAP_SIZE;
float distNext =
- (nodeList[0].x-GetPositionX())*(nodeList[0].x-GetPositionX())+
- (nodeList[0].y-GetPositionY())*(nodeList[0].y-GetPositionY())+
- (nodeList[0].z-GetPositionZ())*(nodeList[0].z-GetPositionZ());
+ (nodeList[0].LocX-GetPositionX())*(nodeList[0].LocX-GetPositionX())+
+ (nodeList[0].LocY-GetPositionY())*(nodeList[0].LocY-GetPositionY())+
+ (nodeList[0].LocZ-GetPositionZ())*(nodeList[0].LocZ-GetPositionZ());
for (uint32 i = 1; i < nodeList.size(); ++i)
{
@@ -21484,20 +21295,20 @@ void Player::ContinueTaxiFlight()
TaxiPathNodeEntry const& prevNode = nodeList[i-1];
// skip nodes at another map
- if (node.mapid != GetMapId())
+ if (node.MapID != GetMapId())
continue;
distPrev = distNext;
distNext =
- (node.x-GetPositionX())*(node.x-GetPositionX())+
- (node.y-GetPositionY())*(node.y-GetPositionY())+
- (node.z-GetPositionZ())*(node.z-GetPositionZ());
+ (node.LocX-GetPositionX())*(node.LocX-GetPositionX())+
+ (node.LocY-GetPositionY())*(node.LocY-GetPositionY())+
+ (node.LocZ-GetPositionZ())*(node.LocZ-GetPositionZ());
float distNodes =
- (node.x-prevNode.x)*(node.x-prevNode.x)+
- (node.y-prevNode.y)*(node.y-prevNode.y)+
- (node.z-prevNode.z)*(node.z-prevNode.z);
+ (node.LocX-prevNode.LocX)*(node.LocX-prevNode.LocX)+
+ (node.LocY-prevNode.LocY)*(node.LocY-prevNode.LocY)+
+ (node.LocZ-prevNode.LocZ)*(node.LocZ-prevNode.LocZ);
if (distNext + distPrev < distNodes)
{
@@ -21509,44 +21320,6 @@ void Player::ContinueTaxiFlight()
GetSession()->SendDoFlight(mountDisplayId, path, startNode);
}
-void Player::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs)
-{
- PacketCooldowns cooldowns;
- WorldPacket data;
- time_t curTime = time(NULL);
- for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
- {
- if (itr->second->state == PLAYERSPELL_REMOVED)
- continue;
- uint32 unSpellId = itr->first;
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(unSpellId);
- if (!spellInfo)
- {
- ASSERT(spellInfo);
- continue;
- }
-
- // Not send cooldown for this spells
- if (spellInfo->IsCooldownStartedOnEvent())
- continue;
-
- if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE)
- continue;
-
- if ((idSchoolMask & spellInfo->GetSchoolMask()) && GetSpellCooldownDelay(unSpellId) < unTimeMs)
- {
- cooldowns[unSpellId] = unTimeMs;
- AddSpellCooldown(unSpellId, 0, curTime + unTimeMs/IN_MILLISECONDS);
- }
- }
-
- if (!cooldowns.empty())
- {
- BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, cooldowns);
- GetSession()->SendPacket(&data);
- }
-}
-
void Player::InitDataForForm(bool reapplyMods)
{
ShapeshiftForm form = GetShapeshiftForm();
@@ -21954,9 +21727,9 @@ void Player::SetPvP(bool state)
(*itr)->SetPvP(state);
}
-void Player::UpdatePvP(bool state, bool override)
+void Player::UpdatePvP(bool state, bool _override)
{
- if (!state || override)
+ if (!state || _override)
{
SetPvP(state);
pvpInfo.EndTimer = 0;
@@ -21968,206 +21741,6 @@ void Player::UpdatePvP(bool state, bool override)
}
}
-bool Player::HasSpellCooldown(uint32 spell_id) const
-{
- SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id);
- return itr != m_spellCooldowns.end() && itr->second.end > time(NULL);
-}
-
-uint32 Player::GetSpellCooldownDelay(uint32 spell_id) const
-{
- SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id);
- time_t t = time(NULL);
- return uint32(itr != m_spellCooldowns.end() && itr->second.end > t ? itr->second.end - t : 0);
-}
-
-void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 itemId, Spell* spell, bool infinityCooldown)
-{
- // init cooldown values
- uint32 cat = 0;
- int32 rec = -1;
- int32 catrec = -1;
-
- // some special item spells without correct cooldown in SpellInfo
- // cooldown information stored in item prototype
- // This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client.
-
- if (itemId)
- {
- if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId))
- {
- for (uint8 idx = 0; idx < MAX_ITEM_SPELLS; ++idx)
- {
- if (uint32(proto->Spells[idx].SpellId) == spellInfo->Id)
- {
- cat = proto->Spells[idx].SpellCategory;
- rec = proto->Spells[idx].SpellCooldown;
- catrec = proto->Spells[idx].SpellCategoryCooldown;
- break;
- }
- }
- }
- }
-
- // if no cooldown found above then base at DBC data
- if (rec < 0 && catrec < 0)
- {
- cat = spellInfo->GetCategory();
- rec = spellInfo->RecoveryTime;
- catrec = spellInfo->CategoryRecoveryTime;
- }
-
- time_t curTime = time(NULL);
-
- time_t catrecTime;
- time_t recTime;
-
- bool needsCooldownPacket = false;
-
- // overwrite time for selected category
- if (infinityCooldown)
- {
- // use +MONTH as infinity mark for spell cooldown (will checked as MONTH/2 at save ans skipped)
- // but not allow ignore until reset or re-login
- catrecTime = catrec > 0 ? curTime+infinityCooldownDelay : 0;
- recTime = rec > 0 ? curTime+infinityCooldownDelay : catrecTime;
- }
- else
- {
- // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
- // prevent 0 cooldowns set by another way
- if (rec <= 0 && catrec <= 0 && (cat == 76 || (spellInfo->IsAutoRepeatRangedSpell() && spellInfo->Id != 75)))
- rec = GetAttackTime(RANGED_ATTACK);
-
- // Now we have cooldown data (if found any), time to apply mods
- if (rec > 0)
- ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, rec, spell);
-
- if (catrec > 0 && !(spellInfo->AttributesEx6 & SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS))
- ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, catrec, spell);
-
- if (int32 cooldownMod = GetTotalAuraModifier(SPELL_AURA_MOD_COOLDOWN))
- {
- // Apply SPELL_AURA_MOD_COOLDOWN only to own spells
- if (HasSpell(spellInfo->Id))
- {
- needsCooldownPacket = true;
- rec += cooldownMod * IN_MILLISECONDS; // SPELL_AURA_MOD_COOLDOWN does not affect category cooldows, verified with shaman shocks
- }
- }
-
- // replace negative cooldowns by 0
- if (rec < 0) rec = 0;
- if (catrec < 0) catrec = 0;
-
- // no cooldown after applying spell mods
- if (rec == 0 && catrec == 0)
- return;
-
- catrecTime = catrec ? curTime+catrec/IN_MILLISECONDS : 0;
- recTime = rec ? curTime+rec/IN_MILLISECONDS : catrecTime;
- }
-
- // self spell cooldown
- if (recTime > 0)
- {
- AddSpellCooldown(spellInfo->Id, itemId, recTime);
-
- if (needsCooldownPacket)
- {
- WorldPacket data;
- BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, rec);
- SendDirectMessage(&data);
- }
- }
-
- // category spells
- if (cat && catrec > 0)
- {
- SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(cat);
- if (i_scstore != sSpellsByCategoryStore.end())
- {
- for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
- {
- if (*i_scset == spellInfo->Id) // skip main spell, already handled above
- continue;
-
- AddSpellCooldown(*i_scset, itemId, catrecTime);
- }
- }
- }
-}
-
-void Player::AddSpellCooldown(uint32 spellid, uint32 itemid, time_t end_time)
-{
- SpellCooldown sc;
- sc.end = end_time;
- sc.itemid = itemid;
- m_spellCooldowns[spellid] = sc;
-}
-
-void Player::ModifySpellCooldown(uint32 spellId, int32 cooldown)
-{
- SpellCooldowns::iterator itr = m_spellCooldowns.find(spellId);
- if (itr == m_spellCooldowns.end())
- return;
-
- time_t now = time(NULL);
- if (itr->second.end + (cooldown / IN_MILLISECONDS) > now)
- itr->second.end += (cooldown / IN_MILLISECONDS);
- else
- m_spellCooldowns.erase(itr);
-
- WorldPacket data(SMSG_MODIFY_COOLDOWN, 4 + 8 + 4);
- data << uint32(spellId); // Spell ID
- data << uint64(GetGUID()); // Player GUID
- data << int32(cooldown); // Cooldown mod in milliseconds
- GetSession()->SendPacket(&data);
-
- TC_LOG_DEBUG("misc", "ModifySpellCooldown:: Player: %s (GUID: %u) Spell: %u cooldown: %u", GetName().c_str(), GetGUIDLow(), spellId, GetSpellCooldownDelay(spellId));
-}
-
-void Player::SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId /*= 0*/, Spell* spell /*= NULL*/, bool setCooldown /*= true*/)
-{
- // start cooldowns at server side, if any
- if (setCooldown)
- AddSpellAndCategoryCooldowns(spellInfo, itemId, spell);
-
- // Send activate cooldown timer (possible 0) at client side
- WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8);
- data << uint32(spellInfo->Id);
- data << uint64(GetGUID());
- SendDirectMessage(&data);
-
- uint32 cat = spellInfo->GetCategory();
- if (cat && spellInfo->CategoryRecoveryTime)
- {
- SpellCategoryStore::const_iterator ct = sSpellsByCategoryStore.find(cat);
- if (ct != sSpellsByCategoryStore.end())
- {
- SpellCategorySet const& catSet = ct->second;
- for (SpellCooldowns::const_iterator i = m_spellCooldowns.begin(); i != m_spellCooldowns.end(); ++i)
- {
- if (i->first == spellInfo->Id) // skip main spell, already handled above
- continue;
-
- SpellInfo const* spellInfo2 = sSpellMgr->GetSpellInfo(i->first);
- if (!spellInfo2 || !spellInfo2->IsCooldownStartedOnEvent())
- continue;
-
- if (catSet.find(i->first) != catSet.end())
- {
- // Send activate cooldown timer (possible 0) at client side
- WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8);
- data << uint32(i->first);
- data << uint64(GetGUID());
- SendDirectMessage(&data);
- }
- }
- }
- }
-}
-
void Player::UpdatePotionCooldown(Spell* spell)
{
// no potion used i combat or still in combat
@@ -22179,14 +21752,14 @@ void Player::UpdatePotionCooldown(Spell* spell)
{
// spell/item pair let set proper cooldown (except not existed charged spell cooldown spellmods for potions)
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(m_lastPotionId))
- for (uint8 idx = 0; idx < MAX_ITEM_SPELLS; ++idx)
+ for (uint8 idx = 0; idx < MAX_ITEM_PROTO_SPELLS; ++idx)
if (proto->Spells[idx].SpellId && proto->Spells[idx].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Spells[idx].SpellId))
- SendCooldownEvent(spellInfo, m_lastPotionId);
+ GetSpellHistory()->SendCooldownEvent(spellInfo, m_lastPotionId);
}
// from spell cases (m_lastPotionId set in Spell::SendSpellCooldown)
else
- SendCooldownEvent(spell->m_spellInfo, m_lastPotionId, spell);
+ GetSpellHistory()->SendCooldownEvent(spell->m_spellInfo, m_lastPotionId, spell);
m_lastPotionId = 0;
}
@@ -22560,13 +22133,13 @@ bool Player::IsVisibleGloballyFor(Player const* u) const
}
template<class T>
-inline void UpdateVisibilityOf_helper(GuidSet& s64, T* target, std::set<Unit*>& /*v*/)
+inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, T* target, std::set<Unit*>& /*v*/)
{
s64.insert(target->GetGUID());
}
template<>
-inline void UpdateVisibilityOf_helper(GuidSet& s64, GameObject* target, std::set<Unit*>& /*v*/)
+inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, GameObject* target, std::set<Unit*>& /*v*/)
{
// @HACK: This is to prevent objects like deeprun tram from disappearing when player moves far from its spawn point while riding it
if ((target->GetGOInfo()->type != GAMEOBJECT_TYPE_TRANSPORT))
@@ -22574,14 +22147,14 @@ inline void UpdateVisibilityOf_helper(GuidSet& s64, GameObject* target, std::set
}
template<>
-inline void UpdateVisibilityOf_helper(GuidSet& s64, Creature* target, std::set<Unit*>& v)
+inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Creature* target, std::set<Unit*>& v)
{
s64.insert(target->GetGUID());
v.insert(target);
}
template<>
-inline void UpdateVisibilityOf_helper(GuidSet& s64, Player* target, std::set<Unit*>& v)
+inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Player* target, std::set<Unit*>& v)
{
s64.insert(target->GetGUID());
v.insert(target);
@@ -22643,9 +22216,9 @@ void Player::UpdateTriggerVisibility()
UpdateData udata;
WorldPacket packet;
- for (GuidSet::iterator itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
+ for (auto itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
{
- if (itr->IsCreature())
+ if (itr->IsCreatureOrVehicle())
{
Creature* creature = GetMap()->GetCreature(*itr);
// Update fields of triggers, transformed units or unselectable units (values dependent on GM state)
@@ -23096,14 +22669,13 @@ void Player::ApplyEquipCooldown(Item* pItem)
continue;
// Don't replace longer cooldowns by equip cooldown if we have any.
- SpellCooldowns::iterator itr = m_spellCooldowns.find(spellData.SpellId);
- if (itr != m_spellCooldowns.end() && itr->second.itemid == pItem->GetEntry() && itr->second.end > time(NULL) + 30)
+ if (GetSpellHistory()->GetRemainingCooldown(spellData.SpellId) > 30 * IN_MILLISECONDS)
continue;
- AddSpellCooldown(spellData.SpellId, pItem->GetEntry(), time(NULL) + 30);
+ GetSpellHistory()->AddCooldown(spellData.SpellId, pItem->GetEntry(), std::chrono::seconds(30));
- WorldPacket data(SMSG_ITEM_COOLDOWN, 12);
- data << pItem->GetGUID();
+ WorldPacket data(SMSG_ITEM_COOLDOWN, 8 + 4);
+ data << uint64(pItem->GetGUID());
data << uint32(spellData.SpellId);
GetSession()->SendPacket(&data);
}
@@ -23702,7 +23274,7 @@ void Player::UpdateForQuestWorldObjects()
UpdateData udata;
WorldPacket packet;
- for (GuidSet::iterator itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
+ for (auto itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
{
if (itr->IsGameObject())
{
@@ -23891,7 +23463,7 @@ bool Player::HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item cons
bool Player::CanNoReagentCast(SpellInfo const* spellInfo) const
{
// don't take reagents for spells with SPELL_ATTR5_NO_REAGENT_WHILE_PREP
- if (spellInfo->AttributesEx5 & SPELL_ATTR5_NO_REAGENT_WHILE_PREP &&
+ if (spellInfo->HasAttribute(SPELL_ATTR5_NO_REAGENT_WHILE_PREP) &&
HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION))
return true;
@@ -23974,7 +23546,7 @@ uint32 Player::GetResurrectionSpellId()
}
// Reincarnation (passive spell) // prio: 1 // Glyph of Renewed Life
- if (prio < 1 && HasSpell(20608) && !HasSpellCooldown(21169) && (HasAura(58059) || HasItemCount(17030)))
+ if (prio < 1 && HasSpell(20608) && !GetSpellHistory()->HasCooldown(21169) && (HasAura(58059) || HasItemCount(17030)))
spell_id = 21169;
return spell_id;
@@ -24194,18 +23766,6 @@ void Player::UpdateAreaDependentAuras(uint32 newArea)
if (itr->second->autocast && itr->second->IsFitToRequirements(this, m_zoneUpdateId, newArea))
if (!HasAura(itr->second->spellId))
CastSpell(this, itr->second->spellId, true);
-
- if (newArea == 4273 && GetVehicleCreatureBase() && GetPositionX() > 400) // Ulduar
- {
- switch (GetVehicleBase()->GetEntry())
- {
- case 33062:
- case 33109:
- case 33060:
- GetVehicleCreatureBase()->DespawnOrUnsummon();
- break;
- }
- }
}
uint32 Player::GetCorpseReclaimDelay(bool pvp) const
@@ -24336,7 +23896,7 @@ PartyResult Player::CanUninviteFromGroup(ObjectGuid guidMember) const
return ERR_PARTY_LFG_BOOT_LIMIT;
lfg::LfgState state = sLFGMgr->GetState(gguid);
- if (state == lfg::LFG_STATE_BOOT)
+ if (sLFGMgr->IsVoteKickActive(gguid))
return ERR_PARTY_LFG_BOOT_IN_PROGRESS;
if (grp->GetMembersCount() <= lfg::LFG_GROUP_KICK_VOTES_NEEDED)
@@ -24843,7 +24403,7 @@ void Player::RestoreBaseRune(uint8 index)
{
AuraEffect const* aura = m_runes->runes[index].ConvertAura;
// If rune was converted by a non-pasive aura that still active we should keep it converted
- if (aura && !(aura->GetSpellInfo()->Attributes & SPELL_ATTR0_PASSIVE))
+ if (aura && !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_PASSIVE))
return;
ConvertRune(index, GetBaseRune(index));
SetRuneConvertAura(index, NULL);
@@ -25054,11 +24614,11 @@ uint32 Player::CalculateTalentsPoints() const
return uint32(talentPointsForLevel * sWorld->getRate(RATE_TALENT));
}
-bool Player::IsKnowHowFlyIn(uint32 mapid, uint32 zone) const
+bool Player::CanFlyInZone(uint32 mapid, uint32 zone) const
{
// continent checked in SpellInfo::CheckLocation at cast and area update
uint32 v_map = GetVirtualMapForMapAndZone(mapid, zone);
- return v_map != 571 || HasSpell(54197); // Cold Weather Flying
+ return v_map != 571 || HasSpell(54197); // 54197 = Cold Weather Flying
}
void Player::LearnSpellHighestRank(uint32 spellid)
@@ -25461,7 +25021,7 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
LearnSpell(spellid, false);
AddTalent(spellid, m_activeSpec, true);
- TC_LOG_INFO("entities.player", "TalentID: %u Rank: %u Spell: %u Spec: %u\n", talentId, talentRank, spellid, m_activeSpec);
+ TC_LOG_DEBUG("entities.player", "TalentID: %u Rank: %u Spell: %u Spec: %u\n", talentId, talentRank, spellid, m_activeSpec);
// update free talent points
SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
@@ -25596,7 +25156,7 @@ void Player::LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRa
// learn! (other talent ranks will unlearned at learning)
pet->learnSpell(spellid);
- TC_LOG_INFO("entities.player", "PetTalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid);
+ TC_LOG_DEBUG("entities.player", "PetTalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid);
// update free talent points
pet->SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
@@ -26041,14 +25601,6 @@ void Player::RemoveAtLoginFlag(AtLoginFlags flags, bool persist /*= false*/)
}
}
-void Player::SendClearCooldown(uint32 spell_id, Unit* target)
-{
- WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8);
- data << uint32(spell_id);
- data << uint64(target->GetGUID());
- SendDirectMessage(&data);
-}
-
void Player::ResetMap()
{
// this may be called during Map::Update
@@ -26699,9 +26251,9 @@ bool Player::SetDisableGravity(bool disable, bool packetOnly /*= false*/)
return true;
}
-bool Player::SetCanFly(bool apply)
+bool Player::SetCanFly(bool apply, bool packetOnly /*= false*/)
{
- if (!Unit::SetCanFly(apply))
+ if (!packetOnly && !Unit::SetCanFly(apply))
return false;
WorldPacket data(apply ? SMSG_MOVE_SET_CAN_FLY : SMSG_MOVE_UNSET_CAN_FLY, 12);
@@ -26951,3 +26503,57 @@ void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell)
GetSession()->SendPacket(&data);
}
+bool Player::ValidateAppearance(uint8 race, uint8 class_, uint8 gender, uint8 hairID, uint8 hairColor, uint8 faceID, uint8 facialHair, uint8 skinColor, bool create /*=false*/)
+{
+ // Check skin color
+ // For Skin type is always 0
+ if (CharSectionsEntry const* entry = GetCharSectionEntry(race, SECTION_TYPE_SKIN, gender, 0, skinColor))
+ { // Skin Color defined as Face color, too, we check skin & face in one pass
+ if (CharSectionsEntry const* entry2 = GetCharSectionEntry(race, SECTION_TYPE_FACE, gender, faceID, skinColor))
+ {
+ // Check DeathKnight exclusive
+ if (((entry->Flags & SECTION_FLAG_DEATH_KNIGHT) || (entry2->Flags & SECTION_FLAG_DEATH_KNIGHT)) && class_ != CLASS_DEATH_KNIGHT)
+ return false;
+ if (create && !((entry->Flags & SECTION_FLAG_PLAYER) && (entry2->Flags & SECTION_FLAG_PLAYER)))
+ return false;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+
+ // These combinations don't have an entry of Type SECTION_TYPE_FACIAL_HAIR, exclude them from that check
+ bool excludeCheck = (race == RACE_TAUREN) || (race == RACE_DRAENEI) || (gender == GENDER_FEMALE && race != RACE_NIGHTELF && race != RACE_UNDEAD_PLAYER);
+
+ // Check Hair
+ if (CharSectionsEntry const* entry = GetCharSectionEntry(race, SECTION_TYPE_HAIR, gender, hairID, hairColor))
+ {
+ if ((entry->Flags & SECTION_FLAG_DEATH_KNIGHT) && class_ != CLASS_DEATH_KNIGHT)
+ return false;
+ if (create && !(entry->Flags & SECTION_FLAG_PLAYER))
+ return false;
+
+ if (!excludeCheck)
+ {
+ if (CharSectionsEntry const* entry2 = GetCharSectionEntry(race, SECTION_TYPE_FACIAL_HAIR, gender, facialHair, hairColor))
+ {
+ if ((entry2->Flags & SECTION_FLAG_DEATH_KNIGHT) && class_ != CLASS_DEATH_KNIGHT)
+ return false;
+ if (create && !(entry2->Flags & SECTION_FLAG_PLAYER))
+ return false;
+ }
+ else
+ return false;
+ }
+ else
+ {
+ // @TODO: Bound checking for facialHair ID (used clientside for markings, tauren beard, etc.)
+ // Not present in DBC
+ }
+ }
+ else
+ return false;
+
+ return true;
+}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 61141192cd1..98b9d8a3d07 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -128,13 +128,6 @@ typedef std::unordered_map<uint32, PlayerTalent*> PlayerTalentMap;
typedef std::unordered_map<uint32, PlayerSpell*> PlayerSpellMap;
typedef std::list<SpellModifier*> SpellModList;
-struct SpellCooldown
-{
- time_t end;
- uint16 itemid;
-};
-
-typedef std::map<uint32, SpellCooldown> SpellCooldowns;
typedef std::unordered_map<uint32 /*instanceId*/, time_t/*releaseTime*/> InstanceTimeMap;
enum TrainerSpellState
@@ -353,9 +346,9 @@ struct Runes
struct EnchantDuration
{
- EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) { };
+ EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) { }
EnchantDuration(Item* _item, EnchantmentSlot _slot, uint32 _leftduration) : item(_item), slot(_slot),
- leftduration(_leftduration){ ASSERT(item); };
+ leftduration(_leftduration){ ASSERT(item); }
Item* item;
EnchantmentSlot slot;
@@ -1499,6 +1492,7 @@ class Player : public Unit, public GridObject<Player>
static bool LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, float& o, bool& in_flight, ObjectGuid guid);
static bool IsValidGender(uint8 Gender) { return Gender <= GENDER_FEMALE; }
+ static bool ValidateAppearance(uint8 race, uint8 class_, uint8 gender, uint8 hairID, uint8 hairColor, uint8 faceID, uint8 facialHair, uint8 skinColor, bool create = false);
/*********************************************************/
/*** SAVE SYSTEM ***/
@@ -1654,8 +1648,6 @@ class Player : public Unit, public GridObject<Player>
PlayerSpellMap const& GetSpellMap() const { return m_spells; }
PlayerSpellMap & GetSpellMap() { return m_spells; }
- SpellCooldowns const& GetSpellCooldownMap() const { return m_spellCooldowns; }
-
void AddSpellMod(SpellModifier* mod, bool apply);
bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = NULL);
template <class T> T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell* spell = NULL);
@@ -1665,33 +1657,14 @@ class Player : public Unit, public GridObject<Player>
void DropModCharge(SpellModifier* mod, Spell* spell);
void SetSpellModTakingSpell(Spell* spell, bool apply);
- static uint32 const infinityCooldownDelay = MONTH; // used for set "infinity cooldowns" for spells and check
- static uint32 const infinityCooldownDelayCheck = MONTH/2;
- bool HasSpellCooldown(uint32 spell_id) const;
- uint32 GetSpellCooldownDelay(uint32 spell_id) const;
- void AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 itemId, Spell* spell = NULL, bool infinityCooldown = false);
- void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time);
- void ModifySpellCooldown(uint32 spellId, int32 cooldown);
- void SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId = 0, Spell* spell = NULL, bool setCooldown = true);
- void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) override;
- void RemoveSpellCooldown(uint32 spell_id, bool update = false);
- void RemoveSpellCategoryCooldown(uint32 cat, bool update = false);
- void SendClearCooldown(uint32 spell_id, Unit* target);
-
- GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; }
-
- void RemoveCategoryCooldown(uint32 cat);
void RemoveArenaSpellCooldowns(bool removeActivePetCooldowns = false);
- void RemoveAllSpellCooldown();
- void _LoadSpellCooldowns(PreparedQueryResult result);
- void _SaveSpellCooldowns(SQLTransaction& trans);
uint32 GetLastPotionId() { return m_lastPotionId; }
void SetLastPotionId(uint32 item_id) { m_lastPotionId = item_id; }
void UpdatePotionCooldown(Spell* spell = NULL);
void setResurrectRequestData(ObjectGuid guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana);
void clearResurrectRequestData() { setResurrectRequestData(ObjectGuid::Empty, 0, 0.0f, 0.0f, 0.0f, 0, 0); }
- bool isResurrectRequestedBy(ObjectGuid guid) const { return m_resurrectGUID == guid; }
+ bool isResurrectRequestedBy(ObjectGuid guid) const { return !m_resurrectGUID.IsEmpty() && m_resurrectGUID == guid; }
bool isResurrectRequested() const { return !m_resurrectGUID.IsEmpty(); }
void ResurrectUsingRequestData();
@@ -1866,7 +1839,7 @@ class Player : public Unit, public GridObject<Player>
bool UpdatePosition(const Position &pos, bool teleport = false) { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); }
void UpdateUnderwaterState(Map* m, float x, float y, float z) override;
- void SendMessageToSet(WorldPacket* data, bool self) override {SendMessageToSetInRange(data, GetVisibilityRange(), self); };// overwrite Object::SendMessageToSet
+ void SendMessageToSet(WorldPacket* data, bool self) override {SendMessageToSetInRange(data, GetVisibilityRange(), self); }// overwrite Object::SendMessageToSet
void SendMessageToSetInRange(WorldPacket* data, float fist, bool self) override;// overwrite Object::SendMessageToSetInRange
void SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool own_team_only);
void SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr) override;
@@ -1974,8 +1947,6 @@ class Player : public Unit, public GridObject<Player>
//End of PvP System
- inline SpellCooldowns GetSpellCooldowns() const { return m_spellCooldowns; }
-
void SetDrunkValue(uint8 newDrunkValue, uint32 itemId = 0);
uint8 GetDrunkValue() const { return GetByteValue(PLAYER_BYTES_3, 1); }
static DrunkenState GetDrunkenstateByValue(uint8 value);
@@ -2135,7 +2106,7 @@ class Player : public Unit, public GridObject<Player>
void SetFallInformation(uint32 time, float z);
void HandleFall(MovementInfo const& movementInfo);
- bool IsKnowHowFlyIn(uint32 mapid, uint32 zone) const;
+ bool CanFlyInZone(uint32 mapid, uint32 zone) const;
void SetClientControl(Unit* target, bool allowMove);
@@ -2170,7 +2141,7 @@ class Player : public Unit, public GridObject<Player>
WorldLocation GetStartPosition() const;
// currently visible objects at player client
- GuidSet m_clientGUIDs;
+ GuidUnorderedSet m_clientGUIDs;
bool HaveAtClient(WorldObject const* u) const;
@@ -2330,7 +2301,7 @@ class Player : public Unit, public GridObject<Player>
void RemoveFromWhisperWhiteList(ObjectGuid guid) { WhisperList.remove(guid); }
bool SetDisableGravity(bool disable, bool packetOnly /* = false */) override;
- bool SetCanFly(bool apply) override;
+ bool SetCanFly(bool apply, bool packetOnly = false) override;
bool SetWaterWalking(bool apply, bool packetOnly = false) override;
bool SetFeatherFall(bool apply, bool packetOnly = false) override;
bool SetHover(bool enable, bool packetOnly = false) override;
@@ -2492,8 +2463,6 @@ class Player : public Unit, public GridObject<Player>
PlayerTalentMap* m_talents[MAX_TALENT_SPECS];
uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use
- GlobalCooldownMgr m_GlobalCooldownMgr;
-
uint8 m_activeSpec;
uint8 m_specsCount;
@@ -2661,8 +2630,6 @@ class Player : public Unit, public GridObject<Player>
AchievementMgr* m_achievementMgr;
ReputationMgr* m_reputationMgr;
- SpellCooldowns m_spellCooldowns;
-
uint32 m_ChampioningFaction;
uint32 m_timeSyncCounter;
diff --git a/src/server/game/Entities/Totem/Totem.cpp b/src/server/game/Entities/Totem/Totem.cpp
index 5bb13fd98cf..85ee51aebf5 100644
--- a/src/server/game/Entities/Totem/Totem.cpp
+++ b/src/server/game/Entities/Totem/Totem.cpp
@@ -17,11 +17,10 @@
*/
#include "Totem.h"
-#include "Log.h"
#include "Group.h"
-#include "ObjectMgr.h"
#include "Opcodes.h"
#include "Player.h"
+#include "SpellHistory.h"
#include "SpellMgr.h"
#include "SpellInfo.h"
#include "WorldPacket.h"
@@ -130,7 +129,7 @@ void Totem::UnSummon(uint32 msTime)
owner->SendAutoRepeatCancel(this);
if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(GetUInt32Value(UNIT_CREATED_BY_SPELL)))
- owner->SendCooldownEvent(spell, 0, NULL, false);
+ GetSpellHistory()->SendCooldownEvent(spell, 0, nullptr, false);
if (Group* group = owner->GetGroup())
{
diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp
index 84dd50c56ca..6d98a4c78b2 100644
--- a/src/server/game/Entities/Transport/Transport.cpp
+++ b/src/server/game/Entities/Transport/Transport.cpp
@@ -20,14 +20,10 @@
#include "Transport.h"
#include "MapManager.h"
#include "ObjectMgr.h"
-#include "Path.h"
#include "ScriptMgr.h"
-#include "WorldPacket.h"
#include "DBCStores.h"
-#include "World.h"
#include "GameObjectAI.h"
#include "Vehicle.h"
-#include "MapReference.h"
#include "Player.h"
#include "Cell.h"
#include "CellImpl.h"
@@ -36,7 +32,7 @@
Transport::Transport() : GameObject(),
_transportInfo(NULL), _isMoving(true), _pendingStop(false),
_triggeredArrivalEvent(false), _triggeredDepartureEvent(false),
- _passengerTeleportItr(_passengers.begin()), _delayedAddModel(false)
+ _passengerTeleportItr(_passengers.begin()), _delayedAddModel(false), _delayedTeleport(false)
{
m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION;
}
@@ -129,7 +125,7 @@ void Transport::Update(uint32 diff)
if (IsMoving() || !_pendingStop)
m_goValue.Transport.PathProgress += diff;
- uint32 timer = m_goValue.Transport.PathProgress % GetPeriod();
+ uint32 timer = m_goValue.Transport.PathProgress % GetTransportPeriod();
// Set current waypoint
// Desired outcome: _currentFrame->DepartureTime < timer < _nextFrame->ArriveTime
@@ -151,8 +147,8 @@ void Transport::Update(uint32 diff)
if (_pendingStop && GetGoState() != GO_STATE_READY)
{
SetGoState(GO_STATE_READY);
- m_goValue.Transport.PathProgress = (m_goValue.Transport.PathProgress / GetPeriod());
- m_goValue.Transport.PathProgress *= GetPeriod();
+ m_goValue.Transport.PathProgress = (m_goValue.Transport.PathProgress / GetTransportPeriod());
+ m_goValue.Transport.PathProgress *= GetTransportPeriod();
m_goValue.Transport.PathProgress += _currentFrame->ArriveTime;
}
break; // its a stop frame and we are waiting
@@ -177,13 +173,13 @@ void Transport::Update(uint32 diff)
MoveToNextWaypoint();
- sScriptMgr->OnRelocate(this, _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z);
+ sScriptMgr->OnRelocate(this, _currentFrame->Node->NodeIndex, _currentFrame->Node->MapID, _currentFrame->Node->LocX, _currentFrame->Node->LocY, _currentFrame->Node->LocZ);
- TC_LOG_DEBUG("entities.transport", "Transport %u (%s) moved to node %u %u %f %f %f", GetEntry(), GetName().c_str(), _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z);
+ TC_LOG_DEBUG("entities.transport", "Transport %u (%s) moved to node %u %u %f %f %f", GetEntry(), GetName().c_str(), _currentFrame->Node->NodeIndex, _currentFrame->Node->MapID, _currentFrame->Node->LocX, _currentFrame->Node->LocY, _currentFrame->Node->LocZ);
// Departure event
if (_currentFrame->IsTeleportFrame())
- if (TeleportTransport(_nextFrame->Node->mapid, _nextFrame->Node->x, _nextFrame->Node->y, _nextFrame->Node->z, _nextFrame->InitialOrientation))
+ if (TeleportTransport(_nextFrame->Node->MapID, _nextFrame->Node->LocX, _nextFrame->Node->LocY, _nextFrame->Node->LocZ, _nextFrame->InitialOrientation))
return; // Update more in new map thread
}
@@ -230,6 +226,14 @@ void Transport::Update(uint32 diff)
sScriptMgr->OnTransportUpdate(this, diff);
}
+void Transport::DelayedUpdate(uint32 /*diff*/)
+{
+ if (GetKeyFrames().size() <= 1)
+ return;
+
+ DelayedTeleportTransport();
+}
+
void Transport::AddPassenger(WorldObject* passenger)
{
if (!IsInWorld())
@@ -335,6 +339,8 @@ GameObject* Transport::CreateGOPassenger(uint32 guid, GameObjectData const* data
return NULL;
}
+ ASSERT(data);
+
float x = data->posX;
float y = data->posY;
float z = data->posZ;
@@ -593,36 +599,8 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
if (oldMap->GetId() != newMapid)
{
- Map* newMap = sMapMgr->CreateBaseMap(newMapid);
+ _delayedTeleport = true;
UnloadStaticPassengers();
- GetMap()->RemoveFromMap<Transport>(this, false);
- SetMap(newMap);
-
- for (_passengerTeleportItr = _passengers.begin(); _passengerTeleportItr != _passengers.end();)
- {
- WorldObject* obj = (*_passengerTeleportItr++);
-
- float destX, destY, destZ, destO;
- obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO);
- TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, o);
-
- switch (obj->GetTypeId())
- {
- case TYPEID_PLAYER:
- if (!obj->ToPlayer()->TeleportTo(newMapid, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT))
- RemovePassenger(obj);
- break;
- case TYPEID_DYNAMICOBJECT:
- obj->AddObjectToRemoveList();
- break;
- default:
- RemovePassenger(obj);
- break;
- }
- }
-
- Relocate(x, y, z, o);
- GetMap()->AddToMap<Transport>(this);
return true;
}
else
@@ -645,6 +623,48 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
}
}
+void Transport::DelayedTeleportTransport()
+{
+ if (!_delayedTeleport)
+ return;
+
+ _delayedTeleport = false;
+ Map* newMap = sMapMgr->CreateBaseMap(_nextFrame->Node->MapID);
+ GetMap()->RemoveFromMap<Transport>(this, false);
+ SetMap(newMap);
+
+ float x = _nextFrame->Node->LocX,
+ y = _nextFrame->Node->LocY,
+ z = _nextFrame->Node->LocZ,
+ o =_nextFrame->InitialOrientation;
+
+ for (_passengerTeleportItr = _passengers.begin(); _passengerTeleportItr != _passengers.end();)
+ {
+ WorldObject* obj = (*_passengerTeleportItr++);
+
+ float destX, destY, destZ, destO;
+ obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO);
+ TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, o);
+
+ switch (obj->GetTypeId())
+ {
+ case TYPEID_PLAYER:
+ if (!obj->ToPlayer()->TeleportTo(_nextFrame->Node->MapID, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT))
+ RemovePassenger(obj);
+ break;
+ case TYPEID_DYNAMICOBJECT:
+ obj->AddObjectToRemoveList();
+ break;
+ default:
+ RemovePassenger(obj);
+ break;
+ }
+ }
+
+ Relocate(x, y, z, o);
+ GetMap()->AddToMap<Transport>(this);
+}
+
void Transport::UpdatePassengerPositions(PassengerSet& passengers)
{
for (PassengerSet::iterator itr = passengers.begin(); itr != passengers.end(); ++itr)
@@ -699,9 +719,9 @@ void Transport::UpdatePassengerPositions(PassengerSet& passengers)
void Transport::DoEventIfAny(KeyFrame const& node, bool departure)
{
- if (uint32 eventid = departure ? node.Node->departureEventID : node.Node->arrivalEventID)
+ if (uint32 eventid = departure ? node.Node->DepartureEventID : node.Node->ArrivalEventID)
{
- TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of %s path", departure ? "departure" : "arrival", eventid, node.Node->index, GetName().c_str());
+ TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of %s path", departure ? "departure" : "arrival", eventid, node.Node->NodeIndex, GetName().c_str());
GetMap()->ScriptsStart(sEventScripts, eventid, this, this);
EventInform(eventid);
}
diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h
index 4e3d7c3c50e..c56ceb1696d 100644
--- a/src/server/game/Entities/Transport/Transport.h
+++ b/src/server/game/Entities/Transport/Transport.h
@@ -39,6 +39,7 @@ class Transport : public GameObject, public TransportBase
void CleanupsBeforeDelete(bool finalCleanup = true) override;
void Update(uint32 diff) override;
+ void DelayedUpdate(uint32 diff);
void BuildUpdate(UpdateDataMapType& data_map) override;
@@ -79,7 +80,7 @@ class Transport : public GameObject, public TransportBase
TransportBase::CalculatePassengerOffset(x, y, z, o, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
}
- uint32 GetPeriod() const { return GetUInt32Value(GAMEOBJECT_LEVEL); }
+ uint32 GetTransportPeriod() const override { return GetUInt32Value(GAMEOBJECT_LEVEL); }
void SetPeriod(uint32 period) { SetUInt32Value(GAMEOBJECT_LEVEL, period); }
uint32 GetTimer() const { return GetGOValue()->Transport.PathProgress; }
@@ -103,6 +104,7 @@ class Transport : public GameObject, public TransportBase
void MoveToNextWaypoint();
float CalculateSegmentPos(float perc);
bool TeleportTransport(uint32 newMapid, float x, float y, float z, float o);
+ void DelayedTeleportTransport();
void UpdatePassengerPositions(PassengerSet& passengers);
void DoEventIfAny(KeyFrame const& node, bool departure);
@@ -127,6 +129,7 @@ class Transport : public GameObject, public TransportBase
PassengerSet _staticPassengers;
bool _delayedAddModel;
+ bool _delayedTeleport;
};
#endif
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index be383922cb1..9b0da57fa31 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -35,7 +35,6 @@
#include "InstanceSaveMgr.h"
#include "InstanceScript.h"
#include "Log.h"
-#include "MapManager.h"
#include "MoveSpline.h"
#include "MoveSplineInit.h"
#include "ObjectAccessor.h"
@@ -52,6 +51,7 @@
#include "SpellAuras.h"
#include "Spell.h"
#include "SpellInfo.h"
+#include "SpellHistory.h"
#include "SpellMgr.h"
#include "TemporarySummon.h"
#include "Totem.h"
@@ -164,7 +164,7 @@ Unit::Unit(bool isWorldObject) :
i_AI(NULL), i_disabledAI(NULL), m_AutoRepeatFirstCast(false), m_procDeep(0),
m_removedAurasCount(0), i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_ThreatManager(this),
m_vehicle(NULL), m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE),
- m_HostileRefManager(this), _lastDamagedTime(0)
+ m_HostileRefManager(this), _lastDamagedTime(0), m_spellHistory(new SpellHistory(this))
{
m_objectType |= TYPEMASK_UNIT;
m_objectTypeId = TYPEID_UNIT;
@@ -258,24 +258,6 @@ Unit::Unit(bool isWorldObject) :
}
////////////////////////////////////////////////////////////
-// Methods of class GlobalCooldownMgr
-bool GlobalCooldownMgr::HasGlobalCooldown(SpellInfo const* spellInfo) const
-{
- GlobalCooldownList::const_iterator itr = m_GlobalCooldowns.find(spellInfo->StartRecoveryCategory);
- return itr != m_GlobalCooldowns.end() && itr->second.duration && getMSTimeDiff(itr->second.cast_time, getMSTime()) < itr->second.duration;
-}
-
-void GlobalCooldownMgr::AddGlobalCooldown(SpellInfo const* spellInfo, uint32 gcd)
-{
- m_GlobalCooldowns[spellInfo->StartRecoveryCategory] = GlobalCooldown(gcd, getMSTime());
-}
-
-void GlobalCooldownMgr::CancelGlobalCooldown(SpellInfo const* spellInfo)
-{
- m_GlobalCooldowns[spellInfo->StartRecoveryCategory].duration = 0;
-}
-
-////////////////////////////////////////////////////////////
// Methods of class Unit
Unit::~Unit()
{
@@ -292,6 +274,7 @@ Unit::~Unit()
delete i_motionMaster;
delete m_charmInfo;
delete movespline;
+ delete m_spellHistory;
ASSERT(!m_duringRemoveFromWorld);
ASSERT(!m_attacking);
@@ -407,7 +390,7 @@ void Unit::UpdateSplinePosition()
pos.m_positionX = loc.x;
pos.m_positionY = loc.y;
pos.m_positionZ = loc.z;
- pos.m_orientation = loc.orientation;
+ pos.SetOrientation(loc.orientation);
if (TransportBase* transport = GetDirectTransport())
transport->CalculatePassengerPosition(loc.x, loc.y, loc.z, &loc.orientation);
@@ -589,7 +572,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
// interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
if (spellProto)
{
- if (!(spellProto->AttributesEx4 & SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS))
+ if (!spellProto->HasAttribute(SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS))
victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, spellProto->Id);
}
else
@@ -777,7 +760,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
if (damagetype != NODAMAGE && damage)
{
if (victim != this && victim->GetTypeId() == TYPEID_PLAYER && // does not support creature push_back
- (!spellProto || !(spellProto->AttributesEx7 & SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE)))
+ (!spellProto || !spellProto->HasAttribute(SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE)))
{
if (damagetype != DOT)
if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
@@ -981,7 +964,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
uint32 crTypeMask = victim->GetCreatureTypeMask();
// Spells with SPELL_ATTR4_FIXED_DAMAGE ignore resilience because their damage is based off another spell's damage.
- if (!(spellInfo->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE))
+ if (!spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
{
if (IsDamageReducedByArmor(damageSchoolMask, spellInfo))
damage = CalcArmorReducedDamage(victim, damage, spellInfo, attackType);
@@ -1459,7 +1442,7 @@ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* s
if (spellInfo)
{
// there are spells with no specific attribute but they have "ignores armor" in tooltip
- if (spellInfo->AttributesCu & SPELL_ATTR0_CU_IGNORE_ARMOR)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_ARMOR))
return false;
// bleeding effects are not reduced by armor
@@ -1560,7 +1543,7 @@ uint32 Unit::CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, Spell
return 0;
// Ignore spells that can't be resisted
- if (spellInfo && spellInfo->AttributesEx4 & SPELL_ATTR4_IGNORE_RESISTANCES)
+ if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR4_IGNORE_RESISTANCES))
return 0;
uint32 const BOSS_LEVEL = 83;
@@ -2234,15 +2217,15 @@ void Unit::SendMeleeAttackStop(Unit* victim)
TC_LOG_DEBUG("entities.unit", "WORLD: Sent SMSG_ATTACKSTOP");
if (victim)
- TC_LOG_INFO("entities.unit", "%s %u stopped attacking %s %u", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow(), (victim->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), victim->GetGUIDLow());
+ TC_LOG_DEBUG("entities.unit", "%s %u stopped attacking %s %u", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow(), (victim->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), victim->GetGUIDLow());
else
- TC_LOG_INFO("entities.unit", "%s %u stopped attacking", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow());
+ TC_LOG_DEBUG("entities.unit", "%s %u stopped attacking", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow());
}
bool Unit::isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType)
{
// These spells can't be blocked
- if (spellProto && spellProto->Attributes & SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK)
+ if (spellProto && spellProto->HasAttribute(SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK))
return false;
if (victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION) || victim->HasInArc(float(M_PI), this))
@@ -2309,7 +2292,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
{
// Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
// resist and deflect chances
- if (spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
+ if (spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
return SPELL_MISS_NONE;
WeaponAttackType attType = BASE_ATTACK;
@@ -2357,10 +2340,10 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
bool canDodge = true;
bool canParry = true;
- bool canBlock = (spellInfo->AttributesEx3 & SPELL_ATTR3_BLOCKABLE_SPELL) != 0;
+ bool canBlock = spellInfo->HasAttribute(SPELL_ATTR3_BLOCKABLE_SPELL);
// Same spells cannot be parry/dodge
- if (spellInfo->Attributes & SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK))
return SPELL_MISS_NONE;
// Chance resist mechanic
@@ -2400,7 +2383,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
}
else // Only deterrence as of 3.3.5
{
- if (spellInfo->AttributesCu & SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET))
canParry = false;
}
}
@@ -2491,7 +2474,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo)
{
// Can`t miss on dead target (on skinning for example)
- if ((!victim->IsAlive() && victim->GetTypeId() != TYPEID_PLAYER) || spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
+ if ((!victim->IsAlive() && victim->GetTypeId() != TYPEID_PLAYER) || spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
return SPELL_MISS_NONE;
SpellSchoolMask schoolMask = spellInfo->GetSchoolMask();
@@ -2926,6 +2909,8 @@ void Unit::_UpdateSpells(uint32 time)
++itr;
}
}
+
+ m_spellHistory->Update();
}
void Unit::_UpdateAutoRepeatSpell()
@@ -3089,7 +3074,7 @@ bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAu
{
if (!skipInstant || m_currentSpells[CURRENT_GENERIC_SPELL]->GetCastTime())
{
- if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
+ if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS)))
return true;
}
}
@@ -3097,7 +3082,7 @@ bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAu
if (!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
(m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED))
{
- if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
+ if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS)))
return true;
}
// autorepeat spells may be finished or delayed, but they are still considered cast
@@ -3232,7 +3217,7 @@ Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8
castItemGUID = castItem->GetGUID();
// find current aura from spell and change it's stackamount, or refresh it's duration
- if (Aura* foundAura = GetOwnedAura(newAura->Id, casterGUID, (newAura->AttributesCu & SPELL_ATTR0_CU_ENCHANT_PROC) ? castItemGUID : ObjectGuid::Empty, 0))
+ if (Aura* foundAura = GetOwnedAura(newAura->Id, casterGUID, newAura->HasAttribute(SPELL_ATTR0_CU_ENCHANT_PROC) ? castItemGUID : ObjectGuid::Empty, 0))
{
// effect masks do not match
// extremely rare case
@@ -3743,7 +3728,7 @@ void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId
// Call OnDispel hook on AuraScript
aura->CallScriptDispel(&dispelInfo);
- if (aura->GetSpellInfo()->AttributesEx7 & SPELL_ATTR7_DISPEL_CHARGES)
+ if (aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES))
aura->ModCharges(-dispelInfo.GetRemovedCharges(), AURA_REMOVE_BY_ENEMY_SPELL);
else
aura->ModStackAmount(-dispelInfo.GetRemovedCharges(), AURA_REMOVE_BY_ENEMY_SPELL);
@@ -3788,7 +3773,7 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, U
}
}
- bool stealCharge = (aura->GetSpellInfo()->AttributesEx7 & SPELL_ATTR7_DISPEL_CHARGES) != 0;
+ bool stealCharge = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
// Cast duration to unsigned to prevent permanent aura's such as Righteous Fury being permanently added to caster
uint32 dur = std::min(2u * MINUTE * IN_MILLISECONDS, uint32(aura->GetDuration()));
@@ -4046,9 +4031,9 @@ void Unit::RemoveArenaAuras()
{
AuraApplication const* aurApp = iter->second;
Aura const* aura = aurApp->GetBase();
- if (!(aura->GetSpellInfo()->AttributesEx4 & SPELL_ATTR4_UNK21) // don't remove stances, shadowform, pally/hunter auras
+ if (!aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_UNK21) // don't remove stances, shadowform, pally/hunter auras
&& !aura->IsPassive() // don't remove passive auras
- && (aurApp->IsPositive() || !(aura->GetSpellInfo()->AttributesEx3 & SPELL_ATTR3_DEATH_PERSISTENT))) // not negative death persistent auras
+ && (aurApp->IsPositive() || !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR3_DEATH_PERSISTENT))) // not negative death persistent auras
RemoveAura(iter);
else
++iter;
@@ -4308,7 +4293,7 @@ void Unit::GetDispellableAuraList(Unit* caster, uint32 dispelMask, DispelCharges
// The charges / stack amounts don't count towards the total number of auras that can be dispelled.
// Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
// Polymorph instead of 1 / (5 + 1) -> 16%.
- bool dispel_charges = (aura->GetSpellInfo()->AttributesEx7 & SPELL_ATTR7_DISPEL_CHARGES) != 0;
+ bool dispel_charges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount();
if (charges > 0)
dispelList.push_back(std::make_pair(aura, charges));
@@ -4861,13 +4846,13 @@ void Unit::AddGameObject(GameObject* gameObj)
m_gameObj.push_back(gameObj);
gameObj->SetOwnerGUID(GetGUID());
- if (GetTypeId() == TYPEID_PLAYER && gameObj->GetSpellId())
+ if (gameObj->GetSpellId())
{
SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(gameObj->GetSpellId());
// Need disable spell use for owner
if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
// note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
- ToPlayer()->AddSpellAndCategoryCooldowns(createBySpell, 0, NULL, true);
+ GetSpellHistory()->StartCooldown(createBySpell, 0, nullptr, true);
}
}
@@ -4892,14 +4877,11 @@ void Unit::RemoveGameObject(GameObject* gameObj, bool del)
{
RemoveAurasDueToSpell(spellid);
- if (GetTypeId() == TYPEID_PLAYER)
- {
- SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid);
- // Need activate spell use for owner
- if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
- // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
- ToPlayer()->SendCooldownEvent(createBySpell);
- }
+ SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid);
+ // Need activate spell use for owner
+ if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
+ // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
+ GetSpellHistory()->SendCooldownEvent(createBySpell);
}
m_gameObj.remove(gameObj);
@@ -5485,12 +5467,12 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
if (RandomSpells.empty()) // shouldn't happen
return false;
- uint8 rand_spell = irand(0, (RandomSpells.size() - 1));
+ uint8 rand_spell = urand(0, (RandomSpells.size() - 1));
CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster);
for (std::vector<uint32>::iterator itr = RandomSpells.begin(); itr != RandomSpells.end(); ++itr)
{
- if (!ToPlayer()->HasSpellCooldown(*itr))
- ToPlayer()->AddSpellCooldown(*itr, 0, time(NULL) + cooldown);
+ if (!GetSpellHistory()->HasCooldown(*itr))
+ GetSpellHistory()->AddCooldown(*itr, 0, std::chrono::seconds(cooldown));
}
break;
}
@@ -5531,12 +5513,12 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
if (RandomSpells.empty()) // shouldn't happen
return false;
- uint8 rand_spell = irand(0, (RandomSpells.size() - 1));
+ uint8 rand_spell = urand(0, (RandomSpells.size() - 1));
CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster);
for (std::vector<uint32>::iterator itr = RandomSpells.begin(); itr != RandomSpells.end(); ++itr)
{
- if (!ToPlayer()->HasSpellCooldown(*itr))
- ToPlayer()->AddSpellCooldown(*itr, 0, time(NULL) + cooldown);
+ if (!GetSpellHistory()->HasCooldown(*itr))
+ GetSpellHistory()->AddCooldown(*itr, 0, std::chrono::seconds(cooldown));
}
break;
}
@@ -5640,20 +5622,17 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
// Glyph of Ice Block
case 56372:
{
- Player* player = ToPlayer();
- if (!player)
+ if (GetTypeId() != TYPEID_PLAYER)
return false;
- SpellCooldowns const cooldowns = player->GetSpellCooldowns();
- // remove cooldowns on all ranks of Frost Nova
- for (SpellCooldowns::const_iterator itr = cooldowns.begin(); itr != cooldowns.end(); ++itr)
+ GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
{
SpellInfo const* cdSpell = sSpellMgr->GetSpellInfo(itr->first);
- // Frost Nova
- if (cdSpell && cdSpell->SpellFamilyName == SPELLFAMILY_MAGE
- && cdSpell->SpellFamilyFlags[0] & 0x00000040)
- player->RemoveSpellCooldown(cdSpell->Id, true);
- }
+ if (!cdSpell || cdSpell->SpellFamilyName != SPELLFAMILY_MAGE
+ || !(cdSpell->SpellFamilyFlags[0] & 0x00000040))
+ return false;
+ return true;
+ }, true);
break;
}
case 47020: // Enter vehicle XT-002 (Scrapbot)
@@ -5881,7 +5860,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
if (dummySpell->SpellIconID == 2218)
{
// Proc only from Abolish desease on self cast
- if (procSpell->Id != 552 || victim != this || !roll_chance_i(triggerAmount))
+ if (!procSpell || procSpell->Id != 552 || victim != this || !roll_chance_i(triggerAmount))
return false;
triggered_spell_id = 64136;
target = this;
@@ -5931,7 +5910,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
case 55677:
{
// Dispel Magic shares spellfamilyflag with abolish disease
- if (procSpell->SpellIconID != 74)
+ if (!procSpell || procSpell->SpellIconID != 74)
return false;
if (!target || !target->IsFriendlyTo(this))
return false;
@@ -6062,7 +6041,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
int32 basepoints1 = CalculatePct(GetMaxPower(Powers(POWER_MANA)), triggerAmount * 2);
// Improved Leader of the Pack
// Check cooldown of heal spell cooldown
- if (GetTypeId() == TYPEID_PLAYER && !ToPlayer()->HasSpellCooldown(34299))
+ if (!GetSpellHistory()->HasCooldown(34299))
CastCustomSpell(this, 68285, &basepoints1, 0, 0, true, 0, triggeredByAura);
break;
}
@@ -6733,7 +6712,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
return false;
// custom cooldown processing case
- if (cooldown && player->HasSpellCooldown(dummySpell->Id))
+ if (cooldown && GetSpellHistory()->HasCooldown(dummySpell->Id))
return false;
if (triggeredByAura->GetBase() && castItem->GetGUID() != triggeredByAura->GetBase()->GetCastItemGUID())
@@ -6799,7 +6778,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
// apply cooldown before cast to prevent processing itself
if (cooldown)
- player->AddSpellCooldown(dummySpell->Id, 0, time(NULL) + cooldown);
+ player->GetSpellHistory()->AddCooldown(dummySpell->Id, 0, std::chrono::seconds(cooldown));
// Attack Twice
for (uint32 i = 0; i < 2; ++i)
@@ -7041,7 +7020,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
return false;
// custom cooldown processing case
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(dummySpell->Id))
+ if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(dummySpell->Id))
return false;
uint32 spellId = 0;
@@ -7088,13 +7067,13 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
return false;
// Remove cooldown (Chain Lightning - has Category Recovery time)
- ToPlayer()->RemoveSpellCooldown(spellId);
+ GetSpellHistory()->ResetCooldown(spellId);
}
CastSpell(victim, spellId, true, castItem, triggeredByAura);
if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(dummySpell->Id, 0, time(NULL) + cooldown);
+ GetSpellHistory()->AddCooldown(dummySpell->Id, 0, std::chrono::seconds(cooldown));
return true;
}
@@ -7107,8 +7086,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
uint32 spell = sSpellMgr->GetSpellWithRank(26364, aurEff->GetSpellInfo()->GetRank());
// custom cooldown processing case
- if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(spell))
- ToPlayer()->RemoveSpellCooldown(spell);
+ if (GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(spell))
+ GetSpellHistory()->ResetCooldown(spell);
CastSpell(target, spell, true, castItem, triggeredByAura);
aurEff->GetBase()->DropCharge();
@@ -7400,7 +7379,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
if (cooldown_spell_id == 0)
cooldown_spell_id = triggered_spell_id;
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(cooldown_spell_id))
+ if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(cooldown_spell_id))
return false;
if (basepoints0)
@@ -7409,7 +7388,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura, originalCaster);
if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(cooldown_spell_id, 0, time(NULL) + cooldown);
+ GetSpellHistory()->AddCooldown(cooldown_spell_id, 0, std::chrono::seconds(cooldown));
return true;
}
@@ -7630,9 +7609,9 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp
*handled = true;
if (cooldown && GetTypeId() == TYPEID_PLAYER)
{
- if (ToPlayer()->HasSpellCooldown(100000))
+ if (GetSpellHistory()->HasCooldown(100000))
return false;
- ToPlayer()->AddSpellCooldown(100000, 0, time(NULL) + cooldown);
+ GetSpellHistory()->AddCooldown(100000, 0, std::chrono::seconds(cooldown));
}
return true;
}
@@ -8301,7 +8280,11 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
return false;
// Howling Blast
- ToPlayer()->RemoveSpellCategoryCooldown(1248, true);
+ GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
+ {
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
+ return spellInfo && spellInfo->GetCategory() == 1248;
+ }, true);
}
// Custom basepoints/target for exist spell
@@ -8320,13 +8303,13 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
if (!target)
return false;
- if (cooldown && target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->HasSpellCooldown(trigger_spell_id))
+ if (cooldown && target->GetTypeId() == TYPEID_PLAYER && target->GetSpellHistory()->HasCooldown(trigger_spell_id))
return false;
target->CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura);
if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown);
+ GetSpellHistory()->AddCooldown(trigger_spell_id, 0, std::chrono::seconds(cooldown));
return true;
}
// Cast positive spell on enemy target
@@ -8409,8 +8392,11 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
case 50227:
{
// Remove cooldown on Shield Slam
- if (GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->RemoveSpellCategoryCooldown(1209, true);
+ GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
+ {
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
+ return spellInfo && spellInfo->GetCategory() == 1209;
+ }, true);
break;
}
// Maelstrom Weapon
@@ -8470,8 +8456,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
case 58628:
{
// remove cooldown of Death Grip
- if (GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->RemoveSpellCooldown(49576, true);
+ GetSpellHistory()->ResetCooldown(49576, true);
return true;
}
// Savage Defense
@@ -8502,7 +8487,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
}
}
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(trigger_spell_id))
+ if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(trigger_spell_id))
return false;
// extra attack should hit same target
@@ -8519,7 +8504,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura);
if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown);
+ GetSpellHistory()->AddCooldown(trigger_spell_id, 0, std::chrono::seconds(cooldown));
return true;
}
@@ -8615,13 +8600,13 @@ bool Unit::HandleOverrideClassScriptAuraProc(Unit* victim, uint32 /*damage*/, Au
return false;
}
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
+ if (cooldown && GetTypeId() == TYPEID_PLAYER && GetSpellHistory()->HasCooldown(triggered_spell_id))
return false;
CastSpell(victim, triggered_spell_id, true, castItem, triggeredByAura);
if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
+ GetSpellHistory()->AddCooldown(triggered_spell_id, 0, std::chrono::seconds(cooldown));
return true;
}
@@ -9356,14 +9341,11 @@ void Unit::SetMinion(Minion *minion, bool apply)
if (minion->IsPetGhoul())
minion->setPowerType(POWER_ENERGY);
- if (GetTypeId() == TYPEID_PLAYER)
- {
- // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
+ // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
- if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
- ToPlayer()->AddSpellAndCategoryCooldowns(spellInfo, 0, NULL, true);
- }
+ if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
+ GetSpellHistory()->StartCooldown(spellInfo, 0, nullptr, true);
}
else
{
@@ -9397,13 +9379,10 @@ void Unit::SetMinion(Minion *minion, bool apply)
}
}
- if (GetTypeId() == TYPEID_PLAYER)
- {
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
- // Remove infinity cooldown
- if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
- ToPlayer()->SendCooldownEvent(spellInfo);
- }
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
+ // Remove infinity cooldown
+ if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
+ GetSpellHistory()->SendCooldownEvent(spellInfo);
//if (minion->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
{
@@ -9602,7 +9581,7 @@ bool Unit::IsMagnet() const
Unit* Unit::GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo)
{
// Patch 1.2 notes: Spell Reflection no longer reflects abilities
- if (spellInfo->Attributes & SPELL_ATTR0_ABILITY || spellInfo->AttributesEx & SPELL_ATTR1_CANT_BE_REDIRECTED || spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR1_CANT_BE_REDIRECTED) || spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return victim;
Unit::AuraEffectList const& magnetAuras = victim->GetAuraEffectsByType(SPELL_AURA_SPELL_MAGNET);
@@ -9854,7 +9833,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
return pdamage;
// Some spells don't benefit from done mods
- if (spellProto->AttributesEx3 & SPELL_ATTR3_NO_DONE_BONUS)
+ if (spellProto->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS))
return pdamage;
// For totems get damage bonus from owner
@@ -9970,11 +9949,15 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod);
}
- // Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods.
- float tmpDamage = (int32(pdamage) + DoneTotal) * (damagetype == DOT ? 1.0f : SpellDamagePctDone(victim, spellProto, damagetype));
- // apply spellmod to Done damage (flat and pct)
- if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage);
+ float tmpDamage = float(int32(pdamage) + DoneTotal);
+ // SPELLMOD_DOT will be applied in AuraEffect::HandlePeriodicDamageAurasTick.
+ if (damagetype != DOT)
+ {
+ tmpDamage *= SpellDamagePctDone(victim, spellProto, damagetype);
+ // apply spellmod to Done damage (flat and pct)
+ if (Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage);
+ }
return uint32(std::max(tmpDamage, 0.0f));
}
@@ -9985,7 +9968,7 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage
return 1.0f;
// Some spells don't benefit from pct done mods
- if (spellProto->AttributesEx6 & SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS)
+ if (spellProto->HasAttribute(SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS))
return 1.0f;
// For totems pct done mods are calculated when its calculation is run on the player in SpellDamageBonusDone.
@@ -10009,7 +9992,7 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage
{
if ((*i)->GetSpellInfo()->EquippedItemClass == -1)
AddPct(DoneTotalMod, (*i)->GetAmount());
- else if (!((*i)->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0))
+ else if (!(*i)->GetSpellInfo()->HasAttribute(SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0))
AddPct(DoneTotalMod, (*i)->GetAmount());
else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellInfo()))
AddPct(DoneTotalMod, (*i)->GetAmount());
@@ -10324,7 +10307,7 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui
}
}
// Spells with SPELL_ATTR4_FIXED_DAMAGE should only benefit from mechanic damage mod auras.
- if (!(spellProto->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE))
+ if (!spellProto->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
{
// get all auras from caster that allow the spell to ignore resistance (sanctified wrath)
AuraEffectList const& IgnoreResistAuras = caster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
@@ -10454,7 +10437,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
return 0.0f;
// not critting spell
- if ((spellProto->AttributesEx2 & SPELL_ATTR2_CANT_CRIT))
+ if (spellProto->HasAttribute(SPELL_ATTR2_CANT_CRIT))
return 0.0f;
float crit_chance = 0.0f;
@@ -10814,11 +10797,15 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
DoneTotal = 0;
}
- // Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods.
- float heal = float(int32(healamount) + DoneTotal) * (damagetype == DOT ? 1.0f : SpellHealingPctDone(victim, spellProto));
- // apply spellmod to Done amount
- if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal);
+ float heal = float(int32(healamount) + DoneTotal);
+ // SPELLMOD_DOT will be applied in AuraEffect::HandlePeriodicHealAurasTick.
+ if (damagetype != DOT)
+ {
+ heal *= SpellHealingPctDone(victim, spellProto);
+ // apply spellmod to Done amount
+ if (Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, heal);
+ }
return uint32(std::max(heal, 0.0f));
}
@@ -11063,7 +11050,7 @@ bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask) const
bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
{
- if (spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return false;
uint32 shoolMask = spellInfo->GetSchoolMask();
@@ -11096,7 +11083,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const
if (itr->type == spellInfo->Id)
return true;
- if (spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return false;
if (spellInfo->Dispel)
@@ -11154,7 +11141,7 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
if (!spellInfo || !spellInfo->Effects[index].IsEffect())
return false;
- if (spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return false;
// If m_immuneToEffect type contain this effect type, IMMUNE effect.
@@ -11177,7 +11164,7 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
SpellImmuneList const& list = m_spellImmune[IMMUNITY_STATE];
for (SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
if (itr->type == aura)
- if (!(spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT))
+ if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
return true;
// Check for immune to application of harmful magical effects
@@ -11252,7 +11239,7 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType
// Some spells don't benefit from pct done mods
if (spellProto)
- if (!(spellProto->AttributesEx6 & SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS))
+ if (!spellProto->HasAttribute(SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS))
{
AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
@@ -11261,7 +11248,7 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType
{
if ((*i)->GetSpellInfo()->EquippedItemClass == -1)
AddPct(DoneTotalMod, (*i)->GetAmount());
- else if (!((*i)->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0))
+ else if (!(*i)->GetSpellInfo()->HasAttribute(SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0))
AddPct(DoneTotalMod, (*i)->GetAmount());
else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellInfo()))
AddPct(DoneTotalMod, (*i)->GetAmount());
@@ -11523,7 +11510,7 @@ void Unit::ApplySpellDispelImmunity(const SpellInfo* spellProto, DispelType type
{
ApplySpellImmune(spellProto->Id, IMMUNITY_DISPEL, type, apply);
- if (apply && spellProto->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
+ if (apply && spellProto->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
{
// Create dispel mask by dispel type
uint32 dispelMask = SpellInfo::GetDispelMask(type);
@@ -11808,7 +11795,7 @@ void Unit::ClearInCombat()
if (HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TAPPED))
SetUInt32Value(UNIT_DYNAMIC_FLAGS, creature->GetCreatureTemplate()->dynamicflags);
- if (creature->IsPet())
+ if (creature->IsPet() || creature->IsGuardian())
{
if (Unit* owner = GetOwner())
for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
@@ -11864,7 +11851,7 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
return false;
// can't attack invisible (ignore stealth for aoe spells) also if the area being looked at is from a spell use the dynamic object created instead of the casting unit.
- if ((!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && (obj ? !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()) : !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea())))
+ if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && (obj ? !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()) : !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea())))
return false;
// can't attack dead
@@ -11872,7 +11859,7 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
return false;
// can't attack untargetable
- if ((!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_CAN_TARGET_UNTARGETABLE))
+ if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE))
&& target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
return false;
@@ -11981,7 +11968,7 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co
return false;
// can't assist invisible
- if ((!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()))
+ if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()))
return false;
// can't assist dead
@@ -11989,11 +11976,11 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co
return false;
// can't assist untargetable
- if ((!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_CAN_TARGET_UNTARGETABLE))
+ if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE))
&& target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
return false;
- if (!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
+ if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
{
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE))
{
@@ -12040,7 +12027,7 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co
// PvC case - player can assist creature only if has specific type flags
// !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) &&
else if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE)
- && (!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
+ && (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG))
&& !((target->GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_PVP)))
{
if (Creature const* creatureTarget = target->ToCreature())
@@ -12829,7 +12816,7 @@ int32 Unit::ModSpellDuration(SpellInfo const* spellProto, Unit const* target, in
return duration;
// some auras are not affected by duration modifiers
- if (spellProto->AttributesEx7 & SPELL_ATTR7_IGNORE_DURATION_MODS)
+ if (spellProto->HasAttribute(SPELL_ATTR7_IGNORE_DURATION_MODS))
return duration;
// cut duration only of negative effects
@@ -12933,17 +12920,17 @@ void Unit::ModSpellCastTime(SpellInfo const* spellInfo, int32 & castTime, Spell*
if (!spellInfo || castTime < 0)
return;
- if (spellInfo->IsChanneled() && !(spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION))
+ if (spellInfo->IsChanneled() && !spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION))
return;
// called from caster
if (Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell);
- if (!((spellInfo->Attributes & (SPELL_ATTR0_ABILITY | SPELL_ATTR0_TRADESPELL)) || (spellInfo->AttributesEx3 & SPELL_ATTR3_NO_DONE_BONUS)) &&
+ if (!(spellInfo->HasAttribute(SPELL_ATTR0_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR0_TRADESPELL) || spellInfo->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS)) &&
((GetTypeId() == TYPEID_PLAYER && spellInfo->SpellFamilyName) || GetTypeId() == TYPEID_UNIT))
castTime = int32(float(castTime) * GetFloatValue(UNIT_MOD_CAST_SPEED));
- else if (spellInfo->Attributes & SPELL_ATTR0_REQ_AMMO && !(spellInfo->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG))
+ else if (spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) && !spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG))
castTime = int32(float(castTime) * m_modAttackSpeedPct[RANGED_ATTACK]);
else if (spellInfo->SpellVisual[0] == 3881 && HasAura(67556)) // cooking with Chef Hat.
castTime = 500;
@@ -13718,7 +13705,7 @@ void CharmInfo::InitPossessCreateSpells()
{
uint32 spellId = _unit->ToCreature()->m_spells[i];
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
- if (spellInfo && !(spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD))
+ if (spellInfo && !spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD))
{
if (spellInfo->IsPassive())
_unit->CastSpell(_unit, spellInfo, true);
@@ -13746,7 +13733,7 @@ void CharmInfo::InitCharmCreateSpells()
uint32 spellId = _unit->ToCreature()->m_spells[x];
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
- if (!spellInfo || spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD)
+ if (!spellInfo || spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD))
{
_charmspells[x].SetActionAndType(spellId, ACT_DISABLED);
continue;
@@ -14133,7 +14120,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
continue;
// Triggered spells not triggering additional spells
- bool triggered = !(spellProto->AttributesEx3 & SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED) ?
+ bool triggered = !spellProto->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED) ?
(procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_DONE_TRAP_ACTIVATION)) : false;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
@@ -14190,7 +14177,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
cooldown = i->spellProcEvent->cooldown;
// Note: must SetCantProc(false) before return
- if (spellInfo->AttributesEx3 & SPELL_ATTR3_DISABLE_PROC)
+ if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
SetCantProc(true);
bool handled = i->aura->CallScriptProcHandlers(aurApp, eventInfo);
@@ -14385,7 +14372,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
i->aura->CallScriptAfterProcHandlers(aurApp, eventInfo);
- if (spellInfo->AttributesEx3 & SPELL_ATTR3_DISABLE_PROC)
+ if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
SetCantProc(false);
}
@@ -15060,7 +15047,7 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, SpellInfo const
// Additional checks for triggered spells (ignore trap casts)
if (procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_DONE_TRAP_ACTIVATION))
{
- if (!(spellProto->AttributesEx3 & SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED))
+ if (!spellProto->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED))
return false;
}
@@ -15540,18 +15527,11 @@ void Unit::SetControlled(bool apply, UnitState state)
{
case UNIT_STATE_STUNNED:
SetStunned(true);
- // i need to stop fear on stun and root or i will get teleport to destination issue as MVMGEN for fear keeps going on
- if (HasUnitState(UNIT_STATE_FLEEING))
- SetFeared(false);
CastStop();
break;
case UNIT_STATE_ROOT:
if (!HasUnitState(UNIT_STATE_STUNNED))
- {
SetRooted(true);
- if (HasUnitState(UNIT_STATE_FLEEING))
- SetFeared(false);
- }
break;
case UNIT_STATE_CONFUSED:
if (!HasUnitState(UNIT_STATE_STUNNED))
@@ -15639,11 +15619,9 @@ void Unit::SetStunned(bool apply)
// setting MOVEMENTFLAG_ROOT
RemoveUnitMovementFlag(MOVEMENTFLAG_MASK_MOVING);
AddUnitMovementFlag(MOVEMENTFLAG_ROOT);
+ StopMoving();
- // Creature specific
- if (GetTypeId() != TYPEID_PLAYER)
- StopMoving();
- else
+ if (GetTypeId() == TYPEID_PLAYER)
SetStandState(UNIT_STAND_STATE_STAND);
WorldPacket data(SMSG_FORCE_MOVE_ROOT, 8);
@@ -15687,6 +15665,7 @@ void Unit::SetRooted(bool apply)
// setting MOVEMENTFLAG_ROOT
RemoveUnitMovementFlag(MOVEMENTFLAG_MASK_MOVING);
AddUnitMovementFlag(MOVEMENTFLAG_ROOT);
+ StopMoving();
if (GetTypeId() == TYPEID_PLAYER)
{
@@ -15700,7 +15679,6 @@ void Unit::SetRooted(bool apply)
WorldPacket data(SMSG_SPLINE_MOVE_ROOT, 8);
data << GetPackGUID();
SendMessageToSet(&data, true);
- StopMoving();
}
}
else
@@ -16220,7 +16198,7 @@ Aura* Unit::AddAura(uint32 spellId, Unit* target)
if (!spellInfo)
return NULL;
- if (!target->IsAlive() && !(spellInfo->Attributes & SPELL_ATTR0_PASSIVE) && !(spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD))
+ if (!target->IsAlive() && !spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE) && !spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_DEAD))
return NULL;
return AddAura(spellInfo, MAX_EFFECT_MASK, target);
@@ -16477,7 +16455,7 @@ void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ)
float vcos, vsin;
GetSinCos(x, y, vsin, vcos);
- WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
+ WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8 + 4 + 4 + 4 + 4 + 4));
data << GetPackGUID();
data << uint32(0); // counter
data << float(vcos); // x direction
@@ -16486,6 +16464,9 @@ void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ)
data << float(-speedZ); // Z Movement speed (vertical)
player->GetSession()->SendPacket(&data);
+
+ if (player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || player->HasAuraType(SPELL_AURA_FLY))
+ player->SetCanFly(true, true);
}
}
@@ -17323,30 +17304,30 @@ void Unit::StopAttackFaction(uint32 faction_id)
void Unit::OutDebugInfo() const
{
TC_LOG_ERROR("entities.unit", "Unit::OutDebugInfo");
- TC_LOG_INFO("entities.unit", "%s name %s", GetGUID().ToString().c_str(), GetName().c_str());
- TC_LOG_INFO("entities.unit", "Owner %s, Minion %s, Charmer %s, Charmed %s", GetOwnerGUID().ToString().c_str(), GetMinionGUID().ToString().c_str(), GetCharmerGUID().ToString().c_str(), GetCharmGUID().ToString().c_str());
- TC_LOG_INFO("entities.unit", "In world %u, unit type mask %u", (uint32)(IsInWorld() ? 1 : 0), m_unitTypeMask);
+ TC_LOG_DEBUG("entities.unit", "%s name %s", GetGUID().ToString().c_str(), GetName().c_str());
+ TC_LOG_DEBUG("entities.unit", "Owner %s, Minion %s, Charmer %s, Charmed %s", GetOwnerGUID().ToString().c_str(), GetMinionGUID().ToString().c_str(), GetCharmerGUID().ToString().c_str(), GetCharmGUID().ToString().c_str());
+ TC_LOG_DEBUG("entities.unit", "In world %u, unit type mask %u", (uint32)(IsInWorld() ? 1 : 0), m_unitTypeMask);
if (IsInWorld())
- TC_LOG_INFO("entities.unit", "Mapid %u", GetMapId());
+ TC_LOG_DEBUG("entities.unit", "Mapid %u", GetMapId());
std::ostringstream o;
o << "Summon Slot: ";
for (uint32 i = 0; i < MAX_SUMMON_SLOT; ++i)
o << m_SummonSlot[i].ToString() << ", ";
- TC_LOG_INFO("entities.unit", "%s", o.str().c_str());
+ TC_LOG_DEBUG("entities.unit", "%s", o.str().c_str());
o.str("");
o << "Controlled List: ";
for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
o << (*itr)->GetGUID().ToString() << ", ";
- TC_LOG_INFO("entities.unit", "%s", o.str().c_str());
+ TC_LOG_DEBUG("entities.unit", "%s", o.str().c_str());
o.str("");
o << "Aura List: ";
for (AuraApplicationMap::const_iterator itr = m_appliedAuras.begin(); itr != m_appliedAuras.end(); ++itr)
o << itr->first << ", ";
- TC_LOG_INFO("entities.unit", "%s", o.str().c_str());
+ TC_LOG_DEBUG("entities.unit", "%s", o.str().c_str());
o.str("");
if (IsVehicle())
@@ -17355,11 +17336,11 @@ void Unit::OutDebugInfo() const
for (SeatMap::iterator itr = GetVehicleKit()->Seats.begin(); itr != GetVehicleKit()->Seats.end(); ++itr)
if (Unit* passenger = ObjectAccessor::GetUnit(*GetVehicleBase(), itr->second.Passenger.Guid))
o << passenger->GetGUID().ToString() << ", ";
- TC_LOG_INFO("entities.unit", "%s", o.str().c_str());
+ TC_LOG_DEBUG("entities.unit", "%s", o.str().c_str());
}
if (GetVehicle())
- TC_LOG_INFO("entities.unit", "On vehicle %u.", GetVehicleBase()->GetEntry());
+ TC_LOG_DEBUG("entities.unit", "On vehicle %u.", GetVehicleBase()->GetEntry());
}
uint32 Unit::GetRemainingPeriodicAmount(ObjectGuid caster, uint32 spellId, AuraType auraType, uint8 effectIndex) const
@@ -17544,7 +17525,7 @@ bool Unit::SetSwim(bool enable)
return true;
}
-bool Unit::SetCanFly(bool enable)
+bool Unit::SetCanFly(bool enable, bool /*packetOnly = false */)
{
if (enable == HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY))
return false;
@@ -17795,27 +17776,6 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target)
data->append(fieldBuffer);
}
-void Unit::BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown)
-{
- data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + 4 + 4);
- data << uint64(GetGUID());
- data << uint8(flags);
- data << uint32(spellId);
- data << uint32(cooldown);
-}
-
-void Unit::BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns)
-{
- data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + (4 + 4) * cooldowns.size());
- data << uint64(GetGUID());
- data << uint8(flags);
- for (std::unordered_map<uint32, uint32>::const_iterator itr = cooldowns.begin(); itr != cooldowns.end(); ++itr)
- {
- data << uint32(itr->first);
- data << uint32(itr->second);
- }
-}
-
int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const
{
int32 val = 0;
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index ddf43f30971..2593ca2c728 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -273,13 +273,6 @@ enum UnitRename
#define MAX_AGGRO_RESET_TIME 10 // in seconds
#define MAX_AGGRO_RADIUS 45.0f // yards
-enum Swing
-{
- NOSWING = 0,
- SINGLEHANDEDSWING = 1,
- TWOHANDEDSWING = 2
-};
-
enum VictimState
{
VICTIMSTATE_INTACT = 0, // set when attacker misses
@@ -339,6 +332,7 @@ class AuraEffect;
class Creature;
class Spell;
class SpellInfo;
+class SpellHistory;
class DynamicObject;
class GameObject;
class Item;
@@ -355,7 +349,7 @@ class TransportBase;
class SpellCastTargets;
typedef std::list<Unit*> UnitList;
-typedef std::list< std::pair<Aura*, uint8> > DispelChargesList;
+typedef std::list<std::pair<Aura*, uint8>> DispelChargesList;
struct SpellImmune
{
@@ -380,13 +374,6 @@ enum WeaponDamageRange
MAXDAMAGE
};
-enum DamageTypeToSchool
-{
- RESISTANCE,
- DAMAGE_DEALT,
- DAMAGE_TAKEN
-};
-
enum AuraRemoveMode
{
AURA_REMOVE_NONE = 0,
@@ -1031,30 +1018,6 @@ enum CurrentSpellTypes
#define CURRENT_FIRST_NON_MELEE_SPELL 1
#define CURRENT_MAX_SPELL 4
-struct GlobalCooldown
-{
- explicit GlobalCooldown(uint32 _dur = 0, uint32 _time = 0) : duration(_dur), cast_time(_time) { }
-
- uint32 duration;
- uint32 cast_time;
-};
-
-typedef std::unordered_map<uint32 /*category*/, GlobalCooldown> GlobalCooldownList;
-
-class GlobalCooldownMgr // Shared by Player and CharmInfo
-{
-public:
- GlobalCooldownMgr() { }
-
-public:
- bool HasGlobalCooldown(SpellInfo const* spellInfo) const;
- void AddGlobalCooldown(SpellInfo const* spellInfo, uint32 gcd);
- void CancelGlobalCooldown(SpellInfo const* spellInfo);
-
-private:
- GlobalCooldownList m_GlobalCooldowns;
-};
-
enum ActiveStates
{
ACT_PASSIVE = 0x01, // 0x01 - passive
@@ -1171,8 +1134,6 @@ struct CharmInfo
CharmSpellInfo* GetCharmSpell(uint8 index) { return &(_charmspells[index]); }
- GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; }
-
void SetIsCommandAttack(bool val);
bool IsCommandAttack();
void SetIsCommandFollow(bool val);
@@ -1205,8 +1166,6 @@ struct CharmInfo
float _stayX;
float _stayY;
float _stayZ;
-
- GlobalCooldownMgr m_GlobalCooldownMgr;
};
// for clearing special attacks
@@ -1237,16 +1196,6 @@ enum PlayerTotemType
SUMMON_TYPE_TOTEM_AIR = 83
};
-/// Spell cooldown flags sent in SMSG_SPELL_COOLDOWN
-enum SpellCooldownFlags
-{
- SPELL_COOLDOWN_FLAG_NONE = 0x0,
- SPELL_COOLDOWN_FLAG_INCLUDE_GCD = 0x1, ///< Starts GCD in addition to normal cooldown specified in the packet
- SPELL_COOLDOWN_FLAG_INCLUDE_EVENT_COOLDOWNS = 0x2 ///< Starts GCD for spells that should start their cooldown on events, requires SPELL_COOLDOWN_FLAG_INCLUDE_GCD set
-};
-
-typedef std::unordered_map<uint32, uint32> PacketCooldowns;
-
// delay time next attack to prevent client attack animation problems
#define ATTACK_DISPLAY_DELAY 200
#define MAX_PLAYER_STEALTH_DETECT_RANGE 30.0f // max distance for detection targets by player
@@ -1585,8 +1534,6 @@ class Unit : public WorldObject
void SetAuraStack(uint32 spellId, Unit* target, uint32 stack);
void SendPlaySpellVisual(uint32 id);
void SendPlaySpellImpact(ObjectGuid guid, uint32 id);
- void BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown);
- void BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns);
void DeMorph();
@@ -1622,7 +1569,7 @@ class Unit : public WorldObject
virtual bool SetWalk(bool enable);
virtual bool SetDisableGravity(bool disable, bool packetOnly = false);
virtual bool SetSwim(bool enable);
- virtual bool SetCanFly(bool enable);
+ virtual bool SetCanFly(bool enable, bool packetOnly = false);
virtual bool SetWaterWalking(bool enable, bool packetOnly = false);
virtual bool SetFeatherFall(bool enable, bool packetOnly = false);
virtual bool SetHover(bool enable, bool packetOnly = false);
@@ -1845,7 +1792,6 @@ class Unit : public WorldObject
void SetChannelObjectGuid(ObjectGuid guid) { SetGuidValue(UNIT_FIELD_CHANNEL_OBJECT, guid); }
void SetCurrentCastSpell(Spell* pSpell);
- virtual void ProhibitSpellSchool(SpellSchoolMask /*idSchoolMask*/, uint32 /*unTimeMs*/) { }
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed = true, bool withInstant = true);
void FinishSpell(CurrentSpellTypes spellType, bool ok = true);
@@ -1863,6 +1809,9 @@ class Unit : public WorldObject
Spell* FindCurrentSpellBySpellId(uint32 spell_id) const;
int32 GetCurrentSpellCastTime(uint32 spell_id) const;
+ SpellHistory* GetSpellHistory() { return m_spellHistory; }
+ SpellHistory const* GetSpellHistory() const { return m_spellHistory; }
+
ObjectGuid m_SummonSlot[MAX_SUMMON_SLOT];
ObjectGuid m_ObjectSlot[MAX_GAMEOBJECT_SLOT];
@@ -1933,7 +1882,7 @@ class Unit : public WorldObject
void TauntApply(Unit* victim);
void TauntFadeOut(Unit* taunter);
ThreatManager& getThreatManager() { return m_ThreatManager; }
- void addHatedBy(HostileReference* pHostileReference) { m_HostileRefManager.insertFirst(pHostileReference); };
+ void addHatedBy(HostileReference* pHostileReference) { m_HostileRefManager.insertFirst(pHostileReference); }
void removeHatedBy(HostileReference* /*pHostileReference*/) { /* nothing to do yet */ }
HostileRefManager& getHostileRefManager() { return m_HostileRefManager; }
@@ -2293,6 +2242,8 @@ class Unit : public WorldObject
bool _isWalkingBeforeCharm; ///< Are we walking before we were charmed?
time_t _lastDamagedTime; // Part of Evade mechanics
+
+ SpellHistory* m_spellHistory;
};
namespace Trinity
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index 9887f303357..b6f9534ac51 100755
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -22,12 +22,8 @@
#include "Vehicle.h"
#include "Unit.h"
#include "Util.h"
-#include "WorldPacket.h"
#include "ScriptMgr.h"
#include "CreatureAI.h"
-#include "ZoneScript.h"
-#include "SpellMgr.h"
-#include "SpellInfo.h"
#include "MoveSplineInit.h"
#include "TemporarySummon.h"
#include "EventProcessor.h"
diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp
index ba82c61e7ff..2264612f89b 100644
--- a/src/server/game/Events/GameEventMgr.cpp
+++ b/src/server/game/Events/GameEventMgr.cpp
@@ -24,7 +24,6 @@
#include "Language.h"
#include "Log.h"
#include "MapManager.h"
-#include "GossipDef.h"
#include "Player.h"
#include "BattlegroundMgr.h"
#include "UnitAI.h"
diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h
index a47b6f29e80..eb29e463a4d 100644
--- a/src/server/game/Events/GameEventMgr.h
+++ b/src/server/game/Events/GameEventMgr.h
@@ -96,7 +96,7 @@ class GameEventMgr
{
private:
GameEventMgr();
- ~GameEventMgr() { };
+ ~GameEventMgr() { }
public:
static GameEventMgr* instance()
diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp
index 88cc201ebf8..859633b16c4 100644
--- a/src/server/game/Globals/ObjectAccessor.cpp
+++ b/src/server/game/Globals/ObjectAccessor.cpp
@@ -20,28 +20,20 @@
#include <boost/thread/locks.hpp>
#include "ObjectAccessor.h"
-#include "CellImpl.h"
#include "Corpse.h"
#include "Creature.h"
#include "DynamicObject.h"
#include "GameObject.h"
#include "GridNotifiers.h"
-#include "GridNotifiersImpl.h"
#include "Item.h"
#include "Map.h"
-#include "MapInstanced.h"
-#include "MapManager.h"
#include "ObjectDefines.h"
#include "ObjectMgr.h"
-#include "Opcodes.h"
#include "Pet.h"
#include "Player.h"
-#include "Vehicle.h"
#include "World.h"
#include "WorldPacket.h"
-#include <cmath>
-
ObjectAccessor::ObjectAccessor() { }
ObjectAccessor::~ObjectAccessor() { }
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index f0d7d039dd5..e540824e71c 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -1039,6 +1039,66 @@ void ObjectMgr::LoadCreatureAddons()
TC_LOG_INFO("server.loading", ">> Loaded %u creature addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
+void ObjectMgr::LoadGameObjectAddons()
+{
+ uint32 oldMSTime = getMSTime();
+
+ // 0 1 2
+ QueryResult result = WorldDatabase.Query("SELECT guid, invisibilityType, invisibilityValue FROM gameobject_addon");
+
+ if (!result)
+ {
+ TC_LOG_INFO("server.loading", ">> Loaded 0 gameobject addon definitions. DB table `gameobject_addon` is empty.");
+ return;
+ }
+
+ uint32 count = 0;
+ do
+ {
+ Field* fields = result->Fetch();
+
+ ObjectGuid::LowType guid = fields[0].GetUInt32();
+
+ const GameObjectData* goData = GetGOData(guid);
+ if (!goData)
+ {
+ TC_LOG_ERROR("sql.sql", "GameObject (GUID: %u) does not exist but has a record in `gameobject_addon`", guid);
+ continue;
+ }
+
+ GameObjectAddon& gameObjectAddon = _gameObjectAddonStore[guid];
+ gameObjectAddon.invisibilityType = InvisibilityType(fields[1].GetUInt8());
+ gameObjectAddon.InvisibilityValue = fields[2].GetUInt32();
+
+ if (gameObjectAddon.invisibilityType >= TOTAL_INVISIBILITY_TYPES)
+ {
+ TC_LOG_ERROR("sql.sql", "GameObject (GUID: %u) has invalid InvisibilityType in `gameobject_addon`", guid);
+ gameObjectAddon.invisibilityType = INVISIBILITY_GENERAL;
+ gameObjectAddon.InvisibilityValue = 0;
+ }
+
+ if (gameObjectAddon.invisibilityType && !gameObjectAddon.InvisibilityValue)
+ {
+ TC_LOG_ERROR("sql.sql", "GameObject (GUID: %u) has InvisibilityType set but has no InvisibilityValue in `gameobject_addon`, set to 1", guid);
+ gameObjectAddon.InvisibilityValue = 1;
+ }
+
+ ++count;
+ }
+ while (result->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded %u gameobject addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
+GameObjectAddon const* ObjectMgr::GetGameObjectAddon(ObjectGuid::LowType lowguid)
+{
+ GameObjectAddonContainer::const_iterator itr = _gameObjectAddonStore.find(lowguid);
+ if (itr != _gameObjectAddonStore.end())
+ return &(itr->second);
+
+ return NULL;
+}
+
CreatureAddon const* ObjectMgr::GetCreatureAddon(uint32 lowguid)
{
CreatureAddonContainer::const_iterator itr = _creatureAddonStore.find(lowguid);
@@ -4941,11 +5001,11 @@ void ObjectMgr::LoadEventScripts()
{
TaxiPathNodeEntry const& node = sTaxiPathNodesByPath[path_idx][node_idx];
- if (node.arrivalEventID)
- evt_scripts.insert(node.arrivalEventID);
+ if (node.ArrivalEventID)
+ evt_scripts.insert(node.ArrivalEventID);
- if (node.departureEventID)
- evt_scripts.insert(node.departureEventID);
+ if (node.DepartureEventID)
+ evt_scripts.insert(node.DepartureEventID);
}
}
@@ -6674,7 +6734,7 @@ void ObjectMgr::LoadGameObjectTemplate()
{
if (got.moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[got.moTransport.taxiPathId].empty())
TC_LOG_ERROR("sql.sql", "GameObject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.",
- entry, got.type, got.moTransport.taxiPathId, got.moTransport.taxiPathId);
+ entry, got.type, got.moTransport.taxiPathId, got.moTransport.taxiPathId);
}
if (uint32 transportMap = got.moTransport.mapID)
_transportMaps.insert(transportMap);
@@ -8601,7 +8661,6 @@ void ObjectMgr::LoadBroadcastTexts()
}
_broadcastTextStore.rehash(result->GetRowCount());
- uint32 count = 0;
do
{
@@ -8627,26 +8686,23 @@ void ObjectMgr::LoadBroadcastTexts()
{
if (!sSoundEntriesStore.LookupEntry(bct.SoundId))
{
- TC_LOG_INFO("sql.sql", "BroadcastText (Id: %u) in table `broadcast_text` has SoundId %u but sound does not exist. Skipped.", bct.Id, bct.SoundId);
- // don't load bct of higher expansions
- continue;
+ TC_LOG_DEBUG("broadcasttext", "BroadcastText (Id: %u) in table `broadcast_text` has SoundId %u but sound does not exist.", bct.Id, bct.SoundId);
+ bct.SoundId = 0;
}
}
if (!GetLanguageDescByID(bct.Language))
{
- TC_LOG_INFO("sql.sql", "BroadcastText (Id: %u) in table `broadcast_text` using Language %u but Language does not exist. Skipped.", bct.Id, bct.Language);
- // don't load bct of higher expansions
- continue;
+ TC_LOG_DEBUG("broadcasttext", "BroadcastText (Id: %u) in table `broadcast_text` using Language %u but Language does not exist.", bct.Id, bct.Language);
+ bct.Language = LANG_UNIVERSAL;
}
if (bct.EmoteId0)
{
if (!sEmotesStore.LookupEntry(bct.EmoteId0))
{
- TC_LOG_INFO("sql.sql", "BroadcastText (Id: %u) in table `broadcast_text` has EmoteId0 %u but emote does not exist. Skipped.", bct.Id, bct.EmoteId0);
- // don't load bct of higher expansions
- continue;
+ TC_LOG_DEBUG("broadcasttext", "BroadcastText (Id: %u) in table `broadcast_text` has EmoteId0 %u but emote does not exist.", bct.Id, bct.EmoteId0);
+ bct.EmoteId0 = 0;
}
}
@@ -8654,9 +8710,8 @@ void ObjectMgr::LoadBroadcastTexts()
{
if (!sEmotesStore.LookupEntry(bct.EmoteId1))
{
- TC_LOG_INFO("sql.sql", "BroadcastText (Id: %u) in table `broadcast_text` has EmoteId1 %u but emote does not exist. Skipped.", bct.Id, bct.EmoteId1);
- // don't load bct of higher expansions
- continue;
+ TC_LOG_DEBUG("broadcasttext", "BroadcastText (Id: %u) in table `broadcast_text` has EmoteId1 %u but emote does not exist.", bct.Id, bct.EmoteId1);
+ bct.EmoteId1 = 0;
}
}
@@ -8664,19 +8719,16 @@ void ObjectMgr::LoadBroadcastTexts()
{
if (!sEmotesStore.LookupEntry(bct.EmoteId2))
{
- TC_LOG_INFO("sql.sql", "BroadcastText (Id: %u) in table `broadcast_text` has EmoteId2 %u but emote does not exist. Skipped.", bct.Id, bct.EmoteId2);
- // don't load bct of higher expansions
- continue;
+ TC_LOG_DEBUG("broadcasttext", "BroadcastText (Id: %u) in table `broadcast_text` has EmoteId2 %u but emote does not exist.", bct.Id, bct.EmoteId2);
+ bct.EmoteId2 = 0;
}
}
_broadcastTextStore[bct.Id] = bct;
-
- ++count;
}
while (result->NextRow());
- TC_LOG_INFO("server.loading", ">> Loaded %u broadcast texts in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " broadcast texts in %u ms", _broadcastTextStore.size(), GetMSTimeDiffToNow(oldMSTime));
}
void ObjectMgr::LoadBroadcastTextLocales()
@@ -8702,8 +8754,7 @@ void ObjectMgr::LoadBroadcastTextLocales()
BroadcastTextContainer::iterator bct = _broadcastTextStore.find(id);
if (bct == _broadcastTextStore.end())
{
- TC_LOG_INFO("sql.sql", "BroadcastText (Id: %u) in table `locales_broadcast_text` does not exist or is incompatible. Skipped!", id);
- // don't load bct of higher expansions
+ TC_LOG_ERROR("sql.sql", "BroadcastText (Id: %u) in table `locales_broadcast_text` does not exist. Skipped!", id);
continue;
}
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index f9562a12335..f18e39077f3 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -49,12 +49,7 @@ struct PlayerClassLevelInfo;
struct PlayerInfo;
struct PlayerLevelInfo;
-// 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
{
@@ -82,12 +77,7 @@ private:
uint8 _summonGroup; ///< Summon's group id
};
-// 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
// DB scripting commands
enum ScriptCommands
@@ -732,6 +722,7 @@ class ObjectMgr
static void ChooseCreatureFlags(CreatureTemplate const* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, CreatureData const* data = NULL);
EquipmentInfo const* GetEquipmentInfo(uint32 entry, int8& id);
CreatureAddon const* GetCreatureAddon(uint32 lowguid);
+ GameObjectAddon const* GetGameObjectAddon(ObjectGuid::LowType lowguid);
CreatureAddon const* GetCreatureTemplateAddon(uint32 entry);
ItemTemplate const* GetItemTemplate(uint32 entry);
ItemTemplateContainer const* GetItemTemplateStore() const { return &_itemTemplateStore; }
@@ -974,6 +965,7 @@ class ObjectMgr
void LoadLinkedRespawn();
bool SetCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid);
void LoadCreatureAddons();
+ void LoadGameObjectAddons();
void LoadCreatureModelInfo();
void LoadEquipmentTemplates();
void LoadGameObjectLocales();
@@ -1419,6 +1411,7 @@ class ObjectMgr
CreatureModelContainer _creatureModelStore;
CreatureAddonContainer _creatureAddonStore;
CreatureAddonContainer _creatureTemplateAddonStore;
+ GameObjectAddonContainer _gameObjectAddonStore;
EquipmentInfoContainer _equipmentInfoStore;
LinkedRespawnContainer _linkedRespawnStore;
CreatureLocaleContainer _creatureLocaleStore;
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
index e14910bdf5e..d52e559c408 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
@@ -21,12 +21,9 @@
#include "WorldPacket.h"
#include "WorldSession.h"
#include "UpdateData.h"
-#include "Item.h"
-#include "Map.h"
#include "Transport.h"
#include "ObjectAccessor.h"
#include "CellImpl.h"
-#include "SpellInfo.h"
using namespace Trinity;
@@ -65,7 +62,7 @@ void VisibleNotifier::SendToSelf()
}
}
- for (GuidSet::const_iterator it = vis_guids.begin(); it != vis_guids.end(); ++it)
+ for (auto it = vis_guids.begin(); it != vis_guids.end(); ++it)
{
i_player.m_clientGUIDs.erase(*it);
i_data.AddOutOfRangeGUID(*it);
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h
index 5eb726084b3..ccf9748e67a 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.h
@@ -43,7 +43,7 @@ namespace Trinity
Player &i_player;
UpdateData i_data;
std::set<Unit*> i_visibleNow;
- GuidSet vis_guids;
+ GuidUnorderedSet vis_guids;
VisibleNotifier(Player &player) : i_player(player), vis_guids(player.m_clientGUIDs) { }
template<class T> void Visit(GridRefManager<T> &m);
diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp
index 779688402b6..c7e1056a3ef 100644
--- a/src/server/game/Grids/ObjectGridLoader.cpp
+++ b/src/server/game/Grids/ObjectGridLoader.cpp
@@ -20,7 +20,6 @@
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Creature.h"
-#include "Vehicle.h"
#include "GameObject.h"
#include "DynamicObject.h"
#include "Corpse.h"
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 5664cbb6e4b..2e81bdd1af8 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -31,7 +31,6 @@
#include "BattlegroundMgr.h"
#include "MapManager.h"
#include "InstanceSaveMgr.h"
-#include "MapInstanced.h"
#include "Util.h"
#include "LFGMgr.h"
#include "UpdateFieldFlags.h"
@@ -1858,6 +1857,9 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const*
// check if someone in party is using dungeon system
if (member->isUsingLfg())
return ERR_LFG_CANT_USE_BATTLEGROUND;
+ // check Freeze debuff
+ if (member->HasAura(9454))
+ return ERR_BATTLEGROUND_JOIN_FAILED;
}
// only check for MinPlayerCount since MinPlayerCount == MaxPlayerCount for arenas...
diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h
index 28e933bd08c..732afce9517 100644
--- a/src/server/game/Groups/Group.h
+++ b/src/server/game/Groups/Group.h
@@ -218,7 +218,7 @@ class Group
ObjectGuid GetMasterLooterGuid() const;
ItemQualities GetLootThreshold() const;
- uint32 GetDbStoreId() const { return m_dbStoreId; };
+ uint32 GetDbStoreId() const { return m_dbStoreId; }
// member manipulation methods
bool IsMember(ObjectGuid guid) const;
diff --git a/src/server/game/Handlers/AddonHandler.cpp b/src/server/game/Handlers/AddonHandler.cpp
index 8d5e07c4d3b..adb76846379 100644
--- a/src/server/game/Handlers/AddonHandler.cpp
+++ b/src/server/game/Handlers/AddonHandler.cpp
@@ -18,7 +18,6 @@
#include "zlib.h"
#include "AddonHandler.h"
-#include "DatabaseEnv.h"
#include "Opcodes.h"
#include "Log.h"
diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp
index de23626eb25..2ec89ac2a26 100644
--- a/src/server/game/Handlers/BattleGroundHandler.cpp
+++ b/src/server/game/Handlers/BattleGroundHandler.cpp
@@ -178,6 +178,10 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
return;
}
+ // check Freeze debuff
+ if (_player->HasAura(9454))
+ return;
+
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
@@ -434,6 +438,10 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData)
WorldPacket data;
if (action)
{
+ // check Freeze debuff
+ if (_player->HasAura(9454))
+ return;
+
if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId))
return; // cheating?
diff --git a/src/server/game/Handlers/BattlefieldHandler.cpp b/src/server/game/Handlers/BattlefieldHandler.cpp
index c7ffac217c4..69e36e7328d 100644
--- a/src/server/game/Handlers/BattlefieldHandler.cpp
+++ b/src/server/game/Handlers/BattlefieldHandler.cpp
@@ -15,8 +15,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "ObjectAccessor.h"
-#include "ObjectMgr.h"
#include "Opcodes.h"
#include "Player.h"
#include "WorldPacket.h"
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index ee8e051ecd9..9cb9077c5ff 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -28,7 +28,6 @@
#include "Guild.h"
#include "GuildMgr.h"
#include "Language.h"
-#include "LFGMgr.h"
#include "Log.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
@@ -1254,6 +1253,9 @@ void WorldSession::HandleAlterAppearance(WorldPacket& recvData)
if (bs_skinColor && (bs_skinColor->type != 3 || bs_skinColor->race != _player->getRace() || bs_skinColor->gender != _player->getGender()))
return;
+ if (!Player::ValidateAppearance(_player->getRace(), _player->getClass(), _player->getGender(), bs_hair->hair_id, Color, _player->GetByteValue(PLAYER_BYTES, 1), bs_facialHair->hair_id, bs_skinColor ? bs_skinColor->hair_id : _player->GetByteValue(PLAYER_BYTES, 0)))
+ return;
+
GameObject* go = _player->FindNearestGameObjectOfType(GAMEOBJECT_TYPE_BARBER_CHAIR, 5.0f);
if (!go)
{
@@ -1338,10 +1340,8 @@ void WorldSession::HandleCharCustomize(WorldPacket& recvData)
>> customizeInfo.FacialHair
>> customizeInfo.Face;
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AT_LOGIN);
-
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_NAME_DATA);
stmt->setUInt32(0, customizeInfo.Guid.GetCounter());
- // TODO: Make async with callback
PreparedQueryResult result = CharacterDatabase.Query(stmt);
if (!result)
@@ -1351,6 +1351,29 @@ void WorldSession::HandleCharCustomize(WorldPacket& recvData)
}
Field* fields = result->Fetch();
+ uint8 plrRace = fields[0].GetUInt8();
+ uint8 plrClass = fields[1].GetUInt8();
+ uint8 plrGender = fields[2].GetUInt8();
+
+ if (!Player::ValidateAppearance(plrRace, plrClass, plrGender, customizeInfo.HairStyle, customizeInfo.HairColor, customizeInfo.Face, customizeInfo.FacialHair, customizeInfo.Skin, true))
+ {
+ SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo);
+ return;
+ }
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AT_LOGIN);
+
+ stmt->setUInt32(0, customizeInfo.Guid.GetCounter());
+ // TODO: Make async with callback
+ result = CharacterDatabase.Query(stmt);
+
+ if (!result)
+ {
+ SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo);
+ return;
+ }
+
+ fields = result->Fetch();
uint32 at_loginFlags = fields[0].GetUInt16();
if (!(at_loginFlags & AT_LOGIN_CUSTOMIZE))
diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp
index f5264bde755..2acbaba1f67 100644
--- a/src/server/game/Handlers/ChatHandler.cpp
+++ b/src/server/game/Handlers/ChatHandler.cpp
@@ -34,7 +34,6 @@
#include "Log.h"
#include "Opcodes.h"
#include "Player.h"
-#include "SpellAuras.h"
#include "SpellAuraEffects.h"
#include "Util.h"
#include "ScriptMgr.h"
diff --git a/src/server/game/Handlers/CombatHandler.cpp b/src/server/game/Handlers/CombatHandler.cpp
index ea990c83f46..39ba593c8d9 100644
--- a/src/server/game/Handlers/CombatHandler.cpp
+++ b/src/server/game/Handlers/CombatHandler.cpp
@@ -22,9 +22,7 @@
#include "WorldSession.h"
#include "ObjectAccessor.h"
#include "CreatureAI.h"
-#include "ObjectDefines.h"
#include "Vehicle.h"
-#include "VehicleDefines.h"
#include "Player.h"
#include "Opcodes.h"
diff --git a/src/server/game/Handlers/DuelHandler.cpp b/src/server/game/Handlers/DuelHandler.cpp
index 37d89274909..954fb66a9db 100644
--- a/src/server/game/Handlers/DuelHandler.cpp
+++ b/src/server/game/Handlers/DuelHandler.cpp
@@ -20,8 +20,6 @@
#include "WorldPacket.h"
#include "WorldSession.h"
#include "Log.h"
-#include "Opcodes.h"
-#include "UpdateData.h"
#include "Player.h"
void WorldSession::HandleDuelAcceptedOpcode(WorldPacket& recvPacket)
diff --git a/src/server/game/Handlers/GuildHandler.cpp b/src/server/game/Handlers/GuildHandler.cpp
index 6b770b58827..ca7b4a5f8cf 100644
--- a/src/server/game/Handlers/GuildHandler.cpp
+++ b/src/server/game/Handlers/GuildHandler.cpp
@@ -23,10 +23,7 @@
#include "ObjectMgr.h"
#include "GuildMgr.h"
#include "Log.h"
-#include "Opcodes.h"
#include "Guild.h"
-#include "GossipDef.h"
-#include "SocialMgr.h"
void WorldSession::HandleGuildQueryOpcode(WorldPacket& recvPacket)
{
diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp
index a24f247c79d..672e1c69920 100644
--- a/src/server/game/Handlers/ItemHandler.cpp
+++ b/src/server/game/Handlers/ItemHandler.cpp
@@ -24,8 +24,6 @@
#include "ObjectMgr.h"
#include "Player.h"
#include "Item.h"
-#include "UpdateData.h"
-#include "ObjectAccessor.h"
#include "SpellInfo.h"
void WorldSession::HandleSplitItemOpcode(WorldPacket& recvData)
diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp
index 34732a681c5..e18e7830cfb 100644
--- a/src/server/game/Handlers/LFGHandler.cpp
+++ b/src/server/game/Handlers/LFGHandler.cpp
@@ -465,10 +465,10 @@ void WorldSession::SendLfgJoinResult(lfg::LfgJoinResultData const& joinData)
void WorldSession::SendLfgQueueStatus(lfg::LfgQueueStatusData const& queueData)
{
- TC_LOG_DEBUG("lfg", "SMSG_LFG_QUEUE_STATUS %s dungeon: %u, waitTime: %d, "
+ TC_LOG_DEBUG("lfg", "SMSG_LFG_QUEUE_STATUS %s state: %s, dungeon: %u, waitTime: %d, "
"avgWaitTime: %d, waitTimeTanks: %d, waitTimeHealer: %d, waitTimeDps: %d, "
"queuedTime: %u, tanks: %u, healers: %u, dps: %u",
- GetPlayerInfo().c_str(), queueData.dungeonId, queueData.waitTime, queueData.waitTimeAvg,
+ GetPlayerInfo().c_str(), lfg::GetStateString(sLFGMgr->GetState(GetPlayer()->GetGUID())).c_str(), queueData.dungeonId, queueData.waitTime, queueData.waitTimeAvg,
queueData.waitTimeTank, queueData.waitTimeHealer, queueData.waitTimeDps,
queueData.queuedTime, queueData.tanks, queueData.healers, queueData.dps);
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index e541b9d7625..7b8ce80ccd7 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -28,9 +28,6 @@
#include "ObjectMgr.h"
#include "GuildMgr.h"
#include "WorldSession.h"
-#include "BigNumber.h"
-#include "SHA1.h"
-#include "UpdateData.h"
#include "LootMgr.h"
#include "Chat.h"
#include "zlib.h"
@@ -38,19 +35,14 @@
#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 "InstanceScript.h"
#include "GameObjectAI.h"
#include "Group.h"
-#include "AccountMgr.h"
#include "Spell.h"
#include "BattlegroundMgr.h"
#include "Battlefield.h"
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index f537af4b46e..e86fa523f68 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -23,7 +23,6 @@
#include "Log.h"
#include "Corpse.h"
#include "Player.h"
-#include "SpellAuras.h"
#include "MapManager.h"
#include "Transport.h"
#include "Battleground.h"
diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp
index 0300759a6e6..3c4bbd87b3f 100644
--- a/src/server/game/Handlers/NPCHandler.cpp
+++ b/src/server/game/Handlers/NPCHandler.cpp
@@ -27,8 +27,6 @@
#include "SpellMgr.h"
#include "Player.h"
#include "GossipDef.h"
-#include "UpdateMask.h"
-#include "ObjectAccessor.h"
#include "Creature.h"
#include "Pet.h"
#include "ReputationMgr.h"
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 684b4abb2aa..0bf33eee234 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -30,6 +30,7 @@
#include "Pet.h"
#include "World.h"
#include "Group.h"
+#include "SpellHistory.h"
#include "SpellInfo.h"
#include "Player.h"
@@ -89,7 +90,7 @@ void WorldSession::HandlePetAction(WorldPacket& recvData)
SpellInfo const* spell = (flag == ACT_ENABLED || flag == ACT_PASSIVE) ? sSpellMgr->GetSpellInfo(spellid) : NULL;
if (!spell)
return;
- if (!(spell->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD))
+ if (!spell->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD))
return;
}
@@ -344,8 +345,6 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
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
@@ -379,8 +378,8 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
else
spell->SendPetCastResult(result);
- if (!pet->ToCreature()->HasSpellCooldown(spellid))
- GetPlayer()->SendClearCooldown(spellid, pet);
+ if (!pet->GetSpellHistory()->HasCooldown(spellid))
+ pet->GetSpellHistory()->ResetCooldown(spellid, true);
spell->finish(false);
delete spell;
@@ -794,7 +793,6 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
{
if (Creature* creature = caster->ToCreature())
{
- creature->AddCreatureSpellCooldown(spellId);
if (Pet* pet = creature->ToPet())
{
// 10% chance to play special pet attack talk, else growl
@@ -812,16 +810,8 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket)
{
spell->SendPetCastResult(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);
- }
+ if (!caster->GetSpellHistory()->HasCooldown(spellId))
+ caster->GetSpellHistory()->ResetCooldown(spellId, true);
spell->finish(false);
delete spell;
diff --git a/src/server/game/Handlers/PetitionsHandler.cpp b/src/server/game/Handlers/PetitionsHandler.cpp
index 1bf081900ee..05e793455da 100644
--- a/src/server/game/Handlers/PetitionsHandler.cpp
+++ b/src/server/game/Handlers/PetitionsHandler.cpp
@@ -28,8 +28,6 @@
#include "Opcodes.h"
#include "Guild.h"
#include "ArenaTeam.h"
-#include "GossipDef.h"
-#include "SocialMgr.h"
#define CHARTER_DISPLAY_ID 16161
diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp
index ed41d2ebeed..d15f21f4ad3 100644
--- a/src/server/game/Handlers/QueryHandler.cpp
+++ b/src/server/game/Handlers/QueryHandler.cpp
@@ -17,7 +17,6 @@
*/
#include "Common.h"
-#include "Language.h"
#include "DatabaseEnv.h"
#include "WorldPacket.h"
#include "WorldSession.h"
@@ -28,7 +27,6 @@
#include "Player.h"
#include "UpdateMask.h"
#include "NPCHandler.h"
-#include "Pet.h"
#include "MapManager.h"
void WorldSession::SendNameQueryOpcode(ObjectGuid guid)
diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp
index b6157d6eb94..3c6258b2d7c 100644
--- a/src/server/game/Handlers/QuestHandler.cpp
+++ b/src/server/game/Handlers/QuestHandler.cpp
@@ -627,7 +627,7 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket
WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4);
data << uint32(count); // placeholder
- for (GuidSet::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr)
+ for (auto itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr)
{
uint32 questStatus = DIALOG_STATUS_NONE;
diff --git a/src/server/game/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp
index 23ce233a905..6da2efa38a6 100644
--- a/src/server/game/Handlers/SkillHandler.cpp
+++ b/src/server/game/Handlers/SkillHandler.cpp
@@ -17,13 +17,11 @@
*/
#include "Common.h"
-#include "DatabaseEnv.h"
#include "Log.h"
#include "ObjectAccessor.h"
#include "Opcodes.h"
#include "Player.h"
#include "Pet.h"
-#include "UpdateMask.h"
#include "WorldPacket.h"
#include "WorldSession.h"
diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
index c4bd892d3cf..a6108b36c13 100644
--- a/src/server/game/Handlers/SpellHandler.cpp
+++ b/src/server/game/Handlers/SpellHandler.cpp
@@ -26,9 +26,6 @@
#include "Opcodes.h"
#include "Spell.h"
#include "Totem.h"
-#include "TemporarySummon.h"
-#include "SpellAuras.h"
-#include "CreatureAI.h"
#include "ScriptMgr.h"
#include "GameObjectAI.h"
#include "SpellAuraEffects.h"
@@ -417,7 +414,7 @@ void WorldSession::HandleCancelAuraOpcode(WorldPacket& recvPacket)
return;
// not allow remove spells with attr SPELL_ATTR0_CANT_CANCEL
- if (spellInfo->Attributes & SPELL_ATTR0_CANT_CANCEL)
+ if (spellInfo->HasAttribute(SPELL_ATTR0_CANT_CANCEL))
return;
// channeled spell case (it currently cast then)
@@ -494,8 +491,6 @@ void WorldSession::HandlePetCancelAuraOpcode(WorldPacket& recvPacket)
}
pet->RemoveOwnedAura(spellId, ObjectGuid::Empty, 0, AURA_REMOVE_BY_CANCEL);
-
- pet->AddCreatureSpellCooldown(spellId);
}
void WorldSession::HandleCancelGrowthAuraOpcode(WorldPacket& /*recvPacket*/) { }
diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp
index 02e0345dba8..af0f5b0fc75 100644
--- a/src/server/game/Handlers/TaxiHandler.cpp
+++ b/src/server/game/Handlers/TaxiHandler.cpp
@@ -24,7 +24,6 @@
#include "Log.h"
#include "ObjectMgr.h"
#include "Player.h"
-#include "UpdateMask.h"
#include "Path.h"
#include "WaypointMovementGenerator.h"
@@ -238,7 +237,7 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData)
TaxiPathNodeEntry const& node = flight->GetPath()[flight->GetCurrentNode()];
flight->SkipCurrentNode();
- GetPlayer()->TeleportTo(curDestNode->map_id, node.x, node.y, node.z, GetPlayer()->GetOrientation());
+ GetPlayer()->TeleportTo(curDestNode->map_id, node.LocX, node.LocY, node.LocZ, GetPlayer()->GetOrientation());
}
return;
}
diff --git a/src/server/game/Handlers/VoiceChatHandler.cpp b/src/server/game/Handlers/VoiceChatHandler.cpp
index 7801ed4d9fe..277755c6eb1 100644
--- a/src/server/game/Handlers/VoiceChatHandler.cpp
+++ b/src/server/game/Handlers/VoiceChatHandler.cpp
@@ -19,7 +19,6 @@
#include "Common.h"
#include "WorldPacket.h"
#include "WorldSession.h"
-#include "Opcodes.h"
#include "Log.h"
void WorldSession::HandleVoiceSessionEnableOpcode(WorldPacket& recvData)
diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp
index 0a355fb14b7..260c2966a52 100644
--- a/src/server/game/Instances/InstanceSaveMgr.cpp
+++ b/src/server/game/Instances/InstanceSaveMgr.cpp
@@ -21,15 +21,12 @@
#include "GridNotifiers.h"
#include "Log.h"
#include "GridStates.h"
-#include "CellImpl.h"
#include "Map.h"
#include "MapManager.h"
#include "MapInstanced.h"
#include "InstanceSaveMgr.h"
#include "Timer.h"
-#include "GridNotifiersImpl.h"
#include "Config.h"
-#include "Transport.h"
#include "ObjectMgr.h"
#include "World.h"
#include "Group.h"
diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp
index badd151bf4c..da806e5b038 100644
--- a/src/server/game/Instances/InstanceScript.cpp
+++ b/src/server/game/Instances/InstanceScript.cpp
@@ -191,6 +191,12 @@ void InstanceScript::UpdateDoorState(GameObject* door)
door->SetGoState(open ? GO_STATE_ACTIVE : GO_STATE_READY);
}
+BossInfo* InstanceScript::GetBossInfo(uint32 id)
+{
+ ASSERT(id < bosses.size());
+ return &bosses[id];
+}
+
void InstanceScript::AddObject(Creature* obj, bool add)
{
ObjectInfoMap::const_iterator j = _creatureInfo.find(obj->GetEntry());
@@ -420,7 +426,26 @@ void InstanceScript::DoUseDoorOrButton(ObjectGuid guid, uint32 withRestoreTime /
TC_LOG_ERROR("scripts", "InstanceScript: DoUseDoorOrButton can't use gameobject entry %u, because type is %u.", go->GetEntry(), go->GetGoType());
}
else
- TC_LOG_DEBUG("scripts", "InstanceScript: HandleGameObject failed");
+ TC_LOG_DEBUG("scripts", "InstanceScript: DoUseDoorOrButton failed");
+}
+
+void InstanceScript::DoCloseDoorOrButton(ObjectGuid guid)
+{
+ if (!guid)
+ return;
+
+ if (GameObject* go = instance->GetGameObject(guid))
+ {
+ if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR || go->GetGoType() == GAMEOBJECT_TYPE_BUTTON)
+ {
+ if (go->getLootState() == GO_ACTIVATED)
+ go->ResetDoorOrButton();
+ }
+ else
+ TC_LOG_ERROR("scripts", "InstanceScript: DoCloseDoorOrButton can't use gameobject entry %u, because type is %u.", go->GetEntry(), go->GetGoType());
+ }
+ else
+ TC_LOG_DEBUG("scripts", "InstanceScript: DoCloseDoorOrButton failed");
}
void InstanceScript::DoRespawnGameObject(ObjectGuid guid, uint32 timeToDespawn /*= MINUTE*/)
diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h
index 3089a4193c9..be05a9f4495 100644
--- a/src/server/game/Instances/InstanceScript.h
+++ b/src/server/game/Instances/InstanceScript.h
@@ -191,6 +191,7 @@ class InstanceScript : public ZoneScript
// Change active state of doors or buttons
void DoUseDoorOrButton(ObjectGuid guid, uint32 withRestoreTime = 0, bool useAlternativeState = false);
+ void DoCloseDoorOrButton(ObjectGuid guid);
// Respawns a GO having negative spawntimesecs in gameobject-table
void DoRespawnGameObject(ObjectGuid guid, uint32 timeToDespawn = MINUTE);
@@ -254,12 +255,16 @@ class InstanceScript : public ZoneScript
void AddObject(GameObject* obj, bool add);
void AddObject(WorldObject* obj, uint32 type, bool add);
- void AddDoor(GameObject* door, bool add);
+ virtual void AddDoor(GameObject* door, bool add);
void AddMinion(Creature* minion, bool add);
- void UpdateDoorState(GameObject* door);
+ virtual void UpdateDoorState(GameObject* door);
void UpdateMinionState(Creature* minion, EncounterState state);
+ // Exposes private data that should never be modified unless exceptional cases.
+ // Pay very much attention at how the returned BossInfo data is modified to avoid issues.
+ BossInfo* GetBossInfo(uint32 id);
+
// Instance Load and Save
bool ReadSaveDataHeaders(std::istringstream& data);
void ReadSaveDataBossStates(std::istringstream& data);
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index db6a2c98379..ba4e4713458 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -853,7 +853,7 @@ ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li)
{
b << uint32(li.itemid);
b << uint32(li.count); // nr of items of this type
- b << uint32(sObjectMgr->GetItemTemplate(li.itemid)->DisplayInfoID);
+ b << uint32(ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(li.itemid))->DisplayInfoID);
b << uint32(li.randomSuffix);
b << uint32(li.randomPropertyId);
//b << uint8(0); // slot type - will send after this function call
@@ -1832,7 +1832,7 @@ void LoadLootTemplates_Spell()
{
// not report about not trainable spells (optionally supported by DB)
// ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example
- if (!(spellInfo->Attributes & SPELL_ATTR0_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR0_TRADESPELL))
+ if (!spellInfo->HasAttribute(SPELL_ATTR0_NOT_SHAPESHIFT) || spellInfo->HasAttribute(SPELL_ATTR0_TRADESPELL))
{
LootTemplates_Spell.ReportNonExistingId(spell_id, "Spell", spellInfo->Id);
}
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 94f458e6742..c1a462497cd 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -28,7 +28,6 @@
#include "Group.h"
#include "InstanceScript.h"
#include "MapInstanced.h"
-#include "MapManager.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Pet.h"
@@ -130,9 +129,9 @@ void Map::LoadMMap(int gx, int gy)
bool mmapLoadResult = MMAP::MMapFactory::createOrGetMMapManager()->loadMap((sWorld->GetDataPath() + "mmaps").c_str(), GetId(), gx, gy);
if (mmapLoadResult)
- TC_LOG_INFO("maps", "MMAP loaded name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
+ TC_LOG_DEBUG("maps", "MMAP loaded name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
else
- TC_LOG_INFO("maps", "Could not load MMAP name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
+ TC_LOG_ERROR("maps", "Could not load MMAP name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
}
void Map::LoadVMap(int gx, int gy)
@@ -144,10 +143,10 @@ void Map::LoadVMap(int gx, int gy)
switch (vmapLoadResult)
{
case VMAP::VMAP_LOAD_RESULT_OK:
- TC_LOG_INFO("maps", "VMAP loaded name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
+ TC_LOG_DEBUG("maps", "VMAP loaded name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
break;
case VMAP::VMAP_LOAD_RESULT_ERROR:
- TC_LOG_INFO("maps", "Could not load VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
+ TC_LOG_ERROR("maps", "Could not load VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
break;
case VMAP::VMAP_LOAD_RESULT_IGNORED:
TC_LOG_DEBUG("maps", "Ignored VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
@@ -177,7 +176,7 @@ void Map::LoadMap(int gx, int gy, bool reload)
//map already load, delete it before reloading (Is it necessary? Do we really need the ability the reload maps during runtime?)
if (GridMaps[gx][gy])
{
- TC_LOG_INFO("maps", "Unloading previously loaded map %u before reloading.", GetId());
+ TC_LOG_DEBUG("maps", "Unloading previously loaded map %u before reloading.", GetId());
sScriptMgr->OnUnloadGridMap(this, GridMaps[gx][gy], gx, gy);
delete (GridMaps[gx][gy]);
@@ -189,7 +188,7 @@ void Map::LoadMap(int gx, int gy, bool reload)
int len = sWorld->GetDataPath().length() + strlen("maps/%03u%02u%02u.map") + 1;
tmp = new char[len];
snprintf(tmp, len, (char *)(sWorld->GetDataPath() + "maps/%03u%02u%02u.map").c_str(), GetId(), gx, gy);
- TC_LOG_INFO("maps", "Loading map %s", tmp);
+ TC_LOG_DEBUG("maps", "Loading map %s", tmp);
// loading data
GridMaps[gx][gy] = new GridMap();
if (!GridMaps[gx][gy]->loadData(tmp))
@@ -2501,7 +2500,7 @@ void Map::UpdateObjectsVisibilityFor(Player* player, Cell cell, CellCoord cellpa
void Map::SendInitSelf(Player* player)
{
- TC_LOG_INFO("maps", "Creating player data for himself %u", player->GetGUIDLow());
+ TC_LOG_DEBUG("maps", "Creating player data for himself %u", player->GetGUIDLow());
UpdateData data;
@@ -2563,6 +2562,17 @@ inline void Map::setNGrid(NGridType *grid, uint32 x, uint32 y)
void Map::DelayedUpdate(const uint32 t_diff)
{
+ for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();)
+ {
+ Transport* transport = *_transportsUpdateIter;
+ ++_transportsUpdateIter;
+
+ if (!transport->IsInWorld())
+ continue;
+
+ transport->DelayedUpdate(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 !
@@ -2853,7 +2863,7 @@ bool InstanceMap::CanEnter(Player* player)
uint32 maxPlayers = GetMaxPlayers();
if (GetPlayersCountExceptGMs() >= maxPlayers)
{
- TC_LOG_INFO("maps", "MAP: Instance '%u' of map '%s' cannot have more than '%u' players. Player '%s' rejected", GetInstanceId(), GetMapName(), maxPlayers, player->GetName().c_str());
+ TC_LOG_WARN("maps", "MAP: Instance '%u' of map '%s' cannot have more than '%u' players. Player '%s' rejected", GetInstanceId(), GetMapName(), maxPlayers, player->GetName().c_str());
player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAX_PLAYERS);
return false;
}
@@ -2922,7 +2932,7 @@ bool InstanceMap::AddPlayerToMap(Player* player)
InstanceSave* mapSave = sInstanceSaveMgr->GetInstanceSave(GetInstanceId());
if (!mapSave)
{
- TC_LOG_INFO("maps", "InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId());
+ TC_LOG_DEBUG("maps", "InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId());
mapSave = sInstanceSaveMgr->AddInstanceSave(GetId(), GetInstanceId(), Difficulty(GetSpawnMode()), 0, true);
}
@@ -2998,7 +3008,7 @@ bool InstanceMap::AddPlayerToMap(Player* player)
// first player enters (no players yet)
SetResetSchedule(false);
- TC_LOG_INFO("maps", "MAP: Player '%s' entered instance '%u' of map '%s'", player->GetName().c_str(), GetInstanceId(), GetMapName());
+ TC_LOG_DEBUG("maps", "MAP: Player '%s' entered instance '%u' of map '%s'", player->GetName().c_str(), GetInstanceId(), GetMapName());
// initialize unload state
m_unloadTimer = 0;
m_resetAfterUnload = false;
@@ -3024,7 +3034,7 @@ void InstanceMap::Update(const uint32 t_diff)
void InstanceMap::RemovePlayerFromMap(Player* player, bool remove)
{
- TC_LOG_INFO("maps", "MAP: Removing player '%s' from instance '%u' of map '%s' before relocating to another map", player->GetName().c_str(), GetInstanceId(), GetMapName());
+ TC_LOG_DEBUG("maps", "MAP: Removing player '%s' from instance '%u' of map '%s' before relocating to another map", player->GetName().c_str(), GetInstanceId(), GetMapName());
//if last player set unload timer
if (!m_unloadTimer && m_mapRefManager.getSize() == 1)
m_unloadTimer = m_unloadWhenEmpty ? MIN_UNLOAD_DELAY : std::max(sWorld->getIntConfig(CONFIG_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY);
@@ -3257,7 +3267,7 @@ bool BattlegroundMap::AddPlayerToMap(Player* player)
void BattlegroundMap::RemovePlayerFromMap(Player* player, bool remove)
{
- TC_LOG_INFO("maps", "MAP: Removing player '%s' from bg '%u' of map '%s' before relocating to another map", player->GetName().c_str(), GetInstanceId(), GetMapName());
+ TC_LOG_DEBUG("maps", "MAP: Removing player '%s' from bg '%u' of map '%s' before relocating to another map", player->GetName().c_str(), GetInstanceId(), GetMapName());
Map::RemovePlayerFromMap(player, remove);
}
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 3bbd6068e4e..43fcbaba31c 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -210,12 +210,7 @@ public:
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0);
};
-// 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
{
@@ -241,11 +236,7 @@ struct ZoneDynamicInfo
uint32 LightFadeInTime;
};
-#if defined(__GNUC__)
-#pragma pack()
-#else
#pragma pack(pop)
-#endif
#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
diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp
index c8dd812ca02..29f4b4ab7c2 100644
--- a/src/server/game/Maps/MapManager.cpp
+++ b/src/server/game/Maps/MapManager.cpp
@@ -27,7 +27,6 @@
#include "InstanceScript.h"
#include "Config.h"
#include "World.h"
-#include "CellImpl.h"
#include "Corpse.h"
#include "ObjectMgr.h"
#include "Language.h"
diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp
index b2e30473632..dadc2eeeac3 100644
--- a/src/server/game/Maps/TransportMgr.cpp
+++ b/src/server/game/Maps/TransportMgr.cpp
@@ -112,7 +112,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
Movement::PointsArray splinePath, allPoints;
bool mapChange = false;
for (size_t i = 0; i < path.size(); ++i)
- allPoints.push_back(G3D::Vector3(path[i].x, path[i].y, path[i].z));
+ allPoints.push_back(G3D::Vector3(path[i].LocX, path[i].LocY, path[i].LocZ));
// Add extra points to allow derivative calculations for all path nodes
allPoints.insert(allPoints.begin(), allPoints.front().lerp(allPoints[1], -0.2f));
@@ -129,7 +129,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
if (!mapChange)
{
TaxiPathNodeEntry const& node_i = path[i];
- if (i != path.size() - 1 && (node_i.actionFlag & 1 || node_i.mapid != path[i + 1].mapid))
+ if (i != path.size() - 1 && (node_i.Flags & 1 || node_i.MapID != path[i + 1].MapID))
{
keyFrames.back().Teleport = true;
mapChange = true;
@@ -142,8 +142,8 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
k.InitialOrientation = Position::NormalizeOrientation(std::atan2(h.y, h.x) + float(M_PI));
keyFrames.push_back(k);
- splinePath.push_back(G3D::Vector3(node_i.x, node_i.y, node_i.z));
- transport->mapsUsed.insert(k.Node->mapid);
+ splinePath.push_back(G3D::Vector3(node_i.LocX, node_i.LocY, node_i.LocZ));
+ transport->mapsUsed.insert(k.Node->MapID);
}
}
else
@@ -153,12 +153,12 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
if (splinePath.size() >= 2)
{
// Remove special catmull-rom spline points
- if (!keyFrames.front().IsStopFrame() && !keyFrames.front().Node->arrivalEventID && !keyFrames.front().Node->departureEventID)
+ if (!keyFrames.front().IsStopFrame() && !keyFrames.front().Node->ArrivalEventID && !keyFrames.front().Node->DepartureEventID)
{
splinePath.erase(splinePath.begin());
keyFrames.erase(keyFrames.begin());
}
- if (!keyFrames.back().IsStopFrame() && !keyFrames.back().Node->arrivalEventID && !keyFrames.back().Node->departureEventID)
+ if (!keyFrames.back().IsStopFrame() && !keyFrames.back().Node->ArrivalEventID && !keyFrames.back().Node->DepartureEventID)
{
splinePath.pop_back();
keyFrames.pop_back();
@@ -311,7 +311,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
float curPathTime = 0.0f;
if (keyFrames[0].IsStopFrame())
{
- curPathTime = float(keyFrames[0].Node->delay);
+ curPathTime = float(keyFrames[0].Node->Delay);
keyFrames[0].DepartureTime = uint32(curPathTime * IN_MILLISECONDS);
}
@@ -322,7 +322,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
{
keyFrames[i].ArriveTime = uint32(curPathTime * IN_MILLISECONDS);
keyFrames[i - 1].NextArriveTime = keyFrames[i].ArriveTime;
- curPathTime += float(keyFrames[i].Node->delay);
+ curPathTime += float(keyFrames[i].Node->Delay);
keyFrames[i].DepartureTime = uint32(curPathTime * IN_MILLISECONDS);
}
else
@@ -374,10 +374,10 @@ Transport* TransportMgr::CreateTransport(uint32 entry, uint32 guid /*= 0*/, Map*
// ...at first waypoint
TaxiPathNodeEntry const* startNode = tInfo->keyFrames.begin()->Node;
- uint32 mapId = startNode->mapid;
- float x = startNode->x;
- float y = startNode->y;
- float z = startNode->z;
+ uint32 mapId = startNode->MapID;
+ float x = startNode->LocX;
+ float y = startNode->LocY;
+ float z = startNode->LocZ;
float o = tInfo->keyFrames.begin()->InitialOrientation;
// initialize the gameobject base
diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h
index dbd99bd163a..fff7b9d8afa 100644
--- a/src/server/game/Maps/TransportMgr.h
+++ b/src/server/game/Maps/TransportMgr.h
@@ -61,7 +61,7 @@ struct KeyFrame
uint32 NextArriveTime;
bool IsTeleportFrame() const { return Teleport; }
- bool IsStopFrame() const { return Node->actionFlag == 2; }
+ bool IsStopFrame() const { return Node->Flags == 2; }
};
struct TransportTemplate
diff --git a/src/server/game/Maps/ZoneScript.h b/src/server/game/Maps/ZoneScript.h
index d8dba57d438..fd52bdd4c14 100644
--- a/src/server/game/Maps/ZoneScript.h
+++ b/src/server/game/Maps/ZoneScript.h
@@ -29,8 +29,8 @@ class ZoneScript
ZoneScript() { }
virtual ~ZoneScript() { }
- virtual uint32 GetCreatureEntry(uint32 /*guidlow*/, CreatureData const* data) { return data->id; }
- virtual uint32 GetGameObjectEntry(uint32 /*guidlow*/, uint32 entry) { return entry; }
+ virtual uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) { return data->id; }
+ virtual uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) { return entry; }
virtual void OnCreatureCreate(Creature* ) { }
virtual void OnCreatureRemove(Creature* ) { }
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 8131984224f..9bae8fbdfae 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -207,7 +207,8 @@ enum TrinityStrings
LANG_LIQUID_STATUS = 175,
LANG_INVALID_GAMEOBJECT_TYPE = 176,
LANG_GAMEOBJECT_DAMAGED = 177,
- // Room for more level 1 178-199 not used
+ LANG_GRID_POSITION = 178,
+ // Room for more level 1 179-199 not used
// level 2 chat
LANG_NO_SELECTION = 200,
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 685bcd338a9..06c58a408da 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -3599,4 +3599,12 @@ enum DiminishingLevels
DIMINISHING_LEVEL_TAUNT_IMMUNE = 4
};
+/// Spell cooldown flags sent in SMSG_SPELL_COOLDOWN
+enum SpellCooldownFlags
+{
+ SPELL_COOLDOWN_FLAG_NONE = 0x0,
+ SPELL_COOLDOWN_FLAG_INCLUDE_GCD = 0x1, ///< Starts GCD in addition to normal cooldown specified in the packet
+ SPELL_COOLDOWN_FLAG_INCLUDE_EVENT_COOLDOWNS = 0x2 ///< Starts GCD for spells that should start their cooldown on events, requires SPELL_COOLDOWN_FLAG_INCLUDE_GCD set
+};
+
#endif
diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp
index 47e5b77a0da..2b323e196a7 100644
--- a/src/server/game/Movement/MotionMaster.cpp
+++ b/src/server/game/Movement/MotionMaster.cpp
@@ -30,7 +30,6 @@
#include "RandomMovementGenerator.h"
#include "MoveSpline.h"
#include "MoveSplineInit.h"
-#include <cassert>
inline bool isStatic(MovementGenerator *mv)
{
@@ -387,6 +386,43 @@ void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float spee
Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED);
}
+void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount)
+{
+ float step = 2 * float(M_PI) / stepCount * (clockwise ? -1.0f : 1.0f);
+ Position const& pos = { x, y, z, 0.0f };
+ float angle = pos.GetAngle(_owner->GetPositionX(), _owner->GetPositionY());
+
+ Movement::MoveSplineInit init(_owner);
+
+ for (uint8 i = 0; i < stepCount; angle += step, ++i)
+ {
+ G3D::Vector3 point;
+ point.x = x + radius * cosf(angle);
+ point.y = y + radius * sinf(angle);
+
+ if (_owner->IsFlying())
+ point.z = z;
+ else
+ point.z = _owner->GetMap()->GetHeight(_owner->GetPhaseMask(), point.x, point.y, z);
+
+ init.Path().push_back(point);
+ }
+
+ if (_owner->IsFlying())
+ {
+ init.SetFly();
+ init.SetCyclic();
+ init.SetAnimation(Movement::ToFly);
+ }
+ else
+ {
+ init.SetWalk(true);
+ init.SetCyclic();
+ }
+
+ init.Launch();
+}
+
void MotionMaster::MoveFall(uint32 id /*=0*/)
{
// use larger distance for vmap height search than in most other cases
diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h
index 2821cd5a59b..c8da50364ba 100644
--- a/src/server/game/Movement/MotionMaster.h
+++ b/src/server/game/Movement/MotionMaster.h
@@ -182,8 +182,9 @@ class MotionMaster //: private std::stack<MovementGenerator *>
void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ);
void MoveJumpTo(float angle, float speedXY, float speedZ);
void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = EVENT_JUMP)
- { MoveJump(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speedXY, speedZ, id); };
+ { MoveJump(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speedXY, speedZ, id); }
void MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id = EVENT_JUMP);
+ void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount);
void MoveFall(uint32 id = 0);
void MoveSeekAssistance(float x, float y, float z);
diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
index cbfc181fe9f..f0c0311280f 100755
--- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
@@ -17,10 +17,8 @@
*/
#include "Creature.h"
-#include "MapManager.h"
#include "ConfusedMovementGenerator.h"
#include "PathGenerator.h"
-#include "VMapFactory.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
#include "Player.h"
diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
index cea25fefbda..fa17846a1ff 100644
--- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
@@ -18,7 +18,6 @@
#include "Creature.h"
#include "CreatureAI.h"
-#include "MapManager.h"
#include "FleeingMovementGenerator.h"
#include "PathGenerator.h"
#include "ObjectAccessor.h"
diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
index ff28f3855a6..4245bffb864 100644
--- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
@@ -19,7 +19,6 @@
#include "HomeMovementGenerator.h"
#include "Creature.h"
#include "CreatureAI.h"
-#include "WorldPacket.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
index 0341af299be..86f0e6e20eb 100644
--- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
@@ -17,9 +17,7 @@
*/
#include "Creature.h"
-#include "MapManager.h"
#include "RandomMovementGenerator.h"
-#include "ObjectAccessor.h"
#include "Map.h"
#include "Util.h"
#include "CreatureGroups.h"
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index ed1ea7f4b17..f91fc1985d5 100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -19,7 +19,6 @@
#include "WaypointMovementGenerator.h"
//Extended headers
#include "ObjectMgr.h"
-#include "World.h"
#include "Transport.h"
//Flightmaster grid preloading
#include "MapManager.h"
@@ -249,10 +248,10 @@ uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const
if (i_currentNode >= i_path->size())
return i_path->size();
- uint32 curMapId = (*i_path)[i_currentNode].mapid;
+ uint32 curMapId = (*i_path)[i_currentNode].MapID;
for (uint32 i = i_currentNode; i < i_path->size(); ++i)
{
- if ((*i_path)[i].mapid != curMapId)
+ if ((*i_path)[i].MapID != curMapId)
return i;
}
@@ -297,7 +296,7 @@ void FlightPathMovementGenerator::DoReset(Player* player)
uint32 end = GetPathAtMapEnd();
for (uint32 i = GetCurrentNode(); i != end; ++i)
{
- G3D::Vector3 vertice((*i_path)[i].x, (*i_path)[i].y, (*i_path)[i].z);
+ G3D::Vector3 vertice((*i_path)[i].LocX, (*i_path)[i].LocY, (*i_path)[i].LocZ);
init.Path().push_back(vertice);
}
init.SetFirstPointId(GetCurrentNode());
@@ -333,10 +332,10 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
if (i_path->empty())
return;
- uint32 map0 = (*i_path)[0].mapid;
+ uint32 map0 = (*i_path)[0].MapID;
for (size_t i = 1; i < i_path->size(); ++i)
{
- if ((*i_path)[i].mapid != map0)
+ if ((*i_path)[i].MapID != map0)
{
i_currentNode = i;
return;
@@ -346,9 +345,9 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry const& node, bool departure)
{
- if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID)
+ if (uint32 eventid = departure ? node.DepartureEventID : node.ArrivalEventID)
{
- TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.index, node.path, player->GetName().c_str());
+ TC_LOG_DEBUG("maps.script", "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.NodeIndex, node.PathID, player->GetName().c_str());
player->GetMap()->ScriptsStart(sEventScripts, eventid, player, player);
}
}
@@ -356,7 +355,7 @@ void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry
bool FlightPathMovementGenerator::GetResetPos(Player*, float& x, float& y, float& z)
{
const TaxiPathNodeEntry& node = (*i_path)[i_currentNode];
- x = node.x; y = node.y; z = node.z;
+ x = node.LocX; y = node.LocY; z = node.LocZ;
return true;
}
@@ -365,10 +364,10 @@ void FlightPathMovementGenerator::InitEndGridInfo()
/*! Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will
be reinitialized for each flightmaster at the end of each spline (or stop) in the flight. */
uint32 nodeCount = (*i_path).size(); //! Number of nodes in path.
- _endMapId = (*i_path)[nodeCount - 1].mapid; //! MapId of last node
+ _endMapId = (*i_path)[nodeCount - 1].MapID; //! MapId of last node
_preloadTargetNode = nodeCount - 3;
- _endGridX = (*i_path)[nodeCount - 1].x;
- _endGridY = (*i_path)[nodeCount - 1].y;
+ _endGridX = (*i_path)[nodeCount - 1].LocX;
+ _endGridY = (*i_path)[nodeCount - 1].LocY;
}
void FlightPathMovementGenerator::PreloadEndGrid()
@@ -379,9 +378,9 @@ void FlightPathMovementGenerator::PreloadEndGrid()
// Load the grid
if (endMap)
{
- TC_LOG_INFO("misc", "Preloading rid (%f, %f) for map %u at node index %u/%u", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path->size()-1));
+ TC_LOG_DEBUG("misc", "Preloading rid (%f, %f) for map %u at node index %u/%u", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path->size()-1));
endMap->LoadGrid(_endGridX, _endGridY);
}
else
- TC_LOG_INFO("misc", "Unable to determine map to preload flightmaster grid");
+ TC_LOG_DEBUG("misc", "Unable to determine map to preload flightmaster grid");
}
diff --git a/src/server/game/Movement/Spline/MoveSpline.cpp b/src/server/game/Movement/Spline/MoveSpline.cpp
index d3fa03c1238..1beeebbbad3 100644
--- a/src/server/game/Movement/Spline/MoveSpline.cpp
+++ b/src/server/game/Movement/Spline/MoveSpline.cpp
@@ -147,7 +147,7 @@ void MoveSpline::init_spline(const MoveSplineInitArgs& args)
/// @todo what to do in such cases? problem is in input data (all points are at same coords)
if (spline.length() < minimal_duration)
{
- TC_LOG_ERROR("misc", "MoveSpline::init_spline: zero length spline, wrong input data?");
+ TC_LOG_DEBUG("misc", "MoveSpline::init_spline: zero length spline, wrong input data?");
spline.set_length(spline.last(), spline.isCyclic() ? 1000 : 1);
}
point_Idx = spline.first();
diff --git a/src/server/game/Movement/Spline/MoveSplineFlag.h b/src/server/game/Movement/Spline/MoveSplineFlag.h
index 62fe808b6f5..0a3b41d412a 100644
--- a/src/server/game/Movement/Spline/MoveSplineFlag.h
+++ b/src/server/game/Movement/Spline/MoveSplineFlag.h
@@ -24,11 +24,7 @@
namespace Movement
{
-#if defined( __GNUC__ )
-#pragma pack(1)
-#else
#pragma pack(push, 1)
-#endif
class MoveSplineFlag
{
@@ -136,11 +132,7 @@ namespace Movement
bool unknown12 : 1;
bool unknown13 : 1;
};
-#if defined( __GNUC__ )
-#pragma pack()
-#else
#pragma pack(pop)
-#endif
}
#endif // TRINITYSERVER_MOVESPLINEFLAG_H
diff --git a/src/server/game/Movement/Spline/MoveSplineInit.cpp b/src/server/game/Movement/Spline/MoveSplineInit.cpp
index 9619d478b7f..180ecf23079 100644
--- a/src/server/game/Movement/Spline/MoveSplineInit.cpp
+++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp
@@ -21,7 +21,6 @@
#include "MovementPacketBuilder.h"
#include "Unit.h"
#include "Transport.h"
-#include "Vehicle.h"
#include "WorldPacket.h"
#include "Opcodes.h"
diff --git a/src/server/game/Movement/Spline/MovementUtil.cpp b/src/server/game/Movement/Spline/MovementUtil.cpp
index 7e63f029fd4..4f7e1d6a7a4 100644
--- a/src/server/game/Movement/Spline/MovementUtil.cpp
+++ b/src/server/game/Movement/Spline/MovementUtil.cpp
@@ -18,7 +18,6 @@
#include "MoveSplineFlag.h"
#include <cmath>
-#include <string>
namespace Movement
{
diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.cpp b/src/server/game/OutdoorPvP/OutdoorPvP.cpp
index cf7be3de5ce..c8bc68d0ddf 100644
--- a/src/server/game/OutdoorPvP/OutdoorPvP.cpp
+++ b/src/server/game/OutdoorPvP/OutdoorPvP.cpp
@@ -20,7 +20,6 @@
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Map.h"
-#include "MapManager.h"
#include "Group.h"
#include "WorldPacket.h"
#include "GridNotifiers.h"
@@ -509,7 +508,7 @@ bool OPvPCapturePoint::HandleCustomSpell(Player* player, uint32 /*spellId*/, Gam
{
if (!player->IsOutdoorPvPActive())
return false;
- return false;
+ return true;
}
bool OutdoorPvP::HandleOpenGo(Player* player, ObjectGuid guid)
diff --git a/src/server/game/Pools/PoolMgr.cpp b/src/server/game/Pools/PoolMgr.cpp
index d643bc5da41..3f561539917 100644
--- a/src/server/game/Pools/PoolMgr.cpp
+++ b/src/server/game/Pools/PoolMgr.cpp
@@ -170,7 +170,7 @@ PoolObject* PoolGroup<T>::RollOne(ActivePoolData& spawns, uint32 triggerFrom)
}
if (!EqualChanced.empty())
{
- int32 index = irand(0, EqualChanced.size()-1);
+ uint32 index = urand(0, EqualChanced.size()-1);
// Triggering object is marked as spawned at this time and can be also rolled (respawn case)
// so this need explicit check for this case
if (EqualChanced[index].guid == triggerFrom || !spawns.IsActiveObject<T>(EqualChanced[index].guid))
diff --git a/src/server/game/Reputation/ReputationMgr.cpp b/src/server/game/Reputation/ReputationMgr.cpp
index b99cb677ba0..a3e458503d6 100644
--- a/src/server/game/Reputation/ReputationMgr.cpp
+++ b/src/server/game/Reputation/ReputationMgr.cpp
@@ -28,6 +28,9 @@
const int32 ReputationMgr::PointsInRank[MAX_REPUTATION_RANK] = {36000, 3000, 3000, 3000, 6000, 12000, 21000, 1000};
+const int32 ReputationMgr::Reputation_Cap = 42999;
+const int32 ReputationMgr::Reputation_Bottom = -42000;
+
ReputationRank ReputationMgr::ReputationToRank(int32 standing)
{
int32 limit = Reputation_Cap + 1;
diff --git a/src/server/game/Reputation/ReputationMgr.h b/src/server/game/Reputation/ReputationMgr.h
index c3a8d4f477c..7d7650b858e 100644
--- a/src/server/game/Reputation/ReputationMgr.h
+++ b/src/server/game/Reputation/ReputationMgr.h
@@ -72,8 +72,8 @@ class ReputationMgr
void LoadFromDB(PreparedQueryResult result);
public: // statics
static const int32 PointsInRank[MAX_REPUTATION_RANK];
- static const int32 Reputation_Cap = 42999;
- static const int32 Reputation_Bottom = -42000;
+ static const int32 Reputation_Cap;
+ static const int32 Reputation_Bottom;
static ReputationRank ReputationToRank(int32 standing);
public: // accessors
diff --git a/src/server/game/Scripting/MapScripts.cpp b/src/server/game/Scripting/MapScripts.cpp
index ab9c2e32cc8..3beaa7daa9b 100644
--- a/src/server/game/Scripting/MapScripts.cpp
+++ b/src/server/game/Scripting/MapScripts.cpp
@@ -21,8 +21,6 @@
#include "GridNotifiersImpl.h"
#include "GossipDef.h"
#include "Map.h"
-#include "MapManager.h"
-#include "MapRefManager.h"
#include "ObjectMgr.h"
#include "Pet.h"
#include "ScriptedCreature.h"
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index 7b4e272b3c1..f0ee013bcc2 100644
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -425,7 +425,8 @@ void AddSC_boss_heigan();
void AddSC_boss_gothik();
void AddSC_boss_thaddius();
void AddSC_instance_naxxramas();
-void AddSC_boss_magus_telestra(); //The Nexus Nexus
+void AddSC_boss_nexus_commanders(); // The Nexus Nexus
+void AddSC_boss_magus_telestra();
void AddSC_boss_anomalus();
void AddSC_boss_ormorok();
void AddSC_boss_keristrasza();
@@ -621,6 +622,7 @@ 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_shattered_halls();
void AddSC_instance_shattered_halls();
void AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts
void AddSC_boss_omor_the_unscarred();
@@ -1151,6 +1153,7 @@ void AddOutlandScripts()
AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls
AddSC_boss_warbringer_omrogg();
AddSC_boss_warchief_kargath_bladefist();
+ AddSC_shattered_halls();
AddSC_instance_shattered_halls();
AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts
AddSC_boss_omor_the_unscarred();
@@ -1253,7 +1256,8 @@ void AddNorthrendScripts()
AddSC_boss_gothik();
AddSC_boss_thaddius();
AddSC_instance_naxxramas();
- AddSC_boss_magus_telestra(); //The Nexus Nexus
+ AddSC_boss_nexus_commanders(); // The Nexus Nexus
+ AddSC_boss_magus_telestra();
AddSC_boss_anomalus();
AddSC_boss_ormorok();
AddSC_boss_keristrasza();
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index 628452d120c..aed829a7b57 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -182,9 +182,8 @@ struct TSpellSummary
uint8 Effects; // set of enum SelectEffect
} *SpellSummary;
-ScriptMgr::ScriptMgr() : _scriptCount(0)
+ScriptMgr::ScriptMgr() : _scriptCount(0), _scheduledScripts(0)
{
- _scheduledScripts = 0;
}
ScriptMgr::~ScriptMgr() { }
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index e290b13c635..a226f1b7ed2 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -1142,7 +1142,7 @@ class ScriptMgr
uint32 _scriptCount;
//atomic op counter for active scripts amount
- std::atomic_long _scheduledScripts;
+ std::atomic<uint32> _scheduledScripts;
};
#endif
diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h
index 68abadccf75..4b47e51fde6 100644
--- a/src/server/game/Server/Protocol/Opcodes.h
+++ b/src/server/game/Server/Protocol/Opcodes.h
@@ -1363,11 +1363,7 @@ enum PacketProcessing
class WorldSession;
class WorldPacket;
-#if defined(__GNUC__)
-#pragma pack(1)
-#else
#pragma pack(push, 1)
-#endif
struct OpcodeHandler
{
@@ -1379,11 +1375,7 @@ struct OpcodeHandler
extern OpcodeHandler opcodeTable[NUM_MSG_TYPES];
-#if defined(__GNUC__)
-#pragma pack()
-#else
#pragma pack(pop)
-#endif
/// Lookup opcode name for human understandable logging
inline const char* LookupOpcodeName(uint16 id)
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index b6b1a4992af..d6055e9733b 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -36,16 +36,12 @@
#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.h"
#include "ScriptMgr.h"
-#include "Transport.h"
#include "WardenWin.h"
-#include "WardenMac.h"
#include "MoveSpline.h"
namespace {
@@ -218,8 +214,8 @@ void WorldSession::SendPacket(WorldPacket* packet)
{
uint64 minTime = uint64(cur_time - lastTime);
uint64 fullTime = uint64(lastTime - firstTime);
- TC_LOG_INFO("misc", "Send all time packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f time: %u", sendPacketCount, sendPacketBytes, float(sendPacketCount)/fullTime, float(sendPacketBytes)/fullTime, uint32(fullTime));
- TC_LOG_INFO("misc", "Send last min packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f", sendLastPacketCount, sendLastPacketBytes, float(sendLastPacketCount)/minTime, float(sendLastPacketBytes)/minTime);
+ TC_LOG_DEBUG("misc", "Send all time packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f time: %u", sendPacketCount, sendPacketBytes, float(sendPacketCount)/fullTime, float(sendPacketBytes)/fullTime, uint32(fullTime));
+ TC_LOG_DEBUG("misc", "Send last min packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f", sendLastPacketCount, sendLastPacketBytes, float(sendLastPacketCount)/minTime, float(sendLastPacketBytes)/minTime);
lastTime = cur_time;
sendLastPacketCount = 1;
@@ -229,6 +225,7 @@ void WorldSession::SendPacket(WorldPacket* packet)
sScriptMgr->OnPacketSend(this, *packet);
+ TC_LOG_TRACE("network.opcode", "S->C: %s %s", GetPlayerInfo().c_str(), GetOpcodeNameForLogging(packet->GetOpcode()).c_str());
m_Socket->SendPacket(*packet);
}
@@ -951,7 +948,7 @@ void WorldSession::ReadAddonsInfo(WorldPacket &data)
if (size > 0xFFFFF)
{
- TC_LOG_ERROR("misc", "WorldSession::ReadAddonsInfo addon info too big, size %u", size);
+ TC_LOG_DEBUG("addon", "WorldSession::ReadAddonsInfo: AddOnInfo too big, size %u", size);
return;
}
@@ -981,7 +978,7 @@ void WorldSession::ReadAddonsInfo(WorldPacket &data)
addonInfo >> enabled >> crc >> unk1;
- TC_LOG_INFO("misc", "ADDON: Name: %s, Enabled: 0x%x, CRC: 0x%x, Unknown2: 0x%x", addonName.c_str(), enabled, crc, unk1);
+ TC_LOG_DEBUG("addon", "AddOn: %s (CRC: 0x%x) - enabled: 0x%x - Unknown2: 0x%x", addonName.c_str(), crc, enabled, unk1);
AddonInfo addon(addonName, enabled, crc, 2, true);
@@ -989,15 +986,14 @@ void WorldSession::ReadAddonsInfo(WorldPacket &data)
if (savedAddon)
{
if (addon.CRC != savedAddon->CRC)
- TC_LOG_INFO("misc", "ADDON: %s was known, but didn't match known CRC (0x%x)!", addon.Name.c_str(), savedAddon->CRC);
+ TC_LOG_WARN("addon", " Addon: %s: modified (CRC: 0x%x) - accountID %d)", addon.Name.c_str(), savedAddon->CRC, GetAccountId());
else
- TC_LOG_INFO("misc", "ADDON: %s was known, CRC is correct (0x%x)", addon.Name.c_str(), savedAddon->CRC);
+ TC_LOG_DEBUG("addon", "Addon: %s: validated (CRC: 0x%x) - accountID %d", addon.Name.c_str(), savedAddon->CRC, GetAccountId());
}
else
{
AddonMgr::SaveAddon(addon);
-
- TC_LOG_INFO("misc", "ADDON: %s (0x%x) was not known, saving...", addon.Name.c_str(), addon.CRC);
+ TC_LOG_WARN("addon", "Addon: %s: unknown (CRC: 0x%x) - accountId %d (storing addon name and checksum to database)", addon.Name.c_str(), addon.CRC, GetAccountId());
}
/// @todo Find out when to not use CRC/pubkey, and other possible states.
@@ -1006,10 +1002,10 @@ void WorldSession::ReadAddonsInfo(WorldPacket &data)
uint32 currentTime;
addonInfo >> currentTime;
- TC_LOG_DEBUG("network", "ADDON: CurrentTime: %u", currentTime);
+ TC_LOG_DEBUG("addon", "AddOn: CurrentTime: %u", currentTime);
}
else
- TC_LOG_ERROR("misc", "Addon packet uncompress error!");
+ TC_LOG_DEBUG("addon", "AddOn: Addon packet uncompress error!");
}
void WorldSession::SendAddonsInfo()
@@ -1048,8 +1044,8 @@ void WorldSession::SendAddonsInfo()
data << uint8(usepk);
if (usepk) // if CRC is wrong, add public key (client need it)
{
- TC_LOG_INFO("misc", "ADDON: CRC (0x%x) for addon %s is wrong (does not match expected 0x%x), sending pubkey",
- itr->CRC, itr->Name.c_str(), STANDARD_ADDON_CRC);
+ TC_LOG_DEBUG("addon", "AddOn: %s: CRC checksum mismatch: got 0x%x - expected 0x%x - sending pubkey to accountID %d",
+ itr->Name.c_str(), itr->CRC, STANDARD_ADDON_CRC, GetAccountId());
data.append(addonPublicKey, sizeof(addonPublicKey));
}
@@ -1262,7 +1258,7 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co
return true;
case POLICY_KICK:
{
- TC_LOG_INFO("network", "AntiDOS: Player kicked!");
+ TC_LOG_WARN("network", "AntiDOS: Player kicked!");
Session->KickPlayer();
return false;
}
@@ -1278,7 +1274,7 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co
case BAN_IP: nameOrIp = Session->GetRemoteAddress(); break;
}
sWorld->BanAccount(bm, nameOrIp, duration, "DOS (Packet Flooding/Spoofing", "Server: AutoDOS");
- TC_LOG_INFO("network", "AntiDOS: Player automatically banned for %u seconds.", duration);
+ TC_LOG_WARN("network", "AntiDOS: Player automatically banned for %u seconds.", duration);
Session->KickPlayer();
return false;
}
@@ -1374,6 +1370,7 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co
case MSG_RANDOM_ROLL: // not profiled
case CMSG_TIME_SYNC_RESP: // not profiled
case CMSG_TRAINER_BUY_SPELL: // not profiled
+ case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: // not profiled
{
// "0" is a magic number meaning there's no limit for the opcode.
// All the opcodes above must cause little CPU usage and no sync/async database queries at all
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index 5b1d9497953..cff423c71c6 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -28,7 +28,7 @@
using boost::asio::ip::tcp;
WorldSocket::WorldSocket(tcp::socket&& socket)
- : Socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr)
+ : Socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), _authed(false)
{
_headerBuffer.Resize(sizeof(ClientPktHeader));
}
@@ -53,7 +53,15 @@ void WorldSocket::HandleSendAuthSession()
seed2.SetRand(16 * 8);
packet.append(seed2.AsByteArray(16).get(), 16); // new encryption seeds
- SendPacket(packet);
+ SendPacketAndLogOpcode(packet);
+}
+
+void WorldSocket::OnClose()
+{
+ {
+ std::lock_guard<std::mutex> sessionGuard(_worldSessionLock);
+ _worldSession = nullptr;
+ }
}
void WorldSocket::ReadHandler()
@@ -80,7 +88,10 @@ void WorldSocket::ReadHandler()
// We just received nice new header
if (!ReadHeaderHandler())
+ {
+ CloseSocket();
return;
+ }
}
// We have full read header, now check the data payload
@@ -101,7 +112,10 @@ void WorldSocket::ReadHandler()
// just received fresh new payload
if (!ReadDataHandler())
+ {
+ CloseSocket();
return;
+ }
_headerBuffer.Reset();
}
@@ -121,17 +135,8 @@ bool WorldSocket::ReadHeaderHandler()
if (!header->IsValidSize() || !header->IsValidOpcode())
{
- if (_worldSession)
- {
- Player* player = _worldSession->GetPlayer();
- TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client (account: %u, char [GUID: %u, name: %s]) sent malformed packet (size: %hu, cmd: %u)",
- _worldSession->GetAccountId(), player ? player->GetGUIDLow() : 0, player ? player->GetName().c_str() : "<none>", header->size, header->cmd);
- }
- else
- TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent malformed packet (size: %hu, cmd: %u)",
- GetRemoteIpAddress().to_string().c_str(), header->size, header->cmd);
-
- CloseSocket();
+ TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent malformed packet (size: %hu, cmd: %u)",
+ GetRemoteIpAddress().to_string().c_str(), header->size, header->cmd);
return false;
}
@@ -146,35 +151,37 @@ bool WorldSocket::ReadDataHandler()
uint16 opcode = uint16(header->cmd);
- std::string opcodeName = GetOpcodeNameForLogging(opcode);
-
WorldPacket packet(opcode, std::move(_packetBuffer));
if (sPacketLog->CanLogPacket())
sPacketLog->LogPacket(packet, CLIENT_TO_SERVER, GetRemoteIpAddress(), GetRemotePort());
- TC_LOG_TRACE("network.opcode", "C->S: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), opcodeName.c_str());
+ std::unique_lock<std::mutex> sessionGuard(_worldSessionLock, std::defer_lock);
switch (opcode)
{
case CMSG_PING:
- HandlePing(packet);
- break;
+ LogOpcodeText(opcode, sessionGuard);
+ return HandlePing(packet);
case CMSG_AUTH_SESSION:
- if (_worldSession)
+ LogOpcodeText(opcode, sessionGuard);
+ if (_authed)
{
- TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from %s", _worldSession->GetPlayerInfo().c_str());
- break;
+ // locking just to safely log offending user is probably overkill but we are disconnecting him anyway
+ if (sessionGuard.try_lock())
+ TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from %s", _worldSession->GetPlayerInfo().c_str());
+ return false;
}
HandleAuthSession(packet);
break;
case CMSG_KEEP_ALIVE:
- TC_LOG_DEBUG("network", "%s", opcodeName.c_str());
- sScriptMgr->OnPacketReceive(_worldSession, packet);
+ LogOpcodeText(opcode, sessionGuard);
break;
default:
{
+ sessionGuard.lock();
+ LogOpcodeText(opcode, sessionGuard);
if (!_worldSession)
{
TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
@@ -195,7 +202,26 @@ bool WorldSocket::ReadDataHandler()
return true;
}
-void WorldSocket::SendPacket(WorldPacket& packet)
+void WorldSocket::LogOpcodeText(uint16 opcode, std::unique_lock<std::mutex> const& guard) const
+{
+ if (!guard)
+ {
+ TC_LOG_TRACE("network.opcode", "C->S: %s %s", GetRemoteIpAddress().to_string().c_str(), GetOpcodeNameForLogging(opcode).c_str());
+ }
+ else
+ {
+ TC_LOG_TRACE("network.opcode", "C->S: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(),
+ GetOpcodeNameForLogging(opcode).c_str());
+ }
+}
+
+void WorldSocket::SendPacketAndLogOpcode(WorldPacket const& packet)
+{
+ TC_LOG_TRACE("network.opcode", "S->C: %s %s", GetRemoteIpAddress().to_string().c_str(), GetOpcodeNameForLogging(packet.GetOpcode()).c_str());
+ SendPacket(packet);
+}
+
+void WorldSocket::SendPacket(WorldPacket const& packet)
{
if (!IsOpen())
return;
@@ -203,8 +229,6 @@ void WorldSocket::SendPacket(WorldPacket& packet)
if (sPacketLog->CanLogPacket())
sPacketLog->LogPacket(packet, SERVER_TO_CLIENT, GetRemoteIpAddress(), GetRemotePort());
- TC_LOG_TRACE("network.opcode", "S->C: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(packet.GetOpcode()).c_str());
-
ServerPktHeader header(packet.size() + 2, packet.GetOpcode());
std::unique_lock<std::mutex> guard(_writeLock);
@@ -257,7 +281,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
recvPacket >> unk4;
recvPacket.read(digest, 20);
- TC_LOG_INFO("network", "WorldSocket::HandleAuthSession: client %u, serverId %u, account %s, loginServerType %u, clientseed %u, realmIndex %u",
+ TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: client %u, serverId %u, account %s, loginServerType %u, clientseed %u, realmIndex %u",
clientBuild,
serverId,
account.c_str(),
@@ -429,7 +453,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType)
{
SendAuthResponseError(AUTH_UNAVAILABLE);
- TC_LOG_INFO("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
+ TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
sScriptMgr->OnFailedAccountLogin(id);
DelayedCloseSocket();
return;
@@ -461,6 +485,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
// At this point, we can safely hook a successful login
sScriptMgr->OnAccountLogin(id);
+ _authed = true;
_worldSession = new WorldSession(id, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter);
_worldSession->LoadGlobalAccountData();
_worldSession->LoadTutorialsData();
@@ -479,10 +504,10 @@ void WorldSocket::SendAuthResponseError(uint8 code)
WorldPacket packet(SMSG_AUTH_RESPONSE, 1);
packet << uint8(code);
- SendPacket(packet);
+ SendPacketAndLogOpcode(packet);
}
-void WorldSocket::HandlePing(WorldPacket& recvPacket)
+bool WorldSocket::HandlePing(WorldPacket& recvPacket)
{
uint32 ping;
uint32 latency;
@@ -511,13 +536,14 @@ void WorldSocket::HandlePing(WorldPacket& recvPacket)
if (maxAllowed && _OverSpeedPings > maxAllowed)
{
+ std::unique_lock<std::mutex> sessionGuard(_worldSessionLock);
+
if (_worldSession && !_worldSession->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_OVERSPEED_PING))
{
TC_LOG_ERROR("network", "WorldSocket::HandlePing: %s kicked for over-speed pings (address: %s)",
_worldSession->GetPlayerInfo().c_str(), GetRemoteIpAddress().to_string().c_str());
- CloseSocket();
- return;
+ return false;
}
}
}
@@ -525,20 +551,23 @@ void WorldSocket::HandlePing(WorldPacket& recvPacket)
_OverSpeedPings = 0;
}
- if (_worldSession)
{
- _worldSession->SetLatency(latency);
- _worldSession->ResetClientTimeDelay();
- }
- else
- {
- TC_LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = %s", GetRemoteIpAddress().to_string().c_str());
+ std::lock_guard<std::mutex> sessionGuard(_worldSessionLock);
- CloseSocket();
- return;
+ if (_worldSession)
+ {
+ _worldSession->SetLatency(latency);
+ _worldSession->ResetClientTimeDelay();
+ }
+ else
+ {
+ TC_LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = %s", GetRemoteIpAddress().to_string().c_str());
+ return false;
+ }
}
WorldPacket packet(SMSG_PONG, 4);
packet << ping;
- return SendPacket(packet);
+ SendPacketAndLogOpcode(packet);
+ return true;
}
diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h
index 89c335662a8..0f6acd0d72c 100644
--- a/src/server/game/Server/WorldSocket.h
+++ b/src/server/game/Server/WorldSocket.h
@@ -55,19 +55,25 @@ public:
void Start() override;
- void SendPacket(WorldPacket& packet);
+ void SendPacket(WorldPacket const& packet);
protected:
+ void OnClose() override;
void ReadHandler() override;
bool ReadHeaderHandler();
bool ReadDataHandler();
private:
+ /// writes network.opcode log
+ /// accessing WorldSession is not threadsafe, only do it when holding _worldSessionLock
+ void LogOpcodeText(uint16 opcode, std::unique_lock<std::mutex> const& guard) const;
+ /// sends and logs network.opcode without accessing WorldSession
+ void SendPacketAndLogOpcode(WorldPacket const& packet);
void HandleSendAuthSession();
void HandleAuthSession(WorldPacket& recvPacket);
void SendAuthResponseError(uint8 code);
- void HandlePing(WorldPacket& recvPacket);
+ bool HandlePing(WorldPacket& recvPacket);
uint32 _authSeed;
AuthCrypt _authCrypt;
@@ -75,7 +81,9 @@ private:
std::chrono::steady_clock::time_point _LastPingTime;
uint32 _OverSpeedPings;
+ std::mutex _worldSessionLock;
WorldSession* _worldSession;
+ bool _authed;
MessageBuffer _headerBuffer;
MessageBuffer _packetBuffer;
diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp
index 947bd62860c..86c09ef6b6b 100644
--- a/src/server/game/Server/WorldSocketMgr.cpp
+++ b/src/server/game/Server/WorldSocketMgr.cpp
@@ -50,7 +50,8 @@ bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string
{
_tcpNoDelay = sConfigMgr->GetBoolDefault("Network.TcpNodelay", true);
- TC_LOG_DEBUG("misc", "Max allowed socket connections %d", boost::asio::socket_base::max_connections);
+ int const max_connections = boost::asio::socket_base::max_connections;
+ TC_LOG_DEBUG("misc", "Max allowed socket connections %d", max_connections);
// -1 means use default
_socketSendBufferSize = sConfigMgr->GetIntDefault("Network.OutKBuff", -1);
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index c267e560005..918b000a557 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -27,12 +27,12 @@
#include "ObjectAccessor.h"
#include "Util.h"
#include "Spell.h"
+#include "SpellHistory.h"
#include "SpellAuraEffects.h"
#include "Battleground.h"
#include "OutdoorPvPMgr.h"
#include "Formulas.h"
#include "GridNotifiers.h"
-#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "ScriptMgr.h"
#include "Vehicle.h"
@@ -542,11 +542,11 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load)
// Haste modifies periodic time of channeled spells
if (m_spellInfo->IsChanneled())
{
- if (m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION))
caster->ModSpellCastTime(m_spellInfo, m_amplitude);
}
// and periodic time of auras affected by SPELL_AURA_PERIODIC_HASTE
- else if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION)
+ else if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION))
m_amplitude = int32(m_amplitude * caster->GetFloatValue(UNIT_MOD_CAST_SPEED));
}
}
@@ -555,7 +555,7 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load)
{
m_tickNumber = m_amplitude ? GetBase()->GetDuration() / m_amplitude : 0;
m_periodicTimer = m_amplitude ? GetBase()->GetDuration() % m_amplitude : 0;
- if (m_spellInfo->AttributesEx5 & SPELL_ATTR5_START_PERIODIC_AT_APPLY)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR5_START_PERIODIC_AT_APPLY))
++m_tickNumber;
}
else // aura just created or reapplied
@@ -571,7 +571,7 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load)
{
m_periodicTimer = 0;
// Start periodic on next tick or at aura apply
- if (m_amplitude && !(m_spellInfo->AttributesEx5 & SPELL_ATTR5_START_PERIODIC_AT_APPLY))
+ if (m_amplitude && !m_spellInfo->HasAttribute(SPELL_ATTR5_START_PERIODIC_AT_APPLY))
m_periodicTimer += m_amplitude;
}
}
@@ -1109,15 +1109,13 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
// Remove cooldown of spells triggered on stance change - they may share cooldown with stance spell
if (spellId)
{
- if (target->GetTypeId() == TYPEID_PLAYER)
- target->ToPlayer()->RemoveSpellCooldown(spellId);
+ target->GetSpellHistory()->ResetCooldown(spellId);
target->CastSpell(target, spellId, true, NULL, this);
}
if (spellId2)
{
- if (target->GetTypeId() == TYPEID_PLAYER)
- target->ToPlayer()->RemoveSpellCooldown(spellId2);
+ target->GetSpellHistory()->ResetCooldown(spellId2);
target->CastSpell(target, spellId2, true, NULL, this);
}
@@ -1133,7 +1131,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
continue;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
- if (!spellInfo || !(spellInfo->Attributes & (SPELL_ATTR0_PASSIVE | SPELL_ATTR0_HIDDEN_CLIENTSIDE)))
+ if (!spellInfo || !(spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE) || spellInfo->HasAttribute(SPELL_ATTR0_HIDDEN_CLIENTSIDE)))
continue;
if (spellInfo->Stances & (1<<(GetMiscValue()-1)))
@@ -1148,7 +1146,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
if (GlyphPropertiesEntry const* glyph = sGlyphPropertiesStore.LookupEntry(glyphId))
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(glyph->SpellId);
- if (!spellInfo || !(spellInfo->Attributes & (SPELL_ATTR0_PASSIVE | SPELL_ATTR0_HIDDEN_CLIENTSIDE)))
+ if (!spellInfo || !(spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE) || spellInfo->HasAttribute(SPELL_ATTR0_HIDDEN_CLIENTSIDE)))
continue;
if (spellInfo->Stances & (1<<(GetMiscValue()-1)))
target->CastSpell(target, glyph->SpellId, true, NULL, this);
@@ -3243,7 +3241,7 @@ void AuraEffect::HandleModStateImmunityMask(AuraApplication const* aurApp, uint8
for (std::list <AuraType>::iterator iter = aura_immunity_list.begin(); iter != aura_immunity_list.end(); ++iter)
target->ApplySpellImmune(GetId(), IMMUNITY_STATE, *iter, apply);
- if (apply && GetSpellInfo()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
+ if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
{
target->RemoveAurasWithMechanic(mechanic_immunity_list, AURA_REMOVE_BY_DEFAULT, GetId());
for (std::list <AuraType>::iterator iter = aura_immunity_list.begin(); iter != aura_immunity_list.end(); ++iter)
@@ -3300,7 +3298,7 @@ void AuraEffect::HandleModMechanicImmunity(AuraApplication const* aurApp, uint8
break;
}
- if (apply && GetSpellInfo()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
+ if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
target->RemoveAurasWithMechanic(mechanic, AURA_REMOVE_BY_DEFAULT, GetId());
}
@@ -3336,7 +3334,7 @@ void AuraEffect::HandleAuraModStateImmunity(AuraApplication const* aurApp, uint8
target->ApplySpellImmune(GetId(), IMMUNITY_STATE, GetMiscValue(), apply);
- if (apply && GetSpellInfo()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
+ if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
target->RemoveAurasByType(AuraType(GetMiscValue()), ObjectGuid::Empty, GetBase());
}
@@ -3372,13 +3370,13 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
// remove all flag auras (they are positive, but they must be removed when you are immune)
- if (GetSpellInfo()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY
- && GetSpellInfo()->AttributesEx2 & SPELL_ATTR2_DAMAGE_REDUCED_SHIELD)
+ if (GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
+ && GetSpellInfo()->HasAttribute(SPELL_ATTR2_DAMAGE_REDUCED_SHIELD))
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
/// @todo optimalize this cycle - use RemoveAurasWithInterruptFlags call or something else
if ((apply)
- && GetSpellInfo()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY
+ && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
&& GetSpellInfo()->IsPositive()) //Only positive immunity removes auras
{
uint32 school_mask = GetMiscValue();
@@ -3759,7 +3757,7 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8
// recalculate current HP/MP after applying aura modifications (only for spells with SPELL_ATTR0_UNK4 0x00000010 flag)
// this check is total bullshit i think
- if (GetMiscValue() == STAT_STAMINA && (m_spellInfo->Attributes & SPELL_ATTR0_ABILITY))
+ if (GetMiscValue() == STAT_STAMINA && m_spellInfo->HasAttribute(SPELL_ATTR0_ABILITY))
target->SetHealth(std::max<uint32>(uint32(healthPct * target->GetMaxHealth() * 0.01f), (alive ? 1 : 0)));
}
@@ -3853,10 +3851,11 @@ void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint
}
else
{
- if (int32(target->GetHealth()) > GetAmount())
- target->ModifyHealth(-GetAmount());
- else
- target->SetHealth(1);
+ if (target->GetHealth() > 0)
+ {
+ int32 value = std::min<int32>(target->GetHealth() - 1, GetAmount());
+ target->ModifyHealth(-value);
+ }
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
}
}
@@ -3868,19 +3867,15 @@ void AuraEffect::HandleAuraModIncreaseMaxHealth(AuraApplication const* aurApp, u
Unit* target = aurApp->GetTarget();
- uint32 oldhealth = target->GetHealth();
- double healthPercentage = (double)oldhealth / (double)target->GetMaxHealth();
+ float percent = target->GetHealthPct();
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
// refresh percentage
- if (oldhealth > 0)
+ if (target->GetHealth() > 0)
{
- uint32 newhealth = uint32(ceil((double)target->GetMaxHealth() * healthPercentage));
- if (newhealth == 0)
- newhealth = 1;
-
- target->SetHealth(newhealth);
+ uint32 newHealth = std::max<uint32>(target->CountPctFromMaxHealth(int32(percent)), 1);
+ target->SetHealth(newHealth);
}
}
@@ -3944,8 +3939,12 @@ void AuraEffect::HandleAuraModIncreaseHealthPercent(AuraApplication const* aurAp
// Unit will keep hp% after MaxHealth being modified if unit is alive.
float percent = target->GetHealthPct();
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount()), apply);
- if (target->IsAlive())
- target->SetHealth(target->CountPctFromMaxHealth(int32(percent)));
+
+ if (target->GetHealth() > 0)
+ {
+ uint32 newHealth = std::max<uint32>(target->CountPctFromMaxHealth(int32(percent)), 1);
+ target->SetHealth(newHealth);
+ }
}
void AuraEffect::HandleAuraIncreaseBaseHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -5846,6 +5845,9 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
else
damage = std::max(int32(damage * GetDonePct()), 0);
+ if (Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage);
+
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
// Calculate armor mitigation
@@ -5901,7 +5903,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
else
damage = uint32(target->CountPctFromMaxHealth(damage));
- if (!(m_spellInfo->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura)
{
damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
@@ -5918,7 +5920,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target);
int32 dmg = damage;
- if (!(GetSpellInfo()->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE))
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
caster->ApplyResilience(target, NULL, &dmg, crit, CR_CRIT_TAKEN_SPELL);
damage = dmg;
@@ -5978,7 +5980,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
if (isAreaAura)
damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellDamagePctDone(target, m_spellInfo, DOT);
else
- damage = std::max(int32(damage * GetDonePct()), 0);
+ damage = std::max(int32(damage * GetDonePct()), 0);
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
@@ -5990,7 +5992,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
damage = damageReductedArmor;
}
- if (!(m_spellInfo->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura)
{
damage = uint32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
@@ -6007,7 +6009,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target);
int32 dmg = damage;
- if (!(GetSpellInfo()->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE))
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
caster->ApplyResilience(target, NULL, &dmg, crit, CR_CRIT_TAKEN_SPELL);
damage = dmg;
@@ -6083,7 +6085,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
}
// heal for caster damage (must be alive)
- if (target != caster && GetSpellInfo()->AttributesEx2 & SPELL_ATTR2_HEALTH_FUNNEL && !caster->IsAlive())
+ if (target != caster && GetSpellInfo()->HasAttribute(SPELL_ATTR2_HEALTH_FUNNEL) && !caster->IsAlive())
return;
// don't regen when permanent aura target has full power
@@ -6149,6 +6151,9 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
else
damage = std::max(int32(damage * GetDonePct()), 0);
+ if (Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage);
+
damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
}
@@ -6177,7 +6182,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
// Health Funnel
// damage caster for heal amount
- if (target != caster && GetSpellInfo()->AttributesEx2 & SPELL_ATTR2_HEALTH_FUNNEL)
+ if (target != caster && GetSpellInfo()->HasAttribute(SPELL_ATTR2_HEALTH_FUNNEL))
{
uint32 funnelDamage = GetSpellInfo()->ManaPerSecond; // damage is not affected by spell power
@@ -6308,7 +6313,7 @@ void AuraEffect::HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) cons
{
Powers powerType = Powers(GetMiscValue());
- if (target->GetTypeId() == TYPEID_PLAYER && target->getPowerType() != powerType && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
+ if (target->GetTypeId() == TYPEID_PLAYER && target->getPowerType() != powerType && !m_spellInfo->HasAttribute(SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
return;
if (!target->IsAlive() || !target->GetMaxPower(powerType))
@@ -6418,6 +6423,9 @@ void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp
void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
+ if (!aurApp)
+ return;
+
Unit* target = aurApp->GetTarget();
Unit* triggerTarget = eventInfo.GetProcTarget();
SpellNonMeleeDamage damageInfo(target, triggerTarget, GetId(), GetSpellInfo()->SchoolMask);
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 93a4c96b92f..5479dcdbf00 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -25,6 +25,7 @@
#include "Player.h"
#include "Unit.h"
#include "Spell.h"
+#include "SpellHistory.h"
#include "SpellAuraEffects.h"
#include "DynamicObject.h"
#include "ObjectAccessor.h"
@@ -191,7 +192,7 @@ void AuraApplication::BuildUpdatePacket(ByteBuffer& data, bool remove) const
Aura const* aura = GetBase();
data << uint32(aura->GetId());
uint32 flags = _flags;
- if (aura->GetMaxDuration() > 0 && !(aura->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_HIDE_DURATION))
+ if (aura->GetMaxDuration() > 0 && !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR5_HIDE_DURATION))
flags |= AFLAG_DURATION;
data << uint8(flags);
data << uint8(aura->GetCasterLevel());
@@ -418,7 +419,7 @@ void Aura::_ApplyForTarget(Unit* target, Unit* caster, AuraApplication * auraApp
if (m_spellInfo->IsCooldownStartedOnEvent())
{
Item* castItem = m_castItemGuid ? caster->ToPlayer()->GetItemByGuid(m_castItemGuid) : NULL;
- caster->ToPlayer()->AddSpellAndCategoryCooldowns(m_spellInfo, castItem ? castItem->GetEntry() : 0, NULL, true);
+ caster->GetSpellHistory()->StartCooldown(m_spellInfo, castItem ? castItem->GetEntry() : 0, nullptr, true);
}
}
}
@@ -446,12 +447,9 @@ void Aura::_UnapplyForTarget(Unit* target, Unit* caster, AuraApplication * auraA
m_removedApplications.push_back(auraApp);
// reset cooldown state for spells
- if (caster && caster->GetTypeId() == TYPEID_PLAYER)
- {
- if (GetSpellInfo()->IsCooldownStartedOnEvent())
- // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
- caster->ToPlayer()->SendCooldownEvent(GetSpellInfo());
- }
+ if (caster && GetSpellInfo()->IsCooldownStartedOnEvent())
+ // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
+ caster->GetSpellHistory()->SendCooldownEvent(GetSpellInfo());
}
// removes aura from all targets
@@ -749,12 +747,13 @@ void Aura::SetDuration(int32 duration, bool withMods)
void Aura::RefreshDuration(bool withMods)
{
- if (withMods)
+ Unit* caster = GetCaster();
+ if (withMods && caster)
{
int32 duration = m_spellInfo->GetMaxDuration();
// Calculate duration of periodics affected by haste.
- if (GetCaster()->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION)
- duration = int32(duration * GetCaster()->GetFloatValue(UNIT_MOD_CAST_SPEED));
+ if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION))
+ duration = int32(duration * caster->GetFloatValue(UNIT_MOD_CAST_SPEED));
SetMaxDuration(duration);
SetDuration(duration);
@@ -1214,7 +1213,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
break;
case 60970: // Heroic Fury (remove Intercept cooldown)
if (target->GetTypeId() == TYPEID_PLAYER)
- target->ToPlayer()->RemoveSpellCooldown(20252, true);
+ target->GetSpellHistory()->ResetCooldown(20252, true);
break;
}
break;
@@ -1496,15 +1495,15 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
// check cooldown
if (caster->GetTypeId() == TYPEID_PLAYER)
{
- if (caster->ToPlayer()->HasSpellCooldown(aura->GetId()))
+ if (caster->GetSpellHistory()->HasCooldown(aura->GetId()))
{
// This additional check is needed to add a minimal delay before cooldown in in effect
// to allow all bubbles broken by a single damage source proc mana return
- if (caster->ToPlayer()->GetSpellCooldownDelay(aura->GetId()) <= 11)
+ if (caster->GetSpellHistory()->GetRemainingCooldown(aura->GetId()) <= 11)
break;
}
else // and add if needed
- caster->ToPlayer()->AddSpellCooldown(aura->GetId(), 0, uint32(time(NULL) + 12));
+ caster->GetSpellHistory()->AddCooldown(aura->GetId(), 0, std::chrono::seconds(12));
}
// effect on caster
@@ -1557,14 +1556,14 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
// Glyph of Guardian Spirit
if (AuraEffect* aurEff = player->GetAuraEffect(63231, 0))
{
- if (!player->HasSpellCooldown(47788))
+ if (!player->GetSpellHistory()->HasCooldown(47788))
break;
- player->RemoveSpellCooldown(GetSpellInfo()->Id, true);
- player->AddSpellCooldown(GetSpellInfo()->Id, 0, uint32(time(NULL) + aurEff->GetAmount()));
+ player->GetSpellHistory()->ResetCooldown(GetSpellInfo()->Id, true);
+ player->GetSpellHistory()->AddCooldown(GetSpellInfo()->Id, 0, std::chrono::seconds(aurEff->GetAmount()));
WorldPacket data;
- player->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, GetSpellInfo()->Id, aurEff->GetAmount()*IN_MILLISECONDS);
+ player->GetSpellHistory()->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, GetSpellInfo()->Id, aurEff->GetAmount() * IN_MILLISECONDS);
player->SendDirectMessage(&data);
}
break;
@@ -1813,7 +1812,7 @@ bool Aura::CanStackWith(Aura const* existingAura) const
if (existingAura->GetSpellInfo()->IsChanneled())
return true;
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_STACK_FOR_DIFF_CASTERS)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_STACK_FOR_DIFF_CASTERS))
return true;
// check same periodic auras
@@ -1865,7 +1864,7 @@ bool Aura::CanStackWith(Aura const* existingAura) const
if (m_spellInfo->IsMultiSlotAura() && !IsArea())
return true;
if (GetCastItemGUID() && existingAura->GetCastItemGUID())
- if (GetCastItemGUID() != existingAura->GetCastItemGUID() && (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_ENCHANT_PROC))
+ if (GetCastItemGUID() != existingAura->GetCastItemGUID() && m_spellInfo->HasAttribute(SPELL_ATTR0_CU_ENCHANT_PROC))
return true;
// same spell with same caster should not stack
return false;
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index ac45461b333..6abcd578411 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -161,8 +161,8 @@ class Aura
{
return GetCasterGUID() == target->GetGUID()
&& m_spellInfo->Stances
- && !(m_spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_NEED_SHAPESHIFT)
- && !(m_spellInfo->Attributes & SPELL_ATTR0_NOT_SHAPESHIFT);
+ && !m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_NEED_SHAPESHIFT)
+ && !m_spellInfo->HasAttribute(SPELL_ATTR0_NOT_SHAPESHIFT);
}
bool CanBeSaved() const;
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 8f8295d57d1..94bb90487bc 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -31,12 +31,9 @@
#include "Player.h"
#include "Pet.h"
#include "Unit.h"
-#include "Totem.h"
#include "Spell.h"
#include "DynamicObject.h"
-#include "Group.h"
#include "UpdateData.h"
-#include "MapManager.h"
#include "ObjectAccessor.h"
#include "CellImpl.h"
#include "SharedDefines.h"
@@ -53,6 +50,7 @@
#include "SpellScript.h"
#include "InstanceScript.h"
#include "SpellInfo.h"
+#include "SpellHistory.h"
#include "Battlefield.h"
#include "BattlefieldMgr.h"
@@ -482,23 +480,23 @@ void SpellCastTargets::Update(Unit* caster)
void SpellCastTargets::OutDebug() const
{
if (!m_targetMask)
- TC_LOG_INFO("spells", "No targets");
+ TC_LOG_DEBUG("spells", "No targets");
- TC_LOG_INFO("spells", "target mask: %u", m_targetMask);
+ TC_LOG_DEBUG("spells", "target mask: %u", m_targetMask);
if (m_targetMask & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_GAMEOBJECT_MASK))
- TC_LOG_INFO("spells", "Object target: %s", m_objectTargetGUID.ToString().c_str());
+ TC_LOG_DEBUG("spells", "Object target: %s", m_objectTargetGUID.ToString().c_str());
if (m_targetMask & TARGET_FLAG_ITEM)
- TC_LOG_INFO("spells", "Item target: %s", m_itemTargetGUID.ToString().c_str());
+ TC_LOG_DEBUG("spells", "Item target: %s", m_itemTargetGUID.ToString().c_str());
if (m_targetMask & TARGET_FLAG_TRADE_ITEM)
- TC_LOG_INFO("spells", "Trade item target: %s", m_itemTargetGUID.ToString().c_str());
+ TC_LOG_DEBUG("spells", "Trade item target: %s", m_itemTargetGUID.ToString().c_str());
if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
- TC_LOG_INFO("spells", "Source location: transport guid:%s trans offset: %s position: %s", m_src._transportGUID.ToString().c_str(), m_src._transportOffset.ToString().c_str(), m_src._position.ToString().c_str());
+ TC_LOG_DEBUG("spells", "Source location: transport guid:%s trans offset: %s position: %s", m_src._transportGUID.ToString().c_str(), m_src._transportOffset.ToString().c_str(), m_src._position.ToString().c_str());
if (m_targetMask & TARGET_FLAG_DEST_LOCATION)
- TC_LOG_INFO("spells", "Destination location: transport guid:%s trans offset: %s position: %s", m_dst._transportGUID.ToString().c_str(), m_dst._transportOffset.ToString().c_str(), m_dst._position.ToString().c_str());
+ TC_LOG_DEBUG("spells", "Destination location: transport guid:%s trans offset: %s position: %s", m_dst._transportGUID.ToString().c_str(), m_dst._transportOffset.ToString().c_str(), m_dst._position.ToString().c_str());
if (m_targetMask & TARGET_FLAG_STRING)
- TC_LOG_INFO("spells", "String: %s", m_strTarget.c_str());
- TC_LOG_INFO("spells", "speed: %f", m_speed);
- TC_LOG_INFO("spells", "elevation: %f", m_elevation);
+ TC_LOG_DEBUG("spells", "String: %s", m_strTarget.c_str());
+ TC_LOG_DEBUG("spells", "speed: %f", m_speed);
+ TC_LOG_DEBUG("spells", "elevation: %f", m_elevation);
}
SpellValue::SpellValue(SpellInfo const* proto)
@@ -512,7 +510,7 @@ SpellValue::SpellValue(SpellInfo const* proto)
Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID, bool skipCheck) :
m_spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(info, caster)),
-m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster)
+m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster)
, m_spellValue(new SpellValue(m_spellInfo)), m_preGeneratedPath(PathGenerator(m_caster))
{
m_customError = SPELL_CUSTOM_ERROR_NONE;
@@ -533,7 +531,7 @@ m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharme
switch (m_spellInfo->DmgClass)
{
case SPELL_DAMAGE_CLASS_MELEE:
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_REQ_OFFHAND)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_REQ_OFFHAND))
m_attackType = OFF_ATTACK;
else
m_attackType = BASE_ATTACK;
@@ -543,7 +541,7 @@ m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharme
break;
default:
// Wands
- if (m_spellInfo->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG))
m_attackType = RANGED_ATTACK;
else
m_attackType = BASE_ATTACK;
@@ -574,7 +572,7 @@ m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharme
m_spellState = SPELL_STATE_NULL;
_triggeredCastFlags = triggerFlags;
- if (info->AttributesEx4 & SPELL_ATTR4_CAN_CAST_WHILE_CASTING)
+ if (info->HasAttribute(SPELL_ATTR4_CAN_CAST_WHILE_CASTING))
_triggeredCastFlags = TriggerCastFlags(uint32(_triggeredCastFlags) | TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_CAST_DIRECTLY);
m_CastItem = NULL;
@@ -615,8 +613,8 @@ m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharme
// Determine if spell can be reflected back to the caster
// Patch 1.2 notes: Spell Reflection no longer reflects abilities
- m_canReflect = m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !(m_spellInfo->Attributes & SPELL_ATTR0_ABILITY)
- && !(m_spellInfo->AttributesEx & SPELL_ATTR1_CANT_BE_REFLECTED) && !(m_spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ m_canReflect = m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !m_spellInfo->HasAttribute(SPELL_ATTR0_ABILITY)
+ && !m_spellInfo->HasAttribute(SPELL_ATTR1_CANT_BE_REFLECTED) && !m_spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
&& !m_spellInfo->IsPassive() && !m_spellInfo->IsPositive();
CleanupTargetList();
@@ -1749,11 +1747,11 @@ uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList*
default:
break;
}
- if (!(m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_DEAD))
retMask &= ~GRID_MAP_TYPE_MASK_CORPSE;
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS))
retMask &= GRID_MAP_TYPE_MASK_CORPSE | GRID_MAP_TYPE_MASK_PLAYER;
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_GHOSTS))
retMask &= GRID_MAP_TYPE_MASK_PLAYER;
if (condList)
@@ -1843,7 +1841,7 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
}
// chain lightning/heal spells and similar - allow to jump at larger distance and go out of los
- bool isBouncingFar = (m_spellInfo->AttributesEx4 & SPELL_ATTR4_AREA_TARGET_CHAIN
+ bool isBouncingFar = (m_spellInfo->HasAttribute(SPELL_ATTR4_AREA_TARGET_CHAIN)
|| m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_NONE
|| m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC);
@@ -1944,7 +1942,7 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
break;
case SPELL_DAMAGE_CLASS_RANGED:
// Auto attack
- if (m_spellInfo->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG))
{
m_procAttacker = PROC_FLAG_DONE_RANGED_AUTO_ATTACK;
m_procVictim = PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK;
@@ -1958,7 +1956,7 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
default:
if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON &&
m_spellInfo->EquippedItemSubClassMask & (1<<ITEM_SUBCLASS_WEAPON_WAND)
- && m_spellInfo->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG) // Wands auto attack
+ && m_spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG)) // Wands auto attack
{
m_procAttacker = PROC_FLAG_DONE_RANGED_AUTO_ATTACK;
m_procVictim = PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK;
@@ -1990,8 +1988,8 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
if (!(m_procAttacker & PROC_FLAG_DONE_RANGED_AUTO_ATTACK))
{
if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS &&
- (m_spellInfo->AttributesEx2 & SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC ||
- m_spellInfo->AttributesEx3 & SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2))
+ (m_spellInfo->HasAttribute(SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC) ||
+ m_spellInfo->HasAttribute(SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2)))
m_procEx |= PROC_EX_INTERNAL_CANT_PROC;
else if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS)
m_procEx |= PROC_EX_INTERNAL_TRIGGERED;
@@ -2275,7 +2273,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
m_spellAura = NULL; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied
//Spells with this flag cannot trigger if effect is cast on self
- bool canEffectTrigger = !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_CANT_TRIGGER_PROC) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2);
+ bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2);
Unit* spellHitTarget = NULL;
if (missInfo == SPELL_MISS_NONE) // In case spell hit target, do all effect on that target
@@ -2395,7 +2393,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
{
caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
- if (caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->Attributes & SPELL_ATTR0_STOP_ATTACK_TARGET) == 0 &&
+ if (caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) == 0 &&
(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx);
}
@@ -2415,7 +2413,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
caster->ProcDamageAndSpell(unit, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
// Failed Pickpocket, reveal rogue
- if (missInfo == SPELL_MISS_RESIST && m_spellInfo->AttributesCu & SPELL_ATTR0_CU_PICKPOCKET && unitTarget->GetTypeId() == TYPEID_UNIT)
+ if (missInfo == SPELL_MISS_RESIST && m_spellInfo->HasAttribute(SPELL_ATTR0_CU_PICKPOCKET) && unitTarget->GetTypeId() == TYPEID_UNIT)
{
m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK);
if (unitTarget->ToCreature()->IsAIEnabled)
@@ -2425,9 +2423,9 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (missInfo != SPELL_MISS_EVADE && !m_caster->IsFriendlyTo(unit) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)))
{
- m_caster->CombatStart(unit, !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO));
+ m_caster->CombatStart(unit, !m_spellInfo->HasAttribute(SPELL_ATTR3_NO_INITIAL_AGGRO));
- if (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_AURA_CC)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_AURA_CC))
if (!unit->IsStandState())
unit->SetStandState(UNIT_STAND_STATE_STAND);
}
@@ -2514,7 +2512,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
{
unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_HITBYSPELL);
/// @todo This is a hack. But we do not know what types of stealth should be interrupted by CC
- if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_AURA_CC) && unit->IsControlledByPlayer())
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_AURA_CC) && unit->IsControlledByPlayer())
unit->RemoveAurasByType(SPELL_AURA_MOD_STEALTH);
}
else if (m_caster->IsFriendlyTo(unit))
@@ -2532,7 +2530,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
if (m_caster->GetTypeId() == TYPEID_PLAYER)
m_caster->ToPlayer()->UpdatePvP(true);
}
- if (unit->IsInCombat() && !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO))
+ if (unit->IsInCombat() && !m_spellInfo->HasAttribute(SPELL_ATTR3_NO_INITIAL_AGGRO))
{
m_caster->SetInCombatState(unit->GetCombatTimer() > 0, unit);
unit->getHostileRefManager().threatAssist(m_caster, 0.0f);
@@ -2625,7 +2623,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
if (m_spellInfo->IsChanneled())
m_originalCaster->ModSpellCastTime(aurSpellInfo, duration, this);
// and duration of auras affected by SPELL_AURA_PERIODIC_HASTE
- else if (m_originalCaster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, aurSpellInfo) || m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION)
+ else if (m_originalCaster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, aurSpellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION))
duration = int32(duration * m_originalCaster->GetFloatValue(UNIT_MOD_CAST_SPEED));
if (duration != m_spellAura->GetMaxDuration())
@@ -3192,7 +3190,7 @@ void Spell::cast(bool skipCheck)
SendSpellGo();
// Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
- if ((m_spellInfo->Speed > 0.0f && !m_spellInfo->IsChanneled()) || m_spellInfo->AttributesEx4 & SPELL_ATTR4_UNK4)
+ if ((m_spellInfo->Speed > 0.0f && !m_spellInfo->IsChanneled()) || m_spellInfo->HasAttribute(SPELL_ATTR4_UNK4))
{
// Remove used for cast item if need (it can be already NULL after TakeReagents call
// in case delayed spell remove item at cast delay start
@@ -3229,7 +3227,7 @@ void Spell::cast(bool skipCheck)
//Clear spell cooldowns after every spell is cast if .cheat cooldown is enabled.
if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_COOLDOWN))
- m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id, true);
+ m_caster->GetSpellHistory()->ResetCooldown(m_spellInfo->Id, true);
}
SetExecutedCurrently(false);
@@ -3433,30 +3431,7 @@ void Spell::_handle_finish_phase()
void Spell::SendSpellCooldown()
{
- Player* _player = m_caster->ToPlayer();
- if (!_player)
- {
- // Handle pet cooldowns here if needed instead of in PetAI to avoid hidden cooldown restarts
- Creature* _creature = m_caster->ToCreature();
- if (_creature && (_creature->IsPet() || _creature->IsGuardian()))
- _creature->AddCreatureSpellCooldown(m_spellInfo->Id);
-
- return;
- }
-
- // mana/health/etc potions, disabled by client (until combat out as declarate)
- if (m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent()))
- {
- // need in some way provided data for Spell::finish SendCooldownEvent
- _player->SetLastPotionId(m_CastItem->GetEntry());
- return;
- }
-
- // have infinity cooldown but set at aura apply // do not set cooldown for triggered spells (needed by reincarnation)
- if (m_spellInfo->IsCooldownStartedOnEvent() || m_spellInfo->IsPassive() || (_triggeredCastFlags & TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD))
- return;
-
- _player->AddSpellAndCategoryCooldowns(m_spellInfo, m_CastItem ? m_CastItem->GetEntry() : 0, this);
+ m_caster->GetSpellHistory()->HandleCooldowns(m_spellInfo, m_CastItem, this);
}
void Spell::update(uint32 difftime)
@@ -3592,7 +3567,7 @@ void Spell::finish(bool ok)
break;
}
}
- if (!found && !(m_spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
+ if (!found && !m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
{
m_caster->resetAttackTimer(BASE_ATTACK);
if (m_caster->haveOffhandWeapon())
@@ -3618,7 +3593,7 @@ void Spell::finish(bool ok)
}
// Stop Attack for some spells
- if (m_spellInfo->Attributes & SPELL_ATTR0_STOP_ATTACK_TARGET)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET))
m_caster->AttackStop();
}
@@ -3783,7 +3758,7 @@ void Spell::SendSpellStart()
if ((IsTriggered() && !m_spellInfo->IsAutoRepeatRangedSpell()) || m_triggeredByAuraSpell)
castFlags |= CAST_FLAG_PENDING;
- if (m_spellInfo->Attributes & SPELL_ATTR0_REQ_AMMO)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO))
castFlags |= CAST_FLAG_AMMO;
if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
(m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsPet()))
@@ -3836,7 +3811,7 @@ void Spell::SendSpellGo()
if ((IsTriggered() && !m_spellInfo->IsAutoRepeatRangedSpell()) || m_triggeredByAuraSpell)
castFlags |= CAST_FLAG_PENDING;
- if (m_spellInfo->Attributes & SPELL_ATTR0_REQ_AMMO)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO))
castFlags |= CAST_FLAG_AMMO; // arrows/bullets visual
if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
@@ -4230,7 +4205,7 @@ void Spell::SendResurrectRequest(Player* target)
data << uint8(m_caster->GetTypeId() == TYPEID_PLAYER ? 0 : 1); // "you'll be afflicted with resurrection sickness"
// override delay sent with SMSG_CORPSE_RECLAIM_DELAY, set instant resurrection for spells with this attribute
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_RESURRECTION_TIMER)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_RESURRECTION_TIMER))
data << uint32(0);
target->GetSession()->SendPacket(&data);
}
@@ -4561,8 +4536,8 @@ void Spell::HandleThreatSpells()
if (m_UniqueTargetInfo.empty())
return;
- if ((m_spellInfo->AttributesEx & SPELL_ATTR1_NO_THREAT) ||
- (m_spellInfo->AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR1_NO_THREAT) ||
+ m_spellInfo->HasAttribute(SPELL_ATTR3_NO_INITIAL_AGGRO))
return;
float threat = 0.0f;
@@ -4573,7 +4548,7 @@ void Spell::HandleThreatSpells()
threat += threatEntry->flatMod;
}
- else if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_NO_INITIAL_THREAT) == 0)
+ else if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NO_INITIAL_THREAT) == 0)
threat += m_spellInfo->SpellLevel;
// past this point only multiplicative effects occur
@@ -4634,30 +4609,33 @@ void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOT
SpellCastResult Spell::CheckCast(bool strict)
{
// check death state
- if (!m_caster->IsAlive() && !(m_spellInfo->Attributes & SPELL_ATTR0_PASSIVE) && !((m_spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD) || (IsTriggered() && !m_triggeredByAuraSpell)))
+ if (!m_caster->IsAlive() && !m_spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE) && !(m_spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD) || (IsTriggered() && !m_triggeredByAuraSpell)))
return SPELL_FAILED_CASTER_DEAD;
// check cooldowns to prevent cheating
- if (m_caster->GetTypeId() == TYPEID_PLAYER && !(m_spellInfo->Attributes & SPELL_ATTR0_PASSIVE))
+ if (!m_spellInfo->IsPassive())
{
- //can cast triggered (by aura only?) spells while have this flag
- if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE) && m_caster->ToPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY))
- return SPELL_FAILED_SPELL_IN_PROGRESS;
+ if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ //can cast triggered (by aura only?) spells while have this flag
+ if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE) && m_caster->ToPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY))
+ return SPELL_FAILED_SPELL_IN_PROGRESS;
- if (m_caster->ToPlayer()->HasSpellCooldown(m_spellInfo->Id))
+ // check if we are using a potion in combat for the 2nd+ time. Cooldown is added only after caster gets out of combat
+ if (m_caster->ToPlayer()->GetLastPotionId() && m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent()))
+ return SPELL_FAILED_NOT_READY;
+ }
+
+ if (!m_caster->GetSpellHistory()->IsReady(m_spellInfo))
{
if (m_triggeredByAuraSpell)
return SPELL_FAILED_DONT_REPORT;
else
return SPELL_FAILED_NOT_READY;
}
-
- // check if we are using a potion in combat for the 2nd+ time. Cooldown is added only after caster gets out of combat
- if (m_caster->ToPlayer()->GetLastPotionId() && m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent()))
- return SPELL_FAILED_NOT_READY;
}
- if (m_spellInfo->AttributesEx7 & SPELL_ATTR7_IS_CHEAT_SPELL && !m_caster->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR7_IS_CHEAT_SPELL) && !m_caster->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS))
{
m_customError = SPELL_CUSTOM_ERROR_GM_ONLY;
return SPELL_FAILED_CUSTOM_ERROR;
@@ -4675,11 +4653,11 @@ SpellCastResult Spell::CheckCast(bool strict)
if (m_caster->GetTypeId() == TYPEID_PLAYER && VMAP::VMapFactory::createOrGetVMapManager()->isLineOfSightCalcEnabled())
{
- if (m_spellInfo->Attributes & SPELL_ATTR0_OUTDOORS_ONLY &&
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_OUTDOORS_ONLY) &&
!m_caster->GetMap()->IsOutdoors(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ()))
return SPELL_FAILED_ONLY_OUTDOORS;
- if (m_spellInfo->Attributes & SPELL_ATTR0_INDOORS_ONLY &&
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_INDOORS_ONLY) &&
m_caster->GetMap()->IsOutdoors(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ()))
return SPELL_FAILED_ONLY_INDOORS;
}
@@ -4705,7 +4683,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (shapeError != SPELL_CAST_OK)
return shapeError;
- if ((m_spellInfo->Attributes & SPELL_ATTR0_ONLY_STEALTHED) && !(m_caster->HasStealthAura()))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_ONLY_STEALTHED) && !(m_caster->HasStealthAura()))
return SPELL_FAILED_ONLY_STEALTHED;
}
}
@@ -4791,7 +4769,7 @@ SpellCastResult Spell::CheckCast(bool strict)
// those spells may have incorrect target entries or not filled at all (for example 15332)
// such spells when learned are not targeting anyone using targeting system, they should apply directly to caster instead
// also, such casts shouldn't be sent to client
- if (!((m_spellInfo->Attributes & SPELL_ATTR0_PASSIVE) && (!m_targets.GetUnitTarget() || m_targets.GetUnitTarget() == m_caster)))
+ if (!(m_spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE) && (!m_targets.GetUnitTarget() || m_targets.GetUnitTarget() == m_caster)))
{
// Check explicit target for m_originalCaster - todo: get rid of such workarounds
SpellCastResult castResult = m_spellInfo->CheckExplicitTarget(m_originalCaster ? m_originalCaster : m_caster, m_targets.GetObjectTarget(), m_targets.GetItemTarget());
@@ -4808,11 +4786,11 @@ SpellCastResult Spell::CheckCast(bool strict)
if (target != m_caster)
{
// Must be behind the target
- if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET) && target->HasInArc(static_cast<float>(M_PI), m_caster))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET) && target->HasInArc(static_cast<float>(M_PI), m_caster))
return SPELL_FAILED_NOT_BEHIND;
// Target must be facing you
- if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER) && !target->HasInArc(static_cast<float>(M_PI), m_caster))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER) && !target->HasInArc(static_cast<float>(M_PI), m_caster))
return SPELL_FAILED_NOT_INFRONT;
if (m_caster->GetEntry() != WORLD_TRIGGER) // Ignore LOS for gameobjects casts (wrongly cast by a trigger)
@@ -4822,7 +4800,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (DynamicObject* dynObj = m_caster->GetDynObject(m_triggeredByAuraSpell->Id))
losTarget = dynObj;
- if (!(m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !target->IsWithinLOSInMap(losTarget))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !target->IsWithinLOSInMap(losTarget))
return SPELL_FAILED_LINE_OF_SIGHT;
}
}
@@ -4834,7 +4812,7 @@ SpellCastResult Spell::CheckCast(bool strict)
float x, y, z;
m_targets.GetDstPos()->GetPosition(x, y, z);
- if (!(m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !m_caster->IsWithinLOS(x, y, z))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !m_caster->IsWithinLOS(x, y, z))
return SPELL_FAILED_LINE_OF_SIGHT;
}
@@ -4855,15 +4833,15 @@ SpellCastResult Spell::CheckCast(bool strict)
}
// Spell cast only in battleground
- if ((m_spellInfo->AttributesEx3 & SPELL_ATTR3_BATTLEGROUND) && m_caster->GetTypeId() == TYPEID_PLAYER)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_BATTLEGROUND) && m_caster->GetTypeId() == TYPEID_PLAYER)
if (!m_caster->ToPlayer()->InBattleground())
return SPELL_FAILED_ONLY_BATTLEGROUNDS;
// do not allow spells to be cast in arenas
// - with greater than 10 min CD without SPELL_ATTR4_USABLE_IN_ARENA flag
// - with SPELL_ATTR4_NOT_USABLE_IN_ARENA flag
- if ((m_spellInfo->AttributesEx4 & SPELL_ATTR4_NOT_USABLE_IN_ARENA) ||
- (m_spellInfo->GetRecoveryTime() > 10 * MINUTE * IN_MILLISECONDS && !(m_spellInfo->AttributesEx4 & SPELL_ATTR4_USABLE_IN_ARENA)))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR4_NOT_USABLE_IN_ARENA) ||
+ (m_spellInfo->GetRecoveryTime() > 10 * MINUTE * IN_MILLISECONDS && !m_spellInfo->HasAttribute(SPELL_ATTR4_USABLE_IN_ARENA)))
if (MapEntry const* mapEntry = sMapStore.LookupEntry(m_caster->GetMapId()))
if (mapEntry->IsBattleArena())
return SPELL_FAILED_NOT_IN_ARENA;
@@ -4881,7 +4859,7 @@ SpellCastResult Spell::CheckCast(bool strict)
// not let players cast spells at mount (and let do it to creatures)
if (m_caster->IsMounted() && m_caster->GetTypeId() == TYPEID_PLAYER && !(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE) &&
- !m_spellInfo->IsPassive() && !(m_spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_MOUNTED))
+ !m_spellInfo->IsPassive() && !m_spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_MOUNTED))
{
if (m_caster->IsInFlight())
return SPELL_FAILED_NOT_ON_TAXI;
@@ -4938,7 +4916,7 @@ SpellCastResult Spell::CheckCast(bool strict)
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_DISPEL)
{
- if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->AttributesEx & SPELL_ATTR1_MELEE_COMBAT_START)
+ if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->HasAttribute(SPELL_ATTR1_MELEE_COMBAT_START))
{
hasDispellableAura = true;
break;
@@ -5507,13 +5485,13 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
}
// cooldown
- if (Creature const* creatureCaster = m_caster->ToCreature())
- if (creatureCaster->HasSpellCooldown(m_spellInfo->Id))
+ if (Creature* creatureCaster = m_caster->ToCreature())
+ if (!creatureCaster->GetSpellHistory()->IsReady(m_spellInfo))
return SPELL_FAILED_NOT_READY;
// Check if spell is affected by GCD
if (m_spellInfo->StartRecoveryCategory > 0)
- if (m_caster->GetCharmInfo() && m_caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo))
+ if (m_caster->GetCharmInfo() && m_caster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo))
return SPELL_FAILED_NOT_READY;
return CheckCast(true);
@@ -5522,7 +5500,7 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
SpellCastResult Spell::CheckCasterAuras() const
{
// spells totally immuned to caster auras (wsg flag drop, give marks etc)
- if (m_spellInfo->AttributesEx6 & SPELL_ATTR6_IGNORE_CASTER_AURAS)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CASTER_AURAS))
return SPELL_CAST_OK;
uint8 school_immune = 0;
@@ -5531,7 +5509,7 @@ SpellCastResult Spell::CheckCasterAuras() const
// Check if the spell grants school or mechanic immunity.
// We use bitmasks so the loop is done only once and not on every aura check below.
- if (m_spellInfo->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
{
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
@@ -5547,7 +5525,7 @@ SpellCastResult Spell::CheckCasterAuras() const
mechanic_immune = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
}
- bool usableInStun = (m_spellInfo->AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_STUNNED) != 0;
+ bool usableInStun = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED);
// Glyph of Pain Suppression
// there is no other way to handle it
@@ -5579,9 +5557,9 @@ SpellCastResult Spell::CheckCasterAuras() const
else
prevented_reason = SPELL_FAILED_STUNNED;
}
- else if (unitflag & UNIT_FLAG_CONFUSED && !(m_spellInfo->AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_CONFUSED))
+ else if (unitflag & UNIT_FLAG_CONFUSED && !m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED))
prevented_reason = SPELL_FAILED_CONFUSED;
- else if (unitflag & UNIT_FLAG_FLEEING && !(m_spellInfo->AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_FEARED))
+ else if (unitflag & UNIT_FLAG_FLEEING && !m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED))
prevented_reason = SPELL_FAILED_FLEEING;
else if (unitflag & UNIT_FLAG_SILENCED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
prevented_reason = SPELL_FAILED_SILENCED;
@@ -5601,7 +5579,7 @@ SpellCastResult Spell::CheckCasterAuras() const
SpellInfo const* auraInfo = aura->GetSpellInfo();
if (auraInfo->GetAllEffectsMechanicMask() & mechanic_immune)
continue;
- if (auraInfo->GetSchoolMask() & school_immune && !(auraInfo->AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE))
+ if (auraInfo->GetSchoolMask() & school_immune && !auraInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE))
continue;
if (auraInfo->GetDispelMask() & dispel_immune)
continue;
@@ -5619,11 +5597,11 @@ SpellCastResult Spell::CheckCasterAuras() const
return SPELL_FAILED_STUNNED;
break;
case SPELL_AURA_MOD_CONFUSE:
- if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_CONFUSED))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED))
return SPELL_FAILED_CONFUSED;
break;
case SPELL_AURA_MOD_FEAR:
- if (!(m_spellInfo->AttributesEx5 & SPELL_ATTR5_USABLE_WHILE_FEARED))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED))
return SPELL_FAILED_FLEEING;
break;
case SPELL_AURA_MOD_SILENCE:
@@ -5804,7 +5782,7 @@ SpellCastResult Spell::CheckItems()
if (!proto)
return SPELL_FAILED_ITEM_NOT_READY;
- for (uint8 i = 0; i < MAX_ITEM_SPELLS; ++i)
+ for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
if (proto->Spells[i].SpellCharges)
if (m_CastItem->GetSpellCharges(i) == 0)
return SPELL_FAILED_NO_CHARGES_REMAIN;
@@ -6260,7 +6238,7 @@ SpellCastResult Spell::CheckItems()
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT) && m_spellInfo->EquippedItemClass >=0)
{
// main hand weapon required
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_MAIN_HAND)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_MAIN_HAND))
{
Item* item = m_caster->ToPlayer()->GetWeaponForAttack(BASE_ATTACK);
@@ -6274,7 +6252,7 @@ SpellCastResult Spell::CheckItems()
}
// offhand hand weapon required
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_REQ_OFFHAND)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR3_REQ_OFFHAND))
{
Item* item = m_caster->ToPlayer()->GetWeaponForAttack(OFF_ATTACK);
@@ -6324,7 +6302,7 @@ void Spell::Delayed() // only called in DealDamage()
else
m_timer += delaytime;
- TC_LOG_INFO("spells", "Spell %u partially interrupted for (%d) ms at damage", m_spellInfo->Id, delaytime);
+ TC_LOG_DEBUG("spells", "Spell %u partially interrupted for (%d) ms at damage", m_spellInfo->Id, delaytime);
WorldPacket data(SMSG_SPELL_DELAYED, 8+4);
data << m_caster->GetPackGUID();
@@ -6463,11 +6441,11 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* lo
}
// check for ignore LOS on the effect itself
- if (m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS))
return true;
// if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour
- if (IsTriggered() && m_triggeredByAuraSpell && (m_triggeredByAuraSpell->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_triggeredByAuraSpell->Id, NULL, SPELL_DISABLE_LOS)))
+ if (IsTriggered() && m_triggeredByAuraSpell && (m_triggeredByAuraSpell->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_triggeredByAuraSpell->Id, NULL, SPELL_DISABLE_LOS)))
return true;
/// @todo shit below shouldn't be here, but it's temporary
@@ -6518,7 +6496,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* lo
bool Spell::IsNextMeleeSwingSpell() const
{
- return (m_spellInfo->Attributes & SPELL_ATTR0_ON_NEXT_SWING) != 0;
+ return m_spellInfo->HasAttribute(SPELL_ATTR0_ON_NEXT_SWING);
}
bool Spell::IsAutoActionResetSpell() const
@@ -6697,7 +6675,7 @@ void Spell::HandleLaunchPhase()
if (m_applyMultiplierMask & (1 << i))
multiplier[i] = m_spellInfo->Effects[i].CalcDamageMultiplier(m_originalCaster, this);
- bool usesAmmo = (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_DIRECT_DAMAGE) != 0;
+ bool usesAmmo = m_spellInfo->HasAttribute(SPELL_ATTR0_CU_DIRECT_DAMAGE);
Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_ABILITY_CONSUME_NO_AMMO);
for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
{
@@ -7140,7 +7118,7 @@ void Spell::CallScriptDestinationTargetSelectHandlers(SpellDestination& target,
bool Spell::CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToCheck)
{
// Skip if there are not any script
- if (!m_loadedScripts.size())
+ if (m_loadedScripts.empty())
return true;
for (std::list<SpellScript*>::iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
@@ -7162,7 +7140,7 @@ bool Spell::CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToC
bool Spell::CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura) const
{
- bool only_on_caster = (triggeredByAura && (triggeredByAura->AttributesEx4 & SPELL_ATTR4_PROC_ONLY_ON_CASTER));
+ bool only_on_caster = (triggeredByAura && triggeredByAura->HasAttribute(SPELL_ATTR4_PROC_ONLY_ON_CASTER));
// If triggeredByAura has SPELL_ATTR4_PROC_ONLY_ON_CASTER then it can only proc on a cast spell with TARGET_UNIT_CASTER
for (uint8 i = 0;i < MAX_SPELL_EFFECTS; ++i)
{
@@ -7233,13 +7211,11 @@ enum GCDLimits
bool Spell::HasGlobalCooldown() const
{
- // Only player or controlled units have global cooldown
- if (m_caster->GetCharmInfo())
- return m_caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo);
- else if (m_caster->GetTypeId() == TYPEID_PLAYER)
- return m_caster->ToPlayer()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo);
- else
+ // Only players or controlled units have global cooldown
+ if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo())
return false;
+
+ return m_caster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo);
}
void Spell::TriggerGlobalCooldown()
@@ -7248,6 +7224,10 @@ void Spell::TriggerGlobalCooldown()
if (!gcd)
return;
+ // Only players or controlled units have global cooldown
+ if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo())
+ return;
+
if (m_caster->GetTypeId() == TYPEID_PLAYER)
if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_COOLDOWN))
return;
@@ -7269,11 +7249,7 @@ void Spell::TriggerGlobalCooldown()
gcd = MAX_GCD;
}
- // Only players or controlled units have global cooldown
- if (m_caster->GetCharmInfo())
- m_caster->GetCharmInfo()->GetGlobalCooldownMgr().AddGlobalCooldown(m_spellInfo, gcd);
- else if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->GetGlobalCooldownMgr().AddGlobalCooldown(m_spellInfo, gcd);
+ m_caster->GetSpellHistory()->AddGlobalCooldown(m_spellInfo, gcd);
}
void Spell::CancelGlobalCooldown()
@@ -7286,10 +7262,10 @@ void Spell::CancelGlobalCooldown()
return;
// Only players or controlled units have global cooldown
- if (m_caster->GetCharmInfo())
- m_caster->GetCharmInfo()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo);
- else if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo);
+ if (m_caster->GetTypeId() != TYPEID_PLAYER && !m_caster->GetCharmInfo())
+ return;
+
+ m_caster->GetSpellHistory()->CancelGlobalCooldown(m_spellInfo);
}
namespace Trinity
@@ -7401,14 +7377,14 @@ WorldObjectSpellConeTargetCheck::WorldObjectSpellConeTargetCheck(float coneAngle
bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target)
{
- if (_spellInfo->AttributesCu & SPELL_ATTR0_CU_CONE_BACK)
+ if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_BACK))
{
if (!_caster->isInBack(target, _coneAngle))
return false;
}
- else if (_spellInfo->AttributesCu & SPELL_ATTR0_CU_CONE_LINE)
+ else if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_LINE))
{
- if (!_caster->HasInLine(target, _caster->GetObjectSize()))
+ if (!_caster->HasInLine(target, _caster->GetObjectSize() + target->GetObjectSize()))
return false;
}
else
@@ -7425,7 +7401,7 @@ WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Po
bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target)
{
// return all targets on missile trajectory (0 - size of a missile)
- if (!_caster->HasInLine(target, 0))
+ if (!_caster->HasInLine(target, target->GetObjectSize()))
return false;
return WorldObjectSpellAreaTargetCheck::operator ()(target);
}
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 2ae2930aeb0..1aac88ac602 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -473,6 +473,7 @@ class Spell
void ReSetTimer() { m_timer = m_casttime > 0 ? m_casttime : 0; }
bool IsNextMeleeSwingSpell() const;
bool IsTriggered() const { return (_triggeredCastFlags & TRIGGERED_FULL_MASK) != 0; }
+ bool IsIgnoringCooldowns() const { return (_triggeredCastFlags & TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD) != 0; }
bool IsChannelActive() const { return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0; }
bool IsAutoActionResetSpell() const;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index d2f2951aac1..3829e12b790 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -32,10 +32,6 @@
#include "DynamicObject.h"
#include "SpellAuras.h"
#include "SpellAuraEffects.h"
-#include "Group.h"
-#include "UpdateData.h"
-#include "MapManager.h"
-#include "ObjectAccessor.h"
#include "SharedDefines.h"
#include "Pet.h"
#include "GameObject.h"
@@ -43,21 +39,16 @@
#include "Creature.h"
#include "Totem.h"
#include "CreatureAI.h"
-#include "BattlegroundMgr.h"
#include "Battleground.h"
#include "OutdoorPvPMgr.h"
#include "Language.h"
#include "SocialMgr.h"
#include "Util.h"
-#include "VMapFactory.h"
#include "TemporarySummon.h"
-#include "CellImpl.h"
#include "GridNotifiers.h"
-#include "GridNotifiersImpl.h"
-#include "SkillDiscovery.h"
#include "Formulas.h"
-#include "Vehicle.h"
#include "ScriptMgr.h"
+#include "SpellHistory.h"
#include "GameObjectAI.h"
#include "AccountMgr.h"
#include "InstanceScript.h"
@@ -324,7 +315,7 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
case SPELLFAMILY_GENERIC:
{
// Meteor like spells (divided damage to targets)
- if (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_SHARE_DAMAGE)
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_SHARE_DAMAGE))
{
uint32 count = 0;
for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
@@ -779,8 +770,8 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex)
return;
// Reset cooldown on stealth if needed
- if (unitTarget->ToPlayer()->HasSpellCooldown(1784))
- unitTarget->ToPlayer()->RemoveSpellCooldown(1784);
+ if (unitTarget->GetSpellHistory()->HasCooldown(1784))
+ unitTarget->GetSpellHistory()->ResetCooldown(1784);
unitTarget->CastSpell(unitTarget, 1784, true);
return;
@@ -889,7 +880,7 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex)
// Remove spell cooldown (not category) if spell triggering spell with cooldown and same category
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime
&& m_spellInfo->GetCategory() == spellInfo->GetCategory())
- m_caster->ToPlayer()->RemoveSpellCooldown(spellInfo->Id);
+ m_caster->GetSpellHistory()->ResetCooldown(spellInfo->Id);
// original caster guid only for GO cast
m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID);
@@ -942,7 +933,7 @@ void Spell::EffectTriggerMissileSpell(SpellEffIndex effIndex)
// Remove spell cooldown (not category) if spell triggering spell with cooldown and same category
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime
&& m_spellInfo->GetCategory() == spellInfo->GetCategory())
- m_caster->ToPlayer()->RemoveSpellCooldown(spellInfo->Id);
+ m_caster->GetSpellHistory()->ResetCooldown(spellInfo->Id);
// original caster guid only for GO cast
m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID);
@@ -1755,7 +1746,7 @@ void Spell::EffectEnergize(SpellEffIndex effIndex)
Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue);
- if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
+ if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !m_spellInfo->HasAttribute(SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
return;
if (unitTarget->GetMaxPower(power) == 0)
@@ -1870,7 +1861,7 @@ void Spell::EffectEnergizePct(SpellEffIndex effIndex)
Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue);
- if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
+ if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !m_spellInfo->HasAttribute(SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
return;
uint32 maxPower = unitTarget->GetMaxPower(power);
@@ -3482,7 +3473,7 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex)
if (m_originalCaster)
{
int32 duration = m_spellInfo->GetDuration();
- unitTarget->ProhibitSpellSchool(curSpellInfo->GetSchoolMask(), unitTarget->ModSpellDuration(m_spellInfo, unitTarget, duration, false, 1 << effIndex));
+ unitTarget->GetSpellHistory()->LockSpellSchool(curSpellInfo->GetSchoolMask(), unitTarget->ModSpellDuration(m_spellInfo, unitTarget, duration, false, 1 << effIndex));
}
ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo->Id);
unitTarget->InterruptSpell(CurrentSpellTypes(i), false);
@@ -4226,7 +4217,7 @@ void Spell::EffectStuck(SpellEffIndex /*effIndex*/)
return;
TC_LOG_DEBUG("spells", "Spell Effect: Stuck");
- TC_LOG_INFO("spells", "Player %s (guid %u) used auto-unstuck future at map %u (%f, %f, %f)", player->GetName().c_str(), player->GetGUIDLow(), player->GetMapId(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
+ TC_LOG_DEBUG("spells", "Player %s (guid %u) used auto-unstuck future at map %u (%f, %f, %f)", player->GetName().c_str(), player->GetGUIDLow(), player->GetMapId(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
if (player->IsInFlight())
return;
@@ -5344,13 +5335,13 @@ void Spell::EffectStealBeneficialBuff(SpellEffIndex effIndex)
if ((aura->GetSpellInfo()->GetDispelMask()) & dispelMask)
{
// Need check for passive? this
- if (!aurApp->IsPositive() || aura->IsPassive() || aura->GetSpellInfo()->AttributesEx4 & SPELL_ATTR4_NOT_STEALABLE)
+ if (!aurApp->IsPositive() || aura->IsPassive() || aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_NOT_STEALABLE))
continue;
// The charges / stack amounts don't count towards the total number of auras that can be dispelled.
// Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
// Polymorph instead of 1 / (5 + 1) -> 16%.
- bool dispel_charges = (aura->GetSpellInfo()->AttributesEx7 & SPELL_ATTR7_DISPEL_CHARGES) != 0;
+ bool dispel_charges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount();
if (charges > 0)
steal_list.push_back(std::make_pair(aura, charges));
@@ -5849,10 +5840,10 @@ void Spell::EffectCastButtons(SpellEffIndex effIndex)
if (!spellInfo)
continue;
- if (!p_caster->HasSpell(spell_id) || p_caster->HasSpellCooldown(spell_id))
+ if (!p_caster->HasSpell(spell_id) || p_caster->GetSpellHistory()->HasCooldown(spell_id))
continue;
- if (!(spellInfo->AttributesEx7 & SPELL_ATTR7_SUMMON_PLAYER_TOTEM))
+ if (!spellInfo->HasAttribute(SPELL_ATTR7_SUMMON_PLAYER_TOTEM))
continue;
uint32 cost = spellInfo->CalcPowerCost(m_caster, spellInfo->GetSchoolMask());
diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp
new file mode 100644
index 00000000000..09e3be690b1
--- /dev/null
+++ b/src/server/game/Spells/SpellHistory.cpp
@@ -0,0 +1,643 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "WorldPacket.h"
+#include "SpellHistory.h"
+#include "Pet.h"
+#include "Player.h"
+#include "SpellInfo.h"
+#include "Spell.h"
+#include "World.h"
+#include "Opcodes.h"
+
+SpellHistory::Clock::duration const SpellHistory::InfinityCooldownDelay = std::chrono::duration_cast<SpellHistory::Clock::duration>(std::chrono::seconds(MONTH));
+SpellHistory::Clock::duration const SpellHistory::InfinityCooldownDelayCheck = std::chrono::duration_cast<SpellHistory::Clock::duration>(std::chrono::seconds(MONTH / 2));
+
+template<>
+struct SpellHistory::PersistenceHelper<Player>
+{
+ static CharacterDatabaseStatements const CooldownsDeleteStatement = CHAR_DEL_CHAR_SPELL_COOLDOWNS;
+ static CharacterDatabaseStatements const CooldownsInsertStatement = CHAR_INS_CHAR_SPELL_COOLDOWN;
+
+ static void SetIdentifier(PreparedStatement* stmt, uint8 index, Unit* owner) { stmt->setUInt32(index, owner->GetGUID().GetCounter()); }
+
+ static bool ReadCooldown(Field* fields, uint32* spellId, CooldownEntry* cooldownEntry)
+ {
+ *spellId = fields[0].GetUInt32();
+ if (!sSpellMgr->GetSpellInfo(*spellId))
+ return false;
+
+ cooldownEntry->CooldownEnd = Clock::from_time_t(time_t(fields[2].GetUInt32()));
+ cooldownEntry->ItemId = fields[1].GetUInt32();
+ return true;
+ }
+
+ static void WriteCooldown(PreparedStatement* stmt, uint8& index, CooldownStorageType::value_type const& cooldown)
+ {
+ stmt->setUInt32(index++, cooldown.first);
+ stmt->setUInt32(index++, cooldown.second.ItemId);
+ stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CooldownEnd)));
+ }
+};
+
+template<>
+struct SpellHistory::PersistenceHelper<Pet>
+{
+ static CharacterDatabaseStatements const CooldownsDeleteStatement = CHAR_DEL_PET_SPELL_COOLDOWNS;
+ static CharacterDatabaseStatements const CooldownsInsertStatement = CHAR_INS_PET_SPELL_COOLDOWN;
+
+ static void SetIdentifier(PreparedStatement* stmt, uint8 index, Unit* owner) { stmt->setUInt32(index, owner->GetCharmInfo()->GetPetNumber()); }
+
+ static bool ReadCooldown(Field* fields, uint32* spellId, CooldownEntry* cooldownEntry)
+ {
+ *spellId = fields[0].GetUInt32();
+ if (!sSpellMgr->GetSpellInfo(*spellId))
+ return false;
+
+ cooldownEntry->CooldownEnd = Clock::from_time_t(time_t(fields[1].GetUInt32()));
+ cooldownEntry->ItemId = 0;
+ return true;
+ }
+
+ static void WriteCooldown(PreparedStatement* stmt, uint8& index, CooldownStorageType::value_type const& cooldown)
+ {
+ stmt->setUInt32(index++, cooldown.first);
+ stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CooldownEnd)));
+ }
+};
+
+template<class OwnerType>
+void SpellHistory::LoadFromDB(PreparedQueryResult cooldownsResult)
+{
+ typedef PersistenceHelper<OwnerType> StatementInfo;
+
+ if (cooldownsResult)
+ {
+ do
+ {
+ uint32 spellId;
+ CooldownEntry cooldown;
+ if (StatementInfo::ReadCooldown(cooldownsResult->Fetch(), &spellId, &cooldown))
+ _spellCooldowns[spellId] = cooldown;
+
+ } while (cooldownsResult->NextRow());
+ }
+}
+
+template<class OwnerType>
+void SpellHistory::SaveToDB(SQLTransaction& trans)
+{
+ typedef PersistenceHelper<OwnerType> StatementInfo;
+
+ uint8 index = 0;
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(StatementInfo::CooldownsDeleteStatement);
+ StatementInfo::SetIdentifier(stmt, index++, _owner);
+ trans->Append(stmt);
+
+ for (auto const& p : _spellCooldowns)
+ {
+ if (!p.second.OnHold)
+ {
+ index = 0;
+ stmt = CharacterDatabase.GetPreparedStatement(StatementInfo::CooldownsInsertStatement);
+ StatementInfo::SetIdentifier(stmt, index++, _owner);
+ StatementInfo::WriteCooldown(stmt, index, p);
+ trans->Append(stmt);
+ }
+ }
+}
+
+void SpellHistory::Update()
+{
+ SQLTransaction t;
+ Clock::time_point now = Clock::now();
+ for (auto itr = _spellCooldowns.begin(); itr != _spellCooldowns.end();)
+ {
+ if (itr->second.CooldownEnd < now)
+ itr = _spellCooldowns.erase(itr);
+ else
+ ++itr;
+ }
+}
+
+void SpellHistory::HandleCooldowns(SpellInfo const* spellInfo, Item const* item, Spell* spell /*= nullptr*/)
+{
+ if (Player* player = _owner->ToPlayer())
+ {
+ // potions start cooldown until exiting combat
+ if (item && (item->IsPotion() || spellInfo->IsCooldownStartedOnEvent()))
+ {
+ player->SetLastPotionId(item->GetEntry());
+ return;
+ }
+ }
+
+ if (spellInfo->IsCooldownStartedOnEvent() || spellInfo->IsPassive() || (spell && spell->IsIgnoringCooldowns()))
+ return;
+
+ StartCooldown(spellInfo, item ? item->GetEntry() : 0, spell);
+}
+
+bool SpellHistory::IsReady(SpellInfo const* spellInfo) const
+{
+ if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
+ if (IsSchoolLocked(spellInfo->GetSchoolMask()))
+ return false;
+
+ if (HasCooldown(spellInfo->Id))
+ return false;
+
+ return true;
+}
+
+template<>
+void SpellHistory::WritePacket<Pet>(WorldPacket& packet) const
+{
+ Clock::time_point now = Clock::now();
+
+ uint8 cooldownsCount = _spellCooldowns.size();
+ packet << uint8(cooldownsCount);
+
+ for (auto const& spellCooldown : _spellCooldowns)
+ {
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellCooldown.first);
+ if (!spellInfo)
+ {
+ packet << uint32(0);
+ packet << uint16(0);
+ packet << uint32(0);
+ packet << uint32(0);
+ continue;
+ }
+
+ packet << uint32(spellCooldown.first); // spell ID
+ packet << uint16(spellInfo->GetCategory()); // spell category
+ if (!spellCooldown.second.OnHold)
+ {
+ uint32 cooldownDuration = spellCooldown.second.CooldownEnd > now ? std::chrono::duration_cast<std::chrono::milliseconds>(spellCooldown.second.CooldownEnd - now).count() : 0;
+ if (cooldownDuration <= 0)
+ {
+ packet << uint32(0);
+ packet << uint32(0);
+ continue;
+ }
+
+ if (spellInfo->GetCategory())
+ {
+ packet << uint32(0);
+ packet << uint32(cooldownDuration);
+ }
+ else
+ {
+ packet << uint32(cooldownDuration);
+ packet << uint32(0);
+ }
+ }
+ }
+}
+
+template<>
+void SpellHistory::WritePacket<Player>(WorldPacket& packet) const
+{
+ Clock::time_point now = Clock::now();
+ Clock::time_point infTime = now + InfinityCooldownDelayCheck;
+
+ uint16 cooldownsCount = _spellCooldowns.size();
+ size_t dataPos = packet.wpos();
+ packet << uint16(cooldownsCount);
+
+ for (auto const& spellCooldown : _spellCooldowns)
+ {
+ SpellInfo const* sEntry = sSpellMgr->GetSpellInfo(spellCooldown.first);
+ if (!sEntry)
+ {
+ --cooldownsCount;
+ continue;
+ }
+
+ packet << uint32(spellCooldown.first);
+
+ packet << uint16(spellCooldown.second.ItemId); // cast item id
+ packet << uint16(sEntry->GetCategory()); // spell category
+
+ // send infinity cooldown in special format
+ if (spellCooldown.second.CooldownEnd >= infTime)
+ {
+ packet << uint32(1); // cooldown
+ packet << uint32(0x80000000); // category cooldown
+ continue;
+ }
+
+ uint32 cooldownDuration = spellCooldown.second.CooldownEnd > now ? std::chrono::duration_cast<std::chrono::milliseconds>(spellCooldown.second.CooldownEnd - now).count() : 0;
+
+ if (sEntry->GetCategory()) // may be wrong, but anyway better than nothing...
+ {
+ packet << uint32(0); // cooldown
+ packet << uint32(cooldownDuration); // category cooldown
+ }
+ else
+ {
+ packet << uint32(cooldownDuration); // cooldown
+ packet << uint32(0); // category cooldown
+ }
+ }
+
+ packet.put<uint16>(dataPos, cooldownsCount);
+}
+
+void SpellHistory::StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spell* spell /*= nullptr*/, bool onHold /*= false*/)
+{
+ // init cooldown values
+ uint32 categoryId = 0;
+ int32 cooldown = -1;
+ int32 categoryCooldown = -1;
+
+ // some special item spells without correct cooldown in SpellInfo
+ // cooldown information stored in item prototype
+ if (itemId)
+ {
+ if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId))
+ {
+ for (uint8 idx = 0; idx < MAX_ITEM_PROTO_SPELLS; ++idx)
+ {
+ if (uint32(proto->Spells[idx].SpellId) == spellInfo->Id)
+ {
+ categoryId = proto->Spells[idx].SpellCategory;
+ cooldown = proto->Spells[idx].SpellCooldown;
+ categoryCooldown = proto->Spells[idx].SpellCategoryCooldown;
+ break;
+ }
+ }
+ }
+ }
+
+ // if no cooldown found above then base at DBC data
+ if (cooldown < 0 && categoryCooldown < 0)
+ {
+ categoryId = spellInfo->GetCategory();
+ cooldown = spellInfo->RecoveryTime;
+ categoryCooldown = spellInfo->CategoryRecoveryTime;
+ }
+
+ Clock::time_point curTime = Clock::now();
+ Clock::time_point catrecTime;
+ Clock::time_point recTime;
+ bool needsCooldownPacket = false;
+
+ // overwrite time for selected category
+ if (onHold)
+ {
+ // use +MONTH as infinite cooldown marker
+ catrecTime = categoryCooldown > 0 ? (curTime + InfinityCooldownDelay) : curTime;
+ recTime = cooldown > 0 ? (curTime + InfinityCooldownDelay) : catrecTime;
+ }
+ else
+ {
+ // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
+ // prevent 0 cooldowns set by another way
+ if (cooldown <= 0 && categoryCooldown <= 0 && (categoryId == 76 || (spellInfo->IsAutoRepeatRangedSpell() && spellInfo->Id != 75)))
+ cooldown = _owner->GetAttackTime(RANGED_ATTACK);
+
+ // Now we have cooldown data (if found any), time to apply mods
+ if (Player* modOwner = _owner->GetSpellModOwner())
+ {
+ if (cooldown > 0)
+ modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, cooldown, spell);
+
+ if (categoryCooldown > 0 && !spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS))
+ modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, categoryCooldown, spell);
+ }
+
+ if (int32 cooldownMod = _owner->GetTotalAuraModifier(SPELL_AURA_MOD_COOLDOWN))
+ {
+ // Apply SPELL_AURA_MOD_COOLDOWN only to own spells
+ Player* playerOwner = GetPlayerOwner();
+ if (!playerOwner || playerOwner->HasSpell(spellInfo->Id))
+ {
+ needsCooldownPacket = true;
+ cooldown += cooldownMod * IN_MILLISECONDS; // SPELL_AURA_MOD_COOLDOWN does not affect category cooldows, verified with shaman shocks
+ }
+ }
+
+ // replace negative cooldowns by 0
+ if (cooldown < 0)
+ cooldown = 0;
+
+ if (categoryCooldown < 0)
+ categoryCooldown = 0;
+
+ // no cooldown after applying spell mods
+ if (cooldown == 0 && categoryCooldown == 0)
+ return;
+
+ catrecTime = categoryCooldown ? curTime + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(categoryCooldown)) : curTime;
+ recTime = cooldown ? curTime + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(cooldown)) : catrecTime;
+ }
+
+ // self spell cooldown
+ if (recTime != curTime)
+ {
+ AddCooldown(spellInfo->Id, itemId, recTime, onHold);
+
+ if (needsCooldownPacket)
+ {
+ if (Player* playerOwner = GetPlayerOwner())
+ {
+ WorldPacket spellCooldown;
+ BuildCooldownPacket(spellCooldown, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, cooldown);
+ playerOwner->SendDirectMessage(&spellCooldown);
+ }
+ }
+ }
+
+ // category spells
+ if (categoryId && catrecTime != curTime)
+ {
+ SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(categoryId);
+ if (i_scstore != sSpellsByCategoryStore.end())
+ {
+ for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
+ {
+ if (*i_scset == spellInfo->Id) // skip main spell, already handled above
+ continue;
+
+ AddCooldown(*i_scset, itemId, catrecTime, onHold);
+ }
+ }
+ }
+}
+
+void SpellHistory::SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId /*= 0*/, Spell* spell /*= nullptr*/, bool startCooldown /*= true*/)
+{
+ // start cooldowns at server side, if any
+ if (startCooldown)
+ StartCooldown(spellInfo, itemId, spell);
+
+ if (Player* player = GetPlayerOwner())
+ {
+ // Send activate cooldown timer (possible 0) at client side
+ WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8);
+ data << uint32(spellInfo->Id);
+ data << uint64(_owner->GetGUID());
+ player->SendDirectMessage(&data);
+
+ uint32 category = spellInfo->GetCategory();
+ if (category && spellInfo->CategoryRecoveryTime)
+ {
+ SpellCategoryStore::const_iterator ct = sSpellsByCategoryStore.find(category);
+ if (ct != sSpellsByCategoryStore.end())
+ {
+ for (auto const& cooldownPair : _spellCooldowns)
+ {
+ uint32 categorySpell = cooldownPair.first;
+ if (!ct->second.count(categorySpell))
+ continue;
+
+ if (categorySpell == spellInfo->Id) // skip main spell, already handled above
+ continue;
+
+ SpellInfo const* spellInfo2 = sSpellMgr->EnsureSpellInfo(categorySpell);
+ if (!spellInfo2->IsCooldownStartedOnEvent())
+ continue;
+
+ data.Initialize(SMSG_COOLDOWN_EVENT, 4 + 8);
+ data << uint32(categorySpell);
+ data << uint64(_owner->GetGUID());
+ player->SendDirectMessage(&data);
+ }
+ }
+ }
+ }
+}
+
+void SpellHistory::AddCooldown(uint32 spellId, uint32 itemId, Clock::time_point cooldownEnd, bool onHold /*= false*/)
+{
+ CooldownEntry& cooldownEntry = _spellCooldowns[spellId];
+ cooldownEntry.CooldownEnd = cooldownEnd;
+ cooldownEntry.ItemId = itemId;
+ cooldownEntry.OnHold = onHold;
+}
+
+void SpellHistory::ModifyCooldown(uint32 spellId, int32 cooldownModMs)
+{
+ auto itr = _spellCooldowns.find(spellId);
+ if (!cooldownModMs || itr == _spellCooldowns.end())
+ return;
+
+ Clock::time_point now = Clock::now();
+ Clock::duration offset = std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(cooldownModMs));
+ if (itr->second.CooldownEnd + offset > now)
+ itr->second.CooldownEnd += offset;
+ else
+ _spellCooldowns.erase(itr);
+
+ if (Player* playerOwner = GetPlayerOwner())
+ {
+ WorldPacket modifyCooldown(SMSG_MODIFY_COOLDOWN, 4 + 8 + 4);
+ modifyCooldown << uint32(spellId);
+ modifyCooldown << uint64(_owner->GetGUID());
+ modifyCooldown << int32(cooldownModMs);
+ playerOwner->SendDirectMessage(&modifyCooldown);
+ }
+}
+
+void SpellHistory::ResetCooldown(uint32 spellId, bool update /*= false*/)
+{
+ auto itr = _spellCooldowns.find(spellId);
+ if (itr == _spellCooldowns.end())
+ return;
+
+ ResetCooldown(itr, update);
+}
+
+void SpellHistory::ResetCooldown(CooldownStorageType::iterator& itr, bool update /*= false*/)
+{
+ if (update)
+ {
+ if (Player* playerOwner = GetPlayerOwner())
+ {
+ WorldPacket data(SMSG_CLEAR_COOLDOWN, 4 + 8);
+ data << uint32(itr->first);
+ data << uint64(_owner->GetGUID());
+ playerOwner->SendDirectMessage(&data);
+ }
+ }
+
+ itr = _spellCooldowns.erase(itr);
+}
+
+void SpellHistory::ResetAllCooldowns()
+{
+ if (GetPlayerOwner())
+ {
+ std::vector<int32> cooldowns;
+ cooldowns.reserve(_spellCooldowns.size());
+ for (auto const& p : _spellCooldowns)
+ cooldowns.push_back(p.first);
+
+ SendClearCooldowns(cooldowns);
+ }
+
+ _spellCooldowns.clear();
+}
+
+bool SpellHistory::HasCooldown(uint32 spellId) const
+{
+ return _spellCooldowns.count(spellId) != 0;
+}
+
+uint32 SpellHistory::GetRemainingCooldown(uint32 spellId) const
+{
+ auto itr = _spellCooldowns.find(spellId);
+ if (itr == _spellCooldowns.end())
+ return 0;
+
+ Clock::time_point now = Clock::now();
+ if (itr->second.CooldownEnd < now)
+ return 0;
+
+ Clock::duration remaining = itr->second.CooldownEnd - now;
+ return uint32(std::chrono::duration_cast<std::chrono::milliseconds>(remaining).count());
+}
+
+void SpellHistory::LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTime)
+{
+ Clock::time_point lockoutEnd = Clock::now() + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(lockoutTime));
+ for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
+ if (SpellSchoolMask(1 << i) & schoolMask)
+ _schoolLockouts[i] = lockoutEnd;
+
+ std::set<uint32> knownSpells;
+ if (Player* plrOwner = _owner->ToPlayer())
+ {
+ for (auto const& p : plrOwner->GetSpellMap())
+ if (p.second->state != PLAYERSPELL_REMOVED)
+ knownSpells.insert(p.first);
+ }
+ else if (Pet* petOwner = _owner->ToPet())
+ {
+ for (auto const& p : petOwner->m_spells)
+ if (p.second.state != PETSPELL_REMOVED)
+ knownSpells.insert(p.first);
+ }
+ else
+ {
+ Creature* creatureOwner = _owner->ToCreature();
+ for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i)
+ if (creatureOwner->m_spells[i])
+ knownSpells.insert(creatureOwner->m_spells[i]);
+ }
+
+ PacketCooldowns cooldowns;
+ WorldPacket spellCooldowns;
+ for (uint32 spellId : knownSpells)
+ {
+ SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(spellId);
+ if (spellInfo->IsCooldownStartedOnEvent())
+ continue;
+
+ if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE)
+ continue;
+
+ if ((schoolMask & spellInfo->GetSchoolMask()) && GetRemainingCooldown(spellId) < lockoutTime)
+ {
+ cooldowns[spellId] = lockoutTime;
+ AddCooldown(spellId, 0, lockoutEnd);
+ }
+ }
+
+ if (Player* player = GetPlayerOwner())
+ {
+ if (!cooldowns.empty())
+ {
+ BuildCooldownPacket(spellCooldowns, SPELL_COOLDOWN_FLAG_NONE, cooldowns);
+ player->SendDirectMessage(&spellCooldowns);
+ }
+ }
+}
+
+bool SpellHistory::IsSchoolLocked(SpellSchoolMask schoolMask) const
+{
+ Clock::time_point now = Clock::now();
+ for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
+ if (SpellSchoolMask(1 << i) & schoolMask)
+ if (_schoolLockouts[i] > now)
+ return true;
+
+ return false;
+}
+
+bool SpellHistory::HasGlobalCooldown(SpellInfo const* spellInfo) const
+{
+ auto itr = _globalCooldowns.find(spellInfo->StartRecoveryCategory);
+ return itr != _globalCooldowns.end() && itr->second > Clock::now();
+}
+
+void SpellHistory::AddGlobalCooldown(SpellInfo const* spellInfo, uint32 duration)
+{
+ _globalCooldowns[spellInfo->StartRecoveryCategory] = Clock::now() + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(duration));
+}
+
+void SpellHistory::CancelGlobalCooldown(SpellInfo const* spellInfo)
+{
+ _globalCooldowns[spellInfo->StartRecoveryCategory] = Clock::time_point(Clock::duration(0));
+}
+
+Player* SpellHistory::GetPlayerOwner() const
+{
+ return _owner->GetCharmerOrOwnerPlayerOrPlayerItself();
+}
+
+void SpellHistory::SendClearCooldowns(std::vector<int32> const& cooldowns) const
+{
+ if (Player* playerOwner = GetPlayerOwner())
+ {
+ for (int32 spell : cooldowns)
+ {
+ WorldPacket data(SMSG_CLEAR_COOLDOWN, 4 + 8);
+ data << uint32(spell);
+ data << uint64(_owner->GetGUID());
+ playerOwner->SendDirectMessage(&data);
+ }
+ }
+}
+
+void SpellHistory::BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown) const
+{
+ data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + 4 + 4);
+ data << uint64(_owner->GetGUID());
+ data << uint8(flags);
+ data << uint32(spellId);
+ data << uint32(cooldown);
+}
+
+void SpellHistory::BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns) const
+{
+ data.Initialize(SMSG_SPELL_COOLDOWN, 8 + 1 + (4 + 4) * cooldowns.size());
+ data << uint64(_owner->GetGUID());
+ data << uint8(flags);
+ for (auto const& cooldown : cooldowns)
+ {
+ data << cooldown.first;
+ data << cooldown.second;
+ }
+}
+
+template void SpellHistory::LoadFromDB<Player>(PreparedQueryResult cooldownsResult);
+template void SpellHistory::LoadFromDB<Pet>(PreparedQueryResult cooldownsResult);
+template void SpellHistory::SaveToDB<Player>(SQLTransaction& trans);
+template void SpellHistory::SaveToDB<Pet>(SQLTransaction& trans);
diff --git a/src/server/game/Spells/SpellHistory.h b/src/server/game/Spells/SpellHistory.h
new file mode 100644
index 00000000000..f1533d57aef
--- /dev/null
+++ b/src/server/game/Spells/SpellHistory.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SpellHistory_h__
+#define SpellHistory_h__
+
+#include "SharedDefines.h"
+#include "QueryResult.h"
+#include "Transaction.h"
+#include <chrono>
+#include <deque>
+
+class Item;
+class Player;
+class Spell;
+class SpellInfo;
+class Unit;
+struct SpellCategoryEntry;
+
+class SpellHistory
+{
+public:
+ typedef std::chrono::system_clock Clock;
+
+ struct CooldownEntry
+ {
+ CooldownEntry() : ItemId(0), OnHold(false) { }
+ CooldownEntry(Clock::time_point endTime, uint32 itemId) : CooldownEnd(endTime), ItemId(itemId), OnHold(false) { }
+
+ Clock::time_point CooldownEnd;
+ uint32 ItemId;
+ bool OnHold;
+ };
+
+ typedef std::unordered_map<uint32 /*spellId*/, CooldownEntry> CooldownStorageType;
+ typedef std::unordered_map<uint32 /*categoryId*/, Clock::time_point> GlobalCooldownStorageType;
+
+ explicit SpellHistory(Unit* owner) : _owner(owner), _schoolLockouts() { }
+
+ template<class OwnerType>
+ void LoadFromDB(PreparedQueryResult cooldownsResult);
+
+ template<class OwnerType>
+ void SaveToDB(SQLTransaction& trans);
+
+ void Update();
+
+ void HandleCooldowns(SpellInfo const* spellInfo, Item const* item, Spell* spell = nullptr);
+ bool IsReady(SpellInfo const* spellInfo) const;
+ template<class OwnerType>
+ void WritePacket(WorldPacket& packet) const;
+
+ // Cooldowns
+ static Clock::duration const InfinityCooldownDelay; // used for set "infinity cooldowns" for spells and check
+ static Clock::duration const InfinityCooldownDelayCheck;
+
+ void StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spell* spell = nullptr, bool onHold = false);
+ void SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId = 0, Spell* spell = nullptr, bool startCooldown = true);
+
+ template<class Type, class Period>
+ void AddCooldown(uint32 spellId, uint32 itemId, std::chrono::duration<Type, Period> cooldownDuration)
+ {
+ AddCooldown(spellId, itemId, Clock::now() + std::chrono::duration_cast<Clock::duration>(cooldownDuration));
+ }
+
+ void AddCooldown(uint32 spellId, uint32 itemId, Clock::time_point cooldownEnd, bool onHold = false);
+ void ModifyCooldown(uint32 spellId, int32 cooldownModMs);
+ void ResetCooldown(uint32 spellId, bool update = false);
+ void ResetCooldown(CooldownStorageType::iterator& itr, bool update = false);
+ template<typename Predicate>
+ void ResetCooldowns(Predicate predicate, bool update = false)
+ {
+ std::vector<int32> resetCooldowns;
+ resetCooldowns.reserve(_spellCooldowns.size());
+ for (auto itr = _spellCooldowns.begin(); itr != _spellCooldowns.end();)
+ {
+ if (predicate(itr))
+ {
+ resetCooldowns.push_back(itr->first);
+ ResetCooldown(itr, false);
+ }
+ else
+ ++itr;
+ }
+
+ if (update && !resetCooldowns.empty())
+ SendClearCooldowns(resetCooldowns);
+ }
+
+ void ResetAllCooldowns();
+ bool HasCooldown(uint32 spellId) const;
+ uint32 GetRemainingCooldown(uint32 spellId) const;
+
+ // School lockouts
+ void LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTime);
+ bool IsSchoolLocked(SpellSchoolMask schoolMask) const;
+
+ // Global cooldown
+ bool HasGlobalCooldown(SpellInfo const* spellInfo) const;
+ void AddGlobalCooldown(SpellInfo const* spellInfo, uint32 duration);
+ void CancelGlobalCooldown(SpellInfo const* spellInfo);
+
+ void BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown) const;
+
+ CooldownStorageType::size_type GetCooldownsSizeForPacket() const { return _spellCooldowns.size(); }
+
+private:
+ Player* GetPlayerOwner() const;
+ void SendClearCooldowns(std::vector<int32> const& cooldowns) const;
+
+ typedef std::unordered_map<uint32, uint32> PacketCooldowns;
+ void BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns) const;
+
+ Unit* _owner;
+ CooldownStorageType _spellCooldowns;
+ Clock::time_point _schoolLockouts[MAX_SPELL_SCHOOL];
+ GlobalCooldownStorageType _globalCooldowns;
+
+ template<class T>
+ struct PersistenceHelper { };
+};
+
+#endif // SpellHistory_h__
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 6215f8cfa0a..789b95e3e14 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -453,7 +453,7 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const
// amount multiplication based on caster's level
if (!caster->IsControlledByPlayer() &&
_spellInfo->SpellLevel && _spellInfo->SpellLevel != caster->getLevel() &&
- !basePointsPerLevel && (_spellInfo->Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION))
+ !basePointsPerLevel && _spellInfo->HasAttribute(SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION))
{
bool canEffectScale = false;
switch (Effect)
@@ -1049,14 +1049,14 @@ bool SpellInfo::NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell) con
bool SpellInfo::IsPassive() const
{
- return (Attributes & SPELL_ATTR0_PASSIVE) != 0;
+ return HasAttribute(SPELL_ATTR0_PASSIVE);
}
bool SpellInfo::IsAutocastable() const
{
- if (Attributes & SPELL_ATTR0_PASSIVE)
+ if (HasAttribute(SPELL_ATTR0_PASSIVE))
return false;
- if (AttributesEx & SPELL_ATTR1_UNAUTOCASTABLE_BY_PET)
+ if (HasAttribute(SPELL_ATTR1_UNAUTOCASTABLE_BY_PET))
return false;
return true;
}
@@ -1107,37 +1107,37 @@ bool SpellInfo::IsMultiSlotAura() const
bool SpellInfo::IsStackableOnOneSlotWithDifferentCasters() const
{
/// TODO: Re-verify meaning of SPELL_ATTR3_STACK_FOR_DIFF_CASTERS and update conditions here
- return StackAmount > 1 && !IsChanneled() && !(AttributesEx3 & SPELL_ATTR3_STACK_FOR_DIFF_CASTERS);
+ return StackAmount > 1 && !IsChanneled() && !HasAttribute(SPELL_ATTR3_STACK_FOR_DIFF_CASTERS);
}
bool SpellInfo::IsCooldownStartedOnEvent() const
{
- return Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE || (CategoryEntry && CategoryEntry->Flags & SPELL_CATEGORY_FLAG_COOLDOWN_STARTS_ON_EVENT);
+ return HasAttribute(SPELL_ATTR0_DISABLED_WHILE_ACTIVE) || (CategoryEntry && CategoryEntry->Flags & SPELL_CATEGORY_FLAG_COOLDOWN_STARTS_ON_EVENT);
}
bool SpellInfo::IsDeathPersistent() const
{
- return (AttributesEx3 & SPELL_ATTR3_DEATH_PERSISTENT) != 0;
+ return HasAttribute(SPELL_ATTR3_DEATH_PERSISTENT);
}
bool SpellInfo::IsRequiringDeadTarget() const
{
- return (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS) != 0;
+ return HasAttribute(SPELL_ATTR3_ONLY_TARGET_GHOSTS);
}
bool SpellInfo::IsAllowingDeadTarget() const
{
- return AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD || Targets & (TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_DEAD);
+ return HasAttribute(SPELL_ATTR2_CAN_TARGET_DEAD) || Targets & (TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_DEAD);
}
bool SpellInfo::CanBeUsedInCombat() const
{
- return !(Attributes & SPELL_ATTR0_CANT_USED_IN_COMBAT);
+ return !HasAttribute(SPELL_ATTR0_CANT_USED_IN_COMBAT);
}
bool SpellInfo::IsPositive() const
{
- return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE);
+ return !HasAttribute(SPELL_ATTR0_CU_NEGATIVE);
}
bool SpellInfo::IsPositiveEffect(uint8 effIndex) const
@@ -1146,27 +1146,27 @@ bool SpellInfo::IsPositiveEffect(uint8 effIndex) const
{
default:
case 0:
- return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE_EFF0);
+ return !HasAttribute(SPELL_ATTR0_CU_NEGATIVE_EFF0);
case 1:
- return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE_EFF1);
+ return !HasAttribute(SPELL_ATTR0_CU_NEGATIVE_EFF1);
case 2:
- return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE_EFF2);
+ return !HasAttribute(SPELL_ATTR0_CU_NEGATIVE_EFF2);
}
}
bool SpellInfo::IsChanneled() const
{
- return (AttributesEx & (SPELL_ATTR1_CHANNELED_1 | SPELL_ATTR1_CHANNELED_2)) != 0;
+ return HasAttribute(SPELL_ATTR1_CHANNELED_1) || HasAttribute(SPELL_ATTR1_CHANNELED_2);
}
bool SpellInfo::NeedsComboPoints() const
{
- return (AttributesEx & (SPELL_ATTR1_REQ_COMBO_POINTS1 | SPELL_ATTR1_REQ_COMBO_POINTS2)) != 0;
+ return HasAttribute(SPELL_ATTR1_REQ_COMBO_POINTS1) || HasAttribute(SPELL_ATTR1_REQ_COMBO_POINTS2);
}
bool SpellInfo::IsBreakingStealth() const
{
- return !(AttributesEx & SPELL_ATTR1_NOT_BREAK_STEALTH);
+ return !HasAttribute(SPELL_ATTR1_NOT_BREAK_STEALTH);
}
bool SpellInfo::IsRangedWeaponSpell() const
@@ -1177,12 +1177,12 @@ bool SpellInfo::IsRangedWeaponSpell() const
bool SpellInfo::IsAutoRepeatRangedSpell() const
{
- return (AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG) != 0;
+ return HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG);
}
bool SpellInfo::IsAffectedBySpellMods() const
{
- return !(AttributesEx3 & SPELL_ATTR3_NO_DONE_BONUS);
+ return !HasAttribute(SPELL_ATTR3_NO_DONE_BONUS);
}
bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const
@@ -1205,11 +1205,11 @@ bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const
bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const
{
// these spells pierce all avalible spells (Resurrection Sickness for example)
- if (Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ if (HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return true;
// these spells (Cyclone for example) can pierce all... // ...but not these (Divine shield, Ice block, Cyclone and Banish for example)
- if ((AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY || aura->Mechanic == MECHANIC_BANISH)))
+ if ((HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE)) && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY || aura->Mechanic == MECHANIC_BANISH)))
return true;
return false;
@@ -1218,15 +1218,15 @@ bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const
bool SpellInfo::CanDispelAura(SpellInfo const* aura) const
{
// These spells (like Mass Dispel) can dispell all auras, except death persistent ones (like Dungeon and Battleground Deserter)
- if (Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY && !aura->IsDeathPersistent())
+ if (HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) && !aura->IsDeathPersistent())
return true;
// These auras (like Divine Shield) can't be dispelled
- if (aura->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ if (aura->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return false;
// These auras (Cyclone for example) are not dispelable
- if (aura->AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE)
+ if (aura->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE))
return false;
return true;
@@ -1235,7 +1235,7 @@ bool SpellInfo::CanDispelAura(SpellInfo const* aura) const
bool SpellInfo::IsSingleTarget() const
{
// all other single target spells have if it has AttributesEx5
- if (AttributesEx5 & SPELL_ATTR5_SINGLE_TARGET_SPELL)
+ if (HasAttribute(SPELL_ATTR5_SINGLE_TARGET_SPELL))
return true;
switch (GetSpellSpecific())
@@ -1332,7 +1332,7 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const
if (actAsShifted)
{
- if (Attributes & SPELL_ATTR0_NOT_SHAPESHIFT) // not while shapeshifted
+ if (HasAttribute(SPELL_ATTR0_NOT_SHAPESHIFT)) // not while shapeshifted
return SPELL_FAILED_NOT_SHAPESHIFT;
else if (Stances != 0) // needs other shapeshift
return SPELL_FAILED_ONLY_SHAPESHIFT;
@@ -1340,7 +1340,7 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const
else
{
// needs shapeshift
- if (!(AttributesEx2 & SPELL_ATTR2_NOT_NEED_SHAPESHIFT) && Stances != 0)
+ if (!HasAttribute(SPELL_ATTR2_NOT_NEED_SHAPESHIFT) && Stances != 0)
return SPELL_FAILED_ONLY_SHAPESHIFT;
}
@@ -1379,7 +1379,7 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
}
// continent limitation (virtual continent)
- if (AttributesEx4 & SPELL_ATTR4_CAST_ONLY_IN_OUTLAND)
+ if (HasAttribute(SPELL_ATTR4_CAST_ONLY_IN_OUTLAND))
{
uint32 v_map = GetVirtualMapForMapAndZone(map_id, zone_id);
MapEntry const* mapEntry = sMapStore.LookupEntry(v_map);
@@ -1388,7 +1388,7 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
}
// raid instance limitation
- if (AttributesEx6 & SPELL_ATTR6_NOT_IN_RAID_INSTANCE)
+ if (HasAttribute(SPELL_ATTR6_NOT_IN_RAID_INSTANCE))
{
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
if (!mapEntry || mapEntry->IsRaid())
@@ -1482,22 +1482,26 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
case SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED:
case SPELL_AURA_FLY:
{
- if (player && !player->IsKnowHowFlyIn(map_id, zone_id))
- return SPELL_FAILED_INCORRECT_AREA;
+ SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(Id);
+ for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter)
+ {
+ if (skillIter->second->skillId == SKILL_MOUNTS)
+ if (player && !player->CanFlyInZone(map_id, zone_id))
+ return SPELL_FAILED_INCORRECT_AREA;
+ }
}
}
}
-
return SPELL_CAST_OK;
}
SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* target, bool implicit) const
{
- if (AttributesEx & SPELL_ATTR1_CANT_TARGET_SELF && caster == target)
+ if (HasAttribute(SPELL_ATTR1_CANT_TARGET_SELF) && caster == target)
return SPELL_FAILED_BAD_TARGETS;
// check visibility - ignore stealth for implicit (area) targets
- if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE) && !caster->CanSeeOrDetect(target, implicit))
+ if (!HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE) && !caster->CanSeeOrDetect(target, implicit))
return SPELL_FAILED_BAD_TARGETS;
Unit const* unitTarget = target->ToUnit();
@@ -1505,7 +1509,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
// creature/player specific target checks
if (unitTarget)
{
- if (AttributesEx & SPELL_ATTR1_CANT_TARGET_IN_COMBAT)
+ if (HasAttribute(SPELL_ATTR1_CANT_TARGET_IN_COMBAT))
{
if (unitTarget->IsInCombat())
return SPELL_FAILED_TARGET_AFFECTING_COMBAT;
@@ -1517,9 +1521,9 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
}
// only spells with SPELL_ATTR3_ONLY_TARGET_GHOSTS can target ghosts
- if (((AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS) != 0) != unitTarget->HasAuraType(SPELL_AURA_GHOST))
+ if (HasAttribute(SPELL_ATTR3_ONLY_TARGET_GHOSTS) != unitTarget->HasAuraType(SPELL_AURA_GHOST))
{
- if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS)
+ if (HasAttribute(SPELL_ATTR3_ONLY_TARGET_GHOSTS))
return SPELL_FAILED_TARGET_NOT_GHOST;
else
return SPELL_FAILED_BAD_TARGETS;
@@ -1530,12 +1534,12 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
if (caster->GetTypeId() == TYPEID_PLAYER)
{
// Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells)
- if (AttributesEx2 & SPELL_ATTR2_CANT_TARGET_TAPPED)
+ if (HasAttribute(SPELL_ATTR2_CANT_TARGET_TAPPED))
if (Creature const* targetCreature = unitTarget->ToCreature())
if (targetCreature->hasLootRecipient() && !targetCreature->isTappedBy(caster->ToPlayer()))
return SPELL_FAILED_CANT_CAST_ON_TAPPED;
- if (AttributesCu & SPELL_ATTR0_CU_PICKPOCKET)
+ if (HasAttribute(SPELL_ATTR0_CU_PICKPOCKET))
{
if (unitTarget->GetTypeId() == TYPEID_PLAYER)
return SPELL_FAILED_BAD_TARGETS;
@@ -1575,21 +1579,21 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
else return SPELL_CAST_OK;
// corpseOwner and unit specific target checks
- if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS && !unitTarget->ToPlayer())
+ if (HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS) && !unitTarget->ToPlayer())
return SPELL_FAILED_TARGET_NOT_PLAYER;
if (!IsAllowingDeadTarget() && !unitTarget->IsAlive())
return SPELL_FAILED_TARGETS_DEAD;
// check this flag only for implicit targets (chain and area), allow to explicitly target units for spells like Shield of Righteousness
- if (implicit && AttributesEx6 & SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED && !unitTarget->CanFreeMove())
+ if (implicit && HasAttribute(SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED) && !unitTarget->CanFreeMove())
return SPELL_FAILED_BAD_TARGETS;
// checked in Unit::IsValidAttack/AssistTarget, shouldn't be checked for ENTRY targets
- //if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
+ //if (!HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
// return SPELL_FAILED_BAD_TARGETS;
- //if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_POSSESSED_FRIENDS)
+ //if (!HasAttribute(SPELL_ATTR6_CAN_TARGET_POSSESSED_FRIENDS)
if (!CheckTargetCreatureType(unitTarget))
{
@@ -1610,7 +1614,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
}
// not allow casting on flying player
- if (unitTarget->HasUnitState(UNIT_STATE_IN_FLIGHT))
+ if (unitTarget->HasUnitState(UNIT_STATE_IN_FLIGHT) && !(AttributesCu & SPELL_ATTR0_CU_ALLOW_INFLIGHT_TARGET))
return SPELL_FAILED_BAD_TARGETS;
/* TARGET_UNIT_MASTER gets blocked here for passengers, because the whole idea of this check is to
@@ -1705,7 +1709,7 @@ SpellCastResult SpellInfo::CheckVehicle(Unit const* caster) const
checkMask = VEHICLE_SEAT_FLAG_CAN_ATTACK;
VehicleSeatEntry const* vehicleSeat = vehicle->GetSeatForPassenger(caster);
- if (!(AttributesEx6 & SPELL_ATTR6_CASTABLE_WHILE_ON_VEHICLE) && !(Attributes & SPELL_ATTR0_CASTABLE_WHILE_MOUNTED)
+ if (!HasAttribute(SPELL_ATTR6_CASTABLE_WHILE_ON_VEHICLE) && !HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_MOUNTED)
&& (vehicleSeat->m_flags & checkMask) != checkMask)
return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW;
@@ -2106,7 +2110,7 @@ uint32 SpellInfo::CalcCastTime(Spell* spell /*= NULL*/) const
if (spell)
spell->GetCaster()->ModSpellCastTime(this, castTime, spell);
- if (Attributes & SPELL_ATTR0_REQ_AMMO && (!IsAutoRepeatRangedSpell()))
+ if (HasAttribute(SPELL_ATTR0_REQ_AMMO) && (!IsAutoRepeatRangedSpell()))
castTime += 500;
return (castTime > 0) ? uint32(castTime) : 0;
@@ -2147,7 +2151,7 @@ uint32 SpellInfo::GetRecoveryTime() const
int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const
{
// Spell drain all exist power on cast (Only paladin lay of Hands)
- if (AttributesEx & SPELL_ATTR1_DRAIN_ALL_POWER)
+ if (HasAttribute(SPELL_ATTR1_DRAIN_ALL_POWER))
{
// If power type - health drain all
if (PowerType == POWER_HEALTH)
@@ -2193,7 +2197,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) c
powerCost += caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school);
// Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost)
- if (AttributesEx4 & SPELL_ATTR4_SPELL_VS_EXTEND_COST)
+ if (HasAttribute(SPELL_ATTR4_SPELL_VS_EXTEND_COST))
{
uint32 speed = 0;
if (SpellShapeshiftEntry const* ss = sSpellShapeshiftStore.LookupEntry(caster->GetShapeshiftForm()))
@@ -2201,7 +2205,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) c
else
{
WeaponAttackType slot = BASE_ATTACK;
- if (AttributesEx3 & SPELL_ATTR3_REQ_OFFHAND)
+ if (HasAttribute(SPELL_ATTR3_REQ_OFFHAND))
slot = OFF_ATTACK;
speed = caster->GetAttackTime(slot);
@@ -2216,7 +2220,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) c
if (!caster->IsControlledByPlayer())
{
- if (Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION)
+ if (HasAttribute(SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION))
{
GtNPCManaCostScalerEntry const* spellScaler = sGtNPCManaCostScalerStore.LookupEntry(SpellLevel - 1);
GtNPCManaCostScalerEntry const* casterScaler = sGtNPCManaCostScalerStore.LookupEntry(caster->getLevel() - 1);
@@ -2361,7 +2365,7 @@ void SpellInfo::_InitializeExplicitTargetMask()
bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const
{
// not found a single positive spell with this attribute
- if (Attributes & SPELL_ATTR0_NEGATIVE_1)
+ if (HasAttribute(SPELL_ATTR0_NEGATIVE_1))
return false;
switch (SpellFamilyName)
@@ -2542,7 +2546,7 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const
if (Effects[effIndex].TargetA.GetTarget() != TARGET_UNIT_CASTER)
return false;
// but not this if this first effect (didn't find better check)
- if (Attributes & SPELL_ATTR0_NEGATIVE_1 && effIndex == 0)
+ if (HasAttribute(SPELL_ATTR0_NEGATIVE_1) && effIndex == 0)
return false;
break;
case SPELL_AURA_MECHANIC_IMMUNITY:
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index d9c062e77fd..cfa9877405d 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -186,6 +186,7 @@ enum SpellCustomAttributes
SPELL_ATTR0_CU_IGNORE_ARMOR = 0x00008000,
SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER = 0x00010000,
SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET = 0x00020000,
+ SPELL_ATTR0_CU_ALLOW_INFLIGHT_TARGET = 0x00040000,
SPELL_ATTR0_CU_NEGATIVE = SPELL_ATTR0_CU_NEGATIVE_EFF0 | SPELL_ATTR0_CU_NEGATIVE_EFF1 | SPELL_ATTR0_CU_NEGATIVE_EFF2
};
@@ -376,6 +377,16 @@ public:
bool HasAura(AuraType aura) const;
bool HasAreaAuraEffect() const;
+ inline bool HasAttribute(SpellAttr0 attribute) const { return !!(Attributes & attribute); }
+ inline bool HasAttribute(SpellAttr1 attribute) const { return !!(AttributesEx & attribute); }
+ inline bool HasAttribute(SpellAttr2 attribute) const { return !!(AttributesEx2 & attribute); }
+ inline bool HasAttribute(SpellAttr3 attribute) const { return !!(AttributesEx3 & attribute); }
+ inline bool HasAttribute(SpellAttr4 attribute) const { return !!(AttributesEx4 & attribute); }
+ inline bool HasAttribute(SpellAttr5 attribute) const { return !!(AttributesEx5 & attribute); }
+ inline bool HasAttribute(SpellAttr6 attribute) const { return !!(AttributesEx6 & attribute); }
+ inline bool HasAttribute(SpellAttr7 attribute) const { return !!(AttributesEx7 & attribute); }
+ inline bool HasAttribute(SpellCustomAttributes customAttribute) const { return !!(AttributesCu & customAttribute); }
+
bool IsExplicitDiscovery() const;
bool IsLootCrafting() const;
bool IsQuestTame() const;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index dd4453cc4c5..13290320084 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -19,15 +19,11 @@
#include "SpellMgr.h"
#include "SpellInfo.h"
#include "ObjectMgr.h"
-#include "SpellAuras.h"
#include "SpellAuraDefines.h"
#include "SharedDefines.h"
#include "DBCStores.h"
-#include "World.h"
#include "Chat.h"
-#include "Spell.h"
#include "BattlegroundMgr.h"
-#include "MapManager.h"
#include "BattlefieldWG.h"
#include "BattlefieldMgr.h"
#include "Player.h"
@@ -2238,7 +2234,7 @@ void SpellMgr::LoadEnchantCustomAttr()
continue;
/// @todo find a better check
- if (!(spellInfo->AttributesEx2 & SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA) || !(spellInfo->Attributes & SPELL_ATTR0_NOT_SHAPESHIFT))
+ if (!spellInfo->HasAttribute(SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA) || !spellInfo->HasAttribute(SPELL_ATTR0_NOT_SHAPESHIFT))
continue;
for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j)
@@ -2958,6 +2954,10 @@ void SpellMgr::LoadSpellInfoCorrections()
switch (spellInfo->Id)
{
+ case 63026: // Force Cast (HACK: Target shouldn't be changed)
+ case 63137: // Force Cast (HACK: Target shouldn't be changed; summon position should be untied from spell destination)
+ spellInfo->Effects[0].TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB);
+ break;
case 53096: // Quetz'lun's Judgment
case 70743: // AoD Special
case 70614: // AoD Special - Vegard
@@ -3004,6 +3004,10 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Effects[EFFECT_0].TriggerSpell = 36325; // They Must Burn Bomb Drop (DND)
break;
case 49838: // Stop Time
+ case 69438: // Sample Satisfaction
+ case 69445: // Perfume Spritz
+ case 69489: // Chocolate Sample
+ case 69563: // Cologne Spritz
spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO;
break;
case 61407: // Energize Cores
@@ -3130,6 +3134,7 @@ void SpellMgr::LoadSpellInfoCorrections()
case 64823: // Item - Druid T8 Balance 4P Bonus
case 34477: // Misdirection
case 44401: // Missile Barrage
+ case 18820: // Insight
spellInfo->ProcCharges = 1;
break;
case 44544: // Fingers of Frost
@@ -3748,7 +3753,7 @@ void SpellMgr::LoadSpellInfoCorrections()
{
case SPELLFAMILY_PALADIN:
// Seals of the Pure should affect Seal of Righteousness
- if (spellInfo->SpellIconID == 25 && spellInfo->Attributes & SPELL_ATTR0_PASSIVE)
+ if (spellInfo->SpellIconID == 25 && spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE))
spellInfo->Effects[EFFECT_0].SpellClassMask[1] |= 0x20000000;
break;
case SPELLFAMILY_DEATHKNIGHT:
diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp
index 96977804f70..b347a982132 100644
--- a/src/server/game/Spells/SpellScript.cpp
+++ b/src/server/game/Spells/SpellScript.cpp
@@ -19,7 +19,6 @@
#include "Spell.h"
#include "SpellAuras.h"
#include "SpellScript.h"
-#include "SpellMgr.h"
bool _SpellScript::_Validate(SpellInfo const* entry)
{
diff --git a/src/server/game/Texts/CreatureTextMgr.cpp b/src/server/game/Texts/CreatureTextMgr.cpp
index 5fbc4b8ae1e..f9ccd2efd16 100644
--- a/src/server/game/Texts/CreatureTextMgr.cpp
+++ b/src/server/game/Texts/CreatureTextMgr.cpp
@@ -77,7 +77,7 @@ void CreatureTextMgr::LoadCreatureTexts()
uint32 oldMSTime = getMSTime();
mTextMap.clear(); // for reload case
- mTextRepeatMap.clear(); //reset all currently used temp texts
+ //all currently used temp texts are NOT reset
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_TEXT);
PreparedQueryResult result = WorldDatabase.Query(stmt);
@@ -224,13 +224,7 @@ uint32 CreatureTextMgr::SendChat(Creature* source, uint8 textGroup, WorldObject
if (tempGroup.empty())
{
- CreatureTextRepeatMap::iterator mapItr = mTextRepeatMap.find(source->GetGUID());
- if (mapItr != mTextRepeatMap.end())
- {
- CreatureTextRepeatGroup::iterator groupItr = mapItr->second.find(textGroup);
- groupItr->second.clear();
- }
-
+ source->ClearTextRepeatGroup(textGroup);
tempGroup = textGroupContainer;
}
@@ -426,26 +420,14 @@ void CreatureTextMgr::SetRepeatId(Creature* source, uint8 textGroup, uint8 id)
if (!source)
return;
- CreatureTextRepeatIds& repeats = mTextRepeatMap[source->GetGUID()][textGroup];
- if (std::find(repeats.begin(), repeats.end(), id) == repeats.end())
- repeats.push_back(id);
- else
- TC_LOG_ERROR("sql.sql", "CreatureTextMgr: TextGroup %u for Creature(%s) GuidLow %u Entry %u, id %u already added", uint32(textGroup), source->GetName().c_str(), source->GetGUIDLow(), source->GetEntry(), uint32(id));
+ source->SetTextRepeatId(textGroup, id);
}
CreatureTextRepeatIds CreatureTextMgr::GetRepeatGroup(Creature* source, uint8 textGroup)
{
ASSERT(source);//should never happen
- CreatureTextRepeatIds ids;
- CreatureTextRepeatMap::const_iterator mapItr = mTextRepeatMap.find(source->GetGUID());
- if (mapItr != mTextRepeatMap.end())
- {
- CreatureTextRepeatGroup::const_iterator groupItr = (*mapItr).second.find(textGroup);
- if (groupItr != mapItr->second.end())
- ids = groupItr->second;
- }
- return ids;
+ return source->GetTextRepeatGroup(textGroup);
}
bool CreatureTextMgr::TextExist(uint32 sourceEntry, uint8 textGroup)
diff --git a/src/server/game/Texts/CreatureTextMgr.h b/src/server/game/Texts/CreatureTextMgr.h
index 6ee1e82ce66..237aedd49d0 100644
--- a/src/server/game/Texts/CreatureTextMgr.h
+++ b/src/server/game/Texts/CreatureTextMgr.h
@@ -75,11 +75,6 @@ typedef std::unordered_map<uint32, CreatureTextHolder> CreatureTextMap; // a
typedef std::map<CreatureTextId, CreatureTextLocale> LocaleCreatureTextMap;
-//used for handling non-repeatable random texts
-typedef std::vector<uint8> CreatureTextRepeatIds;
-typedef std::unordered_map<uint8, CreatureTextRepeatIds> CreatureTextRepeatGroup;
-typedef std::unordered_map<ObjectGuid, CreatureTextRepeatGroup> CreatureTextRepeatMap;//guid based
-
class CreatureTextMgr
{
private:
@@ -115,7 +110,6 @@ class CreatureTextMgr
float GetRangeForChatType(ChatMsg msgType) const;
CreatureTextMap mTextMap;
- CreatureTextRepeatMap mTextRepeatMap;
LocaleCreatureTextMap mLocaleTextMap;
};
diff --git a/src/server/game/Warden/Warden.cpp b/src/server/game/Warden/Warden.cpp
index aed2d73c422..ecf7697db0d 100644
--- a/src/server/game/Warden/Warden.cpp
+++ b/src/server/game/Warden/Warden.cpp
@@ -22,10 +22,8 @@
#include "Log.h"
#include "Opcodes.h"
#include "ByteBuffer.h"
-#include <openssl/md5.h>
#include <openssl/sha.h>
#include "World.h"
-#include "Player.h"
#include "Util.h"
#include "Warden.h"
#include "AccountMgr.h"
diff --git a/src/server/game/Warden/Warden.h b/src/server/game/Warden/Warden.h
index 4d46773adcd..695c6730b27 100644
--- a/src/server/game/Warden/Warden.h
+++ b/src/server/game/Warden/Warden.h
@@ -57,11 +57,7 @@ enum WardenCheckType
MODULE_CHECK = 0xD9 // 217: uint Seed + byte[20] SHA1 (check to ensure module isn't injected)
};
-#if defined(__GNUC__)
-#pragma pack(1)
-#else
#pragma pack(push, 1)
-#endif
struct WardenModuleUse
{
@@ -84,11 +80,7 @@ struct WardenHashRequest
uint8 Seed[16];
};
-#if defined(__GNUC__)
-#pragma pack()
-#else
#pragma pack(pop)
-#endif
struct ClientWardenModule
{
diff --git a/src/server/game/Warden/WardenCheckMgr.cpp b/src/server/game/Warden/WardenCheckMgr.cpp
index c2d095e6530..df9cd4786ad 100644
--- a/src/server/game/Warden/WardenCheckMgr.cpp
+++ b/src/server/game/Warden/WardenCheckMgr.cpp
@@ -21,7 +21,6 @@
#include "WorldSession.h"
#include "Log.h"
#include "Database/DatabaseEnv.h"
-#include "Util.h"
#include "WardenCheckMgr.h"
#include "Warden.h"
diff --git a/src/server/game/Warden/WardenWin.cpp b/src/server/game/Warden/WardenWin.cpp
index 5a9d2d174b4..7db5e8f39e5 100644
--- a/src/server/game/Warden/WardenWin.cpp
+++ b/src/server/game/Warden/WardenWin.cpp
@@ -32,7 +32,6 @@
#include "WardenWin.h"
#include "WardenModuleWin.h"
#include "WardenCheckMgr.h"
-#include "AccountMgr.h"
WardenWin::WardenWin() : Warden(), _serverTicks(0) {}
diff --git a/src/server/game/Warden/WardenWin.h b/src/server/game/Warden/WardenWin.h
index 31d28b22e23..ab6ef7c8c65 100644
--- a/src/server/game/Warden/WardenWin.h
+++ b/src/server/game/Warden/WardenWin.h
@@ -25,11 +25,7 @@
#include "ByteBuffer.h"
#include "Warden.h"
-#if defined(__GNUC__)
-#pragma pack(1)
-#else
#pragma pack(push, 1)
-#endif
struct WardenInitModuleRequest
{
@@ -61,11 +57,7 @@ struct WardenInitModuleRequest
uint8 Function3_set;
};
-#if defined(__GNUC__)
-#pragma pack()
-#else
#pragma pack(pop)
-#endif
class WorldSession;
class Warden;
diff --git a/src/server/game/Weather/Weather.cpp b/src/server/game/Weather/Weather.cpp
index edcbe90498d..2a94cd26183 100644
--- a/src/server/game/Weather/Weather.cpp
+++ b/src/server/game/Weather/Weather.cpp
@@ -25,7 +25,6 @@
#include "Player.h"
#include "World.h"
#include "Log.h"
-#include "ObjectMgr.h"
#include "Util.h"
#include "ScriptMgr.h"
#include "WorldSession.h"
@@ -193,8 +192,10 @@ bool Weather::ReGenerate()
void Weather::SendWeatherUpdateToPlayer(Player* player)
{
- WorldPacket data(SMSG_WEATHER, (4+4+4));
- data << uint32(GetWeatherState()) << (float)m_grade << uint8(0);
+ WorldPacket data(SMSG_WEATHER, (4 + 4 + 1));
+ data << uint32(GetWeatherState());
+ data << (float)m_grade;
+ data << uint8(0);
player->GetSession()->SendPacket(&data);
}
@@ -209,7 +210,7 @@ bool Weather::UpdateWeather()
WeatherState state = GetWeatherState();
- WorldPacket data(SMSG_WEATHER, (4+4+4));
+ WorldPacket data(SMSG_WEATHER, (4 + 4 + 1));
data << uint32(state);
data << (float)m_grade;
data << uint8(0);
diff --git a/src/server/game/Weather/WeatherMgr.cpp b/src/server/game/Weather/WeatherMgr.cpp
index d1a614f494d..9100dd464b9 100644
--- a/src/server/game/Weather/WeatherMgr.cpp
+++ b/src/server/game/Weather/WeatherMgr.cpp
@@ -143,8 +143,10 @@ void LoadWeatherData()
void SendFineWeatherUpdateToPlayer(Player* player)
{
- WorldPacket data(SMSG_WEATHER, (4+4+4));
- data << (uint32)WEATHER_STATE_FINE << (float)0.0f << uint8(0);
+ WorldPacket data(SMSG_WEATHER, (4 + 4 + 1));
+ data << (uint32)WEATHER_STATE_FINE;
+ data << (float)0.0f;
+ data << uint8(0);
player->GetSession()->SendPacket(&data);
}
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 930bf20b6e7..5f54154fab1 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1523,6 +1523,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Gameobject Data...");
sObjectMgr->LoadGameobjects();
+
+ TC_LOG_INFO("server.loading", "Loading GameObject Addon Data...");
+ sObjectMgr->LoadGameObjectAddons(); // must be after LoadGameObjectTemplate() and LoadGameobjects()
TC_LOG_INFO("server.loading", "Loading Creature Linked Respawn...");
sObjectMgr->LoadLinkedRespawn(); // must be after LoadCreatures(), LoadGameObjects()
@@ -1914,28 +1917,24 @@ void World::DetectDBCLang()
TC_LOG_INFO("server.loading", "Using %s DBC Locale as default. All available DBC locales: %s", localeNames[m_defaultDbcLocale], availableLocalsStr.empty() ? "<none>" : availableLocalsStr.c_str());
}
-void World::RecordTimeDiff(const char *text, ...)
+void World::ResetTimeDiffRecord()
{
if (m_updateTimeCount != 1)
return;
- if (!text)
- {
- m_currentTime = getMSTime();
+
+ m_currentTime = getMSTime();
+}
+
+void World::RecordTimeDiff(std::string const& text)
+{
+ if (m_updateTimeCount != 1)
return;
- }
uint32 thisTime = getMSTime();
uint32 diff = getMSTimeDiff(m_currentTime, thisTime);
if (diff > m_int_configs[CONFIG_MIN_LOG_UPDATE])
- {
- va_list ap;
- char str[256];
- va_start(ap, text);
- vsnprintf(str, 256, text, ap);
- va_end(ap);
- TC_LOG_INFO("misc", "Difftime %s: %u.", str, diff);
- }
+ TC_LOG_INFO("misc", "Difftime %s: %u.", text.c_str(), diff);
m_currentTime = thisTime;
}
@@ -2052,7 +2051,7 @@ void World::Update(uint32 diff)
}
/// <li> Handle session updates when the timer has passed
- RecordTimeDiff(NULL);
+ ResetTimeDiffRecord();
UpdateSessions(diff);
RecordTimeDiff("UpdateSessions");
@@ -2099,7 +2098,7 @@ void World::Update(uint32 diff)
/// <li> Handle all other objects
///- Update objects when the timer has passed (maps, transport, creatures, ...)
- RecordTimeDiff(NULL);
+ ResetTimeDiffRecord();
sMapMgr->Update(diff);
RecordTimeDiff("UpdateMapMgr");
@@ -3024,7 +3023,7 @@ void World::ResetRandomBG()
{
TC_LOG_INFO("misc", "Random BG status reset for all characters.");
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_BATTLEGROUND_RANDOM);
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_BATTLEGROUND_RANDOM_ALL);
CharacterDatabase.Execute(stmt);
for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 95c737936bc..af89adcb04e 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -741,7 +741,8 @@ class World
void LoadDBVersion();
char const* GetDBVersion() const { return m_DBVersion.c_str(); }
- void RecordTimeDiff(const char * text, ...);
+ void ResetTimeDiffRecord();
+ void RecordTimeDiff(std::string const& text);
void LoadAutobroadcasts();
diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt
index e7d08d69805..20b970b6ac1 100644
--- a/src/server/scripts/CMakeLists.txt
+++ b/src/server/scripts/CMakeLists.txt
@@ -50,6 +50,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/SFMT
+ ${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/zlib
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
@@ -62,6 +63,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/server/shared/Logging
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
${CMAKE_SOURCE_DIR}/src/server/shared/Threading
+ ${CMAKE_SOURCE_DIR}/src/server/shared/Updater
${CMAKE_SOURCE_DIR}/src/server/shared/Utilities
${CMAKE_SOURCE_DIR}/src/server/collision
${CMAKE_SOURCE_DIR}/src/server/collision/Management
@@ -144,6 +146,8 @@ include_directories(
${VALGRIND_INCLUDE_DIR}
)
+GroupSources(${CMAKE_CURRENT_SOURCE_DIR})
+
add_library(scripts STATIC
${scripts_STAT_SRCS}
${scripts_STAT_PCH_SRC}
diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp
index c6ddd73addd..5668c20d6b0 100644
--- a/src/server/scripts/Commands/cs_account.cpp
+++ b/src/server/scripts/Commands/cs_account.cpp
@@ -667,7 +667,7 @@ public:
if (isAccountNameGiven)
{
targetAccountName = arg1;
- if (!AccountMgr::normalizeString(targetAccountName))
+ if (!AccountMgr::normalizeString(targetAccountName) || !AccountMgr::GetId(targetAccountName))
{
handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, targetAccountName.c_str());
handler->SetSentErrorMessage(true);
diff --git a/src/server/scripts/Commands/cs_lfg.cpp b/src/server/scripts/Commands/cs_lfg.cpp
index 308a841df2a..d1662f3a97c 100644
--- a/src/server/scripts/Commands/cs_lfg.cpp
+++ b/src/server/scripts/Commands/cs_lfg.cpp
@@ -19,7 +19,9 @@
#include "Chat.h"
#include "Language.h"
#include "LFGMgr.h"
+#include "ObjectMgr.h"
#include "Group.h"
+#include "GroupMgr.h"
#include "Player.h"
void GetPlayerInfo(ChatHandler* handler, Player* player)
@@ -47,15 +49,15 @@ public:
{
{ "player", rbac::RBAC_PERM_COMMAND_LFG_PLAYER, false, &HandleLfgPlayerInfoCommand, "", NULL },
{ "group", rbac::RBAC_PERM_COMMAND_LFG_GROUP, false, &HandleLfgGroupInfoCommand, "", NULL },
- { "queue", rbac::RBAC_PERM_COMMAND_LFG_QUEUE, false, &HandleLfgQueueInfoCommand, "", NULL },
- { "clean", rbac::RBAC_PERM_COMMAND_LFG_CLEAN, false, &HandleLfgCleanCommand, "", NULL },
- { "options", rbac::RBAC_PERM_COMMAND_LFG_OPTIONS, false, &HandleLfgOptionsCommand, "", NULL },
+ { "queue", rbac::RBAC_PERM_COMMAND_LFG_QUEUE, true, &HandleLfgQueueInfoCommand, "", NULL },
+ { "clean", rbac::RBAC_PERM_COMMAND_LFG_CLEAN, true, &HandleLfgCleanCommand, "", NULL },
+ { "options", rbac::RBAC_PERM_COMMAND_LFG_OPTIONS, true, &HandleLfgOptionsCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand commandTable[] =
{
- { "lfg", rbac::RBAC_PERM_COMMAND_LFG, false, NULL, "", lfgCommandTable },
+ { "lfg", rbac::RBAC_PERM_COMMAND_LFG, true, NULL, "", lfgCommandTable },
{ NULL, 0, false, NULL, "", NULL }
};
return commandTable;
@@ -74,25 +76,55 @@ public:
static bool HandleLfgGroupInfoCommand(ChatHandler* handler, char const* args)
{
- Player* target = NULL;
- std::string playerName;
- if (!handler->extractPlayerTarget((char*)args, &target, NULL, &playerName))
+ Player* playerTarget;
+ ObjectGuid guidTarget;
+ std::string nameTarget;
+
+ ObjectGuid parseGUID(HIGHGUID_PLAYER, uint32(atoul(args)));
+
+ if (sObjectMgr->GetPlayerNameByGUID(parseGUID, nameTarget))
+ {
+ playerTarget = ObjectAccessor::FindPlayer(parseGUID);
+ guidTarget = parseGUID;
+ }
+ else if (!handler->extractPlayerTarget((char*)args, &playerTarget, &guidTarget, &nameTarget))
return false;
- Group* grp = target->GetGroup();
- if (!grp)
+ Group* groupTarget = NULL;
+
+ if (playerTarget)
+ groupTarget = playerTarget->GetGroup();
+ else
+ {
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER);
+ stmt->setUInt32(0, guidTarget.GetCounter());
+ PreparedQueryResult resultGroup = CharacterDatabase.Query(stmt);
+ if (resultGroup)
+ groupTarget = sGroupMgr->GetGroupByDbStoreId((*resultGroup)[0].GetUInt32());
+ }
+ if (!groupTarget)
{
- handler->PSendSysMessage(LANG_LFG_NOT_IN_GROUP, playerName.c_str());
- return true;
+ handler->PSendSysMessage(LANG_LFG_NOT_IN_GROUP, nameTarget.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
}
- ObjectGuid guid = grp->GetGUID();
+ ObjectGuid guid = groupTarget->GetGUID();
std::string const& state = lfg::GetStateString(sLFGMgr->GetState(guid));
- handler->PSendSysMessage(LANG_LFG_GROUP_INFO, grp->isLFGGroup(),
+ handler->PSendSysMessage(LANG_LFG_GROUP_INFO, groupTarget->isLFGGroup(),
state.c_str(), sLFGMgr->GetDungeon(guid));
- for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
- GetPlayerInfo(handler, itr->GetSource());
+ Group::MemberSlotList const& members = groupTarget->GetMemberSlots();
+
+ for (Group::MemberSlotList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ Group::MemberSlot const& slot = *itr;
+ Player* p = ObjectAccessor::FindPlayer((*itr).guid);
+ if (p)
+ GetPlayerInfo(handler, p);
+ else
+ handler->PSendSysMessage("%s is offline.", slot.name.c_str());
+ }
return true;
}
@@ -118,7 +150,7 @@ public:
static bool HandleLfgQueueInfoCommand(ChatHandler* handler, char const* args)
{
- handler->SendSysMessage(sLFGMgr->DumpQueueInfo(atoi(args) != 0).c_str());
+ handler->SendSysMessage(sLFGMgr->DumpQueueInfo(*args != '\0').c_str());
return true;
}
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 0e86823aa7c..c8a908f6930 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -25,7 +25,6 @@
#include "InstanceSaveMgr.h"
#include "Language.h"
#include "MovementGenerator.h"
-#include "ObjectAccessor.h"
#include "Opcodes.h"
#include "SpellAuras.h"
#include "TargetedMovementGenerator.h"
@@ -36,6 +35,7 @@
#include "GroupMgr.h"
#include "MMapFactory.h"
#include "DisableMgr.h"
+#include "SpellHistory.h"
class misc_commandscript : public CommandScript
{
@@ -237,7 +237,8 @@ public:
zoneId, (zoneEntry ? zoneEntry->area_name[handler->GetSessionDbcLocale()] : unknown),
areaId, (areaEntry ? areaEntry->area_name[handler->GetSessionDbcLocale()] : unknown),
object->GetPhaseMask(),
- object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), object->GetOrientation(),
+ object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), object->GetOrientation());
+ handler->PSendSysMessage(LANG_GRID_POSITION,
cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), object->GetInstanceId(),
zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap, haveMMap);
@@ -708,7 +709,7 @@ public:
if (!*args)
{
- target->RemoveAllSpellCooldown();
+ target->GetSpellHistory()->ResetAllCooldowns();
handler->PSendSysMessage(LANG_REMOVEALL_COOLDOWN, nameLink.c_str());
}
else
@@ -718,14 +719,15 @@ public:
if (!spellIid)
return false;
- if (!sSpellMgr->GetSpellInfo(spellIid))
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellIid);
+ if (!spellInfo)
{
handler->PSendSysMessage(LANG_UNKNOWN_SPELL, target == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str());
handler->SetSentErrorMessage(true);
return false;
}
- target->RemoveSpellCooldown(spellIid, true);
+ target->GetSpellHistory()->ResetCooldown(spellIid, true);
handler->PSendSysMessage(LANG_REMOVE_COOLDOWN, spellIid, target == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str());
}
return true;
@@ -1438,7 +1440,7 @@ public:
* Player %s %s (guid: %u) - I. LANG_PINFO_PLAYER
* ** GM Mode active, Phase: -1 - II. LANG_PINFO_GM_ACTIVE (if GM)
* ** Banned: (Type, Reason, Time, By) - III. LANG_PINFO_BANNED (if banned)
- * ** Muted: (Time, Reason, By) - IV. LANG_PINFO_MUTED (if muted)
+ * ** Muted: (Reason, Time, By) - IV. LANG_PINFO_MUTED (if muted)
* * Account: %s (id: %u), GM Level: %u - V. LANG_PINFO_ACC_ACCOUNT
* * Last Login: %u (Failed Logins: %u) - VI. LANG_PINFO_ACC_LASTLOGIN
* * Uses OS: %s - Latency: %u ms - VII. LANG_PINFO_ACC_OS
@@ -1691,7 +1693,7 @@ public:
// Output IV. LANG_PINFO_MUTED if mute is applied
if (muteTime > 0)
- handler->PSendSysMessage(LANG_PINFO_MUTED, secsToTimeString(muteTime - time(NULL), true).c_str(), muteReason.c_str(), muteBy.c_str());
+ handler->PSendSysMessage(LANG_PINFO_MUTED, muteReason.c_str(), secsToTimeString(muteTime - time(nullptr), true).c_str(), muteBy.c_str());
// Output V. LANG_PINFO_ACC_ACCOUNT
handler->PSendSysMessage(LANG_PINFO_ACC_ACCOUNT, userName.c_str(), accId, security);
@@ -1980,7 +1982,7 @@ public:
PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_MUTE_INFO);
stmt->setUInt32(0, accountId);
PreparedQueryResult result = LoginDatabase.Query(stmt);
-
+
if (!result)
{
handler->PSendSysMessage(LANG_COMMAND_MUTEHISTORY_EMPTY, accountName);
@@ -1991,16 +1993,16 @@ public:
do
{
Field* fields = result->Fetch();
-
+
// we have to manually set the string for mutedate
time_t sqlTime = fields[0].GetUInt32();
tm timeinfo;
char buffer[80];
-
+
// set it to string
localtime_r(&sqlTime, &timeinfo);
strftime(buffer, sizeof(buffer),"%Y-%m-%d %I:%M%p", &timeinfo);
-
+
handler->PSendSysMessage(LANG_COMMAND_MUTEHISTORY_OUTPUT, buffer, fields[1].GetUInt32(), fields[2].GetCString(), fields[3].GetCString());
} while (result->NextRow());
return true;
diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp
index 4667b7c2767..54d1f314140 100644
--- a/src/server/scripts/Commands/cs_modify.cpp
+++ b/src/server/scripts/Commands/cs_modify.cpp
@@ -136,7 +136,7 @@ public:
return false;
}
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
@@ -164,17 +164,6 @@ public:
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;
@@ -185,7 +174,7 @@ public:
return false;
}
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
@@ -215,17 +204,6 @@ public:
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;
@@ -236,7 +214,7 @@ public:
return false;
}
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
@@ -274,7 +252,7 @@ public:
return false;
}
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
@@ -390,7 +368,7 @@ public:
else
mark = atoi(pmark);
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (target == NULL)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
@@ -945,7 +923,7 @@ public:
return false;
}
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
@@ -986,7 +964,7 @@ public:
if (!*args)
return false;
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
@@ -1107,7 +1085,7 @@ public:
if (!*args)
return false;
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
@@ -1137,7 +1115,7 @@ public:
if (drunklevel > 100)
drunklevel = 100;
- if (Player* target = handler->getSelectedPlayer())
+ if (Player* target = handler->getSelectedPlayerOrSelf())
target->SetDrunkValue(drunklevel);
return true;
@@ -1148,7 +1126,7 @@ public:
if (!*args)
return false;
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
@@ -1302,7 +1280,7 @@ public:
if (!*args)
return false;
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
@@ -1324,7 +1302,7 @@ public:
if (!*args)
return false;
- Player* target = handler->getSelectedPlayer();
+ Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index 390be999d9d..09a41fd82b5 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -370,28 +370,13 @@ public:
uint32 lowGuid = atoi((char*)guidStr);
- Creature* creature = NULL;
-
- /* FIXME: impossible without entry
- if (lowguid)
- creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT));
- */
-
// attempt check creature existence by DB data
- if (!creature)
- {
- CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid);
- if (!data)
- {
- handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowGuid);
- handler->SetSentErrorMessage(true);
- return false;
- }
- }
- else
+ CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid);
+ if (!data)
{
- // obtain real GUID for DB operations
- lowGuid = creature->GetDBTableGUIDLow();
+ handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowGuid);
+ handler->SetSentErrorMessage(true);
+ return false;
}
int wait = waitStr ? atoi(waitStr) : 0;
@@ -407,18 +392,6 @@ public:
WorldDatabase.Execute(stmt);
- if (creature && creature->GetWaypointPath())
- {
- creature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
- creature->GetMotionMaster()->Initialize();
- if (creature->IsAlive()) // dead creature will reset movement generator at respawn
- {
- creature->setDeathState(JUST_DIED);
- creature->Respawn(true);
- }
- creature->SaveToDB();
- }
-
handler->SendSysMessage(LANG_WAYPOINT_ADDED);
return true;
@@ -830,34 +803,22 @@ public:
lowguid = atoi(cId);
- /* FIXME: impossible without entry
- if (lowguid)
- creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT));
- */
-
// Attempting creature load from DB data
- if (!creature)
+ CreatureData const* data = sObjectMgr->GetCreatureData(lowguid);
+ if (!data)
{
- CreatureData const* data = sObjectMgr->GetCreatureData(lowguid);
- if (!data)
- {
- handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
- handler->SetSentErrorMessage(true);
- return false;
- }
+ handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
- uint32 map_id = data->mapid;
+ uint32 map_id = data->mapid;
- if (handler->GetSession()->GetPlayer()->GetMapId() != map_id)
- {
- handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
- handler->SetSentErrorMessage(true);
- return false;
- }
- }
- else
+ if (handler->GetSession()->GetPlayer()->GetMapId() != map_id)
{
- lowguid = creature->GetDBTableGUIDLow();
+ handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
+ handler->SetSentErrorMessage(true);
+ return false;
}
}
else
diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp
index 5e83c0c8653..8965b64767a 100644
--- a/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp
+++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp
@@ -126,7 +126,7 @@ public:
if (dist(xn, yn, xh, yh) >= dist(xn, yn, xp, yp) || dist(xp, yp, xh, yh) >= dist(xn, yn, xp, yp))
return false;
// check distance from the beam
- return (abs((xn-xp)*yh+(yp-yn)*xh-xn*yp+xp*yn)/dist(xn, yn, xp, yp) < 1.5f);
+ return (std::abs((xn-xp)*yh+(yp-yn)*xh-xn*yp+xp*yn)/dist(xn, yn, xp, yp) < 1.5f);
}
float dist(float xa, float ya, float xb, float yb) // auxiliary method for distance
diff --git a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp
index 1302c618e6f..e3ab206ac21 100644
--- a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp
+++ b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp
@@ -268,7 +268,7 @@ public:
return ObjectGuid::Empty;
}
- void Load(char const* chrIn)
+ void Load(char const* chrIn) override
{
if (!chrIn)
{
diff --git a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp
index 59f2ce1a2c9..92c3f83034d 100644
--- a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp
+++ b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp
@@ -360,17 +360,17 @@ public:
case GOSSIP_ACTION_INFO_DEF+3:
player->CLOSE_GOSSIP_MENU();
pBarnesAI->m_uiEventId = EVENT_OZ;
- TC_LOG_INFO("scripts", "player (%s) manually set Opera event to EVENT_OZ", player->GetGUID().ToString().c_str());
+ TC_LOG_DEBUG("scripts", "player (%s) manually set Opera event to EVENT_OZ", player->GetGUID().ToString().c_str());
break;
case GOSSIP_ACTION_INFO_DEF+4:
player->CLOSE_GOSSIP_MENU();
pBarnesAI->m_uiEventId = EVENT_HOOD;
- TC_LOG_INFO("scripts", "player (%s) manually set Opera event to EVENT_HOOD", player->GetGUID().ToString().c_str());
+ TC_LOG_DEBUG("scripts", "player (%s) manually set Opera event to EVENT_HOOD", player->GetGUID().ToString().c_str());
break;
case GOSSIP_ACTION_INFO_DEF+5:
player->CLOSE_GOSSIP_MENU();
pBarnesAI->m_uiEventId = EVENT_RAJ;
- TC_LOG_INFO("scripts", "player (%s) manually set Opera event to EVENT_RAJ", player->GetGUID().ToString().c_str());
+ TC_LOG_DEBUG("scripts", "player (%s) manually set Opera event to EVENT_RAJ", player->GetGUID().ToString().c_str());
break;
}
diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp
index b21b2f8a73c..3df07562d50 100644
--- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp
@@ -1657,7 +1657,7 @@ public:
{
npc_the_lich_king_tirion_dawnAI(Creature* creature) : ScriptedAI(creature) { Reset(); }
void Reset() override { }
- void AttackStart(Unit* /*who*/) { } // very sample, just don't make them aggreesive override
+ void AttackStart(Unit* /*who*/) override { } // very sample, just don't make them aggreesive
void UpdateAI(uint32 /*diff*/) override { }
void JustDied(Unit* /*killer*/) override { }
};
diff --git a/src/server/scripts/EasternKingdoms/ShadowfangKeep/instance_shadowfang_keep.cpp b/src/server/scripts/EasternKingdoms/ShadowfangKeep/instance_shadowfang_keep.cpp
index be544449b67..a085463f7ce 100644
--- a/src/server/scripts/EasternKingdoms/ShadowfangKeep/instance_shadowfang_keep.cpp
+++ b/src/server/scripts/EasternKingdoms/ShadowfangKeep/instance_shadowfang_keep.cpp
@@ -236,7 +236,7 @@ public:
OUT_LOAD_INST_DATA_COMPLETE;
}
- void Update(uint32 uiDiff)
+ void Update(uint32 uiDiff) override
{
if (GetData(TYPE_FENRUS) != DONE)
return;
diff --git a/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp b/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp
index 1d7e1594d05..ca944f7037b 100644
--- a/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp
+++ b/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp
@@ -102,7 +102,7 @@ public:
}
}
- virtual void Update(uint32 /*diff*/) // correct order goes form 1-6
+ virtual void Update(uint32 /*diff*/) override // correct order goes form 1-6
{
switch (State)
{
diff --git a/src/server/scripts/EasternKingdoms/SunkenTemple/sunken_temple.cpp b/src/server/scripts/EasternKingdoms/SunkenTemple/sunken_temple.cpp
index 3ced85f09a2..97be139cefe 100644
--- a/src/server/scripts/EasternKingdoms/SunkenTemple/sunken_temple.cpp
+++ b/src/server/scripts/EasternKingdoms/SunkenTemple/sunken_temple.cpp
@@ -36,19 +36,27 @@ EndContentData */
# at_malfurion_Stormrage_trigger
#####*/
-class at_malfurion_stormrage : public AreaTriggerScript
+enum MalfurionMisc
{
-public:
- at_malfurion_stormrage() : AreaTriggerScript("at_malfurion_stormrage") { }
+ NPC_MALFURION_STORMRAGE = 15362,
+ QUEST_ERANIKUS_TYRANT_OF_DREAMS = 8733,
+ QUEST_THE_CHARGE_OF_DRAGONFLIGHTS = 8555,
+};
- bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/) override
- {
- if (player->GetInstanceScript() && !player->FindNearestCreature(15362, 15))
- player->SummonCreature(15362, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), -1.52f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 100000);
- return false;
- }
+class at_malfurion_stormrage : public AreaTriggerScript
+{
+ public:
+ at_malfurion_stormrage() : AreaTriggerScript("at_malfurion_stormrage") { }
+ bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/) override
+ {
+ if (player->GetInstanceScript() && !player->FindNearestCreature(NPC_MALFURION_STORMRAGE, 15.0f) &&
+ player->GetQuestStatus(QUEST_THE_CHARGE_OF_DRAGONFLIGHTS) == QUEST_STATUS_REWARDED && player->GetQuestStatus(QUEST_ERANIKUS_TYRANT_OF_DREAMS) != QUEST_STATUS_REWARDED)
+ player->SummonCreature(NPC_MALFURION_STORMRAGE, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), -1.52f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 100000);
+ return false;
+ }
};
+
/*#####
# go_atalai_statue
#####*/
diff --git a/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp b/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp
index ec2f41cc625..29002460b2a 100644
--- a/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp
+++ b/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp
@@ -41,14 +41,17 @@ enum Says
enum Spells
{
- SPELL_GROUND_TREMOR = 6524,
- SPELL_ARCHAEDAS_AWAKEN = 10347,
- SPELL_BOSS_OBJECT_VISUAL = 11206,
- SPELL_BOSS_AGGRO = 10340,
- SPELL_SUB_BOSS_AGGRO = 11568,
- SPELL_AWAKEN_VAULT_WALKER = 10258,
- SPELL_AWAKEN_EARTHEN_GUARDIAN = 10252,
- SPELL_SELF_DESTRUCT = 9874
+ SPELL_GROUND_TREMOR = 6524,
+ SPELL_ARCHAEDAS_AWAKEN = 10347,
+ SPELL_BOSS_OBJECT_VISUAL = 11206,
+ SPELL_BOSS_AGGRO = 10340,
+ SPELL_SUB_BOSS_AGGRO = 11568,
+ SPELL_AWAKEN_VAULT_WALKER = 10258,
+ SPELL_AWAKEN_EARTHEN_GUARDIAN = 10252,
+ SPELL_SELF_DESTRUCT = 9874,
+ SPELL_FREEZE_ANIM = 16245,
+ SPELL_MINION_FREEZE_ANIM = 10255
+
};
class boss_archaedas : public CreatureScript
@@ -96,6 +99,7 @@ class boss_archaedas : public CreatureScript
me->setFaction(35);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
+ me->AddAura(SPELL_FREEZE_ANIM, me);
}
void ActivateMinion(ObjectGuid uiGuid, bool flag)
@@ -109,6 +113,7 @@ class boss_archaedas : public CreatureScript
minion->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
minion->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
minion->setFaction(14);
+ minion->RemoveAura(SPELL_MINION_FREEZE_ANIM);
}
}
@@ -197,7 +202,7 @@ class boss_archaedas : public CreatureScript
DoMeleeAttackIfReady();
}
- void JustDied (Unit* /*killer*/)
+ void JustDied (Unit* /*killer*/) override
{
instance->SetData(DATA_ANCIENT_DOOR, DONE); // open the vault door
instance->SetData(DATA_MINIONS, SPECIAL); // deactivate his minions
@@ -258,6 +263,7 @@ class npc_archaedas_minions : public CreatureScript
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
me->RemoveAllAuras();
+ me->AddAura(SPELL_MINION_FREEZE_ANIM, me);
}
void EnterCombat(Unit* /*who*/) override
@@ -297,7 +303,7 @@ class npc_archaedas_minions : public CreatureScript
{
bWakingUp = false;
bAmIAwake = true;
- // AttackStart(ObjectAccessor::GetUnit(*me, instance->GetGuidData(0))); // whoWokeArchaedasGUID
+ AttackStart(ObjectAccessor::GetUnit(*me, instance->GetGuidData(0))); // whoWokeArchaedasGUID
return; // dont want to continue until we finish the AttackStart method
}
@@ -346,6 +352,7 @@ class npc_stonekeepers : public CreatureScript
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
me->RemoveAllAuras();
+ me->AddAura(SPELL_MINION_FREEZE_ANIM, me);
}
void EnterCombat(Unit* /*who*/) override
diff --git a/src/server/scripts/EasternKingdoms/Uldaman/boss_ironaya.cpp b/src/server/scripts/EasternKingdoms/Uldaman/boss_ironaya.cpp
index de899c04e1a..7f0faa138ec 100644
--- a/src/server/scripts/EasternKingdoms/Uldaman/boss_ironaya.cpp
+++ b/src/server/scripts/EasternKingdoms/Uldaman/boss_ironaya.cpp
@@ -28,10 +28,9 @@ EndScriptData */
enum Ironaya
{
- SAY_AGGRO = 0,
SPELL_ARCINGSMASH = 8374,
SPELL_KNOCKAWAY = 10101,
- SPELL_WSTOMP = 11876,
+ SPELL_WSTOMP = 11876
};
class boss_ironaya : public CreatureScript
@@ -66,10 +65,7 @@ class boss_ironaya : public CreatureScript
Initialize();
}
- void EnterCombat(Unit* /*who*/) override
- {
- Talk(SAY_AGGRO);
- }
+ void EnterCombat(Unit* /*who*/) override { }
void UpdateAI(uint32 uiDiff) override
{
diff --git a/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp b/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp
index 9d33d41af62..11699d4ec43 100644
--- a/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp
+++ b/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp
@@ -18,12 +18,13 @@
/* ScriptData
SDName: instance_uldaman
-SD%Complete: 99
+SD%Complete: 80%
SDComment: Need some cosmetics updates when archeadas door are closing (Guardians Waypoints).
SDCategory: Uldaman
EndScriptData */
#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
#include "InstanceScript.h"
#include "uldaman.h"
@@ -31,6 +32,8 @@ enum Spells
{
SPELL_ARCHAEDAS_AWAKEN = 10347,
SPELL_AWAKEN_VAULT_WALKER = 10258,
+ SPELL_FREEZE_ANIM = 16245,
+ SPELL_MINION_FREEZE_ANIM = 10255
};
enum Events
@@ -38,6 +41,13 @@ enum Events
EVENT_SUB_BOSS_AGGRO = 2228
};
+enum IronayaTalk
+{
+ SAY_AGGRO = 0
+};
+
+const Position IronayaPoint = { -231.228f, 246.6135f, -49.01617f, 0.0f };
+
class instance_uldaman : public InstanceMapScript
{
public:
@@ -136,9 +146,9 @@ class instance_uldaman : public InstanceMapScript
{
creature->setFaction(35);
creature->RemoveAllAuras();
- //creature->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_ANIMATION_FROZEN);
creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
+ creature->AddAura(SPELL_MINION_FREEZE_ANIM, creature);
}
void SetDoor(ObjectGuid guid, bool open)
@@ -171,6 +181,8 @@ class instance_uldaman : public InstanceMapScript
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
target->setFaction(14);
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ target->RemoveAura(SPELL_MINION_FREEZE_ANIM);
+
return; // only want the first one we find
}
// if we get this far than all four are dead so open the door
@@ -190,11 +202,13 @@ class instance_uldaman : public InstanceMapScript
Creature* target = instance->GetCreature(*i);
if (!target || !target->IsAlive() || target->getFaction() == 14)
continue;
- archaedas->CastSpell(target, SPELL_AWAKEN_VAULT_WALKER, true);
- target->CastSpell(target, SPELL_ARCHAEDAS_AWAKEN, true);
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
target->setFaction(14);
+ target->RemoveAura(SPELL_MINION_FREEZE_ANIM);
+ archaedas->CastSpell(target, SPELL_AWAKEN_VAULT_WALKER, true);
+ target->CastSpell(target, SPELL_ARCHAEDAS_AWAKEN, true);
+
return; // only want the first one we find
}
}
@@ -241,6 +255,7 @@ class instance_uldaman : public InstanceMapScript
if (ObjectAccessor::GetUnit(*archaedas, target))
{
+ archaedas->RemoveAura(SPELL_FREEZE_ANIM);
archaedas->CastSpell(archaedas, SPELL_ARCHAEDAS_AWAKEN, false);
whoWokeuiArchaedasGUID = target;
}
@@ -255,6 +270,12 @@ class instance_uldaman : public InstanceMapScript
ironaya->setFaction(415);
ironaya->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
ironaya->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+
+ ironaya->GetMotionMaster()->Clear();
+ ironaya->GetMotionMaster()->MovePoint(0, IronayaPoint);
+ ironaya->SetHomePosition(IronayaPoint);
+
+ ironaya->AI()->Talk(SAY_AGGRO);
}
void RespawnMinions()
diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp
index 1a98c081570..a9abb2c045d 100644
--- a/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp
+++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp
@@ -694,7 +694,7 @@ class boss_gazakroth : public CreatureScript
public:
boss_gazakroth() : CreatureScript("boss_gazakroth") { }
-
+
struct boss_gazakrothAI : public boss_hexlord_addAI
{
boss_gazakrothAI(Creature* creature) : boss_hexlord_addAI(creature)
@@ -706,7 +706,7 @@ class boss_gazakroth : public CreatureScript
{
firebolt_timer = 2 * IN_MILLISECONDS;
}
-
+
void Reset() override
{
Initialize();
diff --git a/src/server/scripts/EasternKingdoms/zone_arathi_highlands.cpp b/src/server/scripts/EasternKingdoms/zone_arathi_highlands.cpp
index 7c4190a648d..ac261f29287 100644
--- a/src/server/scripts/EasternKingdoms/zone_arathi_highlands.cpp
+++ b/src/server/scripts/EasternKingdoms/zone_arathi_highlands.cpp
@@ -114,7 +114,7 @@ class npc_professor_phizzlethorpe : public CreatureScript
Talk(SAY_AGGRO);
}
- void sQuestAccept(Player* player, Quest const* quest)
+ void sQuestAccept(Player* player, Quest const* quest) override
{
if (quest->GetQuestId() == QUEST_SUNKEN_TREASURE)
{
diff --git a/src/server/scripts/EasternKingdoms/zone_hinterlands.cpp b/src/server/scripts/EasternKingdoms/zone_hinterlands.cpp
index a29bb9b75b3..5b63c509eaa 100644
--- a/src/server/scripts/EasternKingdoms/zone_hinterlands.cpp
+++ b/src/server/scripts/EasternKingdoms/zone_hinterlands.cpp
@@ -75,7 +75,7 @@ public:
summoned->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ());
}
- void sQuestAccept(Player* player, Quest const* quest)
+ void sQuestAccept(Player* player, Quest const* quest) override
{
if (quest->GetQuestId() == QUEST_RESQUE_OOX_09)
{
diff --git a/src/server/scripts/EasternKingdoms/zone_undercity.cpp b/src/server/scripts/EasternKingdoms/zone_undercity.cpp
index 9ce694fb76c..d7d06a2e3ab 100644
--- a/src/server/scripts/EasternKingdoms/zone_undercity.cpp
+++ b/src/server/scripts/EasternKingdoms/zone_undercity.cpp
@@ -40,25 +40,44 @@ EndContentData */
enum Sylvanas
{
- QUEST_JOURNEY_TO_UNDERCITY = 9180,
- EMOTE_LAMENT_END = 0,
- SAY_LAMENT_END = 1,
+ QUEST_JOURNEY_TO_UNDERCITY = 9180,
- SOUND_CREDIT = 10896,
- ENTRY_HIGHBORNE_LAMENTER = 21628,
- ENTRY_HIGHBORNE_BUNNY = 21641,
+ EMOTE_LAMENT_END = 0,
+ SAY_LAMENT_END = 1,
+ EMOTE_LAMENT = 2,
- SPELL_HIGHBORNE_AURA = 37090,
- SPELL_SYLVANAS_CAST = 36568,
- SPELL_RIBBON_OF_SOULS = 34432, // the real one to use might be 37099
+ // Ambassador Sunsorrow
+ SAY_SUNSORROW_WHISPER = 0,
+
+ SOUND_CREDIT = 10896,
+
+ NPC_HIGHBORNE_LAMENTER = 21628,
+ NPC_HIGHBORNE_BUNNY = 21641,
+ NPC_AMBASSADOR_SUNSORROW = 16287,
+
+ SPELL_HIGHBORNE_AURA = 37090,
+ SPELL_SYLVANAS_CAST = 36568,
+ //SPELL_RIBBON_OF_SOULS = 34432, the real one to use might be 37099
+ SPELL_RIBBON_OF_SOULS = 37099,
// Combat spells
- SPELL_BLACK_ARROW = 59712,
- SPELL_FADE = 20672,
- SPELL_FADE_BLINK = 29211,
- SPELL_MULTI_SHOT = 59713,
- SPELL_SHOT = 59710,
- SPELL_SUMMON_SKELETON = 59711
+ SPELL_BLACK_ARROW = 59712,
+ SPELL_FADE = 20672,
+ SPELL_FADE_BLINK = 29211,
+ SPELL_MULTI_SHOT = 59713,
+ SPELL_SHOT = 59710,
+ SPELL_SUMMON_SKELETON = 59711,
+
+ // Events
+ EVENT_FADE = 1,
+ EVENT_SUMMON_SKELETON = 2,
+ EVENT_BLACK_ARROW = 3,
+ EVENT_SHOOT = 4,
+ EVENT_MULTI_SHOT = 5,
+ EVENT_LAMENT_OF_THE_HIGHBORN = 6,
+ EVENT_SUNSORROW_WHISPER = 7,
+
+ GUID_EVENT_INVOKER = 1,
};
float HighborneLoc[4][3]=
@@ -77,26 +96,14 @@ class npc_lady_sylvanas_windrunner : public CreatureScript
public:
npc_lady_sylvanas_windrunner() : CreatureScript("npc_lady_sylvanas_windrunner") { }
- bool OnQuestReward(Player* /*player*/, Creature* creature, const Quest *_Quest, uint32 /*slot*/) override
+ bool OnQuestReward(Player* player, Creature* creature, const Quest *_Quest, uint32 /*slot*/) override
{
if (_Quest->GetQuestId() == QUEST_JOURNEY_TO_UNDERCITY)
- {
- ENSURE_AI(npc_lady_sylvanas_windrunner::npc_lady_sylvanas_windrunnerAI, creature->AI())->LamentEvent = true;
- ENSURE_AI(npc_lady_sylvanas_windrunner::npc_lady_sylvanas_windrunnerAI, creature->AI())->DoPlaySoundToSet(creature, SOUND_CREDIT);
- creature->CastSpell(creature, SPELL_SYLVANAS_CAST, false);
-
- for (uint8 i = 0; i < 4; ++i)
- creature->SummonCreature(ENTRY_HIGHBORNE_LAMENTER, HighborneLoc[i][0], HighborneLoc[i][1], HIGHBORNE_LOC_Y, HighborneLoc[i][2], TEMPSUMMON_TIMED_DESPAWN, 160000);
- }
+ creature->AI()->SetGUID(player->GetGUID(), GUID_EVENT_INVOKER);
return true;
}
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_lady_sylvanas_windrunnerAI(creature);
- }
-
struct npc_lady_sylvanas_windrunnerAI : public ScriptedAI
{
npc_lady_sylvanas_windrunnerAI(Creature* creature) : ScriptedAI(creature)
@@ -106,41 +113,51 @@ public:
void Initialize()
{
- LamentEventTimer = 5000;
LamentEvent = false;
targetGUID.Clear();
-
- FadeTimer = 30000;
- SummonSkeletonTimer = 20000;
- BlackArrowTimer = 15000;
- ShotTimer = 8000;
- MultiShotTimer = 10000;
+ playerGUID.Clear();
}
- uint32 LamentEventTimer;
- bool LamentEvent;
- ObjectGuid targetGUID;
-
- uint32 FadeTimer;
- uint32 SummonSkeletonTimer;
- uint32 BlackArrowTimer;
- uint32 ShotTimer;
- uint32 MultiShotTimer;
-
void Reset() override
{
Initialize();
+ _events.Reset();
}
- void EnterCombat(Unit* /*who*/) override { }
+ void EnterCombat(Unit* /*who*/) override
+ {
+ _events.ScheduleEvent(EVENT_FADE, 30000);
+ _events.ScheduleEvent(EVENT_SUMMON_SKELETON, 20000);
+ _events.ScheduleEvent(EVENT_BLACK_ARROW, 15000);
+ _events.ScheduleEvent(EVENT_SHOOT, 8000);
+ _events.ScheduleEvent(EVENT_MULTI_SHOT, 10000);
+ }
+
+ void SetGUID(ObjectGuid guid, int32 type) override
+ {
+ if (type == GUID_EVENT_INVOKER)
+ {
+ Talk(EMOTE_LAMENT);
+ DoPlaySoundToSet(me, SOUND_CREDIT);
+ DoCast(me, SPELL_SYLVANAS_CAST, false);
+ playerGUID = guid;
+ LamentEvent = true;
+
+ for (uint8 i = 0; i < 4; ++i)
+ me->SummonCreature(NPC_HIGHBORNE_LAMENTER, HighborneLoc[i][0], HighborneLoc[i][1], HIGHBORNE_LOC_Y, HighborneLoc[i][2], TEMPSUMMON_TIMED_DESPAWN, 160000);
+
+ _events.ScheduleEvent(EVENT_LAMENT_OF_THE_HIGHBORN, 2000);
+ _events.ScheduleEvent(EVENT_SUNSORROW_WHISPER, 10000);
+ }
+ }
void JustSummoned(Creature* summoned) override
{
- if (summoned->GetEntry() == ENTRY_HIGHBORNE_BUNNY)
+ if (summoned->GetEntry() == NPC_HIGHBORNE_BUNNY)
{
if (Creature* target = ObjectAccessor::GetCreature(*summoned, targetGUID))
{
- target->MonsterMoveWithSpeed(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0);
+ target->GetMotionMaster()->MoveJump(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ() + 15.0f, 0);
target->SetPosition(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0.0f);
summoned->CastSpell(target, SPELL_RIBBON_OF_SOULS, false);
}
@@ -152,75 +169,86 @@ public:
void UpdateAI(uint32 diff) override
{
- if (LamentEvent)
- {
- if (LamentEventTimer <= diff)
- {
- DoSummon(ENTRY_HIGHBORNE_BUNNY, me, 10.0f, 3000, TEMPSUMMON_TIMED_DESPAWN);
-
- LamentEventTimer = 2000;
- if (!me->HasAura(SPELL_SYLVANAS_CAST))
- {
- Talk(SAY_LAMENT_END);
- Talk(EMOTE_LAMENT_END);
- LamentEvent = false;
- }
- } else LamentEventTimer -= diff;
- }
-
- if (!UpdateVictim())
+ if (!UpdateVictim() && !LamentEvent)
return;
- // Combat spells
+ _events.Update(diff);
- if (FadeTimer <= diff)
- {
- DoCast(me, SPELL_FADE);
- // add a blink to simulate a stealthed movement and reappearing elsewhere
- DoCast(me, SPELL_FADE_BLINK);
- FadeTimer = 30000 + rand32() % 5000;
- // if the victim is out of melee range she cast multi shot
- if (Unit* victim = me->GetVictim())
- if (me->GetDistance(victim) > 10.0f)
- DoCast(victim, SPELL_MULTI_SHOT);
- } else FadeTimer -= diff;
-
- if (SummonSkeletonTimer <= diff)
- {
- DoCast(me, SPELL_SUMMON_SKELETON);
- SummonSkeletonTimer = 20000 + rand32() % 10000;
- } else SummonSkeletonTimer -= diff;
-
- if (BlackArrowTimer <= diff)
- {
- if (Unit* victim = me->GetVictim())
- {
- DoCast(victim, SPELL_BLACK_ARROW);
- BlackArrowTimer = 15000 + rand32() % 5000;
- }
- } else BlackArrowTimer -= diff;
-
- if (ShotTimer <= diff)
- {
- if (Unit* victim = me->GetVictim())
- {
- DoCast(victim, SPELL_SHOT);
- ShotTimer = 8000 + rand32() % 2000;
- }
- } else ShotTimer -= diff;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- if (MultiShotTimer <= diff)
+ while (uint32 eventId = _events.ExecuteEvent())
{
- if (Unit* victim = me->GetVictim())
+ switch (eventId)
{
- DoCast(victim, SPELL_MULTI_SHOT);
- MultiShotTimer = 10000 + rand32() % 3000;
+ case EVENT_FADE:
+ DoCast(me, SPELL_FADE);
+ // add a blink to simulate a stealthed movement and reappearing elsewhere
+ DoCast(me, SPELL_FADE_BLINK);
+ // if the victim is out of melee range she cast multi shot
+ if (Unit* victim = me->GetVictim())
+ if (me->GetDistance(victim) > 10.0f)
+ DoCast(victim, SPELL_MULTI_SHOT);
+ _events.ScheduleEvent(EVENT_FADE, urand(30000, 35000));
+ break;
+ case EVENT_SUMMON_SKELETON:
+ DoCast(me, SPELL_SUMMON_SKELETON);
+ _events.ScheduleEvent(EVENT_SUMMON_SKELETON, urand(20000, 30000));
+ break;
+ case EVENT_BLACK_ARROW:
+ if (Unit* victim = me->GetVictim())
+ DoCast(victim, SPELL_BLACK_ARROW);
+ _events.ScheduleEvent(EVENT_BLACK_ARROW, urand(15000, 20000));
+ break;
+ case EVENT_SHOOT:
+ if (Unit* victim = me->GetVictim())
+ DoCast(victim, SPELL_SHOT);
+ _events.ScheduleEvent(EVENT_SHOOT, urand(8000, 10000));
+ break;
+ case EVENT_MULTI_SHOT:
+ if (Unit* victim = me->GetVictim())
+ DoCast(victim, SPELL_MULTI_SHOT);
+ _events.ScheduleEvent(EVENT_MULTI_SHOT, urand(10000, 13000));
+ break;
+ case EVENT_LAMENT_OF_THE_HIGHBORN:
+ if (!me->HasAura(SPELL_SYLVANAS_CAST))
+ {
+ Talk(SAY_LAMENT_END);
+ Talk(EMOTE_LAMENT_END);
+ LamentEvent = false;
+ me->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL);
+ Reset();
+ }
+ else
+ {
+ DoSummon(NPC_HIGHBORNE_BUNNY, me, 10.0f, 3000, TEMPSUMMON_TIMED_DESPAWN);
+ _events.ScheduleEvent(EVENT_LAMENT_OF_THE_HIGHBORN, 2000);
+ }
+ break;
+ case EVENT_SUNSORROW_WHISPER:
+ if (Creature* ambassador = me->FindNearestCreature(NPC_AMBASSADOR_SUNSORROW, 20.0f))
+ if (Player* player = ObjectAccessor::GetPlayer(*me, playerGUID))
+ ambassador->AI()->Talk(SAY_SUNSORROW_WHISPER, player);
+ break;
+ default:
+ break;
}
- } else MultiShotTimer -= diff;
+ }
DoMeleeAttackIfReady();
}
+
+ private:
+ EventMap _events;
+ bool LamentEvent;
+ ObjectGuid targetGUID;
+ ObjectGuid playerGUID;
};
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_lady_sylvanas_windrunnerAI(creature);
+ }
};
/*######
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp
index 0311ed61c6a..ecda065fda9 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp
@@ -32,8 +32,7 @@ enum Spells
SPELL_CURSE_OF_EXERTION = 52772,
SPELL_TIME_WARP = 52766, //Time slows down, reducing attack, casting and movement speed by 70% for 6 sec.
SPELL_TIME_STOP = 58848, //Stops time in a 50 yard sphere for 2 sec.
- SPELL_WOUNDING_STRIKE = 52771, //Used only on the tank
- H_SPELL_WOUNDING_STRIKE = 58830
+ SPELL_WOUNDING_STRIKE = 52771 //Used only on the tank
};
enum Yells
@@ -45,109 +44,78 @@ enum Yells
SAY_DEATH = 4
};
-class boss_epoch : public CreatureScript
+enum Events
{
-public:
- boss_epoch() : CreatureScript("boss_epoch") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_epochAI>(creature);
- }
-
- struct boss_epochAI : public ScriptedAI
- {
- boss_epochAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- instance = creature->GetInstanceScript();
- }
-
- void Initialize()
- {
- uiStep = 1;
- uiStepTimer = 26000;
- uiCurseOfExertionTimer = 9300;
- uiTimeWarpTimer = 25300;
- uiTimeStopTimer = 21300;
- uiWoundingStrikeTimer = 5300;
- }
-
- uint8 uiStep;
-
- uint32 uiStepTimer;
- uint32 uiWoundingStrikeTimer;
- uint32 uiTimeWarpTimer;
- uint32 uiTimeStopTimer;
- uint32 uiCurseOfExertionTimer;
-
- InstanceScript* instance;
-
- void Reset() override
- {
- Initialize();
-
- instance->SetBossState(DATA_EPOCH, NOT_STARTED);
- }
-
- void EnterCombat(Unit* /*who*/) override
- {
- Talk(SAY_AGGRO);
+ EVENT_CURSE_OF_EXERTION = 1,
+ EVENT_TIME_WARP,
+ EVENT_TIME_STOP,
+ EVENT_WOUNDING_STRIKE
+};
- instance->SetBossState(DATA_EPOCH, IN_PROGRESS);
- }
+class boss_epoch : public CreatureScript
+{
+ public:
+ boss_epoch() : CreatureScript("boss_epoch") { }
- void UpdateAI(uint32 diff) override
+ struct boss_epochAI : public BossAI
{
- //Return since we have no target
- if (!UpdateVictim())
- return;
+ boss_epochAI(Creature* creature) : BossAI(creature, DATA_EPOCH) { }
- if (uiCurseOfExertionTimer < diff)
+ void EnterCombat(Unit* /*who*/) override
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- DoCast(target, SPELL_CURSE_OF_EXERTION);
- uiCurseOfExertionTimer = 9300;
- } else uiCurseOfExertionTimer -= diff;
+ Talk(SAY_AGGRO);
+ _EnterCombat();
- if (uiWoundingStrikeTimer < diff)
- {
- DoCastVictim(SPELL_WOUNDING_STRIKE);
- uiWoundingStrikeTimer = 5300;
- } else uiWoundingStrikeTimer -= diff;
+ events.ScheduleEvent(EVENT_CURSE_OF_EXERTION, 9300);
+ events.ScheduleEvent(EVENT_TIME_WARP, 25300);
+ events.ScheduleEvent(EVENT_TIME_STOP, 21300);
+ events.ScheduleEvent(EVENT_WOUNDING_STRIKE, 5300);
+ }
- if (uiTimeStopTimer < diff)
+ void ExecuteEvent(uint32 eventId) override
{
- DoCastAOE(SPELL_TIME_STOP);
- uiTimeStopTimer = 21300;
- } else uiTimeStopTimer -= diff;
-
- if (uiTimeWarpTimer < diff)
+ switch (eventId)
+ {
+ case EVENT_CURSE_OF_EXERTION:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_CURSE_OF_EXERTION);
+ events.ScheduleEvent(EVENT_CURSE_OF_EXERTION, 9300);
+ break;
+ case EVENT_TIME_WARP:
+ Talk(SAY_TIME_WARP);
+ DoCastAOE(SPELL_TIME_WARP);
+ events.ScheduleEvent(EVENT_TIME_WARP, 25300);
+ break;
+ case EVENT_TIME_STOP:
+ DoCastAOE(SPELL_TIME_STOP);
+ events.ScheduleEvent(EVENT_TIME_STOP, 21300);
+ break;
+ case EVENT_WOUNDING_STRIKE:
+ DoCastVictim(SPELL_WOUNDING_STRIKE);
+ events.ScheduleEvent(EVENT_WOUNDING_STRIKE, 5300);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void JustDied(Unit* /*killer*/) override
{
- Talk(SAY_TIME_WARP);
- DoCastAOE(SPELL_TIME_WARP);
- uiTimeWarpTimer = 25300;
- } else uiTimeWarpTimer -= diff;
+ Talk(SAY_DEATH);
+ _JustDied();
+ }
- DoMeleeAttackIfReady();
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- Talk(SAY_DEATH);
-
- instance->SetBossState(DATA_EPOCH, DONE);
- }
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
+ }
+ };
- void KilledUnit(Unit* victim) override
+ CreatureAI* GetAI(Creature* creature) const override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_SLAY);
+ return GetInstanceAI<boss_epochAI>(creature);
}
- };
-
};
void AddSC_boss_epoch()
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
index f672871922a..b5d2931377f 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
@@ -421,7 +421,7 @@ public:
gossipStep = 0;
}
- void AttackStart(Unit* who)
+ void AttackStart(Unit* who) override
{
if (who && !who->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC))
npc_escortAI::AttackStart(who);
diff --git a/src/server/scripts/Kalimdor/RazorfenKraul/instance_razorfen_kraul.cpp b/src/server/scripts/Kalimdor/RazorfenKraul/instance_razorfen_kraul.cpp
index 2b00254167d..d8966ec76c1 100644
--- a/src/server/scripts/Kalimdor/RazorfenKraul/instance_razorfen_kraul.cpp
+++ b/src/server/scripts/Kalimdor/RazorfenKraul/instance_razorfen_kraul.cpp
@@ -76,7 +76,7 @@ public:
}
}
- void Update(uint32 /*diff*/)
+ void Update(uint32 /*diff*/) override
{
if (WardKeeperDeath == WARD_KEEPERS_NR)
if (GameObject* go = instance->GetGameObject(DoorWardGUID))
diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp
index f8873b06a75..d16a86f350f 100644
--- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp
+++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp
@@ -57,7 +57,7 @@ class instance_ruins_of_ahnqiraj : public InstanceMapScript
}
}
- bool SetBossState(uint32 bossId, EncounterState state)
+ bool SetBossState(uint32 bossId, EncounterState state) override
{
if (!InstanceScript::SetBossState(bossId, state))
return false;
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp
index 50fd94e66ee..65ffb7fd696 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp
@@ -99,7 +99,7 @@ struct boss_twinemperorsAI : public ScriptedAI
uint32 EnrageTimer;
virtual bool IAmVeklor() = 0;
- virtual void Reset() = 0;
+ virtual void Reset() override = 0;
virtual void CastSpellOnBug(Creature* target) = 0;
void TwinReset()
@@ -400,7 +400,7 @@ public:
struct boss_veknilashAI : public boss_twinemperorsAI
{
- bool IAmVeklor() {return false;}
+ bool IAmVeklor() override {return false;}
boss_veknilashAI(Creature* creature) : boss_twinemperorsAI(creature)
{
Initialize();
@@ -425,7 +425,7 @@ public:
me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true);
}
- void CastSpellOnBug(Creature* target)
+ void CastSpellOnBug(Creature* target) override
{
target->setFaction(14);
target->AI()->AttackStart(me->getThreatManager().getHostilTarget());
@@ -488,7 +488,7 @@ public:
struct boss_veklorAI : public boss_twinemperorsAI
{
- bool IAmVeklor() {return true;}
+ bool IAmVeklor() override {return true;}
boss_veklorAI(Creature* creature) : boss_twinemperorsAI(creature)
{
Initialize();
@@ -516,7 +516,7 @@ public:
me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true);
}
- void CastSpellOnBug(Creature* target)
+ void CastSpellOnBug(Creature* target) override
{
target->setFaction(14);
target->AddAura(SPELL_EXPLODEBUG, target);
diff --git a/src/server/scripts/Kalimdor/ZulFarrak/instance_zulfarrak.cpp b/src/server/scripts/Kalimdor/ZulFarrak/instance_zulfarrak.cpp
index 244261a86c1..46e831b0f83 100644
--- a/src/server/scripts/Kalimdor/ZulFarrak/instance_zulfarrak.cpp
+++ b/src/server/scripts/Kalimdor/ZulFarrak/instance_zulfarrak.cpp
@@ -220,7 +220,7 @@ public:
};
}
- virtual void Update(uint32 diff)
+ virtual void Update(uint32 diff) override
{
switch (PyramidPhase)
{
diff --git a/src/server/scripts/Kalimdor/zone_ashenvale.cpp b/src/server/scripts/Kalimdor/zone_ashenvale.cpp
index 76b43729517..b8e6bfb85e8 100644
--- a/src/server/scripts/Kalimdor/zone_ashenvale.cpp
+++ b/src/server/scripts/Kalimdor/zone_ashenvale.cpp
@@ -24,7 +24,6 @@ SDCategory: Ashenvale Forest
EndScriptData */
/* ContentData
-npc_torek
npc_ruul_snowhoof
EndContentData */
@@ -34,132 +33,6 @@ EndContentData */
#include "Player.h"
/*####
-# npc_torek
-####*/
-
-enum Torek
-{
- SAY_READY = 0,
- SAY_MOVE = 1,
- SAY_PREPARE = 2,
- SAY_WIN = 3,
- SAY_END = 4,
- SPELL_REND = 11977,
- SPELL_THUNDERCLAP = 8078,
- QUEST_TOREK_ASSULT = 6544,
- NPC_SPLINTERTREE_RAIDER = 12859,
- NPC_DURIEL = 12860,
- NPC_SILVERWING_SENTINEL = 12896,
- NPC_SILVERWING_WARRIOR = 12897,
- FACTION_QUEST = 113
-};
-
-class npc_torek : public CreatureScript
-{
-public:
- npc_torek() : CreatureScript("npc_torek") { }
-
- struct npc_torekAI : public npc_escortAI
- {
- npc_torekAI(Creature* creature) : npc_escortAI(creature)
- {
- Initialize();
- }
-
- void Initialize()
- {
- rend_Timer = 5000;
- thunderclap_Timer = 8000;
- _completed = false;
- }
-
- void Reset() override
- {
- Initialize();
- }
-
- void EnterCombat(Unit* /*who*/) override { }
-
- void JustSummoned(Creature* summoned) override
- {
- summoned->AI()->AttackStart(me);
- }
-
- void sQuestAccept(Player* player, Quest const* quest)
- {
- if (quest->GetQuestId() == QUEST_TOREK_ASSULT)
- {
- /// @todo find companions, make them follow Torek, at any time (possibly done by core/database in future?)
- Talk(SAY_READY, player);
- me->setFaction(FACTION_QUEST);
- npc_escortAI::Start(true, true, player->GetGUID());
- }
- }
-
- void WaypointReached(uint32 waypointId) override
- {
- if (Player* player = GetPlayerForEscort())
- {
- switch (waypointId)
- {
- case 1:
- Talk(SAY_MOVE, player);
- break;
- case 8:
- Talk(SAY_PREPARE, player);
- break;
- case 19:
- /// @todo verify location and creatures amount.
- me->SummonCreature(NPC_DURIEL, 1776.73f, -2049.06f, 109.83f, 1.54f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
- me->SummonCreature(NPC_SILVERWING_SENTINEL, 1774.64f, -2049.41f, 109.83f, 1.40f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
- me->SummonCreature(NPC_SILVERWING_WARRIOR, 1778.73f, -2049.50f, 109.83f, 1.67f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
- break;
- case 20:
- Talk(SAY_WIN, player);
- _completed = true;
- player->GroupEventHappens(QUEST_TOREK_ASSULT, me);
- break;
- case 21:
- Talk(SAY_END, player);
- break;
- }
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- npc_escortAI::UpdateAI(diff);
-
- if (!UpdateVictim())
- return;
-
- if (rend_Timer <= diff)
- {
- DoCastVictim(SPELL_REND);
- rend_Timer = 20000;
- } else rend_Timer -= diff;
-
- if (thunderclap_Timer <= diff)
- {
- DoCast(me, SPELL_THUNDERCLAP);
- thunderclap_Timer = 30000;
- } else thunderclap_Timer -= diff;
- }
-
- private:
- uint32 rend_Timer;
- uint32 thunderclap_Timer;
- bool _completed;
-
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_torekAI(creature);
- }
-};
-
-/*####
# npc_ruul_snowhoof
####*/
@@ -169,6 +42,7 @@ enum RuulSnowhoof
NPC_THISTLEFUR_TOTEMIC = 3922,
NPC_THISTLEFUR_PATHFINDER = 3926,
QUEST_FREEDOM_TO_RUUL = 6482,
+ FACTION_QUEST = 113,
GO_CAGE = 178147
};
@@ -204,7 +78,7 @@ public:
summoned->AI()->AttackStart(me);
}
- void sQuestAccept(Player* player, Quest const* quest)
+ void sQuestAccept(Player* player, Quest const* quest) override
{
if (quest->GetQuestId() == QUEST_FREEDOM_TO_RUUL)
{
@@ -346,7 +220,7 @@ public:
summoned->AI()->AttackStart(me);
}
- void sQuestAccept(Player* player, Quest const* quest)
+ void sQuestAccept(Player* player, Quest const* quest) override
{
if (quest->GetQuestId() == QUEST_VORSHA)
{
@@ -472,7 +346,6 @@ class go_naga_brazier : public GameObjectScript
void AddSC_ashenvale()
{
- new npc_torek();
new npc_ruul_snowhoof();
new npc_muglash();
new go_naga_brazier();
diff --git a/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp b/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp
index 1eb600cce99..5c9a57acec7 100644
--- a/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp
+++ b/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp
@@ -351,7 +351,7 @@ public:
Talk(SAY_AGGRO, who);
}
- void sQuestAccept(Player* player, Quest const* quest)
+ void sQuestAccept(Player* player, Quest const* quest) override
{
if (quest->GetQuestId() == QUEST_A_CRY_FOR_SAY_HELP)
{
diff --git a/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp b/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
index ca5e4697c35..ab2e82171f1 100644
--- a/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
+++ b/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
@@ -27,10 +27,14 @@ EndScriptData */
npc_webbed_creature
EndContentData */
+#include "Player.h"
+#include "Group.h"
+#include "GridNotifiersImpl.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "ScriptedEscortAI.h"
#include "PassiveAI.h"
-#include "Player.h"
+#include "CellImpl.h"
/*######
## npc_webbed_creature
@@ -88,7 +92,731 @@ public:
}
};
+/*######
+## Quest 9759: Ending Their World
+######*/
+
+enum EndingTheirWorldMisc
+{
+ SAY_SIRONAS_1 = 0,
+
+ SAY_LEGOSO_1 = 0,
+ SAY_LEGOSO_2 = 1,
+ SAY_LEGOSO_3 = 2,
+ SAY_LEGOSO_4 = 3,
+ SAY_LEGOSO_5 = 4,
+ SAY_LEGOSO_6 = 5,
+ SAY_LEGOSO_7 = 6,
+ SAY_LEGOSO_8 = 7,
+ SAY_LEGOSO_9 = 8,
+ SAY_LEGOSO_10 = 9,
+ SAY_LEGOSO_11 = 10,
+ SAY_LEGOSO_12 = 11,
+ SAY_LEGOSO_13 = 12,
+ SAY_LEGOSO_14 = 13,
+ SAY_LEGOSO_15 = 14,
+ SAY_LEGOSO_16 = 15,
+ SAY_LEGOSO_17 = 16,
+ SAY_LEGOSO_18 = 17,
+ SAY_LEGOSO_19 = 18,
+ SAY_LEGOSO_20 = 19,
+ SAY_LEGOSO_21 = 20,
+
+ SPELL_BLOODMYST_TESLA = 31611,
+ SPELL_SIRONAS_CHANNELING = 31612,
+
+ SPELL_UPPERCUT = 10966,
+ SPELL_IMMOLATE = 12742,
+ SPELL_CURSE_OF_BLOOD = 8282,
+
+ SPELL_FROST_SHOCK = 8056,
+ SPELL_HEALING_SURGE = 8004,
+ SPELL_SEARING_TOTEM = 38116,
+ SPELL_STRENGTH_OF_EARTH_TOTEM = 31633,
+
+ NPC_SIRONAS = 17678,
+ NPC_BLOODMYST_TESLA_COIL = 17979,
+ NPC_LEGOSO = 17982,
+
+ GO_DRAENEI_EXPLOSIVES_1 = 182088,
+ GO_DRAENEI_EXPLOSIVES_2 = 182091,
+ GO_FIRE_EXPLOSION = 182071,
+
+ ACTION_SIRONAS_CHANNEL_START = 1,
+ ACTION_SIRONAS_CHANNEL_STOP = 2,
+
+ ACTION_LEGOSO_SIRONAS_KILLED = 1,
+
+ EVENT_UPPERCUT = 1,
+ EVENT_IMMOLATE = 2,
+ EVENT_CURSE_OF_BLOOD = 3,
+
+ EVENT_FROST_SHOCK = 1,
+ EVENT_HEALING_SURGE = 2,
+ EVENT_SEARING_TOTEM = 3,
+ EVENT_STRENGTH_OF_EARTH_TOTEM = 4,
+
+ WP_START = 1,
+ WP_EXPLOSIVES_FIRST_POINT = 21,
+ WP_EXPLOSIVES_FIRST_PLANT = 22,
+ WP_EXPLOSIVES_FIRST_RUNOFF = 23,
+ WP_EXPLOSIVES_FIRST_DETONATE = 24,
+ WP_DEBUG_1 = 25,
+ WP_DEBUG_2 = 26,
+ WP_SIRONAS_HILL = 33,
+ WP_EXPLOSIVES_SECOND_BATTLEROAR = 35,
+ WP_EXPLOSIVES_SECOND_PLANT = 39,
+ WP_EXPLOSIVES_SECOND_DETONATE = 40,
+
+ PHASE_NONE = 0,
+ PHASE_CONTINUE = -1,
+ PHASE_WP_26 = 1,
+ PHASE_WP_22 = 2,
+ PHASE_PLANT_FIRST_KNEEL = 3,
+ PHASE_PLANT_FIRST_STAND = 4,
+ PHASE_PLANT_FIRST_WORK = 5,
+ PHASE_PLANT_FIRST_FINISH = 6,
+ PHASE_PLANT_FIRST_TIMER_1 = 7,
+ PHASE_PLANT_FIRST_TIMER_2 = 8,
+ PHASE_PLANT_FIRST_TIMER_3 = 9,
+ PHASE_PLANT_FIRST_DETONATE = 10,
+ PHASE_PLANT_FIRST_SPEECH = 11,
+ PHASE_PLANT_FIRST_ROTATE = 12,
+ PHASE_PLANT_FIRST_POINT = 13,
+ PHASE_FEEL_SIRONAS_1 = 14,
+ PHASE_FEEL_SIRONAS_2 = 15,
+ PHASE_MEET_SIRONAS_ROAR = 16,
+ PHASE_MEET_SIRONAS_TURN = 17,
+ PHASE_MEET_SIRONAS_SPEECH = 18,
+ PHASE_PLANT_SECOND_KNEEL = 19,
+ PHASE_PLANT_SECOND_SPEECH = 20,
+ PHASE_PLANT_SECOND_STAND = 21,
+ PHASE_PLANT_SECOND_FINISH = 22,
+ PHASE_PLANT_SECOND_WAIT = 23,
+ PHASE_PLANT_SECOND_TIMER_1 = 24,
+ PHASE_PLANT_SECOND_TIMER_2 = 25,
+ PHASE_PLANT_SECOND_TIMER_3 = 26,
+ PHASE_PLANT_SECOND_DETONATE = 27,
+ PHASE_FIGHT_SIRONAS_STOP = 28,
+ PHASE_FIGHT_SIRONAS_SPEECH_1 = 29,
+ PHASE_FIGHT_SIRONAS_SPEECH_2 = 30,
+ PHASE_FIGHT_SIRONAS_START = 31,
+ PHASE_SIRONAS_SLAIN_SPEECH_1 = 32,
+ PHASE_SIRONAS_SLAIN_EMOTE_1 = 33,
+ PHASE_SIRONAS_SLAIN_EMOTE_2 = 34,
+ PHASE_SIRONAS_SLAIN_SPEECH_2 = 35,
+
+ DATA_EVENT_STARTER_GUID = 0,
+
+ MAX_EXPLOSIVES = 5,
+
+ QUEST_ENDING_THEIR_WORLD = 9759
+};
+
+Position const ExplosivesPos[2][MAX_EXPLOSIVES] =
+{
+ {
+ { -1954.946f, -10654.714f, 110.448f },
+ { -1956.331f, -10654.494f, 110.869f },
+ { -1955.906f, -10656.221f, 110.791f },
+ { -1957.294f, -10656.000f, 111.219f },
+ { -1954.462f, -10656.451f, 110.404f }
+ },
+ {
+ { -1915.137f, -10583.651f, 178.365f },
+ { -1914.006f, -10582.964f, 178.471f },
+ { -1912.717f, -10582.398f, 178.658f },
+ { -1915.056f, -10582.251f, 178.162f },
+ { -1913.883f, -10581.778f, 178.346f }
+ }
+};
+
+/*######
+## npc_sironas
+######*/
+
+class npc_sironas : public CreatureScript
+{
+public:
+ npc_sironas() : CreatureScript("npc_sironas") { }
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_sironasAI(creature);
+ }
+
+ struct npc_sironasAI : public ScriptedAI
+ {
+ npc_sironasAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void Reset() override
+ {
+ _events.Reset();
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid2);
+ }
+
+ void EnterCombat(Unit* /*who*/) override
+ {
+ _events.ScheduleEvent(EVENT_UPPERCUT, 15 * IN_MILLISECONDS);
+ _events.ScheduleEvent(EVENT_IMMOLATE, 10 * IN_MILLISECONDS);
+ _events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 5 * IN_MILLISECONDS);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ me->SetObjectScale(1.0f);
+ _events.Reset();
+ if (Creature* legoso = me->FindNearestCreature(NPC_LEGOSO, SIZE_OF_GRIDS))
+ {
+ Group* group = me->GetLootRecipientGroup();
+
+ if (killer->GetGUID() == legoso->GetGUID() ||
+ (group && group->IsMember(killer->GetGUID())) ||
+ killer->GetGUIDLow() == legoso->AI()->GetData(DATA_EVENT_STARTER_GUID))
+ legoso->AI()->DoAction(ACTION_LEGOSO_SIRONAS_KILLED);
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_UPPERCUT:
+ DoCastVictim(SPELL_UPPERCUT);
+ _events.ScheduleEvent(EVENT_UPPERCUT, urand(10, 12) * IN_MILLISECONDS);
+ break;
+ case EVENT_IMMOLATE:
+ DoCastVictim(SPELL_IMMOLATE);
+ _events.ScheduleEvent(EVENT_IMMOLATE, urand(15, 20) * IN_MILLISECONDS);
+ break;
+ case EVENT_CURSE_OF_BLOOD:
+ DoCastVictim(SPELL_CURSE_OF_BLOOD);
+ _events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(20, 25) * IN_MILLISECONDS);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ void DoAction(int32 param) override
+ {
+ switch (param)
+ {
+ case ACTION_SIRONAS_CHANNEL_START:
+ {
+ DoCast(me, SPELL_SIRONAS_CHANNELING);
+ std::list<Creature*> BeamList;
+ _beamGuidList.clear();
+ me->GetCreatureListWithEntryInGrid(BeamList, NPC_BLOODMYST_TESLA_COIL, SIZE_OF_GRIDS);
+ for (std::list<Creature*>::iterator itr = BeamList.begin(); itr != BeamList.end(); ++itr)
+ {
+ _beamGuidList.push_back((*itr)->GetGUID());
+ (*itr)->CastSpell(*itr, SPELL_BLOODMYST_TESLA);
+ }
+ break;
+ }
+ case ACTION_SIRONAS_CHANNEL_STOP:
+ {
+ me->InterruptNonMeleeSpells(true, SPELL_SIRONAS_CHANNELING);
+ std::list<Creature*> creatureList;
+ GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLOODMYST_TESLA_COIL, 500.0f);
+ if (!creatureList.empty())
+ for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
+ (*itr)->InterruptNonMeleeSpells(true, SPELL_BLOODMYST_TESLA);
+ }
+ default:
+ break;
+ }
+ }
+
+ private:
+ GuidList _beamGuidList;
+ EventMap _events;
+ };
+};
+
+/*######
+## npc_demolitionist_legoso
+######*/
+
+class npc_demolitionist_legoso : public CreatureScript
+{
+public:
+ npc_demolitionist_legoso() : CreatureScript("npc_demolitionist_legoso") { }
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_demolitionist_legosoAI(creature);
+ }
+
+ struct npc_demolitionist_legosoAI : public npc_escortAI
+ {
+ npc_demolitionist_legosoAI(Creature* creature) : npc_escortAI(creature)
+ {
+ Initialize();
+ }
+
+ void sQuestAccept(Player* player, Quest const* quest) override
+ {
+ if (quest->GetQuestId() == QUEST_ENDING_THEIR_WORLD)
+ {
+ SetData(DATA_EVENT_STARTER_GUID, player->GetGUIDLow());
+ Start(true, true, player->GetGUID(), quest);
+ }
+ }
+
+ uint32 GetData(uint32 id) const override
+ {
+ switch (id)
+ {
+ case DATA_EVENT_STARTER_GUID:
+ return _eventStarterGuidLow;
+ default:
+ return 0;
+ }
+ }
+
+ void SetData(uint32 data, uint32 value) override
+ {
+ switch (data)
+ {
+ case DATA_EVENT_STARTER_GUID:
+ _eventStarterGuidLow = value;
+ break;
+ default:
+ break;
+ }
+ }
+
+ void Initialize()
+ {
+ _phase = PHASE_NONE;
+ _moveTimer = 0;
+ _eventStarterGuidLow = 0;
+ }
+
+ void Reset() override
+ {
+ Initialize();
+ me->SetCanDualWield(true);
+
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_FROST_SHOCK, 1 * IN_MILLISECONDS);
+ _events.ScheduleEvent(EVENT_HEALING_SURGE, 5 * IN_MILLISECONDS);
+ _events.ScheduleEvent(EVENT_SEARING_TOTEM, 15 * IN_MILLISECONDS);
+ _events.ScheduleEvent(EVENT_STRENGTH_OF_EARTH_TOTEM, 20 * IN_MILLISECONDS);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ if (UpdateVictim())
+ {
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_FROST_SHOCK:
+ DoCastVictim(SPELL_FROST_SHOCK);
+ _events.DelayEvents(1 * IN_MILLISECONDS);
+ _events.ScheduleEvent(EVENT_FROST_SHOCK, urand(10, 15) * IN_MILLISECONDS);
+ break;
+ case EVENT_SEARING_TOTEM:
+ DoCast(me, SPELL_SEARING_TOTEM);
+ _events.DelayEvents(1 * IN_MILLISECONDS);
+ _events.ScheduleEvent(EVENT_SEARING_TOTEM, urand(110, 130) * IN_MILLISECONDS);
+ break;
+ case EVENT_STRENGTH_OF_EARTH_TOTEM:
+ DoCast(me, SPELL_STRENGTH_OF_EARTH_TOTEM);
+ _events.DelayEvents(1 * IN_MILLISECONDS);
+ _events.ScheduleEvent(EVENT_STRENGTH_OF_EARTH_TOTEM, urand(110, 130) * IN_MILLISECONDS);
+ break;
+ case EVENT_HEALING_SURGE:
+ {
+ Unit* target = NULL;
+ if (me->GetHealthPct() < 85)
+ target = me;
+ else if (Player* player = GetPlayerForEscort())
+ if (player->GetHealthPct() < 85)
+ target = player;
+ if (target)
+ {
+ DoCast(target, SPELL_HEALING_SURGE);
+ _events.ScheduleEvent(EVENT_HEALING_SURGE, 10 * IN_MILLISECONDS);
+ }
+ else
+ _events.ScheduleEvent(EVENT_HEALING_SURGE, 2 * IN_MILLISECONDS);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ if (HasEscortState(STATE_ESCORT_NONE))
+ return;
+
+ npc_escortAI::UpdateAI(diff);
+
+ if (_phase)
+ {
+ if (_moveTimer <= diff)
+ {
+ switch (_phase)
+ {
+ case PHASE_WP_26: //debug skip path to point 26, buggy path calculation
+ me->GetMotionMaster()->MovePoint(WP_DEBUG_2, -2021.77f, -10648.8f, 129.903f, false);
+ _moveTimer = 2 * IN_MILLISECONDS;
+ _phase = PHASE_CONTINUE;
+ break;
+ case PHASE_CONTINUE: // continue escort
+ SetEscortPaused(false);
+ _moveTimer = 0 * IN_MILLISECONDS;
+ _phase = PHASE_NONE;
+ break;
+ case PHASE_WP_22: //debug skip path to point 22, buggy path calculation
+ me->GetMotionMaster()->MovePoint(WP_EXPLOSIVES_FIRST_PLANT, -1958.026f, -10660.465f, 111.547f, false);
+ Talk(SAY_LEGOSO_3);
+ _moveTimer = 2 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_FIRST_KNEEL;
+ break;
+ case PHASE_PLANT_FIRST_KNEEL: // plant first explosives stage 1 kneel
+ me->SetStandState(UNIT_STAND_STATE_KNEEL);
+ _moveTimer = 10 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_FIRST_STAND;
+ break;
+ case PHASE_PLANT_FIRST_STAND: // plant first explosives stage 1 stand
+ me->SetStandState(UNIT_STAND_STATE_STAND);
+ _moveTimer = 0.5* IN_MILLISECONDS;
+ _phase = PHASE_PLANT_FIRST_WORK;
+ break;
+ case PHASE_PLANT_FIRST_WORK: // plant first explosives stage 2 work
+ Talk(SAY_LEGOSO_4);
+ _moveTimer = 17.5 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_FIRST_FINISH;
+ break;
+ case PHASE_PLANT_FIRST_FINISH: // plant first explosives finish
+ _explosivesGuids.clear();
+ for (uint8 i = 0; i != MAX_EXPLOSIVES; ++i)
+ {
+ if (GameObject* explosive = me->SummonGameObject(GO_DRAENEI_EXPLOSIVES_1, ExplosivesPos[0][i].m_positionX, ExplosivesPos[0][i].m_positionY, ExplosivesPos[0][i].m_positionZ, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0))
+ _explosivesGuids.push_back(explosive->GetGUID());
+ }
+ me->HandleEmoteCommand(EMOTE_ONESHOT_NONE); // reset anim state
+ // force runoff movement so he will not screw up next waypoint
+ me->GetMotionMaster()->MovePoint(WP_EXPLOSIVES_FIRST_RUNOFF, -1955.6f, -10669.8f, 110.65f, false);
+ Talk(SAY_LEGOSO_5);
+ _moveTimer = 1.5 * IN_MILLISECONDS;
+ _phase = PHASE_CONTINUE;
+ break;
+ case PHASE_PLANT_FIRST_TIMER_1: // first explosives detonate timer 1
+ Talk(SAY_LEGOSO_6);
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_FIRST_TIMER_2;
+ break;
+ case PHASE_PLANT_FIRST_TIMER_2: // first explosives detonate timer 2
+ Talk(SAY_LEGOSO_7);
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_FIRST_TIMER_3;
+ break;
+ case PHASE_PLANT_FIRST_TIMER_3: // first explosives detonate timer 3
+ Talk(SAY_LEGOSO_8);
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_FIRST_DETONATE;
+ break;
+ case PHASE_PLANT_FIRST_DETONATE: // first explosives detonate finish
+ for (GuidList::iterator itr = _explosivesGuids.begin(); itr != _explosivesGuids.end(); ++itr)
+ {
+ if (GameObject* explosive = sObjectAccessor->GetGameObject(*me, *itr))
+ me->RemoveGameObject(explosive, true);
+ }
+ _explosivesGuids.clear();
+ me->HandleEmoteCommand(EMOTE_ONESHOT_CHEER);
+ _moveTimer = 2 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_FIRST_SPEECH;
+ break;
+ case PHASE_PLANT_FIRST_SPEECH: // after detonation 1 speech
+ Talk(SAY_LEGOSO_9);
+ _moveTimer = 4 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_FIRST_ROTATE;
+ break;
+ case PHASE_PLANT_FIRST_ROTATE: // after detonation 1 rotate to next point
+ me->SetFacingTo(2.272f);
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_FIRST_POINT;
+ break;
+ case PHASE_PLANT_FIRST_POINT: // after detonation 1 send point anim and go on to next point
+ me->HandleEmoteCommand(EMOTE_ONESHOT_POINT);
+ _moveTimer = 2 * IN_MILLISECONDS;
+ _phase = PHASE_CONTINUE;
+ break;
+ case PHASE_FEEL_SIRONAS_1: // legoso exclamation before sironas 1.1
+ Talk(SAY_LEGOSO_10);
+ _moveTimer = 4 * IN_MILLISECONDS;
+ _phase = PHASE_FEEL_SIRONAS_2;
+ break;
+ case PHASE_FEEL_SIRONAS_2: // legoso exclamation before sironas 1.2
+ Talk(SAY_LEGOSO_11);
+ _moveTimer = 4 * IN_MILLISECONDS;
+ _phase = PHASE_CONTINUE;
+ break;
+ case PHASE_MEET_SIRONAS_ROAR: // legoso exclamation before sironas 2.1
+ Talk(SAY_LEGOSO_12);
+ _moveTimer = 4 * IN_MILLISECONDS;
+ _phase = PHASE_MEET_SIRONAS_TURN;
+ break;
+ case PHASE_MEET_SIRONAS_TURN: // legoso exclamation before sironas 2.2
+ if (Player* player = GetPlayerForEscort())
+ me->SetFacingToObject(player);
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_MEET_SIRONAS_SPEECH;
+ break;
+ case PHASE_MEET_SIRONAS_SPEECH: // legoso exclamation before sironas 2.3
+ Talk(SAY_LEGOSO_13);
+ _moveTimer = 7 * IN_MILLISECONDS;
+ _phase = PHASE_CONTINUE;
+ break;
+ case PHASE_PLANT_SECOND_KNEEL: // plant second explosives stage 1 kneel
+ me->SetStandState(UNIT_STAND_STATE_KNEEL);
+ _moveTimer = 11 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_SECOND_SPEECH;
+ break;
+ case PHASE_PLANT_SECOND_SPEECH: // plant second explosives stage 2 kneel
+ Talk(SAY_LEGOSO_14);
+ _moveTimer = 13 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_SECOND_STAND;
+ break;
+ case PHASE_PLANT_SECOND_STAND: // plant second explosives finish
+ me->SetStandState(UNIT_STAND_STATE_STAND);
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_SECOND_FINISH;
+ break;
+ case PHASE_PLANT_SECOND_FINISH: // plant second explosives finish - create explosives
+ _explosivesGuids.clear();
+ for (uint8 i = 0; i != MAX_EXPLOSIVES; ++i)
+ {
+ if (GameObject* explosive = me->SummonGameObject(GO_DRAENEI_EXPLOSIVES_2, ExplosivesPos[1][i].m_positionX, ExplosivesPos[1][i].m_positionY, ExplosivesPos[1][i].m_positionZ, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0))
+ _explosivesGuids.push_back(explosive->GetGUID());
+ }
+ Talk(SAY_LEGOSO_15);
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_SECOND_WAIT;
+ break;
+ case PHASE_PLANT_SECOND_WAIT: // plant second explosives finish - proceed to next point
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_CONTINUE;
+ break;
+ case PHASE_PLANT_SECOND_TIMER_1: // second explosives detonate timer 1
+ Talk(SAY_LEGOSO_16);
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_SECOND_TIMER_2;
+ break;
+ case PHASE_PLANT_SECOND_TIMER_2: // second explosives detonate timer 2
+ Talk(SAY_LEGOSO_17);
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_SECOND_TIMER_3;
+ break;
+ case PHASE_PLANT_SECOND_TIMER_3: // second explosives detonate timer 3
+ Talk(SAY_LEGOSO_18);
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_SECOND_DETONATE;
+ break;
+ case PHASE_PLANT_SECOND_DETONATE: // second explosives detonate finish
+ for (GuidList::iterator itr = _explosivesGuids.begin(); itr != _explosivesGuids.end(); ++itr)
+ {
+ if (GameObject* explosive = sObjectAccessor->GetGameObject(*me, *itr))
+ me->RemoveGameObject(explosive, true);
+ }
+ _explosivesGuids.clear();
+ if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS))
+ {
+ sironas->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
+ me->SetFacingToObject(sironas);
+ }
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_FIGHT_SIRONAS_STOP;
+ break;
+ case PHASE_FIGHT_SIRONAS_STOP: // sironas channel stop
+ if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS))
+ sironas->AI()->DoAction(ACTION_SIRONAS_CHANNEL_STOP);
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_FIGHT_SIRONAS_SPEECH_1;
+ break;
+ case PHASE_FIGHT_SIRONAS_SPEECH_1: // sironas exclamation before aggro
+ if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS))
+ sironas->AI()->Talk(SAY_SIRONAS_1);
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_FIGHT_SIRONAS_SPEECH_2;
+ break;
+ case PHASE_FIGHT_SIRONAS_SPEECH_2: // legoso exclamation before aggro
+ if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS))
+ sironas->SetObjectScale(3.0f);
+ Talk(SAY_LEGOSO_19);
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_FIGHT_SIRONAS_START;
+ break;
+ case PHASE_FIGHT_SIRONAS_START: // legoso exclamation at aggro
+ if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS))
+ {
+ Unit* target = GetPlayerForEscort();
+ if (!target)
+ target = me;
+
+ target->AddThreat(sironas, 0.001f);
+ sironas->Attack(target, true);
+ sironas->GetMotionMaster()->MoveChase(target);
+ }
+ _moveTimer = 10 * IN_MILLISECONDS;
+ _phase = PHASE_CONTINUE;
+ break;
+ case PHASE_SIRONAS_SLAIN_SPEECH_1: // legoso exclamation after battle - stage 1.1
+ Talk(SAY_LEGOSO_20);
+ _moveTimer = 2 * IN_MILLISECONDS;
+ _phase = PHASE_SIRONAS_SLAIN_EMOTE_1;
+ break;
+ case PHASE_SIRONAS_SLAIN_EMOTE_1: // legoso exclamation after battle - stage 1.2
+ me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION);
+ _moveTimer = 2 * IN_MILLISECONDS;
+ _phase = PHASE_SIRONAS_SLAIN_EMOTE_2;
+ break;
+ case PHASE_SIRONAS_SLAIN_EMOTE_2: // legoso exclamation after battle - stage 1.3
+ if (Player* player = GetPlayerForEscort())
+ player->GroupEventHappens(QUEST_ENDING_THEIR_WORLD, me);
+ me->HandleEmoteCommand(EMOTE_ONESHOT_CHEER);
+ _moveTimer = 5 * IN_MILLISECONDS;
+ _phase = PHASE_SIRONAS_SLAIN_SPEECH_2;
+ break;
+ case PHASE_SIRONAS_SLAIN_SPEECH_2: // legoso exclamation after battle - stage 2
+ Talk(SAY_LEGOSO_21);
+ _moveTimer = 30 * IN_MILLISECONDS;
+ _phase = PHASE_CONTINUE;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (!me->IsInCombat())
+ _moveTimer -= diff;
+ }
+ }
+
+ void WaypointReached(uint32 waypointId) override
+ {
+ Player* player = GetPlayerForEscort();
+ if (!player)
+ return;
+
+ switch (waypointId)
+ {
+ case WP_START:
+ SetEscortPaused(true);
+ me->SetFacingToObject(player);
+ Talk(SAY_LEGOSO_1);
+ _moveTimer = 2.5 * IN_MILLISECONDS;
+ _phase = PHASE_CONTINUE;
+ break;
+ case WP_EXPLOSIVES_FIRST_POINT:
+ SetEscortPaused(true);
+ Talk(SAY_LEGOSO_2);
+ _moveTimer = 8 * IN_MILLISECONDS;
+ _phase = PHASE_WP_22;
+ break;
+ case WP_EXPLOSIVES_FIRST_PLANT:
+ me->SetFacingTo(1.46f);
+ break;
+ case WP_EXPLOSIVES_FIRST_DETONATE:
+ SetEscortPaused(true);
+ me->SetFacingTo(1.05f);
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_FIRST_TIMER_1;
+ break;
+ case WP_DEBUG_1:
+ SetEscortPaused(true);
+ _moveTimer = 0.5 * IN_MILLISECONDS;
+ _phase = PHASE_WP_26;
+ break;
+ case WP_SIRONAS_HILL:
+ {
+ SetEscortPaused(true);
+
+ //Find Sironas and make it respawn if needed
+ Creature* sironas = NULL;
+ Trinity::AllCreaturesOfEntryInRange check(me, NPC_SIRONAS, SIZE_OF_GRIDS);
+ Trinity::CreatureSearcher<Trinity::AllCreaturesOfEntryInRange> searcher(me, sironas, check);
+ me->VisitNearbyObject(SIZE_OF_GRIDS, searcher);
+
+ if (sironas)
+ {
+ if (!sironas->IsAlive())
+ sironas->Respawn(true);
+
+ sironas->AI()->DoAction(ACTION_SIRONAS_CHANNEL_START);
+ me->SetFacingToObject(sironas);
+ }
+ _moveTimer = 1 * IN_MILLISECONDS;
+ _phase = PHASE_FEEL_SIRONAS_1;
+ break;
+ }
+ case WP_EXPLOSIVES_SECOND_BATTLEROAR:
+ SetEscortPaused(true);
+ _moveTimer = 0.2 * IN_MILLISECONDS;
+ _phase = PHASE_MEET_SIRONAS_ROAR;
+ break;
+ case WP_EXPLOSIVES_SECOND_PLANT:
+ SetEscortPaused(true);
+ _moveTimer = 0.5 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_SECOND_KNEEL;
+ break;
+ case WP_EXPLOSIVES_SECOND_DETONATE:
+ SetEscortPaused(true);
+ me->SetFacingTo(5.7f);
+ _moveTimer = 2 * IN_MILLISECONDS;
+ _phase = PHASE_PLANT_SECOND_TIMER_1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ void DoAction(int32 param) override
+ {
+ switch (param)
+ {
+ case ACTION_LEGOSO_SIRONAS_KILLED:
+ _phase = PHASE_SIRONAS_SLAIN_SPEECH_1;
+ _moveTimer = 5 * IN_MILLISECONDS;
+ break;
+ default:
+ break;
+ }
+ }
+
+ private:
+ int8 _phase;
+ uint32 _moveTimer;
+ uint32 _eventStarterGuidLow;
+ GuidList _explosivesGuids;
+ EventMap _events;
+ };
+};
+
void AddSC_bloodmyst_isle()
{
new npc_webbed_creature();
+ new npc_sironas();
+ new npc_demolitionist_legoso();
}
diff --git a/src/server/scripts/Kalimdor/zone_desolace.cpp b/src/server/scripts/Kalimdor/zone_desolace.cpp
index d5ff4c45d09..bb17de4fd6a 100644
--- a/src/server/scripts/Kalimdor/zone_desolace.cpp
+++ b/src/server/scripts/Kalimdor/zone_desolace.cpp
@@ -88,12 +88,20 @@ public:
DoCast(me, SPELL_KODO_KOMBO_DESPAWN_BUFF, true);
me->UpdateEntry(NPC_TAMED_KODO);
+ me->CombatStop();
+ me->DeleteThreatList();
+ me->SetSpeed(MOVE_RUN, 0.6f, true);
me->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, me->GetFollowAngle());
+ me->setActive(true);
}
}
else if (spell->Id == SPELL_KODO_KOMBO_GOSSIP)
{
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveIdle();
+ me->setActive(false);
me->DespawnOrUnsummon(60000);
}
}
diff --git a/src/server/scripts/Kalimdor/zone_moonglade.cpp b/src/server/scripts/Kalimdor/zone_moonglade.cpp
index 704fefe2678..163620230ef 100644
--- a/src/server/scripts/Kalimdor/zone_moonglade.cpp
+++ b/src/server/scripts/Kalimdor/zone_moonglade.cpp
@@ -384,6 +384,8 @@ public:
}
PlayerGUID = player->GetGUID();
Start(true, false, PlayerGUID);
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid1);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
return;
}
diff --git a/src/server/scripts/Kalimdor/zone_winterspring.cpp b/src/server/scripts/Kalimdor/zone_winterspring.cpp
index 194daf21807..5cb6e78b399 100644
--- a/src/server/scripts/Kalimdor/zone_winterspring.cpp
+++ b/src/server/scripts/Kalimdor/zone_winterspring.cpp
@@ -377,12 +377,12 @@ public:
void DoSummonPriestess()
{
// Summon 2 Elune priestess and make each of them move to a different spot
- if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[0].m_positionX, wingThicketLocations[0].m_positionY, wingThicketLocations[0].m_positionZ, wingThicketLocations[0].m_orientation, TEMPSUMMON_CORPSE_DESPAWN, 0))
+ if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[0].m_positionX, wingThicketLocations[0].m_positionY, wingThicketLocations[0].m_positionZ, wingThicketLocations[0].GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0))
{
priestess->GetMotionMaster()->MovePoint(0, wingThicketLocations[3].m_positionX, wingThicketLocations[3].m_positionY, wingThicketLocations[3].m_positionZ);
_firstPriestessGUID = priestess->GetGUID();
}
- if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[1].m_positionX, wingThicketLocations[1].m_positionY, wingThicketLocations[1].m_positionZ, wingThicketLocations[1].m_orientation, TEMPSUMMON_CORPSE_DESPAWN, 0))
+ if (Creature* priestess = me->SummonCreature(NPC_PRIESTESS_ELUNE, wingThicketLocations[1].m_positionX, wingThicketLocations[1].m_positionY, wingThicketLocations[1].m_positionZ, wingThicketLocations[1].GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0))
{
// Left priestess should have a distinct move point because she is the one who starts the dialogue at point reach
priestess->GetMotionMaster()->MovePoint(1, wingThicketLocations[4].m_positionX, wingThicketLocations[4].m_positionY, wingThicketLocations[4].m_positionZ);
@@ -451,7 +451,7 @@ public:
}
}
- void JustDidDialogueStep(int32 entry)
+ void JustDidDialogueStep(int32 entry) override
{
switch (entry)
{
@@ -480,7 +480,7 @@ public:
break;
case SAY_PRIESTESS_ALTAR_13:
// summon the Guardian of Elune
- if (Creature* guard = me->SummonCreature(NPC_GUARDIAN_ELUNE, wingThicketLocations[2].m_positionX, wingThicketLocations[2].m_positionY, wingThicketLocations[2].m_positionZ, wingThicketLocations[2].m_orientation, TEMPSUMMON_CORPSE_DESPAWN, 0))
+ if (Creature* guard = me->SummonCreature(NPC_GUARDIAN_ELUNE, wingThicketLocations[2].m_positionX, wingThicketLocations[2].m_positionY, wingThicketLocations[2].m_positionZ, wingThicketLocations[2].GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0))
{
guard->GetMotionMaster()->MovePoint(0, wingThicketLocations[5].m_positionX, wingThicketLocations[5].m_positionY, wingThicketLocations[5].m_positionZ);
_guardEluneGUID = guard->GetGUID();
@@ -550,7 +550,7 @@ public:
}
}
- Creature* GetSpeakerByEntry(int32 entry)
+ Creature* GetSpeakerByEntry(int32 entry) override
{
switch (entry)
{
diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp
index 1482e884614..bb190e94cc8 100644
--- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp
@@ -108,7 +108,7 @@ class boss_prince_taldaram : public CreatureScript
events.ScheduleEvent(EVENT_CONJURE_FLAME_SPHERES, 5000);
}
- void JustSummoned(Creature* summon)
+ void JustSummoned(Creature* summon) override
{
BossAI::JustSummoned(summon);
diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt
index e04dcf0ec96..66d9021223f 100644
--- a/src/server/scripts/Northrend/CMakeLists.txt
+++ b/src/server/scripts/Northrend/CMakeLists.txt
@@ -78,8 +78,7 @@ set(scripts_STAT_SRCS
Northrend/Nexus/Oculus/boss_urom.cpp
Northrend/Nexus/Oculus/oculus.cpp
Northrend/Nexus/Oculus/instance_oculus.cpp
- Northrend/Nexus/Nexus/boss_commander_kolurg.cpp
- Northrend/Nexus/Nexus/boss_commander_stoutbeard.cpp
+ Northrend/Nexus/Nexus/boss_nexus_commanders.cpp
Northrend/Nexus/Nexus/boss_ormorok.cpp
Northrend/Nexus/Nexus/boss_magus_telestra.cpp
Northrend/Nexus/Nexus/instance_nexus.cpp
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp
index ec668952a68..3130bf20a0c 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp
@@ -44,7 +44,7 @@ class instance_ruby_sanctum : public InstanceMapScript
BaltharusSharedHealth = 0;
}
- void OnPlayerEnter(Player* /*player*/)
+ void OnPlayerEnter(Player* /*player*/) override
{
if (!GetGuidData(DATA_HALION_CONTROLLER) && GetBossState(DATA_HALION) != DONE && GetBossState(DATA_GENERAL_ZARITHRIAN) == DONE)
{
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp
index 39c9fbe37a6..c56a49cb92c 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp
@@ -741,7 +741,7 @@ class boss_dreadscale : public CreatureScript
switch (pointId)
{
case 0:
- instance->DoUseDoorOrButton(instance->GetGuidData(GO_MAIN_GATE_DOOR));
+ instance->DoCloseDoorOrButton(instance->GetGuidData(GO_MAIN_GATE_DOOR));
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
me->SetReactState(REACT_AGGRESSIVE);
me->SetInCombatWithZone();
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp
index 4f883fd7e90..23bfd773a9b 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp
@@ -255,12 +255,6 @@ class instance_trial_of_the_crusader : public InstanceMapScript
if (GetBossState(BOSS_VALKIRIES) == SPECIAL)
state = DONE;
break;
- case DONE:
- if (instance->GetPlayers().getFirst()->GetSource()->GetTeam() == ALLIANCE)
- EventStage = 4020;
- else
- EventStage = 4030;
- break;
default:
break;
}
@@ -336,7 +330,7 @@ class instance_trial_of_the_crusader : public InstanceMapScript
if (type < MAX_ENCOUNTERS)
{
- TC_LOG_INFO("scripts", "[ToCr] BossState(type %u) %u = state %u;", type, GetBossState(type), state);
+ TC_LOG_DEBUG("scripts", "[ToCr] BossState(type %u) %u = state %u;", type, GetBossState(type), state);
if (state == FAIL)
{
if (instance->IsHeroic())
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp
index 16526b694e9..974bd4672f1 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp
@@ -133,7 +133,7 @@ class npc_announcer_toc10 : public CreatureScript
char const* _message = "We are ready!";
- if (player->IsInCombat() || instance->IsEncounterInProgress() || instance->GetData(TYPE_EVENT))
+ if (player->IsInCombat() || instance->IsEncounterInProgress())
return true;
uint8 i = 0;
@@ -199,17 +199,11 @@ class npc_announcer_toc10 : public CreatureScript
}
else if (instance->GetBossState(BOSS_LICH_KING) != DONE)
{
- if (GameObject* floor = ObjectAccessor::GetGameObject(*player, instance->GetGuidData(GO_ARGENT_COLISEUM_FLOOR)))
- floor->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED);
-
- creature->CastSpell(creature, SPELL_CORPSE_TELEPORT, false);
- creature->CastSpell(creature, SPELL_DESTROY_FLOOR_KNOCKUP, false);
-
- if (!ObjectAccessor::GetCreature(*creature, instance->GetGuidData(NPC_ANUBARAK)))
- creature->SummonCreature(NPC_ANUBARAK, AnubarakLoc[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, DESPAWN_TIME);
-
- if (creature->IsVisible())
- creature->SetVisible(false);
+ if (creature->GetMap()->GetPlayers().getFirst()->GetSource()->GetTeam() == ALLIANCE)
+ instance->SetData(TYPE_EVENT, 4020);
+ else
+ instance->SetData(TYPE_EVENT, 4030);
+ instance->SetBossState(BOSS_LICH_KING, NOT_STARTED);
}
creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
return true;
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
index 9edde447f32..12a745a34bc 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
@@ -2412,14 +2412,14 @@ enum QuelDelarMisc
Position const QuelDelarCenterPos = { 5309.259f, 2006.390f, 718.046f, 0.0f };
Position const QuelDelarSummonPos = { 5298.473f, 1994.852f, 709.424f, 3.979351f };
Position const QuelDelarMovement[] =
-{
+{
{ 5292.870f, 1998.950f, 718.046f, 0.0f },
{ 5295.819f, 1991.912f, 707.707f, 0.0f },
{ 5295.301f, 1989.782f, 708.696f, 0.0f }
};
Position const UtherQuelDelarMovement[] =
-{
+{
{ 5336.830f, 1981.700f, 709.319f, 0.0f },
{ 5314.350f, 1993.440f, 707.726f, 0.0f }
};
@@ -2640,13 +2640,7 @@ class npc_quel_delar_sword : public CreatureScript
break;
case EVENT_QUEL_DELAR_FLIGHT:
{
- Movement::MoveSplineInit init(me);
- FillCirclePath(QuelDelarCenterPos, 18.0f, 718.046f, init.Path(), true);
- init.SetFly();
- init.SetCyclic();
- init.SetAnimation(Movement::ToFly);
- init.Launch();
-
+ me->GetMotionMaster()->MoveCirclePath(QuelDelarCenterPos.GetPositionX(), QuelDelarCenterPos.GetPositionY(), 718.046f, 18.0f, true, 16);
_events.ScheduleEvent(EVENT_QUEL_DELAR_LAND, 15000);
break;
}
@@ -2694,21 +2688,6 @@ class npc_quel_delar_sword : public CreatureScript
}
private:
- void FillCirclePath(Position const& centerPos, float radius, float z, Movement::PointsArray& path, bool clockwise)
- {
- float step = clockwise ? -M_PI / 8.0f : M_PI / 8.0f;
- float angle = centerPos.GetAngle(me->GetPositionX(), me->GetPositionY());
-
- for (uint8 i = 0; i < 16; angle += step, ++i)
- {
- G3D::Vector3 point;
- point.x = centerPos.GetPositionX() + radius * cosf(angle);
- point.y = centerPos.GetPositionY() + radius * sinf(angle);
- point.z = z;
- path.push_back(point);
- }
- }
-
EventMap _events;
InstanceScript* _instance;
bool _intro;
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
index 660a639487f..fabe54303b8 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
@@ -196,7 +196,7 @@ class instance_halls_of_reflection : public InstanceMapScript
}
}
- uint32 GetGameObjectEntry(uint32 /*guidLow*/, uint32 entry) override
+ uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) override
{
if (!_teamInInstance)
{
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp
index 5f27830fd07..68430f6f0f7 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp
@@ -24,6 +24,7 @@
#include "PassiveAI.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellHistory.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
#include "Transport.h"
@@ -644,10 +645,10 @@ protected:
{
if (Instance->GetBossState(DATA_ICECROWN_GUNSHIP_BATTLE) == IN_PROGRESS &&
!me->HasUnitState(UNIT_STATE_CASTING) && !me->HasReactState(REACT_PASSIVE) &&
- !me->HasSpellCooldown(BurningPitchId))
+ !me->GetSpellHistory()->HasCooldown(BurningPitchId))
{
DoCastAOE(BurningPitchId, true);
- me->_AddCreatureSpellCooldown(BurningPitchId, time(NULL) + urand(3000, 4000) / IN_MILLISECONDS);
+ me->GetSpellHistory()->AddCooldown(BurningPitchId, 0, std::chrono::milliseconds(urand(3000, 4000)));
}
}
@@ -1469,7 +1470,7 @@ struct npc_gunship_boarding_addAI : public gunship_npc_AI
DoCast(me, SPELL_BATTLE_EXPERIENCE, true);
DoCast(me, SPELL_TELEPORT_TO_ENEMY_SHIP, true);
DoCast(me, Instance->GetData(DATA_TEAM_IN_INSTANCE) == HORDE ? SPELL_MELEE_TARGETING_ON_ORGRIMS_HAMMER : SPELL_MELEE_TARGETING_ON_SKYBREAKER, true);
- me->_AddCreatureSpellCooldown(BurningPitchId, time(NULL) + 3);
+ me->GetSpellHistory()->AddCooldown(BurningPitchId, 0, std::chrono::seconds(3));
std::list<Player*> players;
Trinity::UnitAuraCheck check(true, Instance->GetData(DATA_TEAM_IN_INSTANCE) == HORDE ? SPELL_ON_ORGRIMS_HAMMER_DECK : SPELL_ON_SKYBREAKER_DECK);
@@ -1698,11 +1699,11 @@ class npc_gunship_rocketeer : public CreatureScript
return;
uint32 spellId = me->GetEntry() == NPC_SKYBREAKER_MORTAR_SOLDIER ? SPELL_ROCKET_ARTILLERY_A : SPELL_ROCKET_ARTILLERY_H;
- if (me->HasSpellCooldown(spellId))
+ if (me->GetSpellHistory()->HasCooldown(spellId))
return;
DoCastAOE(spellId, true);
- me->_AddCreatureSpellCooldown(spellId, time(NULL) + 9);
+ me->GetSpellHistory()->AddCooldown(spellId, 0, std::chrono::seconds(9));
}
};
@@ -1873,7 +1874,7 @@ class spell_igb_rocket_pack_useable : public SpellScriptLoader
{
PrepareAuraScript(spell_igb_rocket_pack_useable_AuraScript);
- bool Load()
+ bool Load() override
{
return GetOwner()->GetInstanceScript() != nullptr;
}
@@ -2001,7 +2002,7 @@ class spell_igb_cannon_blast : public SpellScriptLoader
{
PrepareSpellScript(spell_igb_cannon_blast_SpellScript);
- bool Load()
+ bool Load() override
{
return GetCaster()->GetTypeId() == TYPEID_UNIT;
}
@@ -2343,7 +2344,7 @@ class spell_igb_gunship_fall_teleport : public SpellScriptLoader
{
PrepareSpellScript(spell_igb_gunship_fall_teleport_SpellScript);
- bool Load()
+ bool Load() override
{
return GetCaster()->GetInstanceScript() != nullptr;
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
index 63082808e03..d7a580800bc 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp
@@ -1060,8 +1060,8 @@ class spell_putricide_ooze_eruption_searcher : public SpellScriptLoader
uint32 adhesiveId = sSpellMgr->GetSpellIdForDifficulty(SPELL_VOLATILE_OOZE_ADHESIVE, GetCaster());
if (GetHitUnit()->HasAura(adhesiveId))
{
- GetCaster()->CastSpell(GetHitUnit(), SPELL_OOZE_ERUPTION, true);
GetHitUnit()->RemoveAurasDueToSpell(adhesiveId, GetCaster()->GetGUID(), 0, AURA_REMOVE_BY_ENEMY_SPELL);
+ GetCaster()->CastSpell(GetHitUnit(), SPELL_OOZE_ERUPTION, true);
}
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
index 4d7b9ec42b4..d56a3f80f75 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
@@ -18,7 +18,7 @@
#include "ObjectMgr.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
-#include "SpellAuras.h"
+#include "SpellAuraEffects.h"
#include "GridNotifiers.h"
#include "icecrown_citadel.h"
@@ -213,7 +213,7 @@ class boss_rotface : public CreatureScript
}
break;
case EVENT_MUTATED_INFECTION:
- me->CastCustomSpell(SPELL_MUTATED_INFECTION, SPELLVALUE_MAX_TARGETS, 1, NULL, false);
+ DoCastAOE(SPELL_MUTATED_INFECTION);
events.ScheduleEvent(EVENT_MUTATED_INFECTION, infectionCooldown);
break;
case EVENT_VILE_GAS:
@@ -509,13 +509,6 @@ class spell_rotface_mutated_infection : public SpellScriptLoader
{
PrepareSpellScript(spell_rotface_mutated_infection_SpellScript);
- public:
- spell_rotface_mutated_infection_SpellScript()
- {
- _target = nullptr;
- }
-
- private:
void FilterTargets(std::list<WorldObject*>& targets)
{
// remove targets with this aura already
@@ -527,14 +520,6 @@ class spell_rotface_mutated_infection : public SpellScriptLoader
WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets);
targets.clear();
targets.push_back(target);
- _target = target;
- }
-
- void ReplaceTargets(std::list<WorldObject*>& targets)
- {
- targets.clear();
- if (_target)
- targets.push_back(_target);
}
void NotifyTargets()
@@ -546,19 +531,43 @@ class spell_rotface_mutated_infection : public SpellScriptLoader
void Register() override
{
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rotface_mutated_infection_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rotface_mutated_infection_SpellScript::ReplaceTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY);
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rotface_mutated_infection_SpellScript::ReplaceTargets, EFFECT_2, TARGET_UNIT_SRC_AREA_ENEMY);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rotface_mutated_infection_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
AfterHit += SpellHitFn(spell_rotface_mutated_infection_SpellScript::NotifyTargets);
}
+ };
+
+ class spell_rotface_mutated_infection_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_rotface_mutated_infection_AuraScript);
- WorldObject* _target;
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ if (!sSpellMgr->GetSpellInfo(uint32(spellInfo->Effects[EFFECT_2].CalcValue())))
+ return false;
+ return true;
+ }
+
+ void HandleEffectRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ target->CastSpell(target, uint32(GetSpellInfo()->Effects[EFFECT_2].CalcValue()), true, nullptr, aurEff, GetCasterGUID());
+ }
+
+ void Register() override
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_rotface_mutated_infection_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL);
+ }
};
SpellScript* GetSpellScript() const override
{
return new spell_rotface_mutated_infection_SpellScript();
}
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_rotface_mutated_infection_AuraScript();
+ }
};
class spell_rotface_little_ooze_combine : public SpellScriptLoader
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
index 60268fc8d87..e908d088554 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
@@ -348,7 +348,7 @@ class boss_sindragosa : public CreatureScript
events.ScheduleEvent(EVENT_AIR_MOVEMENT, 1);
break;
case POINT_AIR_PHASE:
- me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, RAID_MODE<int32>(2, 5, 2, 6), NULL);
+ me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, RAID_MODE<int32>(2, 5, 2, 6), NULL, TRIGGERED_FULL_MASK);
me->SetFacingTo(float(M_PI));
events.ScheduleEvent(EVENT_AIR_MOVEMENT_FAR, 1);
events.ScheduleEvent(EVENT_FROST_BOMB, 9000);
@@ -491,7 +491,7 @@ class boss_sindragosa : public CreatureScript
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, FrostBeaconSelector(me)))
{
Talk(EMOTE_WARN_FROZEN_ORB, target);
- DoCast(target, SPELL_ICE_TOMB_DUMMY, true);
+ me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, 1, nullptr, TRIGGERED_FULL_MASK);
}
events.ScheduleEvent(EVENT_ICE_TOMB, urand(16000, 23000));
break;
@@ -1631,7 +1631,7 @@ void AddSC_boss_sindragosa()
new spell_rimefang_icy_blast();
new spell_frostwarden_handler_order_whelp();
new spell_frostwarden_handler_focus_fire();
- new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb", SPELL_ICE_TOMB_DUMMY);
+ new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb", SPELL_ICE_TOMB_DUMMY, TRIGGERED_IGNORE_SET_FACING);
new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb_dummy", SPELL_FROST_BEACON);
new at_sindragosa_lair();
new achievement_all_you_can_eat();
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
index ae0e00cb849..07816ebbe39 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
@@ -2417,6 +2417,7 @@ class spell_the_lich_king_defile : public SpellScriptLoader
void CorrectRange(std::list<WorldObject*>& targets)
{
targets.remove_if(ExactDistanceCheck(GetCaster(), 10.0f * GetCaster()->GetObjectScale()));
+ targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_HARVEST_SOUL_VALKYR));
}
void ChangeDamageAndGrow()
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
index 8bf8e5ee6fb..091190b6b4e 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
+++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
@@ -524,14 +524,16 @@ enum AreaIds
class spell_trigger_spell_from_caster : public SpellScriptLoader
{
public:
- spell_trigger_spell_from_caster(char const* scriptName, uint32 triggerId) : SpellScriptLoader(scriptName), _triggerId(triggerId) { }
+ spell_trigger_spell_from_caster(char const* scriptName, uint32 triggerId, TriggerCastFlags triggerFlags = TRIGGERED_FULL_MASK)
+ : SpellScriptLoader(scriptName), _triggerId(triggerId), _triggerFlags(triggerFlags) { }
class spell_trigger_spell_from_caster_SpellScript : public SpellScript
{
PrepareSpellScript(spell_trigger_spell_from_caster_SpellScript);
public:
- spell_trigger_spell_from_caster_SpellScript(uint32 triggerId) : SpellScript(), _triggerId(triggerId) { }
+ spell_trigger_spell_from_caster_SpellScript(uint32 triggerId, TriggerCastFlags triggerFlags)
+ : SpellScript(), _triggerId(triggerId), _triggerFlags(triggerFlags) { }
bool Validate(SpellInfo const* /*spell*/) override
{
@@ -542,7 +544,7 @@ class spell_trigger_spell_from_caster : public SpellScriptLoader
void HandleTrigger()
{
- GetCaster()->CastSpell(GetHitUnit(), _triggerId, true);
+ GetCaster()->CastSpell(GetHitUnit(), _triggerId, _triggerFlags);
}
void Register() override
@@ -551,15 +553,17 @@ class spell_trigger_spell_from_caster : public SpellScriptLoader
}
uint32 _triggerId;
+ TriggerCastFlags _triggerFlags;
};
SpellScript* GetSpellScript() const override
{
- return new spell_trigger_spell_from_caster_SpellScript(_triggerId);
+ return new spell_trigger_spell_from_caster_SpellScript(_triggerId, _triggerFlags);
}
private:
uint32 _triggerId;
+ TriggerCastFlags _triggerFlags;
};
template<class AI>
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
index f2236061f88..1b823b4a452 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
@@ -317,7 +317,7 @@ class instance_icecrown_citadel : public InstanceMapScript
}
// Weekly quest spawn prevention
- uint32 GetCreatureEntry(uint32 /*guidLow*/, CreatureData const* data)
+ uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) override
{
uint32 entry = data->id;
switch (entry)
@@ -372,7 +372,7 @@ class instance_icecrown_citadel : public InstanceMapScript
return entry;
}
- uint32 GetGameObjectEntry(uint32 /*guidLow*/, uint32 entry) override
+ uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) override
{
switch (entry)
{
diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
index 173c6618cb0..3a431ab3ac0 100644
--- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
@@ -564,7 +564,7 @@ class instance_naxxramas : public InstanceMapScript
return true;
}
- bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target = NULL*/, uint32 /*miscvalue1 = 0*/)
+ bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target = NULL*/, uint32 /*miscvalue1 = 0*/) override
{
switch (criteria_id)
{
diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
index 43069f10464..9c339e596a4 100644
--- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
+++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
@@ -128,7 +128,6 @@ enum Spells
SPELL_ARCANE_BARRAGE_DAMAGE = 63934, // the actual damage - cast by affected player by script spell
// Transition /II-III/
- SPELL_SUMMOM_RED_DRAGON_BUDYY = 56070,
SPELL_RIDE_RED_DRAGON_BUDDY = 56071,
SPELL_SUMMON_RED_DRAGON_BUDDY_F_CAST = 58846, // After implicitly hit player targets they will force cast 56070 on self
SPELL_DESTROY_PLATFORM_CHANNEL = 58842,
@@ -520,11 +519,7 @@ public:
_despawned = false;
break;
case ACTION_CYCLIC_MOVEMENT:
- Movement::MoveSplineInit init(me);
- FillCirclePath(MalygosPositions[3], 120.0f, 283.2763f, init.Path(), true);
- init.SetFly();
- init.SetCyclic();
- init.Launch();
+ me->GetMotionMaster()->MoveCirclePath(MalygosPositions[3].GetPositionX(), MalygosPositions[3].GetPositionY(), 283.2763f, 120.0f, true, 16);
break;
}
}
@@ -1020,22 +1015,6 @@ public:
}
private:
- // Used to generate perfect cyclic movements (Enter Circle).
- void FillCirclePath(Position const& centerPos, float radius, float z, Movement::PointsArray& path, bool clockwise)
- {
- float step = clockwise ? float(-M_PI) / 8.0f : float(M_PI) / 8.0f;
- float angle = centerPos.GetAngle(me->GetPositionX(), me->GetPositionY());
-
- for (uint8 i = 0; i < 16; angle += step, ++i)
- {
- G3D::Vector3 point;
- point.x = centerPos.GetPositionX() + radius * cosf(angle);
- point.y = centerPos.GetPositionY() + radius * sinf(angle);
- point.z = z; // Don't use any height getters unless all bugs are fixed.
- path.push_back(point);
- }
- }
-
uint8 _phase; // Counter for phases used with a getter.
uint8 _summonDeaths; // Keeps count of arcane trash.
uint8 _preparingPulsesChecker; // In retail they use 2 preparing pulses with 7 sec CD, after they pass 2 seconds.
@@ -1326,11 +1305,7 @@ public:
{
if (action < ACTION_DELAYED_DESPAWN)
{
- Movement::MoveSplineInit init(me);
- FillCirclePath(MalygosPositions[3], 35.0f, 282.3402f, init.Path(), true);
- init.SetFly();
- init.SetCyclic();
- init.Launch();
+ me->GetMotionMaster()->MoveCirclePath(MalygosPositions[3].GetPositionX(), MalygosPositions[3].GetPositionY(), 282.3402f, 35.0f, true, 16);
}
else
{
@@ -1339,21 +1314,6 @@ public:
}
private:
- void FillCirclePath(Position const& centerPos, float radius, float z, Movement::PointsArray& path, bool clockwise)
- {
- float step = clockwise ? float(-M_PI) / 9.0f : float(M_PI) / 9.0f;
- float angle = centerPos.GetAngle(me->GetPositionX(), me->GetPositionY());
-
- for (uint8 i = 0; i < 18; angle += step, ++i)
- {
- G3D::Vector3 point;
- point.x = centerPos.GetPositionX() + radius * cosf(angle);
- point.y = centerPos.GetPositionY() + radius * sinf(angle);
- point.z = z; // Don't use any height getters unless all bugs are fixed.
- path.push_back(point);
- }
- }
-
InstanceScript* _instance;
};
diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h
index b6a0d3f9b62..d9b921b38a1 100644
--- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h
+++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h
@@ -80,7 +80,8 @@ enum InstanceSpells
SPELL_VORTEX_5 = 56263, // damage | used to enter to the vehicle
SPELL_PORTAL_OPENED = 61236,
SPELL_RIDE_RED_DRAGON_TRIGGERED = 56072,
- SPELL_IRIS_OPENED = 61012 // visual when starting encounter
+ SPELL_IRIS_OPENED = 61012, // visual when starting encounter
+ SPELL_SUMMOM_RED_DRAGON_BUDDY = 56070
};
#endif
diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp
index fffdbbc3d1b..7b884f39a41 100644
--- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp
+++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp
@@ -39,6 +39,12 @@ public:
SetBossNumber(MAX_ENCOUNTER);
}
+ void OnPlayerEnter(Player* player) override
+ {
+ if (GetBossState(DATA_MALYGOS_EVENT) == DONE)
+ player->CastSpell(player, SPELL_SUMMOM_RED_DRAGON_BUDDY, true);
+ }
+
bool SetBossState(uint32 type, EncounterState state) override
{
if (!InstanceScript::SetBossState(type, state))
diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_kolurg.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_kolurg.cpp
deleted file mode 100644
index fc56f541a4b..00000000000
--- a/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_kolurg.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* Script Data Start
-SDName: Boss Commander Kolurg
-SDAuthor: LordVanMartin
-SD%Complete:
-SDComment: Only Alliance Heroic
-SDCategory:
-Script Data End */
-
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-
-enum Spells
-{
- SPELL_BATTLE_SHOUT = 31403,
- SPELL_CHARGE = 60067,
- SPELL_FRIGHTENING_SHOUT = 19134,
- SPELL_WHIRLWIND_1 = 38619,
- SPELL_WHIRLWIND_2 = 38618
-
-};
-
-//not used
-//Yell
-#define SAY_AGGRO -1576024
-#define SAY_KILL -1576025
-#define SAY_DEATH -1576026
-
-class boss_commander_kolurg : public CreatureScript
-{
-public:
- boss_commander_kolurg() : CreatureScript("boss_commander_kolurg") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new boss_commander_kolurgAI(creature);
- }
-
- struct boss_commander_kolurgAI : public ScriptedAI
- {
- boss_commander_kolurgAI(Creature* creature) : ScriptedAI(creature) { }
-
- void Reset() override { }
- void EnterCombat(Unit* /*who*/) override { }
- void AttackStart(Unit* /*who*/) override { }
- void MoveInLineOfSight(Unit* /*who*/) override { }
-
- void UpdateAI(uint32 /*diff*/) override
- {
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- DoMeleeAttackIfReady();
- }
- void JustDied(Unit* /*killer*/) override { }
- };
-
-};
-
-void AddSC_boss_commander_kolurg()
-{
- new boss_commander_kolurg();
-}
diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_stoutbeard.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_stoutbeard.cpp
deleted file mode 100644
index ff08038d898..00000000000
--- a/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_stoutbeard.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* Script Data Start
-SDName: Boss Commander Stoutbeard
-SDAuthor: LordVanMartin
-SD%Complete:
-SDComment: Only Horde Heroic
-SDCategory:
-Script Data End */
-
-#include "ScriptMgr.h"
-#include "ScriptedCreature.h"
-
-enum CommanderStoutbeard
-{
- SPELL_BATTLE_SHOUT = 31403,
- SPELL_CHARGE = 60067,
- SPELL_FRIGHTENING_SHOUT = 19134,
- SPELL_WHIRLWIND_1 = 38619,
- SPELL_WHIRLWIND_2 = 38618
-};
-
-
-class boss_commander_stoutbeard : public CreatureScript
-{
-public:
- boss_commander_stoutbeard() : CreatureScript("boss_commander_stoutbeard") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new boss_commander_stoutbeardAI(creature);
- }
-
- struct boss_commander_stoutbeardAI : public ScriptedAI
- {
- boss_commander_stoutbeardAI(Creature* creature) : ScriptedAI(creature) { }
-
- void Reset() override { }
- void AttackStart(Unit* /*who*/) override { }
- void MoveInLineOfSight(Unit* /*who*/) override { }
-
- void UpdateAI(uint32 /*diff*/) override
- {
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- DoMeleeAttackIfReady();
- }
- };
-
-};
-
-void AddSC_boss_commander_stoutbeard()
-{
- new boss_commander_stoutbeard();
-}
diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_nexus_commanders.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_nexus_commanders.cpp
new file mode 100644
index 00000000000..d40f9fecc6a
--- /dev/null
+++ b/src/server/scripts/Northrend/Nexus/Nexus/boss_nexus_commanders.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "nexus.h"
+
+enum Spells
+{
+ SPELL_BATTLE_SHOUT = 31403,
+ SPELL_CHARGE = 60067,
+ SPELL_FRIGHTENING_SHOUT = 19134,
+ SPELL_WHIRLWIND = 38618,
+ SPELL_FROZEN_PRISON = 47543
+};
+
+enum Yells
+{
+ SAY_AGGRO = 0,
+ SAY_KILL = 1,
+ SAY_DEATH = 2
+};
+
+enum Events
+{
+ EVENT_CHARGE_COMMANDER = 1,
+ EVENT_WHIRLWIND,
+ EVENT_FRIGHTENING_SHOUT
+};
+
+class boss_nexus_commanders : public CreatureScript
+{
+ public:
+ boss_nexus_commanders() : CreatureScript("boss_nexus_commanders") { }
+
+ struct boss_nexus_commandersAI : public BossAI
+ {
+ boss_nexus_commandersAI(Creature* creature) : BossAI(creature, DATA_COMMANDER) { }
+
+ void EnterCombat(Unit* /*who*/) override
+ {
+ _EnterCombat();
+ Talk(SAY_AGGRO);
+ me->RemoveAurasDueToSpell(SPELL_FROZEN_PRISON);
+ DoCast(me, SPELL_BATTLE_SHOUT);
+
+ events.ScheduleEvent(EVENT_CHARGE_COMMANDER, urand(3000, 4000));
+ events.ScheduleEvent(EVENT_WHIRLWIND, urand(6000, 8000));
+ events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, urand(13000, 15000));
+ }
+
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_CHARGE_COMMANDER:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_CHARGE);
+ events.ScheduleEvent(EVENT_CHARGE_COMMANDER, urand(11000, 15000));
+ break;
+ case EVENT_WHIRLWIND:
+ DoCast(me, SPELL_WHIRLWIND);
+ events.ScheduleEvent(EVENT_WHIRLWIND, urand(19500, 25000));
+ break;
+ case EVENT_FRIGHTENING_SHOUT:
+ DoCastAOE(SPELL_FRIGHTENING_SHOUT);
+ events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, urand(45000, 55000));
+ break;
+ default:
+ break;
+ }
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ Talk(SAY_DEATH);
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_KILL);
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_nexus_commandersAI>(creature);
+ }
+};
+
+void AddSC_boss_nexus_commanders()
+{
+ new boss_nexus_commanders();
+}
diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_ormorok.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_ormorok.cpp
index 74be65c62c2..41645a6ebb8 100644
--- a/src/server/scripts/Northrend/Nexus/Nexus/boss_ormorok.cpp
+++ b/src/server/scripts/Northrend/Nexus/Nexus/boss_ormorok.cpp
@@ -78,7 +78,7 @@ public:
frenzy = false;
}
- void Reset()
+ void Reset() override
{
BossAI::Reset();
Initialize();
diff --git a/src/server/scripts/Northrend/Nexus/Nexus/nexus.h b/src/server/scripts/Northrend/Nexus/Nexus/nexus.h
index 90866ea83f8..c48c7323301 100644
--- a/src/server/scripts/Northrend/Nexus/Nexus/nexus.h
+++ b/src/server/scripts/Northrend/Nexus/Nexus/nexus.h
@@ -21,32 +21,33 @@
#define NexusScriptName "instance_nexus"
#define DataHeader "NEX"
-uint32 const EncounterCount = 4;
+uint32 const EncounterCount = 5;
enum DataTypes
{
- DATA_MAGUS_TELESTRA = 0,
- DATA_ANOMALUS = 1,
- DATA_ORMOROK = 2,
- DATA_KERISTRASZA = 3,
+ DATA_COMMANDER = 0,
+ DATA_MAGUS_TELESTRA = 1,
+ DATA_ANOMALUS = 2,
+ DATA_ORMOROK = 3,
+ DATA_KERISTRASZA = 4,
- ANOMALUS_CONTAINMET_SPHERE = 4,
- ORMOROKS_CONTAINMET_SPHERE = 5,
- TELESTRAS_CONTAINMET_SPHERE = 6
+ ANOMALUS_CONTAINMET_SPHERE = 5,
+ ORMOROKS_CONTAINMET_SPHERE = 6,
+ TELESTRAS_CONTAINMET_SPHERE = 7
};
enum CreatureIds
{
NPC_ANOMALUS = 26763,
NPC_KERISTRASZA = 26723,
-
+
// Alliance
NPC_ALLIANCE_BERSERKER = 26800,
NPC_ALLIANCE_RANGER = 26802,
NPC_ALLIANCE_CLERIC = 26805,
NPC_ALLIANCE_COMMANDER = 27949,
NPC_COMMANDER_STOUTBEARD = 26796,
-
+
// Horde
NPC_HORDE_BERSERKER = 26799,
NPC_HORDE_RANGER = 26801,
@@ -59,7 +60,7 @@ enum GameObjectIds
{
GO_ANOMALUS_CONTAINMET_SPHERE = 188527,
GO_ORMOROKS_CONTAINMET_SPHERE = 188528,
- GO_TELESTRAS_CONTAINMET_SPHERE = 188526
+ GO_TELESTRAS_CONTAINMET_SPHERE = 188526
};
#endif
diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp
index 384694cdd40..453423bd287 100644
--- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp
+++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp
@@ -197,7 +197,7 @@ public:
++_healthAmountModifier;
}
}
-
+
private:
uint32 _healthAmountModifier;
bool _isIntroDone;
diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp
index 536cae08483..3853b0aedfc 100644
--- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp
+++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp
@@ -89,7 +89,7 @@ class boss_volkhan : public CreatureScript
{
public:
boss_volkhan() : CreatureScript("boss_volkhan") { }
-
+
struct boss_volkhanAI : public BossAI
{
boss_volkhanAI(Creature* creature) : BossAI(creature, DATA_VOLKHAN)
@@ -104,7 +104,7 @@ public:
m_bCanShatterGolem = false;
m_uiDelay_Timer = 1000;
m_uiSummonPhase = 0;
- GolemsShattered = 0;
+ GolemsShattered = 0;
m_uiHealthAmountModifier = 1;
}
diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp
index 1e2ca666378..6233c7e8953 100644
--- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp
+++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp
@@ -330,7 +330,7 @@ public:
DespawnDwarf();
- instance->SetBossState(DATA_BRANN_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_TRIBUNAL_OF_AGES, NOT_STARTED);
}
}
@@ -362,8 +362,10 @@ public:
break;
case 13:
Talk(SAY_EVENT_INTRO_1);
+ instance->SetBossState(DATA_TRIBUNAL_OF_AGES, IN_PROGRESS);
SetEscortPaused(true);
JumpToNextStep(20000);
+ // @todo: There should be a pause here and a gossip should start the next step.
break;
case 17:
Talk(SAY_EVENT_INTRO_2);
@@ -421,9 +423,9 @@ public:
Start();
}
- void DamageTaken(Unit* /*done_by*/, uint32 & /*damage*/) override
+ void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/) override
{
- if (brannSparklinNews)
+ if (instance->GetBossState(DATA_TRIBUNAL_OF_AGES) == IN_PROGRESS)
brannSparklinNews = false;
}
@@ -442,9 +444,8 @@ public:
switch (uiStep)
{
case 1:
- if (instance->GetBossState(DATA_BRANN_EVENT) != NOT_STARTED)
+ if (instance->GetBossState(DATA_TRIBUNAL_OF_AGES) != NOT_STARTED)
return;
- instance->SetBossState(DATA_BRANN_EVENT, IN_PROGRESS);
bIsBattle = false;
Talk(SAY_ESCORT_START);
SetRun(true);
@@ -582,7 +583,7 @@ public:
break;
case 29:
Talk(SAY_EVENT_END_02);
- instance->SetBossState(DATA_BRANN_EVENT, DONE);
+ instance->SetBossState(DATA_TRIBUNAL_OF_AGES, DONE);
me->CastSpell(me, SPELL_REWARD_ACHIEVEMENT, true);
JumpToNextStep(5500);
break;
@@ -715,9 +716,7 @@ public:
class achievement_brann_spankin_new : public AchievementCriteriaScript
{
public:
- achievement_brann_spankin_new() : AchievementCriteriaScript("achievement_brann_spankin_new")
- {
- }
+ achievement_brann_spankin_new() : AchievementCriteriaScript("achievement_brann_spankin_new") { }
bool OnCheck(Player* /*player*/, Unit* target) override
{
diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.h b/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.h
index 2ed47b42bbc..df56aadfe22 100644
--- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.h
+++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.h
@@ -28,7 +28,7 @@ enum DataTypes
// Encounter States/Boss GUIDs
DATA_KRYSTALLUS = 0,
DATA_MAIDEN_OF_GRIEF = 1,
- DATA_BRANN_EVENT = 2,
+ DATA_TRIBUNAL_OF_AGES = 2,
DATA_SJONNIR = 3,
// Additional data
diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/instance_halls_of_stone.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/instance_halls_of_stone.cpp
index a70d1ff3a0d..c67e31c4cc0 100644
--- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/instance_halls_of_stone.cpp
+++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/instance_halls_of_stone.cpp
@@ -23,8 +23,8 @@
DoorData const doorData[] =
{
- { GO_SJONNIR_DOOR, DATA_BRANN_EVENT, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
- { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } // END
+ { GO_SJONNIR_DOOR, DATA_TRIBUNAL_OF_AGES, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
+ { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } // END
};
class instance_halls_of_stone : public InstanceMapScript
@@ -90,7 +90,7 @@ class instance_halls_of_stone : public InstanceMapScript
case GO_TRIBUNAL_CHEST:
case GO_TRIBUNAL_CHEST_HERO:
TribunalChestGUID = go->GetGUID();
- if (GetBossState(DATA_BRANN_EVENT) == DONE)
+ if (GetBossState(DATA_TRIBUNAL_OF_AGES) == DONE)
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
break;
case GO_TRIBUNAL_SKY_FLOOR:
@@ -156,7 +156,7 @@ class instance_halls_of_stone : public InstanceMapScript
switch (type)
{
- case DATA_BRANN_EVENT:
+ case DATA_TRIBUNAL_OF_AGES:
if (state == DONE)
{
if (GameObject* go = instance->GetGameObject(TribunalChestGUID))
@@ -178,7 +178,7 @@ class instance_halls_of_stone : public InstanceMapScript
switch (bossId)
{
case DATA_SJONNIR:
- if (GetBossState(DATA_BRANN_EVENT) != DONE)
+ if (GetBossState(DATA_TRIBUNAL_OF_AGES) != DONE)
return false;
break;
default:
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
index 23b86737f4c..a04c809f893 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
@@ -482,40 +482,47 @@ class boss_flame_leviathan : public CreatureScript
if (action && action <= 4) // Tower destruction, debuff leviathan loot and reduce active tower count
{
if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3 | LOOT_MODE_HARD_MODE_4) && ActiveTowersCount == 4)
- {
me->RemoveLootMode(LOOT_MODE_HARD_MODE_4);
- --ActiveTowersCount;
- }
+
if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3) && ActiveTowersCount == 3)
- {
me->RemoveLootMode(LOOT_MODE_HARD_MODE_3);
- --ActiveTowersCount;
- }
+
if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2) && ActiveTowersCount == 2)
- {
me->RemoveLootMode(LOOT_MODE_HARD_MODE_2);
- --ActiveTowersCount;
- }
+
if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1) && ActiveTowersCount == 1)
- {
me->RemoveLootMode(LOOT_MODE_HARD_MODE_1);
- --ActiveTowersCount;
- }
}
switch (action)
{
case ACTION_TOWER_OF_STORM_DESTROYED:
- towerOfStorms = false;
+ if (towerOfStorms)
+ {
+ towerOfStorms = false;
+ --ActiveTowersCount;
+ }
break;
case ACTION_TOWER_OF_FROST_DESTROYED:
- towerOfFrost = false;
+ if (towerOfFrost)
+ {
+ towerOfFrost = false;
+ --ActiveTowersCount;
+ }
break;
case ACTION_TOWER_OF_FLAMES_DESTROYED:
- towerOfFlames = false;
+ if (towerOfFlames)
+ {
+ towerOfFlames = false;
+ --ActiveTowersCount;
+ }
break;
case ACTION_TOWER_OF_LIFE_DESTROYED:
- towerOfLife = false;
+ if (towerOfLife)
+ {
+ towerOfLife = false;
+ --ActiveTowersCount;
+ }
break;
case ACTION_START_HARD_MODE: // Activate hard-mode enable all towers, apply buffs on leviathan
ActiveTowers = true;
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp
index 4841950d9d3..64403ad40ca 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp
@@ -458,7 +458,7 @@ class spell_general_vezax_mark_of_the_faceless : public SpellScriptLoader
{
PrepareAuraScript(spell_general_vezax_mark_of_the_faceless_AuraScript);
- bool Validate(SpellInfo const* /*spellInfo*/)
+ bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_MARK_OF_THE_FACELESS_DAMAGE))
return false;
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
index a682e405d08..d0e4b7be63b 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
@@ -903,17 +903,15 @@ class boss_yogg_saron : public CreatureScript
DoCast(me, SPELL_KNOCK_AWAY);
me->ResetLootMode();
- switch (_instance->GetData(DATA_KEEPERS_COUNT))
- {
- case 0:
- me->AddLootMode(LOOT_MODE_HARD_MODE_4);
- case 1:
- me->AddLootMode(LOOT_MODE_HARD_MODE_3);
- case 2:
- me->AddLootMode(LOOT_MODE_HARD_MODE_2);
- case 3:
- me->AddLootMode(LOOT_MODE_HARD_MODE_1);
- }
+ uint32 keepersCount = _instance->GetData(DATA_KEEPERS_COUNT);
+ if (keepersCount == 0)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_4);
+ if (keepersCount <= 1)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_3);
+ if (keepersCount <= 2)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_2);
+ if (keepersCount <= 3)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_1);
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
@@ -1126,30 +1124,11 @@ class npc_ominous_cloud : public CreatureScript
DoCast(me, SPELL_OMINOUS_CLOUD_VISUAL);
}
- void FillCirclePath(Position const& centerPos, float radius, float z, Movement::PointsArray& path, bool clockwise)
- {
- float step = clockwise ? float(-M_PI) / 8.0f : float(M_PI) / 8.0f;
- float angle = centerPos.GetAngle(me->GetPositionX(), me->GetPositionY());
-
- for (uint8 i = 0; i < 16; angle += step, ++i)
- {
- G3D::Vector3 point;
- point.x = centerPos.GetPositionX() + radius * cosf(angle);
- point.y = centerPos.GetPositionY() + radius * sinf(angle);
- point.z = me->GetMap()->GetHeight(me->GetPhaseMask(), point.x, point.y, z + 5.0f);
- path.push_back(point);
- }
- }
-
void UpdateAI(uint32 /*diff*/) override { }
- void DoAction(int32 action) override
+ void DoAction(int32 /*action*/) override
{
- Movement::MoveSplineInit init(me);
- FillCirclePath(YoggSaronSpawnPos, me->GetDistance2d(YoggSaronSpawnPos.GetPositionX(), YoggSaronSpawnPos.GetPositionY()), me->GetPositionZ(), init.Path(), action != 0);
- init.SetWalk(true);
- init.SetCyclic();
- init.Launch();
+ me->GetMotionMaster()->MoveCirclePath(YoggSaronSpawnPos.GetPositionX(), YoggSaronSpawnPos.GetPositionY(), me->GetPositionZ() + 5.0f, me->GetDistance2d(YoggSaronSpawnPos.GetPositionX(), YoggSaronSpawnPos.GetPositionY()), true, 16);
}
};
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
index 952e35642d0..ca3ea3a60ed 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
@@ -16,6 +16,7 @@
*/
#include "InstanceScript.h"
+#include "Vehicle.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
@@ -91,6 +92,7 @@ class instance_ulduar : public InstanceMapScript
// Creatures
ObjectGuid LeviathanGUID;
+ GuidVector LeviathanVehicleGUIDs;
ObjectGuid IgnisGUID;
ObjectGuid RazorscaleGUID;
ObjectGuid RazorscaleController;
@@ -217,6 +219,11 @@ class instance_ulduar : public InstanceMapScript
case NPC_LEVIATHAN:
LeviathanGUID = creature->GetGUID();
break;
+ case NPC_SALVAGED_DEMOLISHER:
+ case NPC_SALVAGED_SIEGE_ENGINE:
+ case NPC_SALVAGED_CHOPPER:
+ LeviathanVehicleGUIDs.push_back(creature->GetGUID());
+ break;
case NPC_IGNIS:
IgnisGUID = creature->GetGUID();
break;
@@ -441,7 +448,7 @@ class instance_ulduar : public InstanceMapScript
}
}
- void OnGameObjectCreate(GameObject* gameObject)
+ void OnGameObjectCreate(GameObject* gameObject) override
{
switch (gameObject->GetEntry())
{
@@ -682,6 +689,24 @@ class instance_ulduar : public InstanceMapScript
switch (type)
{
case BOSS_LEVIATHAN:
+ if (state == DONE)
+ {
+ // Eject all players from vehicles and make them untargetable.
+ // They will be despawned after a while
+ for (auto const& vehicleGuid : LeviathanVehicleGUIDs)
+ {
+ if (Creature* vehicleCreature = instance->GetCreature(vehicleGuid))
+ {
+ if (Vehicle* vehicle = vehicleCreature->GetVehicleKit())
+ {
+ vehicle->RemoveAllPassengers();
+ vehicleCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ vehicleCreature->DespawnOrUnsummon(5 * MINUTE * IN_MILLISECONDS);
+ }
+ }
+ }
+ }
+ break;
case BOSS_IGNIS:
case BOSS_RAZORSCALE:
case BOSS_XT002:
@@ -1143,6 +1168,34 @@ class instance_ulduar : public InstanceMapScript
}
}
+ void UpdateDoorState(GameObject* door) override
+ {
+ // Leviathan doors are set to DOOR_TYPE_ROOM except the one it uses to enter the room
+ // which has to be set to DOOR_TYPE_PASSAGE
+ if (door->GetEntry() == GO_LEVIATHAN_DOOR && door->GetPositionX() > 400.f)
+ door->SetGoState(GetBossState(BOSS_LEVIATHAN) == DONE ? GO_STATE_ACTIVE : GO_STATE_READY);
+ else
+ InstanceScript::UpdateDoorState(door);
+ }
+
+ void AddDoor(GameObject* door, bool add) override
+ {
+ // Leviathan doors are South except the one it uses to enter the room
+ // which is North and should not be used for boundary checks in BossAI::CheckBoundary()
+ if (door->GetEntry() == GO_LEVIATHAN_DOOR && door->GetPositionX() > 400.f)
+ {
+ if (add)
+ GetBossInfo(BOSS_LEVIATHAN)->door[DOOR_TYPE_PASSAGE].insert(door->GetGUID());
+ else
+ GetBossInfo(BOSS_LEVIATHAN)->door[DOOR_TYPE_PASSAGE].erase(door->GetGUID());
+
+ if (add)
+ UpdateDoorState(door);
+ }
+ else
+ InstanceScript::AddDoor(door, add);
+ }
+
private:
EventMap _events;
uint32 _algalonTimer;
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h
index ddf293dd8b8..d40fb698658 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h
@@ -54,6 +54,7 @@ enum UlduarNPCs
NPC_LEVIATHAN = 33113,
NPC_SALVAGED_DEMOLISHER = 33109,
NPC_SALVAGED_SIEGE_ENGINE = 33060,
+ NPC_SALVAGED_CHOPPER = 33062,
NPC_IGNIS = 33118,
NPC_RAZORSCALE = 33186,
NPC_RAZORSCALE_CONTROLLER = 33233,
diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp
index 571f73ea628..483beda43ee 100644
--- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp
+++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp
@@ -141,7 +141,7 @@ class boss_ingvar_the_plunderer : public CreatureScript
damage = 0;
}
- void DoAction(int32 actionId)
+ void DoAction(int32 actionId) override
{
if (actionId == ACTION_START_PHASE_2)
StartZombiePhase();
diff --git a/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp b/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp
index 36d2c5f8ed3..dc923e534b0 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp
@@ -23,12 +23,9 @@ enum Spells
{
SPELL_ARCANE_VACUUM = 58694,
SPELL_BLIZZARD = 58693,
- H_SPELL_BLIZZARD = 59369,
SPELL_MANA_DESTRUCTION = 59374,
SPELL_TAIL_SWEEP = 58690,
- H_SPELL_TAIL_SWEEP = 59283,
SPELL_UNCONTROLLABLE_ENERGY = 58688,
- H_SPELL_UNCONTROLLABLE_ENERGY = 59281,
SPELL_TRANSFORM = 58668
};
@@ -48,17 +45,11 @@ class boss_cyanigosa : public CreatureScript
public:
boss_cyanigosa() : CreatureScript("boss_cyanigosa") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_cyanigosaAI>(creature);
- }
-
- struct boss_cyanigosaAI : public ScriptedAI
+ struct boss_cyanigosaAI : public BossAI
{
- boss_cyanigosaAI(Creature* creature) : ScriptedAI(creature)
+ boss_cyanigosaAI(Creature* creature) : BossAI(creature, DATA_CYANIGOSA)
{
Initialize();
- instance = creature->GetInstanceScript();
}
void Initialize()
@@ -76,24 +67,20 @@ public:
uint32 uiTailSweepTimer;
uint32 uiUncontrollableEnergyTimer;
- InstanceScript* instance;
-
void Reset() override
{
Initialize();
- instance->SetData(DATA_CYANIGOSA_EVENT, NOT_STARTED);
+ BossAI::Reset();
}
- void EnterCombat(Unit* /*who*/) override
+ void EnterCombat(Unit* who) override
{
+ BossAI::EnterCombat(who);
Talk(SAY_AGGRO);
-
- instance->SetData(DATA_CYANIGOSA_EVENT, IN_PROGRESS);
}
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
if (instance->GetData(DATA_REMOVE_NPC) == 1)
@@ -102,13 +89,12 @@ public:
instance->SetData(DATA_REMOVE_NPC, 0);
}
- //Return since we have no target
if (!UpdateVictim())
return;
if (uiArcaneVacuumTimer <= diff)
{
- DoCast(SPELL_ARCANE_VACUUM);
+ DoCastAOE(SPELL_ARCANE_VACUUM);
uiArcaneVacuumTimer = 10000;
} else uiArcaneVacuumTimer -= diff;
@@ -121,7 +107,7 @@ public:
if (uiTailSweepTimer <= diff)
{
- DoCast(SPELL_TAIL_SWEEP);
+ DoCastVictim(SPELL_TAIL_SWEEP);
uiTailSweepTimer = 20000;
} else uiTailSweepTimer -= diff;
@@ -144,22 +130,23 @@ public:
DoMeleeAttackIfReady();
}
- void JustDied(Unit* /*killer*/) override
+ void JustDied(Unit* killer) override
{
+ BossAI::JustDied(killer);
Talk(SAY_DEATH);
-
- instance->SetData(DATA_CYANIGOSA_EVENT, DONE);
}
void KilledUnit(Unit* victim) override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_SLAY);
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_cyanigosaAI>(creature);
+ }
};
class achievement_defenseless : public AchievementCriteriaScript
diff --git a/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp b/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp
index e990b8796de..5c8d4b8691a 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp
@@ -24,9 +24,7 @@ enum Spells
SPELL_BLOODLUST = 54516,
SPELL_BREAK_BONDS = 59463,
SPELL_CHAIN_HEAL = 54481,
- H_SPELL_CHAIN_HEAL = 59473,
SPELL_EARTH_SHIELD = 54479,
- H_SPELL_EARTH_SHIELD = 59471,
SPELL_EARTH_SHOCK = 54511,
SPELL_LIGHTNING_BOLT = 53044,
SPELL_STORMSTRIKE = 51876
@@ -47,11 +45,6 @@ class boss_erekem : public CreatureScript
public:
boss_erekem() : CreatureScript("boss_erekem") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_erekemAI>(creature);
- }
-
struct boss_erekemAI : public ScriptedAI
{
boss_erekemAI(Creature* creature) : ScriptedAI(creature)
@@ -81,9 +74,9 @@ public:
{
Initialize();
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)))
{
@@ -129,25 +122,23 @@ public:
Talk(SAY_AGGRO);
DoCast(me, SPELL_EARTH_SHIELD);
- if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_EREKEM_CELL)))
- if (pDoor->GetGoState() == GO_STATE_READY)
+ if (GameObject* door = instance->GetGameObject(DATA_EREKEM_CELL))
+ if (door->GetGoState() == GO_STATE_READY)
{
EnterEvadeMode();
return;
}
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
}
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
- //Return since we have no target
if (!UpdateVictim())
return;
@@ -212,22 +203,20 @@ public:
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
- instance->SetData(DATA_1ST_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
- instance->SetData(DATA_2ND_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
void KilledUnit(Unit* victim) override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_SLAY);
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
}
ObjectGuid GetChainHealTargetGUID()
@@ -247,6 +236,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_erekemAI>(creature);
+ }
};
enum GuardSpells
@@ -261,11 +254,6 @@ class npc_erekem_guard : public CreatureScript
public:
npc_erekem_guard() : CreatureScript("npc_erekem_guard") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_erekem_guardAI>(creature);
- }
-
struct npc_erekem_guardAI : public ScriptedAI
{
npc_erekem_guardAI(Creature* creature) : ScriptedAI(creature)
@@ -308,7 +296,6 @@ public:
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
@@ -336,6 +323,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_erekem_guardAI>(creature);
+ }
};
void AddSC_boss_erekem()
diff --git a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp
index 48fe8049d19..9be73febd52 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp
@@ -23,19 +23,16 @@ enum Spells
{
SPELL_DRAINED = 59820,
SPELL_FRENZY = 54312,
- SPELL_FRENZY_H = 59522,
SPELL_PROTECTIVE_BUBBLE = 54306,
SPELL_WATER_BLAST = 54237,
- SPELL_WATER_BLAST_H = 59520,
SPELL_WATER_BOLT_VOLLEY = 54241,
- SPELL_WATER_BOLT_VOLLEY_H = 59521,
SPELL_SPLASH = 59516,
SPELL_WATER_GLOBULE = 54268
};
enum IchoronCreatures
{
- NPC_ICHOR_GLOBULE = 29321,
+ NPC_ICHOR_GLOBULE = 29321
};
enum Yells
@@ -52,18 +49,18 @@ enum Yells
enum Actions
{
ACTION_WATER_ELEMENT_HIT = 1,
- ACTION_WATER_ELEMENT_KILLED = 2,
+ ACTION_WATER_ELEMENT_KILLED = 2
};
/// @todo get those positions from spawn of creature 29326
#define MAX_SPAWN_LOC 5
-static Position SpawnLoc[MAX_SPAWN_LOC]=
+static Position const SpawnLoc[MAX_SPAWN_LOC]=
{
{1840.64f, 795.407f, 44.079f, 1.676f},
{1886.24f, 757.733f, 47.750f, 5.201f},
{1877.91f, 845.915f, 43.417f, 3.560f},
{1918.97f, 850.645f, 47.225f, 4.136f},
- {1935.50f, 796.224f, 52.492f, 4.224f},
+ {1935.50f, 796.224f, 52.492f, 4.224f}
};
enum Misc
@@ -76,11 +73,6 @@ class boss_ichoron : public CreatureScript
public:
boss_ichoron() : CreatureScript("boss_ichoron") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_ichoronAI>(creature);
- }
-
struct boss_ichoronAI : public ScriptedAI
{
boss_ichoronAI(Creature* creature) : ScriptedAI(creature), m_waterElements(creature)
@@ -117,9 +109,9 @@ public:
DespawnWaterElements();
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
@@ -128,16 +120,17 @@ public:
DoCast(me, SPELL_PROTECTIVE_BUBBLE);
- if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_ICHORON_CELL)))
- if (pDoor->GetGoState() == GO_STATE_READY)
+ if (GameObject* door = instance->GetGameObject(DATA_ICHORON_CELL))
+ if (door->GetGoState() == GO_STATE_READY)
{
EnterEvadeMode();
return;
}
+
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
}
void AttackStart(Unit* who) override
@@ -208,7 +201,6 @@ public:
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 uiDiff) override
{
if (!UpdateVictim())
@@ -230,7 +222,7 @@ public:
if (!me->HasAura(SPELL_PROTECTIVE_BUBBLE))
{
Talk(SAY_SHATTER);
- DoCast(me, SPELL_WATER_BLAST);
+ DoCast(me, SPELL_WATER_BLAST); // wrong target
DoCast(me, SPELL_DRAINED);
bIsExploded = true;
me->AttackStop();
@@ -291,12 +283,12 @@ public:
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
- instance->SetData(DATA_1ST_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
- instance->SetData(DATA_2ND_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
@@ -323,13 +315,15 @@ public:
void KilledUnit(Unit* victim) override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_SLAY);
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_ichoronAI>(creature);
+ }
};
class npc_ichor_globule : public CreatureScript
@@ -337,11 +331,6 @@ class npc_ichor_globule : public CreatureScript
public:
npc_ichor_globule() : CreatureScript("npc_ichor_globule") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_ichor_globuleAI>(creature);
- }
-
struct npc_ichor_globuleAI : public ScriptedAI
{
npc_ichor_globuleAI(Creature* creature) : ScriptedAI(creature)
@@ -367,19 +356,18 @@ public:
void AttackStart(Unit* /*who*/) override
{
- return;
}
void UpdateAI(uint32 uiDiff) override
{
if (uiRangeCheck_Timer < uiDiff)
{
- if (Creature* pIchoron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ICHORON)))
+ if (Creature* ichoron = instance->GetCreature(DATA_ICHORON))
{
- if (me->IsWithinDist(pIchoron, 2.0f, false))
+ if (me->IsWithinDist(ichoron, 2.0f, false))
{
- if (pIchoron->AI())
- pIchoron->AI()->DoAction(ACTION_WATER_ELEMENT_HIT);
+ if (ichoron->AI())
+ ichoron->AI()->DoAction(ACTION_WATER_ELEMENT_HIT);
me->DespawnOrUnsummon();
}
}
@@ -391,12 +379,16 @@ public:
void JustDied(Unit* /*killer*/) override
{
DoCast(me, SPELL_SPLASH);
- if (Creature* pIchoron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ICHORON)))
- if (pIchoron->AI())
- pIchoron->AI()->DoAction(ACTION_WATER_ELEMENT_KILLED);
+ if (Creature* ichoron = instance->GetCreature(DATA_ICHORON))
+ if (ichoron->AI())
+ ichoron->AI()->DoAction(ACTION_WATER_ELEMENT_KILLED);
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_ichor_globuleAI>(creature);
+ }
};
class achievement_dehydration : public AchievementCriteriaScript
diff --git a/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp b/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp
index c3df7b71b83..5040dccfa36 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp
@@ -21,13 +21,10 @@
enum Spells
{
- SPELL_CAUTERIZING_FLAMES = 59466, //Only in heroic
- SPELL_FIREBOLT = 54235,
- H_SPELL_FIREBOLT = 59468,
- SPELL_FLAME_BREATH = 54282,
- H_SPELL_FLAME_BREATH = 59469,
- SPELL_LAVA_BURN = 54249,
- H_SPELL_LAVA_BURN = 59594
+ SPELL_CAUTERIZING_FLAMES = 59466, // Only in heroic
+ SPELL_FIREBOLT = 54235,
+ SPELL_FLAME_BREATH = 54282,
+ SPELL_LAVA_BURN = 54249
};
class boss_lavanthor : public CreatureScript
@@ -35,11 +32,6 @@ class boss_lavanthor : public CreatureScript
public:
boss_lavanthor() : CreatureScript("boss_lavanthor") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_lavanthorAI>(creature);
- }
-
struct boss_lavanthorAI : public ScriptedAI
{
boss_lavanthorAI(Creature* creature) : ScriptedAI(creature)
@@ -67,23 +59,24 @@ public:
{
Initialize();
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
- if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_LAVANTHOR_CELL)))
- if (pDoor->GetGoState() == GO_STATE_READY)
- {
- EnterEvadeMode();
- return;
- }
- if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
- else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
+ if (GameObject* door = instance->GetGameObject(DATA_LAVANTHOR_CELL))
+ if (door->GetGoState() == GO_STATE_READY)
+ {
+ EnterEvadeMode();
+ return;
+ }
+
+ if (instance->GetData(DATA_WAVE_COUNT) == 6)
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
+ else if (instance->GetData(DATA_WAVE_COUNT) == 12)
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
}
void AttackStart(Unit* who) override
@@ -102,10 +95,8 @@ public:
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
- //Return since we have no target
if (!UpdateVictim())
return;
@@ -123,9 +114,10 @@ public:
if (uiLavaBurnTimer <= diff)
{
- DoCastVictim(SPELL_LAVA_BURN);
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50.0f, true))
+ DoCast(target, SPELL_LAVA_BURN);
uiLavaBurnTimer = urand(15000, 23000);
- }
+ } else uiLavaBurnTimer -= diff;
if (IsHeroic())
{
@@ -143,17 +135,21 @@ public:
{
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
- instance->SetData(DATA_1ST_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
- instance->SetData(DATA_2ND_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_lavanthorAI>(creature);
+ }
};
void AddSC_boss_lavanthor()
diff --git a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp
index 9a6422dec32..1c98806b127 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp
@@ -19,11 +19,12 @@
#include "ScriptedCreature.h"
#include "violet_hold.h"
-//Spells
enum Spells
{
SPELL_CORROSIVE_SALIVA = 54527,
- SPELL_OPTIC_LINK = 54396
+ SPELL_OPTIC_LINK = 54396,
+ SPELL_RAY_OF_PAIN = 54438, // NYI missing spelldifficulty
+ SPELL_RAY_OF_SUFFERING = 54442 // NYI missing spelldifficulty
};
class boss_moragg : public CreatureScript
@@ -31,11 +32,6 @@ class boss_moragg : public CreatureScript
public:
boss_moragg() : CreatureScript("boss_moragg") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_moraggAI>(creature);
- }
-
struct boss_moraggAI : public ScriptedAI
{
boss_moraggAI(Creature* creature) : ScriptedAI(creature)
@@ -60,23 +56,24 @@ public:
Initialize();
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
- if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_MORAGG_CELL)))
- if (pDoor->GetGoState() == GO_STATE_READY)
+ if (GameObject* door = instance->GetGameObject(DATA_MORAGG_CELL))
+ if (door->GetGoState() == GO_STATE_READY)
{
EnterEvadeMode();
return;
}
+
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
}
void AttackStart(Unit* who) override
@@ -95,10 +92,8 @@ public:
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
- //Return since we have no target
if (!UpdateVictim())
return;
@@ -117,21 +112,26 @@ public:
DoMeleeAttackIfReady();
}
+
void JustDied(Unit* /*killer*/) override
{
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
- instance->SetData(DATA_1ST_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
- instance->SetData(DATA_2ND_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_moraggAI>(creature);
+ }
};
void AddSC_boss_moragg()
diff --git a/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp b/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp
index 833b06cfbff..d1efcb8ca7a 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp
@@ -23,9 +23,7 @@
enum Spells
{
SPELL_ARCANE_BARRAGE_VOLLEY = 54202,
- SPELL_ARCANE_BARRAGE_VOLLEY_H = 59483,
SPELL_ARCANE_BUFFET = 54226,
- SPELL_ARCANE_BUFFET_H = 59485,
SPELL_SUMMON_ETHEREAL_SPHERE_1 = 54102,
SPELL_SUMMON_ETHEREAL_SPHERE_2 = 54137,
SPELL_SUMMON_ETHEREAL_SPHERE_3 = 54138
@@ -40,7 +38,6 @@ enum NPCs
enum CreatureSpells
{
SPELL_ARCANE_POWER = 54160,
- H_SPELL_ARCANE_POWER = 59474,
SPELL_SUMMON_PLAYERS = 54164,
SPELL_POWER_BALL_VISUAL = 54141
};
@@ -61,11 +58,6 @@ class boss_xevozz : public CreatureScript
public:
boss_xevozz() : CreatureScript("boss_xevozz") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_xevozzAI>(creature);
- }
-
struct boss_xevozzAI : public ScriptedAI
{
boss_xevozzAI(Creature* creature) : ScriptedAI(creature)
@@ -90,9 +82,9 @@ public:
void Reset() override
{
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
Initialize();
DespawnSphere();
@@ -139,46 +131,46 @@ public:
void EnterCombat(Unit* /*who*/) override
{
- Talk(SAY_AGGRO);
- if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_XEVOZZ_CELL)))
- if (pDoor->GetGoState() == GO_STATE_READY)
+ if (GameObject* door = instance->GetGameObject(DATA_XEVOZZ_CELL))
+ if (door->GetGoState() == GO_STATE_READY)
{
EnterEvadeMode();
return;
}
+
+ Talk(SAY_AGGRO);
+
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
}
void MoveInLineOfSight(Unit* /*who*/) override { }
-
- void UpdateAI(uint32 uiDiff) override
+ void UpdateAI(uint32 diff) override
{
- //Return since we have no target
if (!UpdateVictim())
return;
- if (uiArcaneBarrageVolley_Timer < uiDiff)
+ if (uiArcaneBarrageVolley_Timer < diff)
{
DoCast(me, SPELL_ARCANE_BARRAGE_VOLLEY);
uiArcaneBarrageVolley_Timer = urand(20000, 22000);
}
- else uiArcaneBarrageVolley_Timer -= uiDiff;
+ else uiArcaneBarrageVolley_Timer -= diff;
if (uiArcaneBuffet_Timer)
{
- if (uiArcaneBuffet_Timer < uiDiff)
+ if (uiArcaneBuffet_Timer < diff)
{
DoCastVictim(SPELL_ARCANE_BUFFET);
uiArcaneBuffet_Timer = 0;
}
- else uiArcaneBuffet_Timer -= uiDiff;
+ else uiArcaneBuffet_Timer -= diff;
}
- if (uiSummonEtherealSphere_Timer < uiDiff)
+ if (uiSummonEtherealSphere_Timer < diff)
{
Talk(SAY_SPAWN);
DoCast(me, SPELL_SUMMON_ETHEREAL_SPHERE_1);
@@ -188,7 +180,7 @@ public:
uiSummonEtherealSphere_Timer = urand(45000, 47000);
uiArcaneBuffet_Timer = urand(5000, 6000);
}
- else uiSummonEtherealSphere_Timer -= uiDiff;
+ else uiSummonEtherealSphere_Timer -= diff;
DoMeleeAttackIfReady();
}
@@ -201,24 +193,27 @@ public:
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
- instance->SetData(DATA_1ST_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
- instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
+
void KilledUnit(Unit* victim) override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_SLAY);
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_xevozzAI>(creature);
+ }
};
class npc_ethereal_sphere : public CreatureScript
@@ -226,11 +221,6 @@ class npc_ethereal_sphere : public CreatureScript
public:
npc_ethereal_sphere() : CreatureScript("npc_ethereal_sphere") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_ethereal_sphereAI>(creature);
- }
-
struct npc_ethereal_sphereAI : public ScriptedAI
{
npc_ethereal_sphereAI(Creature* creature) : ScriptedAI(creature)
@@ -255,16 +245,15 @@ public:
Initialize();
}
- void UpdateAI(uint32 uiDiff) override
+ void UpdateAI(uint32 diff) override
{
- //Return since we have no target
if (!UpdateVictim())
return;
if (!me->HasAura(SPELL_POWER_BALL_VISUAL))
DoCast(me, SPELL_POWER_BALL_VISUAL);
- if (uiRangeCheck_Timer < uiDiff)
+ if (uiRangeCheck_Timer < diff)
{
if (Creature* pXevozz = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_XEVOZZ)))
{
@@ -276,9 +265,9 @@ public:
}
uiRangeCheck_Timer = 1000;
}
- else uiRangeCheck_Timer -= uiDiff;
+ else uiRangeCheck_Timer -= diff;
- if (uiSummonPlayers_Timer < uiDiff)
+ if (uiSummonPlayers_Timer < diff)
{
DoCast(me, SPELL_SUMMON_PLAYERS); // not working right
@@ -295,10 +284,14 @@ public:
uiSummonPlayers_Timer = urand(33000, 35000);
}
- else uiSummonPlayers_Timer -= uiDiff;
+ else uiSummonPlayers_Timer -= diff;
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_ethereal_sphereAI>(creature);
+ }
};
void AddSC_boss_xevozz()
diff --git a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp
index 90fd936e853..c29861f08a4 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp
@@ -22,15 +22,13 @@
enum Spells
{
SPELL_SHROUD_OF_DARKNESS = 54524,
- H_SPELL_SHROUD_OF_DARKNESS = 59745,
SPELL_SUMMON_VOID_SENTRY = 54369,
- SPELL_VOID_SHIFT = 54361,
- H_SPELL_VOID_SHIFT = 59743,
+ SPELL_VOID_SHIFT = 54361
};
enum Creatures
{
- NPC_VOID_SENTRY = 29364
+ NPC_VOID_SENTRY = 29364
};
enum Yells
@@ -53,11 +51,6 @@ class boss_zuramat : public CreatureScript
public:
boss_zuramat() : CreatureScript("boss_zuramat") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_zuramatAI>(creature);
- }
-
struct boss_zuramatAI : public ScriptedAI
{
boss_zuramatAI(Creature* creature) : ScriptedAI(creature)
@@ -107,25 +100,25 @@ public:
void EnterCombat(Unit* /*who*/) override
{
- Talk(SAY_AGGRO);
- if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_ZURAMAT_CELL)))
- if (pDoor->GetGoState() == GO_STATE_READY)
+ if (GameObject* door = instance->GetGameObject(DATA_ZURAMAT_CELL))
+ if (door->GetGoState() == GO_STATE_READY)
{
EnterEvadeMode();
return;
}
+
+ Talk(SAY_AGGRO);
+
if (instance->GetData(DATA_WAVE_COUNT) == 6)
- instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
- instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
}
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
- //Return since we have no target
if (!UpdateVictim())
return;
@@ -171,26 +164,27 @@ public:
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
- instance->SetData(DATA_1ST_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
- instance->SetData(DATA_2ND_BOSS_EVENT, DONE);
+ instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
void KilledUnit(Unit* victim) override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_SLAY);
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
}
-
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_zuramatAI>(creature);
+ }
};
class achievement_void_dance : public AchievementCriteriaScript
diff --git a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp
index 3e3ce5cde75..28c56a02255 100644
--- a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp
+++ b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp
@@ -22,8 +22,6 @@
#include "Player.h"
#include "TemporarySummon.h"
-#define MAX_ENCOUNTER 3
-
/* Violet Hold encounters:
0 - First boss
1 - Second boss
@@ -38,21 +36,6 @@
6 - Zuramat
7 - Cyanigosa */
-enum GameObjects
-{
- GO_MAIN_DOOR = 191723,
- GO_XEVOZZ_DOOR = 191556,
- GO_LAVANTHOR_DOOR = 191566,
- GO_ICHORON_DOOR = 191722,
- GO_ZURAMAT_DOOR = 191565,
- GO_EREKEM_DOOR = 191564,
- GO_EREKEM_GUARD_1_DOOR = 191563,
- GO_EREKEM_GUARD_2_DOOR = 191562,
- GO_MORAGG_DOOR = 191606,
- GO_INTRO_ACTIVATION_CRYSTAL = 193615,
- GO_ACTIVATION_CRYSTAL = 193611
-};
-
enum AzureSaboteurSpells
{
SABOTEUR_SHIELD_DISRUPTION = 58291,
@@ -64,7 +47,7 @@ enum CrystalSpells
SPELL_ARCANE_LIGHTNING = 57930
};
-const Position PortalLocation[] =
+Position const PortalLocation[] =
{
{1877.51f, 850.104f, 44.6599f, 4.7822f }, // WP 1
{1918.37f, 853.437f, 47.1624f, 4.12294f}, // WP 2
@@ -74,21 +57,21 @@ const Position PortalLocation[] =
{1908.31f, 809.657f, 38.7037f, 3.08701f} // WP 6
};
-const Position ArcaneSphere = {1887.060059f, 806.151001f, 61.321602f, 0.0f};
-const Position BossStartMove1 = {1894.684448f, 739.390503f, 47.668003f, 0.0f};
-const Position BossStartMove2 = {1875.173950f, 860.832703f, 43.333565f, 0.0f};
-const Position BossStartMove21 = {1858.854614f, 855.071411f, 43.333565f, 0.0f};
-const Position BossStartMove22 = {1891.926636f, 863.388977f, 43.333565f, 0.0f};
-const Position BossStartMove3 = {1916.138062f, 778.152222f, 35.772308f, 0.0f};
-const Position BossStartMove4 = {1853.618286f, 758.557617f, 38.657505f, 0.0f};
-const Position BossStartMove5 = {1906.683960f, 842.348022f, 38.637459f, 0.0f};
-const Position BossStartMove6 = {1928.207031f, 852.864441f, 47.200813f, 0.0f};
-
-const Position CyanigosasSpawnLocation = {1930.281250f, 804.407715f, 52.410946f, 3.139621f};
-const Position MiddleRoomLocation = {1892.291260f, 805.696838f, 38.438862f, 3.139621f};
-const Position MiddleRoomPortalSaboLocation = {1896.622925f, 804.854126f, 38.504772f, 3.139621f};
-
-//Cyanigosa's prefight event data
+Position const ArcaneSphere = {1887.060059f, 806.151001f, 61.321602f, 0.0f};
+Position const BossStartMove1 = {1894.684448f, 739.390503f, 47.668003f, 0.0f};
+Position const BossStartMove2 = {1875.173950f, 860.832703f, 43.333565f, 0.0f};
+Position const BossStartMove21 = {1858.854614f, 855.071411f, 43.333565f, 0.0f};
+Position const BossStartMove22 = {1891.926636f, 863.388977f, 43.333565f, 0.0f};
+Position const BossStartMove3 = {1916.138062f, 778.152222f, 35.772308f, 0.0f};
+Position const BossStartMove4 = {1853.618286f, 758.557617f, 38.657505f, 0.0f};
+Position const BossStartMove5 = {1906.683960f, 842.348022f, 38.637459f, 0.0f};
+Position const BossStartMove6 = {1928.207031f, 852.864441f, 47.200813f, 0.0f};
+
+Position const CyanigosasSpawnLocation = {1930.281250f, 804.407715f, 52.410946f, 3.139621f};
+Position const MiddleRoomLocation = {1892.291260f, 805.696838f, 38.438862f, 3.139621f};
+Position const MiddleRoomPortalSaboLocation = {1896.622925f, 804.854126f, 38.504772f, 3.139621f};
+
+// Cyanigosa's prefight event data
enum Yells
{
CYANIGOSA_SAY_SPAWN = 0
@@ -100,21 +83,45 @@ enum Spells
CYANIGOSA_BLUE_AURA = 47759,
};
+ObjectData const creatureData[] =
+{
+ { NPC_XEVOZZ, DATA_XEVOZZ },
+ { NPC_LAVANTHOR, DATA_LAVANTHOR },
+ { NPC_ICHORON, DATA_ICHORON },
+ { NPC_ZURAMAT, DATA_ZURAMAT },
+ { NPC_EREKEM, DATA_EREKEM },
+ { NPC_MORAGG, DATA_MORAGG },
+ { NPC_CYANIGOSA, DATA_CYANIGOSA },
+ { NPC_SINCLARI, DATA_SINCLARI },
+ { 0, 0 } // END
+};
+
+ObjectData const gameObjectData[] =
+{
+ { GO_EREKEM_GUARD_1_DOOR, DATA_EREKEM_LEFT_GUARD_CELL },
+ { GO_EREKEM_GUARD_2_DOOR, DATA_EREKEM_RIGHT_GUARD_CELL },
+ { GO_EREKEM_DOOR, DATA_EREKEM_CELL },
+ { GO_ZURAMAT_DOOR, DATA_ZURAMAT_CELL },
+ { GO_LAVANTHOR_DOOR, DATA_LAVANTHOR_CELL },
+ { GO_MORAGG_DOOR, DATA_MORAGG_CELL },
+ { GO_ICHORON_DOOR, DATA_ICHORON_CELL },
+ { GO_XEVOZZ_DOOR, DATA_XEVOZZ_CELL },
+ { GO_MAIN_DOOR, DATA_MAIN_DOOR },
+ { 0, 0 } // END
+};
+
class instance_violet_hold : public InstanceMapScript
{
public:
instance_violet_hold() : InstanceMapScript("instance_violet_hold", 608) { }
- InstanceScript* GetInstanceScript(InstanceMap* map) const override
- {
- return new instance_violet_hold_InstanceMapScript(map);
- }
-
struct instance_violet_hold_InstanceMapScript : public InstanceScript
{
instance_violet_hold_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
+ SetBossNumber(EncounterCount);
+ LoadObjectData(creatureData, gameObjectData);
uiRemoveNpc = 0;
@@ -133,33 +140,15 @@ public:
uiCyanigosaEventTimer = 3 * IN_MILLISECONDS;
bActive = false;
+ bWiped = false;
bIsDoorSpellCast = false;
bCrystalActivated = false;
defenseless = true;
uiMainEventPhase = NOT_STARTED;
-
- memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
}
- ObjectGuid uiMoragg;
- ObjectGuid uiErekem;
ObjectGuid uiErekemGuard[2];
- ObjectGuid uiIchoron;
- ObjectGuid uiLavanthor;
- ObjectGuid uiXevozz;
- ObjectGuid uiZuramat;
- ObjectGuid uiCyanigosa;
- ObjectGuid uiSinclari;
-
- ObjectGuid uiMoraggCell;
- ObjectGuid uiErekemCell;
- ObjectGuid uiErekemLeftGuardCell;
- ObjectGuid uiErekemRightGuardCell;
- ObjectGuid uiIchoronCell;
- ObjectGuid uiLavanthorCell;
- ObjectGuid uiXevozzCell;
- ObjectGuid uiZuramatCell;
- ObjectGuid uiMainDoor;
+
ObjectGuid uiTeleportationPortal;
ObjectGuid uiSaboteurPortal;
@@ -179,7 +168,6 @@ public:
uint8 uiDoorIntegrity;
- uint16 m_auiEncounter[MAX_ENCOUNTER];
uint8 uiCountErekemGuards;
uint8 uiCountActivationCrystals;
uint8 uiCyanigosaEventPhase;
@@ -193,52 +181,23 @@ public:
std::list<uint8> NpcAtDoorCastingList;
- std::string str_data;
-
- bool IsEncounterInProgress() const override
- {
- for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- if (m_auiEncounter[i] == IN_PROGRESS)
- return true;
-
- return false;
- }
-
void OnCreatureCreate(Creature* creature) override
{
+ InstanceScript::OnCreatureCreate(creature);
+
switch (creature->GetEntry())
{
- case CREATURE_XEVOZZ:
- uiXevozz = creature->GetGUID();
- break;
- case CREATURE_LAVANTHOR:
- uiLavanthor = creature->GetGUID();
- break;
- case CREATURE_ICHORON:
- uiIchoron = creature->GetGUID();
- break;
- case CREATURE_ZURAMAT:
- uiZuramat = creature->GetGUID();
- break;
- case CREATURE_EREKEM:
- uiErekem = creature->GetGUID();
- break;
- case CREATURE_EREKEM_GUARD:
+ case NPC_EREKEM_GUARD:
if (uiCountErekemGuards < 2)
{
uiErekemGuard[uiCountErekemGuards++] = creature->GetGUID();
- creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE);
}
break;
- case CREATURE_MORAGG:
- uiMoragg = creature->GetGUID();
+ case NPC_CYANIGOSA:
+ creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE);
break;
- case CREATURE_CYANIGOSA:
- uiCyanigosa = creature->GetGUID();
- creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
- break;
- case CREATURE_SINCLARI:
- uiSinclari = creature->GetGUID();
+ default:
break;
}
@@ -254,68 +213,53 @@ public:
void OnGameObjectCreate(GameObject* go) override
{
+ InstanceScript::OnGameObjectCreate(go);
+
switch (go->GetEntry())
{
- case GO_EREKEM_GUARD_1_DOOR:
- uiErekemLeftGuardCell = go->GetGUID();
- break;
- case GO_EREKEM_GUARD_2_DOOR:
- uiErekemRightGuardCell = go->GetGUID();
- break;
- case GO_EREKEM_DOOR:
- uiErekemCell = go->GetGUID();
- break;
- case GO_ZURAMAT_DOOR:
- uiZuramatCell = go->GetGUID();
- break;
- case GO_LAVANTHOR_DOOR:
- uiLavanthorCell = go->GetGUID();
- break;
- case GO_MORAGG_DOOR:
- uiMoraggCell = go->GetGUID();
- break;
- case GO_ICHORON_DOOR:
- uiIchoronCell = go->GetGUID();
- break;
- case GO_XEVOZZ_DOOR:
- uiXevozzCell = go->GetGUID();
- break;
- case GO_MAIN_DOOR:
- uiMainDoor = go->GetGUID();
- break;
case GO_ACTIVATION_CRYSTAL:
if (uiCountActivationCrystals < 4)
uiActivationCrystal[uiCountActivationCrystals++] = go->GetGUID();
break;
+ default:
+ break;
}
}
- void SetData(uint32 type, uint32 data) override
+ bool SetBossState(uint32 type, EncounterState state) override
{
+ if (!InstanceScript::SetBossState(type, state))
+ return false;
+
switch (type)
{
case DATA_1ST_BOSS_EVENT:
- UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, CREATURE_EREKEM, NULL);
- m_auiEncounter[0] = data;
- if (data == DONE)
- SaveToDB();
+ if (state == DONE)
+ UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, NPC_EREKEM, nullptr);
break;
case DATA_2ND_BOSS_EVENT:
- UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, CREATURE_MORAGG, NULL);
- m_auiEncounter[1] = data;
- if (data == DONE)
- SaveToDB();
- break;
- case DATA_CYANIGOSA_EVENT:
- m_auiEncounter[2] = data;
- if (data == DONE)
+ if (state == DONE)
+ UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, NPC_MORAGG, nullptr);
+ break;
+ case DATA_CYANIGOSA:
+ if (state == DONE)
{
- SaveToDB();
uiMainEventPhase = DONE;
- if (GameObject* pMainDoor = instance->GetGameObject(uiMainDoor))
- pMainDoor->SetGoState(GO_STATE_ACTIVE);
+ if (GameObject* mainDoor = GetGameObject(DATA_MAIN_DOOR))
+ mainDoor->SetGoState(GO_STATE_ACTIVE);
}
break;
+ default:
+ break;
+ }
+
+ return true;
+ }
+
+ void SetData(uint32 type, uint32 data) override
+ {
+ switch (type)
+ {
case DATA_WAVE_COUNT:
uiWaveCount = data;
bActive = true;
@@ -339,21 +283,8 @@ public:
NpcAtDoorCastingList.pop_back();
break;
case DATA_MAIN_DOOR:
- if (GameObject* pMainDoor = instance->GetGameObject(uiMainDoor))
- {
- switch (data)
- {
- case GO_STATE_ACTIVE:
- pMainDoor->SetGoState(GO_STATE_ACTIVE);
- break;
- case GO_STATE_READY:
- pMainDoor->SetGoState(GO_STATE_READY);
- break;
- case GO_STATE_ACTIVE_ALTERNATIVE:
- pMainDoor->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE);
- break;
- }
- }
+ if (GameObject* mainDoor = GetGameObject(type))
+ mainDoor->SetGoState(GOState(data));
break;
case DATA_START_BOSS_ENCOUNTER:
switch (uiWaveCount)
@@ -373,7 +304,7 @@ public:
uiMainEventPhase = data;
if (data == IN_PROGRESS) // Start event
{
- if (GameObject* mainDoor = instance->GetGameObject(uiMainDoor))
+ if (GameObject* mainDoor = GetGameObject(DATA_MAIN_DOOR))
mainDoor->SetGoState(GO_STATE_READY);
uiWaveCount = 1;
bActive = true;
@@ -403,9 +334,6 @@ public:
{
switch (type)
{
- case DATA_1ST_BOSS_EVENT: return m_auiEncounter[0];
- case DATA_2ND_BOSS_EVENT: return m_auiEncounter[1];
- case DATA_CYANIGOSA_EVENT: return m_auiEncounter[2];
case DATA_WAVE_COUNT: return uiWaveCount;
case DATA_REMOVE_NPC: return uiRemoveNpc;
case DATA_PORTAL_LOCATION: return uiLocation;
@@ -420,125 +348,107 @@ public:
return 0;
}
- ObjectGuid GetGuidData(uint32 identifier) const override
+ ObjectGuid GetGuidData(uint32 type) const override
{
- switch (identifier)
+ switch (type)
{
- case DATA_MORAGG: return uiMoragg;
- case DATA_EREKEM: return uiErekem;
case DATA_EREKEM_GUARD_1: return uiErekemGuard[0];
case DATA_EREKEM_GUARD_2: return uiErekemGuard[1];
- case DATA_ICHORON: return uiIchoron;
- case DATA_LAVANTHOR: return uiLavanthor;
- case DATA_XEVOZZ: return uiXevozz;
- case DATA_ZURAMAT: return uiZuramat;
- case DATA_CYANIGOSA: return uiCyanigosa;
- case DATA_MORAGG_CELL: return uiMoraggCell;
- case DATA_EREKEM_CELL: return uiErekemCell;
- case DATA_EREKEM_RIGHT_GUARD_CELL: return uiErekemRightGuardCell;
- case DATA_EREKEM_LEFT_GUARD_CELL: return uiErekemLeftGuardCell;
- case DATA_ICHORON_CELL: return uiIchoronCell;
- case DATA_LAVANTHOR_CELL: return uiLavanthorCell;
- case DATA_XEVOZZ_CELL: return uiXevozzCell;
- case DATA_ZURAMAT_CELL: return uiZuramatCell;
- case DATA_MAIN_DOOR: return uiMainDoor;
- case DATA_SINCLARI: return uiSinclari;
case DATA_TELEPORTATION_PORTAL: return uiTeleportationPortal;
case DATA_SABOTEUR_PORTAL: return uiSaboteurPortal;
}
- return ObjectGuid::Empty;
+ return InstanceScript::GetGuidData(type);
}
void SpawnPortal()
{
SetData(DATA_PORTAL_LOCATION, (GetData(DATA_PORTAL_LOCATION) + urand(1, 5))%6);
- if (Creature* pSinclari = instance->GetCreature(uiSinclari))
- if (Creature* portal = pSinclari->SummonCreature(CREATURE_TELEPORTATION_PORTAL, PortalLocation[GetData(DATA_PORTAL_LOCATION)], TEMPSUMMON_CORPSE_DESPAWN))
+ if (Creature* sinclari = GetCreature(DATA_SINCLARI))
+ if (Creature* portal = sinclari->SummonCreature(NPC_TELEPORTATION_PORTAL, PortalLocation[GetData(DATA_PORTAL_LOCATION)], TEMPSUMMON_CORPSE_DESPAWN))
uiTeleportationPortal = portal->GetGUID();
}
void StartBossEncounter(uint8 uiBoss, bool bForceRespawn = true)
{
- Creature* pBoss = NULL;
+ Creature* boss = nullptr;
switch (uiBoss)
{
case BOSS_MORAGG:
- HandleGameObject(uiMoraggCell, bForceRespawn);
- pBoss = instance->GetCreature(uiMoragg);
- if (pBoss)
- pBoss->GetMotionMaster()->MovePoint(0, BossStartMove1);
+ HandleGameObject(GetObjectGuid(DATA_MORAGG_CELL), bForceRespawn);
+ boss = GetCreature(DATA_MORAGG);
+ if (boss)
+ boss->GetMotionMaster()->MovePoint(0, BossStartMove1);
break;
case BOSS_EREKEM:
- HandleGameObject(uiErekemCell, bForceRespawn);
- HandleGameObject(uiErekemRightGuardCell, bForceRespawn);
- HandleGameObject(uiErekemLeftGuardCell, bForceRespawn);
-
- pBoss = instance->GetCreature(uiErekem);
+ HandleGameObject(GetObjectGuid(DATA_EREKEM_CELL), bForceRespawn);
+ HandleGameObject(GetObjectGuid(DATA_EREKEM_LEFT_GUARD_CELL), bForceRespawn);
+ HandleGameObject(GetObjectGuid(DATA_EREKEM_RIGHT_GUARD_CELL), bForceRespawn);
- if (pBoss)
- pBoss->GetMotionMaster()->MovePoint(0, BossStartMove2);
+ boss = GetCreature(DATA_EREKEM);
+ if (boss)
+ boss->GetMotionMaster()->MovePoint(0, BossStartMove2);
if (Creature* pGuard1 = instance->GetCreature(uiErekemGuard[0]))
{
if (bForceRespawn)
- pGuard1->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ pGuard1->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE);
else
- pGuard1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ pGuard1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE);
pGuard1->GetMotionMaster()->MovePoint(0, BossStartMove21);
}
if (Creature* pGuard2 = instance->GetCreature(uiErekemGuard[1]))
{
if (bForceRespawn)
- pGuard2->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ pGuard2->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE);
else
- pGuard2->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ pGuard2->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE);
pGuard2->GetMotionMaster()->MovePoint(0, BossStartMove22);
}
break;
case BOSS_ICHORON:
- HandleGameObject(uiIchoronCell, bForceRespawn);
- pBoss = instance->GetCreature(uiIchoron);
- if (pBoss)
- pBoss->GetMotionMaster()->MovePoint(0, BossStartMove3);
+ HandleGameObject(GetObjectGuid(DATA_ICHORON_CELL), bForceRespawn);
+ boss = GetCreature(DATA_ICHORON);
+ if (boss)
+ boss->GetMotionMaster()->MovePoint(0, BossStartMove3);
break;
case BOSS_LAVANTHOR:
- HandleGameObject(uiLavanthorCell, bForceRespawn);
- pBoss = instance->GetCreature(uiLavanthor);
- if (pBoss)
- pBoss->GetMotionMaster()->MovePoint(0, BossStartMove4);
+ HandleGameObject(GetObjectGuid(DATA_LAVANTHOR_CELL), bForceRespawn);
+ boss = GetCreature(DATA_LAVANTHOR);
+ if (boss)
+ boss->GetMotionMaster()->MovePoint(0, BossStartMove4);
break;
case BOSS_XEVOZZ:
- HandleGameObject(uiXevozzCell, bForceRespawn);
- pBoss = instance->GetCreature(uiXevozz);
- if (pBoss)
- pBoss->GetMotionMaster()->MovePoint(0, BossStartMove5);
+ HandleGameObject(GetObjectGuid(DATA_XEVOZZ_CELL), bForceRespawn);
+ boss = GetCreature(DATA_XEVOZZ);
+ if (boss)
+ boss->GetMotionMaster()->MovePoint(0, BossStartMove5);
break;
case BOSS_ZURAMAT:
- HandleGameObject(uiZuramatCell, bForceRespawn);
- pBoss = instance->GetCreature(uiZuramat);
- if (pBoss)
- pBoss->GetMotionMaster()->MovePoint(0, BossStartMove6);
+ HandleGameObject(GetObjectGuid(DATA_ZURAMAT_CELL), bForceRespawn);
+ boss = GetCreature(DATA_ZURAMAT);
+ if (boss)
+ boss->GetMotionMaster()->MovePoint(0, BossStartMove6);
break;
}
// generic boss state changes
- if (pBoss)
+ if (boss)
{
- pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
- pBoss->SetReactState(REACT_AGGRESSIVE);
+ boss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ boss->SetReactState(REACT_AGGRESSIVE);
if (!bForceRespawn)
{
- if (pBoss->isDead())
+ if (boss->isDead())
{
// respawn but avoid to be looted again
- pBoss->Respawn();
- pBoss->RemoveLootMode(1);
+ boss->Respawn();
+ boss->RemoveLootMode(1);
}
- pBoss->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ boss->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
uiWaveCount = 0;
}
}
@@ -554,12 +464,12 @@ public:
case 6:
if (uiFirstBoss == 0)
uiFirstBoss = urand(1, 6);
- if (Creature* pSinclari = instance->GetCreature(uiSinclari))
+ if (Creature* sinclari = GetCreature(DATA_SINCLARI))
{
- if (Creature* pPortal = pSinclari->SummonCreature(CREATURE_TELEPORTATION_PORTAL, MiddleRoomPortalSaboLocation, TEMPSUMMON_CORPSE_DESPAWN))
- uiSaboteurPortal = pPortal->GetGUID();
- if (Creature* pAzureSaboteur = pSinclari->SummonCreature(CREATURE_SABOTEOUR, MiddleRoomLocation, TEMPSUMMON_DEAD_DESPAWN))
- pAzureSaboteur->CastSpell(pAzureSaboteur, SABOTEUR_SHIELD_EFFECT, false);
+ if (Creature* portal = sinclari->SummonCreature(NPC_TELEPORTATION_PORTAL, MiddleRoomPortalSaboLocation, TEMPSUMMON_CORPSE_DESPAWN))
+ uiSaboteurPortal = portal->GetGUID();
+ if (Creature* azureSaboteur = sinclari->SummonCreature(NPC_SABOTEOUR, MiddleRoomLocation, TEMPSUMMON_DEAD_DESPAWN))
+ azureSaboteur->CastSpell(azureSaboteur, SABOTEUR_SHIELD_EFFECT, false);
}
break;
case 12:
@@ -568,25 +478,22 @@ public:
{
uiSecondBoss = urand(1, 6);
} while (uiSecondBoss == uiFirstBoss);
- if (Creature* pSinclari = instance->GetCreature(uiSinclari))
+ if (Creature* sinclari = GetCreature(DATA_SINCLARI))
{
- if (Creature* pPortal = pSinclari->SummonCreature(CREATURE_TELEPORTATION_PORTAL, MiddleRoomPortalSaboLocation, TEMPSUMMON_CORPSE_DESPAWN))
+ if (Creature* pPortal = sinclari->SummonCreature(NPC_TELEPORTATION_PORTAL, MiddleRoomPortalSaboLocation, TEMPSUMMON_CORPSE_DESPAWN))
uiSaboteurPortal = pPortal->GetGUID();
- if (Creature* pAzureSaboteur = pSinclari->SummonCreature(CREATURE_SABOTEOUR, MiddleRoomLocation, TEMPSUMMON_DEAD_DESPAWN))
+ if (Creature* pAzureSaboteur = sinclari->SummonCreature(NPC_SABOTEOUR, MiddleRoomLocation, TEMPSUMMON_DEAD_DESPAWN))
pAzureSaboteur->CastSpell(pAzureSaboteur, SABOTEUR_SHIELD_EFFECT, false);
}
break;
case 18:
- {
- Creature* pSinclari = instance->GetCreature(uiSinclari);
- if (pSinclari)
- pSinclari->SummonCreature(CREATURE_CYANIGOSA, CyanigosasSpawnLocation, TEMPSUMMON_DEAD_DESPAWN);
+ if (Creature* sinclari = GetCreature(DATA_SINCLARI))
+ sinclari->SummonCreature(NPC_CYANIGOSA, CyanigosasSpawnLocation, TEMPSUMMON_DEAD_DESPAWN);
break;
- }
case 1:
{
- if (GameObject* pMainDoor = instance->GetGameObject(uiMainDoor))
- pMainDoor->SetGoState(GO_STATE_READY);
+ if (GameObject* mainDoor = GetGameObject(DATA_MAIN_DOOR))
+ mainDoor->SetGoState(GO_STATE_READY);
DoUpdateWorldState(WORLD_STATE_VH_PRISON_STATE, 100);
// no break
}
@@ -596,54 +503,15 @@ public:
}
}
- std::string GetSaveData() override
+ void WriteSaveDataMore(std::ostringstream& data) override
{
- OUT_SAVE_INST_DATA;
-
- std::ostringstream saveStream;
- saveStream << "V H " << (uint16)m_auiEncounter[0]
- << ' ' << (uint16)m_auiEncounter[1]
- << ' ' << (uint16)m_auiEncounter[2]
- << ' ' << (uint16)uiFirstBoss
- << ' ' << (uint16)uiSecondBoss;
-
- str_data = saveStream.str();
-
- OUT_SAVE_INST_DATA_COMPLETE;
- return str_data;
+ data << uiFirstBoss << ' ' << uiSecondBoss;
}
- void Load(const char* in) override
+ void ReadSaveDataMore(std::istringstream& data) override
{
- if (!in)
- {
- OUT_LOAD_INST_DATA_FAIL;
- return;
- }
-
- OUT_LOAD_INST_DATA(in);
-
- char dataHead1, dataHead2;
- uint16 data0, data1, data2, data3, data4;
-
- std::istringstream loadStream(in);
- loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3 >> data4;
-
- if (dataHead1 == 'V' && dataHead2 == 'H')
- {
- m_auiEncounter[0] = data0;
- m_auiEncounter[1] = data1;
- m_auiEncounter[2] = data2;
-
- for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- if (m_auiEncounter[i] == IN_PROGRESS)
- m_auiEncounter[i] = NOT_STARTED;
-
- uiFirstBoss = uint8(data3);
- uiSecondBoss = uint8(data4);
- } else OUT_LOAD_INST_DATA_FAIL;
-
- OUT_LOAD_INST_DATA_COMPLETE;
+ data >> uiFirstBoss;
+ data >> uiSecondBoss;
}
bool CheckWipe()
@@ -694,54 +562,51 @@ public:
if (GameObject* crystal = instance->GetGameObject(uiActivationCrystal[i]))
crystal->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
- if (Creature* pSinclari = instance->GetCreature(uiSinclari))
+ if (Creature* sinclari = GetCreature(DATA_SINCLARI))
{
- pSinclari->SetVisible(true);
+ sinclari->SetVisible(true);
std::list<Creature*> GuardList;
- pSinclari->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f);
+ sinclari->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f);
if (!GuardList.empty())
{
- for (std::list<Creature*>::const_iterator itr = GuardList.begin(); itr != GuardList.end(); ++itr)
+ for (Creature* guard : GuardList)
{
- if (Creature* pGuard = *itr)
- {
- pGuard->SetVisible(true);
- pGuard->SetReactState(REACT_AGGRESSIVE);
- pGuard->GetMotionMaster()->MovePoint(1, pGuard->GetHomePosition());
- }
+ guard->SetVisible(true);
+ guard->SetReactState(REACT_AGGRESSIVE);
+ guard->GetMotionMaster()->MovePoint(1, guard->GetHomePosition());
}
}
- pSinclari->GetMotionMaster()->MovePoint(1, pSinclari->GetHomePosition());
- pSinclari->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ sinclari->GetMotionMaster()->MovePoint(1, sinclari->GetHomePosition());
+ sinclari->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
}
// Cyanigosa is spawned but not tranformed, prefight event
- Creature* pCyanigosa = instance->GetCreature(uiCyanigosa);
- if (pCyanigosa && !pCyanigosa->HasAura(CYANIGOSA_SPELL_TRANSFORM))
+ Creature* cyanigosa = GetCreature(DATA_CYANIGOSA);
+ if (cyanigosa && !cyanigosa->HasAura(CYANIGOSA_SPELL_TRANSFORM))
{
if (uiCyanigosaEventTimer <= diff)
{
switch (uiCyanigosaEventPhase)
{
case 1:
- pCyanigosa->CastSpell(pCyanigosa, CYANIGOSA_BLUE_AURA, false);
- pCyanigosa->AI()->Talk(CYANIGOSA_SAY_SPAWN);
+ cyanigosa->CastSpell(cyanigosa, CYANIGOSA_BLUE_AURA, false);
+ cyanigosa->AI()->Talk(CYANIGOSA_SAY_SPAWN);
uiCyanigosaEventTimer = 7*IN_MILLISECONDS;
++uiCyanigosaEventPhase;
break;
case 2:
- pCyanigosa->GetMotionMaster()->MoveJump(MiddleRoomLocation.GetPositionX(), MiddleRoomLocation.GetPositionY(), MiddleRoomLocation.GetPositionZ(), 10.0f, 20.0f);
- pCyanigosa->CastSpell(pCyanigosa, CYANIGOSA_BLUE_AURA, false);
+ cyanigosa->GetMotionMaster()->MoveJump(MiddleRoomLocation.GetPositionX(), MiddleRoomLocation.GetPositionY(), MiddleRoomLocation.GetPositionZ(), 10.0f, 20.0f);
+ cyanigosa->CastSpell(cyanigosa, CYANIGOSA_BLUE_AURA, false);
uiCyanigosaEventTimer = 7*IN_MILLISECONDS;
++uiCyanigosaEventPhase;
break;
case 3:
- pCyanigosa->RemoveAurasDueToSpell(CYANIGOSA_BLUE_AURA);
- pCyanigosa->CastSpell(pCyanigosa, CYANIGOSA_SPELL_TRANSFORM, 0);
- pCyanigosa->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
- pCyanigosa->SetReactState(REACT_AGGRESSIVE);
+ cyanigosa->RemoveAurasDueToSpell(CYANIGOSA_BLUE_AURA);
+ cyanigosa->CastSpell(cyanigosa, CYANIGOSA_SPELL_TRANSFORM, 0);
+ cyanigosa->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
+ cyanigosa->SetReactState(REACT_AGGRESSIVE);
uiCyanigosaEventTimer = 2*IN_MILLISECONDS;
++uiCyanigosaEventPhase;
break;
@@ -793,15 +658,17 @@ public:
trigger->CastSpell(trigger, spellInfoLightning, true, 0, 0, trigger->GetGUID());
// Kill all mobs registered with SetGuidData(ADD_TRASH_MOB)
- for (GuidSet::const_iterator itr = trashMobs.begin(); itr != trashMobs.end(); ++itr)
+ for (GuidSet::const_iterator itr = trashMobs.begin(); itr != trashMobs.end();)
{
Creature* creature = instance->GetCreature(*itr);
+ // Increment the iterator before killing the creature because the kill will remove itr from trashMobs
+ ++itr;
if (creature && creature->IsAlive())
trigger->Kill(creature);
}
}
- void ProcessEvent(WorldObject* /*go*/, uint32 uiEventId)
+ void ProcessEvent(WorldObject* /*go*/, uint32 uiEventId) override
{
switch (uiEventId)
{
@@ -812,6 +679,11 @@ public:
}
}
};
+
+ InstanceScript* GetInstanceScript(InstanceMap* map) const override
+ {
+ return new instance_violet_hold_InstanceMapScript(map);
+ }
};
void AddSC_instance_violet_hold()
diff --git a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp
index 645a9da4764..8bcc80b5a84 100644
--- a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp
+++ b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp
@@ -32,18 +32,18 @@
enum PortalCreatures
{
- CREATURE_AZURE_INVADER_1 = 30661,
- CREATURE_AZURE_INVADER_2 = 30961,
- CREATURE_AZURE_SPELLBREAKER_1 = 30662,
- CREATURE_AZURE_SPELLBREAKER_2 = 30962,
- CREATURE_AZURE_BINDER_1 = 30663,
- CREATURE_AZURE_BINDER_2 = 30918,
- CREATURE_AZURE_MAGE_SLAYER_1 = 30664,
- CREATURE_AZURE_MAGE_SLAYER_2 = 30963,
- CREATURE_AZURE_CAPTAIN = 30666,
- CREATURE_AZURE_SORCEROR = 30667,
- CREATURE_AZURE_RAIDER = 30668,
- CREATURE_AZURE_STALKER = 32191
+ NPC_AZURE_INVADER_1 = 30661,
+ NPC_AZURE_INVADER_2 = 30961,
+ NPC_AZURE_SPELLBREAKER_1 = 30662,
+ NPC_AZURE_SPELLBREAKER_2 = 30962,
+ NPC_AZURE_BINDER_1 = 30663,
+ NPC_AZURE_BINDER_2 = 30918,
+ NPC_AZURE_MAGE_SLAYER_1 = 30664,
+ NPC_AZURE_MAGE_SLAYER_2 = 30963,
+ NPC_AZURE_CAPTAIN = 30666,
+ NPC_AZURE_SORCEROR = 30667,
+ NPC_AZURE_RAIDER = 30668,
+ NPC_AZURE_STALKER = 32191
};
enum AzureInvaderSpells
@@ -258,7 +258,7 @@ public:
{
case GOSSIP_ACTION_INFO_DEF+1:
player->CLOSE_GOSSIP_MENU();
- ENSURE_AI(npc_sinclari_vh::npc_sinclariAI, (creature->AI()))->uiPhase = 1;
+ ENSURE_AI(npc_sinclari_vh::npc_sinclariAI, creature->AI())->uiPhase = 1;
if (InstanceScript* instance = creature->GetInstanceScript())
instance->SetData(DATA_MAIN_EVENT_PHASE, SPECIAL);
break;
@@ -296,17 +296,12 @@ public:
return true;
}
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_sinclariAI>(creature);
- }
-
struct npc_sinclariAI : public ScriptedAI
{
npc_sinclariAI(Creature* creature) : ScriptedAI(creature)
{
Initialize();
- instance = creature->GetInstanceScript();
+ instance = creature->GetInstanceScript();
}
void Initialize()
@@ -345,8 +340,6 @@ public:
void UpdateAI(uint32 uiDiff) override
{
- ScriptedAI::UpdateAI(uiDiff);
-
if (uiPhase)
{
if (uiTimer <= uiDiff)
@@ -415,6 +408,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_sinclariAI>(creature);
+ }
};
class npc_azure_saboteur : public CreatureScript
@@ -422,14 +419,9 @@ class npc_azure_saboteur : public CreatureScript
public:
npc_azure_saboteur() : CreatureScript("npc_azure_saboteur") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_azure_saboteurAI>(creature);
- }
-
struct npc_azure_saboteurAI : public npc_escortAI
{
- npc_azure_saboteurAI(Creature* creature):npc_escortAI(creature)
+ npc_azure_saboteurAI(Creature* creature) : npc_escortAI(creature)
{
instance = creature->GetInstanceScript();
bHasGotMovingPoints = false;
@@ -532,13 +524,16 @@ public:
{
me->CastSpell(me, SABOTEUR_SHIELD_DISRUPTION, false);
me->DisappearAndDie();
- Creature* pSaboPort = ObjectAccessor::GetCreature((*me), instance->GetGuidData(DATA_SABOTEUR_PORTAL));
- if (pSaboPort)
+ if (Creature* pSaboPort = ObjectAccessor::GetCreature((*me), instance->GetGuidData(DATA_SABOTEUR_PORTAL)))
pSaboPort->DisappearAndDie();
instance->SetData(DATA_START_BOSS_ENCOUNTER, 1);
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_azure_saboteurAI>(creature);
+ }
};
class npc_teleportation_portal_vh : public CreatureScript
@@ -546,11 +541,6 @@ class npc_teleportation_portal_vh : public CreatureScript
public:
npc_teleportation_portal_vh() : CreatureScript("npc_teleportation_portal_vh") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_teleportation_portalAI>(creature);
- }
-
struct npc_teleportation_portalAI : public ScriptedAI
{
npc_teleportation_portalAI(Creature* creature) : ScriptedAI(creature), listOfMobs(me)
@@ -583,7 +573,6 @@ public:
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
if (instance->GetData(DATA_REMOVE_NPC) == 1)
@@ -608,7 +597,7 @@ public:
uint8 k = uiWaveCount < 12 ? 2 : 3;
for (uint8 i = 0; i < k; ++i)
{
- uint32 entry = RAND(CREATURE_AZURE_CAPTAIN, CREATURE_AZURE_RAIDER, CREATURE_AZURE_STALKER, CREATURE_AZURE_SORCEROR);
+ uint32 entry = RAND(NPC_AZURE_CAPTAIN, NPC_AZURE_RAIDER, NPC_AZURE_STALKER, NPC_AZURE_SORCEROR);
DoSummon(entry, me, 2.0f, 20000, TEMPSUMMON_DEAD_DESPAWN);
}
me->SetVisible(false);
@@ -633,14 +622,14 @@ public:
uint8 k = instance->GetData(DATA_WAVE_COUNT) < 12 ? 3 : 4;
for (uint8 i = 0; i < k; ++i)
{
- uint32 entry = RAND(CREATURE_AZURE_INVADER_1, CREATURE_AZURE_INVADER_2, CREATURE_AZURE_SPELLBREAKER_1, CREATURE_AZURE_SPELLBREAKER_2, CREATURE_AZURE_MAGE_SLAYER_1, CREATURE_AZURE_MAGE_SLAYER_2, CREATURE_AZURE_BINDER_1, CREATURE_AZURE_BINDER_2);
+ uint32 entry = RAND(NPC_AZURE_INVADER_1, NPC_AZURE_INVADER_2, NPC_AZURE_SPELLBREAKER_1, NPC_AZURE_SPELLBREAKER_2, NPC_AZURE_MAGE_SLAYER_1, NPC_AZURE_MAGE_SLAYER_2, NPC_AZURE_BINDER_1, NPC_AZURE_BINDER_2);
DoSummon(entry, me, 2.0f, 20000, TEMPSUMMON_DEAD_DESPAWN);
}
}
else
{
bPortalGuardianOrKeeperOrEliteSpawn = true;
- uint32 entry = RAND(CREATURE_PORTAL_GUARDIAN, CREATURE_PORTAL_KEEPER);
+ uint32 entry = RAND(NPC_PORTAL_GUARDIAN, NPC_PORTAL_KEEPER);
if (Creature* pPortalKeeper = DoSummon(entry, me, 2.0f, 0, TEMPSUMMON_DEAD_DESPAWN))
me->CastSpell(pPortalKeeper, SPELL_PORTAL_CHANNEL, false);
}
@@ -674,11 +663,15 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_teleportation_portalAI>(creature);
+ }
};
struct violet_hold_trashAI : public npc_escortAI
{
- violet_hold_trashAI(Creature* creature):npc_escortAI(creature)
+ violet_hold_trashAI(Creature* creature) : npc_escortAI(creature)
{
instance = creature->GetInstanceScript();
bHasGotMovingPoints = false;
@@ -723,7 +716,7 @@ struct violet_hold_trashAI : public npc_escortAI
}
}
- void UpdateAI(uint32) override
+ void UpdateAI(uint32 diff) override
{
if (instance->GetData(DATA_MAIN_EVENT_PHASE) != IN_PROGRESS)
me->CastStop();
@@ -778,6 +771,8 @@ struct violet_hold_trashAI : public npc_escortAI
SetDespawnAtEnd(false);
Start(true, true);
}
+
+ npc_escortAI::UpdateAI(diff);
}
void JustDied(Unit* /*killer*/) override
@@ -791,7 +786,6 @@ struct violet_hold_trashAI : public npc_escortAI
DoCast(SPELL_DESTROY_DOOR_SEAL);
instance->SetData(DATA_NPC_PRESENCE_AT_DOOR_ADD, 1);
}
-
};
class npc_azure_invader : public CreatureScript
@@ -799,11 +793,6 @@ class npc_azure_invader : public CreatureScript
public:
npc_azure_invader() : CreatureScript("npc_azure_invader") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_azure_invaderAI>(creature);
- }
-
struct npc_azure_invaderAI : public violet_hold_trashAI
{
npc_azure_invaderAI(Creature* creature) : violet_hold_trashAI(creature)
@@ -833,12 +822,11 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
- if (me->GetEntry() == CREATURE_AZURE_INVADER_1)
+ if (me->GetEntry() == NPC_AZURE_INVADER_1)
{
if (uiCleaveTimer <= diff)
{
@@ -848,14 +836,13 @@ public:
if (uiImpaleTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_IMPALE);
uiImpaleTimer = 4000;
} else uiImpaleTimer -= diff;
}
- if (me->GetEntry() == CREATURE_AZURE_INVADER_2)
+ if (me->GetEntry() == NPC_AZURE_INVADER_2)
{
if (uiBrutalStrikeTimer <= diff)
{
@@ -876,6 +863,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_azure_invaderAI>(creature);
+ }
};
class npc_azure_binder : public CreatureScript
@@ -883,11 +874,6 @@ class npc_azure_binder : public CreatureScript
public:
npc_azure_binder() : CreatureScript("npc_azure_binder") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_azure_binderAI>(creature);
- }
-
struct npc_azure_binderAI : public violet_hold_trashAI
{
npc_azure_binderAI(Creature* creature) : violet_hold_trashAI(creature)
@@ -917,12 +903,11 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
- if (me->GetEntry() == CREATURE_AZURE_BINDER_1)
+ if (me->GetEntry() == NPC_AZURE_BINDER_1)
{
if (uiArcaneExplosionTimer <= diff)
{
@@ -930,16 +915,15 @@ public:
uiArcaneExplosionTimer = 5000;
} else uiArcaneExplosionTimer -= diff;
- if (uiArcainBarrageTimer <= diff)
+ if (uiArcainBarrageTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
- DoCast(target, SPELL_ARCANE_BARRAGE);
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
+ DoCast(target, SPELL_ARCANE_BARRAGE);
uiArcainBarrageTimer = 6000;
} else uiArcainBarrageTimer -= diff;
}
- if (me->GetEntry() == CREATURE_AZURE_BINDER_2)
+ if (me->GetEntry() == NPC_AZURE_BINDER_2)
{
if (uiFrostNovaTimer <= diff)
{
@@ -949,8 +933,7 @@ public:
if (uiFrostboltTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_FROSTBOLT);
uiFrostboltTimer = 6000;
} else uiFrostboltTimer -= diff;
@@ -960,6 +943,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_azure_binderAI>(creature);
+ }
};
class npc_azure_mage_slayer : public CreatureScript
@@ -967,11 +954,6 @@ class npc_azure_mage_slayer : public CreatureScript
public:
npc_azure_mage_slayer() : CreatureScript("npc_azure_mage_slayer") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_azure_mage_slayerAI>(creature);
- }
-
struct npc_azure_mage_slayerAI : public violet_hold_trashAI
{
npc_azure_mage_slayerAI(Creature* creature) : violet_hold_trashAI(creature)
@@ -997,12 +979,11 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
- if (me->GetEntry() == CREATURE_AZURE_MAGE_SLAYER_1)
+ if (me->GetEntry() == NPC_AZURE_MAGE_SLAYER_1)
{
if (uiArcaneEmpowermentTimer <= diff)
{
@@ -1011,12 +992,11 @@ public:
} else uiArcaneEmpowermentTimer -= diff;
}
- if (me->GetEntry() == CREATURE_AZURE_MAGE_SLAYER_2)
+ if (me->GetEntry() == NPC_AZURE_MAGE_SLAYER_2)
{
if (uiSpellLockTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_SPELL_LOCK);
uiSpellLockTimer = 9000;
} else uiSpellLockTimer -= diff;
@@ -1026,6 +1006,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_azure_mage_slayerAI>(creature);
+ }
};
class npc_azure_raider : public CreatureScript
@@ -1033,11 +1017,6 @@ class npc_azure_raider : public CreatureScript
public:
npc_azure_raider() : CreatureScript("npc_azure_raider") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_azure_raiderAI>(creature);
- }
-
struct npc_azure_raiderAI : public violet_hold_trashAI
{
npc_azure_raiderAI(Creature* creature) : violet_hold_trashAI(creature)
@@ -1063,7 +1042,6 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
@@ -1084,6 +1062,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_azure_raiderAI>(creature);
+ }
};
class npc_azure_stalker : public CreatureScript
@@ -1114,7 +1096,6 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
@@ -1123,8 +1104,7 @@ public:
{
if (_tacticalBlinkTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40, true))
DoCast(target, SPELL_TACTICAL_BLINK);
_tacticalBlinkTimer = 6000;
_tacticalBlinkCast = true;
@@ -1135,8 +1115,8 @@ public:
{
if (_backstabTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_NEAREST, 0, 10, true);
- DoCast(target, SPELL_BACKSTAB);
+ if (Unit* target = SelectTarget(SELECT_TARGET_NEAREST, 0, 10, true))
+ DoCast(target, SPELL_BACKSTAB);
_tacticalBlinkCast = false;
_backstabTimer =1300;
} else _backstabTimer -= diff;
@@ -1191,36 +1171,32 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
- if (me->GetEntry() == CREATURE_AZURE_SPELLBREAKER_1)
+ if (me->GetEntry() == NPC_AZURE_SPELLBREAKER_1)
{
if (uiArcaneBlastTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_ARCANE_BLAST);
uiArcaneBlastTimer = 6000;
} else uiArcaneBlastTimer -= diff;
if (uiSlowTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_SLOW);
uiSlowTimer = 5000;
} else uiSlowTimer -= diff;
}
- if (me->GetEntry() == CREATURE_AZURE_SPELLBREAKER_2)
+ if (me->GetEntry() == NPC_AZURE_SPELLBREAKER_2)
{
if (uiChainsOfIceTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_CHAINS_OF_ICE);
uiChainsOfIceTimer = 7000;
} else uiChainsOfIceTimer -= diff;
@@ -1247,11 +1223,6 @@ class npc_azure_captain : public CreatureScript
public:
npc_azure_captain() : CreatureScript("npc_azure_captain") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_azure_captainAI>(creature);
- }
-
struct npc_azure_captainAI : public violet_hold_trashAI
{
npc_azure_captainAI(Creature* creature) : violet_hold_trashAI(creature)
@@ -1277,7 +1248,6 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
@@ -1298,6 +1268,10 @@ public:
}
};
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_azure_captainAI>(creature);
+ }
};
class npc_azure_sorceror : public CreatureScript
@@ -1305,11 +1279,6 @@ class npc_azure_sorceror : public CreatureScript
public:
npc_azure_sorceror() : CreatureScript("npc_azure_sorceror") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_azure_sorcerorAI>(creature);
- }
-
struct npc_azure_sorcerorAI : public violet_hold_trashAI
{
npc_azure_sorcerorAI(Creature* creature) : violet_hold_trashAI(creature)
@@ -1337,15 +1306,13 @@ public:
void UpdateAI(uint32 diff) override
{
violet_hold_trashAI::UpdateAI(diff);
- npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
if (uiArcaneStreamTimer <= diff)
{
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
- if (target)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_ARCANE_STREAM);
uiArcaneStreamTimer = urand(0, 5000)+5000;
uiArcaneStreamTimerStartingValueHolder = uiArcaneStreamTimer;
@@ -1360,6 +1327,11 @@ public:
DoMeleeAttackIfReady();
}
};
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_azure_sorcerorAI>(creature);
+ }
};
diff --git a/src/server/scripts/Northrend/VioletHold/violet_hold.h b/src/server/scripts/Northrend/VioletHold/violet_hold.h
index 404d1f493e6..275a7467d83 100644
--- a/src/server/scripts/Northrend/VioletHold/violet_hold.h
+++ b/src/server/scripts/Northrend/VioletHold/violet_hold.h
@@ -18,13 +18,18 @@
#ifndef DEF_VIOLET_HOLD_H
#define DEF_VIOLET_HOLD_H
-#define DataHeader "VIO"
+#define DataHeader "VH"
+
+uint32 const EncounterCount = 3;
enum Data
{
+ // Main encounters
DATA_1ST_BOSS_EVENT,
DATA_2ND_BOSS_EVENT,
- DATA_CYANIGOSA_EVENT,
+ DATA_CYANIGOSA,
+
+ // Misc
DATA_WAVE_COUNT,
DATA_REMOVE_NPC,
DATA_PORTAL_LOCATION,
@@ -38,10 +43,8 @@ enum Data
DATA_ACTIVATE_CRYSTAL,
DATA_MAIN_EVENT_PHASE,
DATA_DEFENSELESS,
-};
-enum Data64
-{
+ // Bosses
DATA_MORAGG,
DATA_EREKEM,
DATA_EREKEM_GUARD_1,
@@ -50,7 +53,8 @@ enum Data64
DATA_LAVANTHOR,
DATA_XEVOZZ,
DATA_ZURAMAT,
- DATA_CYANIGOSA,
+
+ // Cells
DATA_MORAGG_CELL,
DATA_EREKEM_CELL,
DATA_EREKEM_LEFT_GUARD_CELL,
@@ -59,6 +63,8 @@ enum Data64
DATA_LAVANTHOR_CELL,
DATA_XEVOZZ_CELL,
DATA_ZURAMAT_CELL,
+
+ // Misc
DATA_MAIN_DOOR,
DATA_SINCLARI,
DATA_TELEPORTATION_PORTAL,
@@ -81,33 +87,48 @@ enum Bosses
enum CreaturesIds
{
- CREATURE_TELEPORTATION_PORTAL = 31011,
- CREATURE_PORTAL_GUARDIAN = 30660,
- CREATURE_PORTAL_KEEPER = 30695,
- CREATURE_XEVOZZ = 29266,
- CREATURE_LAVANTHOR = 29312,
- CREATURE_ICHORON = 29313,
- CREATURE_ZURAMAT = 29314,
- CREATURE_EREKEM = 29315,
- CREATURE_EREKEM_GUARD = 29395,
- CREATURE_MORAGG = 29316,
- CREATURE_CYANIGOSA = 31134,
- CREATURE_SINCLARI = 30658,
- CREATURE_SABOTEOUR = 31079,
- NPC_VIOLET_HOLD_GUARD = 30659,
- NPC_DEFENSE_SYSTEM = 30837
+ NPC_TELEPORTATION_PORTAL = 31011,
+ NPC_PORTAL_GUARDIAN = 30660,
+ NPC_PORTAL_KEEPER = 30695,
+ NPC_XEVOZZ = 29266,
+ NPC_LAVANTHOR = 29312,
+ NPC_ICHORON = 29313,
+ NPC_ZURAMAT = 29314,
+ NPC_EREKEM = 29315,
+ NPC_EREKEM_GUARD = 29395,
+ NPC_MORAGG = 29316,
+ NPC_CYANIGOSA = 31134,
+ NPC_SINCLARI = 30658,
+ NPC_SABOTEOUR = 31079,
+ NPC_VIOLET_HOLD_GUARD = 30659,
+ NPC_DEFENSE_SYSTEM = 30837
+};
+
+enum GameObjectIds
+{
+ GO_MAIN_DOOR = 191723,
+ GO_XEVOZZ_DOOR = 191556,
+ GO_LAVANTHOR_DOOR = 191566,
+ GO_ICHORON_DOOR = 191722,
+ GO_ZURAMAT_DOOR = 191565,
+ GO_EREKEM_DOOR = 191564,
+ GO_EREKEM_GUARD_1_DOOR = 191563,
+ GO_EREKEM_GUARD_2_DOOR = 191562,
+ GO_MORAGG_DOOR = 191606,
+ GO_INTRO_ACTIVATION_CRYSTAL = 193615,
+ GO_ACTIVATION_CRYSTAL = 193611
};
enum WorldStateIds
{
- WORLD_STATE_VH = 3816,
- WORLD_STATE_VH_PRISON_STATE = 3815,
- WORLD_STATE_VH_WAVE_COUNT = 3810,
+ WORLD_STATE_VH = 3816,
+ WORLD_STATE_VH_PRISON_STATE = 3815,
+ WORLD_STATE_VH_WAVE_COUNT = 3810,
};
enum Events
{
- EVENT_ACTIVATE_CRYSTAL = 20001
+ EVENT_ACTIVATE_CRYSTAL = 20001
};
#endif
diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp
index 9b341180c99..280a94aa21f 100644
--- a/src/server/scripts/Northrend/zone_borean_tundra.cpp
+++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp
@@ -395,6 +395,9 @@ enum NesingwaryTrapper
GO_CARIBOU_TRAP_15 = 188008,
SPELL_TRAPPED = 46104,
+
+ // Texts
+ SAY_NESINGWARY_1 = 0
};
#define CaribouTrapsNum 15
@@ -471,7 +474,7 @@ public:
phase = 3;
break;
case 3:
- //Talk(SAY_NESINGWARY_1);
+ Talk(SAY_NESINGWARY_1);
phaseTimer = 2000;
phase = 4;
break;
@@ -1703,7 +1706,7 @@ public:
break;
}
creature->SetStandState(UNIT_STAND_STATE_STAND);
- creature->AI()->Talk(SAY_1);
+ creature->AI()->Talk(SAY_1, player);
ENSURE_AI(npc_escortAI, (creature->AI()))->Start(true, false, player->GetGUID());
}
return true;
diff --git a/src/server/scripts/Northrend/zone_dragonblight.cpp b/src/server/scripts/Northrend/zone_dragonblight.cpp
index b7efa7c3d3e..dc5b75d425d 100644
--- a/src/server/scripts/Northrend/zone_dragonblight.cpp
+++ b/src/server/scripts/Northrend/zone_dragonblight.cpp
@@ -174,7 +174,7 @@ class npc_commander_eligor_dawnbringer : public CreatureScript
{
if (id == 1)
{
- me->SetFacingTo(PosTalkLocations[talkWing].m_orientation);
+ me->SetFacingTo(PosTalkLocations[talkWing].GetOrientation());
TurnAudience();
switch (talkWing)
diff --git a/src/server/scripts/Northrend/zone_grizzly_hills.cpp b/src/server/scripts/Northrend/zone_grizzly_hills.cpp
index dad71ab0c24..83fd3859716 100644
--- a/src/server/scripts/Northrend/zone_grizzly_hills.cpp
+++ b/src/server/scripts/Northrend/zone_grizzly_hills.cpp
@@ -816,6 +816,44 @@ class spell_shredder_delivery : public SpellScriptLoader
}
};
+enum InfectedWorgenBite
+{
+ SPELL_INFECTED_WORGEN_BITE = 53094,
+ SPELL_WORGENS_CALL = 53095
+};
+
+class spell_infected_worgen_bite : public SpellScriptLoader
+{
+ public:
+ spell_infected_worgen_bite() : SpellScriptLoader("spell_infected_worgen_bite") { }
+
+ class spell_infected_worgen_bite_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_infected_worgen_bite_AuraScript);
+
+ void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ if (GetStackAmount() == GetSpellInfo()->StackAmount)
+ {
+ Remove();
+ target->CastSpell(target, SPELL_WORGENS_CALL, true);
+ }
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_infected_worgen_bite_AuraScript::HandleAfterEffectApply, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAPPLY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_infected_worgen_bite_AuraScript();
+ }
+};
+
void AddSC_grizzly_hills()
{
new npc_emily();
@@ -827,4 +865,5 @@ void AddSC_grizzly_hills()
new npc_venture_co_straggler();
new npc_lake_frog();
new spell_shredder_delivery();
+ new spell_infected_worgen_bite();
}
diff --git a/src/server/scripts/Northrend/zone_icecrown.cpp b/src/server/scripts/Northrend/zone_icecrown.cpp
index 7f29a6621bd..2e426fd77cf 100644
--- a/src/server/scripts/Northrend/zone_icecrown.cpp
+++ b/src/server/scripts/Northrend/zone_icecrown.cpp
@@ -25,53 +25,6 @@
#include "CombatAI.h"
/*######
-## npc_squire_david
-######*/
-
-enum SquireDavid
-{
- QUEST_THE_ASPIRANT_S_CHALLENGE_H = 13680,
- QUEST_THE_ASPIRANT_S_CHALLENGE_A = 13679,
-
- NPC_ARGENT_VALIANT = 33448,
-
- GOSSIP_TEXTID_SQUIRE = 14407
-};
-
-#define GOSSIP_SQUIRE_ITEM_1 "I am ready to fight!"
-#define GOSSIP_SQUIRE_ITEM_2 "How do the Argent Crusader raiders fight?"
-
-class npc_squire_david : public CreatureScript
-{
-public:
- npc_squire_david() : CreatureScript("npc_squire_david") { }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (player->GetQuestStatus(QUEST_THE_ASPIRANT_S_CHALLENGE_H) == QUEST_STATUS_INCOMPLETE ||
- player->GetQuestStatus(QUEST_THE_ASPIRANT_S_CHALLENGE_A) == QUEST_STATUS_INCOMPLETE)//We need more info about it.
- {
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SQUIRE_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SQUIRE_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2);
- }
-
- player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_SQUIRE, creature->GetGUID());
- return true;
- }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- if (action == GOSSIP_ACTION_INFO_DEF+1)
- {
- player->CLOSE_GOSSIP_MENU();
- creature->SummonCreature(NPC_ARGENT_VALIANT, 8575.451f, 952.472f, 547.554f, 0.38f);
- }
- return true;
- }
-};
-
-/*######
## npc_argent_valiant
######*/
@@ -837,7 +790,6 @@ class npc_frostbrood_skytalon : public CreatureScript
void AddSC_icecrown()
{
- new npc_squire_david;
new npc_argent_valiant;
new npc_guardian_pavilion;
new npc_tournament_training_dummy;
diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp
index bfdea4a1435..d5d9f8ae77e 100644
--- a/src/server/scripts/Northrend/zone_storm_peaks.cpp
+++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp
@@ -19,6 +19,7 @@
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
#include "ScriptedEscortAI.h"
+#include "SpellHistory.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
#include "Vehicle.h"
@@ -641,97 +642,6 @@ enum JokkumScriptcast
EVENT_KROLMIR_9 = 24,
};
-class npc_king_jokkum_vehicle : public CreatureScript
-{
-public:
- npc_king_jokkum_vehicle() : CreatureScript("npc_king_jokkum_vehicle") { }
-
- struct npc_king_jokkum_vehicleAI : public VehicleAI
- {
- npc_king_jokkum_vehicleAI(Creature* creature) : VehicleAI(creature)
- {
- pathEnd = false;
- }
-
- void Reset() override
- {
- playerGUID.Clear();
- pathEnd = false;
- }
-
- void OnCharmed(bool /*apply*/) override { }
-
- void PassengerBoarded(Unit* who, int8 /*seat*/, bool apply) override
- {
- if (apply)
- {
- playerGUID = who->GetGUID();
- Talk(SAY_HOLD_ON, who);
- me->CastSpell(who, SPELL_JOKKUM_KILL_CREDIT, true);
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
- me->GetMotionMaster()->MovePath(PATH_JOKKUM, false);
- }
- }
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type != WAYPOINT_MOTION_TYPE)
- return;
-
- if (pathEnd)
- {
- if (id == 4)
- {
-
- }
- }
- else
- {
- if (id == 19)
- {
- pathEnd = true;
- me->SetFacingTo(0.418879f);
- Talk(SAY_JOKKUM_1);
- if (Player* player = ObjectAccessor::GetPlayer(*me, playerGUID))
- me->CastSpell(player, SPELL_PLAYER_CAST_VERANUS_SUMMON);
- me->CastSpell(me, SPELL_EJECT_ALL_PASSENGERS);
-
- }
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!pathEnd)
- return;
-
- events.Update(diff);
-
- while (uint32 eventId = events.ExecuteEvent())
- {
- switch (eventId)
- {
- case EVENT_KROLMIR_1:
- Talk(SAY_JOKKUM_2);
- events.ScheduleEvent(EVENT_KROLMIR_2, 4000);
- break;
- }
- }
- }
-
- private:
- EventMap events;
- ObjectGuid playerGUID;
- bool pathEnd;
-
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_king_jokkum_vehicleAI(creature);
- }
-};
-
class spell_jokkum_scriptcast : public SpellScriptLoader
{
public: spell_jokkum_scriptcast() : SpellScriptLoader("spell_jokkum_scriptcast") { }
@@ -855,7 +765,6 @@ void AddSC_storm_peaks()
new npc_icefang();
new npc_hyldsmeet_protodrake();
new npc_brann_bronzebeard_keystone();
- new npc_king_jokkum_vehicle();
new spell_jokkum_scriptcast();
new spell_veranus_summon();
new spell_close_rift();
diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h
index 80c8041bc6d..fac9d8fa357 100644
--- a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h
+++ b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h
@@ -261,13 +261,13 @@ class OPvPCapturePointNA : public OPvPCapturePoint
public:
OPvPCapturePointNA(OutdoorPvP* pvp);
- bool Update(uint32 diff);
+ bool Update(uint32 diff) override;
- void ChangeState();
+ void ChangeState() override;
- void FillInitialWorldStates(WorldPacket & data);
+ void FillInitialWorldStates(WorldPacket & data) override;
- bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go);
+ bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go) override;
int32 HandleOpenGo(Player* player, ObjectGuid guid) override;
diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h b/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h
index a08e141294d..9c76b35937e 100644
--- a/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h
+++ b/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h
@@ -184,9 +184,9 @@ class OPvPCapturePointZM_GraveYard : public OPvPCapturePoint
public:
OPvPCapturePointZM_GraveYard(OutdoorPvP* pvp);
- bool Update(uint32 diff);
+ bool Update(uint32 diff) override;
- void ChangeState() { }
+ void ChangeState() override { }
void FillInitialWorldStates(WorldPacket & data);
@@ -196,11 +196,11 @@ class OPvPCapturePointZM_GraveYard : public OPvPCapturePoint
void SetBeaconState(uint32 controlling_team); // not good atm
- bool HandleGossipOption(Player* player, ObjectGuid guid, uint32 gossipid);
+ bool HandleGossipOption(Player* player, ObjectGuid guid, uint32 gossipid) override;
- bool HandleDropFlag(Player* player, uint32 spellId);
+ bool HandleDropFlag(Player* player, uint32 spellId) override;
- bool CanTalkTo(Player* player, Creature* creature, GossipMenuItems const& gso);
+ bool CanTalkTo(Player* player, Creature* creature, GossipMenuItems const& gso) override;
uint32 GetGraveYardState() const;
diff --git a/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp b/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp
index 662bad46162..263fd8340b9 100644
--- a/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp
+++ b/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp
@@ -113,7 +113,7 @@ public:
Map::PlayerList const &PlayerList = map->GetPlayers();
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
if (Player* i_pl = i->GetSource())
- if (i_pl->IsAlive() && (dist = i_pl->IsWithinDist(me, 45)))
+ if (i_pl->IsAlive() && (dist = i_pl->GetDistance(me)) < 45)
{
i_pl->RemoveAurasDueToSpell(SPELL_INHIBITMAGIC);
me->AddAura(SPELL_INHIBITMAGIC, i_pl);
diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_ambassador_hellmaw.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_ambassador_hellmaw.cpp
index 2b5ad18022a..9667b4e3bb0 100644
--- a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_ambassador_hellmaw.cpp
+++ b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_ambassador_hellmaw.cpp
@@ -93,7 +93,7 @@ class boss_ambassador_hellmaw : public CreatureScript
{
}
- void DoAction(int32 actionId)
+ void DoAction(int32 actionId) override
{
if (actionId == ACTION_AMBASSADOR_HELLMAW_INTRO)
DoIntro();
diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/instance_shadow_labyrinth.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/instance_shadow_labyrinth.cpp
index 9d2737c8ba5..f984272f4d5 100644
--- a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/instance_shadow_labyrinth.cpp
+++ b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/instance_shadow_labyrinth.cpp
@@ -92,7 +92,7 @@ class instance_shadow_labyrinth : public InstanceMapScript
}
}
- void OnUnitDeath(Unit* unit)
+ void OnUnitDeath(Unit* unit) override
{
Creature* creature = unit->ToCreature();
if (!creature)
diff --git a/src/server/scripts/Outland/CMakeLists.txt b/src/server/scripts/Outland/CMakeLists.txt
index 24658dbc21f..42621b76941 100644
--- a/src/server/scripts/Outland/CMakeLists.txt
+++ b/src/server/scripts/Outland/CMakeLists.txt
@@ -27,6 +27,7 @@ set(scripts_STAT_SRCS
Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp
Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp
+ Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp
Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp
Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp
Outland/CoilfangReservoir/SteamVault/boss_mekgineer_steamrigger.cpp
diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp
index 2750476db76..096777163a6 100644
--- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp
+++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp
@@ -280,7 +280,7 @@ public:
Map::PlayerList const &PlayerList = map->GetPlayers();
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
{
- if (i->GetSource() && i->GetSource()->IsAlive() && me->HasInArc(float(diff/20000*M_PI*2), i->GetSource()) && me->IsWithinDist(i->GetSource(), SPOUT_DIST) && !i->GetSource()->IsInWater())
+ if (i->GetSource() && i->GetSource()->IsAlive() && me->HasInArc(diff/20000.f*float(M_PI)*2.f, i->GetSource()) && me->IsWithinDist(i->GetSource(), SPOUT_DIST) && !i->GetSource()->IsInWater())
DoCast(i->GetSource(), SPELL_SPOUT, true); // only knock back players in arc, in 100yards, not in water
}
}
diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp
index 1657b178327..d7ba0a34939 100644
--- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp
+++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp
@@ -275,8 +275,8 @@ class instance_serpent_shrine : public InstanceMapScript
if (data == DONE)
{
HandleGameObject(BridgePart[0], true);
- HandleGameObject(BridgePart[0], true);
- HandleGameObject(BridgePart[0], true);
+ HandleGameObject(BridgePart[1], true);
+ HandleGameObject(BridgePart[2], true);
}
break;
case DATA_TRASH:
diff --git a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/instance_steam_vault.cpp b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/instance_steam_vault.cpp
index 30444caa496..4cc522c7523 100644
--- a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/instance_steam_vault.cpp
+++ b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/instance_steam_vault.cpp
@@ -43,7 +43,7 @@ class go_main_chambers_access_panel : public GameObjectScript
}
};
-ObjectData const gameObjectData[] =
+ObjectData const gameObjectData[] =
{
{ GO_ACCESS_PANEL_HYDRO, DATA_ACCESS_PANEL_HYDRO },
{ GO_ACCESS_PANEL_MEK, DATA_ACCESS_PANEL_MEK },
diff --git a/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp b/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp
index 374ce3cd957..88dbeff09f5 100644
--- a/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp
+++ b/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp
@@ -123,7 +123,7 @@ public:
instance->SetBossState(DATA_MAULGAR, DONE);
}
- void DoAction(int32 actionId)
+ void DoAction(int32 actionId) override
{
if (actionId == ACTION_ADD_DEATH)
Talk(SAY_OGRE_DEATH);
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp
index fb44a403d86..dfc5f5992a6 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp
@@ -108,6 +108,7 @@ class boss_grand_warlock_nethekurse : public CreatureScript
void Reset() override
{
+ _Reset();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
Initialize();
@@ -115,9 +116,8 @@ class boss_grand_warlock_nethekurse : public CreatureScript
void JustDied(Unit* /*killer*/) override
{
+ _JustDied();
Talk(SAY_DIE);
-
- instance->SetBossState(DATA_NETHEKURSE, DONE);
}
void SetData(uint32 data, uint32 value) override
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp
index 0d7fe11956b..a950882eddd 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp
@@ -160,6 +160,7 @@ class boss_warbringer_omrogg : public CreatureScript
void Reset() override
{
+ _Reset();
if (Unit* LeftHead = ObjectAccessor::GetUnit(*me, LeftHeadGUID))
{
LeftHead->setDeathState(JUST_DIED);
@@ -257,14 +258,14 @@ class boss_warbringer_omrogg : public CreatureScript
Creature* LeftHead = ObjectAccessor::GetCreature(*me, LeftHeadGUID);
Creature* RightHead = ObjectAccessor::GetCreature(*me, RightHeadGUID);
+ _JustDied();
+
if (!LeftHead || !RightHead)
return;
LeftHead->AI()->Talk(YELL_DIE_L);
RightHead->AI()->SetData(SETDATA_DATA, SETDATA_YELL);
-
- instance->SetBossState(DATA_OMROGG, DONE);
}
void UpdateAI(uint32 diff) override
@@ -416,7 +417,7 @@ class npc_omrogg_heads : public CreatureScript
void EnterCombat(Unit* /*who*/) override { }
- void SetData(uint32 data, uint32 value)
+ void SetData(uint32 data, uint32 value) override
{
if (data == SETDATA_DATA && value == SETDATA_YELL)
{
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp
index b44ae46c78c..7f2e08b39ca 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp
@@ -35,7 +35,10 @@ enum Says
{
SAY_AGGRO = 0,
SAY_SLAY = 1,
- SAY_DEATH = 2
+ SAY_DEATH = 2,
+
+ SAY_CALL_EXECUTIONER_A = 3,
+ SAY_CALL_EXECUTIONER_H = 4
};
enum Spells
@@ -84,10 +87,28 @@ class boss_warchief_kargath_bladefist : public CreatureScript
resetcheck_timer = 5000;
}
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_EXECUTIONER_TAUNT)
+ {
+ switch (instance->GetData(DATA_TEAM_IN_INSTANCE))
+ {
+ case ALLIANCE:
+ Talk(SAY_CALL_EXECUTIONER_A);
+ break;
+ case HORDE:
+ Talk(SAY_CALL_EXECUTIONER_H);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
void Reset() override
{
removeAdds();
-
+ _Reset();
me->SetSpeed(MOVE_RUN, 2);
me->SetWalk(false);
@@ -96,10 +117,9 @@ class boss_warchief_kargath_bladefist : public CreatureScript
void JustDied(Unit* /*killer*/) override
{
+ _JustDied();
Talk(SAY_DEATH);
removeAdds();
-
- instance->SetBossState(DATA_KARGATH, DONE);
}
void EnterCombat(Unit* /*who*/) override
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp
index c6b08bdada1..5cfae286f9b 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp
@@ -24,9 +24,21 @@ SDCategory: Hellfire Citadel, Shattered Halls
EndScriptData */
#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "SpellAuraEffects.h"
#include "InstanceScript.h"
+#include "Player.h"
+#include "SpellAuras.h"
#include "shattered_halls.h"
+DoorData const doorData[] =
+{
+ { GO_GRAND_WARLOCK_CHAMBER_DOOR_1, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
+ { GO_GRAND_WARLOCK_CHAMBER_DOOR_2, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
+ { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE }
+};
+
class instance_shattered_halls : public InstanceMapScript
{
public:
@@ -43,6 +55,41 @@ class instance_shattered_halls : public InstanceMapScript
{
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
+ LoadDoorData(doorData);
+ executionTimer = 0;
+ executed = 0;
+ _team = 0;
+ }
+
+ void OnPlayerEnter(Player* player) override
+ {
+ Aura* ex = nullptr;
+
+ if (!_team)
+ _team = player->GetTeam();
+
+ player->CastSpell(player, SPELL_REMOVE_KARGATH_EXECUTIONER, true);
+
+ if (!executionTimer || executionerGUID.IsEmpty())
+ return;
+
+ switch (executed)
+ {
+ case 0:
+ ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_1, player);
+ break;
+ case 1:
+ ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_2, player);
+ break;
+ case 2:
+ ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_3, player);
+ break;
+ default:
+ break;
+ }
+
+ if (ex)
+ ex->SetDuration(executionTimer);
}
void OnGameObjectCreate(GameObject* go) override
@@ -50,21 +97,65 @@ class instance_shattered_halls : public InstanceMapScript
switch (go->GetEntry())
{
case GO_GRAND_WARLOCK_CHAMBER_DOOR_1:
- nethekurseDoor1GUID = go->GetGUID();
+ case GO_GRAND_WARLOCK_CHAMBER_DOOR_2:
+ AddDoor(go, true);
+ default:
break;
+ }
+ }
+
+ void OnGameObjectRemove(GameObject* go) override
+ {
+ switch (go->GetEntry())
+ {
+ case GO_GRAND_WARLOCK_CHAMBER_DOOR_1:
case GO_GRAND_WARLOCK_CHAMBER_DOOR_2:
- nethekurseDoor2GUID = go->GetGUID();
+ AddDoor(go, false);
+ default:
break;
}
}
void OnCreatureCreate(Creature* creature) override
{
+ if (!_team)
+ {
+ Map::PlayerList const &players = instance->GetPlayers();
+ if (!players.isEmpty())
+ if (Player* player = players.begin()->GetSource())
+ _team = player->GetTeam();
+ }
+
switch (creature->GetEntry())
{
case NPC_GRAND_WARLOCK_NETHEKURSE:
nethekurseGUID = creature->GetGUID();
break;
+ case NPC_KARGATH_BLADEFIST:
+ kargathGUID = creature->GetGUID();
+ break;
+ case NPC_RANDY_WHIZZLESPROCKET:
+ if (_team == HORDE)
+ creature->UpdateEntry(NPC_DRISELLA);
+ break;
+ case NPC_SHATTERED_EXECUTIONER:
+ executionTimer = 55 * MINUTE * IN_MILLISECONDS;
+ DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_1);
+ executionerGUID = creature->GetGUID();
+ SaveToDB();
+ break;
+ case NPC_CAPTAIN_ALINA:
+ case NPC_CAPTAIN_BONESHATTER:
+ victimsGUID[0] = creature->GetGUID();
+ break;
+ case NPC_ALLIANCE_VICTIM_1:
+ case NPC_HORDE_VICTIM_1:
+ victimsGUID[1] = creature->GetGUID();
+ break;
+ case NPC_ALLIANCE_VICTIM_2:
+ case NPC_HORDE_VICTIM_2:
+ victimsGUID[2] = creature->GetGUID();
+ break;
}
}
@@ -75,18 +166,18 @@ class instance_shattered_halls : public InstanceMapScript
switch (type)
{
- case DATA_NETHEKURSE:
- if (state == IN_PROGRESS)
- {
- HandleGameObject(nethekurseDoor1GUID, false);
- HandleGameObject(nethekurseDoor2GUID, false);
- }
- else
+ case DATA_SHATTERED_EXECUTIONER:
+ if (state == DONE)
{
- HandleGameObject(nethekurseDoor1GUID, true);
- HandleGameObject(nethekurseDoor2GUID, true);
+ DoCastSpellOnPlayers(SPELL_REMOVE_KARGATH_EXECUTIONER);
+ executionTimer = 0;
+ SaveToDB();
}
break;
+ case DATA_KARGATH:
+ if (Creature* executioner = instance->GetCreature(executionerGUID))
+ executioner->AI()->Reset(); // trigger removal of IMMUNE_TO_PC flag
+ break;
case DATA_OMROGG:
break;
}
@@ -99,21 +190,116 @@ class instance_shattered_halls : public InstanceMapScript
{
case NPC_GRAND_WARLOCK_NETHEKURSE:
return nethekurseGUID;
- break;
- case GO_GRAND_WARLOCK_CHAMBER_DOOR_1:
- return nethekurseDoor1GUID;
- break;
- case GO_GRAND_WARLOCK_CHAMBER_DOOR_2:
- return nethekurseDoor2GUID;
- break;
+ case NPC_KARGATH_BLADEFIST:
+ return kargathGUID;
+ case NPC_SHATTERED_EXECUTIONER:
+ return executionerGUID;
+ case DATA_FIRST_PRISONER:
+ case DATA_SECOND_PRISONER:
+ case DATA_THIRD_PRISONER:
+ return victimsGUID[data - DATA_FIRST_PRISONER];
+ default:
+ return ObjectGuid::Empty;
+ }
+ }
+
+ void WriteSaveDataMore(std::ostringstream& data) override
+ {
+ if (!instance->IsHeroic())
+ return;
+
+ data << uint32(executed) << ' '
+ << executionTimer << ' ';
+ }
+
+ void ReadSaveDataMore(std::istringstream& data) override
+ {
+ if (!instance->IsHeroic())
+ return;
+
+ uint32 readbuff;
+ data >> readbuff;
+ executed = uint8(readbuff);
+ data >> readbuff;
+
+ if (executed > VictimCount)
+ {
+ executed = VictimCount;
+ executionTimer = 0;
+ return;
+ }
+
+ if (!readbuff)
+ return;
+
+ Creature* executioner = nullptr;
+
+ instance->LoadGrid(Executioner.GetPositionX(), Executioner.GetPositionY());
+ if (Creature* kargath = instance->GetCreature(kargathGUID))
+ if (executionerGUID.IsEmpty())
+ executioner = kargath->SummonCreature(NPC_SHATTERED_EXECUTIONER, Executioner);
+
+ if (executioner)
+ for (uint8 i = executed; i < VictimCount; ++i)
+ executioner->SummonCreature(executionerVictims[i](GetData(DATA_TEAM_IN_INSTANCE)), executionerVictims[i].GetPos());
+
+ executionTimer = readbuff;
+ }
+
+ uint32 GetData(uint32 type) const override
+ {
+ switch (type)
+ {
+ case DATA_PRISONERS_EXECUTED:
+ return executed;
+ case DATA_TEAM_IN_INSTANCE:
+ return _team;
+ default:
+ return 0;
}
- return ObjectGuid::Empty;
}
- protected:
+ void Update(uint32 diff) override
+ {
+ if (!executionTimer)
+ return;
+
+ if (executionTimer <= diff)
+ {
+ DoCastSpellOnPlayers(SPELL_REMOVE_KARGATH_EXECUTIONER);
+ switch (++executed)
+ {
+ case 1:
+ DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_2);
+ executionTimer = 10 * MINUTE * IN_MILLISECONDS;
+ break;
+ case 2:
+ DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_3);
+ executionTimer = 15 * MINUTE * IN_MILLISECONDS;
+ break;
+ default:
+ executionTimer = 0;
+ break;
+ }
+
+ if (Creature* executioner = instance->GetCreature(executionerGUID))
+ executioner->AI()->SetData(DATA_PRISONERS_EXECUTED, executed);
+
+ SaveToDB();
+ }
+ else
+ executionTimer -= diff;
+ }
+
+ private:
ObjectGuid nethekurseGUID;
- ObjectGuid nethekurseDoor1GUID;
- ObjectGuid nethekurseDoor2GUID;
+ ObjectGuid kargathGUID;
+ ObjectGuid executionerGUID;
+ ObjectGuid victimsGUID[3];
+
+ uint8 executed;
+ uint32 executionTimer;
+ uint32 _team;
};
};
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp
new file mode 100644
index 00000000000..500b0ae4bcb
--- /dev/null
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "SpellAuraEffects.h"
+#include "InstanceScript.h"
+#include "Player.h"
+#include "SpellAuras.h"
+#include "shattered_halls.h"
+
+class at_nethekurse_exit : public AreaTriggerScript
+{
+ public:
+ at_nethekurse_exit() : AreaTriggerScript("at_nethekurse_exit") { };
+
+ bool OnTrigger(Player* player, AreaTriggerEntry const*) override
+ {
+ if (InstanceScript* is = player->GetInstanceScript())
+ {
+ if (is->instance->IsHeroic())
+ {
+ Creature* executioner = nullptr;
+
+ is->instance->LoadGrid(Executioner.GetPositionX(), Executioner.GetPositionY());
+ if (Creature* kargath = ObjectAccessor::GetCreature(*player, is->GetGuidData(NPC_KARGATH_BLADEFIST)))
+ {
+ if (is->GetGuidData(NPC_SHATTERED_EXECUTIONER).IsEmpty())
+ {
+ executioner = kargath->SummonCreature(NPC_SHATTERED_EXECUTIONER, Executioner);
+ kargath->AI()->DoAction(ACTION_EXECUTIONER_TAUNT);
+ }
+ }
+
+ if (executioner)
+ for (uint8 i = 0; i < VictimCount; ++i)
+ executioner->SummonCreature(executionerVictims[i](is->GetData(DATA_TEAM_IN_INSTANCE)), executionerVictims[i].GetPos());
+ }
+ }
+
+ return false;
+ }
+};
+
+enum Spells
+{
+ SPELL_CLEAVE = 15284
+};
+
+class boss_shattered_executioner : public CreatureScript
+{
+ public:
+ boss_shattered_executioner() : CreatureScript("boss_shattered_executioner") { }
+
+ struct boss_shattered_executionerAI : public BossAI
+ {
+ boss_shattered_executionerAI(Creature* creature) : BossAI(creature, DATA_SHATTERED_EXECUTIONER)
+ {
+ Initialize();
+ };
+
+ void Initialize()
+ {
+ cleaveTimer = 500;
+ }
+
+ void Reset() override
+ {
+ _Reset();
+
+ // _Reset() resets the loot mode, so we add them again, if any
+ uint32 prisonersExecuted = instance->GetData(DATA_PRISONERS_EXECUTED);
+ if (prisonersExecuted == 0)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_3);
+ if (prisonersExecuted <= 1)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_2);
+ if (prisonersExecuted <= 2)
+ me->AddLootMode(LOOT_MODE_HARD_MODE_1);
+
+ if (instance->GetBossState(DATA_KARGATH) == DONE)
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+ else
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+
+ Initialize();
+ }
+
+ void JustSummoned(Creature*) override { } // avoid despawn of prisoners on death/reset
+
+ void JustDied(Unit*) override
+ {
+ _JustDied();
+
+ if (instance->GetData(DATA_PRISONERS_EXECUTED) > 0)
+ return;
+
+ Map::PlayerList const &players = instance->instance->GetPlayers();
+ for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
+ {
+ Player* pl = itr->GetSource();
+ uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
+ if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE)
+ pl->CompleteQuest(qId);
+ }
+ }
+
+ void SetData(uint32 type, uint32 data) override
+ {
+ if (type == DATA_PRISONERS_EXECUTED && data <= 3)
+ {
+ if (Creature* victim = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FIRST_PRISONER + data - 1)))
+ me->Kill(victim);
+
+ if (data == 1)
+ {
+ Map::PlayerList const &players = instance->instance->GetPlayers();
+ for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
+ {
+ Player* pl = itr->GetSource();
+ uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H;
+ if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE)
+ pl->FailQuest(qId);
+ }
+ }
+
+ switch (data)
+ {
+ case 3:
+ me->RemoveLootMode(LOOT_MODE_HARD_MODE_1);
+ case 2:
+ me->RemoveLootMode(LOOT_MODE_HARD_MODE_2);
+ case 1:
+ me->RemoveLootMode(LOOT_MODE_HARD_MODE_3);
+ default:
+ break;
+ }
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ if (cleaveTimer <= diff)
+ {
+ DoCast(SPELL_CLEAVE);
+ cleaveTimer = urand(5000, 7000);
+ }
+ else
+ cleaveTimer -= diff;
+
+ DoMeleeAttackIfReady();
+ }
+ private:
+ uint32 cleaveTimer;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_shattered_executionerAI>(creature);
+ }
+};
+
+class spell_kargath_executioner : public SpellScriptLoader
+{
+ public:
+ spell_kargath_executioner() : SpellScriptLoader("spell_kargath_executioner") { }
+
+ class spell_kargath_executioner_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_kargath_executioner_AuraScript);
+
+ bool AreaCheck(Unit* target)
+ {
+ if (target->GetMap()->GetId() != 540)
+ return false;
+
+ return true;
+ }
+
+ bool Load() override
+ {
+ return GetCaster()->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void Register() override
+ {
+ DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_kargath_executioner_AuraScript::AreaCheck);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_kargath_executioner_AuraScript();
+ }
+};
+
+class spell_remove_kargath_executioner : public SpellScriptLoader
+{
+ public:
+ spell_remove_kargath_executioner() : SpellScriptLoader("spell_remove_kargath_executioner") { }
+
+ class spell_remove_kargath_executioner_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_remove_kargath_executioner_SpellScript);
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Unit* target = GetCaster();
+
+ target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_1);
+ target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_2);
+ target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_3);
+ }
+
+ bool Load() override
+ {
+ return GetCaster()->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_remove_kargath_executioner_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_remove_kargath_executioner_SpellScript();
+ }
+};
+
+void AddSC_shattered_halls()
+{
+ new at_nethekurse_exit();
+ new boss_shattered_executioner();
+ new spell_kargath_executioner();
+ new spell_remove_kargath_executioner();
+}
diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
index 90cbbe2a438..894cc9c40a6 100644
--- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
+++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h
@@ -21,18 +21,45 @@
#define DataHeader "SH"
-uint32 const EncounterCount = 3;
+uint32 const EncounterCount = 4;
+uint32 const VictimCount = 3;
enum DataTypes
{
- DATA_NETHEKURSE = 1,
- DATA_OMROGG = 2,
- DATA_KARGATH = 3
+ DATA_NETHEKURSE = 0,
+ DATA_OMROGG = 1,
+ DATA_KARGATH = 2,
+
+ DATA_SHATTERED_EXECUTIONER = 3,
+ DATA_PRISONERS_EXECUTED = 4,
+
+ DATA_TEAM_IN_INSTANCE = 5,
+
+ DATA_FIRST_PRISONER,
+ DATA_SECOND_PRISONER,
+ DATA_THIRD_PRISONER
};
enum CreatureIds
{
- NPC_GRAND_WARLOCK_NETHEKURSE = 16807
+ NPC_GRAND_WARLOCK_NETHEKURSE = 16807,
+ NPC_KARGATH_BLADEFIST = 16808,
+
+ NPC_SHATTERED_EXECUTIONER = 17301,
+
+ // Alliance Ids
+ NPC_RANDY_WHIZZLESPROCKET = 17288,
+
+ NPC_CAPTAIN_ALINA = 17290,
+ NPC_ALLIANCE_VICTIM_1 = 17289,
+ NPC_ALLIANCE_VICTIM_2 = 17292,
+
+ // Horde Ids
+ NPC_DRISELLA = 17294,
+
+ NPC_CAPTAIN_BONESHATTER = 17296,
+ NPC_HORDE_VICTIM_1 = 17295,
+ NPC_HORDE_VICTIM_2 = 17297
};
enum GameobjectIds
@@ -41,4 +68,47 @@ enum GameobjectIds
GO_GRAND_WARLOCK_CHAMBER_DOOR_2 = 182540
};
+enum QuestIds
+{
+ QUEST_IMPRISONED_A = 9524,
+ QUEST_IMPRISONED_H = 9525
+};
+
+enum InstanceSpells
+{
+ SPELL_KARGATH_EXECUTIONER_1 = 39288,
+ SPELL_KARGATH_EXECUTIONER_2 = 39289,
+ SPELL_KARGATH_EXECUTIONER_3 = 39290,
+
+ SPELL_REMOVE_KARGATH_EXECUTIONER = 39291
+};
+
+enum Actions
+{
+ ACTION_EXECUTIONER_TAUNT = 1
+};
+
+const Position Executioner = { 152.8524f, -83.63912f, 2.021005f, 0.06981317f };
+
+struct FactionSpawnerHelper
+{
+ FactionSpawnerHelper(uint32 allianceEntry, uint32 hordeEntry, const Position& pos) : _allianceNPC(allianceEntry), _hordeNPC(hordeEntry), _spawnPos(pos) { }
+
+ inline uint32 operator()(uint32 teamID) const { return teamID == ALLIANCE ? _allianceNPC : _hordeNPC; }
+ inline Position const& GetPos() const { return _spawnPos; }
+
+private:
+ const uint32 _allianceNPC;
+ const uint32 _hordeNPC;
+ const Position _spawnPos;
+};
+
+const FactionSpawnerHelper executionerVictims[VictimCount] =
+{
+ { NPC_CAPTAIN_ALINA, NPC_CAPTAIN_BONESHATTER, { 138.8807f, -84.22707f, 1.992269f, 0.06981317f } },
+ { NPC_ALLIANCE_VICTIM_1, NPC_HORDE_VICTIM_1, { 151.2411f, -91.02930f, 2.019741f, 1.57079600f } },
+ { NPC_ALLIANCE_VICTIM_2, NPC_HORDE_VICTIM_2, { 151.0459f, -77.51981f, 2.021008f, 4.74729500f } }
+};
+
+
#endif
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp
index cc825afd3a0..48508aa4790 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp
@@ -77,12 +77,11 @@ class boss_alar : public CreatureScript
public:
boss_alar() : CreatureScript("boss_alar") { }
- struct boss_alarAI : public ScriptedAI
+ struct boss_alarAI : public BossAI
{
- boss_alarAI(Creature* creature) : ScriptedAI(creature)
+ boss_alarAI(Creature* creature) : BossAI(creature, DATA_ALAR)
{
Initialize();
- instance = creature->GetInstanceScript();
DefaultMoveSpeedRate = creature->GetSpeedRate(MOVE_RUN);
DiveBomb_Timer = 0;
MeltArmor_Timer = 0;
@@ -105,8 +104,6 @@ class boss_alar : public CreatureScript
cur_wp = 4;
}
- InstanceScript* instance;
-
WaitEventType WaitEvent;
uint32 WaitTimer;
@@ -129,9 +126,8 @@ class boss_alar : public CreatureScript
void Reset() override
{
- instance->SetData(DATA_ALAREVENT, NOT_STARTED);
-
Initialize();
+ _Reset();
me->SetDisplayId(me->GetNativeDisplayId());
me->SetSpeed(MOVE_RUN, DefaultMoveSpeedRate);
@@ -145,18 +141,11 @@ class boss_alar : public CreatureScript
void EnterCombat(Unit* /*who*/) override
{
- instance->SetData(DATA_ALAREVENT, IN_PROGRESS);
-
+ _EnterCombat();
me->SetDisableGravity(true); // after enterevademode will be set walk movement
- DoZoneInCombat();
me->setActive(true);
}
- void JustDied(Unit* /*killer*/) override
- {
- instance->SetData(DATA_ALAREVENT, DONE);
- }
-
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() == CREATURE_EMBER_OF_ALAR)
@@ -508,7 +497,7 @@ class npc_ember_of_alar : public CreatureScript
DoCast(me, SPELL_EMBER_BLAST, true);
me->SetDisplayId(11686);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- if (instance->GetData(DATA_ALAREVENT) == 2)
+ if (instance->GetBossState(DATA_ALAR) == IN_PROGRESS)
{
if (Unit* Alar = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_ALAR)))
{
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp
index ee12d8c4d0d..ff9bdf15276 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp
@@ -92,17 +92,13 @@ class boss_high_astromancer_solarian : public CreatureScript
{
public:
- boss_high_astromancer_solarian()
- : CreatureScript("boss_high_astromancer_solarian")
- {
- }
+ boss_high_astromancer_solarian() : CreatureScript("boss_high_astromancer_solarian") { }
- struct boss_high_astromancer_solarianAI : public ScriptedAI
+ struct boss_high_astromancer_solarianAI : public BossAI
{
- boss_high_astromancer_solarianAI(Creature* creature) : ScriptedAI(creature), Summons(me)
+ boss_high_astromancer_solarianAI(Creature* creature) : BossAI(creature, DATA_HIGH_ASTROMANCER_SOLARIAN)
{
Initialize();
- instance = creature->GetInstanceScript();
defaultarmor = creature->GetArmor();
defaultsize = creature->GetObjectScale();
@@ -126,9 +122,6 @@ class boss_high_astromancer_solarian : public CreatureScript
Phase = 1;
}
- InstanceScript* instance;
- SummonList Summons;
-
uint8 Phase;
uint32 ArcaneMissiles_Timer;
@@ -152,16 +145,13 @@ class boss_high_astromancer_solarian : public CreatureScript
void Reset() override
{
Initialize();
-
- instance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, NOT_STARTED);
-
+ _Reset();
me->SetArmor(defaultarmor);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetVisible(true);
me->SetObjectScale(defaultsize);
me->SetDisplayId(MODEL_HUMAN);
- Summons.DespawnAll();
}
void KilledUnit(Unit* /*victim*/) override
@@ -174,15 +164,13 @@ class boss_high_astromancer_solarian : public CreatureScript
me->SetObjectScale(defaultsize);
me->SetDisplayId(MODEL_HUMAN);
Talk(SAY_DEATH);
- instance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, DONE);
+ _JustDied();
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
- DoZoneInCombat();
-
- instance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, IN_PROGRESS);
+ _EnterCombat();
}
void SummonMinion(uint32 entry, float x, float y, float z)
@@ -193,7 +181,7 @@ class boss_high_astromancer_solarian : public CreatureScript
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
Summoned->AI()->AttackStart(target);
- Summons.Summon(Summoned);
+ summons.Summon(Summoned);
}
}
@@ -316,10 +304,10 @@ class boss_high_astromancer_solarian : public CreatureScript
Portals[i][2] = PORTAL_Z;
}
}
- if ((abs(Portals[2][0] - Portals[1][0]) < 7) && (abs(Portals[2][1] - Portals[1][1]) < 7))
+ if ((std::abs(Portals[2][0] - Portals[1][0]) < 7) && (std::abs(Portals[2][1] - Portals[1][1]) < 7))
{
int i=1;
- if (abs(CENTER_X + 26.0f - Portals[2][0]) < 7)
+ if (std::abs(CENTER_X + 26.0f - Portals[2][0]) < 7)
i = -1;
Portals[2][0] = Portals[2][0]+7*i;
Portals[2][1] = Portal_Y(Portals[2][0], LARGE_PORTAL_RADIUS);
@@ -431,10 +419,7 @@ class npc_solarium_priest : public CreatureScript
{
public:
- npc_solarium_priest()
- : CreatureScript("npc_solarium_priest")
- {
- }
+ npc_solarium_priest() : CreatureScript("npc_solarium_priest") { }
struct npc_solarium_priestAI : public ScriptedAI
{
@@ -462,9 +447,7 @@ class npc_solarium_priest : public CreatureScript
Initialize();
}
- void EnterCombat(Unit* /*who*/) override
- {
- }
+ void EnterCombat(Unit* /*who*/) override { }
void UpdateAI(uint32 diff) override
{
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
index 9aa1981eabb..f5583c0bc53 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp
@@ -286,17 +286,13 @@ class boss_kaelthas : public CreatureScript
{
public:
- boss_kaelthas()
- : CreatureScript("boss_kaelthas")
- {
- }
- //Kael'thas AI
- struct boss_kaelthasAI : public ScriptedAI
+ boss_kaelthas() : CreatureScript("boss_kaelthas") { }
+
+ struct boss_kaelthasAI : public BossAI
{
- boss_kaelthasAI(Creature* creature) : ScriptedAI(creature), summons(me)
+ boss_kaelthasAI(Creature* creature) : BossAI(creature, DATA_KAELTHAS)
{
Initialize();
- instance = creature->GetInstanceScript();
PhaseSubphase = 0;
Phase_Timer = 0;
}
@@ -320,8 +316,6 @@ class boss_kaelthas : public CreatureScript
ChainPyros = false;
}
- InstanceScript* instance;
-
uint32 Fireball_Timer;
uint32 ArcaneDisruption_Timer;
uint32 Phoenix_Timer;
@@ -341,8 +335,6 @@ class boss_kaelthas : public CreatureScript
bool IsCastingFireball;
bool ChainPyros;
- SummonList summons;
-
ObjectGuid m_auiAdvisorGuid[MAX_ADVISORS];
void Reset() override
@@ -351,8 +343,8 @@ class boss_kaelthas : public CreatureScript
if (me->IsInCombat())
PrepareAdvisors();
-
- summons.DespawnAll();
+
+ _Reset();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
@@ -413,7 +405,6 @@ class boss_kaelthas : public CreatureScript
}
void MoveInLineOfSight(Unit* who) override
-
{
if (!me->HasUnitState(UNIT_STATE_STUNNED) && me->CanCreatureAttack(who))
{
@@ -444,6 +435,8 @@ class boss_kaelthas : public CreatureScript
{
if (!instance->GetData(DATA_KAELTHASEVENT) && !Phase)
StartEvent();
+
+ instance->SetBossState(DATA_KAELTHAS, IN_PROGRESS);
}
void KilledUnit(Unit* /*victim*/) override
@@ -463,11 +456,6 @@ class boss_kaelthas : public CreatureScript
}
}
- void SummonedCreatureDespawn(Creature* summon) override
- {
- summons.Despawn(summon);
- }
-
void JustDied(Unit* /*killer*/) override
{
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
@@ -475,8 +463,6 @@ class boss_kaelthas : public CreatureScript
Talk(SAY_DEATH);
- summons.DespawnAll();
-
instance->SetData(DATA_KAELTHASEVENT, 0);
for (uint8 i = 0; i < MAX_ADVISORS; ++i)
@@ -484,6 +470,7 @@ class boss_kaelthas : public CreatureScript
if (Unit* pAdvisor = ObjectAccessor::GetUnit(*me, m_auiAdvisorGuid[i]))
pAdvisor->Kill(pAdvisor);
}
+ _JustDied();
}
void UpdateAI(uint32 diff) override
@@ -1024,10 +1011,8 @@ class boss_thaladred_the_darkener : public CreatureScript
{
public:
- boss_thaladred_the_darkener()
- : CreatureScript("boss_thaladred_the_darkener")
- {
- }
+ boss_thaladred_the_darkener() : CreatureScript("boss_thaladred_the_darkener") { }
+
struct boss_thaladred_the_darkenerAI : public advisorbase_ai
{
boss_thaladred_the_darkenerAI(Creature* creature) : advisorbase_ai(creature)
@@ -1130,10 +1115,8 @@ class boss_lord_sanguinar : public CreatureScript
{
public:
- boss_lord_sanguinar()
- : CreatureScript("boss_lord_sanguinar")
- {
- }
+ boss_lord_sanguinar() : CreatureScript("boss_lord_sanguinar") { }
+
struct boss_lord_sanguinarAI : public advisorbase_ai
{
boss_lord_sanguinarAI(Creature* creature) : advisorbase_ai(creature)
@@ -1205,10 +1188,8 @@ class boss_grand_astromancer_capernian : public CreatureScript
{
public:
- boss_grand_astromancer_capernian()
- : CreatureScript("boss_grand_astromancer_capernian")
- {
- }
+ boss_grand_astromancer_capernian() : CreatureScript("boss_grand_astromancer_capernian") { }
+
struct boss_grand_astromancer_capernianAI : public advisorbase_ai
{
boss_grand_astromancer_capernianAI(Creature* creature) : advisorbase_ai(creature)
@@ -1358,10 +1339,8 @@ class boss_master_engineer_telonicus : public CreatureScript
{
public:
- boss_master_engineer_telonicus()
- : CreatureScript("boss_master_engineer_telonicus")
- {
- }
+ boss_master_engineer_telonicus() : CreatureScript("boss_master_engineer_telonicus") { }
+
struct boss_master_engineer_telonicusAI : public advisorbase_ai
{
boss_master_engineer_telonicusAI(Creature* creature) : advisorbase_ai(creature)
@@ -1449,10 +1428,8 @@ class npc_kael_flamestrike : public CreatureScript
{
public:
- npc_kael_flamestrike()
- : CreatureScript("npc_kael_flamestrike")
- {
- }
+ npc_kael_flamestrike() : CreatureScript("npc_kael_flamestrike") { }
+
struct npc_kael_flamestrikeAI : public ScriptedAI
{
npc_kael_flamestrikeAI(Creature* creature) : ScriptedAI(creature)
@@ -1482,7 +1459,6 @@ class npc_kael_flamestrike : public CreatureScript
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void EnterCombat(Unit* /*who*/) override { }
void UpdateAI(uint32 diff) override
@@ -1523,10 +1499,8 @@ class npc_phoenix_tk : public CreatureScript
{
public:
- npc_phoenix_tk()
- : CreatureScript("npc_phoenix_tk")
- {
- }
+ npc_phoenix_tk() : CreatureScript("npc_phoenix_tk") { }
+
struct npc_phoenix_tkAI : public ScriptedAI
{
npc_phoenix_tkAI(Creature* creature) : ScriptedAI(creature)
@@ -1585,10 +1559,8 @@ class npc_phoenix_egg_tk : public CreatureScript
{
public:
- npc_phoenix_egg_tk()
- : CreatureScript("npc_phoenix_egg_tk")
- {
- }
+ npc_phoenix_egg_tk() : CreatureScript("npc_phoenix_egg_tk") { }
+
struct npc_phoenix_egg_tkAI : public ScriptedAI
{
npc_phoenix_egg_tkAI(Creature* creature) : ScriptedAI(creature)
@@ -1611,7 +1583,6 @@ class npc_phoenix_egg_tk : public CreatureScript
//ignore any
void MoveInLineOfSight(Unit* /*who*/) override { }
-
void AttackStart(Unit* who) override
{
if (me->Attack(who, false))
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp
index 9186b491fa4..1aa7d5298e5 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp
@@ -47,17 +47,13 @@ class boss_void_reaver : public CreatureScript
{
public:
- boss_void_reaver()
- : CreatureScript("boss_void_reaver")
- {
- }
+ boss_void_reaver() : CreatureScript("boss_void_reaver") { }
- struct boss_void_reaverAI : public ScriptedAI
+ struct boss_void_reaverAI : public BossAI
{
- boss_void_reaverAI(Creature* creature) : ScriptedAI(creature)
+ boss_void_reaverAI(Creature* creature) : BossAI(creature, DATA_VOID_REAVER)
{
Initialize();
- instance = creature->GetInstanceScript();
}
void Initialize()
@@ -70,8 +66,6 @@ class boss_void_reaver : public CreatureScript
Enraged = false;
}
- InstanceScript* instance;
-
uint32 Pounding_Timer;
uint32 ArcaneOrb_Timer;
uint32 KnockAway_Timer;
@@ -82,9 +76,7 @@ class boss_void_reaver : public CreatureScript
void Reset() override
{
Initialize();
-
- if (me->IsAlive())
- instance->SetData(DATA_VOIDREAVEREVENT, NOT_STARTED);
+ _Reset();
}
void KilledUnit(Unit* /*victim*/) override
@@ -96,15 +88,13 @@ class boss_void_reaver : public CreatureScript
{
Talk(SAY_DEATH);
DoZoneInCombat();
-
- instance->SetData(DATA_VOIDREAVEREVENT, DONE);
+ _JustDied();
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
-
- instance->SetData(DATA_VOIDREAVEREVENT, IN_PROGRESS);
+ _EnterCombat();
}
void UpdateAI(uint32 diff) override
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp b/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp
index 38c9cdd487c..c421b9974ce 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp
@@ -27,8 +27,6 @@ EndScriptData */
#include "InstanceScript.h"
#include "the_eye.h"
-#define MAX_ENCOUNTER 5
-
/* The Eye encounters:
0 - Kael'thas event
1 - Al' ar event
@@ -39,20 +37,16 @@ EndScriptData */
class instance_the_eye : public InstanceMapScript
{
public:
- instance_the_eye()
- : InstanceMapScript("instance_the_eye", 550)
- {
- }
+ instance_the_eye() : InstanceMapScript("instance_the_eye", 550) { }
struct instance_the_eye_InstanceMapScript : public InstanceScript
{
instance_the_eye_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
- memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
+ SetBossNumber(EncounterCount);
KaelthasEventPhase = 0;
- AlarEventPhase = 0;
}
ObjectGuid ThaladredTheDarkener;
@@ -63,44 +57,34 @@ class instance_the_eye : public InstanceMapScript
ObjectGuid Astromancer;
ObjectGuid Alar;
uint8 KaelthasEventPhase;
- uint8 AlarEventPhase;
-
- uint32 m_auiEncounter[MAX_ENCOUNTER];
-
- bool IsEncounterInProgress() const override
- {
- for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- if (m_auiEncounter[i] == IN_PROGRESS)
- return true;
-
- return false;
- }
void OnCreatureCreate(Creature* creature) override
{
switch (creature->GetEntry())
{
- case 20064:
- ThaladredTheDarkener = creature->GetGUID();
- break;
- case 20063:
- MasterEngineerTelonicus = creature->GetGUID();
- break;
- case 20062:
- GrandAstromancerCapernian = creature->GetGUID();
- break;
- case 20060:
- LordSanguinar = creature->GetGUID();
- break;
- case 19622:
- Kaelthas = creature->GetGUID();
- break;
- case 18805:
- Astromancer = creature->GetGUID();
- break;
- case 19514:
- Alar = creature->GetGUID();
- break;
+ case NPC_SANGUINAR:
+ LordSanguinar = creature->GetGUID();
+ break;
+ case NPC_CAPERNIAN:
+ GrandAstromancerCapernian = creature->GetGUID();
+ break;
+ case NPC_TELONICUS:
+ MasterEngineerTelonicus = creature->GetGUID();
+ break;
+ case NPC_THALADRED:
+ ThaladredTheDarkener = creature->GetGUID();
+ break;
+ case NPC_KAELTHAS:
+ Kaelthas = creature->GetGUID();
+ break;
+ case NPC_HIGH_ASTROMANCER_SOLARIAN:
+ Astromancer = creature->GetGUID();
+ break;
+ case NPC_ALAR:
+ Alar = creature->GetGUID();
+ break;
+ default:
+ break;
}
}
@@ -113,7 +97,7 @@ class instance_the_eye : public InstanceMapScript
case DATA_GRANDASTROMANCERCAPERNIAN: return GrandAstromancerCapernian;
case DATA_MASTERENGINEERTELONICUS: return MasterEngineerTelonicus;
case DATA_KAELTHAS: return Kaelthas;
- case DATA_ASTROMANCER: return Astromancer;
+ case DATA_HIGH_ASTROMANCER_SOLARIAN: return Astromancer;
case DATA_ALAR: return Alar;
}
return ObjectGuid::Empty;
@@ -123,64 +107,23 @@ class instance_the_eye : public InstanceMapScript
{
switch (type)
{
- case DATA_ALAREVENT:
- AlarEventPhase = data;
- m_auiEncounter[0] = data;
- break;
- case DATA_HIGHASTROMANCERSOLARIANEVENT:
- m_auiEncounter[1] = data;
- break;
- case DATA_VOIDREAVEREVENT:
- m_auiEncounter[2] = data;
- break;
- case DATA_KAELTHASEVENT:
- KaelthasEventPhase = data;
- m_auiEncounter[3] = data;
- break;
+ case DATA_KAELTHASEVENT:
+ KaelthasEventPhase = data;
+ break;
+ default:
+ break;
}
- if (data == DONE)
- SaveToDB();
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
- case DATA_ALAREVENT: return AlarEventPhase;
- case DATA_HIGHASTROMANCERSOLARIANEVENT: return m_auiEncounter[1];
- case DATA_VOIDREAVEREVENT: return m_auiEncounter[2];
- case DATA_KAELTHASEVENT: return KaelthasEventPhase;
+ case DATA_KAELTHASEVENT:
+ return KaelthasEventPhase;
}
return 0;
}
-
- std::string GetSaveData() override
- {
- OUT_SAVE_INST_DATA;
-
- std::ostringstream stream;
- stream << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' ' << m_auiEncounter[2] << ' ' << m_auiEncounter[3];
-
- OUT_SAVE_INST_DATA_COMPLETE;
- return stream.str();
- }
-
- void Load(const char* in) override
- {
- if (!in)
- {
- OUT_LOAD_INST_DATA_FAIL;
- return;
- }
- OUT_LOAD_INST_DATA(in);
-
- std::istringstream stream(in);
- stream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3];
- for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- if (m_auiEncounter[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead.
- m_auiEncounter[i] = NOT_STARTED;
- OUT_LOAD_INST_DATA_COMPLETE;
- }
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h b/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h
index 718f37861d9..c46fe408274 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h
+++ b/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h
@@ -21,19 +21,33 @@
#define DataHeader "TE"
+uint32 const EncounterCount = 4;
+
enum DataTypes
{
- DATA_ALAREVENT = 1,
- DATA_ASTROMANCER = 2,
- DATA_GRANDASTROMANCERCAPERNIAN = 3,
- DATA_HIGHASTROMANCERSOLARIANEVENT = 4,
- DATA_KAELTHAS = 5,
+ // Encounter States/Boss GUIDs
+ DATA_KAELTHAS = 0,
+ DATA_ALAR = 1,
+ DATA_HIGH_ASTROMANCER_SOLARIAN = 2,
+ DATA_VOID_REAVER = 3,
+
+ DATA_ASTROMANCER = 4,
+ DATA_GRANDASTROMANCERCAPERNIAN = 5,
DATA_KAELTHASEVENT = 6,
DATA_LORDSANGUINAR = 7,
DATA_MASTERENGINEERTELONICUS = 8,
- DATA_THALADREDTHEDARKENER = 10,
- DATA_VOIDREAVEREVENT = 11,
- DATA_ALAR = 12
+ DATA_THALADREDTHEDARKENER = 9
+};
+
+enum CreatureIds
+{
+ NPC_SANGUINAR = 20060,
+ NPC_CAPERNIAN = 20062,
+ NPC_TELONICUS = 20063,
+ NPC_THALADRED = 20064,
+ NPC_KAELTHAS = 19622,
+ NPC_HIGH_ASTROMANCER_SOLARIAN = 18805,
+ NPC_ALAR = 19514
};
#endif
diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/instance_mechanar.cpp b/src/server/scripts/Outland/TempestKeep/Mechanar/instance_mechanar.cpp
index 4955a2201e5..b2d63315029 100644
--- a/src/server/scripts/Outland/TempestKeep/Mechanar/instance_mechanar.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Mechanar/instance_mechanar.cpp
@@ -42,7 +42,7 @@ class instance_mechanar : public InstanceMapScript
LoadDoorData(doorData);
}
- void OnGameObjectCreate(GameObject* gameObject)
+ void OnGameObjectCreate(GameObject* gameObject) override
{
switch (gameObject->GetEntry())
{
diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp
index 50b77aac410..03e2154792b 100644
--- a/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp
+++ b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp
@@ -283,7 +283,10 @@ class boss_harbinger_skyriss_illusion : public CreatureScript
{
boss_harbinger_skyriss_illusionAI(Creature* creature) : ScriptedAI(creature) { }
- void Reset() override { }
+ void Reset() override
+ {
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ }
void EnterCombat(Unit* /*who*/) override { }
};
diff --git a/src/server/scripts/Outland/zone_blades_edge_mountains.cpp b/src/server/scripts/Outland/zone_blades_edge_mountains.cpp
index 72355b05ec1..aaf006f6c5f 100644
--- a/src/server/scripts/Outland/zone_blades_edge_mountains.cpp
+++ b/src/server/scripts/Outland/zone_blades_edge_mountains.cpp
@@ -24,12 +24,9 @@ SDCategory: Blade's Edge Mountains
EndScriptData */
/* ContentData
-npc_bloodmaul_brutebane
-npc_bloodmaul_brute
npc_nether_drake
npc_daranelle
go_legion_obelisk
-go_thunderspike
EndContentData */
#include "ScriptMgr.h"
@@ -45,171 +42,6 @@ EndContentData */
#include "SpellAuraEffects.h"
/*######
-## npc_bloodmaul_brutebane
-######*/
-
-enum Bloodmaul
-{
- NPC_OGRE_BRUTE = 19995,
- NPC_QUEST_CREDIT = 21241,
- GO_KEG = 184315,
- QUEST_GETTING_THE_BLADESPIRE_TANKED = 10512,
- QUEST_BLADESPIRE_KEGGER = 10545
-};
-
-class npc_bloodmaul_brutebane : public CreatureScript
-{
-public:
- npc_bloodmaul_brutebane() : CreatureScript("npc_bloodmaul_brutebane") { }
-
- struct npc_bloodmaul_brutebaneAI : public ScriptedAI
- {
- npc_bloodmaul_brutebaneAI(Creature* creature) : ScriptedAI(creature)
- {
- if (Creature* Ogre = me->FindNearestCreature(NPC_OGRE_BRUTE, 50, true))
- {
- Ogre->SetReactState(REACT_DEFENSIVE);
- Ogre->GetMotionMaster()->MovePoint(1, me->GetPositionX()-1, me->GetPositionY()+1, me->GetPositionZ());
- }
- }
-
- void UpdateAI(uint32 /*diff*/) override { }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_bloodmaul_brutebaneAI(creature);
- }
-};
-
-/*######
-## npc_bloodmaul_brute
-######*/
-
-enum BloodmaulBrute
-{
- EVENT_CLEAVE = 1,
- EVENT_DEBILITATING_STRIKE = 2,
- SAY_AGGRO = 0,
- SAY_DEATH = 1,
- SAY_ENRAGE = 2,
- SPELL_CLEAVE = 15496,
- SPELL_DEBILITATING_STRIKE = 37577,
- SPELL_ENRAGE = 8599,
- QUEST_INTO_THE_SOULGRINDER = 11000
-};
-
-class npc_bloodmaul_brute : public CreatureScript
-{
-public:
- npc_bloodmaul_brute() : CreatureScript("npc_bloodmaul_brute") { }
-
- struct npc_bloodmaul_bruteAI : public ScriptedAI
- {
- npc_bloodmaul_bruteAI(Creature* creature) : ScriptedAI(creature)
- {
- hp30 = false;
- }
-
- void Reset() override
- {
- PlayerGUID.Clear();
- hp30 = false;
- }
-
- void EnterCombat(Unit* /*who*/) override
- {
- if (urand (0, 100) < 35)
- Talk(SAY_AGGRO);
-
- events.ScheduleEvent(EVENT_CLEAVE, urand(9000,12000));
- events.ScheduleEvent(EVENT_DEBILITATING_STRIKE, 15000);
- }
-
- void JustDied(Unit* killer) override
- {
- if (killer->GetTypeId() == TYPEID_PLAYER)
- if (killer->ToPlayer()->GetQuestRewardStatus(QUEST_INTO_THE_SOULGRINDER))
- Talk(SAY_DEATH);
- }
-
- void MoveInLineOfSight(Unit* who) override
- {
- if (!who || (!who->IsAlive()))
- return;
-
- if (me->IsWithinDistInMap(who, 50.0f))
- {
- if (who->GetTypeId() == TYPEID_PLAYER)
- if (who->ToPlayer()->GetQuestStatus(QUEST_GETTING_THE_BLADESPIRE_TANKED) == QUEST_STATUS_INCOMPLETE
- || who->ToPlayer()->GetQuestStatus(QUEST_BLADESPIRE_KEGGER) == QUEST_STATUS_INCOMPLETE)
- PlayerGUID = who->GetGUID();
- }
- }
-
- void MovementInform(uint32 /*type*/, uint32 id) override
- {
- if (id == 1)
- {
- if (GameObject* Keg = me->FindNearestGameObject(GO_KEG, 20))
- Keg->Delete();
-
- me->HandleEmoteCommand(7);
- me->SetReactState(REACT_AGGRESSIVE);
- me->GetMotionMaster()->MoveTargetedHome();
-
- Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID);
- Creature* Credit = me->FindNearestCreature(NPC_QUEST_CREDIT, 50, true);
- if (player && Credit)
- player->KilledMonster(Credit->GetCreatureTemplate(), Credit->GetGUID());
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
-
- while (uint32 eventId = events.ExecuteEvent())
- {
- switch (eventId)
- {
- case EVENT_CLEAVE:
- DoCast(me, SPELL_CLEAVE);
- events.ScheduleEvent(EVENT_CLEAVE, urand(9000,12000));
- break;
- case EVENT_DEBILITATING_STRIKE:
- DoCastVictim(SPELL_DEBILITATING_STRIKE);
- events.ScheduleEvent(EVENT_DEBILITATING_STRIKE, urand(18000,22000));
- break;
- }
- }
-
- if (!hp30 && HealthBelowPct(30))
- {
- hp30 = true;
- Talk(SAY_ENRAGE);
- DoCast(me, SPELL_ENRAGE);
- }
-
- DoMeleeAttackIfReady();
- }
-
- private:
- EventMap events;
- ObjectGuid PlayerGUID;
- bool hp30;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_bloodmaul_bruteAI(creature);
- }
-};
-
-/*######
## npc_nether_drake
######*/
@@ -507,31 +339,6 @@ public:
}
};
-/*######
-## go_thunderspike
-######*/
-
-enum TheThunderspike
-{
- NPC_GOR_GRIMGUT = 21319,
- QUEST_THUNDERSPIKE = 10526,
-};
-
-class go_thunderspike : public GameObjectScript
-{
- public:
- go_thunderspike() : GameObjectScript("go_thunderspike") { }
-
- bool OnGossipHello(Player* player, GameObject* go) override
- {
- if (player->GetQuestStatus(QUEST_THUNDERSPIKE) == QUEST_STATUS_INCOMPLETE && !go->FindNearestCreature(NPC_GOR_GRIMGUT, 25.0f, true))
- if (Creature* gorGrimgut = go->SummonCreature(NPC_GOR_GRIMGUT, -2413.4f, 6914.48f, 25.01f, 3.67f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000))
- gorGrimgut->AI()->AttackStart(player);
-
- return true;
- }
-};
-
enum SimonGame
{
NPC_SIMON_BUNNY = 22923,
@@ -1219,12 +1026,9 @@ class spell_oscillating_field : public SpellScriptLoader
void AddSC_blades_edge_mountains()
{
- new npc_bloodmaul_brutebane();
- new npc_bloodmaul_brute();
new npc_nether_drake();
new npc_daranelle();
new go_legion_obelisk();
- new go_thunderspike();
new npc_simon_bunny();
new go_simon_cluster();
new go_apexis_relic();
diff --git a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp
index 97777cd5f6e..d1a31906d58 100644
--- a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp
+++ b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp
@@ -289,7 +289,7 @@ public:
summoned->AI()->AttackStart(me);
}
- void sQuestAccept(Player* player, Quest const* quest)
+ void sQuestAccept(Player* player, Quest const* quest) override
{
if (quest->GetQuestId() == QUEST_ROAD_TO_FALCON_WATCH)
{
@@ -420,10 +420,482 @@ public:
}
};
+enum ExorcismSpells
+{
+ SPELL_JULES_GOES_PRONE = 39283,
+ SPELL_JULES_THREATENS_AURA = 39284,
+ SPELL_JULES_GOES_UPRIGHT = 39294,
+ SPELL_JULES_VOMITS_AURA = 39295,
+
+ SPELL_BARADAS_COMMAND = 39277,
+ SPELL_BARADA_FALTERS = 39278,
+};
+
+enum ExorcismTexts
+{
+ SAY_BARADA_1 = 0,
+ SAY_BARADA_2 = 1,
+ SAY_BARADA_3 = 2,
+ SAY_BARADA_4 = 3,
+ SAY_BARADA_5 = 4,
+ SAY_BARADA_6 = 5,
+ SAY_BARADA_7 = 6,
+ SAY_BARADA_8 = 7,
+
+ SAY_JULES_1 = 0,
+ SAY_JULES_2 = 1,
+ SAY_JULES_3 = 2,
+ SAY_JULES_4 = 3,
+ SAY_JULES_5 = 4,
+};
+
+Position const exorcismPos[11] =
+{
+ { -707.123f, 2751.686f, 101.592f, 4.577416f }, //Barada Waypoint-1 0
+ { -710.731f, 2749.075f, 101.592f, 1.513286f }, //Barada Cast position 1
+ { -710.332f, 2754.394f, 102.948f, 3.207566f }, //Jules 2
+ { -714.261f, 2747.754f, 103.391f, 0.0f }, //Jules Waypoint-1 3
+ { -713.113f, 2750.194f, 103.391f, 0.0f }, //Jules Waypoint-2 4
+ { -710.385f, 2750.896f, 103.391f, 0.0f }, //Jules Waypoint-3 5
+ { -708.309f, 2750.062f, 103.391f, 0.0f }, //Jules Waypoint-4 6
+ { -707.401f, 2747.696f, 103.391f, 0.0f }, //Jules Waypoint-5 7
+ { -708.591f, 2745.266f, 103.391f, 0.0f }, //Jules Waypoint-6 8
+ { -710.597f, 2744.035f, 103.391f, 0.0f }, //Jules Waypoint-7 9
+ { -713.089f, 2745.302f, 103.391f, 0.0f }, //Jules Waypoint-8 10
+};
+
+enum ExorcismMisc
+{
+ NPC_DARKNESS_RELEASED = 22507,
+ NPC_FOUL_PURGE = 22506,
+ NPC_COLONEL_JULES = 22432,
+
+ BARADAS_GOSSIP_MESSAGE = 10683,
+
+ QUEST_THE_EXORCISM_OF_COLONEL_JULES = 10935,
+
+ ACTION_START_EVENT = 1,
+ ACTION_JULES_HOVER = 2,
+ ACTION_JULES_FLIGHT = 3,
+ ACTION_JULES_MOVE_HOME = 4,
+};
+
+enum ExorcismEvents
+{
+ EVENT_BARADAS_TALK = 1,
+
+ //Colonel Jules
+ EVENT_SUMMON_SKULL = 1,
+};
+
+/*######
+## npc_barada
+######*/
+
+class npc_barada : public CreatureScript
+{
+public:
+ npc_barada() : CreatureScript("npc_barada") { }
+
+ struct npc_baradaAI : public ScriptedAI
+ {
+ npc_baradaAI(Creature* creature) : ScriptedAI(creature)
+ {
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ step = 0;
+ }
+
+ void Reset() override
+ {
+ events.Reset();
+ Initialize();
+
+ playerGUID.Clear();
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
+ }
+
+ void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
+ {
+ player->PlayerTalkClass->ClearMenus();
+ switch (gossipListId)
+ {
+ case 1:
+ player->PlayerTalkClass->SendCloseGossip();
+ me->AI()->Talk(SAY_BARADA_1);
+ me->AI()->DoAction(ACTION_START_EVENT);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_START_EVENT)
+ {
+ if (Creature* jules = me->FindNearestCreature(NPC_COLONEL_JULES, 20.0f, true))
+ {
+ julesGUID = jules->GetGUID();
+ jules->AI()->Talk(SAY_JULES_1);
+ }
+
+ me->GetMotionMaster()->MovePoint(0, exorcismPos[1]);
+ Talk(SAY_BARADA_2);
+
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
+ }
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type != POINT_MOTION_TYPE)
+ return;
+
+ if (id == 0)
+ me->GetMotionMaster()->MovePoint(1, exorcismPos[1]);
+
+ if (id == 1)
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 2000);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ {
+ jules->AI()->DoAction(ACTION_JULES_MOVE_HOME);
+ jules->RemoveAllAuras();
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_BARADAS_TALK:
+ switch (step)
+ {
+ case 0:
+ me->SetFacingTo(1.513286f);
+
+ me->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 3000);
+ step++;
+ break;
+ case 1:
+ DoCast(SPELL_BARADAS_COMMAND);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 5000);
+ step++;
+ break;
+ case 2:
+ Talk(SAY_BARADA_3);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 7000);
+ step++;
+ break;
+ case 3:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_2);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 18000);
+ step++;
+ break;
+ case 4:
+ DoCast(SPELL_BARADA_FALTERS);
+ me->HandleEmoteCommand(EMOTE_STAND_STATE_NONE);
+
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->DoAction(ACTION_JULES_HOVER);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 11000);
+ step++;
+ break;
+ case 5:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_3);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 13000);
+ step++;
+ break;
+ case 6:
+ Talk(SAY_BARADA_4);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 5000);
+ step++;
+ break;
+ case 7:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_3);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 13000);
+ step++;
+ break;
+ case 8:
+ Talk(SAY_BARADA_4);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 12000);
+ step++;
+ break;
+ case 9:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_4);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 12000);
+ step++;
+ break;
+ case 10:
+ Talk(SAY_BARADA_4);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 5000);
+ step++;
+ break;
+ case 11:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->DoAction(ACTION_JULES_FLIGHT);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 12:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_4);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 8000);
+ step++;
+ break;
+ case 13:
+ Talk(SAY_BARADA_5);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 14:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_4);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 15:
+ Talk(SAY_BARADA_6);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 16:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_5);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 17:
+ Talk(SAY_BARADA_7);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 18:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->AI()->Talk(SAY_JULES_3);
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 19:
+ Talk(SAY_BARADA_7);
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 20:
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ {
+ jules->AI()->DoAction(ACTION_JULES_MOVE_HOME);
+ jules->RemoveAura(SPELL_JULES_VOMITS_AURA);
+ }
+
+ events.ScheduleEvent(EVENT_BARADAS_TALK, 10000);
+ step++;
+ break;
+ case 21:
+ //End
+ if (Player* player = ObjectAccessor::FindPlayer(playerGUID))
+ player->KilledMonsterCredit(NPC_COLONEL_JULES, ObjectGuid::Empty);
+
+ if (Creature* jules = ObjectAccessor::GetCreature(*me, julesGUID))
+ jules->RemoveAllAuras();
+
+ me->RemoveAura(SPELL_BARADAS_COMMAND);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
+
+ Talk(SAY_BARADA_8);
+ me->GetMotionMaster()->MoveTargetedHome();
+ EnterEvadeMode();
+ break;
+ }
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap events;
+ uint8 step;
+ ObjectGuid julesGUID;
+ ObjectGuid playerGUID;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_baradaAI(creature);
+ }
+};
+
+/*######
+## npc_colonel_jules
+######*/
+
+class npc_colonel_jules : public CreatureScript
+{
+public:
+ npc_colonel_jules() : CreatureScript("npc_colonel_jules") { }
+
+ struct npc_colonel_julesAI : public ScriptedAI
+ {
+ npc_colonel_julesAI(Creature* creature) : ScriptedAI(creature), summons(me)
+ {
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ circleRounds = 0;
+ point = 3;
+ wpreached = false;
+ }
+
+ void Reset() override
+ {
+ events.Reset();
+
+ summons.DespawnAll();
+ Initialize();
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_JULES_HOVER:
+ me->AddAura(SPELL_JULES_GOES_PRONE, me);
+ me->AddAura(SPELL_JULES_THREATENS_AURA, me);
+
+ me->SetCanFly(true);
+ me->SetSpeed(MOVE_RUN, 0.2f);
+
+ me->SetFacingTo(3.207566f);
+ me->GetMotionMaster()->MoveJump(exorcismPos[2], 2.0f, 2.0f);
+
+ events.ScheduleEvent(EVENT_SUMMON_SKULL, 10000);
+ break;
+ case ACTION_JULES_FLIGHT:
+ circleRounds++;
+
+ me->RemoveAura(SPELL_JULES_GOES_PRONE);
+
+ me->AddAura(SPELL_JULES_GOES_UPRIGHT, me);
+ me->AddAura(SPELL_JULES_VOMITS_AURA, me);
+
+ wpreached = true;
+ me->GetMotionMaster()->MovePoint(point, exorcismPos[point]);
+ break;
+ case ACTION_JULES_MOVE_HOME:
+ wpreached = false;
+ me->SetSpeed(MOVE_RUN, 1.0f);
+ me->GetMotionMaster()->MovePoint(11, exorcismPos[2]);
+
+ events.CancelEvent(EVENT_SUMMON_SKULL);
+ break;
+ }
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ summons.Summon(summon);
+ summon->GetMotionMaster()->MoveRandom(10.0f);
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type != POINT_MOTION_TYPE)
+ return;
+
+ if (id < 10)
+ wpreached = true;
+
+ if (id == 8)
+ {
+ for (uint8 i = 0; i < circleRounds; i++)
+ DoSummon(NPC_FOUL_PURGE, exorcismPos[8]);
+ }
+
+ if (id == 10)
+ {
+ wpreached = true;
+ point = 3;
+ circleRounds++;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (wpreached)
+ {
+ me->GetMotionMaster()->MovePoint(point, exorcismPos[point]);
+ point++;
+ wpreached = false;
+ }
+
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SUMMON_SKULL:
+ uint8 summonCount = urand(1,3);
+
+ for (uint8 i = 0; i < summonCount; i++)
+ me->SummonCreature(NPC_DARKNESS_RELEASED, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 1.5f, 0, TEMPSUMMON_MANUAL_DESPAWN);
+
+ events.ScheduleEvent(EVENT_SUMMON_SKULL, urand(10000, 15000));
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap events;
+ SummonList summons;
+
+ uint8 circleRounds;
+ uint8 point;
+
+ bool wpreached;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_colonel_julesAI(creature);
+ }
+};
+
void AddSC_hellfire_peninsula()
{
new npc_aeranas();
new npc_ancestral_wolf();
new npc_wounded_blood_elf();
new npc_fel_guard_hound();
+ new npc_barada();
+ new npc_colonel_jules();
}
diff --git a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp
index c661e19a98d..318214978ae 100644
--- a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp
+++ b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp
@@ -31,7 +31,6 @@ npc_enslaved_netherwing_drake
npc_drake_dealer_hurlunk
npcs_flanis_swiftwing_and_kagrosh
npc_karynaku
-npc_overlord_morghor
npc_earthmender_wilda
npc_torloth_the_magnificent
npc_illidari_spawn
@@ -677,331 +676,6 @@ class npc_karynaku : public CreatureScript
};
/*####
-# npc_overlord_morghor
-# this whole script is wrong and needs a rewrite.even the illidan npc used is the wrong one.npc id 23467 may be the correct one
-####*/
-enum OverlordData
-{
- QUEST_LORD_ILLIDAN_STORMRAGE = 11108,
-
- C_ILLIDAN = 22083,
- C_YARZILL = 23141,
-
- SPELL_ONE = 39990, // Red Lightning Bolt
- SPELL_TWO = 41528, // Mark of Stormrage
- SPELL_THREE = 40216, // Dragonaw Faction
- SPELL_FOUR = 42016, // Dragonaw Trasform
-
- OVERLORD_SAY_1 = 0,
- OVERLORD_SAY_2 = 1,
- //OVERLORD_SAY_3 = 2,
- OVERLORD_SAY_4 = 3,
- OVERLORD_SAY_5 = 4,
- OVERLORD_SAY_6 = 5,
-
- OVERLORD_YELL_1 = 6,
- OVERLORD_YELL_2 = 7,
-
- LORD_ILLIDAN_SAY_1 = 0,
- LORD_ILLIDAN_SAY_2 = 1,
- LORD_ILLIDAN_SAY_3 = 2,
- LORD_ILLIDAN_SAY_4 = 3,
- LORD_ILLIDAN_SAY_5 = 4,
- LORD_ILLIDAN_SAY_6 = 5,
- LORD_ILLIDAN_SAY_7 = 6,
-
- YARZILL_THE_MERC_SAY = 0
-};
-
-class npc_overlord_morghor : public CreatureScript
-{
-public:
- npc_overlord_morghor() : CreatureScript("npc_overlord_morghor") { }
-
- bool OnQuestAccept(Player* player, Creature* creature, const Quest *_Quest) override
- {
- if (_Quest->GetQuestId() == QUEST_LORD_ILLIDAN_STORMRAGE)
- {
- ENSURE_AI(npc_overlord_morghor::npc_overlord_morghorAI, creature->AI())->PlayerGUID = player->GetGUID();
- ENSURE_AI(npc_overlord_morghor::npc_overlord_morghorAI, creature->AI())->StartEvent();
- return true;
- }
- return false;
- }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_overlord_morghorAI(creature);
- }
-
- struct npc_overlord_morghorAI : public ScriptedAI
- {
- npc_overlord_morghorAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- }
-
- void Initialize()
- {
- PlayerGUID.Clear();
- IllidanGUID.Clear();
-
- ConversationTimer = 0;
- Step = 0;
-
- Event = false;
- }
-
- ObjectGuid PlayerGUID;
- ObjectGuid IllidanGUID;
-
- uint32 ConversationTimer;
- uint32 Step;
-
- bool Event;
-
- void Reset() override
- {
- Initialize();
- me->SetUInt32Value(UNIT_NPC_FLAGS, 2);
- }
-
- void StartEvent()
- {
- me->SetUInt32Value(UNIT_NPC_FLAGS, 0);
- me->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
- Unit* Illidan = me->SummonCreature(C_ILLIDAN, -5107.83f, 602.584f, 85.2393f, 4.92598f, TEMPSUMMON_CORPSE_DESPAWN, 0);
- if (Illidan)
- {
- IllidanGUID = Illidan->GetGUID();
- Illidan->SetVisible(false);
- }
- if (PlayerGUID)
- {
- Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID);
- if (player)
- Talk(OVERLORD_SAY_1, player);
- }
- ConversationTimer = 4200;
- Step = 0;
- Event = true;
- }
-
- uint32 NextStep(uint32 Step)
- {
- Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID);
- Creature* Illi = ObjectAccessor::GetCreature(*me, IllidanGUID);
-
- if (!player)
- {
- EnterEvadeMode();
- return 0;
- }
-
- switch (Step)
- {
- case 0:
- return 0;
- break;
- case 1:
- me->GetMotionMaster()->MovePoint(0, -5104.41f, 595.297f, 85.6838f);
- return 9000;
- break;
- case 2:
- Talk(OVERLORD_YELL_1, player);
- return 4500;
- break;
- case 3:
- me->SetInFront(player);
- return 3200;
- break;
- case 4:
- Talk(OVERLORD_SAY_2, player);
- return 2000;
- break;
- case 5:
- if (Illi)
- {
- Illi->SetVisible(true);
- Illi->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- Illi->SetDisplayId(21526);
- }
- return 350;
- break;
- case 6:
- if (Illi)
- {
- Illi->CastSpell(Illi, SPELL_ONE, true);
- Illi->SetTarget(me->GetGUID());
- me->SetTarget(IllidanGUID);
- }
- return 2000;
- break;
- case 7:
- Talk(OVERLORD_YELL_2);
- return 4500;
- break;
- case 8:
- me->SetUInt32Value(UNIT_FIELD_BYTES_1, 8);
- return 2500;
- break;
- case 9:
- // missing text "Lord Illidan, this is the Dragonmaw that I, and others, have told you about. He will lead us to victory!"
- return 5000;
- break;
- case 10:
- if (Illi)
- Illi->AI()->Talk(LORD_ILLIDAN_SAY_1);
- return 5000;
- break;
- case 11:
- Talk(OVERLORD_SAY_4, player);
- return 6000;
- break;
- case 12:
- if (Illi)
- Illi->AI()->Talk(LORD_ILLIDAN_SAY_2);
- return 5500;
- break;
- case 13:
- if (Illi)
- Illi->AI()->Talk(LORD_ILLIDAN_SAY_3);
- return 4000;
- break;
- case 14:
- if (Illi)
- Illi->SetTarget(PlayerGUID);
- return 1500;
- break;
- case 15:
- if (Illi)
- Illi->AI()->Talk(LORD_ILLIDAN_SAY_4);
- return 1500;
- break;
- case 16:
- if (Illi)
- Illi->CastSpell(player, SPELL_TWO, true);
- player->RemoveAurasDueToSpell(SPELL_THREE);
- player->RemoveAurasDueToSpell(SPELL_FOUR);
- return 5000;
- break;
- case 17:
- if (Illi)
- Illi->AI()->Talk(LORD_ILLIDAN_SAY_5);
- return 5000;
- break;
- case 18:
- if (Illi)
- Illi->AI()->Talk(LORD_ILLIDAN_SAY_6);
- return 5000;
- break;
- case 19:
- if (Illi)
- Illi->AI()->Talk(LORD_ILLIDAN_SAY_7);
- return 5000;
- break;
- case 20:
- if (Illi)
- {
- Illi->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
- Illi->SetDisableGravity(true);
- }
- return 500;
- break;
- case 21:
- Talk(OVERLORD_SAY_5);
- return 500;
- break;
- case 22:
- if (Illi)
- {
- Illi->SetVisible(false);
- Illi->setDeathState(JUST_DIED);
- }
- return 1000;
- break;
- case 23:
- me->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
- return 2000;
- break;
- case 24:
- me->SetTarget(PlayerGUID);
- return 5000;
- break;
- case 25:
- Talk(OVERLORD_SAY_6);
- return 2000;
- break;
- case 26:
- player->GroupEventHappens(QUEST_LORD_ILLIDAN_STORMRAGE, me);
- return 6000;
- break;
- case 27:
- {
- Unit* Yarzill = me->FindNearestCreature(C_YARZILL, 50.0f);
- if (Yarzill)
- Yarzill->SetTarget(PlayerGUID);
- return 500;
- }
- break;
- case 28:
- player->RemoveAurasDueToSpell(SPELL_TWO);
- player->RemoveAurasDueToSpell(41519);
- player->CastSpell(player, SPELL_THREE, true);
- player->CastSpell(player, SPELL_FOUR, true);
- return 1000;
- break;
- case 29:
- {
- if (Creature* Yarzill = me->FindNearestCreature(C_YARZILL, 50.0f))
- Yarzill->AI()->Talk(YARZILL_THE_MERC_SAY, player);
- return 5000;
- }
- break;
- case 30:
- {
- if (Creature* Yarzill = me->FindNearestCreature(C_YARZILL, 50.0f))
- Yarzill->SetTarget(ObjectGuid::Empty);
- return 5000;
- }
- break;
- case 31:
- {
- if (Creature* Yarzill = me->FindNearestCreature(C_YARZILL, 50.0f))
- Yarzill->CastSpell(player, 41540, true);
- return 1000;
- }
- break;
- case 32:
- me->GetMotionMaster()->MovePoint(0, -5085.77f, 577.231f, 86.6719f);
- return 5000;
- break;
- case 33:
- me->SetTarget(ObjectGuid::Empty);
- Reset();
- return 100;
- break;
- default :
- return 0;
- break;
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!ConversationTimer)
- return;
-
- if (ConversationTimer <= diff)
- {
- if (Event && PlayerGUID)
- ConversationTimer = NextStep(++Step);
- } else ConversationTimer -= diff;
- }
- };
-};
-
-/*####
# npc_earthmender_wilda
####*/
@@ -2026,7 +1700,6 @@ void AddSC_shadowmoon_valley()
new npc_drake_dealer_hurlunk();
new npcs_flanis_swiftwing_and_kagrosh();
new npc_karynaku();
- new npc_overlord_morghor();
new npc_earthmender_wilda();
new npc_lord_illidan_stormrage();
new go_crystal_prison();
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index ee70cca2e50..68c115f9faf 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -34,6 +34,7 @@
#include "Pet.h"
#include "ReputationMgr.h"
#include "SkillDiscovery.h"
+#include "SpellHistory.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
#include "Vehicle.h"
@@ -1293,8 +1294,8 @@ class spell_gen_divine_storm_cd_reset : public SpellScriptLoader
void HandleScript(SpellEffIndex /*effIndex*/)
{
Player* caster = GetCaster()->ToPlayer();
- if (caster->HasSpellCooldown(SPELL_DIVINE_STORM))
- caster->RemoveSpellCooldown(SPELL_DIVINE_STORM, true);
+ if (caster->GetSpellHistory()->HasCooldown(SPELL_DIVINE_STORM))
+ caster->GetSpellHistory()->ResetCooldown(SPELL_DIVINE_STORM, true);
}
void Register() override
@@ -3330,7 +3331,7 @@ class spell_pvp_trinket_wotf_shared_cd : public SpellScriptLoader
{
// This is only needed because spells cast from spell_linked_spell are triggered by default
// Spell::SendSpellCooldown() skips all spells with TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD
- GetCaster()->ToPlayer()->AddSpellAndCategoryCooldowns(GetSpellInfo(), GetCastItem() ? GetCastItem()->GetEntry() : 0, GetSpell());
+ GetCaster()->GetSpellHistory()->StartCooldown(GetSpellInfo(), 0, GetSpell());
}
void Register() override
@@ -3629,6 +3630,43 @@ class spell_gen_eject_all_passengers : public SpellScriptLoader
}
};
+class spell_gen_eject_passenger : public SpellScriptLoader
+{
+ public:
+ spell_gen_eject_passenger() : SpellScriptLoader("spell_gen_eject_passenger") { }
+
+ class spell_gen_eject_passenger_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_gen_eject_passenger_SpellScript);
+
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Effects[EFFECT_0].CalcValue() < 1)
+ return false;
+ return true;
+ }
+
+ void EjectPassenger(SpellEffIndex /*effIndex*/)
+ {
+ if (Vehicle* vehicle = GetHitUnit()->GetVehicleKit())
+ {
+ if (Unit* passenger = vehicle->GetPassenger(GetEffectValue() - 1))
+ passenger->ExitVehicle();
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_gen_eject_passenger_SpellScript::EjectPassenger, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_gen_eject_passenger_SpellScript();
+ }
+};
+
enum GMFreeze
{
SPELL_GM_FREEZE = 9454
@@ -4121,6 +4159,7 @@ void AddSC_generic_spell_scripts()
new spell_gen_wg_water();
new spell_gen_whisper_gulch_yogg_saron_whisper();
new spell_gen_eject_all_passengers();
+ new spell_gen_eject_passenger();
new spell_gen_gm_freeze();
new spell_gen_stand();
new spell_gen_mixology_bonus();
diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp
index 3ee337f81d4..75df264360f 100644
--- a/src/server/scripts/Spells/spell_hunter.cpp
+++ b/src/server/scripts/Spells/spell_hunter.cpp
@@ -27,6 +27,7 @@
#include "CellImpl.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
+#include "SpellHistory.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
@@ -246,7 +247,7 @@ class spell_hun_chimera_shot : public SpellScriptLoader
if (spellId)
caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, true);
if (spellId == SPELL_HUNTER_CHIMERA_SHOT_SCORPID && caster->ToPlayer()) // Scorpid Sting - Add 1 minute cooldown
- caster->ToPlayer()->AddSpellCooldown(spellId, 0, uint32(time(NULL) + 60));
+ caster->GetSpellHistory()->AddCooldown(spellId, 0, std::chrono::minutes(1));
}
}
@@ -654,24 +655,20 @@ class spell_hun_readiness : public SpellScriptLoader
void HandleDummy(SpellEffIndex /*effIndex*/)
{
- Player* caster = GetCaster()->ToPlayer();
// immediately finishes the cooldown on your other Hunter abilities except Bestial Wrath
- const SpellCooldowns& cm = caster->ToPlayer()->GetSpellCooldownMap();
- for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
+ GetCaster()->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
+ SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
///! If spellId in cooldown map isn't valid, the above will return a null pointer.
- if (spellInfo &&
- spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER &&
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER &&
spellInfo->Id != SPELL_HUNTER_READINESS &&
spellInfo->Id != SPELL_HUNTER_BESTIAL_WRATH &&
spellInfo->Id != SPELL_DRAENEI_GIFT_OF_THE_NAARU &&
spellInfo->GetRecoveryTime() > 0)
- caster->RemoveSpellCooldown((itr++)->first, true);
- else
- ++itr;
- }
+ return true;
+ return false;
+ }, true);
}
void Register() override
diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp
index 9843a472971..717382a0e36 100644
--- a/src/server/scripts/Spells/spell_item.cpp
+++ b/src/server/scripts/Spells/spell_item.cpp
@@ -24,6 +24,7 @@
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellHistory.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
#include "SkillDiscovery.h"
@@ -477,7 +478,7 @@ class spell_item_flask_of_the_north : public SpellScriptLoader
break;
}
- caster->CastSpell(caster, possibleSpells[irand(0, (possibleSpells.size() - 1))], true, NULL);
+ caster->CastSpell(caster, possibleSpells[urand(0, (possibleSpells.size() - 1))], true, NULL);
}
void Register() override
@@ -1349,7 +1350,7 @@ class spell_item_red_rider_air_rifle : public SpellScriptLoader
caster->CastSpell(caster, SPELL_AIR_RIFLE_HOLD_VISUAL, true);
// needed because this spell shares GCD with its triggered spells (which must not be cast with triggered flag)
if (Player* player = caster->ToPlayer())
- player->GetGlobalCooldownMgr().CancelGlobalCooldown(GetSpellInfo());
+ player->GetSpellHistory()->CancelGlobalCooldown(GetSpellInfo());
if (urand(0, 4))
caster->CastSpell(target, SPELL_AIR_RIFLE_SHOOT, false);
else
@@ -2368,7 +2369,7 @@ class spell_item_rocket_boots : public SpellScriptLoader
if (Battleground* bg = caster->GetBattleground())
bg->EventPlayerDroppedFlag(caster);
- caster->RemoveSpellCooldown(SPELL_ROCKET_BOOTS_PROC);
+ caster->GetSpellHistory()->ResetCooldown(SPELL_ROCKET_BOOTS_PROC);
caster->CastSpell(caster, SPELL_ROCKET_BOOTS_PROC, true, NULL);
}
@@ -2548,14 +2549,14 @@ class spell_item_refocus : public SpellScriptLoader
if (!caster || caster->getClass() != CLASS_HUNTER)
return;
- if (caster->HasSpellCooldown(SPELL_AIMED_SHOT))
- caster->RemoveSpellCooldown(SPELL_AIMED_SHOT, true);
+ if (caster->GetSpellHistory()->HasCooldown(SPELL_AIMED_SHOT))
+ caster->GetSpellHistory()->ResetCooldown(SPELL_AIMED_SHOT, true);
- if (caster->HasSpellCooldown(SPELL_MULTISHOT))
- caster->RemoveSpellCooldown(SPELL_MULTISHOT, true);
+ if (caster->GetSpellHistory()->HasCooldown(SPELL_MULTISHOT))
+ caster->GetSpellHistory()->ResetCooldown(SPELL_MULTISHOT, true);
- if (caster->HasSpellCooldown(SPELL_VOLLEY))
- caster->RemoveSpellCooldown(SPELL_VOLLEY, true);
+ if (caster->GetSpellHistory()->HasCooldown(SPELL_VOLLEY))
+ caster->GetSpellHistory()->ResetCooldown(SPELL_VOLLEY, true);
}
void Register() override
diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp
index ba9f66d255b..4edbf8822f7 100644
--- a/src/server/scripts/Spells/spell_mage.cpp
+++ b/src/server/scripts/Spells/spell_mage.cpp
@@ -23,6 +23,7 @@
#include "Player.h"
#include "ScriptMgr.h"
+#include "SpellHistory.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
@@ -171,22 +172,12 @@ class spell_mage_cold_snap : public SpellScriptLoader
void HandleDummy(SpellEffIndex /*effIndex*/)
{
- Player* caster = GetCaster()->ToPlayer();
- // immediately finishes the cooldown on Frost spells
- const SpellCooldowns& cm = caster->GetSpellCooldownMap();
- for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
+ GetCaster()->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool
{
SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
-
- if (spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
- (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) &&
- spellInfo->Id != SPELL_MAGE_COLD_SNAP && spellInfo->GetRecoveryTime() > 0)
- {
- caster->RemoveSpellCooldown((itr++)->first, true);
- }
- else
- ++itr;
- }
+ return spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) &&
+ spellInfo->Id != SPELL_MAGE_COLD_SNAP && spellInfo->GetRecoveryTime() > 0;
+ }, true);
}
void Register() override
diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp
index cf320a05346..197d55486a8 100644
--- a/src/server/scripts/Spells/spell_paladin.cpp
+++ b/src/server/scripts/Spells/spell_paladin.cpp
@@ -25,6 +25,7 @@
#include "ScriptMgr.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
+#include "SpellHistory.h"
#include "Group.h"
enum PaladinSpells
@@ -133,7 +134,7 @@ class spell_pal_ardent_defender : public SpellScriptLoader
int32 remainingHealth = victim->GetHealth() - dmgInfo.GetDamage();
uint32 allowedHealth = victim->CountPctFromMaxHealth(35);
// If damage kills us
- if (remainingHealth <= 0 && !victim->ToPlayer()->HasSpellCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL))
+ if (remainingHealth <= 0 && !victim->GetSpellHistory()->HasCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL))
{
// Cast healing spell, completely avoid damage
absorbAmount = dmgInfo.GetDamage();
@@ -148,7 +149,7 @@ class spell_pal_ardent_defender : public SpellScriptLoader
int32 healAmount = int32(victim->CountPctFromMaxHealth(uint32(healPct * pctFromDefense)));
victim->CastCustomSpell(victim, PAL_SPELL_ARDENT_DEFENDER_HEAL, &healAmount, NULL, NULL, true, NULL, aurEff);
- victim->ToPlayer()->AddSpellCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL, 0, time(NULL) + 120);
+ victim->GetSpellHistory()->AddCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL, 0, std::chrono::minutes(2));
}
else if (remainingHealth < int32(allowedHealth))
{
diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp
index 629630d0bef..60ff67d74c0 100644
--- a/src/server/scripts/Spells/spell_quest.cpp
+++ b/src/server/scripts/Spells/spell_quest.cpp
@@ -208,22 +208,23 @@ class spell_q6124_6129_apply_salve : public SpellScriptLoader
if (GetCastItem())
if (Creature* creatureTarget = GetHitCreature())
{
- uint32 uiNewEntry = 0;
+ uint32 newEntry = 0;
switch (caster->GetTeam())
{
case HORDE:
if (creatureTarget->GetEntry() == NPC_SICKLY_GAZELLE)
- uiNewEntry = NPC_CURED_GAZELLE;
+ newEntry = NPC_CURED_GAZELLE;
break;
case ALLIANCE:
if (creatureTarget->GetEntry() == NPC_SICKLY_DEER)
- uiNewEntry = NPC_CURED_DEER;
+ newEntry = NPC_CURED_DEER;
break;
}
- if (uiNewEntry)
+ if (newEntry)
{
- creatureTarget->UpdateEntry(uiNewEntry);
+ creatureTarget->UpdateEntry(newEntry);
creatureTarget->DespawnOrUnsummon(DESPAWN_TIME);
+ caster->KilledMonsterCredit(newEntry);
}
}
}
@@ -338,7 +339,7 @@ class spell_q11396_11399_scourging_crystal_controller : public SpellScriptLoader
SpellScript* GetSpellScript() const override
{
return new spell_q11396_11399_scourging_crystal_controller_SpellScript();
- };
+ }
};
// 43882 Scourging Crystal Controller Dummy
@@ -374,7 +375,7 @@ class spell_q11396_11399_scourging_crystal_controller_dummy : public SpellScript
SpellScript* GetSpellScript() const override
{
return new spell_q11396_11399_scourging_crystal_controller_dummy_SpellScript();
- };
+ }
};
// http://www.wowhead.com/quest=11515 Blood for Blood
@@ -855,7 +856,7 @@ class spell_symbol_of_life_dummy : public SpellScriptLoader
SpellScript* GetSpellScript() const override
{
return new spell_symbol_of_life_dummy_SpellScript();
- };
+ }
};
// http://www.wowhead.com/quest=12659 Scalps!
@@ -898,7 +899,7 @@ class spell_q12659_ahunaes_knife : public SpellScriptLoader
SpellScript* GetSpellScript() const override
{
return new spell_q12659_ahunaes_knife_SpellScript();
- };
+ }
};
enum StoppingTheSpread
@@ -944,7 +945,7 @@ class spell_q9874_liquid_fire : public SpellScriptLoader
SpellScript* GetSpellScript() const override
{
return new spell_q9874_liquid_fire_SpellScript();
- };
+ }
};
enum SalvagingLifesStength
@@ -988,7 +989,7 @@ class spell_q12805_lifeblood_dummy : public SpellScriptLoader
SpellScript* GetSpellScript() const override
{
return new spell_q12805_lifeblood_dummy_SpellScript();
- };
+ }
};
/*
@@ -2422,6 +2423,36 @@ class spell_q10929_fumping : SpellScriptLoader
}
};
+class spell_q12414_hand_over_reins : public SpellScriptLoader
+{
+ public:
+ spell_q12414_hand_over_reins() : SpellScriptLoader("spell_q12414_hand_over_reins") { }
+
+ class spell_q12414_hand_over_reins_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_q12414_hand_over_reins_SpellScript);
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Creature* caster = GetCaster()->ToCreature();
+ GetHitUnit()->ExitVehicle();
+
+ if (caster)
+ caster->DespawnOrUnsummon();
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_q12414_hand_over_reins_SpellScript::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_q12414_hand_over_reins_SpellScript();
+ }
+};
+
void AddSC_quest_spell_scripts()
{
new spell_q55_sacred_cleansing();
@@ -2480,4 +2511,5 @@ void AddSC_quest_spell_scripts()
new spell_q13400_illidan_kill_master();
new spell_q14100_q14111_make_player_destroy_totems();
new spell_q10929_fumping();
+ new spell_q12414_hand_over_reins();
}
diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp
index edb5cd5260c..da50f471f1c 100644
--- a/src/server/scripts/Spells/spell_rogue.cpp
+++ b/src/server/scripts/Spells/spell_rogue.cpp
@@ -25,6 +25,7 @@
#include "ScriptMgr.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
+#include "SpellHistory.h"
#include "Containers.h"
enum RogueSpells
@@ -139,11 +140,11 @@ class spell_rog_cheat_death : public SpellScriptLoader
void Absorb(AuraEffect* /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount)
{
Player* target = GetTarget()->ToPlayer();
- if (dmgInfo.GetDamage() < target->GetHealth() || target->HasSpellCooldown(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN) || !roll_chance_i(absorbChance))
+ if (dmgInfo.GetDamage() < target->GetHealth() || target->GetSpellHistory()->HasCooldown(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN) || !roll_chance_i(absorbChance))
return;
target->CastSpell(target, SPELL_ROGUE_CHEAT_DEATH_COOLDOWN, true);
- target->AddSpellCooldown(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN, 0, time(NULL) + 60);
+ target->GetSpellHistory()->AddCooldown(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN, 0, std::chrono::minutes(1));
uint32 health10 = target->CountPctFromMaxHealth(10);
@@ -443,35 +444,21 @@ class spell_rog_preparation : public SpellScriptLoader
void HandleDummy(SpellEffIndex /*effIndex*/)
{
- Player* caster = GetCaster()->ToPlayer();
-
- //immediately finishes the cooldown on certain Rogue abilities
- const SpellCooldowns& cm = caster->GetSpellCooldownMap();
- for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
+ Unit* caster = GetCaster();
+ caster->GetSpellHistory()->ResetCooldowns([caster](SpellHistory::CooldownStorageType::iterator itr) -> bool
{
SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(itr->first);
-
- if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE)
- {
- if (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_COLDB_SHADOWSTEP || // Cold Blood, Shadowstep
- spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VAN_EVAS_SPRINT) // Vanish, Evasion, Sprint
- caster->RemoveSpellCooldown((itr++)->first, true);
- else if (caster->HasAura(SPELL_ROGUE_GLYPH_OF_PREPARATION))
- {
- if (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_DISMANTLE || // Dismantle
- spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_KICK || // Kick
- (spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_BLADE_FLURRY && // Blade Flurry
- spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_BLADE_FLURRY))
- caster->RemoveSpellCooldown((itr++)->first, true);
- else
- ++itr;
- }
- else
- ++itr;
- }
- else
- ++itr;
- }
+ if (spellInfo->SpellFamilyName != SPELLFAMILY_ROGUE)
+ return false;
+
+ return (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_COLDB_SHADOWSTEP || // Cold Blood, Shadowstep
+ spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VAN_EVAS_SPRINT) || // Vanish, Evasion, Sprint
+ (caster->HasAura(SPELL_ROGUE_GLYPH_OF_PREPARATION) &&
+ (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_DISMANTLE || // Dismantle
+ spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_KICK || // Kick
+ (spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_BLADE_FLURRY && // Blade Flurry
+ spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_BLADE_FLURRY)));
+ }, true);
}
void Register() override
diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp
index 2ee0d5091b5..5564a8275c8 100644
--- a/src/server/scripts/Spells/spell_shaman.cpp
+++ b/src/server/scripts/Spells/spell_shaman.cpp
@@ -25,6 +25,7 @@
#include "ScriptMgr.h"
#include "GridNotifiers.h"
#include "Unit.h"
+#include "SpellHistory.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
@@ -338,7 +339,7 @@ class spell_sha_earth_shield : public SpellScriptLoader
{
//! HACK due to currenct proc system implementation
if (Player* player = GetTarget()->ToPlayer())
- if (player->HasSpellCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL))
+ if (player->GetSpellHistory()->HasCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL))
return false;
return true;
}
@@ -351,7 +352,7 @@ class spell_sha_earth_shield : public SpellScriptLoader
/// @hack: due to currenct proc system implementation
if (Player* player = GetTarget()->ToPlayer())
- player->AddSpellCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL, 0, time(NULL) + 3);
+ player->GetSpellHistory()->AddCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL, 0, std::chrono::seconds(3));
}
void Register() override
@@ -804,7 +805,7 @@ class spell_sha_item_t10_elemental_2p_bonus : public SpellScriptLoader
{
PreventDefaultAction();
if (Player* target = GetTarget()->ToPlayer())
- target->ModifySpellCooldown(SPELL_SHAMAN_ELEMENTAL_MASTERY, -aurEff->GetAmount());
+ target->GetSpellHistory()->ModifyCooldown(SPELL_SHAMAN_ELEMENTAL_MASTERY, -aurEff->GetAmount());
}
void Register() override
diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp
index fa2b323e220..c7839a59608 100644
--- a/src/server/scripts/Spells/spell_warrior.cpp
+++ b/src/server/scripts/Spells/spell_warrior.cpp
@@ -23,6 +23,7 @@
#include "Player.h"
#include "ScriptMgr.h"
+#include "SpellHistory.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
@@ -847,7 +848,7 @@ class spell_warr_vigilance_trigger : public SpellScriptLoader
// Remove Taunt cooldown
if (Player* target = GetHitPlayer())
- target->RemoveSpellCooldown(SPELL_WARRIOR_TAUNT, true);
+ target->GetSpellHistory()->ResetCooldown(SPELL_WARRIOR_TAUNT, true);
}
void Register() override
diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp
index 93010f06283..d1d2ddc8a80 100644
--- a/src/server/scripts/World/npcs_special.cpp
+++ b/src/server/scripts/World/npcs_special.cpp
@@ -53,6 +53,7 @@ EndContentData */
#include "GridNotifiersImpl.h"
#include "Cell.h"
#include "CellImpl.h"
+#include "SpellHistory.h"
#include "SpellAuras.h"
#include "Pet.h"
#include "CreatureTextMgr.h"
@@ -1214,14 +1215,14 @@ public:
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
- if (player->HasSpellCooldown(SPELL_INT) ||
- player->HasSpellCooldown(SPELL_ARM) ||
- player->HasSpellCooldown(SPELL_DMG) ||
- player->HasSpellCooldown(SPELL_RES) ||
- player->HasSpellCooldown(SPELL_STR) ||
- player->HasSpellCooldown(SPELL_AGI) ||
- player->HasSpellCooldown(SPELL_STM) ||
- player->HasSpellCooldown(SPELL_SPI))
+ if (player->GetSpellHistory()->HasCooldown(SPELL_INT) ||
+ player->GetSpellHistory()->HasCooldown(SPELL_ARM) ||
+ player->GetSpellHistory()->HasCooldown(SPELL_DMG) ||
+ player->GetSpellHistory()->HasCooldown(SPELL_RES) ||
+ player->GetSpellHistory()->HasCooldown(SPELL_STR) ||
+ player->GetSpellHistory()->HasCooldown(SPELL_AGI) ||
+ player->GetSpellHistory()->HasCooldown(SPELL_STM) ||
+ player->GetSpellHistory()->HasCooldown(SPELL_SPI))
player->SEND_GOSSIP_MENU(7393, creature->GetGUID());
else
{
@@ -1281,52 +1282,44 @@ public:
bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) override
{
player->PlayerTalkClass->ClearMenus();
+ uint32 spellId = 0;
switch (sender)
{
case GOSSIP_SENDER_MAIN:
SendAction(player, creature, action);
break;
case GOSSIP_SENDER_MAIN + 1:
- creature->CastSpell(player, SPELL_DMG, false);
- player->AddSpellCooldown(SPELL_DMG, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_DMG;
break;
case GOSSIP_SENDER_MAIN + 2:
- creature->CastSpell(player, SPELL_RES, false);
- player->AddSpellCooldown(SPELL_RES, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_RES;
break;
case GOSSIP_SENDER_MAIN + 3:
- creature->CastSpell(player, SPELL_ARM, false);
- player->AddSpellCooldown(SPELL_ARM, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_ARM;
break;
case GOSSIP_SENDER_MAIN + 4:
- creature->CastSpell(player, SPELL_SPI, false);
- player->AddSpellCooldown(SPELL_SPI, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_SPI;
break;
case GOSSIP_SENDER_MAIN + 5:
- creature->CastSpell(player, SPELL_INT, false);
- player->AddSpellCooldown(SPELL_INT, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_INT;
break;
case GOSSIP_SENDER_MAIN + 6:
- creature->CastSpell(player, SPELL_STM, false);
- player->AddSpellCooldown(SPELL_STM, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_STM;
break;
case GOSSIP_SENDER_MAIN + 7:
- creature->CastSpell(player, SPELL_STR, false);
- player->AddSpellCooldown(SPELL_STR, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_STR;
break;
case GOSSIP_SENDER_MAIN + 8:
- creature->CastSpell(player, SPELL_AGI, false);
- player->AddSpellCooldown(SPELL_AGI, 0, time(NULL) + 7200);
- SendAction(player, creature, action);
+ spellId = SPELL_AGI;
break;
}
+
+ if (spellId)
+ {
+ creature->CastSpell(player, spellId, false);
+ player->GetSpellHistory()->AddCooldown(spellId, 0, std::chrono::hours(2));
+ SendAction(player, creature, action);
+ }
return true;
}
};
diff --git a/src/server/shared/CMakeLists.txt b/src/server/shared/CMakeLists.txt
index fb86ac7db18..abc019863b1 100644
--- a/src/server/shared/CMakeLists.txt
+++ b/src/server/shared/CMakeLists.txt
@@ -21,6 +21,7 @@ file(GLOB_RECURSE sources_Logging Logging/*.cpp Logging/*.h)
file(GLOB_RECURSE sources_Networking Networking/*.cpp Networking/*.h)
file(GLOB_RECURSE sources_Packets Packets/*.cpp Packets/*.h)
file(GLOB_RECURSE sources_Threading Threading/*.cpp Threading/*.h)
+file(GLOB_RECURSE sources_Updater Updater/*.cpp Updater/*.h)
file(GLOB_RECURSE sources_Utilities Utilities/*.cpp Utilities/*.h)
file(GLOB sources_localdir *.cpp *.h)
@@ -51,6 +52,7 @@ set(shared_STAT_SRCS
${sources_Networking}
${sources_Packets}
${sources_Threading}
+ ${sources_Updater}
${sources_Utilities}
${sources_localdir}
)
@@ -59,8 +61,9 @@ include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
${CMAKE_SOURCE_DIR}/dep/SFMT
- ${CMAKE_SOURCE_DIR}/dep/sockets/include
+ ${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/utf8cpp
+ ${CMAKE_SOURCE_DIR}/dep/process
${CMAKE_SOURCE_DIR}/src/server
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/Configuration
@@ -74,12 +77,15 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/Packets
${CMAKE_CURRENT_SOURCE_DIR}/Threading
${CMAKE_CURRENT_SOURCE_DIR}/Utilities
+ ${CMAKE_CURRENT_SOURCE_DIR}/Updater
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object
${MYSQL_INCLUDE_DIR}
${OPENSSL_INCLUDE_DIR}
${VALGRIND_INCLUDE_DIR}
)
+GroupSources(${CMAKE_CURRENT_SOURCE_DIR})
+
add_library(shared STATIC
${shared_STAT_SRCS}
${shared_STAT_PCH_SRC}
diff --git a/src/server/shared/Configuration/Config.cpp b/src/server/shared/Configuration/Config.cpp
index 1e1f8c7c3c6..ea426a5d33e 100644
--- a/src/server/shared/Configuration/Config.cpp
+++ b/src/server/shared/Configuration/Config.cpp
@@ -21,7 +21,6 @@
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include "Config.h"
-#include "Errors.h"
using namespace boost::property_tree;
diff --git a/src/server/shared/Cryptography/ARC4.cpp b/src/server/shared/Cryptography/ARC4.cpp
index 28c3da8d228..d1082b39347 100644
--- a/src/server/shared/Cryptography/ARC4.cpp
+++ b/src/server/shared/Cryptography/ARC4.cpp
@@ -17,7 +17,6 @@
*/
#include "ARC4.h"
-#include <openssl/sha.h>
ARC4::ARC4(uint8 len) : m_ctx()
{
diff --git a/src/server/shared/Cryptography/BigNumber.cpp b/src/server/shared/Cryptography/BigNumber.cpp
index 434268097fe..720e8e30441 100644
--- a/src/server/shared/Cryptography/BigNumber.cpp
+++ b/src/server/shared/Cryptography/BigNumber.cpp
@@ -18,7 +18,6 @@
#include "Cryptography/BigNumber.h"
#include <openssl/bn.h>
-#include <openssl/crypto.h>
#include <cstring>
#include <algorithm>
#include <memory>
@@ -171,19 +170,20 @@ bool BigNumber::isZero() const
std::unique_ptr<uint8[]> BigNumber::AsByteArray(int32 minSize, bool littleEndian)
{
- int length = (minSize >= GetNumBytes()) ? minSize : GetNumBytes();
+ int numBytes = GetNumBytes();
+ int length = (minSize >= numBytes) ? minSize : numBytes;
uint8* array = new uint8[length];
// If we need more bytes than length of BigNumber set the rest to 0
- if (length > GetNumBytes())
+ if (length > numBytes)
memset((void*)array, 0, length);
BN_bn2bin(_bn, (unsigned char *)array);
// openssl's BN stores data internally in big endian format, reverse if little endian desired
if (littleEndian)
- std::reverse(array, array + length);
+ std::reverse(array, array + numBytes);
std::unique_ptr<uint8[]> ret(array);
return ret;
diff --git a/src/server/shared/Cryptography/SHA1.h b/src/server/shared/Cryptography/SHA1.h
index ebd9f721d4a..f59bdc25556 100644
--- a/src/server/shared/Cryptography/SHA1.h
+++ b/src/server/shared/Cryptography/SHA1.h
@@ -39,8 +39,8 @@ class SHA1Hash
void Initialize();
void Finalize();
- uint8 *GetDigest(void) { return mDigest; };
- int GetLength(void) const { return SHA_DIGEST_LENGTH; };
+ uint8 *GetDigest(void) { return mDigest; }
+ int GetLength(void) const { return SHA_DIGEST_LENGTH; }
private:
SHA_CTX mC;
diff --git a/src/server/shared/Database/AdhocStatement.h b/src/server/shared/Database/AdhocStatement.h
index 8d9365900d9..8195d9add98 100644
--- a/src/server/shared/Database/AdhocStatement.h
+++ b/src/server/shared/Database/AdhocStatement.h
@@ -40,4 +40,4 @@ class BasicStatementTask : public SQLOperation
QueryResultPromise* m_result;
};
-#endif \ No newline at end of file
+#endif
diff --git a/src/server/shared/Database/DatabaseLoader.cpp b/src/server/shared/Database/DatabaseLoader.cpp
new file mode 100644
index 00000000000..36ee4b12c83
--- /dev/null
+++ b/src/server/shared/Database/DatabaseLoader.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "DatabaseLoader.h"
+#include "DBUpdater.h"
+#include "Config.h"
+
+#include <mysqld_error.h>
+
+DatabaseLoader::DatabaseLoader(std::string const& logger, uint32 const defaultUpdateMask)
+ : _logger(logger), _autoSetup(sConfigMgr->GetBoolDefault("Updates.AutoSetup", true)),
+ _updateFlags(sConfigMgr->GetIntDefault("Updates.EnableDatabases", defaultUpdateMask))
+{
+}
+
+template <class T>
+DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::string const& name)
+{
+ bool const updatesEnabledForThis = DBUpdater<T>::IsEnabled(_updateFlags);
+
+ _open.push(std::make_pair([this, name, updatesEnabledForThis, &pool]() -> bool
+ {
+ std::string const dbString = sConfigMgr->GetStringDefault(name + "DatabaseInfo", "");
+ if (dbString.empty())
+ {
+ TC_LOG_ERROR(_logger.c_str(), "Database %s not specified in configuration file!", name.c_str());
+ return false;
+ }
+
+ uint8 const asyncThreads = uint8(sConfigMgr->GetIntDefault(name + "Database.WorkerThreads", 1));
+ if (asyncThreads < 1 || asyncThreads > 32)
+ {
+ TC_LOG_ERROR(_logger.c_str(), "%s database: invalid number of worker threads specified. "
+ "Please pick a value between 1 and 32.", name.c_str());
+ return false;
+ }
+
+ uint8 const synchThreads = uint8(sConfigMgr->GetIntDefault(name + "Database.SynchThreads", 1));
+
+ pool.SetConnectionInfo(dbString, asyncThreads, synchThreads);
+ if (uint32 error = pool.Open())
+ {
+ // Database does not exist
+ if ((error == ER_BAD_DB_ERROR) && updatesEnabledForThis && _autoSetup)
+ {
+ // Try to create the database and connect again if auto setup is enabled
+ if (DBUpdater<T>::Create(pool) && (!pool.Open()))
+ error = 0;
+ }
+
+ // If the error wasn't handled quit
+ if (error)
+ {
+ TC_LOG_ERROR("sql.driver", "\nDatabasePool %s NOT opened. There were errors opening the MySQL connections. Check your SQLDriverLogFile "
+ "for specific errors. Read wiki at http://collab.kpsn.org/display/tc/TrinityCore+Home", name.c_str());
+
+ return false;
+ }
+ }
+ return true;
+ },
+ [&pool]()
+ {
+ pool.Close();
+ }));
+
+ // Populate and update only if updates are enabled for this pool
+ if (updatesEnabledForThis)
+ {
+ _populate.push([this, name, &pool]() -> bool
+ {
+ if (!DBUpdater<T>::Populate(pool))
+ {
+ TC_LOG_ERROR(_logger.c_str(), "Could not populate the %s database, see log for details.", name.c_str());
+ return false;
+ }
+ return true;
+ });
+
+ _update.push([this, name, &pool]() -> bool
+ {
+ if (!DBUpdater<T>::Update(pool))
+ {
+ TC_LOG_ERROR(_logger.c_str(), "Could not update the %s database, see log for details.", name.c_str());
+ return false;
+ }
+ return true;
+ });
+ }
+
+ _prepare.push([this, name, &pool]() -> bool
+ {
+ if (!pool.PrepareStatements())
+ {
+ TC_LOG_ERROR(_logger.c_str(), "Could not prepare statements of the %s database, see log for details.", name.c_str());
+ return false;
+ }
+ return true;
+ });
+
+ return *this;
+}
+
+bool DatabaseLoader::Load()
+{
+ if (!OpenDatabases())
+ return false;
+
+ if (!PopulateDatabases())
+ return false;
+
+ if (!UpdateDatabases())
+ return false;
+
+ if (!PrepareStatements())
+ return false;
+
+ return true;
+}
+
+bool DatabaseLoader::OpenDatabases()
+{
+ while (!_open.empty())
+ {
+ std::pair<Predicate, std::function<void()>> const load = _open.top();
+ if (load.first())
+ _close.push(load.second);
+ else
+ {
+ // Close all loaded databases
+ while (!_close.empty())
+ {
+ _close.top()();
+ _close.pop();
+ }
+ return false;
+ }
+
+ _open.pop();
+ }
+ return true;
+}
+
+// Processes the elements of the given stack until a predicate returned false.
+bool DatabaseLoader::Process(std::stack<Predicate>& stack)
+{
+ while (!stack.empty())
+ {
+ if (!stack.top()())
+ return false;
+
+ stack.pop();
+ }
+ return true;
+}
+
+bool DatabaseLoader::PopulateDatabases()
+{
+ return Process(_populate);
+}
+
+bool DatabaseLoader::UpdateDatabases()
+{
+ return Process(_update);
+}
+
+bool DatabaseLoader::PrepareStatements()
+{
+ return Process(_prepare);
+}
+
+template
+DatabaseLoader& DatabaseLoader::AddDatabase<LoginDatabaseConnection>(DatabaseWorkerPool<LoginDatabaseConnection>& pool, std::string const& name);
+template
+DatabaseLoader& DatabaseLoader::AddDatabase<WorldDatabaseConnection>(DatabaseWorkerPool<WorldDatabaseConnection>& pool, std::string const& name);
+template
+DatabaseLoader& DatabaseLoader::AddDatabase<CharacterDatabaseConnection>(DatabaseWorkerPool<CharacterDatabaseConnection>& pool, std::string const& name);
diff --git a/src/server/shared/Database/DatabaseLoader.h b/src/server/shared/Database/DatabaseLoader.h
new file mode 100644
index 00000000000..d35597ba807
--- /dev/null
+++ b/src/server/shared/Database/DatabaseLoader.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DatabaseLoader_h__
+#define DatabaseLoader_h__
+
+#include "DatabaseWorkerPool.h"
+#include "DatabaseEnv.h"
+
+#include <stack>
+#include <functional>
+
+// A helper class to initiate all database worker pools,
+// handles updating, delays preparing of statements and cleans up on failure.
+class DatabaseLoader
+{
+public:
+ DatabaseLoader(std::string const& logger, uint32 const defaultUpdateMask);
+
+ // Register a database to the loader (lazy implemented)
+ template <class T>
+ DatabaseLoader& AddDatabase(DatabaseWorkerPool<T>& pool, std::string const& name);
+
+ // Load all databases
+ bool Load();
+
+ enum DatabaseTypeFlags
+ {
+ DATABASE_NONE = 0,
+
+ DATABASE_LOGIN = 1,
+ DATABASE_CHARACTER = 2,
+ DATABASE_WORLD = 4,
+
+ DATABASE_MASK_ALL = DATABASE_LOGIN | DATABASE_CHARACTER | DATABASE_WORLD
+ };
+
+private:
+ bool OpenDatabases();
+ bool PopulateDatabases();
+ bool UpdateDatabases();
+ bool PrepareStatements();
+
+ using Predicate = std::function<bool()>;
+
+ static bool Process(std::stack<Predicate>& stack);
+
+ std::string const _logger;
+ bool const _autoSetup;
+ uint32 const _updateFlags;
+
+ std::stack<std::pair<Predicate, std::function<void()>>> _open;
+ std::stack<std::function<void()>> _close;
+ std::stack<Predicate> _populate, _update, _prepare;
+};
+
+#endif // DatabaseLoader_h__
diff --git a/src/server/shared/Database/DatabaseWorker.cpp b/src/server/shared/Database/DatabaseWorker.cpp
index 1fe638552a0..56757ce12a0 100644
--- a/src/server/shared/Database/DatabaseWorker.cpp
+++ b/src/server/shared/Database/DatabaseWorker.cpp
@@ -18,8 +18,6 @@
#include "DatabaseEnv.h"
#include "DatabaseWorker.h"
#include "SQLOperation.h"
-#include "MySQLConnection.h"
-#include "MySQLThreading.h"
#include "ProducerConsumerQueue.h"
DatabaseWorker::DatabaseWorker(ProducerConsumerQueue<SQLOperation*>* newQueue, MySQLConnection* connection)
diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h
index f0ddbe91ad8..6bc204fbf76 100644
--- a/src/server/shared/Database/DatabaseWorkerPool.h
+++ b/src/server/shared/Database/DatabaseWorkerPool.h
@@ -28,8 +28,10 @@
#include "QueryResult.h"
#include "QueryHolder.h"
#include "AdhocStatement.h"
+#include "StringFormat.h"
#include <mysqld_error.h>
+#include <memory>
#define MIN_MYSQL_SERVER_VERSION 50100u
#define MIN_MYSQL_CLIENT_VERSION 50100u
@@ -57,9 +59,9 @@ class DatabaseWorkerPool
public:
/* Activity state */
- DatabaseWorkerPool() : _connectionInfo(NULL)
+ DatabaseWorkerPool() : _queue(new ProducerConsumerQueue<SQLOperation*>()),
+ _async_threads(0), _synch_threads(0)
{
- _queue = new ProducerConsumerQueue<SQLOperation*>();
memset(_connectionCount, 0, sizeof(_connectionCount));
_connections.resize(IDX_SIZE);
@@ -70,31 +72,37 @@ class DatabaseWorkerPool
~DatabaseWorkerPool()
{
_queue->Cancel();
+ }
- delete _queue;
+ void SetConnectionInfo(std::string const& infoString, uint8 const asyncThreads, uint8 const synchThreads)
+ {
+ _connectionInfo.reset(new MySQLConnectionInfo(infoString));
- delete _connectionInfo;
+ _async_threads = asyncThreads;
+ _synch_threads = synchThreads;
}
- bool Open(const std::string& infoString, uint8 async_threads, uint8 synch_threads)
+ uint32 Open()
{
- _connectionInfo = new MySQLConnectionInfo(infoString);
+ WPFatal(_connectionInfo.get(), "Connection info was not set!");
TC_LOG_INFO("sql.driver", "Opening DatabasePool '%s'. Asynchronous connections: %u, synchronous connections: %u.",
- GetDatabaseName(), async_threads, synch_threads);
+ GetDatabaseName(), _async_threads, _synch_threads);
- bool res = OpenConnections(IDX_ASYNC, async_threads);
+ uint32 error = OpenConnections(IDX_ASYNC, _async_threads);
- if (!res)
- return res;
+ if (error)
+ return error;
- res = OpenConnections(IDX_SYNCH, synch_threads);
+ error = OpenConnections(IDX_SYNCH, _synch_threads);
- if (res)
+ if (!error)
+ {
TC_LOG_INFO("sql.driver", "DatabasePool '%s' opened successfully. %u total connections running.", GetDatabaseName(),
(_connectionCount[IDX_SYNCH] + _connectionCount[IDX_ASYNC]));
+ }
- return res;
+ return error;
}
void Close()
@@ -120,6 +128,32 @@ class DatabaseWorkerPool
TC_LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName());
}
+ //! Prepares all prepared statements
+ bool PrepareStatements()
+ {
+ for (uint8 i = 0; i < IDX_SIZE; ++i)
+ for (uint32 c = 0; c < _connectionCount[i]; ++c)
+ {
+ T* t = _connections[i][c];
+ t->LockIfReady();
+ if (!t->PrepareStatements())
+ {
+ t->Unlock();
+ Close();
+ return false;
+ }
+ else
+ t->Unlock();
+ }
+
+ return true;
+ }
+
+ inline MySQLConnectionInfo const* GetConnectionInfo() const
+ {
+ return _connectionInfo.get();
+ }
+
/**
Delayed one-way statement methods.
*/
@@ -137,18 +171,13 @@ class DatabaseWorkerPool
//! Enqueues a one-way SQL operation in string format -with variable args- that will be executed asynchronously.
//! This method should only be used for queries that are only executed once, e.g during startup.
- void PExecute(const char* sql, ...)
+ template<typename... Args>
+ void PExecute(const char* sql, Args const&... args)
{
if (!sql)
return;
- va_list ap;
- char szQuery[MAX_QUERY_LEN];
- va_start(ap, sql);
- vsnprintf(szQuery, MAX_QUERY_LEN, sql, ap);
- va_end(ap);
-
- Execute(szQuery);
+ Execute(Trinity::StringFormat(sql, args...).c_str());
}
//! Enqueues a one-way SQL operation in prepared statement format that will be executed asynchronously.
@@ -177,18 +206,13 @@ class DatabaseWorkerPool
//! Directly executes a one-way SQL operation in string format -with variable args-, that will block the calling thread until finished.
//! This method should only be used for queries that are only executed once, e.g during startup.
- void DirectPExecute(const char* sql, ...)
+ template<typename... Args>
+ void DirectPExecute(const char* sql, Args const&... args)
{
if (!sql)
return;
- va_list ap;
- char szQuery[MAX_QUERY_LEN];
- va_start(ap, sql);
- vsnprintf(szQuery, MAX_QUERY_LEN, sql, ap);
- va_end(ap);
-
- return DirectExecute(szQuery);
+ DirectExecute(Trinity::StringFormat(sql, args...).c_str());
}
//! Directly executes a one-way SQL operation in prepared statement format, that will block the calling thread until finished.
@@ -227,34 +251,24 @@ class DatabaseWorkerPool
//! Directly executes an SQL query in string format -with variable args- that will block the calling thread until finished.
//! Returns reference counted auto pointer, no need for manual memory management in upper level code.
- QueryResult PQuery(const char* sql, T* conn, ...)
+ template<typename... Args>
+ QueryResult PQuery(const char* sql, T* conn, Args const&... args)
{
if (!sql)
return QueryResult(NULL);
- va_list ap;
- char szQuery[MAX_QUERY_LEN];
- va_start(ap, conn);
- vsnprintf(szQuery, MAX_QUERY_LEN, sql, ap);
- va_end(ap);
-
- return Query(szQuery, conn);
+ return Query(Trinity::StringFormat(sql, args...).c_str(), conn);
}
//! Directly executes an SQL query in string format -with variable args- that will block the calling thread until finished.
//! Returns reference counted auto pointer, no need for manual memory management in upper level code.
- QueryResult PQuery(const char* sql, ...)
+ template<typename... Args>
+ QueryResult PQuery(const char* sql, Args const&... args)
{
if (!sql)
return QueryResult(NULL);
- va_list ap;
- char szQuery[MAX_QUERY_LEN];
- va_start(ap, sql);
- vsnprintf(szQuery, MAX_QUERY_LEN, sql, ap);
- va_end(ap);
-
- return Query(szQuery);
+ return Query(Trinity::StringFormat(sql, args...).c_str());
}
//! Directly executes an SQL query in prepared format that will block the calling thread until finished.
@@ -295,15 +309,10 @@ class DatabaseWorkerPool
//! Enqueues a query in string format -with variable args- that will set the value of the QueryResultFuture return object as soon as the query is executed.
//! The return value is then processed in ProcessQueryCallback methods.
- QueryResultFuture AsyncPQuery(const char* sql, ...)
+ template<typename... Args>
+ QueryResultFuture AsyncPQuery(const char* sql, Args const&... args)
{
- va_list ap;
- char szQuery[MAX_QUERY_LEN];
- va_start(ap, sql);
- vsnprintf(szQuery, MAX_QUERY_LEN, sql, ap);
- va_end(ap);
-
- return AsyncQuery(szQuery);
+ return AsyncQuery(Trinity::StringFormat(sql, args...).c_str());
}
//! Enqueues a query in prepared format that will set the value of the PreparedQueryResultFuture return object as soon as the query is executed.
@@ -461,7 +470,7 @@ class DatabaseWorkerPool
}
private:
- bool OpenConnections(InternalIndex type, uint8 numConnections)
+ uint32 OpenConnections(InternalIndex type, uint8 numConnections)
{
_connections[type].resize(numConnections);
for (uint8 i = 0; i < numConnections; ++i)
@@ -469,7 +478,7 @@ class DatabaseWorkerPool
T* t;
if (type == IDX_ASYNC)
- t = new T(_queue, *_connectionInfo);
+ t = new T(_queue.get(), *_connectionInfo);
else if (type == IDX_SYNCH)
t = new T(*_connectionInfo);
else
@@ -478,35 +487,32 @@ class DatabaseWorkerPool
_connections[type][i] = t;
++_connectionCount[type];
- bool res = t->Open();
+ uint32 error = t->Open();
- if (res)
+ if (!error)
{
if (mysql_get_server_version(t->GetHandle()) < MIN_MYSQL_SERVER_VERSION)
{
TC_LOG_ERROR("sql.driver", "TrinityCore does not support MySQL versions below 5.1");
- res = false;
+ error = 1;
}
}
// Failed to open a connection or invalid version, abort and cleanup
- if (!res)
+ if (error)
{
- TC_LOG_ERROR("sql.driver", "DatabasePool %s NOT opened. There were errors opening the MySQL connections. Check your SQLDriverLogFile "
- "for specific errors. Read wiki at http://collab.kpsn.org/display/tc/TrinityCore+Home", GetDatabaseName());
-
while (_connectionCount[type] != 0)
{
T* t = _connections[type][i--];
delete t;
--_connectionCount[type];
}
-
- return false;
+ return error;
}
}
- return true;
+ // Everything is fine
+ return 0;
}
unsigned long EscapeString(char *to, const char *from, unsigned long length)
@@ -546,10 +552,13 @@ class DatabaseWorkerPool
return _connectionInfo->database.c_str();
}
- ProducerConsumerQueue<SQLOperation*>* _queue; //! Queue shared by async worker threads.
- std::vector< std::vector<T*> > _connections;
- uint32 _connectionCount[2]; //! Counter of MySQL connections;
- MySQLConnectionInfo* _connectionInfo;
+ //! Queue shared by async worker threads.
+ std::unique_ptr<ProducerConsumerQueue<SQLOperation*>> _queue;
+ std::vector<std::vector<T*>> _connections;
+ //! Counter of MySQL connections;
+ uint32 _connectionCount[IDX_SIZE];
+ std::unique_ptr<MySQLConnectionInfo> _connectionInfo;
+ uint8 _async_threads, _synch_threads;
};
#endif
diff --git a/src/server/shared/Database/Field.h b/src/server/shared/Database/Field.h
index b88fb56cb06..1bbd264482f 100644
--- a/src/server/shared/Database/Field.h
+++ b/src/server/shared/Database/Field.h
@@ -255,11 +255,7 @@ class Field
Field();
~Field();
- #if defined(__GNUC__)
- #pragma pack(1)
- #else
#pragma pack(push, 1)
- #endif
struct
{
uint32 length; // Length (prepared strings only)
@@ -267,11 +263,7 @@ class Field
enum_field_types type; // Field type
bool raw; // Raw bytes? (Prepared statement or ad hoc)
} data;
- #if defined(__GNUC__)
- #pragma pack()
- #else
#pragma pack(pop)
- #endif
void SetByteValue(void const* newValue, size_t const newSize, enum_field_types newType, uint32 length);
void SetStructuredValue(char* newValue, enum_field_types newType);
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
index 265b0578841..1ca01501d01 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
@@ -60,7 +60,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_CHAR_POSITION_XYZ, "SELECT map, position_x, position_y, position_z FROM characters WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_POSITION, "SELECT position_x, position_y, position_z, orientation, map, taxi_path FROM characters WHERE guid = ?", CONNECTION_SYNCH);
- PrepareStatement(CHAR_DEL_BATTLEGROUND_RANDOM, "DELETE FROM character_battleground_random", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_BATTLEGROUND_RANDOM_ALL, "DELETE FROM character_battleground_random", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_BATTLEGROUND_RANDOM, "DELETE FROM character_battleground_random WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_BATTLEGROUND_RANDOM, "INSERT INTO character_battleground_random (guid) VALUES (?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER, "SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, "
@@ -104,7 +105,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_MAIL_COUNT, "SELECT COUNT(*) FROM mail WHERE receiver = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHARACTER_SOCIALLIST, "SELECT friend, flags, note FROM character_social JOIN characters ON characters.guid = character_social.friend WHERE character_social.guid = ? AND deleteinfos_name IS NULL LIMIT 255", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ FROM character_homebind WHERE guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, "SELECT spell, item, time FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, "SELECT spell, item, time FROM character_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_GUILD_MEMBER, "SELECT guildid, rank FROM guild_member WHERE guid = ?", CONNECTION_BOTH);
PrepareStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED, "SELECT g.guildid, g.name, gr.rname, gr.rid, gm.pnote, gm.offnote "
@@ -300,6 +301,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_ARENA_TEAM_MEMBER, "DELETE FROM arena_team_member WHERE arenaTeamId = ? AND guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_ARENA_TEAM_STATS, "UPDATE arena_team SET rating = ?, weekGames = ?, weekWins = ?, seasonGames = ?, seasonWins = ?, rank = ? WHERE arenaTeamId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_ARENA_TEAM_MEMBER, "UPDATE arena_team_member SET personalRating = ?, weekGames = ?, weekWins = ?, seasonGames = ?, seasonWins = ? WHERE arenaTeamId = ? AND guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_CHARACTER_ARENA_STATS, "DELETE FROM character_arena_stats WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_REP_CHARACTER_ARENA_STATS, "REPLACE INTO character_arena_stats (guid, slot, matchMakerRating) VALUES (?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_PLAYER_ARENA_TEAMS, "SELECT arena_team_member.arenaTeamId FROM arena_team_member JOIN arena_team ON arena_team_member.arenaTeamId = arena_team.arenaTeamId WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_UPD_ARENA_TEAM_NAME, "UPDATE arena_team SET name = ? WHERE arenaTeamId = ?", CONNECTION_ASYNC);
@@ -495,7 +497,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_UPD_CHAR_REP_FACTION_CHANGE, "UPDATE character_reputation SET faction = ?, standing = ? WHERE faction = ? AND guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHAR_TITLES_FACTION_CHANGE, "UPDATE characters SET knownTitles = ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_RES_CHAR_TITLES_FACTION_CHANGE, "UPDATE characters SET chosenTitle = 0 WHERE guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN, "DELETE FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_CHAR_SPELL_COOLDOWNS, "DELETE FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_CHAR_SPELL_COOLDOWN, "INSERT INTO character_spell_cooldown (guid, spell, item, time) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHARACTER, "DELETE FROM characters WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_ACTION, "DELETE FROM character_action WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_AURA, "DELETE FROM character_aura WHERE guid = ?", CONNECTION_ASYNC);
@@ -575,7 +578,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_INS_CHAR_PET_DECLINEDNAME, "INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_PET_AURA, "SELECT caster_guid, spell, effect_mask, recalculate_mask, stackcount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, maxduration, remaintime, remaincharges FROM pet_aura WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_PET_SPELL, "SELECT spell, active FROM pet_spell WHERE guid = ?", CONNECTION_SYNCH);
- PrepareStatement(CHAR_SEL_PET_SPELL_COOLDOWN, "SELECT spell, time FROM pet_spell_cooldown WHERE guid = ?", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_PET_SPELL_COOLDOWN, "SELECT spell, time FROM pet_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_PET_DECLINED_NAME, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_pet_declinedname WHERE owner = ? AND id = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_PET_AURAS, "DELETE FROM pet_aura WHERE guid = ?", CONNECTION_BOTH);
PrepareStatement(CHAR_DEL_PET_SPELLS, "DELETE FROM pet_spell WHERE guid = ?", CONNECTION_ASYNC);
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h
index f7ff5b9186e..f88a912e022 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.h
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.h
@@ -72,6 +72,7 @@ enum CharacterDatabaseStatements
CHAR_SEL_CHAR_POSITION_XYZ,
CHAR_SEL_CHAR_POSITION,
+ CHAR_DEL_BATTLEGROUND_RANDOM_ALL,
CHAR_DEL_BATTLEGROUND_RANDOM,
CHAR_INS_BATTLEGROUND_RANDOM,
@@ -253,6 +254,7 @@ enum CharacterDatabaseStatements
CHAR_DEL_ARENA_TEAM_MEMBER,
CHAR_UPD_ARENA_TEAM_STATS,
CHAR_UPD_ARENA_TEAM_MEMBER,
+ CHAR_DEL_CHARACTER_ARENA_STATS,
CHAR_REP_CHARACTER_ARENA_STATS,
CHAR_SEL_PLAYER_ARENA_TEAMS,
CHAR_UPD_ARENA_TEAM_NAME,
@@ -434,7 +436,8 @@ enum CharacterDatabaseStatements
CHAR_UPD_CHAR_REP_FACTION_CHANGE,
CHAR_UPD_CHAR_TITLES_FACTION_CHANGE,
CHAR_RES_CHAR_TITLES_FACTION_CHANGE,
- CHAR_DEL_CHAR_SPELL_COOLDOWN,
+ CHAR_DEL_CHAR_SPELL_COOLDOWNS,
+ CHAR_INS_CHAR_SPELL_COOLDOWN,
CHAR_DEL_CHARACTER,
CHAR_DEL_CHAR_ACTION,
CHAR_DEL_CHAR_AURA,
diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp
index 1a9f973d47b..10f4a7baa18 100644
--- a/src/server/shared/Database/MySQLConnection.cpp
+++ b/src/server/shared/Database/MySQLConnection.cpp
@@ -22,11 +22,9 @@
#include <winsock2.h>
#endif
#include <mysql.h>
-#include <mysqld_error.h>
#include <errmsg.h>
#include "MySQLConnection.h"
-#include "MySQLThreading.h"
#include "QueryResult.h"
#include "SQLOperation.h"
#include "PreparedStatement.h"
@@ -72,14 +70,14 @@ void MySQLConnection::Close()
delete this;
}
-bool MySQLConnection::Open()
+uint32 MySQLConnection::Open()
{
MYSQL *mysqlInit;
mysqlInit = mysql_init(NULL);
if (!mysqlInit)
{
TC_LOG_ERROR("sql.sql", "Could not initialize Mysql connection to database `%s`", m_connectionInfo.database.c_str());
- return false;
+ return CR_UNKNOWN_ERROR;
}
int port;
@@ -137,13 +135,13 @@ bool MySQLConnection::Open()
// set connection properties to UTF8 to properly handle locales for different
// server configs - core sends data in UTF8, so MySQL must expect UTF8 too
mysql_set_character_set(m_Mysql, "utf8");
- return PrepareStatements();
+ return 0;
}
else
{
- TC_LOG_ERROR("sql.sql", "Could not connect to MySQL database at %s: %s\n", m_connectionInfo.host.c_str(), mysql_error(mysqlInit));
+ TC_LOG_ERROR("sql.sql", "Could not connect to MySQL database at %s: %s", m_connectionInfo.host.c_str(), mysql_error(mysqlInit));
mysql_close(mysqlInit);
- return false;
+ return mysql_errno(mysqlInit);
}
}
@@ -491,8 +489,18 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo)
m_reconnecting = true;
uint64 oldThreadId = mysql_thread_id(GetHandle());
mysql_close(GetHandle());
- if (this->Open()) // Don't remove 'this' pointer unless you want to skip loading all prepared statements....
+
+ uint32 const lErrno = Open();
+ if (!lErrno)
{
+ // Don't remove 'this' pointer unless you want to skip loading all prepared statements...
+ if (!this->PrepareStatements())
+ {
+ TC_LOG_ERROR("sql.sql", "Could not re-prepare statements!");
+ Close();
+ return false;
+ }
+
TC_LOG_INFO("sql.sql", "Connection to the MySQL server is active.");
if (oldThreadId != mysql_thread_id(GetHandle()))
TC_LOG_INFO("sql.sql", "Successfully reconnected to %s @%s:%s (%s).",
@@ -503,7 +511,7 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo)
return true;
}
- uint32 lErrno = mysql_errno(GetHandle()); // It's possible this attempted reconnect throws 2006 at us. To prevent crazy recursive calls, sleep here.
+ // It's possible this attempted reconnect throws 2006 at us. To prevent crazy recursive calls, sleep here.
std::this_thread::sleep_for(std::chrono::seconds(3)); // Sleep 3 seconds
return _HandleMySQLErrno(lErrno); // Call self (recursive)
}
diff --git a/src/server/shared/Database/MySQLConnection.h b/src/server/shared/Database/MySQLConnection.h
index d486f5b4679..78d8d2fb5dd 100644
--- a/src/server/shared/Database/MySQLConnection.h
+++ b/src/server/shared/Database/MySQLConnection.h
@@ -72,9 +72,11 @@ class MySQLConnection
MySQLConnection(ProducerConsumerQueue<SQLOperation*>* queue, MySQLConnectionInfo& connInfo); //! Constructor for asynchronous connections.
virtual ~MySQLConnection();
- virtual bool Open();
+ virtual uint32 Open();
void Close();
+ bool PrepareStatements();
+
public:
bool Execute(const char* sql);
bool Execute(PreparedStatement* stmt);
@@ -111,7 +113,6 @@ class MySQLConnection
MySQLPreparedStatement* GetPreparedStatement(uint32 index);
void PrepareStatement(uint32 index, const char* sql, ConnectionFlags flags);
- bool PrepareStatements();
virtual void DoPrepareStatements() = 0;
protected:
diff --git a/src/server/shared/Database/QueryHolder.cpp b/src/server/shared/Database/QueryHolder.cpp
index 75b96e1996c..2fdb3825526 100644
--- a/src/server/shared/Database/QueryHolder.cpp
+++ b/src/server/shared/Database/QueryHolder.cpp
@@ -40,29 +40,6 @@ bool SQLQueryHolder::SetQuery(size_t index, const char *sql)
return true;
}
-bool SQLQueryHolder::SetPQuery(size_t index, const char *format, ...)
-{
- if (!format)
- {
- TC_LOG_ERROR("sql.sql", "Query (index: %u) is empty.", uint32(index));
- return false;
- }
-
- va_list ap;
- char szQuery [MAX_QUERY_LEN];
- va_start(ap, format);
- int res = vsnprintf(szQuery, MAX_QUERY_LEN, format, ap);
- va_end(ap);
-
- if (res == -1)
- {
- TC_LOG_ERROR("sql.sql", "SQL Query truncated (and not execute) for format: %s", format);
- return false;
- }
-
- return SetQuery(index, szQuery);
-}
-
bool SQLQueryHolder::SetPreparedQuery(size_t index, PreparedStatement* stmt)
{
if (m_queries.size() <= index)
diff --git a/src/server/shared/Database/QueryHolder.h b/src/server/shared/Database/QueryHolder.h
index 6fd1901447e..4102bba1223 100644
--- a/src/server/shared/Database/QueryHolder.h
+++ b/src/server/shared/Database/QueryHolder.h
@@ -29,8 +29,9 @@ class SQLQueryHolder
public:
SQLQueryHolder() { }
~SQLQueryHolder();
- bool SetQuery(size_t index, const char *sql);
- bool SetPQuery(size_t index, const char *format, ...) ATTR_PRINTF(3, 4);
+ bool SetQuery(size_t index, const char* sql);
+ template<typename... Args>
+ bool SetPQuery(size_t index, const char* sql, Args const&... args) { return SetQuery(index, Trinity::StringFormat(sql, args...).c_str()); }
bool SetPreparedQuery(size_t index, PreparedStatement* stmt);
void SetSize(size_t size);
QueryResult GetResult(size_t index);
diff --git a/src/server/shared/Database/Transaction.cpp b/src/server/shared/Database/Transaction.cpp
index 9f36d198bde..f657411f716 100644
--- a/src/server/shared/Database/Transaction.cpp
+++ b/src/server/shared/Database/Transaction.cpp
@@ -30,17 +30,6 @@ void Transaction::Append(const char* sql)
m_queries.push_back(data);
}
-void Transaction::PAppend(const char* sql, ...)
-{
- va_list ap;
- char szQuery [MAX_QUERY_LEN];
- va_start(ap, sql);
- vsnprintf(szQuery, MAX_QUERY_LEN, sql, ap);
- va_end(ap);
-
- Append(szQuery);
-}
-
//- Append a prepared statement to the transaction
void Transaction::Append(PreparedStatement* stmt)
{
diff --git a/src/server/shared/Database/Transaction.h b/src/server/shared/Database/Transaction.h
index 83d59006ddc..a51c96ea93b 100644
--- a/src/server/shared/Database/Transaction.h
+++ b/src/server/shared/Database/Transaction.h
@@ -19,6 +19,7 @@
#define _TRANSACTION_H
#include "SQLOperation.h"
+#include "StringFormat.h"
//- Forward declare (don't include header to prevent circular includes)
class PreparedStatement;
@@ -38,7 +39,8 @@ class Transaction
void Append(PreparedStatement* statement);
void Append(const char* sql);
- void PAppend(const char* sql, ...);
+ template<typename... Args>
+ void PAppend(const char* sql, Args const&... args) { Append(Trinity::StringFormat(sql, args...).c_str()); }
size_t GetSize() const { return m_queries.size(); }
@@ -59,8 +61,8 @@ class TransactionTask : public SQLOperation
friend class DatabaseWorker;
public:
- TransactionTask(SQLTransaction trans) : m_trans(trans) { } ;
- ~TransactionTask(){ };
+ TransactionTask(SQLTransaction trans) : m_trans(trans) { }
+ ~TransactionTask() { }
protected:
bool Execute() override;
diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp
index e9f4f9ca9ac..e9f888f280d 100644
--- a/src/server/shared/Debugging/WheatyExceptionReport.cpp
+++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp
@@ -61,6 +61,9 @@ HANDLE WheatyExceptionReport::m_hDumpFile;
HANDLE WheatyExceptionReport::m_hProcess;
SymbolPairs WheatyExceptionReport::symbols;
std::stack<SymbolDetail> WheatyExceptionReport::symbolDetails;
+bool WheatyExceptionReport::stackOverflowException;
+bool WheatyExceptionReport::alreadyCrashed;
+std::mutex WheatyExceptionReport::alreadyCrashedLock;
// Declare global instance of class
WheatyExceptionReport g_WheatyExceptionReport;
@@ -72,6 +75,8 @@ WheatyExceptionReport::WheatyExceptionReport() // Constructor
// Install the unhandled exception filter function
m_previousFilter = SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter);
m_hProcess = GetCurrentProcess();
+ stackOverflowException = false;
+ alreadyCrashed = false;
if (!IsDebuggerPresent())
{
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
@@ -97,6 +102,16 @@ WheatyExceptionReport::~WheatyExceptionReport()
LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter(
PEXCEPTION_POINTERS pExceptionInfo)
{
+ std::unique_lock<std::mutex> guard(alreadyCrashedLock);
+ // Handle only 1 exception in the whole process lifetime
+ if (alreadyCrashed)
+ return EXCEPTION_EXECUTE_HANDLER;
+
+ alreadyCrashed = true;
+
+ if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)
+ stackOverflowException = true;
+
TCHAR module_folder_name[MAX_PATH];
GetModuleFileName(0, module_folder_name, MAX_PATH);
TCHAR* pos = _tcsrchr(module_folder_name, '\\');
@@ -419,107 +434,114 @@ void WheatyExceptionReport::printTracesForAllThreads(bool bWriteVariables)
void WheatyExceptionReport::GenerateExceptionReport(
PEXCEPTION_POINTERS pExceptionInfo)
{
- SYSTEMTIME systime;
- GetLocalTime(&systime);
-
- // Start out with a banner
- _tprintf(_T("Revision: %s\r\n"), _FULLVERSION);
- _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute);
- PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
-
- PrintSystemInfo();
- // First print information about the type of fault
- _tprintf(_T("\r\n//=====================================================\r\n"));
- _tprintf(_T("Exception code: %08X %s\r\n"),
- pExceptionRecord->ExceptionCode,
- GetExceptionString(pExceptionRecord->ExceptionCode));
-
- // Now print information about where the fault occured
- TCHAR szFaultingModule[MAX_PATH];
- DWORD section;
- DWORD_PTR offset;
- GetLogicalAddress(pExceptionRecord->ExceptionAddress,
- szFaultingModule,
- sizeof(szFaultingModule),
- section, offset);
+ __try
+ {
+ SYSTEMTIME systime;
+ GetLocalTime(&systime);
+
+ // Start out with a banner
+ _tprintf(_T("Revision: %s\r\n"), _FULLVERSION);
+ _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute);
+ PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
+
+ PrintSystemInfo();
+ // First print information about the type of fault
+ _tprintf(_T("\r\n//=====================================================\r\n"));
+ _tprintf(_T("Exception code: %08X %s\r\n"),
+ pExceptionRecord->ExceptionCode,
+ GetExceptionString(pExceptionRecord->ExceptionCode));
+
+ // Now print information about where the fault occured
+ TCHAR szFaultingModule[MAX_PATH];
+ DWORD section;
+ DWORD_PTR offset;
+ GetLogicalAddress(pExceptionRecord->ExceptionAddress,
+ szFaultingModule,
+ sizeof(szFaultingModule),
+ section, offset);
#ifdef _M_IX86
- _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"),
- pExceptionRecord->ExceptionAddress,
- section, offset, szFaultingModule);
+ _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"),
+ pExceptionRecord->ExceptionAddress,
+ section, offset, szFaultingModule);
#endif
#ifdef _M_X64
- _tprintf(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"),
- pExceptionRecord->ExceptionAddress,
- section, offset, szFaultingModule);
+ _tprintf(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"),
+ pExceptionRecord->ExceptionAddress,
+ section, offset, szFaultingModule);
#endif
- PCONTEXT pCtx = pExceptionInfo->ContextRecord;
+ PCONTEXT pCtx = pExceptionInfo->ContextRecord;
- // Show the registers
- #ifdef _M_IX86 // X86 Only!
- _tprintf(_T("\r\nRegisters:\r\n"));
+ // Show the registers
+#ifdef _M_IX86 // X86 Only!
+ _tprintf(_T("\r\nRegisters:\r\n"));
- _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n")
- , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx,
- pCtx->Esi, pCtx->Edi);
+ _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n")
+ , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx,
+ pCtx->Esi, pCtx->Edi);
- _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip);
- _tprintf(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"),
- pCtx->SegSs, pCtx->Esp, pCtx->Ebp);
- _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
- pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
- _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags);
- #endif
+ _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip);
+ _tprintf(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"),
+ pCtx->SegSs, pCtx->Esp, pCtx->Ebp);
+ _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
+ pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
+ _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags);
+#endif
- #ifdef _M_X64
- _tprintf(_T("\r\nRegisters:\r\n"));
- _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n")
- _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n")
- , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx,
- pCtx->Rsi, pCtx->Rdi, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15);
- _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip);
- _tprintf(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"),
- pCtx->SegSs, pCtx->Rsp, pCtx->Rbp);
- _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
- pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
- _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags);
- #endif
+#ifdef _M_X64
+ _tprintf(_T("\r\nRegisters:\r\n"));
+ _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n")
+ _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n")
+ , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx,
+ pCtx->Rsi, pCtx->Rdi, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15);
+ _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip);
+ _tprintf(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"),
+ pCtx->SegSs, pCtx->Rsp, pCtx->Rbp);
+ _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
+ pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
+ _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags);
+#endif
- SymSetOptions(SYMOPT_DEFERRED_LOADS);
+ SymSetOptions(SYMOPT_DEFERRED_LOADS);
- // Initialize DbgHelp
- if (!SymInitialize(GetCurrentProcess(), 0, TRUE))
- {
- _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"),
- ErrorMessage(GetLastError()));
- }
+ // Initialize DbgHelp
+ if (!SymInitialize(GetCurrentProcess(), 0, TRUE))
+ {
+ _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"),
+ ErrorMessage(GetLastError()));
+ }
- CONTEXT trashableContext = *pCtx;
+ CONTEXT trashableContext = *pCtx;
- WriteStackDetails(&trashableContext, false, NULL);
- printTracesForAllThreads(false);
+ WriteStackDetails(&trashableContext, false, NULL);
+ printTracesForAllThreads(false);
-// #ifdef _M_IX86 // X86 Only!
+ // #ifdef _M_IX86 // X86 Only!
- _tprintf(_T("========================\r\n"));
- _tprintf(_T("Local Variables And Parameters\r\n"));
+ _tprintf(_T("========================\r\n"));
+ _tprintf(_T("Local Variables And Parameters\r\n"));
- trashableContext = *pCtx;
- WriteStackDetails(&trashableContext, true, NULL);
- printTracesForAllThreads(true);
+ trashableContext = *pCtx;
+ WriteStackDetails(&trashableContext, true, NULL);
+ printTracesForAllThreads(true);
- /*_tprintf(_T("========================\r\n"));
- _tprintf(_T("Global Variables\r\n"));
+ /*_tprintf(_T("========================\r\n"));
+ _tprintf(_T("Global Variables\r\n"));
- SymEnumSymbols(GetCurrentProcess(),
+ SymEnumSymbols(GetCurrentProcess(),
(UINT_PTR)GetModuleHandle(szFaultingModule),
0, EnumerateSymbolsCallback, 0);*/
- // #endif // X86 Only!
+ // #endif // X86 Only!
- SymCleanup(GetCurrentProcess());
+ SymCleanup(GetCurrentProcess());
- _tprintf(_T("\r\n"));
+ _tprintf(_T("\r\n"));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ _tprintf(_T("Error writing the crash log\r\n"));
+ }
}
//======================================================================
@@ -1068,7 +1090,7 @@ bool logChildren)
{
case btChar:
case btStdString:
- FormatOutputValue(buffer, basicType, length, (PVOID)offset, sizeof(buffer));
+ FormatOutputValue(buffer, basicType, length, (PVOID)offset, sizeof(buffer), elementsCount);
symbolDetails.top().Value = buffer;
break;
default:
@@ -1196,7 +1218,8 @@ void WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer,
BasicType basicType,
DWORD64 length,
PVOID pAddress,
-size_t bufferSize)
+size_t bufferSize,
+size_t countOverride)
{
__try
{
@@ -1204,10 +1227,15 @@ size_t bufferSize)
{
case btChar:
{
- if (strlen((char*)pAddress) > bufferSize - 6)
+ // Special case handling for char[] type
+ if (countOverride != 0)
+ length = countOverride;
+ else
+ length = strlen((char*)pAddress);
+ if (length > bufferSize - 6)
pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, (char*)pAddress);
else
- pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", (char*)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s\"", length, (char*)pAddress);
break;
}
case btStdString:
@@ -1307,16 +1335,43 @@ DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer(DWORD_PTR address)
//============================================================================
int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...)
{
- TCHAR szBuff[WER_LARGE_BUFFER_SIZE];
int retValue;
- DWORD cbWritten;
va_list argptr;
-
va_start(argptr, format);
+ if (stackOverflowException)
+ {
+ retValue = heapprintf(format, argptr);
+ va_end(argptr);
+ }
+ else
+ {
+ retValue = stackprintf(format, argptr);
+ va_end(argptr);
+ }
+
+ return retValue;
+}
+
+int __cdecl WheatyExceptionReport::stackprintf(const TCHAR * format, va_list argptr)
+{
+ int retValue;
+ DWORD cbWritten;
+
+ TCHAR szBuff[WER_LARGE_BUFFER_SIZE];
retValue = vsprintf(szBuff, format, argptr);
- va_end(argptr);
+ WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0);
+
+ return retValue;
+}
+int __cdecl WheatyExceptionReport::heapprintf(const TCHAR * format, va_list argptr)
+{
+ int retValue;
+ DWORD cbWritten;
+ TCHAR* szBuff = (TCHAR*)malloc(sizeof(TCHAR) * WER_LARGE_BUFFER_SIZE);
+ retValue = vsprintf(szBuff, format, argptr);
WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0);
+ free(szBuff);
return retValue;
}
diff --git a/src/server/shared/Debugging/WheatyExceptionReport.h b/src/server/shared/Debugging/WheatyExceptionReport.h
index 9137b91aac9..ef6334add16 100644
--- a/src/server/shared/Debugging/WheatyExceptionReport.h
+++ b/src/server/shared/Debugging/WheatyExceptionReport.h
@@ -172,12 +172,14 @@ class WheatyExceptionReport
static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, const char*, char*, bool, bool);
- static void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize);
+ static void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize, size_t countOverride = 0);
static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase);
static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address);
static int __cdecl _tprintf(const TCHAR * format, ...);
+ static int __cdecl stackprintf(const TCHAR * format, va_list argptr);
+ static int __cdecl heapprintf(const TCHAR * format, va_list argptr);
static bool StoreSymbol(DWORD type , DWORD_PTR offset);
static void ClearSymbols();
@@ -191,6 +193,9 @@ class WheatyExceptionReport
static HANDLE m_hProcess;
static SymbolPairs symbols;
static std::stack<SymbolDetail> symbolDetails;
+ static bool stackOverflowException;
+ static bool alreadyCrashed;
+ static std::mutex alreadyCrashedLock;
static char* PushSymbolDetail(char* pszCurrBuffer);
static char* PopSymbolDetail(char* pszCurrBuffer);
diff --git a/src/server/shared/Define.h b/src/server/shared/Define.h
index add7995ad8f..97e07cef8b3 100644
--- a/src/server/shared/Define.h
+++ b/src/server/shared/Define.h
@@ -78,9 +78,9 @@
#endif //!COREDEBUG
#if COMPILER == COMPILER_GNU
-# define ATTR_NORETURN __attribute__((noreturn))
-# define ATTR_PRINTF(F, V) __attribute__ ((format (printf, F, V)))
-# define ATTR_DEPRECATED __attribute__((deprecated))
+# define ATTR_NORETURN __attribute__((__noreturn__))
+# define ATTR_PRINTF(F, V) __attribute__ ((__format__ (__printf__, F, V)))
+# define ATTR_DEPRECATED __attribute__((__deprecated__))
#else //COMPILER != COMPILER_GNU
# define ATTR_NORETURN
# define ATTR_PRINTF(F, V)
diff --git a/src/server/shared/Dynamic/ObjectRegistry.h b/src/server/shared/Dynamic/ObjectRegistry.h
index be253f947a7..1eb9368be61 100644
--- a/src/server/shared/Dynamic/ObjectRegistry.h
+++ b/src/server/shared/Dynamic/ObjectRegistry.h
@@ -47,12 +47,12 @@ class ObjectRegistry
}
/// Inserts a registry item
- bool InsertItem(T *obj, Key key, bool override = false)
+ bool InsertItem(T *obj, Key key, bool _override = false)
{
typename RegistryMapType::iterator iter = i_registeredObjects.find(key);
if ( iter != i_registeredObjects.end() )
{
- if ( !override )
+ if ( !_override )
return false;
delete iter->second;
i_registeredObjects.erase(iter);
diff --git a/src/server/shared/Logging/Appender.cpp b/src/server/shared/Logging/Appender.cpp
index dff931e3da8..31db3ae1b86 100644
--- a/src/server/shared/Logging/Appender.cpp
+++ b/src/server/shared/Logging/Appender.cpp
@@ -18,6 +18,10 @@
#include "Appender.h"
#include "Common.h"
#include "Util.h"
+#include "StringFormat.h"
+
+#include <utility>
+#include <sstream>
std::string LogMessage::getTimeStr(time_t time)
{
@@ -68,38 +72,23 @@ void Appender::setLogLevel(LogLevel _level)
level = _level;
}
-void Appender::write(LogMessage& message)
+void Appender::write(LogMessage* message)
{
- if (!level || level > message.level)
+ if (!level || level > message->level)
return;
- message.prefix.clear();
+ std::ostringstream ss;
+
if (flags & APPENDER_FLAGS_PREFIX_TIMESTAMP)
- message.prefix.append(message.getTimeStr());
+ ss << message->getTimeStr() << ' ';
if (flags & APPENDER_FLAGS_PREFIX_LOGLEVEL)
- {
- if (!message.prefix.empty())
- message.prefix.push_back(' ');
-
- char text[MAX_QUERY_LEN];
- snprintf(text, MAX_QUERY_LEN, "%-5s", Appender::getLogLevelString(message.level));
- message.prefix.append(text);
- }
+ ss << Trinity::StringFormat("%-5s ", Appender::getLogLevelString(message->level));
if (flags & APPENDER_FLAGS_PREFIX_LOGFILTERTYPE)
- {
- if (!message.prefix.empty())
- message.prefix.push_back(' ');
-
- message.prefix.push_back('[');
- message.prefix.append(message.type);
- message.prefix.push_back(']');
- }
-
- if (!message.prefix.empty())
- message.prefix.push_back(' ');
+ ss << '[' << message->type << "] ";
+ message->prefix = ss.str();
_write(message);
}
diff --git a/src/server/shared/Logging/Appender.h b/src/server/shared/Logging/Appender.h
index 6f38eb6aaf7..73af351e41d 100644
--- a/src/server/shared/Logging/Appender.h
+++ b/src/server/shared/Logging/Appender.h
@@ -21,6 +21,7 @@
#include <unordered_map>
#include <string>
#include <time.h>
+#include <type_traits>
#include "Define.h"
// Values assigned have their equivalent in enum ACE_Log_Priority
@@ -57,16 +58,19 @@ enum AppenderFlags
struct LogMessage
{
- LogMessage(LogLevel _level, std::string const& _type, std::string const& _text)
- : level(_level), type(_type), text(_text), mtime(time(NULL))
+ LogMessage(LogLevel _level, std::string const& _type, std::string&& _text)
+ : level(_level), type(_type), text(std::forward<std::string>(_text)), mtime(time(NULL))
{ }
+ LogMessage(LogMessage const& /*other*/) = delete;
+ LogMessage& operator=(LogMessage const& /*other*/) = delete;
+
static std::string getTimeStr(time_t time);
std::string getTimeStr();
- LogLevel level;
- std::string type;
- std::string text;
+ LogLevel const level;
+ std::string const type;
+ std::string const text;
std::string prefix;
std::string param1;
time_t mtime;
@@ -91,11 +95,11 @@ class Appender
AppenderFlags getFlags() const;
void setLogLevel(LogLevel);
- void write(LogMessage& message);
+ void write(LogMessage* message);
static const char* getLogLevelString(LogLevel level);
private:
- virtual void _write(LogMessage const& /*message*/) = 0;
+ virtual void _write(LogMessage const* /*message*/) = 0;
uint8 id;
std::string name;
diff --git a/src/server/shared/Logging/AppenderConsole.cpp b/src/server/shared/Logging/AppenderConsole.cpp
index ae27337fb9a..2efa4db4d2e 100644
--- a/src/server/shared/Logging/AppenderConsole.cpp
+++ b/src/server/shared/Logging/AppenderConsole.cpp
@@ -158,14 +158,14 @@ void AppenderConsole::ResetColor(bool stdout_stream)
#endif
}
-void AppenderConsole::_write(LogMessage const& message)
+void AppenderConsole::_write(LogMessage const* message)
{
- bool stdout_stream = !(message.level == LOG_LEVEL_ERROR || message.level == LOG_LEVEL_FATAL);
+ bool stdout_stream = !(message->level == LOG_LEVEL_ERROR || message->level == LOG_LEVEL_FATAL);
if (_colored)
{
uint8 index;
- switch (message.level)
+ switch (message->level)
{
case LOG_LEVEL_TRACE:
index = 5;
@@ -189,9 +189,9 @@ void AppenderConsole::_write(LogMessage const& message)
}
SetColor(stdout_stream, _colors[index]);
- utf8printf(stdout_stream ? stdout : stderr, "%s%s", message.prefix.c_str(), message.text.c_str());
+ utf8printf(stdout_stream ? stdout : stderr, "%s%s\n", message->prefix.c_str(), message->text.c_str());
ResetColor(stdout_stream);
}
else
- utf8printf(stdout_stream ? stdout : stderr, "%s%s", message.prefix.c_str(), message.text.c_str());
+ utf8printf(stdout_stream ? stdout : stderr, "%s%s\n", message->prefix.c_str(), message->text.c_str());
}
diff --git a/src/server/shared/Logging/AppenderConsole.h b/src/server/shared/Logging/AppenderConsole.h
index 0f9536b3111..0acf7636e35 100644
--- a/src/server/shared/Logging/AppenderConsole.h
+++ b/src/server/shared/Logging/AppenderConsole.h
@@ -51,7 +51,7 @@ class AppenderConsole: public Appender
private:
void SetColor(bool stdout_stream, ColorTypes color);
void ResetColor(bool stdout_stream);
- void _write(LogMessage const& message) override;
+ void _write(LogMessage const* message) override;
bool _colored;
ColorTypes _colors[MaxLogLevels];
};
diff --git a/src/server/shared/Logging/AppenderDB.cpp b/src/server/shared/Logging/AppenderDB.cpp
index d297d6d08d3..8a329ea3a0f 100644
--- a/src/server/shared/Logging/AppenderDB.cpp
+++ b/src/server/shared/Logging/AppenderDB.cpp
@@ -23,18 +23,18 @@ AppenderDB::AppenderDB(uint8 id, std::string const& name, LogLevel level)
AppenderDB::~AppenderDB() { }
-void AppenderDB::_write(LogMessage const& message)
+void AppenderDB::_write(LogMessage const* message)
{
// Avoid infinite loop, PExecute triggers Logging with "sql.sql" type
- if (!enabled || !message.type.find("sql"))
+ if (!enabled || (message->type.find("sql") != std::string::npos))
return;
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_LOG);
- stmt->setUInt64(0, message.mtime);
+ stmt->setUInt64(0, message->mtime);
stmt->setUInt32(1, realmId);
- stmt->setString(2, message.type);
- stmt->setUInt8(3, uint8(message.level));
- stmt->setString(4, message.text);
+ stmt->setString(2, message->type);
+ stmt->setUInt8(3, uint8(message->level));
+ stmt->setString(4, message->text);
LoginDatabase.Execute(stmt);
}
diff --git a/src/server/shared/Logging/AppenderDB.h b/src/server/shared/Logging/AppenderDB.h
index e20ceaf77b4..09affdb46f1 100644
--- a/src/server/shared/Logging/AppenderDB.h
+++ b/src/server/shared/Logging/AppenderDB.h
@@ -31,7 +31,7 @@ class AppenderDB: public Appender
private:
uint32 realmId;
bool enabled;
- void _write(LogMessage const& message) override;
+ void _write(LogMessage const* message) override;
};
#endif
diff --git a/src/server/shared/Logging/AppenderFile.cpp b/src/server/shared/Logging/AppenderFile.cpp
index 07a88a367ae..5a8d610a36b 100644
--- a/src/server/shared/Logging/AppenderFile.cpp
+++ b/src/server/shared/Logging/AppenderFile.cpp
@@ -43,21 +43,21 @@ AppenderFile::~AppenderFile()
CloseFile();
}
-void AppenderFile::_write(LogMessage const& message)
+void AppenderFile::_write(LogMessage const* message)
{
- bool exceedMaxSize = maxFileSize > 0 && (fileSize.load() + message.Size()) > maxFileSize;
+ bool exceedMaxSize = maxFileSize > 0 && (fileSize.load() + message->Size()) > maxFileSize;
if (dynamicName)
{
char namebuf[TRINITY_PATH_MAX];
- snprintf(namebuf, TRINITY_PATH_MAX, filename.c_str(), message.param1.c_str());
+ snprintf(namebuf, TRINITY_PATH_MAX, filename.c_str(), message->param1.c_str());
// always use "a" with dynamic name otherwise it could delete the log we wrote in last _write() call
FILE* file = OpenFile(namebuf, "a", backup || exceedMaxSize);
if (!file)
return;
- fprintf(file, "%s%s", message.prefix.c_str(), message.text.c_str());
+ fprintf(file, "%s%s\n", message->prefix.c_str(), message->text.c_str());
fflush(file);
- fileSize += uint64(message.Size());
+ fileSize += uint64(message->Size());
fclose(file);
return;
}
@@ -67,9 +67,9 @@ void AppenderFile::_write(LogMessage const& message)
if (!logfile)
return;
- fprintf(logfile, "%s%s", message.prefix.c_str(), message.text.c_str());
+ fprintf(logfile, "%s%s\n", message->prefix.c_str(), message->text.c_str());
fflush(logfile);
- fileSize += uint64(message.Size());
+ fileSize += uint64(message->Size());
}
FILE* AppenderFile::OpenFile(std::string const &filename, std::string const &mode, bool backup)
diff --git a/src/server/shared/Logging/AppenderFile.h b/src/server/shared/Logging/AppenderFile.h
index 23651fc1129..36afdd23ad1 100644
--- a/src/server/shared/Logging/AppenderFile.h
+++ b/src/server/shared/Logging/AppenderFile.h
@@ -30,7 +30,7 @@ class AppenderFile: public Appender
private:
void CloseFile();
- void _write(LogMessage const& message) override;
+ void _write(LogMessage const* message) override;
FILE* logfile;
std::string filename;
std::string logDir;
diff --git a/src/server/shared/Logging/Log.cpp b/src/server/shared/Logging/Log.cpp
index 4bf4dacb302..a2150733c6b 100644
--- a/src/server/shared/Logging/Log.cpp
+++ b/src/server/shared/Logging/Log.cpp
@@ -25,7 +25,6 @@
#include "AppenderDB.h"
#include "LogOperation.h"
-#include <cstdarg>
#include <cstdio>
#include <sstream>
@@ -199,6 +198,9 @@ void Log::CreateLoggerFromConfig(std::string const& appenderName)
return;
}
+ if (level < lowestLogLevel)
+ lowestLogLevel = level;
+
logger.Create(name, level);
//fprintf(stdout, "Log::CreateLoggerFromConfig: Created Logger %s, Level %u\n", name.c_str(), level);
@@ -261,30 +263,18 @@ void Log::ReadLoggersFromConfig()
}
}
-void Log::vlog(std::string const& filter, LogLevel level, char const* str, va_list argptr)
-{
- char text[MAX_QUERY_LEN];
- vsnprintf(text, MAX_QUERY_LEN, str, argptr);
- write(new LogMessage(level, filter, text));
-}
-
-void Log::write(LogMessage* msg) const
+void Log::write(std::unique_ptr<LogMessage>&& msg) const
{
Logger const* logger = GetLoggerByType(msg->type);
- msg->text.append("\n");
if (_ioService)
{
- auto logOperation = std::shared_ptr<LogOperation>(new LogOperation(logger, msg));
+ auto logOperation = std::shared_ptr<LogOperation>(new LogOperation(logger, std::forward<std::unique_ptr<LogMessage>>(msg)));
_ioService->post(_strand->wrap([logOperation](){ logOperation->call(); }));
-
}
else
- {
- logger->write(*msg);
- delete msg;
- }
+ logger->write(msg.get());
}
std::string Log::GetTimestampStr()
@@ -321,6 +311,9 @@ bool Log::SetLogLevel(std::string const& name, const char* newLevelc, bool isLog
return false;
it->second.setLogLevel(newLevel);
+
+ if (newLevel != LOG_LEVEL_DISABLED && newLevel < lowestLogLevel)
+ lowestLogLevel = newLevel;
}
else
{
@@ -343,40 +336,20 @@ void Log::outCharDump(char const* str, uint32 accountId, uint64 guid, char const
ss << "== START DUMP == (account: " << accountId << " guid: " << guid << " name: " << name
<< ")\n" << str << "\n== END DUMP ==\n";
- LogMessage* msg = new LogMessage(LOG_LEVEL_INFO, "entities.player.dump", ss.str());
+ std::unique_ptr<LogMessage> msg(new LogMessage(LOG_LEVEL_INFO, "entities.player.dump", ss.str()));
std::ostringstream param;
param << guid << '_' << name;
msg->param1 = param.str();
- write(msg);
-}
-
-void Log::outCommand(uint32 account, const char * str, ...)
-{
- if (!str || !ShouldLog("commands.gm", LOG_LEVEL_INFO))
- return;
-
- va_list ap;
- va_start(ap, str);
- char text[MAX_QUERY_LEN];
- vsnprintf(text, MAX_QUERY_LEN, str, ap);
- va_end(ap);
-
- LogMessage* msg = new LogMessage(LOG_LEVEL_INFO, "commands.gm", text);
-
- std::ostringstream ss;
- ss << account;
- msg->param1 = ss.str();
-
- write(msg);
+ write(std::move(msg));
}
void Log::SetRealmId(uint32 id)
{
for (AppenderMap::iterator it = appenders.begin(); it != appenders.end(); ++it)
if (it->second && it->second->getType() == APPENDER_DB)
- ((AppenderDB *)it->second)->setRealmId(id);
+ static_cast<AppenderDB*>(it->second)->setRealmId(id);
}
void Log::Close()
@@ -394,6 +367,7 @@ void Log::LoadFromConfig()
{
Close();
+ lowestLogLevel = LOG_LEVEL_FATAL;
AppenderId = 0;
m_logsDir = sConfigMgr->GetStringDefault("LogsDir", "");
if (!m_logsDir.empty())
diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h
index 1d67ff87f76..e22a06e635e 100644
--- a/src/server/shared/Logging/Log.h
+++ b/src/server/shared/Logging/Log.h
@@ -22,12 +22,14 @@
#include "Define.h"
#include "Appender.h"
#include "Logger.h"
-#include <stdarg.h>
+#include "StringFormat.h"
#include <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
+#include <stdarg.h>
#include <unordered_map>
#include <string>
+#include <memory>
#define LOGGER_ROOT "root"
@@ -59,17 +61,32 @@ class Log
bool ShouldLog(std::string const& type, LogLevel level) const;
bool SetLogLevel(std::string const& name, char const* level, bool isLogger = true);
- void outMessage(std::string const& f, LogLevel level, char const* str, ...) ATTR_PRINTF(4, 5);
+ template<typename... Args>
+ inline void outMessage(std::string const& filter, LogLevel const level, const char* fmt, Args const&... args)
+ {
+ write(std::unique_ptr<LogMessage>(new LogMessage(level, filter, Trinity::StringFormat(fmt, args...))));
+ }
+
+ template<typename... Args>
+ void outCommand(uint32 account, const char* fmt, Args const&... args)
+ {
+ if (!ShouldLog("commands.gm", LOG_LEVEL_INFO))
+ return;
+
+ std::unique_ptr<LogMessage> msg(new LogMessage(LOG_LEVEL_INFO, "commands.gm", std::move(Trinity::StringFormat(fmt, args...))));
+
+ msg->param1 = std::to_string(account);
+
+ write(std::move(msg));
+ }
- void outCommand(uint32 account, const char * str, ...) ATTR_PRINTF(3, 4);
void outCharDump(char const* str, uint32 account_id, uint64 guid, char const* name);
void SetRealmId(uint32 id);
private:
static std::string GetTimestampStr();
- void vlog(std::string const& f, LogLevel level, char const* str, va_list argptr);
- void write(LogMessage* msg) const;
+ void write(std::unique_ptr<LogMessage>&& msg) const;
Logger const* GetLoggerByType(std::string const& type) const;
Appender* GetAppenderByName(std::string const& name);
@@ -82,6 +99,7 @@ class Log
AppenderMap appenders;
LoggerMap loggers;
uint8 AppenderId;
+ LogLevel lowestLogLevel;
std::string m_logsDir;
std::string m_logsTimestamp;
@@ -113,6 +131,10 @@ inline bool Log::ShouldLog(std::string const& type, LogLevel level) const
// Speed up in cases where requesting "Type.sub1.sub2" but only configured
// Logger "Type"
+ // Don't even look for a logger if the LogLevel is lower than lowest log levels across all loggers
+ if (level < lowestLogLevel)
+ return false;
+
Logger const* logger = GetLoggerByType(type);
if (!logger)
return false;
@@ -121,23 +143,34 @@ inline bool Log::ShouldLog(std::string const& type, LogLevel level) const
return logLevel != LOG_LEVEL_DISABLED && logLevel <= level;
}
-inline void Log::outMessage(std::string const& filter, LogLevel level, const char * str, ...)
-{
- va_list ap;
- va_start(ap, str);
-
- vlog(filter, level, str, ap);
-
- va_end(ap);
-}
-
#define sLog Log::instance()
+#define LOG_EXCEPTION_FREE(filterType__, level__, ...) \
+ { \
+ try \
+ { \
+ sLog->outMessage(filterType__, level__, __VA_ARGS__); \
+ } \
+ catch (std::exception& e) \
+ { \
+ sLog->outMessage("server", LOG_LEVEL_ERROR, "Wrong format occurred (%s) at %s:%u.", \
+ e.what(), __FILE__, __LINE__); \
+ } \
+ }
+
#if PLATFORM != PLATFORM_WINDOWS
+void check_args(const char* format, ...) ATTR_PRINTF(1, 2);
+
+// This will catch format errors on build time
#define TC_LOG_MESSAGE_BODY(filterType__, level__, ...) \
do { \
if (sLog->ShouldLog(filterType__, level__)) \
- sLog->outMessage(filterType__, level__, __VA_ARGS__); \
+ { \
+ if (false) \
+ check_args(__VA_ARGS__); \
+ \
+ LOG_EXCEPTION_FREE(filterType__, level__, __VA_ARGS__); \
+ } \
} while (0)
#else
#define TC_LOG_MESSAGE_BODY(filterType__, level__, ...) \
@@ -145,7 +178,7 @@ inline void Log::outMessage(std::string const& filter, LogLevel level, const cha
__pragma(warning(disable:4127)) \
do { \
if (sLog->ShouldLog(filterType__, level__)) \
- sLog->outMessage(filterType__, level__, __VA_ARGS__); \
+ LOG_EXCEPTION_FREE(filterType__, level__, __VA_ARGS__); \
} while (0) \
__pragma(warning(pop))
#endif
diff --git a/src/server/shared/Logging/LogOperation.cpp b/src/server/shared/Logging/LogOperation.cpp
index 9afb28a49c2..bcd923c705e 100644
--- a/src/server/shared/Logging/LogOperation.cpp
+++ b/src/server/shared/Logging/LogOperation.cpp
@@ -18,14 +18,8 @@
#include "LogOperation.h"
#include "Logger.h"
-LogOperation::~LogOperation()
-{
- delete msg;
-}
-
int LogOperation::call()
{
- if (logger && msg)
- logger->write(*msg);
+ logger->write(msg.get());
return 0;
}
diff --git a/src/server/shared/Logging/LogOperation.h b/src/server/shared/Logging/LogOperation.h
index b8655413273..ffdd35c3c09 100644
--- a/src/server/shared/Logging/LogOperation.h
+++ b/src/server/shared/Logging/LogOperation.h
@@ -18,23 +18,25 @@
#ifndef LOGOPERATION_H
#define LOGOPERATION_H
+#include <memory>
+
class Logger;
struct LogMessage;
class LogOperation
{
public:
- LogOperation(Logger const* _logger, LogMessage* _msg)
- : logger(_logger), msg(_msg)
+ LogOperation(Logger const* _logger, std::unique_ptr<LogMessage>&& _msg)
+ : logger(_logger), msg(std::forward<std::unique_ptr<LogMessage>>(_msg))
{ }
- ~LogOperation();
+ ~LogOperation() { }
int call();
protected:
Logger const* logger;
- LogMessage* msg;
+ std::unique_ptr<LogMessage> msg;
};
#endif
diff --git a/src/server/shared/Logging/Logger.cpp b/src/server/shared/Logging/Logger.cpp
index 615732deb30..3b02eb47575 100644
--- a/src/server/shared/Logging/Logger.cpp
+++ b/src/server/shared/Logging/Logger.cpp
@@ -50,9 +50,9 @@ void Logger::setLogLevel(LogLevel _level)
level = _level;
}
-void Logger::write(LogMessage& message) const
+void Logger::write(LogMessage* message) const
{
- if (!level || level > message.level || message.text.empty())
+ if (!level || level > message->level || message->text.empty())
{
//fprintf(stderr, "Logger::write: Logger %s, Level %u. Msg %s Level %u WRONG LEVEL MASK OR EMPTY MSG\n", getName().c_str(), getLogLevel(), message.text.c_str(), message.level);
return;
diff --git a/src/server/shared/Logging/Logger.h b/src/server/shared/Logging/Logger.h
index a81ee8d7bd2..1aee75c5d72 100644
--- a/src/server/shared/Logging/Logger.h
+++ b/src/server/shared/Logging/Logger.h
@@ -32,7 +32,7 @@ class Logger
std::string const& getName() const;
LogLevel getLogLevel() const;
void setLogLevel(LogLevel level);
- void write(LogMessage& message) const;
+ void write(LogMessage* message) const;
private:
std::string name;
diff --git a/src/server/shared/Networking/MessageBuffer.h b/src/server/shared/Networking/MessageBuffer.h
index 90afaf35796..95e26974626 100644
--- a/src/server/shared/Networking/MessageBuffer.h
+++ b/src/server/shared/Networking/MessageBuffer.h
@@ -55,9 +55,9 @@ public:
uint8* GetBasePointer() { return _storage.data(); }
- uint8* GetReadPointer() { return &_storage[_rpos]; }
+ uint8* GetReadPointer() { return GetBasePointer() + _rpos; }
- uint8* GetWritePointer() { return &_storage[_wpos]; }
+ uint8* GetWritePointer() { return GetBasePointer() + _wpos; }
void ReadCompleted(size_type bytes) { _rpos += bytes; }
diff --git a/src/server/shared/Networking/Socket.h b/src/server/shared/Networking/Socket.h
index f6bf3976b85..1989411bccb 100644
--- a/src/server/shared/Networking/Socket.h
+++ b/src/server/shared/Networking/Socket.h
@@ -34,7 +34,9 @@
using boost::asio::ip::tcp;
#define READ_BLOCK_SIZE 4096
-#define TC_SOCKET_USE_IOCP BOOST_ASIO_HAS_IOCP
+#ifdef BOOST_ASIO_HAS_IOCP
+#define TC_SOCKET_USE_IOCP
+#endif
template<class T>
class Socket : public std::enable_shared_from_this<T>
@@ -48,6 +50,7 @@ public:
virtual ~Socket()
{
+ _closed = true;
boost::system::error_code error;
_socket.close(error);
}
@@ -60,7 +63,7 @@ public:
return false;
#ifndef TC_SOCKET_USE_IOCP
- std::unique_lock<std::mutex> guard(_writeLock, std::try_to_lock);
+ std::unique_lock<std::mutex> guard(_writeLock);
if (!guard)
return true;
@@ -95,26 +98,6 @@ public:
std::bind(&Socket<T>::ReadHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
}
- void ReadData(std::size_t size)
- {
- if (!IsOpen())
- return;
-
- boost::system::error_code error;
-
- std::size_t bytesRead = boost::asio::read(_socket, boost::asio::buffer(_readBuffer.GetWritePointer(), size), error);
-
- _readBuffer.WriteCompleted(bytesRead);
-
- if (error || bytesRead != size)
- {
- TC_LOG_DEBUG("network", "Socket::ReadData: %s errored with: %i (%s)", GetRemoteIpAddress().to_string().c_str(), error.value(),
- error.message().c_str());
-
- CloseSocket();
- }
- }
-
void QueuePacket(MessageBuffer&& buffer, std::unique_lock<std::mutex>& guard)
{
_writeQueue.push(std::move(buffer));
@@ -138,6 +121,8 @@ public:
if (shutdownError)
TC_LOG_DEBUG("network", "Socket::CloseSocket: %s errored when shutting down socket: %i (%s)", GetRemoteIpAddress().to_string().c_str(),
shutdownError.value(), shutdownError.message().c_str());
+
+ OnClose();
}
/// Marks the socket for closing after write buffer becomes empty
@@ -146,6 +131,8 @@ public:
MessageBuffer& GetReadBuffer() { return _readBuffer; }
protected:
+ virtual void OnClose() { }
+
virtual void ReadHandler() = 0;
bool AsyncProcessQueue(std::unique_lock<std::mutex>&)
diff --git a/src/server/shared/Networking/SocketMgr.h b/src/server/shared/Networking/SocketMgr.h
index df57baf257e..2078ae90c62 100644
--- a/src/server/shared/Networking/SocketMgr.h
+++ b/src/server/shared/Networking/SocketMgr.h
@@ -99,7 +99,7 @@ public:
}
catch (boost::system::system_error const& err)
{
- TC_LOG_INFO("network", "Failed to retrieve client's remote address %s", err.what());
+ TC_LOG_WARN("network", "Failed to retrieve client's remote address %s", err.what());
}
}
diff --git a/src/server/shared/PrecompiledHeaders/sharedPCH.h b/src/server/shared/PrecompiledHeaders/sharedPCH.h
index d0c15b17f0c..87af9f44eb7 100644
--- a/src/server/shared/PrecompiledHeaders/sharedPCH.h
+++ b/src/server/shared/PrecompiledHeaders/sharedPCH.h
@@ -6,3 +6,4 @@
#include "SQLOperation.h"
#include "Errors.h"
#include "TypeList.h"
+#include "TaskScheduler.h"
diff --git a/src/server/shared/Threading/ProducerConsumerQueue.h b/src/server/shared/Threading/ProducerConsumerQueue.h
index ab01568309b..e2f13e5c339 100644
--- a/src/server/shared/Threading/ProducerConsumerQueue.h
+++ b/src/server/shared/Threading/ProducerConsumerQueue.h
@@ -70,7 +70,9 @@ public:
{
std::unique_lock<std::mutex> lock(_queueLock);
- _condition.wait(lock, [this]() { return !_queue.empty() || _shutdown; });
+ // we could be using .wait(lock, predicate) overload here but some threading error analysis tools produce false positives
+ while (_queue.empty() && !_shutdown)
+ _condition.wait(lock);
if (_queue.empty() || _shutdown)
return;
diff --git a/src/server/shared/Updater/DBUpdater.cpp b/src/server/shared/Updater/DBUpdater.cpp
new file mode 100644
index 00000000000..20ded669cec
--- /dev/null
+++ b/src/server/shared/Updater/DBUpdater.cpp
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "DBUpdater.h"
+#include "Log.h"
+#include "revision.h"
+#include "UpdateFetcher.h"
+#include "DatabaseLoader.h"
+#include "Config.h"
+
+#include <fstream>
+#include <iostream>
+#include <unordered_map>
+#include <boost/process.hpp>
+#include <boost/iostreams/device/file_descriptor.hpp>
+#include <boost/system/system_error.hpp>
+
+using namespace boost::process;
+using namespace boost::process::initializers;
+using namespace boost::iostreams;
+
+template<class T>
+std::string DBUpdater<T>::GetSourceDirectory()
+{
+ std::string const entry = sConfigMgr->GetStringDefault("Updates.SourcePath", "");
+ if (!entry.empty())
+ return entry;
+ else
+ return _SOURCE_DIRECTORY;
+}
+
+template<class T>
+std::string DBUpdater<T>::GetMySqlCli()
+{
+ std::string const entry = sConfigMgr->GetStringDefault("Updates.MySqlCLIPath", "");
+ if (!entry.empty())
+ return entry;
+ else
+ return _MYSQL_EXECUTABLE;
+}
+
+// Auth Database
+template<>
+std::string DBUpdater<LoginDatabaseConnection>::GetConfigEntry()
+{
+ return "Updates.Auth";
+}
+
+template<>
+std::string DBUpdater<LoginDatabaseConnection>::GetTableName()
+{
+ return "Auth";
+}
+
+template<>
+std::string DBUpdater<LoginDatabaseConnection>::GetBaseFile()
+{
+ return DBUpdater<LoginDatabaseConnection>::GetSourceDirectory() + "/sql/base/auth_database.sql";
+}
+
+template<>
+bool DBUpdater<LoginDatabaseConnection>::IsEnabled(uint32 const updateMask)
+{
+ // This way silences warnings under msvc
+ return (updateMask & DatabaseLoader::DATABASE_LOGIN) ? true : false;
+}
+
+// World Database
+template<>
+std::string DBUpdater<WorldDatabaseConnection>::GetConfigEntry()
+{
+ return "Updates.World";
+}
+
+template<>
+std::string DBUpdater<WorldDatabaseConnection>::GetTableName()
+{
+ return "World";
+}
+
+template<>
+std::string DBUpdater<WorldDatabaseConnection>::GetBaseFile()
+{
+ return _FULL_DATABASE;
+}
+
+template<>
+bool DBUpdater<WorldDatabaseConnection>::IsEnabled(uint32 const updateMask)
+{
+ // This way silences warnings under msvc
+ return (updateMask & DatabaseLoader::DATABASE_WORLD) ? true : false;
+}
+
+template<>
+BaseLocation DBUpdater<WorldDatabaseConnection>::GetBaseLocationType()
+{
+ return LOCATION_DOWNLOAD;
+}
+
+// Character Database
+template<>
+std::string DBUpdater<CharacterDatabaseConnection>::GetConfigEntry()
+{
+ return "Updates.Character";
+}
+
+template<>
+std::string DBUpdater<CharacterDatabaseConnection>::GetTableName()
+{
+ return "Character";
+}
+
+template<>
+std::string DBUpdater<CharacterDatabaseConnection>::GetBaseFile()
+{
+ return DBUpdater<CharacterDatabaseConnection>::GetSourceDirectory() + "/sql/base/characters_database.sql";
+}
+
+template<>
+bool DBUpdater<CharacterDatabaseConnection>::IsEnabled(uint32 const updateMask)
+{
+ // This way silences warnings under msvc
+ return (updateMask & DatabaseLoader::DATABASE_CHARACTER) ? true : false;
+}
+
+// All
+template<class T>
+BaseLocation DBUpdater<T>::GetBaseLocationType()
+{
+ return LOCATION_REPOSITORY;
+}
+
+template<class T>
+bool DBUpdater<T>::CheckExecutable()
+{
+ DBUpdater<T>::Path const exe(DBUpdater<T>::GetMySqlCli());
+ if (!exists(exe))
+ {
+ // Check for mysql in path
+ std::vector<std::string> args = {"--version"};
+ uint32 ret;
+ try
+ {
+ child c = execute(run_exe("mysql"), set_args(args), throw_on_error(), close_stdout());
+ ret = wait_for_exit(c);
+ }
+ catch (boost::system::system_error&)
+ {
+ ret = EXIT_FAILURE;
+ }
+
+ if (ret == EXIT_FAILURE)
+ {
+ TC_LOG_FATAL("sql.updates", "Didn't find executeable mysql binary at \'%s\', correct the path in the *.conf (\"Updates.MySqlCLIPath\").",
+ absolute(exe).generic_string().c_str());
+
+ return false;
+ }
+ }
+ return true;
+}
+
+template<class T>
+bool DBUpdater<T>::Create(DatabaseWorkerPool<T>& pool)
+{
+ TC_LOG_INFO("sql.updates", "Database \"%s\" does not exist, do you want to create it? [yes (default) / no]: ",
+ pool.GetConnectionInfo()->database.c_str());
+
+ std::string answer;
+ std::getline(std::cin, answer);
+ if (!answer.empty() && !(answer.substr(0, 1) == "y"))
+ return false;
+
+ TC_LOG_INFO("sql.updates", "Creating database \"%s\"...", pool.GetConnectionInfo()->database.c_str());
+
+ // Path of temp file
+ static Path const temp("create_table.sql");
+
+ // Create temporary query to use external mysql cli
+ std::ofstream file(temp.generic_string());
+ if (!file.is_open())
+ {
+ TC_LOG_FATAL("sql.updates", "Failed to create temporary query file \"%s\"!", temp.generic_string().c_str());
+ return false;
+ }
+
+ file << "CREATE DATABASE `" << pool.GetConnectionInfo()->database << "` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci\n\n";
+
+ file.close();
+
+ try
+ {
+ DBUpdater<T>::ApplyFile(pool, pool.GetConnectionInfo()->host, pool.GetConnectionInfo()->user, pool.GetConnectionInfo()->password,
+ pool.GetConnectionInfo()->port_or_socket, "", temp);
+ }
+ catch (UpdateException&)
+ {
+ TC_LOG_FATAL("sql.updates", "Failed to create database %s! Has the user `CREATE` priviliges?", pool.GetConnectionInfo()->database.c_str());
+ boost::filesystem::remove(temp);
+ return false;
+ }
+
+ TC_LOG_INFO("sql.updates", "Done.");
+ boost::filesystem::remove(temp);
+ return true;
+}
+
+template<class T>
+bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool)
+{
+ if (!DBUpdater<T>::CheckExecutable())
+ return false;
+
+ TC_LOG_INFO("sql.updates", "Updating %s database...", DBUpdater<T>::GetTableName().c_str());
+
+ Path const sourceDirectory(GetSourceDirectory());
+
+ if (!is_directory(sourceDirectory))
+ {
+ TC_LOG_ERROR("sql.updates", "DBUpdater: Given source directory %s does not exist, skipped!", sourceDirectory.generic_string().c_str());
+ return false;
+ }
+
+ UpdateFetcher updateFetcher(sourceDirectory, [&](std::string const& query) { DBUpdater<T>::Apply(pool, query); },
+ [&](Path const& file) { DBUpdater<T>::ApplyFile(pool, file); },
+ [&](std::string const& query) -> QueryResult { return DBUpdater<T>::Retrieve(pool, query); });
+
+ uint32 count;
+ try
+ {
+ count = updateFetcher.Update(
+ sConfigMgr->GetBoolDefault("Updates.Redundancy", true),
+ sConfigMgr->GetBoolDefault("Updates.AllowRehash", true),
+ sConfigMgr->GetBoolDefault("Updates.ArchivedRedundancy", false),
+ sConfigMgr->GetIntDefault("Updates.CleanDeadRefMaxCount", 3));
+ }
+ catch (UpdateException&)
+ {
+ return false;
+ }
+
+ if (!count)
+ TC_LOG_INFO("sql.updates", ">> %s database is up-to-date!", DBUpdater<T>::GetTableName().c_str());
+ else
+ TC_LOG_INFO("sql.updates", ">> Applied %d %s.", count, count == 1 ? "query" : "queries");
+
+ return true;
+}
+
+template<class T>
+bool DBUpdater<T>::Populate(DatabaseWorkerPool<T>& pool)
+{
+ {
+ QueryResult const result = Retrieve(pool, "SHOW TABLES");
+ if (result && (result->GetRowCount() > 0))
+ return true;
+ }
+
+ if (!DBUpdater<T>::CheckExecutable())
+ return false;
+
+ TC_LOG_INFO("sql.updates", "Database %s is empty, auto populating it...", DBUpdater<T>::GetTableName().c_str());
+
+ std::string const p = DBUpdater<T>::GetBaseFile();
+ if (p.empty())
+ {
+ TC_LOG_INFO("sql.updates", ">> No base file provided, skipped!");
+ return true;
+ }
+
+ Path const base(p);
+ if (!exists(base))
+ {
+ switch (DBUpdater<T>::GetBaseLocationType())
+ {
+ case LOCATION_REPOSITORY:
+ {
+ TC_LOG_ERROR("sql.updates", ">> Base file \"%s\" is missing, try to clone the source again.",
+ base.generic_string().c_str());
+
+ break;
+ }
+ case LOCATION_DOWNLOAD:
+ {
+ TC_LOG_ERROR("sql.updates", ">> File \"%s\" is missing, download it from \"http://www.trinitycore.org/f/files/category/1-database/\"" \
+ " and place it in your server directory.", base.filename().generic_string().c_str());
+ break;
+ }
+ }
+ return false;
+ }
+
+ // Update database
+ TC_LOG_INFO("sql.updates", ">> Applying \'%s\'...", base.generic_string().c_str());
+ try
+ {
+ ApplyFile(pool, base);
+ }
+ catch (UpdateException&)
+ {
+ return false;
+ }
+
+ TC_LOG_INFO("sql.updates", ">> Done!");
+ return true;
+}
+
+template<class T>
+QueryResult DBUpdater<T>::Retrieve(DatabaseWorkerPool<T>& pool, std::string const& query)
+{
+ return pool.PQuery(query.c_str());
+}
+
+template<class T>
+void DBUpdater<T>::Apply(DatabaseWorkerPool<T>& pool, std::string const& query)
+{
+ pool.DirectExecute(query.c_str());
+}
+
+template<class T>
+void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, Path const& path)
+{
+ DBUpdater<T>::ApplyFile(pool, pool.GetConnectionInfo()->host, pool.GetConnectionInfo()->user, pool.GetConnectionInfo()->password,
+ pool.GetConnectionInfo()->port_or_socket, pool.GetConnectionInfo()->database, path);
+}
+
+template<class T>
+void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& host, std::string const& user,
+ std::string const& password, std::string const& port_or_socket, std::string const& database, Path const& path)
+{
+ std::vector<std::string> args;
+ args.reserve(7);
+
+ // CLI Client connection info
+ args.push_back("-h" + host);
+ args.push_back("-u" + user);
+ args.push_back("-p" + password);
+
+ // Check if we want to connect through ip or socket (Unix only)
+#ifdef _WIN32
+
+ args.push_back("-P" + port_or_socket);
+
+#else
+
+ if (!std::isdigit(port_or_socket[0]))
+ {
+ // We can't check here if host == "." because is named localhost if socket option is enabled
+ args.push_back("-P0");
+ args.push_back("--protocol=SOCKET");
+ args.push_back("-S" + port_or_socket);
+ }
+ else
+ // generic case
+ args.push_back("-P" + port_or_socket);
+
+#endif
+
+ // Set the default charset to utf8
+ args.push_back("--default-character-set=utf8");
+
+ // Set max allowed packet to 1 GB
+ args.push_back("--max-allowed-packet=1GB");
+
+ // Database
+ if (!database.empty())
+ args.push_back(database);
+
+ // ToDo: use the existing query in memory as virtual file if possible
+ file_descriptor_source source(path);
+
+ uint32 ret;
+ try
+ {
+ child c = execute(run_exe(DBUpdater<T>::GetMySqlCli().empty() ? "mysql" :
+ boost::filesystem::absolute(DBUpdater<T>::GetMySqlCli()).generic_string()),
+ set_args(args), bind_stdin(source), throw_on_error());
+
+ ret = wait_for_exit(c);
+ }
+ catch (boost::system::system_error&)
+ {
+ ret = EXIT_FAILURE;
+ }
+
+ source.close();
+
+ if (ret != EXIT_SUCCESS)
+ {
+ TC_LOG_FATAL("sql.updates", "Applying of file \'%s\' to database \'%s\' failed!" \
+ " If you are an user pull the latest revision from the repository. If you are a developer fix your sql query.",
+ path.generic_string().c_str(), pool.GetConnectionInfo()->database.c_str());
+
+ throw UpdateException("update failed");
+ }
+}
+
+template class DBUpdater<LoginDatabaseConnection>;
+template class DBUpdater<WorldDatabaseConnection>;
+template class DBUpdater<CharacterDatabaseConnection>;
diff --git a/src/server/shared/Updater/DBUpdater.h b/src/server/shared/Updater/DBUpdater.h
new file mode 100644
index 00000000000..0caf8a438fb
--- /dev/null
+++ b/src/server/shared/Updater/DBUpdater.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DBUpdater_h__
+#define DBUpdater_h__
+
+#include "DatabaseEnv.h"
+
+#include <string>
+#include <boost/filesystem.hpp>
+
+class UpdateException : public std::exception
+{
+public:
+ UpdateException(std::string const& msg) : _msg(msg) { }
+ ~UpdateException() throw() { }
+
+ char const* what() const throw() override { return _msg.c_str(); }
+
+private:
+ std::string const _msg;
+};
+
+enum BaseLocation
+{
+ LOCATION_REPOSITORY,
+ LOCATION_DOWNLOAD
+};
+
+template <class T>
+class DBUpdater
+{
+public:
+ using Path = boost::filesystem::path;
+
+ static std::string GetSourceDirectory();
+
+ static inline std::string GetConfigEntry();
+
+ static inline std::string GetTableName();
+
+ static std::string GetBaseFile();
+
+ static bool IsEnabled(uint32 const updateMask);
+
+ static BaseLocation GetBaseLocationType();
+
+ static bool Create(DatabaseWorkerPool<T>& pool);
+
+ static bool Update(DatabaseWorkerPool<T>& pool);
+
+ static bool Populate(DatabaseWorkerPool<T>& pool);
+
+private:
+ static std::string GetMySqlCli();
+ static bool CheckExecutable();
+
+ static QueryResult Retrieve(DatabaseWorkerPool<T>& pool, std::string const& query);
+ static void Apply(DatabaseWorkerPool<T>& pool, std::string const& query);
+ static void ApplyFile(DatabaseWorkerPool<T>& pool, Path const& path);
+ static void ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& host, std::string const& user,
+ std::string const& password, std::string const& port_or_socket, std::string const& database, Path const& path);
+};
+
+#endif // DBUpdater_h__
diff --git a/src/server/shared/Updater/UpdateFetcher.cpp b/src/server/shared/Updater/UpdateFetcher.cpp
new file mode 100644
index 00000000000..a4bdd193743
--- /dev/null
+++ b/src/server/shared/Updater/UpdateFetcher.cpp
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "UpdateFetcher.h"
+#include "Log.h"
+#include "Util.h"
+
+#include <fstream>
+#include <chrono>
+#include <vector>
+#include <sstream>
+#include <exception>
+#include <unordered_map>
+#include <openssl/sha.h>
+
+using namespace boost::filesystem;
+
+UpdateFetcher::UpdateFetcher(Path const& sourceDirectory,
+ std::function<void(std::string const&)> const& apply,
+ std::function<void(Path const& path)> const& applyFile,
+ std::function<QueryResult(std::string const&)> const& retrieve) :
+ _sourceDirectory(sourceDirectory), _apply(apply), _applyFile(applyFile),
+ _retrieve(retrieve)
+{
+}
+
+UpdateFetcher::LocaleFileStorage UpdateFetcher::GetFileList() const
+{
+ LocaleFileStorage files;
+ DirectoryStorage directories = ReceiveIncludedDirectories();
+ for (auto const& entry : directories)
+ FillFileListRecursively(entry.path, files, entry.state, 1);
+
+ return files;
+}
+
+void UpdateFetcher::FillFileListRecursively(Path const& path, LocaleFileStorage& storage, State const state, uint32 const depth) const
+{
+ static uint32 const MAX_DEPTH = 10;
+ static directory_iterator const end;
+
+ for (directory_iterator itr(path); itr != end; ++itr)
+ {
+ if (is_directory(itr->path()))
+ {
+ if (depth < MAX_DEPTH)
+ FillFileListRecursively(itr->path(), storage, state, depth + 1);
+ }
+ else if (itr->path().extension() == ".sql")
+ {
+ TC_LOG_TRACE("sql.updates", "Added locale file \"%s\".", itr->path().filename().generic_string().c_str());
+
+ LocaleFileEntry const entry = { itr->path(), state };
+
+ // Check for doubled filenames
+ // Since elements are only compared through their filenames this is ok
+ if (storage.find(entry) != storage.end())
+ {
+ TC_LOG_FATAL("sql.updates", "Duplicated filename occurred \"%s\", since updates are ordered " \
+ "through its filename every name needs to be unique!", itr->path().generic_string().c_str());
+
+ throw UpdateException("Updating failed, see the log for details.");
+ }
+
+ storage.insert(entry);
+ }
+ }
+}
+
+UpdateFetcher::DirectoryStorage UpdateFetcher::ReceiveIncludedDirectories() const
+{
+ DirectoryStorage directories;
+
+ QueryResult const result = _retrieve("SELECT `path`, `state` FROM `updates_include`");
+ if (!result)
+ return directories;
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ std::string path = fields[0].GetString();
+ if (path.substr(0, 1) == "$")
+ path = _sourceDirectory.generic_string() + path.substr(1);
+
+ Path const p(path);
+
+ if (!is_directory(p))
+ {
+ TC_LOG_WARN("sql.updates", "DBUpdater: Given update include directory \"%s\" isn't existing, skipped!", p.generic_string().c_str());
+ continue;
+ }
+
+ DirectoryEntry const entry = { p, AppliedFileEntry::StateConvert(fields[1].GetString()) };
+ directories.push_back(entry);
+
+ TC_LOG_TRACE("sql.updates", "Added applied file \"%s\" from remote.", p.filename().generic_string().c_str());
+
+ } while (result->NextRow());
+
+ return directories;
+}
+
+UpdateFetcher::AppliedFileStorage UpdateFetcher::ReceiveAppliedFiles() const
+{
+ AppliedFileStorage map;
+
+ QueryResult result = _retrieve("SELECT `name`, `hash`, `state`, UNIX_TIMESTAMP(`timestamp`) FROM `updates` ORDER BY `name` ASC");
+ if (!result)
+ return map;
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ AppliedFileEntry const entry = { fields[0].GetString(), fields[1].GetString(),
+ AppliedFileEntry::StateConvert(fields[2].GetString()), fields[3].GetUInt64() };
+
+ map.insert(std::make_pair(entry.name, entry));
+ }
+ while (result->NextRow());
+
+ return map;
+}
+
+UpdateFetcher::SQLUpdate UpdateFetcher::ReadSQLUpdate(boost::filesystem::path const& file) const
+{
+ std::ifstream in(file.c_str());
+ WPFatal(in.is_open(), "Could not read an update file.");
+
+ auto const start_pos = in.tellg();
+ in.ignore(std::numeric_limits<std::streamsize>::max());
+ auto const char_count = in.gcount();
+ in.seekg(start_pos);
+
+ SQLUpdate const update(new std::string(char_count, char{}));
+
+ in.read(&(*update)[0], update->size());
+ in.close();
+ return update;
+}
+
+uint32 UpdateFetcher::Update(bool const redundancyChecks, bool const allowRehash, bool const archivedRedundancy, int32 const cleanDeadReferencesMaxCount) const
+{
+ LocaleFileStorage const available = GetFileList();
+ AppliedFileStorage applied = ReceiveAppliedFiles();
+
+ // Fill hash to name cache
+ HashToFileNameStorage hashToName;
+ for (auto entry : applied)
+ hashToName.insert(std::make_pair(entry.second.hash, entry.first));
+
+ uint32 importedUpdates = 0;
+
+ for (auto const& availableQuery : available)
+ {
+ TC_LOG_DEBUG("sql.updates", "Checking update \"%s\"...", availableQuery.first.filename().generic_string().c_str());
+
+ AppliedFileStorage::const_iterator iter = applied.find(availableQuery.first.filename().string());
+ if (iter != applied.end())
+ {
+ // If redundancy is disabled skip it since the update is already applied.
+ if (!redundancyChecks)
+ {
+ TC_LOG_DEBUG("sql.updates", ">> Update is already applied, skipping redundancy checks.");
+ applied.erase(iter);
+ continue;
+ }
+
+ // If the update is in an archived directory and is marked as archived in our database skip redundancy checks (archived updates never change).
+ if (!archivedRedundancy && (iter->second.state == ARCHIVED) && (availableQuery.second == ARCHIVED))
+ {
+ TC_LOG_DEBUG("sql.updates", ">> Update is archived and marked as archived in database, skipping redundancy checks.");
+ applied.erase(iter);
+ continue;
+ }
+ }
+
+ // Read update from file
+ SQLUpdate const update = ReadSQLUpdate(availableQuery.first);
+
+ // Calculate hash
+ std::string const hash = CalculateHash(update);
+
+ UpdateMode mode = MODE_APPLY;
+
+ // Update is not in our applied list
+ if (iter == applied.end())
+ {
+ // Catch renames (different filename but same hash)
+ HashToFileNameStorage::const_iterator const hashIter = hashToName.find(hash);
+ if (hashIter != hashToName.end())
+ {
+ // Check if the original file was removed if not we've got a problem.
+ LocaleFileStorage::const_iterator localeIter;
+ // Push localeIter forward
+ for (localeIter = available.begin(); (localeIter != available.end()) &&
+ (localeIter->first.filename().string() != hashIter->second); ++localeIter);
+
+ // Conflict!
+ if (localeIter != available.end())
+ {
+ TC_LOG_WARN("sql.updates", ">> Seems like update \"%s\" \'%s\' was renamed, but the old file is still there! " \
+ "Trade it as a new file! (Probably its an unmodified copy of file \"%s\")",
+ availableQuery.first.filename().string().c_str(), hash.substr(0, 7).c_str(),
+ localeIter->first.filename().string().c_str());
+ }
+ // Its save to trade the file as renamed here
+ else
+ {
+ TC_LOG_INFO("sql.updates", ">> Renaming update \"%s\" to \"%s\" \'%s\'.",
+ hashIter->second.c_str(), availableQuery.first.filename().string().c_str(), hash.substr(0, 7).c_str());
+
+ RenameEntry(hashIter->second, availableQuery.first.filename().string());
+ applied.erase(hashIter->second);
+ continue;
+ }
+ }
+ // Apply the update if it was never seen before.
+ else
+ {
+ TC_LOG_INFO("sql.updates", ">> Applying update \"%s\" \'%s\'...",
+ availableQuery.first.filename().string().c_str(), hash.substr(0, 7).c_str());
+ }
+ }
+ // Rehash the update entry if it is contained in our database but with an empty hash.
+ else if (allowRehash && iter->second.hash.empty())
+ {
+ mode = MODE_REHASH;
+
+ TC_LOG_INFO("sql.updates", ">> Re-hashing update \"%s\" \'%s\'...", availableQuery.first.filename().string().c_str(),
+ hash.substr(0, 7).c_str());
+ }
+ else
+ {
+ // If the hash of the files differs from the one stored in our database reapply the update (because it was changed).
+ if (iter->second.hash != hash)
+ {
+ TC_LOG_INFO("sql.updates", ">> Reapplying update \"%s\" \'%s\' -> \'%s\' (it changed)...", availableQuery.first.filename().string().c_str(),
+ iter->second.hash.substr(0, 7).c_str(), hash.substr(0, 7).c_str());
+ }
+ else
+ {
+ // If the file wasn't changed and just moved update its state if necessary.
+ if (iter->second.state != availableQuery.second)
+ {
+ TC_LOG_DEBUG("sql.updates", ">> Updating state of \"%s\" to \'%s\'...",
+ availableQuery.first.filename().string().c_str(), AppliedFileEntry::StateConvert(availableQuery.second).c_str());
+
+ UpdateState(availableQuery.first.filename().string(), availableQuery.second);
+ }
+
+ TC_LOG_DEBUG("sql.updates", ">> Update is already applied and is matching hash \'%s\'.", hash.substr(0, 7).c_str());
+
+ applied.erase(iter);
+ continue;
+ }
+ }
+
+ uint32 speed = 0;
+ AppliedFileEntry const file = { availableQuery.first.filename().string(), hash, availableQuery.second, 0 };
+
+ switch (mode)
+ {
+ case MODE_APPLY:
+ speed = Apply(availableQuery.first);
+ /*no break*/
+ case MODE_REHASH:
+ UpdateEntry(file, speed);
+ break;
+ }
+
+ if (iter != applied.end())
+ applied.erase(iter);
+
+ if (mode == MODE_APPLY)
+ ++importedUpdates;
+ }
+
+ // Cleanup up orphaned entries if enabled
+ if (!applied.empty())
+ {
+ bool const doCleanup = (cleanDeadReferencesMaxCount < 0) || (applied.size() <= static_cast<size_t>(cleanDeadReferencesMaxCount));
+
+ for (auto const& entry : applied)
+ {
+ TC_LOG_WARN("sql.updates", ">> File \'%s\' was applied to the database but is missing in" \
+ " your update directory now!", entry.first.c_str());
+
+ if (doCleanup)
+ TC_LOG_INFO("sql.updates", "Deleting orphaned entry \'%s\'...", entry.first.c_str());
+ }
+
+ if (doCleanup)
+ CleanUp(applied);
+ else
+ {
+ TC_LOG_ERROR("sql.updates", "Cleanup is disabled! There are " SZFMTD " dirty files that were applied to your database " \
+ "but are now missing in your source directory!", applied.size());
+ }
+ }
+
+ return importedUpdates;
+}
+
+std::string UpdateFetcher::CalculateHash(SQLUpdate const& query) const
+{
+ // Calculate a Sha1 hash based on query content.
+ unsigned char digest[SHA_DIGEST_LENGTH];
+ SHA1((unsigned char*)query->c_str(), query->length(), (unsigned char*)&digest);
+
+ return ByteArrayToHexStr(digest, SHA_DIGEST_LENGTH);
+}
+
+uint32 UpdateFetcher::Apply(Path const& path) const
+{
+ using Time = std::chrono::high_resolution_clock;
+ using ms = std::chrono::milliseconds;
+
+ // Benchmark query speed
+ auto const begin = Time::now();
+
+ // Update database
+ _applyFile(path);
+
+ // Return time the query took to apply
+ return std::chrono::duration_cast<ms>(Time::now() - begin).count();
+}
+
+void UpdateFetcher::UpdateEntry(AppliedFileEntry const& entry, uint32 const speed) const
+{
+ std::string const update = "REPLACE INTO `updates` (`name`, `hash`, `state`, `speed`) VALUES (\"" +
+ entry.name + "\", \"" + entry.hash + "\", \'" + entry.GetStateAsString() + "\', " + std::to_string(speed) + ")";
+
+ // Update database
+ _apply(update);
+}
+
+void UpdateFetcher::RenameEntry(std::string const& from, std::string const& to) const
+{
+ // Delete target if it exists
+ {
+ std::string const update = "DELETE FROM `updates` WHERE `name`=\"" + to + "\"";
+
+ // Update database
+ _apply(update);
+ }
+
+ // Rename
+ {
+ std::string const update = "UPDATE `updates` SET `name`=\"" + to + "\" WHERE `name`=\"" + from + "\"";
+
+ // Update database
+ _apply(update);
+ }
+}
+
+void UpdateFetcher::CleanUp(AppliedFileStorage const& storage) const
+{
+ if (storage.empty())
+ return;
+
+ std::stringstream update;
+ size_t remaining = storage.size();
+
+ update << "DELETE FROM `updates` WHERE `name` IN(";
+
+ for (auto const& entry : storage)
+ {
+ update << "\"" << entry.first << "\"";
+ if ((--remaining) > 0)
+ update << ", ";
+ }
+
+ update << ")";
+
+ // Update database
+ _apply(update.str());
+}
+
+void UpdateFetcher::UpdateState(std::string const& name, State const state) const
+{
+ std::string const update = "UPDATE `updates` SET `state`=\'" + AppliedFileEntry::StateConvert(state) + "\' WHERE `name`=\"" + name + "\"";
+
+ // Update database
+ _apply(update);
+}
diff --git a/src/server/shared/Updater/UpdateFetcher.h b/src/server/shared/Updater/UpdateFetcher.h
new file mode 100644
index 00000000000..fa142547873
--- /dev/null
+++ b/src/server/shared/Updater/UpdateFetcher.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef UpdateFetcher_h__
+#define UpdateFetcher_h__
+
+#include <DBUpdater.h>
+
+#include <functional>
+#include <string>
+#include <memory>
+#include <vector>
+
+class UpdateFetcher
+{
+ typedef boost::filesystem::path Path;
+
+public:
+ UpdateFetcher(Path const& updateDirectory,
+ std::function<void(std::string const&)> const& apply,
+ std::function<void(Path const& path)> const& applyFile,
+ std::function<QueryResult(std::string const&)> const& retrieve);
+
+ uint32 Update(bool const redundancyChecks, bool const allowRehash,
+ bool const archivedRedundancy, int32 const cleanDeadReferencesMaxCount) const;
+
+private:
+ enum UpdateMode
+ {
+ MODE_APPLY,
+ MODE_REHASH
+ };
+
+ enum State
+ {
+ RELEASED,
+ ARCHIVED
+ };
+
+ struct AppliedFileEntry
+ {
+ AppliedFileEntry(std::string const& name_, std::string const& hash_, State state_, uint64 timestamp_)
+ : name(name_), hash(hash_), state(state_), timestamp(timestamp_) { }
+
+ std::string const name;
+
+ std::string const hash;
+
+ State const state;
+
+ uint64 const timestamp;
+
+ static inline State StateConvert(std::string const& state)
+ {
+ return (state == "RELEASED") ? RELEASED : ARCHIVED;
+ }
+
+ static inline std::string StateConvert(State const state)
+ {
+ return (state == RELEASED) ? "RELEASED" : "ARCHIVED";
+ }
+
+ std::string GetStateAsString() const
+ {
+ return StateConvert(state);
+ }
+ };
+
+ struct DirectoryEntry
+ {
+ DirectoryEntry(Path const& path_, State state_) : path(path_), state(state_) { }
+
+ Path const path;
+
+ State const state;
+ };
+
+ typedef std::pair<Path, State> LocaleFileEntry;
+
+ struct PathCompare
+ {
+ inline bool operator() (LocaleFileEntry const& left, LocaleFileEntry const& right) const
+ {
+ return left.first.filename().string() < right.first.filename().string();
+ }
+ };
+
+ typedef std::set<LocaleFileEntry, PathCompare> LocaleFileStorage;
+ typedef std::unordered_map<std::string, std::string> HashToFileNameStorage;
+ typedef std::unordered_map<std::string, AppliedFileEntry> AppliedFileStorage;
+ typedef std::vector<UpdateFetcher::DirectoryEntry> DirectoryStorage;
+ typedef std::shared_ptr<std::string> SQLUpdate;
+
+ LocaleFileStorage GetFileList() const;
+ void FillFileListRecursively(Path const& path, LocaleFileStorage& storage, State const state, uint32 const depth) const;
+
+ DirectoryStorage ReceiveIncludedDirectories() const;
+ AppliedFileStorage ReceiveAppliedFiles() const;
+
+ SQLUpdate ReadSQLUpdate(Path const& file) const;
+ std::string CalculateHash(SQLUpdate const& query) const;
+
+ uint32 Apply(Path const& path) const;
+
+ void UpdateEntry(AppliedFileEntry const& entry, uint32 const speed = 0) const;
+ void RenameEntry(std::string const& from, std::string const& to) const;
+ void CleanUp(AppliedFileStorage const& storage) const;
+
+ void UpdateState(std::string const& name, State const state) const;
+
+ Path const _sourceDirectory;
+
+ std::function<void(std::string const&)> const _apply;
+ std::function<void(Path const& path)> const _applyFile;
+ std::function<QueryResult(std::string const&)> const _retrieve;
+};
+
+#endif // UpdateFetcher_h__
diff --git a/src/server/shared/Utilities/ServiceWin32.cpp b/src/server/shared/Utilities/ServiceWin32.cpp
index c73949fc6a3..3e5e416b1a3 100644
--- a/src/server/shared/Utilities/ServiceWin32.cpp
+++ b/src/server/shared/Utilities/ServiceWin32.cpp
@@ -255,7 +255,7 @@ bool WinServiceRun()
if (!StartServiceCtrlDispatcher(serviceTable))
{
- TC_LOG_ERROR("server.worldserver", "StartService Failed. Error [%u]", ::GetLastError());
+ TC_LOG_ERROR("server.worldserver", "StartService Failed. Error [%u]", uint32(::GetLastError()));
return false;
}
return true;
diff --git a/src/server/shared/Utilities/StringFormat.h b/src/server/shared/Utilities/StringFormat.h
new file mode 100644
index 00000000000..70d9aefb14d
--- /dev/null
+++ b/src/server/shared/Utilities/StringFormat.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TRINITYCORE_STRING_FORMAT_H
+#define TRINITYCORE_STRING_FORMAT_H
+
+#include <format.h>
+
+namespace Trinity
+{
+ //! Default TC string format function
+ template<typename... Args>
+ inline std::string StringFormat(const char* fmt, Args const&... args)
+ {
+ return fmt::sprintf(fmt, args...);
+ }
+}
+
+#endif
diff --git a/src/server/shared/Utilities/TaskScheduler.cpp b/src/server/shared/Utilities/TaskScheduler.cpp
new file mode 100644
index 00000000000..4b261413fd9
--- /dev/null
+++ b/src/server/shared/Utilities/TaskScheduler.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "TaskScheduler.h"
+
+TaskScheduler& TaskScheduler::Update()
+{
+ _now = clock_t::now();
+ Dispatch();
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::Update(size_t const milliseconds)
+{
+ return Update(std::chrono::milliseconds(milliseconds));
+}
+
+TaskScheduler& TaskScheduler::Async(std::function<void()> const& callable)
+{
+ _asyncHolder.push(callable);
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::CancelAll()
+{
+ /// Clear the task holder
+ _task_holder.Clear();
+ _asyncHolder = AsyncHolder();
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::CancelGroup(group_t const group)
+{
+ _task_holder.RemoveIf([group](TaskContainer const& task) -> bool
+ {
+ return task->IsInGroup(group);
+ });
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::CancelGroupsOf(std::vector<group_t> const& groups)
+{
+ std::for_each(groups.begin(), groups.end(),
+ std::bind(&TaskScheduler::CancelGroup, this, std::placeholders::_1));
+
+ return *this;
+}
+
+TaskScheduler& TaskScheduler::InsertTask(TaskContainer task)
+{
+ _task_holder.Push(std::move(task));
+ return *this;
+}
+
+void TaskScheduler::Dispatch()
+{
+ // Process all asyncs
+ while (!_asyncHolder.empty())
+ {
+ _asyncHolder.front()();
+ _asyncHolder.pop();
+ }
+
+ while (!_task_holder.IsEmpty())
+ {
+ if (_task_holder.First()->_end > _now)
+ break;
+
+ // Perfect forward the context to the handler
+ // Use weak references to catch destruction before callbacks.
+ TaskContext context(_task_holder.Pop(), std::weak_ptr<TaskScheduler>(self_reference));
+
+ // Invoke the context
+ context.Invoke();
+ }
+}
+
+void TaskScheduler::TaskQueue::Push(TaskContainer&& task)
+{
+ container.insert(task);
+}
+
+auto TaskScheduler::TaskQueue::Pop() -> TaskContainer
+{
+ TaskContainer result = *container.begin();
+ container.erase(container.begin());
+ return result;
+}
+
+auto TaskScheduler::TaskQueue::First() const -> TaskContainer const&
+{
+ return *container.begin();
+}
+
+void TaskScheduler::TaskQueue::Clear()
+{
+ container.clear();
+}
+
+void TaskScheduler::TaskQueue::RemoveIf(std::function<bool(TaskContainer const&)> const& filter)
+{
+ for (auto itr = container.begin(); itr != container.end();)
+ if (filter(*itr))
+ itr = container.erase(itr);
+ else
+ ++itr;
+}
+
+void TaskScheduler::TaskQueue::ModifyIf(std::function<bool(TaskContainer const&)> const& filter)
+{
+ std::vector<TaskContainer> cache;
+ for (auto itr = container.begin(); itr != container.end();)
+ if (filter(*itr))
+ {
+ cache.push_back(*itr);
+ itr = container.erase(itr);
+ }
+ else
+ ++itr;
+
+ container.insert(cache.begin(), cache.end());
+}
+
+bool TaskScheduler::TaskQueue::IsEmpty() const
+{
+ return container.empty();
+}
+
+TaskContext& TaskContext::Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply)
+{
+ if (auto const owner = _owner.lock())
+ apply(*owner);
+
+ return *this;
+}
+
+bool TaskContext::IsExpired() const
+{
+ return _owner.expired();
+}
+
+bool TaskContext::IsInGroup(TaskScheduler::group_t const group) const
+{
+ return _task->IsInGroup(group);
+}
+
+TaskContext& TaskContext::SetGroup(TaskScheduler::group_t const group)
+{
+ _task->_group = group;
+ return *this;
+}
+
+TaskContext& TaskContext::ClearGroup()
+{
+ _task->_group = boost::none;
+ return *this;
+}
+
+TaskScheduler::repeated_t TaskContext::GetRepeatCounter() const
+{
+ return _task->_repeated;
+}
+
+TaskContext& TaskContext::Async(std::function<void()> const& callable)
+{
+ return Dispatch(std::bind(&TaskScheduler::Async, std::placeholders::_1, callable));
+}
+
+TaskContext& TaskContext::CancelAll()
+{
+ return Dispatch(std::mem_fn(&TaskScheduler::CancelAll));
+}
+
+TaskContext& TaskContext::CancelGroup(TaskScheduler::group_t const group)
+{
+ return Dispatch(std::bind(&TaskScheduler::CancelGroup, std::placeholders::_1, group));
+}
+
+TaskContext& TaskContext::CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups)
+{
+ return Dispatch(std::bind(&TaskScheduler::CancelGroupsOf, std::placeholders::_1, std::cref(groups)));
+}
+
+void TaskContext::AssertOnConsumed() const
+{
+ // This was adapted to TC to prevent static analysis tools from complaining.
+ // If you encounter this assertion check if you repeat a TaskContext more then 1 time!
+ ASSERT(!(*_consumed) && "Bad task logic, task context was consumed already!");
+}
+
+void TaskContext::Invoke()
+{
+ _task->_task(*this);
+}
diff --git a/src/server/shared/Utilities/TaskScheduler.h b/src/server/shared/Utilities/TaskScheduler.h
new file mode 100644
index 00000000000..98e210e55b1
--- /dev/null
+++ b/src/server/shared/Utilities/TaskScheduler.h
@@ -0,0 +1,627 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TASK_SCHEDULER_H_
+#define _TASK_SCHEDULER_H_
+
+#include <algorithm>
+#include <chrono>
+#include <vector>
+#include <queue>
+#include <memory>
+#include <utility>
+#include <set>
+
+#include <boost/optional.hpp>
+
+#include "Util.h"
+
+class TaskContext;
+
+/// The TaskScheduler class provides the ability to schedule std::function's in the near future.
+/// Use TaskScheduler::Update to update the scheduler.
+/// Popular methods are:
+/// * Schedule (Schedules a std::function which will be executed in the near future).
+/// * Schedules an asynchronous function which will be executed at the next update tick.
+/// * Cancel, Delay & Reschedule (Methods to manipulate already scheduled tasks).
+/// Tasks are organized in groups (uint), multiple tasks can have the same group id,
+/// you can provide a group or not, but keep in mind that you can only manipulate specific tasks through its group id!
+/// Tasks callbacks use the function signature void(TaskContext) where TaskContext provides
+/// access to the function schedule plan which makes it possible to repeat the task
+/// with the same duration or a new one.
+/// It also provides access to the repeat counter which is useful for task that repeat itself often
+/// but behave different every time (spoken event dialogs for example).
+class TaskScheduler
+{
+ friend class TaskContext;
+
+ // Time definitions (use steady clock)
+ typedef std::chrono::steady_clock clock_t;
+ typedef clock_t::time_point timepoint_t;
+ typedef clock_t::duration duration_t;
+
+ // Task group type
+ typedef uint32 group_t;
+ // Task repeated type
+ typedef uint32 repeated_t;
+ // Task handle type
+ typedef std::function<void(TaskContext)> task_handler_t;
+
+ class Task
+ {
+ friend class TaskContext;
+ friend class TaskScheduler;
+
+ timepoint_t _end;
+ duration_t _duration;
+ boost::optional<group_t> _group;
+ repeated_t _repeated;
+ task_handler_t _task;
+
+ public:
+ // All Argument construct
+ Task(timepoint_t const& end, duration_t const& duration, boost::optional<group_t> const& group,
+ repeated_t const repeated, task_handler_t const& task)
+ : _end(end), _duration(duration), _group(group), _repeated(repeated), _task(task) { }
+
+ // Minimal Argument construct
+ Task(timepoint_t const& end, duration_t const& duration, task_handler_t const& task)
+ : _end(end), _duration(duration), _group(boost::none), _repeated(0), _task(task) { }
+
+ // Copy construct
+ Task(Task const&) = delete;
+ // Move construct
+ Task(Task&&) = delete;
+ // Copy Assign
+ Task& operator= (Task const&) = default;
+ // Move Assign
+ Task& operator= (Task&& right) = delete;
+
+ // Order tasks by its end
+ inline bool operator< (Task const& other) const
+ {
+ return _end < other._end;
+ }
+
+ inline bool operator> (Task const& other) const
+ {
+ return _end > other._end;
+ }
+
+ // Compare tasks with its end
+ inline bool operator== (Task const& other)
+ {
+ return _end == other._end;
+ }
+
+ // Returns true if the task is in the given group
+ inline bool IsInGroup(group_t const group) const
+ {
+ return _group == group;
+ }
+ };
+
+ typedef std::shared_ptr<Task> TaskContainer;
+
+ /// Container which provides Task order, insert and reschedule operations.
+ struct Compare
+ {
+ bool operator() (TaskContainer const& left, TaskContainer const& right)
+ {
+ return (*left.get()) < (*right.get());
+ };
+ };
+
+ class TaskQueue
+ {
+ std::multiset<TaskContainer, Compare> container;
+
+ public:
+ // Pushes the task in the container
+ void Push(TaskContainer&& task);
+
+ /// Pops the task out of the container
+ TaskContainer Pop();
+
+ TaskContainer const& First() const;
+
+ void Clear();
+
+ void RemoveIf(std::function<bool(TaskContainer const&)> const& filter);
+
+ void ModifyIf(std::function<bool(TaskContainer const&)> const& filter);
+
+ bool IsEmpty() const;
+ };
+
+ /// Contains a self reference to track if this object was deleted or not.
+ std::shared_ptr<TaskScheduler> self_reference;
+
+ /// The current time point (now)
+ timepoint_t _now;
+
+ /// The Task Queue which contains all task objects.
+ TaskQueue _task_holder;
+
+ typedef std::queue<std::function<void()>> AsyncHolder;
+
+ /// Contains all asynchronous tasks which will be invoked at
+ /// the next update tick.
+ AsyncHolder _asyncHolder;
+
+public:
+ TaskScheduler() : self_reference(this, [](TaskScheduler const*) { }),
+ _now(clock_t::now()) { }
+
+ TaskScheduler(TaskScheduler const&) = delete;
+ TaskScheduler(TaskScheduler&&) = delete;
+ TaskScheduler& operator= (TaskScheduler const&) = delete;
+ TaskScheduler& operator= (TaskScheduler&&) = delete;
+
+ /// Update the scheduler to the current time.
+ TaskScheduler& Update();
+
+ /// Update the scheduler with a difftime in ms.
+ TaskScheduler& Update(size_t const milliseconds);
+
+ /// Update the scheduler with a difftime.
+ template<class _Rep, class _Period>
+ TaskScheduler& Update(std::chrono::duration<_Rep, _Period> const& difftime)
+ {
+ _now += difftime;
+ Dispatch();
+ return *this;
+ }
+
+ /// Schedule an callable function that is executed at the next update tick.
+ /// Its safe to modify the TaskScheduler from within the callable.
+ TaskScheduler& Async(std::function<void()> const& callable);
+
+ /// Schedule an event with a fixed rate.
+ /// Never call this from within a task context! Use TaskContext::Schedule instead!
+ template<class _Rep, class _Period>
+ TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time,
+ task_handler_t const& task)
+ {
+ return ScheduleAt(_now, time, task);
+ }
+
+ /// Schedule an event with a fixed rate.
+ /// Never call this from within a task context! Use TaskContext::Schedule instead!
+ template<class _Rep, class _Period>
+ TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time,
+ group_t const group, task_handler_t const& task)
+ {
+ return ScheduleAt(_now, time, group, task);
+ }
+
+ /// Schedule an event with a randomized rate between min and max rate.
+ /// Never call this from within a task context! Use TaskContext::Schedule instead!
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max, task_handler_t const& task)
+ {
+ return Schedule(RandomDurationBetween(min, max), task);
+ }
+
+ /// Schedule an event with a fixed rate.
+ /// Never call this from within a task context! Use TaskContext::Schedule instead!
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max, group_t const group,
+ task_handler_t const& task)
+ {
+ return Schedule(RandomDurationBetween(min, max), group, task);
+ }
+
+ /// Cancels all tasks.
+ /// Never call this from within a task context! Use TaskContext::CancelAll instead!
+ TaskScheduler& CancelAll();
+
+ /// Cancel all tasks of a single group.
+ /// Never call this from within a task context! Use TaskContext::CancelGroup instead!
+ TaskScheduler& CancelGroup(group_t const group);
+
+ /// Cancels all groups in the given std::vector.
+ /// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}"
+ TaskScheduler& CancelGroupsOf(std::vector<group_t> const& groups);
+
+ /// Delays all tasks with the given duration.
+ template<class _Rep, class _Period>
+ TaskScheduler& DelayAll(std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ _task_holder.ModifyIf([&duration](TaskContainer const& task) -> bool
+ {
+ task->_end += duration;
+ return true;
+ });
+ return *this;
+ }
+
+ /// Delays all tasks with a random duration between min and max.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskScheduler& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return DelayAll(RandomDurationBetween(min, max));
+ }
+
+ /// Delays all tasks of a group with the given duration.
+ template<class _Rep, class _Period>
+ TaskScheduler& DelayGroup(group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ _task_holder.ModifyIf([&duration, group](TaskContainer const& task) -> bool
+ {
+ if (task->IsInGroup(group))
+ {
+ task->_end += duration;
+ return true;
+ }
+ else
+ return false;
+ });
+ return *this;
+ }
+
+ /// Delays all tasks of a group with a random duration between min and max.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskScheduler& DelayGroup(group_t const group,
+ std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return DelayGroup(group, RandomDurationBetween(min, max));
+ }
+
+ /// Reschedule all tasks with a given duration.
+ template<class _Rep, class _Period>
+ TaskScheduler& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ auto const end = _now + duration;
+ _task_holder.ModifyIf([end](TaskContainer const& task) -> bool
+ {
+ task->_end = end;
+ return true;
+ });
+ return *this;
+ }
+
+ /// Reschedule all tasks with a random duration between min and max.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskScheduler& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return RescheduleAll(RandomDurationBetween(min, max));
+ }
+
+ /// Reschedule all tasks of a group with the given duration.
+ template<class _Rep, class _Period>
+ TaskScheduler& RescheduleGroup(group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ auto const end = _now + duration;
+ _task_holder.ModifyIf([end, group](TaskContainer const& task) -> bool
+ {
+ if (task->IsInGroup(group))
+ {
+ task->_end = end;
+ return true;
+ }
+ else
+ return false;
+ });
+ return *this;
+ }
+
+ /// Reschedule all tasks of a group with a random duration between min and max.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskScheduler& RescheduleGroup(group_t const group,
+ std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return RescheduleGroup(group, RandomDurationBetween(min, max));
+ }
+
+private:
+ /// Insert a new task to the enqueued tasks.
+ TaskScheduler& InsertTask(TaskContainer task);
+
+ template<class _Rep, class _Period>
+ TaskScheduler& ScheduleAt(timepoint_t const& end,
+ std::chrono::duration<_Rep, _Period> const& time, task_handler_t const& task)
+ {
+ return InsertTask(TaskContainer(new Task(end + time, time, task)));
+ }
+
+ /// Schedule an event with a fixed rate.
+ /// Never call this from within a task context! Use TaskContext::schedule instead!
+ template<class _Rep, class _Period>
+ TaskScheduler& ScheduleAt(timepoint_t const& end,
+ std::chrono::duration<_Rep, _Period> const& time,
+ group_t const group, task_handler_t const& task)
+ {
+ static repeated_t const DEFAULT_REPEATED = 0;
+ return InsertTask(TaskContainer(new Task(end + time, time, group, DEFAULT_REPEATED, task)));
+ }
+
+ // Returns a random duration between min and max
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ static std::chrono::milliseconds
+ RandomDurationBetween(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ auto const milli_min = std::chrono::duration_cast<std::chrono::milliseconds>(min);
+ auto const milli_max = std::chrono::duration_cast<std::chrono::milliseconds>(max);
+
+ // TC specific: use SFMT URandom
+ return std::chrono::milliseconds(urand(milli_min.count(), milli_max.count()));
+ }
+
+ /// Dispatch remaining tasks
+ void Dispatch();
+};
+
+class TaskContext
+{
+ friend class TaskScheduler;
+
+ /// Associated task
+ TaskScheduler::TaskContainer _task;
+
+ /// Owner
+ std::weak_ptr<TaskScheduler> _owner;
+
+ /// Marks the task as consumed
+ std::shared_ptr<bool> _consumed;
+
+ /// Dispatches an action safe on the TaskScheduler
+ TaskContext& Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply);
+
+public:
+ // Empty constructor
+ TaskContext()
+ : _task(), _owner(), _consumed(std::make_shared<bool>(true)) { }
+
+ // Construct from task and owner
+ explicit TaskContext(TaskScheduler::TaskContainer&& task, std::weak_ptr<TaskScheduler>&& owner)
+ : _task(task), _owner(owner), _consumed(std::make_shared<bool>(false)) { }
+
+ // Copy construct
+ TaskContext(TaskContext const& right)
+ : _task(right._task), _owner(right._owner), _consumed(right._consumed) { }
+
+ // Move construct
+ TaskContext(TaskContext&& right)
+ : _task(std::move(right._task)), _owner(std::move(right._owner)), _consumed(std::move(right._consumed)) { }
+
+ // Copy assign
+ TaskContext& operator= (TaskContext const& right)
+ {
+ _task = right._task;
+ _owner = right._owner;
+ _consumed = right._consumed;
+ return *this;
+ }
+
+ // Move assign
+ TaskContext& operator= (TaskContext&& right)
+ {
+ _task = std::move(right._task);
+ _owner = std::move(right._owner);
+ _consumed = std::move(right._consumed);
+ return *this;
+ }
+
+ /// Returns true if the owner was deallocated and this context has expired.
+ bool IsExpired() const;
+
+ /// Returns true if the event is in the given group
+ bool IsInGroup(TaskScheduler::group_t const group) const;
+
+ /// Sets the event in the given group
+ TaskContext& SetGroup(TaskScheduler::group_t const group);
+
+ /// Removes the group from the event
+ TaskContext& ClearGroup();
+
+ /// Returns the repeat counter which increases every time the task is repeated.
+ TaskScheduler::repeated_t GetRepeatCounter() const;
+
+ /// Repeats the event and sets a new duration.
+ /// std::chrono::seconds(5) for example.
+ /// This will consume the task context, its not possible to repeat the task again
+ /// from the same task context!
+ template<class _Rep, class _Period>
+ TaskContext& Repeat(std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ AssertOnConsumed();
+
+ // Set new duration, in-context timing and increment repeat counter
+ _task->_duration = duration;
+ _task->_end += duration;
+ _task->_repeated += 1;
+ (*_consumed) = true;
+ return Dispatch(std::bind(&TaskScheduler::InsertTask, std::placeholders::_1, _task));
+ }
+
+ /// Repeats the event with the same duration.
+ /// This will consume the task context, its not possible to repeat the task again
+ /// from the same task context!
+ TaskContext& Repeat()
+ {
+ return Repeat(_task->_duration);
+ }
+
+ /// Repeats the event and set a new duration that is randomized between min and max.
+ /// std::chrono::seconds(5) for example.
+ /// This will consume the task context, its not possible to repeat the task again
+ /// from the same task context!
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskContext& Repeat(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return Repeat(TaskScheduler::RandomDurationBetween(min, max));
+ }
+
+ /// Schedule a callable function that is executed at the next update tick from within the context.
+ /// Its safe to modify the TaskScheduler from within the callable.
+ TaskContext& Async(std::function<void()> const& callable);
+
+ /// Schedule an event with a fixed rate from within the context.
+ /// Its possible that the new event is executed immediately!
+ /// Use TaskScheduler::Async to create a task
+ /// which will be called at the next update tick.
+ template<class _Rep, class _Period>
+ TaskContext& Schedule(std::chrono::duration<_Rep, _Period> const& time,
+ TaskScheduler::task_handler_t const& task)
+ {
+ auto const end = _task->_end;
+ return Dispatch([end, time, task](TaskScheduler& scheduler) -> TaskScheduler&
+ {
+ return scheduler.ScheduleAt<_Rep, _Period>(end, time, task);
+ });
+ }
+
+ /// Schedule an event with a fixed rate from within the context.
+ /// Its possible that the new event is executed immediately!
+ /// Use TaskScheduler::Async to create a task
+ /// which will be called at the next update tick.
+ template<class _Rep, class _Period>
+ TaskContext& Schedule(std::chrono::duration<_Rep, _Period> const& time,
+ TaskScheduler::group_t const group, TaskScheduler::task_handler_t const& task)
+ {
+ auto const end = _task->_end;
+ return Dispatch([end, time, group, task](TaskScheduler& scheduler) -> TaskScheduler&
+ {
+ return scheduler.ScheduleAt<_Rep, _Period>(end, time, group, task);
+ });
+ }
+
+ /// Schedule an event with a randomized rate between min and max rate from within the context.
+ /// Its possible that the new event is executed immediately!
+ /// Use TaskScheduler::Async to create a task
+ /// which will be called at the next update tick.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskContext& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::task_handler_t const& task)
+ {
+ return Schedule(TaskScheduler::RandomDurationBetween(min, max), task);
+ }
+
+ /// Schedule an event with a randomized rate between min and max rate from within the context.
+ /// Its possible that the new event is executed immediately!
+ /// Use TaskScheduler::Async to create a task
+ /// which will be called at the next update tick.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskContext& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::group_t const group,
+ TaskScheduler::task_handler_t const& task)
+ {
+ return Schedule(TaskScheduler::RandomDurationBetween(min, max), group, task);
+ }
+
+ /// Cancels all tasks from within the context.
+ TaskContext& CancelAll();
+
+ /// Cancel all tasks of a single group from within the context.
+ TaskContext& CancelGroup(TaskScheduler::group_t const group);
+
+ /// Cancels all groups in the given std::vector from within the context.
+ /// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}"
+ TaskContext& CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups);
+
+ /// Delays all tasks with the given duration from within the context.
+ template<class _Rep, class _Period>
+ TaskContext& DelayAll(std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ return Dispatch(std::bind(&TaskScheduler::DelayAll<_Rep, _Period>, std::placeholders::_1, duration));
+ }
+
+ /// Delays all tasks with a random duration between min and max from within the context.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskContext& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return DelayAll(TaskScheduler::RandomDurationBetween(min, max));
+ }
+
+ /// Delays all tasks of a group with the given duration from within the context.
+ template<class _Rep, class _Period>
+ TaskContext& DelayGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ return Dispatch(std::bind(&TaskScheduler::DelayGroup<_Rep, _Period>, std::placeholders::_1, group, duration));
+ }
+
+ /// Delays all tasks of a group with a random duration between min and max from within the context.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskContext& DelayGroup(TaskScheduler::group_t const group,
+ std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return DelayGroup(group, TaskScheduler::RandomDurationBetween(min, max));
+ }
+
+ /// Reschedule all tasks with the given duration.
+ template<class _Rep, class _Period>
+ TaskContext& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ return Dispatch(std::bind(&TaskScheduler::RescheduleAll, std::placeholders::_1, duration));
+ }
+
+ /// Reschedule all tasks with a random duration between min and max.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskContext& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return RescheduleAll(TaskScheduler::RandomDurationBetween(min, max));
+ }
+
+ /// Reschedule all tasks of a group with the given duration.
+ template<class _Rep, class _Period>
+ TaskContext& RescheduleGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
+ {
+ return Dispatch(std::bind(&TaskScheduler::RescheduleGroup<_Rep, _Period>, std::placeholders::_1, group, duration));
+ }
+
+ /// Reschedule all tasks of a group with a random duration between min and max.
+ template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
+ TaskContext& RescheduleGroup(TaskScheduler::group_t const group,
+ std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
+ std::chrono::duration<_RepRight, _PeriodRight> const& max)
+ {
+ return RescheduleGroup(group, TaskScheduler::RandomDurationBetween(min, max));
+ }
+
+private:
+ /// Asserts if the task was consumed already.
+ void AssertOnConsumed() const;
+
+ /// Invokes the associated hook of the task.
+ void Invoke();
+};
+
+/// Milliseconds shorthand typedef.
+typedef std::chrono::milliseconds Milliseconds;
+
+/// Seconds shorthand typedef.
+typedef std::chrono::seconds Seconds;
+
+/// Minutes shorthand typedef.
+typedef std::chrono::minutes Minutes;
+
+/// Hours shorthand typedef.
+typedef std::chrono::hours Hours;
+
+#endif /// _TASK_SCHEDULER_H_
diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h
index 0a4e5e4a4a0..cd523511c1d 100644
--- a/src/server/shared/Utilities/Util.h
+++ b/src/server/shared/Utilities/Util.h
@@ -688,8 +688,9 @@ class EventMap
/**
* @name RepeatEvent
- * @brief Repeats the mostly recently executed event.
- * @param time Time until the event occurs. Equivalent to Repeat(urand(minTime, maxTime).
+ * @brief Repeats the mostly recently executed event, Equivalent to Repeat(urand(minTime, maxTime).
+ * @param minTime Minimum time until the event occurs.
+ * @param maxTime Maximum time until the event occurs.
*/
void Repeat(uint32 minTime, uint32 maxTime)
{
@@ -839,7 +840,7 @@ class EventMap
/**
* @name GetTimeUntilEvent
* @brief Returns time in milliseconds until next event.
- * @param Id of the event.
+ * @param eventId of the event.
* @return Time of next event.
*/
uint32 GetTimeUntilEvent(uint32 eventId) const;
diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt
index 97180fb36a0..d3b2eba9698 100644
--- a/src/server/worldserver/CMakeLists.txt
+++ b/src/server/worldserver/CMakeLists.txt
@@ -47,6 +47,8 @@ include_directories(
${CMAKE_SOURCE_DIR}/dep/gsoap
${CMAKE_SOURCE_DIR}/dep/sockets/include
${CMAKE_SOURCE_DIR}/dep/SFMT
+ ${CMAKE_SOURCE_DIR}/dep/cppformat
+ ${CMAKE_SOURCE_DIR}/dep/process
${CMAKE_SOURCE_DIR}/src/server/collision
${CMAKE_SOURCE_DIR}/src/server/collision/Management
${CMAKE_SOURCE_DIR}/src/server/collision/Models
@@ -63,6 +65,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/server/shared/Networking
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
${CMAKE_SOURCE_DIR}/src/server/shared/Threading
+ ${CMAKE_SOURCE_DIR}/src/server/shared/Updater
${CMAKE_SOURCE_DIR}/src/server/shared/Utilities
${CMAKE_SOURCE_DIR}/src/server/game
${CMAKE_SOURCE_DIR}/src/server/game/Accounts
@@ -141,6 +144,8 @@ include_directories(
${VALGRIND_INCLUDE_DIR}
)
+GroupSources(${CMAKE_CURRENT_SOURCE_DIR})
+
add_executable(worldserver
${worldserver_SRCS}
${worldserver_PCH_SRC}
@@ -168,6 +173,7 @@ target_link_libraries(worldserver
g3dlib
gsoap
Detour
+ format
${JEMALLOC_LIBRARY}
${READLINE_LIBRARY}
${TERMCAP_LIBRARY}
diff --git a/src/server/worldserver/CommandLine/CliRunnable.cpp b/src/server/worldserver/CommandLine/CliRunnable.cpp
index 6e961922b0e..ad9ae28f712 100644
--- a/src/server/worldserver/CommandLine/CliRunnable.cpp
+++ b/src/server/worldserver/CommandLine/CliRunnable.cpp
@@ -23,21 +23,16 @@
#include "Common.h"
#include "ObjectMgr.h"
#include "World.h"
-#include "WorldSession.h"
#include "Configuration/Config.h"
-#include "AccountMgr.h"
-#include "Chat.h"
#include "CliRunnable.h"
-#include "Language.h"
#include "Log.h"
-#include "MapManager.h"
-#include "Player.h"
#include "Util.h"
#if PLATFORM != PLATFORM_WINDOWS
#include <readline/readline.h>
#include <readline/history.h>
+#include "Chat.h"
char* command_finder(const char* text, int state)
{
diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp
index 06d8775440a..430c3ce4d73 100644
--- a/src/server/worldserver/Main.cpp
+++ b/src/server/worldserver/Main.cpp
@@ -47,6 +47,7 @@
#include "SystemConfig.h"
#include "WorldSocket.h"
#include "WorldSocketMgr.h"
+#include "DatabaseLoader.h"
using namespace boost::program_options;
@@ -92,7 +93,8 @@ void ShutdownCLIThread(std::thread* cliThread);
void ShutdownThreadPool(std::vector<std::thread>& threadPool);
variables_map GetConsoleArguments(int argc, char** argv, std::string& cfg_file, std::string& cfg_service);
-int mainImpl(int argc, char** argv)
+/// Launch the Trinity server
+extern int main(int argc, char** argv)
{
std::string configFile = _TRINITY_CORE_CONFIG;
std::string configService;
@@ -288,25 +290,6 @@ int mainImpl(int argc, char** argv)
return World::GetExitCode();
}
-/// Launch the Trinity server
-extern int main(int argc, char** argv)
-{
- try
- {
- return mainImpl(argc, argv);
- }
- catch (std::exception& ex)
- {
- std::cerr << "Top-level exception caught:" << ex.what() << "\n";
-
-#ifndef NDEBUG // rethrow exception for the debugger
- throw;
-#else
- return 1;
-#endif
- }
-}
-
void ShutdownCLIThread(std::thread* cliThread)
{
if (cliThread != nullptr)
@@ -325,7 +308,7 @@ void ShutdownCLIThread(std::thread* cliThread)
errorBuffer = "Unknown error";
TC_LOG_DEBUG("server.worldserver", "Error cancelling I/O of CliThread, error code %u, detail: %s",
- errorCode, errorBuffer);
+ uint32(errorCode), errorBuffer);
LocalFree(errorBuffer);
// send keyboard input to safely unblock the CLI thread
@@ -465,80 +448,15 @@ bool StartDB()
{
MySQL::Library_Init();
- std::string dbString;
- uint8 asyncThreads, synchThreads;
+ // Load databases
+ DatabaseLoader loader("server.worldserver", DatabaseLoader::DATABASE_NONE);
+ loader
+ .AddDatabase(WorldDatabase, "World")
+ .AddDatabase(CharacterDatabase, "Character")
+ .AddDatabase(LoginDatabase, "Login");
- dbString = sConfigMgr->GetStringDefault("WorldDatabaseInfo", "");
- if (dbString.empty())
- {
- TC_LOG_ERROR("server.worldserver", "World database not specified in configuration file");
+ if (!loader.Load())
return false;
- }
-
- asyncThreads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.WorkerThreads", 1));
- if (asyncThreads < 1 || asyncThreads > 32)
- {
- TC_LOG_ERROR("server.worldserver", "World database: invalid number of worker threads specified. "
- "Please pick a value between 1 and 32.");
- return false;
- }
-
- synchThreads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.SynchThreads", 1));
- ///- Initialize the world database
- if (!WorldDatabase.Open(dbString, asyncThreads, synchThreads))
- {
- TC_LOG_ERROR("server.worldserver", "Cannot connect to world database %s", dbString.c_str());
- return false;
- }
-
- ///- Get character database info from configuration file
- dbString = sConfigMgr->GetStringDefault("CharacterDatabaseInfo", "");
- if (dbString.empty())
- {
- TC_LOG_ERROR("server.worldserver", "Character database not specified in configuration file");
- return false;
- }
-
- asyncThreads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.WorkerThreads", 1));
- if (asyncThreads < 1 || asyncThreads > 32)
- {
- TC_LOG_ERROR("server.worldserver", "Character database: invalid number of worker threads specified. "
- "Please pick a value between 1 and 32.");
- return false;
- }
-
- synchThreads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.SynchThreads", 2));
-
- ///- Initialize the Character database
- if (!CharacterDatabase.Open(dbString, asyncThreads, synchThreads))
- {
- TC_LOG_ERROR("server.worldserver", "Cannot connect to Character database %s", dbString.c_str());
- return false;
- }
-
- ///- Get login database info from configuration file
- dbString = sConfigMgr->GetStringDefault("LoginDatabaseInfo", "");
- if (dbString.empty())
- {
- TC_LOG_ERROR("server.worldserver", "Login database not specified in configuration file");
- return false;
- }
-
- asyncThreads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.WorkerThreads", 1));
- if (asyncThreads < 1 || asyncThreads > 32)
- {
- TC_LOG_ERROR("server.worldserver", "Login database: invalid number of worker threads specified. "
- "Please pick a value between 1 and 32.");
- return false;
- }
-
- synchThreads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.SynchThreads", 1));
- ///- Initialise the login database
- if (!LoginDatabase.Open(dbString, asyncThreads, synchThreads))
- {
- TC_LOG_ERROR("server.worldserver", "Cannot connect to login database %s", dbString.c_str());
- return false;
- }
///- Get the realm Id from the configuration file
realmID = sConfigMgr->GetIntDefault("RealmID", 0);
diff --git a/src/server/worldserver/RemoteAccess/RASession.h b/src/server/worldserver/RemoteAccess/RASession.h
index d272f323c6a..efd2106fdd1 100644
--- a/src/server/worldserver/RemoteAccess/RASession.h
+++ b/src/server/worldserver/RemoteAccess/RASession.h
@@ -30,8 +30,6 @@ using boost::asio::ip::tcp;
const size_t bufferSize = 4096;
-#define BUFFER_SIZE 4096
-
class RASession : public std::enable_shared_from_this <RASession>
{
public:
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index ecb5824b1c5..447ef9a45a8 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -11,6 +11,7 @@
# PERFORMANCE SETTINGS
# SERVER LOGGING
# SERVER SETTINGS
+# UPDATE SETTINGS
# WARDEN SETTINGS
# PLAYER INTERACTION
# CREATURE SETTINGS
@@ -1020,7 +1021,7 @@ OffhandCheckAtSpellUnlearn = 1
# ClientCacheVersion
# Description: Client cache version for client cache data reset. Use any value different
# from DB and not recently been used to trigger client side cache reset.
-# Default: 0 - (Use DB value from world DB db_version.cache_id field)
+# Default: 0 - (Use DB value from world DB version.cache_id field)
ClientCacheVersion = 0
@@ -1121,6 +1122,92 @@ BirthdayTime = 1222964635
###################################################################################################
###################################################################################################
+# UPDATE SETTINGS
+#
+# Updates.EnableDatabases
+# Description: A mask that describes which databases shall be updated.
+#
+# Following flags are available
+# DATABASE_LOGIN = 1, // Auth database
+# DATABASE_CHARACTER = 2, // Character database
+# DATABASE_WORLD = 4, // World database
+#
+# Default: 0 - (All Disabled)
+# 4 - (Enable world only)
+# 7 - (All enabled)
+
+Updates.EnableDatabases = 0
+
+#
+# Updates.SourcePath
+# Description: The path to your TrinityCore source directory.
+# If the path is left empty, built-in CMAKE_SOURCE_DIR is used.
+# Example: "../TrinityCore"
+# Default: ""
+
+Updates.SourcePath = ""
+
+#
+# Updates.SourcePath
+# Description: The path to your mysql cli binary.
+# If the path is left empty, built-in path from cmake is used.
+# Example: "C:/Program Files/MySQL/MySQL Server 5.6/bin/mysql.exe"
+# "mysql.exe"
+# "/usr/bin/mysql"
+# Default: ""
+
+Updates.MySqlCLIPath = ""
+
+#
+# Updates.AutoSetup
+# Description: Auto populate empty databases.
+# Default: 1 - (Enabled)
+# 0 - (Disabled)
+
+Updates.AutoSetup = 1
+
+#
+# Updates.Redundancy
+# Description: Perform data redundancy checks through hashing
+# to detect changes on sql updates and reapply it.
+# Default: 1 - (Enabled)
+# 0 - (Disabled)
+
+Updates.Redundancy = 1
+
+#
+# Updates.ArchivedRedundancy
+# Description: Check hashes of archived updates (slows down startup).
+# Default: 0 - (Disabled)
+# 1 - (Enabled)
+
+Updates.ArchivedRedundancy = 0
+
+#
+# Updates.AllowRehash
+# Description: Inserts the current file hash in the database if it is left empty.
+# Useful if you want to mark a file as applied but you don't know its hash.
+# Default: 1 - (Enabled)
+# 0 - (Disabled)
+
+Updates.AllowRehash = 1
+
+#
+# Updates.CleanDeadRefMaxCount
+# Description: Cleans dead/ orphaned references that occur if an update was removed or renamed and edited in one step.
+# It only starts the clean up if the count of the missing updates is below or equal the Updates.CleanDeadRefMaxCount value.
+# This way prevents erasing of the update history due to wrong source directory state (maybe wrong branch or bad revision).
+# Disable this if you want to know if the database is in a possible "dirty state".
+# Default: 3 - (Enabled)
+# 0 - (Disabled)
+# -1 - (Enabled - unlimited)
+
+Updates.CleanDeadRefMaxCount = 3
+
+#
+###################################################################################################
+
+###################################################################################################
# WARDEN SETTINGS
#
# Warden.Enabled
@@ -3173,8 +3260,10 @@ Logger.root=5,Console Server
Logger.server=3,Console Server
Logger.commands.gm=3,Console GM
Logger.sql.sql=5,Console DBErrors
+Logger.sql.updates=3,Console Server
#Logger.achievement=3,Console Server
+#Logger.addon=3,Console Server
#Logger.ahbot=3,Console Server
#Logger.auctionHouse=3,Console Server
#Logger.bg.arena=3,Console Server
diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp
index a573f9fecc8..dcaa3ba0a76 100644
--- a/src/tools/map_extractor/System.cpp
+++ b/src/tools/map_extractor/System.cpp
@@ -63,8 +63,9 @@ typedef struct
map_id *map_ids;
uint16 *areas;
uint16 *LiqType;
-char output_path[128] = ".";
-char input_path[128] = ".";
+#define MAX_PATH_LENGTH 128
+char output_path[MAX_PATH_LENGTH] = ".";
+char input_path[MAX_PATH_LENGTH] = ".";
uint32 maxAreaId = 0;
// **************************************************
@@ -143,11 +144,11 @@ void Usage(char* prg)
printf(
"Usage:\n"\
"%s -[var] [value]\n"\
- "-i set input path\n"\
- "-o set output path\n"\
+ "-i set input path (max %d characters)\n"\
+ "-o set output path (max %d characters)\n"\
"-e extract only MAP(1)/DBC(2) - standard: both(3)\n"\
"-f height stored as int (less map size but lost some accuracy) 1 by default\n"\
- "Example: %s -f 0 -i \"c:\\games\\game\"", prg, prg);
+ "Example: %s -f 0 -i \"c:\\games\\game\"", prg, MAX_PATH_LENGTH - 1, MAX_PATH_LENGTH - 1, prg);
exit(1);
}
@@ -166,14 +167,20 @@ void HandleArgs(int argc, char * arg[])
switch(arg[c][1])
{
case 'i':
- if(c + 1 < argc) // all ok
- strcpy(input_path, arg[(c++) + 1]);
+ if (c + 1 < argc && strlen(arg[c + 1]) < MAX_PATH_LENGTH) // all ok
+ {
+ strncpy(input_path, arg[c++ + 1], MAX_PATH_LENGTH);
+ input_path[MAX_PATH_LENGTH - 1] = '\0';
+ }
else
Usage(arg[0]);
break;
case 'o':
- if(c + 1 < argc) // all ok
- strcpy(output_path, arg[(c++) + 1]);
+ if (c + 1 < argc && strlen(arg[c + 1]) < MAX_PATH_LENGTH) // all ok
+ {
+ strncpy(output_path, arg[c++ + 1], MAX_PATH_LENGTH);
+ output_path[MAX_PATH_LENGTH - 1] = '\0';
+ }
else
Usage(arg[0]);
break;
@@ -250,7 +257,17 @@ uint32 ReadMapDBC()
for(uint32 x = 0; x < map_count; ++x)
{
map_ids[x].id = dbc.getRecord(x).getUInt(0);
- strcpy(map_ids[x].name, dbc.getRecord(x).getString(1));
+
+ const char* map_name = dbc.getRecord(x).getString(1);
+ size_t max_map_name_length = sizeof(map_ids[x].name);
+ if (strlen(map_name) >= max_map_name_length)
+ {
+ printf("Fatal error: Map name too long!\n");
+ exit(1);
+ }
+
+ strncpy(map_ids[x].name, map_name, max_map_name_length);
+ map_ids[x].name[max_map_name_length - 1] = '\0';
}
printf("Done! (%u maps loaded)\n", (uint32)map_count);
return map_count;
diff --git a/src/tools/map_extractor/mpq_libmpq.cpp b/src/tools/map_extractor/mpq_libmpq.cpp
index 3e12747e9c5..482e3a3abbd 100644
--- a/src/tools/map_extractor/mpq_libmpq.cpp
+++ b/src/tools/map_extractor/mpq_libmpq.cpp
@@ -71,7 +71,7 @@ MPQFile::MPQFile(const char* filename):
uint32_t filenum;
if(libmpq__file_number(mpq_a, filename, &filenum)) continue;
libmpq__off_t transferred;
- libmpq__file_unpacked_size(mpq_a, filenum, &size);
+ libmpq__file_size_unpacked(mpq_a, filenum, &size);
// HACK: in patch.mpq some files don't want to open and give 1 for filesize
if (size<=1) {
diff --git a/src/tools/map_extractor/mpq_libmpq04.h b/src/tools/map_extractor/mpq_libmpq04.h
index 470e7bd0c50..c6fe36a8221 100644
--- a/src/tools/map_extractor/mpq_libmpq04.h
+++ b/src/tools/map_extractor/mpq_libmpq04.h
@@ -43,7 +43,7 @@ public:
uint32_t filenum;
if(libmpq__file_number(mpq_a, "(listfile)", &filenum)) return;
libmpq__off_t size, transferred;
- libmpq__file_unpacked_size(mpq_a, filenum, &size);
+ libmpq__file_size_unpacked(mpq_a, filenum, &size);
char *buffer = new char[size+1];
buffer[size] = '\0';
diff --git a/src/tools/vmap4_assembler/CMakeLists.txt b/src/tools/vmap4_assembler/CMakeLists.txt
index c0ff9e9a153..dfd6c7d4dd4 100644
--- a/src/tools/vmap4_assembler/CMakeLists.txt
+++ b/src/tools/vmap4_assembler/CMakeLists.txt
@@ -16,7 +16,6 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/server/collision
${CMAKE_SOURCE_DIR}/src/server/collision/Maps
${CMAKE_SOURCE_DIR}/src/server/collision/Models
- ${ACE_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR}
)
diff --git a/src/tools/vmap4_extractor/adtfile.cpp b/src/tools/vmap4_extractor/adtfile.cpp
index a4caf06a7c2..557511f6d1e 100644
--- a/src/tools/vmap4_extractor/adtfile.cpp
+++ b/src/tools/vmap4_extractor/adtfile.cpp
@@ -184,6 +184,7 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY)
ModelInstance inst(ADT,ModelInstansName[id].c_str(), map_num, tileX, tileY, dirfile);
}
delete[] ModelInstansName;
+ ModelInstansName = NULL;
}
}
else if (!strcmp(fourcc,"MODF"))
@@ -198,6 +199,7 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY)
WMOInstance inst(ADT,WmoInstansName[id].c_str(), map_num, tileX, tileY, dirfile);
}
delete[] WmoInstansName;
+ WmoInstansName = NULL;
}
}
//======================
diff --git a/src/tools/vmap4_extractor/mpq_libmpq.cpp b/src/tools/vmap4_extractor/mpq_libmpq.cpp
index 5e0effc1a77..f3eb3da96b6 100644
--- a/src/tools/vmap4_extractor/mpq_libmpq.cpp
+++ b/src/tools/vmap4_extractor/mpq_libmpq.cpp
@@ -71,7 +71,7 @@ MPQFile::MPQFile(const char* filename):
uint32 filenum;
if(libmpq__file_number(mpq_a, filename, &filenum)) continue;
libmpq__off_t transferred;
- libmpq__file_unpacked_size(mpq_a, filenum, &size);
+ libmpq__file_size_unpacked(mpq_a, filenum, &size);
// HACK: in patch.mpq some files don't want to open and give 1 for filesize
if (size<=1) {
diff --git a/src/tools/vmap4_extractor/mpq_libmpq04.h b/src/tools/vmap4_extractor/mpq_libmpq04.h
index bb842daf258..6196285627d 100644
--- a/src/tools/vmap4_extractor/mpq_libmpq04.h
+++ b/src/tools/vmap4_extractor/mpq_libmpq04.h
@@ -42,7 +42,7 @@ public:
uint32_t filenum;
if(libmpq__file_number(mpq_a, "(listfile)", &filenum)) return;
libmpq__off_t size, transferred;
- libmpq__file_unpacked_size(mpq_a, filenum, &size);
+ libmpq__file_size_unpacked(mpq_a, filenum, &size);
char *buffer = new char[size + 1];
buffer[size] = '\0';
diff --git a/src/tools/vmap4_extractor/vec3d.h b/src/tools/vmap4_extractor/vec3d.h
index a0c22729052..211f5f26c72 100644
--- a/src/tools/vmap4_extractor/vec3d.h
+++ b/src/tools/vmap4_extractor/vec3d.h
@@ -103,7 +103,7 @@ public:
float length() const
{
- return sqrt(x*x+y*y+z*z);
+ return std::sqrt(x*x+y*y+z*z);
}
Vec3D& normalize()
@@ -209,7 +209,7 @@ public:
float length() const
{
- return sqrt(x*x+y*y);
+ return std::sqrt(x*x+y*y);
}
Vec2D& normalize()
diff --git a/src/tools/vmap4_extractor/vmapexport.cpp b/src/tools/vmap4_extractor/vmapexport.cpp
index 4cec49ef333..7a12897563e 100644
--- a/src/tools/vmap4_extractor/vmapexport.cpp
+++ b/src/tools/vmap4_extractor/vmapexport.cpp
@@ -197,7 +197,7 @@ bool ExtractSingleWmo(std::string& fname)
for (uint32 i = 0; i < froot.nGroups; ++i)
{
char temp[1024];
- strcpy(temp, fname.c_str());
+ strncpy(temp, fname.c_str(), 1024);
temp[fname.length()-4] = 0;
char groupFileName[1024];
sprintf(groupFileName, "%s_%03u.wmo", temp, i);
@@ -395,7 +395,9 @@ bool processArgv(int argc, char ** argv, const char *versionString)
if((i+1)<argc)
{
hasInputPathParam = true;
- strcpy(input_path, argv[i+1]);
+ strncpy(input_path, argv[i + 1], sizeof(input_path));
+ input_path[sizeof(input_path) - 1] = '\0';
+
if (input_path[strlen(input_path) - 1] != '\\' && input_path[strlen(input_path) - 1] != '/')
strcat(input_path, "/");
++i;
@@ -511,11 +513,22 @@ int main(int argc, char ** argv)
map_ids=new map_id[map_count];
for (unsigned int x=0;x<map_count;++x)
{
- map_ids[x].id=dbc->getRecord (x).getUInt(0);
- strcpy(map_ids[x].name,dbc->getRecord(x).getString(1));
- printf("Map - %s\n",map_ids[x].name);
- }
+ map_ids[x].id = dbc->getRecord(x).getUInt(0);
+
+ const char* map_name = dbc->getRecord(x).getString(1);
+ size_t max_map_name_length = sizeof(map_ids[x].name);
+ if (strlen(map_name) >= max_map_name_length)
+ {
+ delete dbc;
+ delete[] map_ids;
+ printf("FATAL ERROR: Map name too long.\n");
+ return 1;
+ }
+ strncpy(map_ids[x].name, map_name, max_map_name_length);
+ map_ids[x].name[max_map_name_length - 1] = '\0';
+ printf("Map - %s\n", map_ids[x].name);
+ }
delete dbc;
ParsMapFiles();
diff --git a/src/tools/vmap4_extractor/wdtfile.cpp b/src/tools/vmap4_extractor/wdtfile.cpp
index 6ba91c6e12c..877f49ce371 100644
--- a/src/tools/vmap4_extractor/wdtfile.cpp
+++ b/src/tools/vmap4_extractor/wdtfile.cpp
@@ -103,6 +103,7 @@ bool WDTFile::init(char* /*map_id*/, unsigned int mapID)
}
delete[] gWmoInstansName;
+ gWmoInstansName = NULL;
}
}
WDT.seek((int)nextpos);